From 17402a817f45fdcc6d3152eca7e8e3e680de428a Mon Sep 17 00:00:00 2001 From: John Mertic Date: Wed, 9 Nov 2011 23:01:05 -0500 Subject: [PATCH] Release 6.3.0 --- ModuleInstall/ModuleInstaller.php | 1102 +- ModuleInstall/ModuleScanner.php | 175 +- .../tpls/ModuleLoaderListView.tpl | 4 +- ModuleInstall/extensions.php | 63 + Zend/Gdata/Contacts.php | 139 + Zend/Gdata/Contacts/Extension/Address.php | 125 + Zend/Gdata/Contacts/Extension/Birthday.php | 91 + Zend/Gdata/Contacts/Extension/Email.php | 119 + Zend/Gdata/Contacts/Extension/Name.php | 91 + .../Gdata/Contacts/Extension/Organization.php | 104 + Zend/Gdata/Contacts/Extension/PhoneNumber.php | 112 + Zend/Gdata/Contacts/ListEntry.php | 259 + Zend/Gdata/Contacts/ListFeed.php | 71 + Zend/Oauth/Config.php | 2 +- Zend/Oauth/Provider.php | 354 + data/BeanFactory.php | 193 + data/Link.php | 43 +- data/Link2.php | 615 + .../EmailAddressRelationship.php | 114 + data/Relationships/M2MRelationship.php | 530 + data/Relationships/One2MBeanRelationship.php | 310 + data/Relationships/One2MRelationship.php | 176 + .../Relationships/One2OneBeanRelationship.php | 111 + data/Relationships/One2OneRelationship.php | 75 + data/Relationships/RelationshipFactory.php | 206 + data/Relationships/SugarRelationship.php | 446 + data/SugarBean.php | 517 +- download.php | 18 +- export.php | 17 +- files.md5 | 1058 +- include/Dashlets/Dashlet.php | 5 + include/Dashlets/DashletGeneric.php | 2 + .../Dashlets/DashletGenericAutoRefresh.tpl | 2 +- .../DashletGenericAutoRefreshDynamic.tpl | 2 +- include/Dashlets/DashletGenericChart.php | 2 + .../Dashlets/DashletGenericChartConfigure.tpl | 5 +- include/Dashlets/DashletGenericConfigure.tpl | 3 + include/Dashlets/DashletGenericDisplay.tpl | 11 +- include/DetailView/DetailView.php | 2 +- include/DetailView/DetailView.tpl | 2 +- include/EditView/EditView.tpl | 4 +- include/EditView/EditView2.php | 110 +- include/EditView/SubpanelQuickCreate.php | 15 +- include/EditView/SubpanelQuickEdit.php | 143 + include/EditView/SugarVCR.php | 6 +- include/EditView/header.tpl | 2 +- include/ListView/ListView.php | 105 +- include/ListView/ListViewDCMenu.tpl | 4 +- include/ListView/ListViewDisplay.php | 32 +- include/ListView/ListViewFacade.php | 12 +- include/ListView/ListViewGeneric.tpl | 50 +- include/ListView/ListViewNoMassUpdate.tpl | 4 +- include/ListView/ListViewSmarty.php | 3 +- include/MVC/Controller/SugarController.php | 10 + include/MVC/Controller/action_view_map.php | 4 + include/MVC/SugarApplication.php | 30 +- include/MVC/View/SugarView.php | 156 +- include/MVC/View/views/view.ajaxui.php | 63 + include/MVC/View/views/view.config.php | 47 +- include/MVC/View/views/view.detail.php | 7 +- include/MVC/View/views/view.metadata.php | 372 + include/MVC/View/views/view.quickcreate.php | 1 + include/MVC/View/views/view.quickedit.php | 208 + include/MassUpdate.php | 2 +- .../MySugar/DashletsDialog/DashletsDialog.php | 3 +- include/MySugar/javascript/MySugar.js | 8 +- include/MySugar/tpls/MySugar.tpl | 119 +- include/MySugar/tpls/addDashletsDialog.tpl | 8 +- include/OutboundEmail/OutboundEmail.php | 3 + include/Popups/PopupSmarty.php | 21 + include/Popups/tpls/PopupGeneric.tpl | 8 +- include/SearchForm/SearchForm.php | 6 +- include/SearchForm/SearchForm2.php | 9 +- include/SearchForm/tpls/SearchFormGeneric.tpl | 4 +- .../tpls/SearchFormGenericAdvanced.tpl | 2 +- include/SearchForm/tpls/header.tpl | 4 +- .../plugins/function.overlib_includes.php | 4 +- .../plugins/function.sugar_ajax_url.php | 50 + .../Smarty/plugins/function.sugar_button.php | 34 +- .../Smarty/plugins/function.sugar_field.php | 6 +- .../Smarty/plugins/function.sugar_link.php | 4 +- include/Smarty/plugins/modifier.lookup.php | 47 + .../plugins/modifier.multienum_to_ac.php | 66 + include/SubPanel/SubPanel.php | 6 +- include/SubPanel/SubPanelDynamic.html | 2 +- include/SubPanel/SubPanelTiles.js | 26 +- include/SubPanel/SubPanelTiles.php | 10 +- include/SubPanel/SugarTab.php | 7 + include/SubPanel/tpls/singletabmenu.tpl | 2 +- include/SugarCache/SugarCache.php | 9 + include/SugarCache/SugarCacheAPC.php | 21 +- include/SugarCache/SugarCacheAbstract.php | 68 +- include/SugarCache/SugarCacheFile.php | 32 +- include/SugarCache/SugarCacheMemcache.php | 2 +- include/SugarCache/SugarCacheMemcached.php | 8 +- include/SugarCache/SugarCacheZend.php | 17 +- include/SugarCharts/Jit/js/mySugarCharts.js | 4 +- .../Jit/tpls/DashletGenericChartScript.tpl | 26 +- include/SugarCharts/Jit/tpls/chart.tpl | 58 +- include/SugarCharts/JsChart.php | 1 - include/SugarDateTime.php | 38 +- .../SugarEmailAddress/SugarEmailAddress.js | 13 +- .../SugarEmailAddress/SugarEmailAddress.php | 47 +- .../SugarFields/Fields/Address/EditView.tpl | 9 +- .../Fields/Address/SugarFieldAddress.js | 14 +- .../Fields/Address/en_us.EditView.tpl | 9 +- .../Fields/Base/SugarFieldBase.php | 84 +- .../Fields/Collection/CollectionEditView.tpl | 14 +- .../Collection/CollectionEditViewRow.tpl | 2 +- .../Fields/Collection/SugarFieldCollection.js | 23 +- .../Collection/SugarFieldCollection.php | 9 + .../Collection/ViewSugarFieldCollection.php | 5 +- include/SugarFields/Fields/Enum/EditView.tpl | 319 +- include/SugarFields/Fields/File/EditView.tpl | 5 +- .../Fields/File/SugarFieldFile.php | 9 + .../SugarFields/Fields/Multienum/EditView.tpl | 392 +- .../Fields/Multienum/SugarFieldMultienum.php | 6 +- .../SugarFields/Fields/Parent/EditView.tpl | 57 +- .../SugarFields/Fields/Parent/SearchView.tpl | 57 +- .../Fields/Parent/SugarFieldParent.php | 9 + .../Fields/Phone/SugarFieldPhone.php | 2 + .../SugarFields/Fields/Relate/DetailView.tpl | 4 +- .../SugarFields/Fields/Relate/EditView.tpl | 16 +- .../Fields/Relate/SugarFieldRelate.php | 13 +- include/SugarLogger/SugarLogger.php | 26 +- include/SugarOAuthServer.php | 257 + include/SugarObjects/LanguageManager.php | 22 + include/SugarObjects/VardefManager.php | 517 +- .../basic/metadata/detailviewdefs.php | 2 +- .../SugarObjects/templates/basic/vardefs.php | 3 + .../templates/company/vardefs.php | 6 +- .../templates/file/metadata/editviewdefs.php | 3 +- .../file/metadata/quickcreatedefs.php | 3 +- .../SugarObjects/templates/person/vardefs.php | 2 +- include/SugarTheme/SugarTheme.php | 288 +- include/Sugar_Smarty.php | 5 + include/TimeDate.php | 44 +- .../formatters/default/company_detail.js | 4 +- include/connectors/sources/default/source.php | 1 - .../sources/ext/eapm/eapm.php} | 32 +- include/database/DBHelper.php | 80 +- include/database/DBManager.php | 47 +- include/database/DBManagerFactory.php | 28 +- include/database/MssqlHelper.php | 16 +- include/database/MssqlManager.php | 2 +- include/database/MysqlHelper.php | 10 + include/database/SqlsrvHelper.php | 11 + include/database/SqlsrvManager.php | 3 + include/dir_inc.php | 5 +- include/export_utils.php | 593 +- include/externalAPI/Base/ExternalAPIBase.php | 1 + include/externalAPI/ExternalAPIFactory.php | 10 +- include/formbase.php | 58 +- include/generic/DeleteRelationship.php | 1 + include/generic/Save2.php | 1 + .../generic/SugarWidgets/SugarWidgetField.php | 64 +- .../SugarWidgets/SugarWidgetFieldcurrency.php | 98 +- .../SugarWidgets/SugarWidgetFieldenum.php | 37 +- .../SugarWidgets/SugarWidgetFieldname.php | 67 +- .../SugarWidgets/SugarWidgetReportField.php | 427 +- .../SugarWidgetSubPanelDeleteButton.php | 78 + .../SugarWidgetSubPanelDetailViewLink.php | 38 +- .../SugarWidgetSubPanelEditButton.php | 24 +- .../SugarWidgetSubPanelRelFieldEditButton.php | 95 + .../SugarWidgetSubPanelTopButton.php | 54 +- ...ugarWidgetSubPanelTopButtonQuickCreate.php | 6 +- ...SugarWidgetSubPanelTopCreateNoteButton.php | 3 +- ...SugarWidgetSubPanelTopCreateTaskButton.php | 1 + ...garWidgetSubPanelTopScheduleCallButton.php | 1 + ...WidgetSubPanelTopScheduleMeetingButton.php | 13 +- include/globalControlLinks.php | 7 +- include/images/configure.png | Bin 0 -> 3178 bytes include/images/create_users.png | Bin 0 -> 2576 bytes include/images/import.png | Bin 0 -> 2589 bytes include/images/poweredby_sugarcrm.png | Bin 4579 -> 4750 bytes include/images/settings.png | Bin 0 -> 3576 bytes include/images/start.png | Bin 0 -> 2765 bytes include/images/university.png | Bin 3933 -> 2653 bytes include/images/university2.png | Bin 0 -> 3933 bytes include/images/wiki.png | Bin 3698 -> 0 bytes include/javascript/ajaxUI.js | 87 + include/javascript/calendar.js | 5 +- include/javascript/importWizard.js | 42 + include/javascript/include.js | 3 +- include/javascript/javascript.php | 9 +- include/javascript/jsAlerts.php | 14 +- include/javascript/jsclass_base.js | 3 +- include/javascript/overlibmws.js | 105 +- include/javascript/overlibmws_iframe.js | 103 +- .../phpjs/get_html_translation_table.js | 128 + .../javascript/phpjs/html_entity_decode.js | 125 + include/javascript/phpjs/license.js | 123 + include/javascript/popup_helper.js | 4 +- include/javascript/popup_parent_helper.js | 8 +- include/javascript/quickCompose.js | 14 +- include/javascript/quicksearch.js | 16 +- include/javascript/sugar_3.js | 99 +- .../sugar_connection_event_listener.js | 2 +- include/javascript/sugar_grp1.js | 589 +- include/javascript/sugar_grp1_yui.js | 15292 +++++++++------- include/javascript/sugar_grp_emails.js | 291 +- include/javascript/sugar_grp_jsolait.js | 242 + include/javascript/sugar_grp_overlib.js | 208 +- include/javascript/sugar_grp_quickcomp.js | 183 +- include/javascript/sugar_grp_yui_widgets.js | 25 +- .../sugarwidgets/SugarYUIWidgets.js | 7 +- include/language/en_us.lang.php | 137 +- include/language/jsLanguage.php | 6 +- include/modules.php | 36 +- include/parsecsv.lib.php | 772 + include/templates/TemplateGroupChooser.php | 8 +- include/utils.php | 162 +- include/utils/LogicHook.php | 115 +- include/utils/autoloader.php | 38 + include/utils/db_utils.php | 6 +- include/utils/file_utils.php | 14 +- include/utils/layout_utils.php | 20 +- include/utils/mvc_utils.php | 91 +- include/utils/php_zip_utils.php | 43 +- install/install_utils.php | 6 +- install/language/en_us.lang.php | 2 +- install/performSetup.php | 61 +- install/populateSeedData.php | 4 +- jssource/JSGroupings.php | 27 +- jssource/jsmin.php | 2 +- .../include/MySugar/javascript/MySugar.js | 13 +- .../include/SubPanel/SubPanelTiles.js | 251 +- .../SugarCharts/Jit/js/mySugarCharts.js | 2 + .../SugarEmailAddress/SugarEmailAddress.js | 102 +- .../Fields/Address/SugarFieldAddress.js | 144 +- .../Fields/Collection/SugarFieldCollection.js | 209 +- .../formatters/default/company_detail.js | 40 +- .../src_files/include/javascript/ajaxUI.js | 328 + .../src_files/include/javascript/calendar.js | 4 +- .../include/javascript/importWizard.js | 154 + .../src_files/include/javascript/include.js | 5 +- .../include/javascript/jsclass_base.js | 4 +- .../include/javascript/overlibmws.js | 105 +- .../include/javascript/overlibmws_iframe.js | 103 +- .../phpjs/get_html_translation_table.js | 285 + .../javascript/phpjs/html_entity_decode.js | 164 + .../include/javascript/phpjs/license.js | 122 + .../include/javascript/popup_helper.js | 16 +- .../include/javascript/popup_parent_helper.js | 7 +- .../include/javascript/quickCompose.js | 41 +- .../include/javascript/quicksearch.js | 35 +- .../src_files/include/javascript/sugar_3.js | 530 +- .../sugar_connection_event_listener.js | 2 +- .../sugarwidgets/SugarYUIWidgets.js | 19 +- .../modules/InboundEmail/InboundEmail.js | 3 +- .../modules/Meetings/jsclass_scheduler.js | 99 +- jssource/src_files/modules/Studio/studio.js | 2 +- jssource/src_files/themes/Sugar5/js/style.js | 73 +- metadata/calls_usersMetaData.php | 55 +- metadata/contacts_bugsMetaData.php | 53 +- metadata/foldersMetaData.php | 8 +- metadata/oauth_nonce.php | 76 + modules/ACLActions/actiondefs.php | 7 +- modules/ACLActions/language/en_us.lang.php | 1 + modules/Accounts/AccountFormBase.php | 17 +- modules/Accounts/Popup_picker.html | 2 +- modules/Accounts/ShowDuplicates.php | 3 +- modules/Accounts/language/en_us.lang.php | 18 +- modules/Accounts/metadata/subpaneldefs.php | 44 +- .../Accounts/metadata/subpanels/ForEmails.php | 2 +- modules/Administration/RebuildJSLang.php | 15 +- .../Administration/RebuildRelationship.php | 6 +- modules/Administration/SupportPortal.php | 3 +- modules/Administration/action_view_map.php | 1 + modules/Administration/controller.php | 22 +- modules/Administration/index.php | 5 + modules/Administration/index.tpl | 17 +- .../Administration/language/en_us.lang.php | 39 +- .../metadata/adminpaneldefs.php | 44 +- modules/Administration/repairDatabase.php | 6 +- .../templates/ConfigureAjaxUI.tpl | 128 + modules/Administration/vardefs.php | 2 +- .../views/view.configureajaxui.php | 106 + modules/Bugs/language/en_us.lang.php | 13 +- modules/Bugs/vardefs.php | 5 +- modules/Calendar/Calendar.php | 8 +- modules/Calls/Call.php | 11 +- modules/Calls/CallFormBase.php | 7 +- .../MyCallsDashlet/MyCallsDashlet.php | 2 + modules/Calls/language/en_us.lang.php | 12 +- modules/Calls/metadata/editviewdefs.php | 16 +- modules/Calls/metadata/quickcreatedefs.php | 10 +- modules/Calls/tpls/footer.tpl | 47 +- modules/Calls/vardefs.php | 19 +- modules/CampaignLog/Popup_picker.html | 2 +- modules/CampaignLog/vardefs.php | 8 + modules/Campaigns/Delete.php | 4 +- modules/Campaigns/ProspectLink.php | 4 +- modules/Campaigns/RoiDetailView.tpl | 1 + modules/Campaigns/TrackDetailView.tpl | 2 +- modules/Campaigns/WizardNewsletterSave.php | 2 + modules/Campaigns/language/en_us.lang.php | 2 +- modules/Campaigns/views/view.detail.php | 1 + modules/Cases/Menu.php | 2 +- modules/Cases/language/en_us.lang.php | 32 +- modules/Cases/metadata/subpaneldefs.php | 34 +- .../Dashlets/PredefinedChartDashletScript.tpl | 7 +- modules/Configurator/controller.php | 24 +- modules/Configurator/language/en_us.lang.php | 6 + modules/Configurator/tpls/EditView.tpl | 10 + modules/Configurator/tpls/adminwizard.tpl | 228 +- .../Configurator/views/view.adminwizard.php | 66 +- modules/Configurator/views/view.edit.php | 6 + .../rest/insideview/InsideViewLogicHook.php | 1 + .../ext/rest/insideview/insideview.php | 11 +- .../ext/rest/insideview/tpls/InsideView.tpl | 53 +- modules/Connectors/controller.php | 3 +- .../Connectors/tpls/display_properties.tpl | 8 +- .../views/view.displayproperties.php | 5 +- .../views/view.mappingproperties.php | 4 +- .../views/view.searchproperties.php | 4 +- modules/Contacts/Contact.php | 75 +- modules/Contacts/ContactFormBase.php | 24 +- modules/Contacts/ShowDuplicates.php | 4 +- modules/Contacts/language/en_us.lang.php | 22 +- modules/Contacts/metadata/subpaneldefs.php | 8 +- modules/Contacts/tpls/QuickCreate.tpl | 3 +- modules/Contacts/vardefs.php | 12 +- modules/Contacts/views/view.edit.php | 3 +- modules/Currencies/Currency.php | 10 +- .../metadata/editviewdefs.php | 3 +- modules/Documents/language/en_us.lang.php | 2 +- modules/Documents/metadata/editviewdefs.php | 3 +- .../Documents/metadata/quickcreatedefs.php | 7 +- modules/Documents/tpls/view.extdoc.tpl | 4 +- modules/Documents/views/view.edit.php | 14 +- modules/DynamicFields/DynamicField.php | 39 +- .../templates/Fields/TemplateEnum.php | 3 - .../templates/Fields/TemplateMultiEnum.php | 4 +- modules/EAPM/controller.php | 8 + modules/EAPM/metadata/editviewdefs.php | 4 +- modules/EAPM/vardefs.php | 4 - modules/EAPM/views/view.detail.php | 16 + modules/EAPM/views/view.edit.php | 25 +- modules/EmailMan/EmailMan.php | 6 +- modules/EmailMan/EmailManDelivery.php | 6 +- modules/EmailMan/tpls/config.tpl | 1 - modules/EmailMan/vardefs.php | 2 + modules/EmailTemplates/EditView.html | 9 +- .../EmailTemplates/EmailTemplateFormBase.php | 2 + modules/Emails/EditView.html | 433 + modules/Emails/EditView.php | 14 +- modules/Emails/EditViewArchive.html | 2 +- modules/Emails/Email.php | 5 +- modules/Emails/javascript/Email.js | 2 +- modules/Emails/javascript/EmailUI.js | 76 +- modules/Emails/javascript/EmailUICompose.js | 9 +- modules/Emails/javascript/EmailUIShared.js | 16 +- modules/Emails/javascript/ajax.js | 135 +- modules/Emails/language/en_us.lang.php | 14 +- modules/Emails/metadata/subpaneldefs.php | 19 +- modules/Emails/templates/importRelate.tpl | 2 +- modules/Emails/vardefs.php | 21 + modules/Employees/views/view.list.php | 14 +- modules/Groups/Group.php | 4 +- modules/Home/About.php | 4 +- .../ChartsDashlet/ChartsDashletScript.tpl | 7 +- .../InvadersDashlet/InvadersDashlet.php | 1 + .../InvadersDashlet/InvadersOptions.tpl | 1 + .../Dashlets/JotPadDashlet/JotPadDashlet.php | 1 + .../Home/Dashlets/RSSDashlet/RSSDashlet.php | 7 +- .../Dashlets/RSSDashlet/RSSDashletOptions.tpl | 1 + .../SugarNewsDashlet/SugarNewsDashlet.php | 1 + .../Dashlets/iFrameDashlet/iFrameDashlet.php | 1 + modules/Home/Home.tpl | 10 +- modules/Home/SubpanelEdits.php | 76 + modules/Home/UnifiedSearchAdvanced.php | 2 +- modules/Home/UnifiedSearchAdvancedResults.tpl | 6 +- modules/Home/index.php | 3 +- modules/Home/language/en_us.lang.php | 4 +- modules/Import/CsvAutoDetect.php | 373 + modules/Import/Forms.php | 22 +- modules/Import/ImportCacheFiles.php | 30 +- modules/Import/ImportDuplicateCheck.php | 194 +- modules/Import/ImportFieldSanitize.php | 2 +- modules/Import/ImportFile.php | 329 - modules/Import/Importer.php | 833 + modules/Import/UsersLastImport.php | 45 +- modules/Import/controller.php | 128 +- modules/Import/language/en_us.lang.php | 148 +- modules/Import/{ => maps}/ImportMap.php | 54 + modules/Import/{ => maps}/ImportMapAct.php | 2 +- modules/Import/{ => maps}/ImportMapCsv.php | 2 +- modules/Import/maps/ImportMapGoogle.php | 99 + modules/Import/{ => maps}/ImportMapOther.php | 0 .../Import/{ => maps}/ImportMapOutlook.php | 2 +- .../Import/{ => maps}/ImportMapSalesforce.php | 4 +- modules/Import/{ => maps}/ImportMapTab.php | 2 +- .../sources/ExternalSourceEAPMAdapter.php | 157 + modules/Import/sources/ImportDataSource.php | 345 + modules/Import/sources/ImportFile.php | 448 + modules/Import/tpls/confirm.tpl | 199 + modules/Import/tpls/confirm_table.tpl | 56 + modules/Import/tpls/dupcheck.tpl | 126 + modules/Import/tpls/error.tpl | 74 +- modules/Import/tpls/last.tpl | 147 +- modules/Import/tpls/listview.tpl | 95 + modules/Import/tpls/listviewpaginator.tpl | 86 + modules/Import/tpls/step1.tpl | 190 +- modules/Import/tpls/step2.tpl | 166 +- modules/Import/tpls/step3.tpl | 315 +- modules/Import/tpls/undo.tpl | 21 +- modules/Import/tpls/wizardWrapper.tpl | 76 + modules/Import/views/ImportListView.php | 177 + modules/Import/views/ImportView.php | 170 + modules/Import/views/view.confirm.php | 652 + modules/Import/views/view.dupcheck.php | 371 + modules/Import/views/view.extdupcheck.php | 117 + modules/Import/views/view.last.php | 306 +- modules/Import/views/view.step1.php | 467 +- modules/Import/views/view.step2.php | 313 +- modules/Import/views/view.step3.php | 664 +- modules/Import/views/view.step4.php | 645 +- modules/Import/views/view.undo.php | 57 +- modules/InboundEmail/InboundEmail.js | 3 +- modules/InboundEmail/Save.php | 1 + modules/Leads/Lead.php | 17 +- modules/Leads/language/en_us.lang.php | 18 +- modules/Leads/metadata/subpaneldefs.php | 2 +- modules/Leads/tpls/ConvertLead.tpl | 12 +- modules/Leads/tpls/ConvertLeadFooter.tpl | 75 + modules/Leads/tpls/ConvertLeadHeader.tpl | 34 + modules/Leads/vardefs.php | 49 +- modules/Leads/views/view.convertlead.php | 87 +- modules/MailMerge/Step2.html | 22 +- modules/MailMerge/controller.php | 21 +- .../MyMeetingsDashlet/MyMeetingsDashlet.php | 1 + modules/Meetings/Meeting.php | 20 +- modules/Meetings/MeetingFormBase.php | 4 +- modules/Meetings/Menu.php | 2 +- modules/Meetings/jsclass_scheduler.js | 14 +- modules/Meetings/language/en_us.lang.php | 32 +- modules/Meetings/metadata/editviewdefs.php | 12 +- modules/Meetings/metadata/quickcreatedefs.php | 10 +- modules/Meetings/tpls/footer.tpl | 47 +- modules/Meetings/vardefs.php | 23 +- modules/ModuleBuilder/MB/MBLanguage.php | 8 +- modules/ModuleBuilder/MB/MBVardefs.php | 19 +- modules/ModuleBuilder/Module/StudioModule.php | 7 +- modules/ModuleBuilder/controller.php | 31 +- .../ModuleBuilder/javascript/ModuleBuilder.js | 19 +- .../ModuleBuilder/javascript/SimpleList.js | 5 + modules/ModuleBuilder/javascript/studio2.js | 81 +- .../javascript/studio2FieldDD.js | 5 + .../ModuleBuilder/javascript/studio2ListDD.js | 6 +- .../javascript/studio2PanelDD.js | 40 +- .../ModuleBuilder/javascript/studio2RowDD.js | 26 +- modules/ModuleBuilder/language/en_us.lang.php | 2 + .../ModuleBuilder/parsers/parser.label.php | 1 + .../relationships/AbstractRelationship.php | 68 +- .../relationships/AbstractRelationships.php | 27 +- .../relationships/DeployedRelationships.php | 9 +- .../relationships/ManyToManyRelationship.php | 1 + .../relationships/ManyToOneRelationship.php | 1 + .../relationships/OneToManyRelationship.php | 5 +- .../relationships/OneToOneRelationship.php | 8 +- .../relationships/UndeployedRelationships.php | 51 +- .../views/GridLayoutMetaDataParser.php | 3 +- modules/ModuleBuilder/tpls/LayoutEditor.css | 2 +- .../ModuleBuilder/tpls/MBModule/vardef.tpl | 3 + .../ModuleBuilder/tpls/Preview/layoutView.tpl | 2 +- modules/ModuleBuilder/tpls/index.tpl | 4 +- modules/ModuleBuilder/tpls/labels.tpl | 2 + modules/ModuleBuilder/tpls/listView.tpl | 7 + modules/ModuleBuilder/views/view.dashlet.php | 2 +- modules/ModuleBuilder/views/view.dropdown.php | 4 + modules/ModuleBuilder/views/view.labels.php | 7 +- modules/ModuleBuilder/views/view.listview.php | 1 + modules/ModuleBuilder/views/view.main.php | 2 +- .../ModuleBuilder/views/view.modulefield.php | 11 +- .../ModuleBuilder/views/view.modulefields.php | 10 +- .../ModuleBuilder/views/view.popupview.php | 2 +- modules/MySettings/LoadTabSubpanels.php | 3 +- modules/Notes/Note.php | 3 +- modules/Notes/language/en_us.lang.php | 7 +- modules/Notes/vardefs.php | 1 + modules/OAuthKeys/OAuthKey.php | 90 + modules/OAuthKeys/controller.php | 46 + modules/OAuthKeys/language/en_us.lang.php | 64 + modules/OAuthKeys/metadata/SearchFields.php | 55 + modules/OAuthKeys/metadata/detailviewdefs.php | 65 + modules/OAuthKeys/metadata/editviewdefs.php | 52 + modules/OAuthKeys/metadata/listviewdefs.php | 53 + modules/OAuthKeys/metadata/metafiles.php | 46 + modules/OAuthKeys/metadata/searchdefs.php | 56 + modules/OAuthKeys/metadata/subpaneldefs.php | 56 + modules/OAuthKeys/vardefs.php | 86 + modules/OAuthTokens/OAuthToken.php | 246 + modules/OAuthTokens/action_view_map.php | 41 + modules/OAuthTokens/controller.php | 65 + modules/OAuthTokens/language/en_us.lang.php | 53 + .../metadata/subpanels/ForKeys.php | 79 + .../metadata/subpanels/ForUser.php | 79 + modules/OAuthTokens/tpl/authorize.tpl | 53 + modules/OAuthTokens/tpl/authorized.tpl | 39 + modules/OAuthTokens/vardefs.php | 195 + modules/OAuthTokens/views/view.authorize.php | 86 + modules/Opportunities/Menu.php | 2 +- modules/Opportunities/language/en_us.lang.php | 13 +- .../Opportunities/metadata/subpaneldefs.php | 7 +- modules/Opportunities/vardefs.php | 15 +- modules/Project/language/en_us.lang.php | 2 +- modules/ProjectTask/ProjectTask.php | 41 +- modules/ProspectLists/ProspectList.php | 25 +- modules/ProspectLists/Save.php | 6 +- modules/ProspectLists/vardefs.php | 6 + modules/Prospects/Menu.php | 2 +- modules/Prospects/language/en_us.lang.php | 14 +- modules/Prospects/vardefs.php | 3 + modules/Relationships/Relationship.php | 10 +- modules/Relationships/action_view_map.php | 38 + modules/Relationships/editFields.tpl | 115 + .../Relationships/views/view.editfields.php | 84 + modules/SavedSearch/SavedSearch.php | 3 +- modules/SavedSearch/index.php | 3 +- modules/Schedulers/Scheduler.php | 3 + modules/Schedulers/_AddJobsHere.php | 49 +- modules/SchedulersJobs/SchedulersJob.php | 4 +- modules/SchedulersJobs/vardefs.php | 2 - modules/Studio/DropDowns/DropDownHelper.php | 4 +- modules/Studio/TabGroups/TabGroupHelper.php | 3 + modules/Studio/language/en_us.lang.php | 8 +- modules/Studio/studio.js | 2 +- modules/Studio/wizards/RenameModules.php | 943 + modules/Studio/wizards/RenameModules.tpl | 258 + modules/Studio/wizards/StudioWizard.php | 7 +- .../Dashlets/SugarFeedDashlet/Options.tpl | 3 +- .../SugarFeedDashlet/SugarFeedDashlet.php | 16 +- modules/SugarFeed/language/en_us.lang.php | 14 +- modules/TableDictionary.php | 3 +- modules/Tasks/Task.php | 8 +- modules/Tasks/language/en_us.lang.php | 8 + modules/Tasks/metadata/editviewdefs.php | 2 +- modules/Tasks/vardefs.php | 1 + modules/UpgradeWizard/commit.php | 25 +- modules/UpgradeWizard/end.php | 7 + modules/UpgradeWizard/silentUpgrade_step1.php | 23 + modules/UpgradeWizard/silentUpgrade_step2.php | 4 + modules/UpgradeWizard/uw_utils.php | 6 +- modules/Users/Changenewpassword.php | 2 +- modules/Users/DetailView.php | 17 +- modules/Users/DetailView.tpl | 21 +- modules/Users/Save.php | 21 + modules/Users/User.php | 6 +- .../SugarAuthenticate/SugarAuthenticate.php | 2 +- modules/Users/language/en_us.lang.php | 59 +- modules/Users/metadata/subpaneldefs.php | 4 +- modules/Users/reassignUserRecords.php | 62 +- modules/Users/tpls/wizard.tpl | 46 +- modules/Users/vardefs.php | 58 +- modules/Users/views/view.list.php | 18 + modules/Users/views/view.wizard.php | 43 +- modules/vCals/vCal.php | 2 +- service/core/SoapHelperWebService.php | 95 +- service/v3/SugarWebServiceImplv3.php | 3 +- service/v3/SugarWebServiceUtilv3.php | 115 +- service/v3_1/SugarWebServiceUtilv3_1.php | 3 +- service/v4/SugarWebServiceImplv4.php | 173 +- service/v4/SugarWebServiceUtilv4.php | 149 +- soap/SoapHelperFunctions.php | 14 - soap/SoapPortalUsers.php | 5 +- sugar_version.php | 8 +- tests/ModuleInstall/ExtTest.php | 189 + tests/SugarTestHelper.php | 12 + tests/SugarTestImportUtilities.php | 11 +- tests/SugarTestMeetingUtilities.php | 17 + tests/SugarTestUserUtilities.php | 5 +- tests/data/Bug39780Test.php | 10 +- tests/data/Bug40989Test.php | 2 +- .../Bug47949Test.php} | 53 +- tests/include/Bug33806.php | 92 + .../include/ListView/ListViewDisplayTest.php | 5 +- tests/include/MVC/SugarApplicationTest.php | 37 +- tests/include/MVC/View/views/Bug47572Test.php | 61 + tests/include/SearchForm/Bug43452Test.php | 35 + tests/include/SearchForm/Bug46713Test.php | 120 + .../Smarty/plugins/FunctionSugarLinkTest.php | 10 +- .../SugarEmailAddress/Bug41557Test.php | 88 + .../Fields/Currency/Bug38424CurrencyTest.php | 1 + .../Fields/Float/Bug38424FloatTest.php | 1 + .../Fields/Int/Bug38424IntTest.php | 1 + .../include/SugarFolders/SugarFoldersTest.php | 11 +- tests/include/TimeDateTest.php | 33 +- tests/include/ValidDBNameTest.php | 16 +- .../generic/SugarWidgets/Bug44272Test.php | 14 +- tests/include/javascript/JSAlertsTest.php | 6 + tests/include/utils/Bug46122Test.php | 11 +- tests/include/utils/Bug46850Test.php | 166 + tests/modules/Administration/Bug36978Test.php | 2 +- tests/modules/Currencies/CurrencyTest.php | 4 +- tests/modules/DynamicFields/Bug43471Test.php | 1 + tests/modules/Emails/Bug45960Test.php | 91 + tests/modules/Employees/Bug46923Test.php | 88 + tests/modules/Home/Bug43653Test.php | 27 +- tests/modules/Import/Bug45907Test.csv | 11 + tests/modules/Import/Bug45907Test.php | 89 + tests/modules/Import/Bug45963Test.php | 64 + tests/modules/Import/Bug47737Test.php | 97 + tests/modules/Import/CsvAutoDetectTest.php | 116 + .../Import/ImportDuplicateCheckTest.php | 79 +- .../Import/ImportFieldSanitizeTest.php | 2 +- tests/modules/Import/ImportFileLimitTest.php | 81 + .../modules/Import/ImportFileSplitterTest.php | 4 +- tests/modules/Import/ImportFileTest.php | 221 +- tests/modules/Import/ImportFormsTest.php | 3 +- tests/modules/Import/ImportMapTest.php | 2 +- tests/modules/Import/ImporterTest.php | 122 + tests/modules/Import/TestCharset.csv | 2 + tests/modules/Import/TestCharset2.csv | 12 + tests/modules/Leads/Bug40209Test.php | 23 +- tests/modules/Leads/Bug45187Test.php | 97 + tests/modules/Leads/ConvertLeadTests.php | 367 +- .../modules/ModuleBuilder/MB/Bug39598Test.php | 36 + .../ModuleBuilder/Module/StudioModuleTest.php | 2 + .../ModuleBuilder/parsers/Bug45645Test.php | 64 + tests/modules/Notes/Bug40263Test.php | 14 +- tests/modules/Project/Bug37123Test.php | 1 + tests/modules/Reports/Bug47271Test.php | 78 + tests/modules/SNIP/SampleEvent.ics | 29 + tests/modules/Studio/RenameModulesTest.php | 253 + tests/modules/SubPanel/Bug40434Test.php | 36 + .../UpgradeCustomTemplateMetaTest.php | 50 +- .../Documents/metadata/editviewdefs.php | 4 +- .../modules/Calls/metadata/editviewdefs.php | 5 +- .../Documents/metadata/editviewdefs.php | 5 +- .../Documents/metadata/quickcreatedefs.php | 5 +- .../modules/Calls/metadata/editviewdefs.php | 9 +- .../Meetings/metadata/editviewdefs.php | 176 - tests/modules/Users/Bug46473Test.php | 88 + tests/service/Bug31003Test.php | 4 +- tests/service/Bug41296Test.php | 95 + tests/service/OAuthTest.php | 209 + tests/service/RESTAPI3Test.php | 20 +- tests/service/RESTAPI4Test.php | 92 + tests/tests/SugarTestLangPackCreatorTest.php | 8 + themes/Sugar5/css/style.css | 21 +- themes/Sugar5/js/style.js | 8 +- themes/Sugar5/tpls/_companyLogo.tpl | 2 +- themes/Sugar5/tpls/_head.tpl | 1 + themes/Sugar5/tpls/_headerModuleList.tpl | 5 + themes/Sugar5/tpls/footer.tpl | 7 +- themes/Sugar5/tpls/header.tpl | 22 +- themes/default/css/style.css | 2 +- themes/default/css/wizard.css | 3 +- themes/default/images/id-ff-down.png | Bin 0 -> 1325 bytes 650 files changed, 40726 insertions(+), 15608 deletions(-) create mode 100644 ModuleInstall/extensions.php create mode 100644 Zend/Gdata/Contacts.php create mode 100644 Zend/Gdata/Contacts/Extension/Address.php create mode 100644 Zend/Gdata/Contacts/Extension/Birthday.php create mode 100644 Zend/Gdata/Contacts/Extension/Email.php create mode 100644 Zend/Gdata/Contacts/Extension/Name.php create mode 100644 Zend/Gdata/Contacts/Extension/Organization.php create mode 100644 Zend/Gdata/Contacts/Extension/PhoneNumber.php create mode 100644 Zend/Gdata/Contacts/ListEntry.php create mode 100644 Zend/Gdata/Contacts/ListFeed.php create mode 100644 Zend/Oauth/Provider.php create mode 100644 data/BeanFactory.php create mode 100644 data/Link2.php create mode 100644 data/Relationships/EmailAddressRelationship.php create mode 100644 data/Relationships/M2MRelationship.php create mode 100644 data/Relationships/One2MBeanRelationship.php create mode 100644 data/Relationships/One2MRelationship.php create mode 100644 data/Relationships/One2OneBeanRelationship.php create mode 100644 data/Relationships/One2OneRelationship.php create mode 100644 data/Relationships/RelationshipFactory.php create mode 100644 data/Relationships/SugarRelationship.php create mode 100644 include/EditView/SubpanelQuickEdit.php create mode 100644 include/MVC/View/views/view.ajaxui.php create mode 100644 include/MVC/View/views/view.metadata.php create mode 100644 include/MVC/View/views/view.quickedit.php create mode 100644 include/Smarty/plugins/function.sugar_ajax_url.php create mode 100644 include/Smarty/plugins/modifier.lookup.php create mode 100644 include/Smarty/plugins/modifier.multienum_to_ac.php create mode 100644 include/SugarOAuthServer.php rename include/{SugarFields/Fields/Encrypt/SugarFieldEncrypt.php => connectors/sources/ext/eapm/eapm.php} (77%) create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelDeleteButton.php create mode 100644 include/generic/SugarWidgets/SugarWidgetSubPanelRelFieldEditButton.php create mode 100644 include/images/configure.png create mode 100644 include/images/create_users.png create mode 100644 include/images/import.png create mode 100644 include/images/settings.png create mode 100644 include/images/start.png create mode 100644 include/images/university2.png delete mode 100644 include/images/wiki.png create mode 100644 include/javascript/ajaxUI.js create mode 100644 include/javascript/importWizard.js create mode 100644 include/javascript/phpjs/get_html_translation_table.js create mode 100644 include/javascript/phpjs/html_entity_decode.js create mode 100644 include/javascript/phpjs/license.js create mode 100644 include/javascript/sugar_grp_jsolait.js create mode 100644 include/parsecsv.lib.php create mode 100644 jssource/src_files/include/javascript/ajaxUI.js create mode 100644 jssource/src_files/include/javascript/importWizard.js create mode 100644 jssource/src_files/include/javascript/phpjs/get_html_translation_table.js create mode 100644 jssource/src_files/include/javascript/phpjs/html_entity_decode.js create mode 100644 jssource/src_files/include/javascript/phpjs/license.js create mode 100644 metadata/oauth_nonce.php create mode 100644 modules/Administration/templates/ConfigureAjaxUI.tpl create mode 100644 modules/Administration/views/view.configureajaxui.php create mode 100644 modules/Emails/EditView.html create mode 100644 modules/Home/SubpanelEdits.php create mode 100644 modules/Import/CsvAutoDetect.php delete mode 100644 modules/Import/ImportFile.php create mode 100644 modules/Import/Importer.php rename modules/Import/{ => maps}/ImportMap.php (80%) rename modules/Import/{ => maps}/ImportMapAct.php (98%) rename modules/Import/{ => maps}/ImportMapCsv.php (97%) create mode 100644 modules/Import/maps/ImportMapGoogle.php rename modules/Import/{ => maps}/ImportMapOther.php (100%) rename modules/Import/{ => maps}/ImportMapOutlook.php (98%) rename modules/Import/{ => maps}/ImportMapSalesforce.php (97%) rename modules/Import/{ => maps}/ImportMapTab.php (97%) create mode 100644 modules/Import/sources/ExternalSourceEAPMAdapter.php create mode 100644 modules/Import/sources/ImportDataSource.php create mode 100644 modules/Import/sources/ImportFile.php create mode 100644 modules/Import/tpls/confirm.tpl create mode 100644 modules/Import/tpls/confirm_table.tpl create mode 100644 modules/Import/tpls/dupcheck.tpl create mode 100644 modules/Import/tpls/listview.tpl create mode 100644 modules/Import/tpls/listviewpaginator.tpl create mode 100644 modules/Import/tpls/wizardWrapper.tpl create mode 100644 modules/Import/views/ImportListView.php create mode 100644 modules/Import/views/ImportView.php create mode 100644 modules/Import/views/view.confirm.php create mode 100644 modules/Import/views/view.dupcheck.php create mode 100644 modules/Import/views/view.extdupcheck.php create mode 100644 modules/OAuthKeys/OAuthKey.php create mode 100644 modules/OAuthKeys/controller.php create mode 100644 modules/OAuthKeys/language/en_us.lang.php create mode 100644 modules/OAuthKeys/metadata/SearchFields.php create mode 100644 modules/OAuthKeys/metadata/detailviewdefs.php create mode 100644 modules/OAuthKeys/metadata/editviewdefs.php create mode 100644 modules/OAuthKeys/metadata/listviewdefs.php create mode 100644 modules/OAuthKeys/metadata/metafiles.php create mode 100644 modules/OAuthKeys/metadata/searchdefs.php create mode 100644 modules/OAuthKeys/metadata/subpaneldefs.php create mode 100644 modules/OAuthKeys/vardefs.php create mode 100644 modules/OAuthTokens/OAuthToken.php create mode 100644 modules/OAuthTokens/action_view_map.php create mode 100644 modules/OAuthTokens/controller.php create mode 100644 modules/OAuthTokens/language/en_us.lang.php create mode 100644 modules/OAuthTokens/metadata/subpanels/ForKeys.php create mode 100644 modules/OAuthTokens/metadata/subpanels/ForUser.php create mode 100644 modules/OAuthTokens/tpl/authorize.tpl create mode 100644 modules/OAuthTokens/tpl/authorized.tpl create mode 100644 modules/OAuthTokens/vardefs.php create mode 100644 modules/OAuthTokens/views/view.authorize.php create mode 100644 modules/Relationships/action_view_map.php create mode 100644 modules/Relationships/editFields.tpl create mode 100644 modules/Relationships/views/view.editfields.php create mode 100644 modules/Studio/wizards/RenameModules.php create mode 100644 modules/Studio/wizards/RenameModules.tpl create mode 100755 tests/ModuleInstall/ExtTest.php rename tests/{include/SugarFields/Fields/Encrypt/SugarFieldEncryptTest.php => data/Bug47949Test.php} (70%) create mode 100755 tests/include/Bug33806.php create mode 100755 tests/include/MVC/View/views/Bug47572Test.php create mode 100755 tests/include/SearchForm/Bug46713Test.php create mode 100755 tests/include/SugarEmailAddress/Bug41557Test.php create mode 100755 tests/include/utils/Bug46850Test.php create mode 100755 tests/modules/Emails/Bug45960Test.php create mode 100755 tests/modules/Employees/Bug46923Test.php create mode 100755 tests/modules/Import/Bug45907Test.csv create mode 100755 tests/modules/Import/Bug45907Test.php create mode 100755 tests/modules/Import/Bug45963Test.php create mode 100755 tests/modules/Import/Bug47737Test.php create mode 100755 tests/modules/Import/CsvAutoDetectTest.php create mode 100755 tests/modules/Import/ImportFileLimitTest.php create mode 100755 tests/modules/Import/ImporterTest.php create mode 100755 tests/modules/Import/TestCharset.csv create mode 100755 tests/modules/Import/TestCharset2.csv create mode 100755 tests/modules/Leads/Bug45187Test.php create mode 100755 tests/modules/ModuleBuilder/parsers/Bug45645Test.php create mode 100755 tests/modules/Reports/Bug47271Test.php create mode 100755 tests/modules/SNIP/SampleEvent.ics create mode 100755 tests/modules/Studio/RenameModulesTest.php delete mode 100755 tests/modules/UpgradeWizard/SugarMerge/metadata_files/611/modules/Meetings/metadata/editviewdefs.php create mode 100755 tests/modules/Users/Bug46473Test.php create mode 100755 tests/service/Bug41296Test.php create mode 100755 tests/service/OAuthTest.php create mode 100644 themes/default/images/id-ff-down.png diff --git a/ModuleInstall/ModuleInstaller.php b/ModuleInstall/ModuleInstaller.php index 91db83af..90cb6382 100644 --- a/ModuleInstall/ModuleInstaller.php +++ b/ModuleInstall/ModuleInstaller.php @@ -60,12 +60,14 @@ class ModuleInstaller{ var $silent = false; var $base_dir = ''; var $modulesInPackage = array(); + public $disabled_path = DISABLED_PATH; function ModuleInstaller(){ $this->ms = new ModuleScanner(); $this->modules = get_module_dir_list(); $this->db = & DBManagerFactory::getInstance(); - + include("ModuleInstall/extensions.php"); + $this->extensions = $extensions; } /* @@ -87,6 +89,15 @@ class ModuleInstaller{ } } + // workaround for bug 45812 - refresh vardefs cache before unpacking to avoid partial vardefs in cache + global $beanList; + foreach ($this->modules as $module_name) { + if (!empty($beanList[$module_name])) { + $objectName = BeanFactory::getObjectName($module_name); + VardefManager::loadVardef($module_name, $objectName); + } + } + global $app_strings, $mod_strings; $this->base_dir = $base_dir; $total_steps = 5; //minimum number of steps with no tasks @@ -94,19 +105,14 @@ class ModuleInstaller{ $tasks = array( 'pre_execute', 'install_copy', + 'install_extensions', 'install_images', - 'install_menus', 'install_dcactions', - 'install_userpage', 'install_dashlets', - 'install_administration', 'install_connectors', - 'install_vardefs', - 'install_layoutdefs', 'install_layoutfields', 'install_relationships', - 'install_languages', - 'install_logichooks', + 'enable_manifest_logichooks', 'post_execute', 'reset_opcodes', ); @@ -136,41 +142,6 @@ class ModuleInstaller{ }//fi $this->id_name = $installdefs['id']; $this->installdefs = $installdefs; - $installed_modules = array(); - $tab_modules = array(); - if(isset($installdefs['beans'])){ - $str = "install_user_prefs($module, empty($bean['hide_by_default'])); - $tab_modules[] = $module; - }else{ - $str .= "\$modules_exempt_from_availability_check['$module'] = '$module';\n"; - $str .= "\$modInvisList[] = '$module';\n"; - } - $installed_modules[] = $module; - }else{ - $errors[] = 'Bean array not well defined.'; - $this->abort($errors); - } - } - $str.= "\n?>"; - if(!file_exists("custom/Extension/application/Ext/Include")){ - mkdir_recursive("custom/Extension/application/Ext/Include", true); - } - $out = sugar_fopen("custom/Extension/application/Ext/Include/$this->id_name.php", 'w'); - fwrite($out,$str); - fclose($out); - $this->rebuild_modules(); - } if(!$this->silent){ $current_step++; update_progress_bar('install', $current_step, $total_steps); @@ -183,7 +154,7 @@ class ModuleInstaller{ update_progress_bar('install', $current_step, $total_steps); } } - $this->install_beans($installed_modules); + $this->install_beans($this->installed_modules); if(!$this->silent){ $current_step++; update_progress_bar('install', $total_steps, $total_steps); @@ -218,18 +189,23 @@ class ModuleInstaller{ include('custom/application/Ext/Include/modules.ext.php'); } require_once("modules/Administration/upgrade_custom_relationships.php"); - upgrade_custom_relationships($installed_modules); + upgrade_custom_relationships($this->installed_modules); $this->rebuild_all(true); require_once('modules/Administration/QuickRepairAndRebuild.php'); $rac = new RepairAndClear(); - $rac->repairAndClearAll($selectedActions, $installed_modules,true, false); + $rac->repairAndClearAll($selectedActions, $this->installed_modules,true, false); $this->rebuild_relationships(); - UpdateSystemTabs('Add',$tab_modules); - - //clear the unified_search_module.php file + UpdateSystemTabs('Add',$this->tab_modules); + //Clear out all the langauge cache files. + clearAllJsAndJsLangFilesWithoutOutput(); + $cache_key = 'app_list_strings.'.$GLOBALS['current_language']; + sugar_cache_clear($cache_key ); + sugar_cache_reset(); + + //clear the unified_search_module.php file require_once('modules/Home/UnifiedSearchAdvanced.php'); - UnifiedSearchAdvanced::unlinkUnifiedSearchModulesFile(); - + UnifiedSearchAdvanced::unlinkUnifiedSearchModulesFile(); + $this->log('
' . translate('LBL_MI_COMPLETE') . ''); }else{ die("No \$installdefs Defined In $this->base_dir/manifest.php"); @@ -357,8 +333,290 @@ class ModuleInstaller{ } + /** + * Get directory where module's extensions go + * @param string $module Module name + */ + public function getExtDir($module) + { + if($module == 'application') { + return "custom/Extension/application/Ext"; + } else { + return "custom/Extension/modules/$module/Ext"; + } + } + + /** + * Install file(s) into Ext/ part + * @param string $section Name of the install file section + * @param string $extname Name in Ext directory + * @param string $module This extension belongs to a specific module + */ + public function installExt($section, $extname, $module = '') + { + if(isset($this->installdefs[$section])){ + $this->log(sprintf(translate("LBL_MI_IN_EXT"), $section)); + foreach($this->installdefs[$section] as $item){ + if(isset($item['from'])) { + $from = str_replace('', $this->base_dir, $item['from']); + } else { + $from = ''; + } + if(!empty($module)) { + $item['to_module'] = $module; + } + $GLOBALS['log']->debug("Installing section $section from $from for " .$item['to_module'] ); + if($item['to_module'] == 'application') { + $path = "custom/Extension/application/Ext/$extname"; + } else { + $path = "custom/Extension/modules/{$item['to_module']}/Ext/$extname"; + } + if(!file_exists($path)){ + mkdir_recursive($path, true); + } + if(isset($item["name"])) { + $target = $item["name"]; + } else if (!empty($from)){ + $target = basename($from, ".php"); + } else { + $target = $this->id_name; + } + if(!empty($from)) { + copy_recursive($from , "$path/$target.php"); + } + } + } + } + + /** + * Uninstall file(s) into Ext/ part + * @param string $section Name of the install file section + * @param string $extname Name in Ext directory + * @param string $module This extension belongs to a specific module + */ + public function uninstallExt($section, $extname, $module = '') + { + if(isset($this->installdefs[$section])){ + $this->log(sprintf(translate("LBL_MI_UN_EXT"), $section)); + foreach($this->installdefs[$section] as $item){ + if(isset($item['from'])) { + $from = str_replace('', $this->base_dir, $item['from']); + } else { + $from = ''; + } + if(!empty($module)) { + $item['to_module'] = $module; + } + $GLOBALS['log']->debug("Uninstalling section $section from $from for " .$item['to_module'] ); + if($item['to_module'] == 'application') { + $path = "custom/Extension/application/Ext/$extname"; + } else { + $path = "custom/Extension/modules/{$item['to_module']}/Ext/$extname"; + } + if(isset($item["name"])) { + $target = $item["name"]; + } else if (!empty($from)){ + $target = basename($from, ".php"); + } else { + $target = $this->id_name; + } + $disabled_path = $path.'/'.DISABLED_PATH; + if (file_exists("$path/$target.php")) { + rmdir_recursive("$path/$target.php"); + } else if (file_exists("$disabled_path/$target.php")) { + rmdir_recursive("$disabled_path/$target.php"); + } else if (!empty($from) && file_exists($path . '/'. basename($from))) { + rmdir_recursive( $path . '/'. basename($from)); + } else if (!empty($from) && file_exists($disabled_path . '/'. basename($from))) { + rmdir_recursive( $disabled_path . '/'. basename($from)); + } + } + } + } + + /** + * Rebuild generic extension + * @param string $ext Extension directory + * @param string $filename Target filename + */ + public function rebuildExt($ext, $filename) + { + $this->log(translate('LBL_MI_REBUILDING') . " $ext..."); + $this->merge_files("Ext/$ext/", $filename); + } + + /** + * Disable generic extension + * @param string $section Install file section name + * @param string $extname Extension directory + * @param string $module This extension belongs to a specific module + */ + public function disableExt($section, $extname, $module = '') + { + if(isset($this->installdefs[$section])) { + foreach($this->installdefs[$section] as $item) { + if(isset($item['from'])) { + $from = str_replace('', $this->base_dir, $item['from']); + } else { + $from = ''; + } + if(!empty($module)) { + $item['to_module'] = $module; + } + $GLOBALS['log']->debug("Disabling $extname ... from $from for " .$item['to_module']); + if($item['to_module'] == 'application') { + $path = "custom/Extension/application/Ext/$extname"; + } else { + $path = "custom/Extension/modules/{$item['to_module']}/Ext/$extname"; + } + if(isset($item["name"])) { + $target = $item["name"]; + } else if (!empty($from)){ + $target = basename($from, ".php"); + }else { + $target = $this->id_name; + } + $disabled_path = $path.'/'.DISABLED_PATH; + if (file_exists("$path/$target.php")) { + mkdir_recursive($disabled_path, true); + rename("$path/$target.php", "$disabled_path/$target.php"); + } else if (!empty($from) && file_exists($path . '/'. basename($from))) { + mkdir_recursive($disabled_path, true); + rename( $path . '/'. basename($from), $disabled_path.'/'. basename($from)); + } + } + } + } + + /** + * Enable generic extension + * @param string $section Install file section name + * @param string $extname Extension directory + * @param string $module This extension belongs to a specific module + */ + public function enableExt($section, $extname, $module = '') + { + if(isset($this->installdefs[$section])) { + foreach($this->installdefs[$section] as $item) { + if(isset($item['from'])) { + $from = str_replace('', $this->base_dir, $item['from']); + } else { + $from = ''; + } + if(!empty($module)) { + $item['to_module'] = $module; + } + $GLOBALS['log']->debug("Enabling $extname ... from $from for " .$item['to_module']); + + if($item['to_module'] == 'application') { + $path = "custom/Extension/application/Ext/$extname"; + } else { + $path = "custom/Extension/modules/{$item['to_module']}/Ext/$extname"; + } + if(isset($item["name"])) { + $target = $item["name"]; + } else if (!empty($from)){ + $target = basename($from, ".php"); + } else { + $target = $this->id_name; + } + if(!file_exists($path)) { + mkdir_recursive($path, true); + } + $disabled_path = $path.'/'.DISABLED_PATH; + if (file_exists("$disabled_path/$target.php")) { + rename("$disabled_path/$target.php", "$path/$target.php"); + } + if (!empty($from) && file_exists($disabled_path . '/'. basename($from))) { + rename($disabled_path.'/'. basename($from), $path . '/'. basename($from)); + } + } + } + } + + public function install_extensions() + { + foreach($this->extensions as $extname => $ext) { + $install = "install_$extname"; + if(method_exists($this, $install)) { + // non-standard function + $this->$install(); + } else { + if(!empty($ext["section"])) { + $module = isset($ext['module'])?$ext['module']:''; + $this->installExt($ext["section"], $ext["extdir"], $module); + } + } + } + $this->rebuild_extensions(); + } + + public function uninstall_extensions() + { + foreach($this->extensions as $extname => $ext) { + $func = "uninstall_$extname"; + if(method_exists($this, $func)) { + // non-standard function + $this->$func(); + } else { + if(!empty($ext["section"])) { + $module = isset($ext['module'])?$ext['module']:''; + $this->uninstallExt($ext["section"], $ext["extdir"], $module); + } + } + } + $this->rebuild_extensions(); + } + + public function rebuild_extensions() + { + foreach($this->extensions as $extname => $ext) { + $func = "rebuild_$extname"; + if(method_exists($this, $func)) { + // non-standard function + $this->$func(); + } else { + $this->rebuildExt($ext["extdir"], $ext["file"]); + } + } + } - function install_dashlets(){ + public function disable_extensions() + { + foreach($this->extensions as $extname => $ext) { + $func = "disable_$extname"; + if(method_exists($this, $func)) { + // non-standard install + $this->$func(); + } else { + if(!empty($ext["section"])) { + $module = isset($ext['module'])?$ext['module']:''; + $this->disableExt($ext["section"], $ext["extdir"], $module); + } + } + } + $this->rebuild_extensions(); + } + + public function enable_extensions() + { + foreach($this->extensions as $extname => $ext) { + $func = "enable_$extname"; + if(method_exists($this, $func)) { + // non-standard install + $this->$func(); + } else { + if(!empty($ext["section"])) { + $module = isset($ext['module'])?$ext['module']:''; + $this->enableExt($ext["section"], $ext["extdir"], $module); + } + } + } + $this->rebuild_extensions(); + } + + function install_dashlets() + { if(isset($this->installdefs['dashlets'])){ foreach($this->installdefs['dashlets'] as $cp){ $this->log(translate('LBL_MI_IN_DASHLETS') . $cp['name']); @@ -397,49 +655,6 @@ class ModuleInstaller{ } } - function install_menus(){ - if(isset($this->installdefs['menu'])){ - $this->log(translate('LBL_MI_IN_MENUS')); - foreach($this->installdefs['menu'] as $menu){ - $menu['from'] = str_replace('', $this->base_dir, $menu['from']); - $GLOBALS['log']->debug("Installing Menu ..." . $menu['from']. " for " .$menu['to_module'] ); - $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus'; - if($menu['to_module'] == 'application'){ - $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus'; - } - if(!file_exists($path)){ - mkdir_recursive($path, true); - - } - copy_recursive($menu['from'] , $path . '/'. $this->id_name . '.php'); - } - $this->rebuild_menus(); - } - } - - function uninstall_menus(){ - if(isset($this->installdefs['menu'])){ - $this->log(translate('LBL_MI_UN_MENUS')); - foreach($this->installdefs['menu'] as $menu){ - $menu['from'] = str_replace('', $this->base_dir, $menu['from']); - $GLOBALS['log']->debug("Uninstalling Menu ..." . $menu['from']. " for " .$menu['to_module'] ); - $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus'; - if($menu['to_module'] == 'application'){ - $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus'; - } - if (sugar_is_file($path . '/'. $this->id_name . '.php', 'w')) - { - rmdir_recursive( $path . '/'. $this->id_name . '.php'); - } - else if (sugar_is_file($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php', 'w')) - { - rmdir_recursive( $path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php'); - } - } - $this->rebuild_menus(); - } - } - function install_dcactions(){ if(isset($this->installdefs['dcaction'])){ $this->log(translate('LBL_MI_IN_MENUS')); @@ -476,39 +691,6 @@ class ModuleInstaller{ } } - function install_administration(){ - if(isset($this->installdefs['administration'])){ - $this->log(translate('LBL_MI_IN_ADMIN')); - foreach($this->installdefs['administration'] as $administration){ - $administration['from'] = str_replace('', $this->base_dir, $administration['from']); - $GLOBALS['log']->debug("Installing Administration Section ..." . $administration['from'] ); - $path = 'custom/Extension/modules/Administration/Ext/Administration'; - if(!file_exists($path)){ - mkdir_recursive($path, true); - - } - copy_recursive($administration['from'] , $path . '/'. $this->id_name . '.php'); - } - $this->rebuild_administration(); - } - - } - function uninstall_administration(){ - if(isset($this->installdefs['administration'])){ - $this->log(translate('LBL_MI_UN_ADMIN')); - foreach($this->installdefs['administration'] as $administration){ - $administration['from'] = str_replace('', $this->base_dir, $administration['from']); - $GLOBALS['log']->debug("Uninstalling Administration Section ..." . $administration['from'] ); - $path = 'custom/Extension/modules/Administration/Ext/Administration'; - if (sugar_is_file($path . '/'. $this->id_name . '.php', "w")) - rmdir_recursive( $path . '/'. $this->id_name . '.php'); - else if (sugar_is_file($path . '/'. DISABLED_PATH . "/" . $this->id_name . '.php', "w")) - rmdir_recursive( $path . '/'. DISABLED_PATH . "/" . $this->id_name . '.php'); - } - $this->rebuild_administration(); - } - } - function install_connectors(){ if(isset($this->installdefs['connectors'])){ foreach($this->installdefs['connectors'] as $cp){ @@ -554,82 +736,8 @@ class ModuleInstaller{ } } - function install_userpage(){ - if(isset($this->installdefs['user_page'])){ - $this->log(translate('LBL_MI_IN_USER')); - foreach($this->installdefs['user_page'] as $userpage){ - $userpage['from'] = str_replace('', $this->base_dir, $userpage['from']); - $GLOBALS['log']->debug("Installing User Page Section ..." . $userpage['from'] ); - $path = 'custom/Extension/modules/Users/Ext/UserPage'; - if(!file_exists($path)){ - mkdir_recursive($path, true); - - } - copy_recursive($userpage['from'] , $path . '/'. $this->id_name . '.php'); - } - $this->rebuild_userpage(); - } - - } - function uninstall_userpage(){ - if(isset($this->installdefs['user_page'])){ - $this->log(translate('LBL_MI_UN_USER') ); - foreach($this->installdefs['user_page'] as $userpage){ - $userpage['from'] = str_replace('', $this->base_dir, $userpage['from']); - $GLOBALS['log']->debug("Uninstalling User Page Section ..." . $userpage['from'] ); - $path = 'custom/Extension/modules/Users/Ext/UserPage'; - rmdir_recursive( $path . '/'. $this->id_name . '.php'); - } - $this->rebuild_userpage(); - } - } - - /* - * ModuleInstaller->install_vardefs uses the vardefs section of the installdefs and copies from the 'from' path (replacing as usual) to either - * custom/Extension/modules//Ext/Vardefs or custom/Extension//Ext/Vardefs if the 'to_module' value in the installdefs is set to 'application'. - * Finally rebuild_vardefs() is used to merge /Ext/Vardefs into vardefs.ext.php - */ - function install_vardefs(){ - if(isset($this->installdefs['vardefs'])){ - $this->log(translate('LBL_MI_IN_VAR') ); - foreach($this->installdefs['vardefs'] as $vardefs){ - $vardefs['from'] = str_replace('', $this->base_dir, $vardefs['from']); - $this->install_vardef($vardefs['from'], $vardefs['to_module'], $this->id_name); - } - $this->rebuild_vardefs(); - } - } - function uninstall_vardefs(){ - if(isset($this->installdefs['vardefs'])){ - $this->log(translate('LBL_MI_UN_VAR') ); - foreach($this->installdefs['vardefs'] as $vardefs){ - $vardefs['from'] = str_replace('', $this->base_dir, $vardefs['from']); - $GLOBALS['log']->debug("Uninstalling Vardefs ..." . $vardefs['from'] . " for " .$vardefs['to_module']); - $path = 'custom/Extension/modules/' . $vardefs['to_module']. '/Ext/Vardefs'; - if($vardefs['to_module'] == 'application'){ - $path ='custom/Extension/' . $vardefs['to_module']. '/Ext/Vardefs'; - } - if(file_exists($path . '/'. $this->id_name . '.php')) - { - rmdir_recursive( $path . '/'. $this->id_name . '.php'); - } - else if(file_exists($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php')) - { - rmdir_recursive($path . '/'. DISABLED_PATH . '/'. $this->id_name . '.php'); - } - else if (file_exists($path . '/'. basename($vardefs['from'] ))) - { - rmdir_recursive( $path . '/'. basename($vardefs['from'] )); - } - else if(file_exists($path . '/'. DISABLED_PATH . '/'. basename($vardefs['from']))) - { - rmdir_recursive($path . '/'. DISABLED_PATH . '/'. basename($vardefs['from'])); - } - } - $this->rebuild_vardefs(); - } - } - function install_vardef($from, $to_module){ + function install_vardef($from, $to_module) + { $GLOBALS['log']->debug("Installing Vardefs ..." . $from . " for " .$to_module); $path = 'custom/Extension/modules/' . $to_module. '/Ext/Vardefs'; if($to_module == 'application'){ @@ -641,50 +749,6 @@ class ModuleInstaller{ copy_recursive($from , $path.'/'. basename($from)); } - /* - * ModuleInstaller->install_layoutdefs installs the $layout_defs variable (subpanel definitions) from Ext/Layoutdefs to the to_module location of - * custom/Extension/modules/' . $to_module. '/Ext/Layoutdefs/<$module>.php. before calling rebuild_layoutdefs which merge_files Ext/Layoutdefs/, 'layoutdefs.ext.php'. Note that this is not used for the viewdefs in the metadata directory - they are installed through the install_copy() operation that just takes the contents of the module directory and places it in the /modules area. - */ - function install_layoutdefs(){ - if(isset($this->installdefs['layoutdefs'])){ - $this->log(translate('LBL_MI_IN_SUBPANEL') ); - foreach($this->installdefs['layoutdefs'] as $layoutdefs){ - $layoutdefs['from'] = str_replace('', $this->base_dir, $layoutdefs['from']); - $this->install_layoutdef($layoutdefs['from'], $layoutdefs['to_module'], $this->id_name); - } - $this->rebuild_layoutdefs(); - } - } - function uninstall_layoutdefs(){ - if(isset($this->installdefs['layoutdefs'])){ - $this->log(translate('LBL_MI_UN_SUBPANEL') ); - foreach($this->installdefs['layoutdefs'] as $layoutdefs){ - $layoutdefs['from'] = str_replace('', $this->base_dir, $layoutdefs['from']); - $GLOBALS['log']->debug("Uninstalling Layoutdefs ..." . $layoutdefs['from'] . " for " .$layoutdefs['to_module']); - $path = 'custom/Extension/modules/' . $layoutdefs['to_module']. '/Ext/Layoutdefs'; - if($layoutdefs['to_module'] == 'application'){ - $path ='custom/Extension/' . $layoutdefs['to_module']. '/Ext/Layoutdefs'; - } - if (file_exists($path . '/'. $this->id_name . '.php')) - { - rmdir_recursive( $path . '/'. $this->id_name . '.php'); - } - else if (file_exists($path . '/'. DISABLED_PATH . '/' . $this->id_name . '.php')) - { - rmdir_recursive($path . '/'. DISABLED_PATH . '/' . $this->id_name . '.php'); - } - else if (file_exists($path . '/'. basename($layoutdefs['from'] ))) - { - rmdir_recursive( $path . '/'. basename($layoutdefs['from'] )); - } - else if(file_exists($path . '/'. DISABLED_PATH . '/'. basename($layoutdefs['from']))) - { - rmdir_recursive($path . '/'. DISABLED_PATH . '/'. basename($layoutdefs['from'])); - } - } - $this->rebuild_layoutdefs(); - } - } function install_layoutdef($from, $to_module){ $GLOBALS['log']->debug("Installing Layout Defs ..." . $from . " for " .$to_module); $path = 'custom/Extension/modules/' . $to_module. '/Ext/Layoutdefs'; @@ -697,6 +761,7 @@ class ModuleInstaller{ copy_recursive($from , $path.'/'. basename($from)); } + // Non-standard - needs special rebuild call function install_languages() { $languages = array(); @@ -724,6 +789,7 @@ class ModuleInstaller{ } } + // Non-standard, needs special rebuild function uninstall_languages(){ $languages = array(); if(isset($this->installdefs['language'])){ @@ -748,6 +814,81 @@ class ModuleInstaller{ } } + // Non-standard, needs special rebuild + public function disable_languages() + { + if(isset($this->installdefs['language'])) { + $languages = $modules = array(); + foreach($this->installdefs['language'] as $item) { + $from = str_replace('', $this->base_dir, $item['from']); + $GLOBALS['log']->debug("Disabling Language {$item['language']}... from $from for " .$item['to_module']); + $modules[]=$item['to_module']; + $languages[$item['language']] = $item['language']; + if($item['to_module'] == 'application') { + $path = "custom/Extension/application/Ext/Language"; + } else { + $path = "custom/Extension/modules/{$item['to_module']}/Ext/Language"; + } + if(isset($item["name"])) { + $target = $item["name"]; + } else { + $target = $this->id_name; + } + $target = "{$item['language']}.$target"; + + $disabled_path = $path.'/'.DISABLED_PATH; + if (file_exists("$path/$target.php")) { + mkdir_recursive($disabled_path, true); + rename("$path/$target.php", "$disabled_path/$target.php"); + } else if (file_exists($path . '/'. basename($from))) { + mkdir_recursive($disabled_path, true); + rename( $path . '/'. basename($from), $disabled_path.'/'. basename($from)); + } + } + $this->rebuild_languages($languages, $modules); + } + } + + // Non-standard, needs special rebuild + public function enable_languages() + { + if(isset($this->installdefs['language'])) { + foreach($this->installdefs['language'] as $item) { + $from = str_replace('', $this->base_dir, $item['from']); + $GLOBALS['log']->debug("Enabling Language {$item['language']}... from $from for " .$item['to_module']); + $modules[]=$item['to_module']; + $languages[$item['language']] = $item['language']; + if(!empty($module)) { + $item['to_module'] = $module; + } + + if($item['to_module'] == 'application') { + $path = "custom/Extension/application/Ext/Language"; + } else { + $path = "custom/Extension/modules/{$item['to_module']}/Ext/Language"; + } + if(isset($item["name"])) { + $target = $item["name"]; + } else { + $target = $this->id_name; + } + $target = "{$item['language']}.$target"; + + if(!file_exists($path)) { + mkdir_recursive($path, true); + } + $disabled_path = $path.'/'.DISABLED_PATH; + if (file_exists("$disabled_path/$target.php")) { + rename("$disabled_path/$target.php", "$path/$target.php"); + } + if (file_exists($disabled_path . '/'. basename($from))) { + rename($disabled_path.'/'. basename($from), $path . '/'. basename($from)); + } + } + $this->rebuild_languages($languages, $modules); + } + } + // Functions for adding and removing logic hooks from uploaded files // Since one class/file can be used by multiple logic hooks, I'm not going to touch the file labeled in the logic_hook entry /* The module hook definition should look like this: @@ -766,17 +907,7 @@ class ModuleInstaller{ ... blah blah ... ); */ - function install_logichooks() { - // Since the logic hook files get copied over with the rest of the module directory, we just need to enable them - $this->enable_logichooks(); - } - - function uninstall_logichooks() { - // Since the logic hook files get removed with the rest of the module directory, we just need to disable them - $this->disable_logichooks(); - } - - function enable_logichooks() { + function enable_manifest_logichooks() { if(empty($this->installdefs['logic_hooks']) || !is_array($this->installdefs['logic_hooks'])) { return; } @@ -788,12 +919,11 @@ class ModuleInstaller{ } } - function disable_logichooks() { + function disable_manifest_logichooks() { if(empty($this->installdefs['logic_hooks']) || !is_array($this->installdefs['logic_hooks'])) { return; } - foreach($this->installdefs['logic_hooks'] as $hook ) { remove_logic_hook($hook['module'], $hook['hook'], array($hook['order'], $hook['description'], $hook['file'], $hook['class'], $hook['function'])); } @@ -929,13 +1059,16 @@ class ModuleInstaller{ + + Relationship::delete_cache(); $this->rebuild_vardefs () ; $this->rebuild_layoutdefs () ; if ($save_table_dictionary) { $this->rebuild_tabledictionary () ; } - + require_once("data/Relationships/RelationshipFactory.php"); + SugarRelationshipFactory::deleteCache(); } } @@ -1087,7 +1220,9 @@ class ModuleInstaller{ //Find all the relatioships/relate fields involving this module. $rels_to_remove = array(); foreach($beanList as $mod => $bean) { - VardefManager::loadVardef($mod, $bean); + //Some modules like cases have a bean name that doesn't match the object name + $bean = BeanFactory::getObjectName($mod); + VardefManager::loadVardef($mod, $bean); //We can skip modules that are in this package as they will be removed anyhow if (!in_array($mod, $this->modulesInPackage) && !empty($dictionary[$bean]) && !empty($dictionary[$bean]['fields'])) { @@ -1178,16 +1313,11 @@ class ModuleInstaller{ 'uninstall_relationships', 'uninstall_copy', 'uninstall_dcactions', - 'uninstall_menus', 'uninstall_dashlets', - 'uninstall_userpage', - 'uninstall_administration', 'uninstall_connectors', - 'uninstall_vardefs', - 'uninstall_layoutdefs', 'uninstall_layoutfields', - 'uninstall_languages', - 'uninstall_logichooks', + 'uninstall_extensions', + 'disable_manifest_logichooks', 'post_uninstall', ); $total_steps += count($tasks); //now the real number of steps @@ -1204,7 +1334,6 @@ class ModuleInstaller{ $this->id_name = $this->installdefs['id']; $installed_modules = array(); if(isset($this->installdefs['beans'])){ - foreach($this->installdefs['beans'] as $bean){ $installed_modules[] = $bean['module']; @@ -1217,19 +1346,11 @@ class ModuleInstaller{ $current_step++; update_progress_bar('install', $total_steps, $total_steps); } - if (sugar_is_file("custom/Extension/application/Ext/Include/$this->id_name.php", 'w')) - rmdir_recursive("custom/Extension/application/Ext/Include/$this->id_name.php"); - else if(sugar_is_file("custom/Extension/application/Ext/Include/" . DISABLED_PATH . "/$this->id_name.php", 'w')) - rmdir_recursive("custom/Extension/application/Ext/Include/" . DISABLED_PATH . "/$this->id_name.php"); - - $this->rebuild_modules(); } if(!$this->silent){ $current_step++; update_progress_bar('install', $current_step, $total_steps); } - - foreach($tasks as $task){ $this->$task(); if(!$this->silent){ @@ -1266,10 +1387,10 @@ class ModuleInstaller{ UpdateSystemTabs('Restore',$installed_modules); - //clear the unified_search_module.php file + //clear the unified_search_module.php file require_once('modules/Home/UnifiedSearchAdvanced.php'); - UnifiedSearchAdvanced::unlinkUnifiedSearchModulesFile(); - + UnifiedSearchAdvanced::unlinkUnifiedSearchModulesFile(); + $this->log('
' . translate('LBL_MI_COMPLETE') . ''); if(!$this->silent){ update_progress_bar('install', $total_steps, $total_steps); @@ -1279,7 +1400,8 @@ class ModuleInstaller{ } } - function rebuild_languages($languages, $modules=""){ + function rebuild_languages($languages = array(), $modules="") + { foreach($languages as $language=>$value){ $this->log(translate('LBL_MI_REBUILDING') . " Language...$language"); $this->merge_files('Ext/Language/', $language.'.lang.ext.php', $language); @@ -1290,24 +1412,12 @@ class ModuleInstaller{ } } sugar_cache_reset(); - - } - - function rebuild_vardefs(){ - $this->log(translate('LBL_MI_REBUILDING') . " Vardefs..."); - $this->merge_files('Ext/Vardefs/', 'vardefs.ext.php'); - sugar_cache_reset(); } - function rebuild_layoutdefs(){ - $this->log(translate('LBL_MI_REBUILDING') . " Layoutdefs..."); - $this->merge_files('Ext/Layoutdefs/', 'layoutdefs.ext.php'); - - } - - function rebuild_menus(){ - $this->log(translate('LBL_MI_REBUILDING') . " Menus..."); - $this->merge_files('Ext/Menus/', 'menu.ext.php'); + function rebuild_vardefs() + { + $this->rebuildExt("Vardefs", 'vardefs.ext.php'); + sugar_cache_reset(); } function rebuild_dashletcontainers(){ @@ -1315,22 +1425,9 @@ class ModuleInstaller{ $this->merge_files('Ext/DashletContainer/Containers/', 'dcactions.ext.php'); } - function rebuild_modules(){ - $this->log(translate('LBL_MI_REBUILDING') . " Modules..."); - $this->merge_files('Ext/Include/', 'modules.ext.php', '', true); - } - - function rebuild_administration(){ - $this->log(translate('LBL_MI_REBUILDING') . " administration " . translate('LBL_MI_SECTION')); - $this->merge_files('Ext/Administration/', 'administration.ext.php'); - } - function rebuild_userpage(){ - $this->log(translate('LBL_MI_REBUILDING') . " User Page " . translate('LBL_MI_SECTION')); - $this->merge_files('Ext/UserPage/', 'userpage.ext.php'); - } - function rebuild_tabledictionary(){ - $this->log(translate('LBL_MI_REBUILDING') . " administration " . translate('LBL_MI_SECTION')); - $this->merge_files('Ext/TableDictionary/', 'tabledictionary.ext.php'); + function rebuild_tabledictionary() + { + $this->rebuildExt("TableDictionary", 'tabledictionary.ext.php'); } function rebuild_relationships() { @@ -1371,16 +1468,11 @@ class ModuleInstaller{ $this->rebuild_modules(); $this->rebuild_languages($sugar_config['languages']); - $this->rebuild_vardefs(); - $this->rebuild_layoutdefs(); - $this->rebuild_menus(); + $this->rebuild_extensions(); $this->rebuild_dashletcontainers(); - $this->rebuild_userpage(); - $this->rebuild_administration(); $this->rebuild_relationships(); $this->rebuild_tabledictionary(); - //$this->repair_indices(); - $this->reset_opcodes(); + $this->reset_opcodes(); sugar_cache_reset(); } @@ -1424,9 +1516,9 @@ class ModuleInstaller{ $extension .= "\n?>"; if($shouldSave){ - if(!file_exists("custom/$extpath")){ - mkdir_recursive("custom/$extpath", true); - } + if(!file_exists("custom/$extpath")) { + mkdir_recursive("custom/$extpath", true); + } $out = sugar_fopen("custom/$extpath/$name", 'w'); fwrite($out,$extension); fclose($out); @@ -1473,6 +1565,43 @@ class ModuleInstaller{ } + function install_modules() + { + $this->installed_modules = array(); + $this->tab_modules = array(); + if(isset($this->installdefs['beans'])){ + $str = "installdefs['beans'] as $bean){ + if(!empty($bean['module']) && !empty($bean['class']) && !empty($bean['path'])){ + $module = $bean['module']; + $class = $bean['class']; + $path = $bean['path']; + + $str .= "\$beanList['$module'] = '$class';\n"; + $str .= "\$beanFiles['$class'] = '$path';\n"; + if($bean['tab']){ + $str .= "\$moduleList[] = '$module';\n"; + $this->install_user_prefs($module, empty($bean['hide_by_default'])); + $this->tab_modules[] = $module; + }else{ + $str .= "\$modules_exempt_from_availability_check['$module'] = '$module';\n"; + $str .= "\$report_include_modules['$module'] = '$module';\n"; + $str .= "\$modInvisList[] = '$module';\n"; + } + $this->installed_modules[] = $module; + }else{ + $errors[] = 'Bean array not well defined.'; + $this->abort($errors); + } + } + $str.= "\n?>"; + if(!file_exists("custom/Extension/application/Ext/Include")){ + mkdir_recursive("custom/Extension/application/Ext/Include", true); + } + file_put_contents("custom/Extension/application/Ext/Include/{$this->id_name}.php", $str); + } + } + /* * ModuleInstaller->install_beans runs through the list of beans given, instantiates each bean, calls bean->create_tables, and then calls SugarBean::createRelationshipMeta for the * bean/module. @@ -1490,7 +1619,7 @@ class ModuleInstaller{ if(is_subclass_of($mod, 'SugarBean') && $mod->disable_vardefs == false ){ $GLOBALS['log']->debug( "Creating Tables Bean : $bean"); $mod->create_tables(); - SugarBean::createRelationshipMeta($mod->getObjectName(), $mod->db,$mod->table_name,'',$mod->module_dir); + SugarBean::createRelationshipMeta($mod->getObjectName(), $mod->db,$mod->table_name,'',$mod->module_dir); } }else{ $GLOBALS['log']->debug( "File Does Not Exist:" . $beanFiles[$class] ); @@ -1739,15 +1868,10 @@ private function dir_file_count($path){ $current_step = 0; $tasks = array( 'enable_copy', - 'enable_menus', - 'enable_userpage', 'enable_dashlets', - 'enable_administration', - 'enable_vardefs', - 'enable_layoutdefs', 'enable_relationships', - 'enable_languages', - 'enable_logichooks', + 'enable_extensions', + 'enable_manifest_logichooks', 'reset_opcodes', ); $total_steps += count($tasks); @@ -1779,12 +1903,6 @@ private function dir_file_count($path){ foreach($this->installdefs['beans'] as $bean){ $installed_modules[] = $bean['module']; } - if(!file_exists("custom/Extension/application/Ext/Include")){ - mkdir_recursive("custom/Extension/application/Ext/Include", true); - } - if (file_exists("custom/Extension/application/Ext/Include/".DISABLED_PATH.'/'. $this->id_name . '.php')) - rename("custom/Extension/application/Ext/Include/".DISABLED_PATH.'/'. $this->id_name . '.php',"custom/Extension/application/Ext/Include/$this->id_name.php"); - $this->rebuild_modules(); } if(!$this->silent){ $current_step++; @@ -1819,15 +1937,10 @@ private function dir_file_count($path){ $this->base_dir = $base_dir; $tasks = array( 'disable_copy', - 'disable_menus', 'disable_dashlets', - 'disable_userpage', - 'disable_administration', - 'disable_vardefs', - 'disable_layoutdefs', 'disable_relationships', - 'disable_languages', - 'disable_logichooks', + 'disable_extensions', + 'disable_manifest_logichooks', 'reset_opcodes', ); $total_steps += count($tasks); //now the real number of steps @@ -1846,16 +1959,6 @@ private function dir_file_count($path){ foreach($this->installdefs['beans'] as $bean){ $installed_modules[] = $bean['module']; } - - mkdir_recursive("custom/Extension/application/Ext/Include/".DISABLED_PATH, true); - - //Clear any older disabled version - if (file_exists("custom/Extension/application/Ext/Include/".DISABLED_PATH.'/'. $this->id_name . '.php')) - rmdir_recursive("custom/Extension/application/Ext/Include/".DISABLED_PATH.'/'. $this->id_name . '.php'); - - if (file_exists("custom/Extension/application/Ext/Include/$this->id_name.php")) - rename("custom/Extension/application/Ext/Include/$this->id_name.php", "custom/Extension/application/Ext/Include/".DISABLED_PATH.'/'. $this->id_name . '.php'); - $this->rebuild_modules(); } if(!$this->silent){ $current_step++; @@ -1879,65 +1982,15 @@ private function dir_file_count($path){ die("No manifest.php Defined In $this->base_dir/manifest.php"); } } - function enable_vardef($to_module){ - if(isset($this->installdefs['vardefs'])){ - foreach($this->installdefs['vardefs'] as $vardefs){ - $GLOBALS['log']->debug("Enabling Vardefs ..." .$to_module); - $path = 'custom/Extension/modules/' . $to_module. '/Ext/Vardefs'; - if($to_module == 'application'){ - $path ='custom/Extension/' . $to_module. '/Ext/Vardefs'; - } - if(!file_exists($path)){ - mkdir_recursive($path, true); - } - if (file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')) - rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php'); - if (file_exists($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from']))) - rename($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from']), $path . '/'. basename($vardefs['from'])); - } - } - } - function enable_vardefs(){ - if(isset($this->installdefs['vardefs'])){ - foreach($this->installdefs['vardefs'] as $vardefs){ - $vardefs['from'] = str_replace('', $this->base_dir, $vardefs['from']); - $GLOBALS['log']->debug("Enabling Vardefs ..." . $vardefs['from'] . " for " .$vardefs['to_module']); - $path = 'custom/Extension/modules/' . $vardefs['to_module']. '/Ext/Vardefs'; - if($vardefs['to_module'] == 'application'){ - $path ='custom/Extension/' . $vardefs['to_module']. '/Ext/Vardefs'; - } - if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')) - rename( $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php'); - - if (file_exists($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from']))) - rename($path . '/'.DISABLED_PATH.'/'. basename($vardefs['from']), $path . '/'. basename($vardefs['from'])); - } - $this->rebuild_vardefs(); - } + function enable_vardef($to_module) + { + $this->enableExt("vardefs", "Vardefs", $to_module); } - function disable_vardefs(){ - $GLOBALS['log']->debug("Disabling Vardefs ".var_export($this->installdefs, true)); - if(isset($this->installdefs['vardefs'])){ - foreach($this->installdefs['vardefs'] as $vardefs){ - $vardefs['from'] = str_replace('', $this->base_dir, $vardefs['from']); - $GLOBALS['log']->debug("Disabling Vardefs ..." . $vardefs['from'] . " for " .$vardefs['to_module']); - $path = 'custom/Extension/modules/' . $vardefs['to_module']. '/Ext/Vardefs'; - if($vardefs['to_module'] == 'application'){ - $path ='custom/Extension/' . $vardefs['to_module']. '/Ext/Vardefs'; - } - if(file_exists($path . '/'. $this->id_name . '.php')) { - mkdir_recursive($path . '/'.DISABLED_PATH, true); - rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'); - } - if(file_exists($path . '/'. basename($vardefs['from']))) - { - mkdir_recursive($path . '/'.DISABLED_PATH, true); - rename( $path . '/'. basename($vardefs['from']), $path . '/'.DISABLED_PATH.'/'.basename($vardefs['from'])); - } - } - $this->rebuild_vardefs(); - } + + function enable_layoutdef($to_module) + { + $this->enableExt("layoutdefs", "Layoutdefs", $to_module); } function enable_relationships(){ @@ -2014,127 +2067,6 @@ private function dir_file_count($path){ } } - function enable_layoutdefs(){ - if(isset($this->installdefs['layoutdefs'])){ - foreach($this->installdefs['layoutdefs'] as $layoutdefs){ - $this->enable_layoutdef($layoutdefs['to_module'], $this->id_name); - } - $this->rebuild_layoutdefs(); - } - } - function enable_layoutdef($to_module){ - $GLOBALS['log']->debug("Enabling Layout Defs ..." .$to_module); - if(isset($this->installdefs['layoutdefs'])){ - foreach($this->installdefs['layoutdefs'] as $layoutdefs){ - $path = 'custom/Extension/modules/' . $to_module. '/Ext/Layoutdefs'; - if($to_module == 'application'){ - $path ='custom/Extension/' . $to_module. '/Ext/Layoutdefs'; - } - if (file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')) - { - rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php'); - } - if (file_exists($path . '/'.DISABLED_PATH.'/'. basename($layoutdefs['from']))) - { - rename($path . '/'.DISABLED_PATH.'/'. basename($layoutdefs['from']), $path . '/'. basename($layoutdefs['from'])); - } - } - } - } - - function disable_layoutdefs(){ - if(isset($this->installdefs['layoutdefs'])){ - foreach($this->installdefs['layoutdefs'] as $layoutdefs){ - $layoutdefs['from'] = str_replace('', $this->base_dir, $layoutdefs['from']); - $GLOBALS['log']->debug("Disabling Layoutdefs ..." . $layoutdefs['from'] . " for " .$layoutdefs['to_module']); - $path = 'custom/Extension/modules/' . $layoutdefs['to_module']. '/Ext/Layoutdefs'; - if($layoutdefs['to_module'] == 'application'){ - $path ='custom/Extension/' . $layoutdefs['to_module']. '/Ext/Layoutdefs'; - } - if (file_exists($path . '/'. $this->id_name . '.php')) - { - mkdir_recursive($path . '/'.DISABLED_PATH, true); - rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'); - }else if (file_exists($path . '/'. basename($layoutdefs['from']))) - { - mkdir_recursive($path . '/'.DISABLED_PATH, true); - rename( $path . '/'. basename($layoutdefs['from']), $path . '/'.DISABLED_PATH.'/'. basename($layoutdefs['from'])); - } - } - $this->rebuild_layoutdefs(); - } - } - - function enable_menus(){ - if(isset($this->installdefs['menu'])){ - foreach($this->installdefs['menu'] as $menu){ - $menu['from'] = str_replace('', $this->base_dir, $menu['from']); - $GLOBALS['log']->debug("Enabling Menu ..." . $menu['from']. " for " .$menu['to_module'] ); - $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus'; - if($menu['to_module'] == 'application'){ - $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus'; - } - - if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')){ - rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php'); - } - - } - $this->rebuild_menus(); - } - - } - - function disable_menus(){ - if(isset($this->installdefs['menu'])){ - foreach($this->installdefs['menu'] as $menu){ - $menu['from'] = str_replace('', $this->base_dir, $menu['from']); - $GLOBALS['log']->debug("Disabling Menu ..." . $menu['from']. " for " .$menu['to_module'] ); - $path = 'custom/Extension/modules/' . $menu['to_module']. '/Ext/Menus'; - if($menu['to_module'] == 'application'){ - $path ='custom/Extension/' . $menu['to_module']. '/Ext/Menus'; - } - if (file_exists( $path . '/'. $this->id_name . '.php')) - { - mkdir_recursive($path . '/'.DISABLED_PATH, true); - rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'); - } - } - $this->rebuild_menus(); - } - } - - function enable_administration(){ - if(isset($this->installdefs['administration'])){ - foreach($this->installdefs['administration'] as $administration){ - $administration['from'] = str_replace('', $this->base_dir, $administration['from']); - $GLOBALS['log']->debug("Installing Administration Section ..." . $administration['from'] ); - $path = 'custom/Extension/modules/Administration/Ext/Administration'; - - if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')){ - rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php'); - } - } - $this->rebuild_administration(); - } - - } - function disable_administration(){ - if(isset($this->installdefs['administration'])){ - foreach($this->installdefs['administration'] as $administration){ - $administration['from'] = str_replace('', $this->base_dir, $administration['from']); - $GLOBALS['log']->debug("Uninstalling Administration Section ..." . $administration['from'] ); - $path = 'custom/Extension/modules/Administration/Ext/Administration'; - if (file_exists($path . '/'. $this->id_name . '.php')) - { - mkdir_recursive($path . '/'.DISABLED_PATH, true); - rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'); - } - } - $this->rebuild_administration(); - } - } - function enable_dashlets(){ if(isset($this->installdefs['dashlets'])){ foreach($this->installdefs['dashlets'] as $cp){ @@ -2168,78 +2100,6 @@ private function dir_file_count($path){ } } - function enable_languages(){ - $languages = array(); - if(isset($this->installdefs['language'])){ - foreach($this->installdefs['language'] as $packs){ - $languages[$packs['language']] = $packs['language']; - $packs['from'] = str_replace('', $this->base_dir, $packs['from']); - $GLOBALS['log']->debug("Installing Language Pack ..." . $packs['from'] . " for " .$packs['to_module']); - $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language'; - if($packs['to_module'] == 'application'){ - $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language'; - } - - if(!file_exists($path)){ - mkdir_recursive($path, true); - } - if (file_exists($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php')) - rename($path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php', $path.'/'.$packs['language'].'.'. $this->id_name . '.php'); - } - $this->rebuild_languages($languages); - } - } - - function disable_languages(){ - $languages = array(); - if(isset($this->installdefs['language'])){ - foreach($this->installdefs['language'] as $packs){ - $languages[$packs['language']] = $packs['language']; - $packs['from'] = str_replace('', $this->base_dir, $packs['from']); - $GLOBALS['log']->debug("Uninstalling Language Pack ..." . $packs['from'] . " for " .$packs['to_module']); - $path = 'custom/Extension/modules/' . $packs['to_module']. '/Ext/Language'; - if($packs['to_module'] == 'application'){ - $path ='custom/Extension/' . $packs['to_module']. '/Ext/Language'; - } - mkdir_recursive($path . '/'.DISABLED_PATH, true); - if (file_exists($path.'/'.$packs['language'].'.'. $this->id_name . '.php')) - rename($path.'/'.$packs['language'].'.'. $this->id_name . '.php', $path.'/'.DISABLED_PATH.'/'.$packs['language'].'.'. $this->id_name . '.php'); - - } - $this->rebuild_languages($languages); - } - } - - function enable_userpage(){ - if(isset($this->installdefs['user_page'])){ - foreach($this->installdefs['user_page'] as $userpage){ - $userpage['from'] = str_replace('', $this->base_dir, $userpage['from']); - $GLOBALS['log']->debug("Installing User Page Section ..." . $userpage['from'] ); - $path = 'custom/Extension/modules/Users/Ext/UserPage'; - if(file_exists($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php')){ - rename($path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php', $path . '/'. $this->id_name . '.php'); - } - - } - $this->rebuild_userpage(); - } - - } - function disable_userpage(){ - if(isset($this->installdefs['user_page'])){ - foreach($this->installdefs['user_page'] as $userpage){ - $userpage['from'] = str_replace('', $this->base_dir, $userpage['from']); - $GLOBALS['log']->debug("Uninstalling User Page Section ..." . $userpage['from'] ); - $path = 'custom/Extension/modules/Users/Ext/UserPage'; - if (file_exists( $path . '/'. $this->id_name . '.php')) { - mkdir_recursive($path . '/'.DISABLED_PATH, true); - rename( $path . '/'. $this->id_name . '.php', $path . '/'.DISABLED_PATH.'/'. $this->id_name . '.php'); - } - } - $this->rebuild_userpage(); - } - } - function enable_copy(){ //copy files back onto file system. first perform md5 check to determine if anything has been modified //here we should just go through the files in the -restore directory and copy those back @@ -2310,6 +2170,31 @@ private function dir_file_count($path){ } } + /** + * BC implementation to provide specific calls to extensions + */ + public function __call($name, $args) + { + $nameparts = explode('_', $name); + // name is something_something + if(count($nameparts) == 2 && isset($this->extensions[$nameparts[1]])) { + $ext = $this->extensions[$nameparts[1]]; + switch($nameparts[0]) { + case 'enable': + return $this->enableExt($ext['section'], $ext['extdir']); + case 'disable': + return $this->disableExt($ext['section'], $ext['extdir']); + case 'install': + return $this->installExt($ext['section'], $ext['extdir']); + case 'uninstall': + return $this->uninstallExt($ext['section'], $ext['extdir']); + case 'rebuild': + return $this->rebuildExt($ext['extdir'], $ext['file']); + } + } + sugar_die("Unknown method ModuleInstaller::$name called"); + } + } function UpdateSystemTabs($action, $installed_modules){ @@ -2343,9 +2228,6 @@ private function dir_file_count($path){ default: break; } - } + } } - - -?> diff --git a/ModuleInstall/ModuleScanner.php b/ModuleInstall/ModuleScanner.php index 9e4b32bb..93dc9d94 100644 --- a/ModuleInstall/ModuleScanner.php +++ b/ModuleInstall/ModuleScanner.php @@ -1,4 +1,4 @@ -'language', 'install_logichooks'=>'logic_hooks', 'post_execute'=>'post_execute', - + ); - + private $blackListExempt = array(); - + private $validExt = array('png', 'gif', 'jpg', 'css', 'js', 'php', 'txt', 'html', 'htm', 'tpl', 'pdf', 'md5', 'xml'); private $blackList = array( 'popen', @@ -120,9 +120,9 @@ class ModuleScanner{ 'exec', 'system', 'shell_exec', - 'passthru', + 'passthru', 'chgrp', - 'chmod', + 'chmod', 'chwown', 'file_put_contents', 'file', @@ -133,7 +133,7 @@ class ModuleScanner{ 'filemtime', 'fileowner', 'fileperms', - 'fopen', + 'fopen', 'is_executable', 'is_writable', 'is_writeable', @@ -152,7 +152,7 @@ class ModuleScanner{ 'call_user_func', 'call_user_func_array', 'create_function', - + //mutliple files per function call 'copy', @@ -182,14 +182,14 @@ class ModuleScanner{ echo "'''Default Extensions'''
"; foreach($this->validExt as $b){ echo '#' . $b . '
'; - + } echo "'''Default Black Listed Functions'''
"; foreach($this->blackList as $b){ echo '#' . $b . '
'; - + } - + } public function __construct(){ @@ -202,42 +202,42 @@ class ModuleScanner{ if(!empty($GLOBALS['sugar_config']['moduleInstaller']['validExt'])){ $this->validExt = array_merge($this->validExt, $GLOBALS['sugar_config']['moduleInstaller']['validExt']); } - + } private $issues = array(); private $pathToModule = ''; - + /** *returns a list of issues */ public function getIssues(){ return $this->issues; } - + /** *returns true or false if any issues were found */ public function hasIssues(){ return !empty($this->issues); } - + /** *Ensures that a file has a valid extension */ private function isValidExtension($file){ $file = strtolower($file); - + $extPos = strrpos($file, '.'); //make sure they don't override the files.md5 if($extPos === false || $file == 'files.md5')return false; $ext = substr($file, $extPos + 1); return in_array($ext, $this->validExt); - + } - + /** - *Scans a directory and calls on scan file for each file + *Scans a directory and calls on scan file for each file **/ public function scanDir($path){ static $startPath = ''; @@ -249,21 +249,40 @@ class ModuleScanner{ if(is_dir($next)){ if(substr($e, 0, 1) == '.')continue; $this->scanDir($next); - }else{ + }else{ $issues = $this->scanFile($next); - - + + } } return true; } - - + + /** + * Check if the file contents looks like PHP + * @param string $contents File contents + * @return boolean + */ + protected function isPHPFile($contents) + { + if(stripos($contents, 'isPHPFile($contents)) return $issues; + $tokens = @token_get_all($contents); $checkFunction = false; $possibleIssue = ''; $lastToken = false; @@ -285,7 +304,7 @@ class ModuleScanner{ $issues['backtick'] = translate('ML_INVALID_FUNCTION') . " '`'"; case '(': if($checkFunction)$issues[] = $possibleIssue; - break; + break; } $checkFunction = false; $possibleIssue = ''; @@ -301,8 +320,8 @@ class ModuleScanner{ $token[1] = strtolower($token[1]); if(!in_array($token[1], $this->blackList))break; if(in_array($token[1], $this->blackListExempt))break; - if ($lastToken !== false && - ($lastToken[0] == T_NEW || $lastToken[0] == T_OBJECT_OPERATOR || $lastToken[0] == T_DOUBLE_COLON)) + if ($lastToken !== false && + ($lastToken[0] == T_NEW || $lastToken[0] == T_OBJECT_OPERATOR || $lastToken[0] == T_DOUBLE_COLON)) { break; } @@ -310,7 +329,7 @@ class ModuleScanner{ $checkFunction = true; $possibleIssue = translate('ML_INVALID_FUNCTION') . ' ' . $token[1] . '()'; break; - + default: $checkFunction = false; $possibleIssue = ''; @@ -321,18 +340,18 @@ class ModuleScanner{ $lastToken = $token; } } - + } if(!empty($issues)){ $this->issues['file'][$file] = $issues; } - - return $issues; + + return $issues; } - - + + /* - * checks files.md5 file to see if the file is from sugar + * checks files.md5 file to see if the file is from sugar * ONLY WORKS ON FILES */ public function sugarFileExists($path){ @@ -343,11 +362,11 @@ class ModuleScanner{ $md5 = $md5_string; } if(isset($md5['./' . $path]))return true; - - + + } - - + + /** *This function will scan the Manifest for disabled actions specified in $GLOBALS['sugar_config']['moduleInstaller']['disableActions'] *if $GLOBALS['sugar_config']['moduleInstaller']['disableRestrictedCopy'] is set to false or not set it will call on scanCopy to ensure that it is not overriding files @@ -364,9 +383,9 @@ class ModuleScanner{ return $fileIssues; } include($manifestPath); - - - //scan for disabled actions + + + //scan for disabled actions if(isset($GLOBALS['sugar_config']['moduleInstaller']['disableActions'])){ foreach($GLOBALS['sugar_config']['moduleInstaller']['disableActions'] as $action){ if(isset($installdefs[$this->manifestMap[$action]])){ @@ -374,8 +393,8 @@ class ModuleScanner{ } } } - - //now lets scan for files that will override our files + + //now lets scan for files that will override our files if(empty($GLOBALS['sugar_config']['moduleInstaller']['disableRestrictedCopy']) && isset($installdefs['copy'])){ foreach($installdefs['copy'] as $copy){ $from = str_replace('', $this->pathToModule, $copy['from']); @@ -391,25 +410,25 @@ class ModuleScanner{ } while(substr_count($to, '//')){ $to = str_replace('//', '/', $to); - } + } $this->scanCopy($from, $to); } } if(!empty($issues)){ $this->issues['manifest'][$manifestPath] = $issues; } - - - + + + } - - + + /** - * Takes in where the file will is specified to be copied from and to - * and ensures that there is no official sugar file there. If the file exists it will check + * Takes in where the file will is specified to be copied from and to + * and ensures that there is no official sugar file there. If the file exists it will check * against the MD5 file list to see if Sugar Created the file - * + * */ function scanCopy($from, $to){ //if the file doesn't exist for the $to then it is not overriding anything @@ -421,28 +440,28 @@ class ModuleScanner{ } $to .= '/'. basename($from); } - //if the $to is a file and it is found in sugarFileExists then don't allow overriding it + //if the $to is a file and it is found in sugarFileExists then don't allow overriding it if(is_file($to) && $this->sugarFileExists($to)){ $this->issues['copy'][$from] = translate('ML_OVERRIDE_CORE_FILES') . '(' . $to . ')'; } - + if(is_dir($from)){ $d = dir($from); while($e = $d->read()){ if($e == '.' || $e == '..')continue; - $this->scanCopy($from .'/'. $e, $to .'/' . $e); + $this->scanCopy($from .'/'. $e, $to .'/' . $e); } } - - - - - + + + + + } - - + + /** - *Main external function that takes in a path to a package and then scans + *Main external function that takes in a path to a package and then scans *that package's manifest for disabled actions and then it scans the PHP files *for restricted function calls * @@ -454,22 +473,22 @@ class ModuleScanner{ $this->scanDir($path); } } - + /** - *This function will take all issues of the current instance and print them to the screen + *This function will take all issues of the current instance and print them to the screen **/ public function displayIssues($package='Package'){ - echo '

'.str_replace('{PACKAGE}' , $package ,translate('ML_PACKAGE_SCANNING')). '


' . translate('ML_INSTALLATION_FAILED') . '


' .str_replace('{PACKAGE}' , $package ,translate('ML_PACKAGE_NOT_CONFIRM')). '

  • '. translate('ML_OBTAIN_NEW_PACKAGE') . '
  • ' . translate('ML_RELAX_LOCAL'). + echo '

    '.str_replace('{PACKAGE}' , $package ,translate('ML_PACKAGE_SCANNING')). '


    ' . translate('ML_INSTALLATION_FAILED') . '


    ' .str_replace('{PACKAGE}' , $package ,translate('ML_PACKAGE_NOT_CONFIRM')). '

    • '. translate('ML_OBTAIN_NEW_PACKAGE') . '
    • ' . translate('ML_RELAX_LOCAL'). '


    ' . translate('ML_SUGAR_LOADING_POLICY') . ' ' . translate('ML_SUGAR_KB') . '.'. '
    ' . translate('ML_AVAIL_RESTRICTION'). ' ' . translate('ML_SUGAR_DZ') . '.

    '; - + foreach($this->issues as $type=>$issues){ echo '

    '. ucfirst($type) .' ' . translate('ML_ISSUES') . '

    '; - echo '
    '; + echo '
    '; foreach($issues as $file=>$issue){ $file = str_replace($this->pathToModule . '/', '', $file); - echo '
    ' . $file . '
    '; + echo '
    ' . $file . '
    '; if(is_array($issue)){ foreach($issue as $i){ echo "$i
    "; @@ -480,13 +499,13 @@ class ModuleScanner{ echo "
    "; } echo '
    '; - + } echo "
    "; - + } - - + + } diff --git a/ModuleInstall/PackageManager/tpls/ModuleLoaderListView.tpl b/ModuleInstall/PackageManager/tpls/ModuleLoaderListView.tpl index 2fd74b1d..0e3103d8 100644 --- a/ModuleInstall/PackageManager/tpls/ModuleLoaderListView.tpl +++ b/ModuleInstall/PackageManager/tpls/ModuleLoaderListView.tpl @@ -43,8 +43,8 @@ view/hide {foreach from=$displayColumns key=colHeader item=params} {if $params.show} - -
    + +
    {sugar_translate label=$params.label module='Administration'}
    diff --git a/ModuleInstall/extensions.php b/ModuleInstall/extensions.php new file mode 100644 index 00000000..97d53eb4 --- /dev/null +++ b/ModuleInstall/extensions.php @@ -0,0 +1,63 @@ + array("section" => "action_view_map","extdir" => "ActionViewMap", "file" => 'action_view_map.ext.php'), + "actionfilemap" => array("section" => "action_file_map","extdir" => "ActionFileMap", "file" => 'action_file_map.ext.php'), + "actionremap" => array("section" => "action_remap", "extdir" => "ActionReMap", "file" => 'action_remap.ext.php'), + "administration" => array("section" => "administration", "extdir" => "Administration", "file" => 'administration.ext.php', "module" => "Administration"), + "entrypoints" => array("section" => "entrypoints", "extdir" => "EntryPointRegistry", "file" => 'entry_point_registry.ext.php', "module" => "application"), + "exts" => array("section" => "extensions", "extdir" => "Extensions", "file" => 'extensions.ext.php', "module" => "application"), + "file_access" => array("section" => "file_access", "extdir" => "FileAccessControlMap", "file" => 'file_access_control_map.ext.php'), + "languages" => array("section" => "language", "extdir" => "Language", "file" => '' /* custom rebuild */), + "layoutdefs" => array("section" => "layoutdefs", "extdir" => "Layoutdefs", "file" => 'layoutdefs.ext.php'), + "links" => array("section" => "linkdefs", "extdir" => "GlobalLinks", "file" => 'links.ext.php', "module" => "application"), + "logichooks" => array("section" => "hookdefs", "extdir" => "LogicHooks", "file" => 'logichooks.ext.php'), + "menus" => array("section" => "menu", "extdir" => "Menus", "file" => "menu.ext.php"), + "modules" => array("section" => "beans", "extdir" => "Include", "file" => 'modules.ext.php', "module" => "application"), + "schedulers" => array("section" => "scheduledefs", "extdir" => "ScheduledTasks", "file" => 'scheduledtasks.ext.php', "module" => "Schedulers"), + "userpage" => array("section" => "user_page", "extdir" => "UserPage", "file" => 'userpage.ext.php', "module" => "Users"), + "utils" => array("section" => "utils", "extdir" => "Utils", "file" => 'custom_utils.ext.php', "module" => "application"), + "vardefs" => array("section" => "vardefs", "extdir" => "Vardefs", "file" => 'vardefs.ext.php'), +); +if(file_exists("custom/application/Ext/Extensions/extensions.ext.php")) { + include("custom/application/Ext/Extensions/extensions.ext.php"); +} + + diff --git a/Zend/Gdata/Contacts.php b/Zend/Gdata/Contacts.php new file mode 100644 index 00000000..80ca393b --- /dev/null +++ b/Zend/Gdata/Contacts.php @@ -0,0 +1,139 @@ +registerPackage('Zend_Gdata_Contacts'); + $this->registerPackage('Zend_Gdata_Contacts_Extension'); + parent::__construct($client, $applicationId); + $this->_httpClient->setParameterPost('service', self::AUTH_SERVICE_NAME); + $this->setMajorProtocolVersion(self::DEFAULT_MAJOR_PROTOCOL_VERSION); + } + + /** + * Retrieve feed object + * + * @return Zend_Gdata_Calendar_ListFeed + */ + public function getContactListFeed() + { + $query = new Zend_Gdata_Query(self::CONTACT_FEED_URI); + $query->maxResults = $this->maxResults; + $query->startIndex = $this->startIndex; + return parent::getFeed($query,'Zend_Gdata_Contacts_ListFeed'); + } + + /** + * Retrieve a single feed object by id + * + * @param string $entryID + * @return string|Zend_Gdata_App_Feed + */ + public function getContactEntry($entryID) + { + return parent::getEntry($entryID,'Zend_Gdata_Contacts_ListEntry'); + } + + /** + * Set the max results that the feed should return. + * + * @param $maxResults + * @return void + */ + public function setMaxResults($maxResults) + { + $this->maxResults = $maxResults; + } + + /** + * Set the start index. + * + * @param $value + * @return void + */ + public function setStartIndex($value) + { + $this->startIndex = $value; + } + +} + diff --git a/Zend/Gdata/Contacts/Extension/Address.php b/Zend/Gdata/Contacts/Extension/Address.php new file mode 100644 index 00000000..9d095a8c --- /dev/null +++ b/Zend/Gdata/Contacts/Extension/Address.php @@ -0,0 +1,125 @@ + 'primary', 'home' => 'alt', '' => 'primary'); + /** + * Constructs a new Zend_Gdata_Contacts_Extension_Name object. + * @param string $value (optional) The text content of the element. + */ + public function __construct($value = null) + { + $this->registerAllNamespaces(Zend_Gdata_Contacts::$namespaces); + parent::__construct(); + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) + { + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Extracts XML attributes from the DOM and converts them to the + * appropriate object members. + * + * @param DOMNode $attribute The DOMNode attribute to be handled. + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'primary': + if(strtolower($attribute->nodeValue) == 'true') + $this->_isPrimary = true; + else + $this->_isPrimary = false; + break; + + case 'rel': + $this->_addressType = $attribute->nodeValue; + break; + + default: + parent::takeAttributeFromDOM($attribute); + } + } + + protected function getAddressType() + { + if($this->_addressType == null) + return ''; + else + return str_replace($this->lookupNamespace('gd') . '#', '', $this->_addressType); + } + + public function toArray() + { + $results = array(); + + $keyPrefix= $this->_transformMapping[strtolower($this->getAddressType())]; + + foreach($this->_extensionElements as $elem) + { + if( $elem->_rootElement == 'formattedAddress') + continue; + $elemKey = $elem->_rootElement == 'region' ? 'state' : $elem->_rootElement; + $elemKey = "$keyPrefix" . "_address_" . "$elemKey"; + $results[$elemKey] = $elem->getText(); + } + + return $results; + } + +} + + diff --git a/Zend/Gdata/Contacts/Extension/Birthday.php b/Zend/Gdata/Contacts/Extension/Birthday.php new file mode 100644 index 00000000..53864f9e --- /dev/null +++ b/Zend/Gdata/Contacts/Extension/Birthday.php @@ -0,0 +1,91 @@ +registerAllNamespaces(Zend_Gdata_Contacts::$namespaces); + parent::__construct(); + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) + { + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Extracts XML attributes from the DOM and converts them to the + * appropriate object members. + * + * @param DOMNode $attribute The DOMNode attribute to be handled. + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) { + case 'when': + $this->_value = $attribute->nodeValue; + break; + default: + parent::takeAttributeFromDOM($attribute); + } + } + + public function getBirthday() + { + return $this->_value; + } +} + diff --git a/Zend/Gdata/Contacts/Extension/Email.php b/Zend/Gdata/Contacts/Extension/Email.php new file mode 100644 index 00000000..dc280aaf --- /dev/null +++ b/Zend/Gdata/Contacts/Extension/Email.php @@ -0,0 +1,119 @@ +registerAllNamespaces(Zend_Gdata_Contacts::$namespaces); + parent::__construct(); + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) + { + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Extracts XML attributes from the DOM and converts them to the + * appropriate object members. + * + * @param DOMNode $attribute The DOMNode attribute to be handled. + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) + { + case 'primary': + if(strtolower($attribute->nodeValue) == 'true') + $this->_isPrimary = true; + else + $this->_isPrimary = false; + break; + + case 'rel': + $this->_emailType = $attribute->nodeValue; + break; + + case 'address': + $this->_email = $attribute->nodeValue; + break; + + default: + parent::takeAttributeFromDOM($attribute); + break; + } + } + + public function getEmailType() + { + if($this->_emailType == null) + return ''; + else + return str_replace($this->lookupNamespace('gd') . '#', '', $this->_emailType); + } + + public function getEmail() + { + return $this->_email; + } + + public function isPrimary() + { + return $this->_isPrimary; + } +} + diff --git a/Zend/Gdata/Contacts/Extension/Name.php b/Zend/Gdata/Contacts/Extension/Name.php new file mode 100644 index 00000000..b2397ab3 --- /dev/null +++ b/Zend/Gdata/Contacts/Extension/Name.php @@ -0,0 +1,91 @@ + '', 'last_name' => '', 'full_name' => ''); + /** + * Constructs a new Zend_Gdata_Contacts_Extension_Name object. + * @param string $value (optional) The text content of the element. + */ + public function __construct($value = null) + { + $this->registerAllNamespaces(Zend_Gdata_Contacts::$namespaces); + parent::__construct(); + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) + { + case $this->lookupNamespace('gd') . ':' . 'fullName'; + $entry = new Zend_Gdata_Entry(); + $entry->transferFromDOM($child); + $this->_names['full_name'] = $entry->getText(); + break; + + case $this->lookupNamespace('gd') . ':' . 'givenName'; + $entry = new Zend_Gdata_Entry(); + $entry->transferFromDOM($child); + $this->_names['first_name'] = $entry->getText(); + break; + + case $this->lookupNamespace('gd') . ':' . 'familyName'; + $entry = new Zend_Gdata_Entry(); + $entry->transferFromDOM($child); + $this->_names['last_name'] = $entry->getText(); + break; + default: + parent::takeChildFromDOM($child); + break; + } + } + + public function toArray() + { + return $this->_names; + } +} + diff --git a/Zend/Gdata/Contacts/Extension/Organization.php b/Zend/Gdata/Contacts/Extension/Organization.php new file mode 100644 index 00000000..84fcd07f --- /dev/null +++ b/Zend/Gdata/Contacts/Extension/Organization.php @@ -0,0 +1,104 @@ +registerAllNamespaces(Zend_Gdata_Contacts::$namespaces); + parent::__construct(); + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + + switch ($absoluteNodeName) + { + case $this->lookupNamespace('gd') . ':' . 'orgName'; + $entry = new Zend_Gdata_Entry(); + $entry->transferFromDOM($child); + $this->_orgName = $entry; + break; + + case $this->lookupNamespace('gd') . ':' . 'orgTitle'; + $entry = new Zend_Gdata_Entry(); + $entry->transferFromDOM($child); + $this->_orgTitle = $entry; + break; + + default: + parent::takeChildFromDOM($child); + break; + } + } + + + public function getOrganizationName() + { + if($this->_orgName != null) + return $this->_orgName->getText(); + else + return ''; + } + public function getOrganizationTitle() + { + if($this->_orgTitle != null) + return $this->_orgTitle->getText(); + else + return ''; + } + + + +} + + diff --git a/Zend/Gdata/Contacts/Extension/PhoneNumber.php b/Zend/Gdata/Contacts/Extension/PhoneNumber.php new file mode 100644 index 00000000..e8cacaf1 --- /dev/null +++ b/Zend/Gdata/Contacts/Extension/PhoneNumber.php @@ -0,0 +1,112 @@ +registerAllNamespaces(Zend_Gdata_Contacts::$namespaces); + parent::__construct(); + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) + { + default: + parent::takeChildFromDOM($child); + break; + } + } + + /** + * Extracts XML attributes from the DOM and converts them to the + * appropriate object members. + * + * @param DOMNode $attribute The DOMNode attribute to be handled. + */ + protected function takeAttributeFromDOM($attribute) + { + switch ($attribute->localName) + { + case 'primary': + if(strtolower($attribute->nodeValue) == 'true') + $this->_isPrimaryNumber = true; + else + $this->_isPrimaryNumber = false; + break; + + case 'rel': + $this->_phoneType = $attribute->nodeValue; + break; + + default: + parent::takeAttributeFromDOM($attribute); + break; + } + } + + public function getPhoneType() + { + return str_replace($this->lookupNamespace('gd') . '#', '', $this->_phoneType); + } + + public function getNumber() + { + return $this->getText(); + } + + public function isPrimary() + { + return $this->_isPrimaryNumber; + } +} + diff --git a/Zend/Gdata/Contacts/ListEntry.php b/Zend/Gdata/Contacts/ListEntry.php new file mode 100644 index 00000000..b34a624d --- /dev/null +++ b/Zend/Gdata/Contacts/ListEntry.php @@ -0,0 +1,259 @@ +registerAllNamespaces(Zend_Gdata_Contacts::$namespaces); + parent::__construct($element); + } + + public function getDOM($doc = null, $majorVersion = 1, $minorVersion = null) + { + $element = parent::getDOM($doc, $majorVersion, $minorVersion); + return $element; + } + + protected function takeChildFromDOM($child) + { + $absoluteNodeName = $child->namespaceURI . ':' . $child->localName; + switch ($absoluteNodeName) { + + case $this->lookupNamespace('gd') . ':' . 'name'; + $item = new Zend_Gdata_Contacts_Extension_Name(); + $item->transferFromDOM($child); + $this->_names = $item; + break; + + case $this->lookupNamespace('gContact') . ':' . 'birthday'; + $item = new Zend_Gdata_Contacts_Extension_Birthday(); + $item->transferFromDOM($child); + $this->_birthday = $item; + break; + + case $this->lookupNamespace('gd') . ':' . 'phoneNumber'; + $item = new Zend_Gdata_Contacts_Extension_PhoneNumber(); + $item->transferFromDOM($child); + $this->_phones[] = $item; + break; + + case $this->lookupNamespace('gd') . ':' . 'email'; + $item = new Zend_Gdata_Contacts_Extension_Email(); + $item->transferFromDOM($child); + $this->_emails[] = $item; + break; + + case $this->lookupNamespace('gd') . ':' . 'structuredPostalAddress'; + $item = new Zend_Gdata_Contacts_Extension_Address(); + $item->transferFromDOM($child); + $this->_addresses[] = $item; + break; + + case $this->lookupNamespace('gd') . ':' . 'organization'; + $item = new Zend_Gdata_Contacts_Extension_Organization(); + $item->transferFromDOM($child); + $this->_organization = $item; + break; + + default: + parent::takeChildFromDOM($child); + break; + } + } + + public function toArray() + { + $entry = array( 'first_name' => '', 'last_name' => '', 'full_name' => '', 'id' => '', 'birthday' => '','email1' => '','email2' => '', + 'title' => '', 'account_name' => '', 'notes' => '', 'phone_main' => '','phone_mobile' => '', + 'alt_address_street' => '','alt_address_postcode' => '','alt_address_city' => '','alt_address_state' => '','alt_address_country' => '', + 'primary_address_street' => '','primary_address_postcode' => '','primary_address_city' => '','primary_address_state' => '','primary_address_country' => '', + 'team_name' => '', 'assigned_user_name' => '' + ); + + if($this->_names != null) + $entry = array_merge($entry, $this->_names->toArray() ); + + //Get the self link so we can query for the contact details at a later date + foreach($this->_link as $linkEntry) + { + $linkRel = $linkEntry->getRel(); + if( $linkRel != null && $linkRel == "self" ) + { + continue; + } + } + + //Get addresses + foreach($this->_addresses as $address) + { + $entry = array_merge($entry, $address->toArray() ); + } + //Process phones + foreach($this->_phones as $phoneEntry) + { + $key = "phone_" . $phoneEntry->getPhoneType(); + $entry[$key] = $phoneEntry->getNumber(); + } + + //Process emails + $entry = array_merge($entry, $this->getEmailAddresses() ); + + //Get Notes + if($this->_content != null) + $entry['notes'] = $this->getContent()->getText(); + + //ID + $entry['id'] = $this->getId()->getText(); + + //Birthday + if($this->_birthday != null) + $entry['birthday'] = $this->_birthday->getBirthday(); + + //Organization name and title + if($this->_organization != null) + { + $entry['account_name'] = $this->_organization->getOrganizationName(); + $entry['title'] = $this->_organization->getOrganizationTitle(); + } + + return $entry; + } + + protected function getEmailAddresses() + { + $results = array(); + $primaryEmail = $this->getPrimaryEmail(); + if($primaryEmail !== FALSE) + $results['email1'] = $primaryEmail; + else + { + $nonPrimaryEmail = $this->getNextNonPrimaryEmail(); + if($nonPrimaryEmail !== FALSE) + $results['email1'] = $nonPrimaryEmail; + else + return array(); + } + + $secondaryEmail = $this->getNextNonPrimaryEmail(); + if($secondaryEmail !== FALSE) + $results['email2'] = $secondaryEmail; + + return $results; + + } + protected function getPrimaryEmail() + { + $results = FALSE; + foreach($this->_emails as $emailEntry) + { + if( $emailEntry->isPrimary() ) + return $emailEntry->getEmail(); + } + return $results; + } + + protected function getNextNonPrimaryEmail() + { + $results = FALSE; + foreach($this->_emails as $k => $emailEntry) + { + if( !$emailEntry->isPrimary() ) + { + $results = $emailEntry->getEmail(); + unset($this->_emails[$k]); + return $results; + } + } + return $results; + } + +} diff --git a/Zend/Gdata/Contacts/ListFeed.php b/Zend/Gdata/Contacts/ListFeed.php new file mode 100644 index 00000000..4097cffa --- /dev/null +++ b/Zend/Gdata/Contacts/ListFeed.php @@ -0,0 +1,71 @@ +registerAllNamespaces(Zend_Gdata_Contacts::$namespaces); + parent::__construct($element); + } +} diff --git a/Zend/Oauth/Config.php b/Zend/Oauth/Config.php index 42ff29a5..be708ebe 100644 --- a/Zend/Oauth/Config.php +++ b/Zend/Oauth/Config.php @@ -16,7 +16,7 @@ * @package Zend_Oauth * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) * @license http://framework.zend.com/license/new-bsd New BSD License - + */ /** Zend_Oauth */ diff --git a/Zend/Oauth/Provider.php b/Zend/Oauth/Provider.php new file mode 100644 index 00000000..93f910ed --- /dev/null +++ b/Zend/Oauth/Provider.php @@ -0,0 +1,354 @@ + "nonce_used", + self::BAD_TIMESTAMP => "timestamp_refused", + self::CONSUMER_KEY_UNKNOWN => "consumer_key_unknown", + self::CONSUMER_KEY_REFUSED => "consumer_key_refused", + self::INVALID_SIGNATURE => "signature_invalid", + self::TOKEN_USED => "token_used", + self::TOKEN_EXPIRED => "token_expired", + self::TOKEN_REVOKED => "token_revoked", + self::TOKEN_REJECTED => "token_rejected", + self::PARAMETER_ABSENT => "parameter_absent", + self::SIGNATURE_METHOD_REJECTED => "signature_method_rejected", + self::OAUTH_VERIFIER_INVALID => "verifier_invalid", + ); + + public $token; + public $token_secret; + public $consumer_key; + public $consumer_secret; + public $verifier; + + protected $problem; + + protected $tokenHandler; + protected $consumerHandler; + protected $nonceHandler; + + protected $requestPath; + /** + * Current URL + * @var Zend_Uri_Http + */ + protected $url; + /** + * + * Required OAuth parameters + * @var array + */ + protected $required = array("oauth_consumer_key", "oauth_signature", "oauth_signature_method", "oauth_nonce", "oauth_timestamp"); + + /** + * Set consumer key handler + * @param string $callback + * @return Zend_Oauth_Provider + */ + public function setConsumerHandler($callback) + { + $this->consumerHandler = $callback; + return $this; + } + + /** + * Set nonce/ts handler + * @param string $callback + * @return Zend_Oauth_Provider + */ + public function setTimestampNonceHandler($callback) + { + $this->nonceHandler = $callback; + return $this; + } + + /** + * Set token handler + * @param string $callback + * @return Zend_Oauth_Provider + */ + public function setTokenHandler($callback) + { + $this->tokenHandler = $callback; + return $this; + } + + /** + * Set URL for requesting token (doesn't need token) + * @param string $req_path + * @return Zend_Oauth_Provider + */ + public function setRequestTokenPath($req_path) + { + $this->requestPath = $req_path; + return $this; + } + + /** + * Set this request as token endpoint + * @param string $request + * @return Zend_Oauth_Provider + */ + public function isRequestTokenEndpoint($request) + { + $this->is_request = $request; + return $this; + } + + /** + * Report problem in OAuth as string + * @param Zend_Oauth_Exception $e + * @return string + */ + public function reportProblem(Zend_Oauth_Exception $e) + { + $code = $e->getCode(); + if($code == self::PARAMETER_ABSENT) { + return "oauth_problem=parameter_absent&oauth_parameters_absent={$this->problem}"; + } + if($code == self::INVALID_SIGNATURE) { + return "oauth_problem=signature_invalid&debug_sbs={$this->problem}"; + } + if(isset($this->errnames[$code])) { + return "oauth_problem=".$this->errnames[$code]; + } + return "oauth_problem=unknown_problem&code=$code"; + } + + /** + * Check if this request needs token + * @return bool + */ + protected function needsToken() + { + if(!empty($this->is_request)) { + return false; + } + if(empty($this->requestPath)) { + return true; + } + $GLOBALS['log']->debug("URLs: now: ".$this->url->getUri(). " req: {$this->requestPath}"); + if($this->requestPath[0] == '/') { + return $this->url->getPath() != $this->requestPath; + } + return $this->url->getUri() != $this->requestPath; + } + + /** + * Check if all required parameters are there + * @param array $params + * @throws Zend_Oauth_Exception + */ + protected function checkRequiredParams($params) + { + foreach($this->required as $param) { + if(!isset($params[$param])) { + $this->problem = $param; + throw new Zend_Oauth_Exception("Missing parameter: $param", self::PARAMETER_ABSENT); + } + } + if($this->needsToken() && !isset($params["oauth_token"])) { + $this->problem = "oauth_token"; + throw new Zend_Oauth_Exception("Missing parameter: oauth_token", self::PARAMETER_ABSENT); + } + return true; + } + + /** + * Check if signature method is supported + * @param string $signatureMethod + * @throws Zend_Oauth_Exception + */ + protected function checkSignatureMethod($signatureMethod) + { + $className = ''; + $hashAlgo = null; + $parts = explode('-', $signatureMethod); + if (count($parts) > 1) { + $className = 'Zend_Oauth_Signature_' . ucfirst(strtolower($parts[0])); + } else { + $className = 'Zend_Oauth_Signature_' . ucfirst(strtolower($signatureMethod)); + } + $filename = str_replace('_', '/', $className) . '.php'; + if(file_exists($filename)) { + require_once $filename; + } + if(!class_exists($className)) { + throw new Zend_Oauth_Exception("Invalid signature method", self::SIGNATURE_METHOD_REJECTED); + } + } + + /** + * Collect request parameters from the environment + * @param string $method HTTP method being used + * @param string $params Extra parameters + */ + protected function assembleParams($method, $params = array()) + { + $params = array_merge($_GET, $params); + if($method == 'POST') { + $params = array_merge($_POST, $params); + } + $auth = null; + if(function_exists('apache_request_headers')) { + $headers = apache_request_headers(); + if(isset($headers['Authorization'])) { + $auth = $headers['Authorization']; + } elseif(isset($headers['authorization'])) { + $auth = $headers['authorization']; + } + } + if(empty($auth) && !empty($_SERVER['HTTP_AUTHORIZATION'])) { + $auth = $_SERVER['HTTP_AUTHORIZATION']; + } + + if(!empty($auth) && substr($auth, 0, 6) == 'OAuth ') { + // import header data + if (preg_match_all('/(oauth_[a-z_-]*)=(:?"([^"]*)"|([^,]*))/', $_SERVER['HTTP_AUTHORIZATION'], $matches)) { + foreach ($matches[1] as $num => $header) { + if($header == 'realm') { + continue; + } + $params[$header] = urldecode(empty($matches[3][$num])? $matches[4][$num] : $matches[3][$num]); + } + } + } + return $params; + } + + /** + * Get current request URL + */ + protected function getRequestUrl() + { + $proto = "http"; + if(empty($_SERVER['SERVER_PORT']) || empty($_SERVER['HTTP_HOST']) || empty($_SERVER['REQUEST_URI'])) { + return Zend_Uri_Http::fromString("http://localhost/"); + } + if($_SERVER['SERVER_PORT'] == 443 || (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on')) { + $proto = 'https'; + } + return Zend_Uri_Http::fromString("$proto://{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}"); + } + + /** + * Validate OAuth request + * @param Zend_Uri_Http $url Request URL, will use current if null + * @param array $params Additional parameters + * @return bool + * @throws Zend_Oauth_Exception + */ + public function checkOAuthRequest(Zend_Uri_Http $url = null, $params = array()) + { + if(empty($url)) { + $this->url = $this->getRequestUrl(); + } else { + $this->url = clone $url; + } + // We'll ignore query for the pruposes of URL matching + $this->url->setQuery(''); + + if(isset($_SERVER['REQUEST_METHOD'])) { + $method = $_SERVER['REQUEST_METHOD']; + } elseif(isset($_SERVER['HTTP_METHOD'])) { + $method = $_SERVER['HTTP_METHOD']; + } else { + $method = 'GET'; + } + $params = $this->assembleParams($method, $params); + $this->checkSignatureMethod($params['oauth_signature_method']); + $this->checkRequiredParams($params); + + $this->timestamp = $params['oauth_timestamp']; + $this->nonce = $params['oauth_nonce']; + $this->consumer_key = $params['oauth_consumer_key']; + + if(!is_callable($this->nonceHandler)) { + throw new Zend_Oauth_Exception("Nonce handler not callable", self::BAD_NONCE); + } + + $res = call_user_func($this->nonceHandler, $this); + if($res != self::OK) { + throw new Zend_Oauth_Exception("Invalid request", $res); + } + + if(!is_callable($this->consumerHandler)) { + throw new Zend_Oauth_Exception("Consumer handler not callable", self::CONSUMER_KEY_UNKNOWN); + } + + $res = call_user_func($this->consumerHandler, $this); + // this will set $this->consumer_secret if OK + if($res != self::OK) { + throw new Zend_Oauth_Exception("Consumer key invalid", $res); + } + + if($this->needsToken()) { + $this->token = $params['oauth_token']; + $this->verifier = $params['oauth_verifier']; + if(!is_callable($this->tokenHandler)) { + throw new Zend_Oauth_Exception("Token handler not callable", self::TOKEN_REJECTED); + } + $res = call_user_func($this->tokenHandler, $this); + // this will set $this->token_secret if OK + if($res != self::OK) { + throw new Zend_Oauth_Exception("Token invalid", $res); + } + } + + $util = new Zend_Oauth_Http_Utility(); + $req_sign = $params['oauth_signature']; + unset($params['oauth_signature']); + $our_sign = $util->sign($params, $params['oauth_signature_method'], $this->consumer_secret, + $this->token_secret, $method, $this->url->getUri()); + if($req_sign != $our_sign) { + // TODO: think how to extract signature base string + $this->problem = $our_sign; + throw new Zend_Oauth_Exception("Invalid signature", self::INVALID_SIGNATURE); + } + + return true; + } + + /** + * Generate new token + * @param int $size How many characters? + */ + public function generateToken($size) + { + $str = ''; + while(strlen($str) < $size) { + $str .= md5(uniqid(mt_rand(), true), true); + } + return substr($str, 0, $size); + } +} \ No newline at end of file diff --git a/data/BeanFactory.php b/data/BeanFactory.php new file mode 100644 index 00000000..6e260732 --- /dev/null +++ b/data/BeanFactory.php @@ -0,0 +1,193 @@ +retrieve($id); + if($result == null) + return FALSE; + else + self::registerBean($module, $bean, $id); + } else + { + self::$hits++; + self::$touched[$module][$id]++; + $bean = self::$loadedBeans[$module][$id]; + } + } else { + $bean = new $beanClass(); + } + + return $bean; + } + + public static function newBean($module) + { + return self::getBean($module); + } + + public static function getBeanName($module) + { + global $beanList; + if (empty($beanList[$module])) return false; + + return $beanList[$module]; + } + + /** + * Returns the object name / dictionary key for a given module. This should normally + * be the same as the bean name, but may not for special case modules (ex. Case vs aCase) + * @static + * @param String $module + * @return bool + */ + public static function getObjectName($module) + { + global $objectList; + if (empty($objectList[$module])) + return self::getBeanName($module); + + return $objectList[$module]; + } + + + /** + * @static + * This function registers a bean with the bean factory so that it can be access from accross the code without doing + * multiple retrieves. Beans should be registered as soon as they have an id. + * @param String $module + * @param SugarBean $bean + * @param bool|String $id + * @return bool true if the bean registered successfully. + */ + public static function registerBean($module, $bean, $id=false) + { + global $beanList; + if (empty($beanList[$module])) return false; + + if (!isset(self::$loadedBeans[$module])) + self::$loadedBeans[$module] = array(); + + //Do not double register a bean + if (!empty($id) && isset(self::$loadedBeans[$module][$id])) + return true; + + $index = "i" . (self::$total % self::$maxLoaded); + //We should only hold a limited number of beans in memory at a time. + //Once we have the max, unload the oldest bean. + if (count(self::$loadOrder) >= self::$maxLoaded - 1) + { + for($i = 0; $i < self::$maxLoaded; $i++) + { + if (isset(self::$loadOrder[$index])) + { + $info = self::$loadOrder[$index]; + //If a bean isn't in the database yet, we need to hold onto it. + if (!empty(self::$loadedBeans[$info['module']][$info['id']]->in_save)) + { + self::$total++; + } + //Beans that have been used recently should be held in memory if possible + else if (!empty(self::$touched[$info['module']][$info['id']]) && self::$touched[$info['module']][$info['id']] > 0) + { + self::$touched[$info['module']][$info['id']]--; + self::$total++; + } + else + break; + } else { + break; + } + $index = "i" . (self::$total % self::$maxLoaded); + } + if (isset(self::$loadOrder[$index])) + { + unset(self::$loadedBeans[$info['module']][$info['id']]); + unset(self::$touched[$info['module']][$info['id']]); + unset(self::$loadOrder[$index]); + } + } + + if(!empty($bean->id)) + $id = $bean->id; + + if ($id) + { + self::$loadedBeans[$module][$id] = $bean; + self::$total++; + self::$loadOrder[$index] = array("module" => $module, "id" => $id); + self::$touched[$module][$id] = 0; + } else{ + return false; + } + return true; + } +} + diff --git a/data/Link.php b/data/Link.php index f0b84ed4..cdfedd2e 100644 --- a/data/Link.php +++ b/data/Link.php @@ -45,7 +45,6 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); ********************************************************************************/ - class Link { /* Private variables.*/ @@ -81,11 +80,13 @@ class Link { * $_key_name: optional, name of the primary key column for _table_name */ function Link($_rel_name, &$_bean, $fieldDef, $_table_name='', $_key_name=''){ - $GLOBALS['log']->debug("Link Constructor, relationship name: ".$_rel_name); + global $dictionary; + require_once("modules/TableDictionary.php"); + $GLOBALS['log']->debug("Link Constructor, relationship name: ".$_rel_name); $GLOBALS['log']->debug("Link Constructor, Table name: ".$_table_name); $GLOBALS['log']->debug("Link Constructor, Key name: ".$_key_name); - //_pp(func_get_args()); - $this->_relationship_name=$_rel_name; + + $this->_relationship_name=$_rel_name; $this->relationship_fields = (!empty($fieldDef['rel_fields']))?$fieldDef['rel_fields']: array(); $this->_bean=&$_bean; $this->_relationship=new Relationship(); @@ -143,6 +144,10 @@ class Link { } + function loadedSuccesfully() { + return !empty($this->_relationship->id); + } + /* This method will return the following based on cardinality of the relationship. * # one-to-many, many-to-many: empty array if not data is found else array of keys. * # if many-to-many and $role set to true : empty array if not data is found else @@ -624,7 +629,7 @@ class Link { } $query.=' WHERE '.$this->_relationship->rhs_table.".id='".$where_key_value."'"; - $GLOBALS['log']->debug("Relationship Query ".$query); + $GLOBALS['log']->fatal("Relationship Query ".$query); $result=$this->_db->query($query, true); } @@ -642,6 +647,7 @@ class Link { if (!empty($this->_relationship->relationship_role_column)) { $bean->{$this->_relationship->relationship_role_column}=$this->_relationship->relationship_role_column_value; } + $GLOBALS['log']->fatal("Adding many to one bean based {$bean->module_dir} {$bean->id}"); $bean->save(); } @@ -656,13 +662,13 @@ class Link { function add($rel_keys,$additional_values=array()) { if (!isset($rel_keys) or empty($rel_keys)) { - $GLOBALS['log']->debug("Link.add, Null key passed, no-op, returning... "); + $GLOBALS['log']->fatal("Link.add, Null key passed, no-op, returning... "); return; } //check to ensure that we do in fact have an id on the bean. if(empty($this->_bean->id)){ - $GLOBALS['log']->debug("Link.add, No id on the bean... "); + $GLOBALS['log']->fatal("Link.add, No id on the bean... "); return; } @@ -674,7 +680,7 @@ class Link { $bean_is_lhs=$this->_get_bean_position(); if (!isset($bean_is_lhs)) { - $GLOBALS['log']->debug("Invalid relationship parameters. Exiting.."); + $GLOBALS['log']->fatal("Invalid relationship parameters. Exiting.."); return null; } //if multiple keys are passed then check for unsupported relationship types. @@ -682,16 +688,16 @@ class Link { if (($this->_relationship->relationship_type == 'one-to-one') or ($this->_relationship->relationship_type == 'one-to-many' and !$bean_is_lhs) or ($this->_relationship->relationship_type == 'many-to-one')) { - $GLOBALS['log']->error("Invalid parameters passed to function, the relationship does not support addition of multiple records."); + $GLOBALS['log']->fatal("Invalid parameters passed to function, the relationship does not support addition of multiple records."); return; } } - $GLOBALS['log']->debug("Relationship type = {$this->_relationship->relationship_type}"); + $GLOBALS['log']->fatal("Relationship type = {$this->_relationship->relationship_type}"); foreach($keys as $key) { //fetch the related record using the key and update. - if ($this->_relationship->relationship_type=='one-to-one' or $this->_relationship->relationship_type == 'one-to-many') { - $this->_add_one_to_many_table_based($key,$bean_is_lhs); + if ($this->_relationship->relationship_type=='one-to-one' || $this->_relationship->relationship_type == 'one-to-many' ) { + $this->_add_one_to_many_table_based($key,$bean_is_lhs); } //updates the bean passed to the instance.... @@ -702,6 +708,17 @@ class Link { //insert record in the link table. if ($this->_relationship->relationship_type=='many-to-many' ) { + //replace existing relationships for one-to-one + if(!empty($GLOBALS['dictionary'][$this->_relationship_name]['true_relationship_type']) && + ($GLOBALS['dictionary'][$this->_relationship_name]['true_relationship_type'] == 'one-to-one')) + { + //Remove all existing links with either bean. + $old_rev = isset($this->_relationship->reverse) ? false : $this->_relationship->reverse; + $this->_relationship->reverse = true; + $this->delete($key); + $this->delete($this->_bean->id); + $this->_relationship->reverse = $old_rev; + } //Swap the bean positions for self relationships not coming from subpanels. //such as one-to-many relationship fields generated in studio/MB @@ -931,7 +948,7 @@ class Link { } //if query string is not empty execute it. if (isset($query)) { - $GLOBALS['log']->debug('Link.Delete:Delete Query: '.$query); + $GLOBALS['log']->fatal('Link.Delete:Delete Query: '.$query); $this->_db->query($query,true); } $custom_logic_arguments = array(); diff --git a/data/Link2.php b/data/Link2.php new file mode 100644 index 00000000..ee351246 --- /dev/null +++ b/data/Link2.php @@ -0,0 +1,615 @@ +focus = $bean; + //Try to load the link vardef from the beans field defs. Otherwise start searching + if (empty($bean->field_defs) || empty($bean->field_defs[$linkName]) || empty($bean->field_defs[$linkName]['relationship'])) + { + if (empty($linkDef)) + { + //Assume $linkName is really relationship_name, and find the link name with the vardef manager + $this->def = VardefManager::getLinkFieldForRelationship($bean->module_dir, $bean->object_name, $linkName); + } + else { + $this->def = $linkDef; + } + //Check if multiple links were found for a given relationship + if (is_array($this->def) && !isset($this->def['name'])) + { + //More than one link found, we need to figure out if we are currently on the LHS or RHS + //default to lhs for now + if (isset($this->def[0]['side']) && $this->def[0]['side'] == 'left') + { + $this->def = $this->def[0]; + } + else if (isset($this->def[1]['side']) && $this->def[1]['side'] == 'left') + { + $this->def = $this->def[1]; + } + else { + $this->def = $this->def[0]; + } + } + if (empty($this->def['name'])) + { + $GLOBALS['log']->fatal("failed to find link for $linkName"); + return false; + } + + $this->name = $this->def['name']; + } + else { + //Linkdef was found in the bean (this is the normal expectation) + $this->def = $bean->field_defs[$linkName]; + $this->name = $linkName; + } + //Instantiate the relationship for this link. + $this->relationship = SugarRelationshipFactory::getInstance()->getRelationship($this->def['relationship']); + + if (!$this->loadedSuccesfully()) + { + $GLOBALS['log']->fatal("{$this->name} for {$this->def['relationship']} failed to load\n"); + } + //Following behavior is tied to a property(ignore_role) value in the vardef. It alters the values of 2 properties, ignore_role_filter and add_distinct. + //the property values can be altered again before any requests are made. + if (!empty($this->def) && is_array($this->def)) { + if (array_key_exists('ignore_role', $this->def)) { + if ($this->def['ignore_role']) { + $this->ignore_role_filter=true; + $this->add_distinct=true; + } + } + } + } + + /** + * Returns false if no relationship was found for this link + * @return bool + */ + public function loadedSuccesfully() + { + return !empty($this->relationship); + } + + /** + * Forces the link to load the relationship rows. + * Will be called internally when the $rows property is accessed or get() is called + * @return void + */ + public function load() + { + $data = $this->relationship->load($this); + $this->rows = $data['rows']; + $this->beans = null; + $this->loaded = true; + } + + /** + * @return array ids of records related through this link + */ + public function get($role = false) { + if (!$this->loaded) + $this->load(); + + return array_keys($this->rows); + } + + /** + * @deprecated + * + * @return string name of table for the relationship of this link + */ + public function getRelatedTableName() { + return BeanFactory::getBean($this->getRelatedModuleName())->table_name; + } + + /** + * @return string the name of the module on the other side of this link + */ + public function getRelatedModuleName() { + if (!$this->relationship) return false; + + if ($this->getSide() == REL_LHS) { + return $this->relationship->getRHSModule(); + } else { + return $this->relationship->getLHSModule(); + } + } + + /** + * @return string the name of the link field used on the other side of the rel + */ + public function getRelatedModuleLinkName() { + if (!$this->relationship) return false; + + if ($this->getSide() == REL_LHS) { + return $this->relationship->getRHSLink(); + } else { + return $this->relationship->getLHSLink(); + } + } + + /** + * + * @return string "many" if multiple records can be related through this link + * or "one" if at most, one record can be related. + */ + public function getType() + { + switch ($this->relationship->type) + { + case REL_MANY_MANY: + return "many"; + case REL_ONE_ONE: + return "one"; + case REL_ONE_MANY: + return $this->getSide() == REL_LHS ? "many" : "one"; + } + return "many"; + } + + /** + * @return SugarBean The parent Bean this link references + */ + public function getFocus() + { + return $this->focus; + } + + /** + * @deprecated + * @return list of fields that exist only on the relationship + */ + public function getRelatedFields(){ + return $this->relationship_fields; + } + + /** + * @param $name + * @return The value for the relationship field $name + */ + public function getRelatedField($name){ + if (!empty($this->relationship_fields) && !empty($this->relationship_fields[$name])) + return $this->relationship_fields[$name]; + else + return null; //For now return null. Later try the relationship object directly. + } + + /** + * @return SugarRelationship the relationship object this link references + */ + public function getRelationshipObject() { + return $this->relationship; + } + + /** + * @return string "LHS" or "RHS" depending on the side of the relationship this link represents + */ + public function getSide() { + //First try the relationship + if ($this->relationship->getLHSLink() == $this->name && + ($this->relationship->getLHSModule() == $this->focus->module_name) + ){ + return REL_LHS; + } + + if ($this->relationship->getRHSLink() == $this->name && + ($this->relationship->getRHSModule() == $this->focus->module_name) + ){ + return REL_RHS; + } + + //Next try the vardef + if (!empty($this->def['side'])) + { + if ((strtolower($this->def['side']) == 'left' || $this->def['side'] == REL_LHS) + //Some relationships make have left in the vardef errorneously if generated by module builder + && $this->name != $this->relationship->def['join_key_lhs']) + { + return REL_LHS ; + } + else { + return REL_RHS; + } + } + //Next try using the id_name and relationship join keys + else if (!empty($this->def['id_name'])) + { + if (isset($this->relationship->def['join_key_lhs']) && $this->def['id_name'] == $this->relationship->def['join_key_lhs']) + return REL_RHS; + else if (isset($this->relationship->def['join_key_rhs']) && $this->def['id_name'] == $this->relationship->def['join_key_rhs']) + return REL_LHS; + } + + $GLOBALS['log']->error("Unable to get proper side for link {$this->name}"); + } + + /** + * @return bool true if LHSModule == RHSModule + */ + protected function is_self_relationship() { + return $this->relationship->isSelfReferencing(); + } + + /** + * @return bool true if this link represents a relationship where the parent could be one of multiple modules. (ex. Activities parent) + */ + public function isParentRelationship(){ + return $this->relationship->isParentRelationship(); + } + + /** + * @param $params array of parameters. Possible parameters include: + * 'join_table_link_alias': alias the relationship join table in the query (for M2M relationships), + * 'join_table_alias': alias for the final table to be joined against (usually a module main table) + * @param bool $return_array if true the query is returned as a array broken up into + * select, join, where, type, rel_key, and joined_tables + * @return string/array join query for this link + */ + function getJoin($params, $return_array =false) + { + return $this->relationship->getJoin($this, $params, $return_array); + } + + /** + * @param array $params optional parameters. Possible Values; + * 'return_as_array': returns the query broken into + * @return String/Array query to grab just ids for this relationship + */ + function getQuery($params = array()) + { + return $this->relationship->getQuery($this, $params); + } + + /** + * This function is similair getJoin except for M2m relationships it won't join agaist the final table. + * Its used to retrieve the ID of the related beans only + * @param $params array of parameters. Possible parameters include: + * 'return_as_array': returns the query broken into + * @param bool $return_array same as passing 'return_as_array' into parameters + * @return string/array query to use when joining for subpanels + */ + public function getSubpanelQuery($params = array(), $return_array = false) + { + if (!empty($this->def['ignore_role'])) + $params['ignore_role'] = true; + return $this->relationship->getSubpanelQuery($this, $params, $return_array); + } + + /** + * @return array of SugarBeans related through this link. Use with caution. + */ + function getBeans() { + if (!$this->loaded) { + $this->load(); + } + if(!is_array($this->beans)) + { + $this->beans = array(); + $rel_module = $this->getRelatedModuleName(); + foreach ($this->rows as $id => $vals) + { + $tmpBean = BeanFactory::getBean($rel_module, $id); + if($tmpBean !== FALSE) + $this->beans[$id] = $tmpBean; + } + } + + return $this->beans; + } + + /** + * @return bool true if this link has initialized its related beans. + */ + public function beansAreLoaded() { + return is_array($this->beans); + } + + /** + * use this function to create link between 2 objects + * 1:1 will be treated like 1 to many. + * + * the function also allows for setting of values for additional field in the table being + * updated to save the relationship, in case of many-to-many relationships this would be the join table. + * + * @param array $rel_keys array of ids or SugarBean objects. If you have the bean in memory, pass it in. + * @param array $additional_values the values should be passed as key value pairs with column name as the key name and column value as key value. + * + * @return void + */ + function add($rel_keys,$additional_values=array()) { + if (!is_array($rel_keys)) + $rel_keys = array($rel_keys); + + foreach($rel_keys as $key) + { + //We must use beans for LogicHooks and other buisiness logic to fire correctly + if (!($key instanceof SugarBean)) { + $key = $this->getRelatedBean($key); + if (!($key instanceof SugarBean)) { + $GLOBALS['log']->error("Unable to load related bean by id"); + return false; + } + } + + if(empty($key->id) || empty($this->focus->id)) + return false; + + if ($this->getSide() == REL_LHS) { + $this->relationship->add($this->focus, $key, $additional_values); + } + else { + $this->relationship->add($key, $this->focus, $additional_values); + } + } + } + + + + /** + * Marks the relationship delted for this given record pair. + * @param $id id of the Parent/Focus SugarBean + * @param string $related_id id or SugarBean to unrelate. Pass a SugarBean if you have it. + * @return void + */ + function delete($id, $related_id='') { + if (empty($this->focus->id)) + $this->focus = BeanFactory::getBean($this->focus->module_name, $id); + if (!empty($related_id)) + { + if (!($related_id instanceof SugarBean)) { + $related_id = $this->getRelatedBean($related_id); + } + if ($this->getSide() == REL_LHS) { + $this->relationship->remove($this->focus, $related_id); + } + else { + $this->relationship->remove($related_id, $this->focus); + } + } + else + { + $this->relationship->removeAll($this); + } + } + + /** + * Returns a SugarBean with the given ID from the related module. + * @param bool $id id of related record to retrieve + * @return SugarBean + */ + protected function getRelatedBean($id = false) + { + return BeanFactory::getBean($this->getRelatedModuleName(), $id); + } + + public function &__get($name) + { + switch($name) + { + case "relationship_type": + return $this->relationship->type; + case "_relationship": + return $this->relationship; + case "beans": + if (!is_array($this->beans)) + $this->getBeans(); + return $this->beans; + case "rows": + if (!is_array($this->rows)) + $this->load(); + return $this->rows; + } + return $this->$name; + } + + public function __set($name, $val) + { + if($name == "beans") + $this->beans = $val; + + } + + /** + * @param SugarBean $bean + * @return void + */ + public function addBean($bean) + { + if (!is_array($this->beans)) + $this->getBeans(); + $this->beans[$bean->id] = $bean; + } + + /** + * @param SugarBean $bean + * @return void + */ + public function removeBean($bean) + { + if (!is_array($this->beans)) + $this->getBeans(); + unset($this->beans[$bean->id]); + unset($this->rows[$bean->id]); + } + + + /** + * @param $table_name string relationship table + * @param $join_key_values array of key=>values to identify this relationship by + * @return bool true if the given join key set exists in the relationship table + */ + public function relationship_exists($table_name, $join_key_values) { + + //find the key values for the table. + $dup_keys=$this->_get_alternate_key_fields($table_name); + if (empty($dup_keys)) { + $GLOBALS['log']->debug("No alternate key define, skipping duplicate check.."); + return false; + } + + $delimiter=''; + $this->_duplicate_where=' WHERE '; + foreach ($dup_keys as $field) { + //look for key in $join_key_values, if found add to filter criteria else abort duplicate checking. + if (isset($join_key_values[$field])) { + + $this->_duplicate_where .= $delimiter.' '.$field."='".$join_key_values[$field]."'"; + $delimiter='AND'; + } else { + $GLOBALS['log']->error('Duplicate checking aborted, Please supply a value for this column '.$field); + return false; + } + } + //add deleted check. + $this->_duplicate_where .= $delimiter.' deleted=0'; + + $query='SELECT id FROM '.$table_name.$this->_duplicate_where; + + $GLOBALS['log']->debug("relationship_exists query(".$query.')'); + + $result=$this->_db->query($query, true); + $row = $this->_db->fetchByAssoc($result); + + if ($row == null) { + return false; + } + else { + $this->_duplicate_key=$row['id']; + return true; + } + } + + //Below are functions not used directly and exist for backwards compatiblity with customizations, will be removed in a later version + + /* returns array of keys for duplicate checking, first check for an index of type alternate_key, if not found searches for + * primary key. + * + */ + public function _get_alternate_key_fields($table_name) { + $indices=Link::_get_link_table_definition($table_name,'indices'); + if (!empty($indices)) { + foreach ($indices as $index) { + if ( isset($index['type']) && $index['type'] == 'alternate_key' ) { + return $index['fields']; + } + } + } + //bug 32623, when the relationship is built in old version, there is no alternate_key. we have to use join_key_lhs and join_key_lhs. + $relDef = $this->relationship->def; + if (!empty($relDef['join_key_lhs']) && !empty($relDef['join_key_rhs'])) + return array($relDef['join_key_lhs'], $relDef['join_key_rhs']); + } + + /** + * @depricated + * Gets the vardef for the relationship of this link. + */ + public function _get_link_table_definition($table_name, $def_name) { + + if (isset($this->relationship->def[$def_name])) + return $this->relationship->def[$def_name]; + + return null; + } + + /** + * @depricated + * Return the name of the role field for the passed many to many table. + * if there is no role filed : return false + * @param $table_name name of relationship table to inspect + * @return bool|string + */ + public function _get_link_table_role_field($table_name) { + $varDefs = $this->_get_link_table_definition($table_name, 'fields'); + $role_field = false; + if(!empty($varDefs)){ + $role_field = ''; + foreach($varDefs as $v){ + if(strpos($v['name'], '_role') !== false){ + $role_field = $v['name']; + } + } + } + return $role_field; + } + + /** + * @deprecated + * + * @return boolean returns true if this link is LHS + */ + public function _get_bean_position() + { + return $this->getSide() == REL_LHS; + } +} +?> diff --git a/data/Relationships/EmailAddressRelationship.php b/data/Relationships/EmailAddressRelationship.php new file mode 100644 index 00000000..b69be30e --- /dev/null +++ b/data/Relationships/EmailAddressRelationship.php @@ -0,0 +1,114 @@ +value pairs of fields to save on the relationship + * @return boolean true if successful + */ + public function add($lhs, $rhs, $additionalFields = array()) + { + $lhsLinkName = $this->lhsLink; + + if (empty($lhs->$lhsLinkName) && !$lhs->load_relationship($lhsLinkName)) + { + $lhsClass = get_class($lhs); + $GLOBALS['log']->fatal("could not load LHS $lhsLinkName in $lhsClass"); + return false; + } + + //Many to many has no additional logic, so just add a new row to the table and notify the beans. + $dataToInsert = $this->getRowToInsert($lhs, $rhs, $additionalFields); + + $this->addRow($dataToInsert); + + if ($this->self_referencing) + $this->addSelfReferencing($lhs, $rhs, $additionalFields); + + if ($lhs->$lhsLinkName->beansAreLoaded()) + $lhs->$lhsLinkName->addBean($rhs); + + $this->callAfterAdd($lhs, $rhs, $lhsLinkName); + } + + public function remove($lhs, $rhs) + { + $lhsLinkName = $this->lhsLink; + + if (!($lhs instanceof SugarBean)) { + $GLOBALS['log']->fatal("LHS is not a SugarBean object"); + return false; + } + if (!($rhs instanceof SugarBean)) { + $GLOBALS['log']->fatal("RHS is not a SugarBean object"); + return false; + } + if (empty($lhs->$lhsLinkName) && !$lhs->load_relationship($lhsLinkName)) + { + $GLOBALS['log']->fatal("could not load LHS $lhsLinkName"); + return false; + } + $dataToRemove = array( + $this->def['join_key_lhs'] => $lhs->id, + $this->def['join_key_rhs'] => $rhs->id + ); + + $this->removeRow($dataToRemove); + + if ($this->self_referencing) + $this->removeSelfReferencing($lhs, $rhs); + + if (empty($_SESSION['disable_workflow']) || $_SESSION['disable_workflow'] != "Yes") + { + if (!empty($lhs->$lhsLinkName)) + { + $lhs->$lhsLinkName->load(); + $this->callAfterDelete($lhs, $rhs, $lhsLinkName); + } + } + } +} \ No newline at end of file diff --git a/data/Relationships/M2MRelationship.php b/data/Relationships/M2MRelationship.php new file mode 100644 index 00000000..1a950333 --- /dev/null +++ b/data/Relationships/M2MRelationship.php @@ -0,0 +1,530 @@ +def = $def; + $this->name = $def['name']; + + $lhsModule = $def['lhs_module']; + $this->lhsLinkDef = $this->getLinkedDefForModuleByRelationship($lhsModule); + $this->lhsLink = $this->lhsLinkDef['name']; + + $rhsModule = $def['rhs_module']; + $this->rhsLinkDef = $this->getLinkedDefForModuleByRelationship($rhsModule); + $this->rhsLink = $this->rhsLinkDef['name']; + + $this->self_referencing = $lhsModule == $rhsModule; + } + + /** + * Find the link entry for a particular relationship and module. + * + * @param $module + * @return array|bool + */ + public function getLinkedDefForModuleByRelationship($module) + { + $results = VardefManager::getLinkFieldForRelationship( $module, BeanFactory::getObjectName($module), $this->name); + //Only a single link was found + if( isset($results['name']) ) + { + return $results; + } + //Multiple links with same relationship name + else if( is_array($results) ) + { + $GLOBALS['log']->error("Warning: Multiple links found for relationship {$this->name} within module {$module}"); + return $this->getMostAppropriateLinkedDefinition($results); + } + else + { + return FALSE; + } + } + + /** + * Find the most 'appropriate' link entry for a relationship/module in which there are multiple link entries with the + * same relationship name. + * + * @param $links + * @return bool + */ + protected function getMostAppropriateLinkedDefinition($links) + { + //First priority is to find a link name that matches the relationship name + foreach($links as $link) + { + if( isset($link['name']) && $link['name'] == $this->name ) + { + return $link; + } + } + //Next would be a relationship that has a side defined + foreach($links as $link) + { + if( isset($link['id_name'])) + { + return $link; + } + } + //Unable to find an appropriate link, guess and use the first one + $GLOBALS['log']->error("Unable to determine best appropriate link for relationship {$this->name}"); + return $links[0]; + } + /** + * @param $lhs SugarBean left side bean to add to the relationship. + * @param $rhs SugarBean right side bean to add to the relationship. + * @param $additionalFields key=>value pairs of fields to save on the relationship + * @return boolean true if successful + */ + public function add($lhs, $rhs, $additionalFields = array()) + { + $lhsLinkName = $this->lhsLink; + $rhsLinkName = $this->rhsLink; + + if (empty($lhs->$lhsLinkName) && !$lhs->load_relationship($lhsLinkName)) + { + $lhsClass = get_class($lhs); + $GLOBALS['log']->fatal("could not load LHS $lhsLinkName in $lhsClass"); + return false; + } + if (empty($rhs->$rhsLinkName) && !$rhs->load_relationship($rhsLinkName)) + { + $rhsClass = get_class($rhs); + $GLOBALS['log']->fatal("could not load RHS $rhsLinkName in $rhsClass"); + return false; + } + + //Many to many has no additional logic, so just add a new row to the table and notify the beans. + $dataToInsert = $this->getRowToInsert($lhs, $rhs, $additionalFields); + + $this->addRow($dataToInsert); + + if ($this->self_referencing) + $this->addSelfReferencing($lhs, $rhs, $additionalFields); + + if ($lhs->$lhsLinkName->beansAreLoaded()) + $lhs->$lhsLinkName->addBean($rhs); + if ($rhs->$rhsLinkName->beansAreLoaded()) + $rhs->$rhsLinkName->addBean($lhs); + + $this->callAfterAdd($lhs, $rhs, $lhsLinkName); + $this->callAfterAdd($rhs, $lhs, $rhsLinkName); + } + + protected function getRowToInsert($lhs, $rhs, $additionalFields = array()) + { + $row = array( + "id" => create_guid(), + $this->def['join_key_lhs'] => $lhs->id, + $this->def['join_key_rhs'] => $rhs->id, + 'date_modified' => TimeDate::getInstance()->getNow()->asDb(), + 'deleted' => 0, + ); + + + if (!empty($this->def['relationship_role_column']) && !empty($this->def['relationship_role_column_value']) && !$this->ignore_role_filter ) + { + $row[$this->relationship_role_column] = $this->relationship_role_column_value; + } + + if (!empty($this->def['fields'])) + { + foreach($this->def['fields'] as $fieldDef) + { + if (!empty($fieldDef['name']) && !isset($row[$fieldDef['name']]) && !empty($fieldDef['default'])) + { + $row[$fieldDef['name']] = $fieldDef['default']; + } + } + } + if (!empty($additionalFields)) + { + $row = array_merge($row, $additionalFields); + } + + return $row; + } + + /** + * Adds the reversed version of this relationship to the table so that it can be accessed from either side equally + * @param $lhs + * @param $rhs + * @param array $additionalFields + * @return void + */ + protected function addSelfReferencing($lhs, $rhs, $additionalFields = array()) + { + if ($rhs->id != $lhs->id) + { + $dataToInsert = $this->getRowToInsert($rhs, $lhs, $additionalFields); + $this->addRow($dataToInsert); + } + } + + public function remove($lhs, $rhs) + { + $lhsLinkName = $this->lhsLink; + $rhsLinkName = $this->rhsLink; + + if (!($lhs instanceof SugarBean)) { + $GLOBALS['log']->fatal("LHS is not a SugarBean object"); + return false; + } + if (!($rhs instanceof SugarBean)) { + $GLOBALS['log']->fatal("RHS is not a SugarBean object"); + return false; + } + if (empty($lhs->$lhsLinkName) && !$lhs->load_relationship($lhsLinkName)) + { + $GLOBALS['log']->fatal("could not load LHS $lhsLinkName"); + return false; + } + if (empty($rhs->$rhsLinkName) && !$rhs->load_relationship($rhsLinkName)) + { + $GLOBALS['log']->fatal("could not load RHS $rhsLinkName"); + return false; + } + + $dataToRemove = array( + $this->def['join_key_lhs'] => $lhs->id, + $this->def['join_key_rhs'] => $rhs->id + ); + + $this->removeRow($dataToRemove); + + if ($this->self_referencing) + $this->removeSelfReferencing($lhs, $rhs); + + if (empty($_SESSION['disable_workflow']) || $_SESSION['disable_workflow'] != "Yes") + { + if ($lhs->$lhsLinkName instanceof Link2) + { + $lhs->$lhsLinkName->load(); + $this->callAfterDelete($lhs, $rhs, $lhsLinkName); + } + + if ($rhs->$rhsLinkName instanceof Link2) + { + $rhs->$rhsLinkName->load(); + $this->callAfterDelete($rhs, $lhs, $rhsLinkName); + } + } + } + + /** + * Removes the reversed version of this relationship + * @param $lhs + * @param $rhs + * @param array $additionalFields + * @return void + */ + protected function removeSelfReferencing($lhs, $rhs, $additionalFields = array()) + { + if ($rhs->id != $lhs->id) + { + $dataToRemove = array( + $this->def['join_key_lhs'] => $rhs->id, + $this->def['join_key_rhs'] => $lhs->id + ); + $this->removeRow($dataToRemove); + } + } + + /** + * @param $link Link2 loads the relationship for this link. + * @return void + */ + public function load($link) + { + $db = DBManagerFactory::getInstance(); + $query = $this->getQuery($link); + $result = $db->query($query); + $rows = Array(); + $idField = $link->getSide() == REL_LHS ? $this->def['join_key_rhs'] : $this->def['join_key_lhs']; + while ($row = $db->fetchByAssoc($result)) + { + if (empty($row['id']) && empty($row[$idField])) + continue; + $id = empty($row['id']) ? $row[$idField] : $row['id']; + $rows[$id] = $row; + } + return array("rows" => $rows); + } + + public function getQuery($link, $params = array()) + { + if ($link->getSide() == REL_LHS) { + $knownKey = $this->def['join_key_lhs']; + $targetKey = $this->def['join_key_rhs']; + } + else + { + $knownKey = $this->def['join_key_rhs']; + $targetKey = $this->def['join_key_lhs']; + } + $rel_table = $this->getRelationshipTable(); + + $where = "$rel_table.$knownKey = '{$link->getFocus()->id}'" . $this->getRoleWhere(); + + if (empty($params['return_as_array'])) { + return "SELECT $targetKey id FROM $rel_table WHERE $where AND deleted=0"; + } + else + { + return array( + 'select' => "SELECT $targetKey id", + 'from' => "FROM $rel_table", + 'where' => "WHERE $where AND $rel_table.deleted=0", + ); + } + } + + public function getJoin($link, $params = array(), $return_array = false) + { + $linkIsLHS = $link->getSide() == REL_LHS; + if ($linkIsLHS) { + $startingTable = (empty($params['left_join_table_alias']) ? $link->getFocus()->table_name : $params['left_join_table_alias']); + } else { + $startingTable = (empty($params['right_join_table_alias']) ? $link->getFocus()->table_name : $params['right_join_table_alias']); + } + + $startingKey = $linkIsLHS ? $this->def['lhs_key'] : $this->def['rhs_key']; + $startingJoinKey = $linkIsLHS ? $this->def['join_key_lhs'] : $this->def['join_key_rhs']; + $joinTable = $this->getRelationshipTable(); + $joinTableWithAlias = $joinTable; + $joinKey = $linkIsLHS ? $this->def['join_key_rhs'] : $this->def['join_key_lhs']; + $targetTable = $linkIsLHS ? $this->def['rhs_table'] : $this->def['lhs_table']; + $targetTableWithAlias = $targetTable; + $targetKey = $linkIsLHS ? $this->def['rhs_key'] : $this->def['lhs_key']; + $join_type= isset($params['join_type']) ? $params['join_type'] : ' INNER JOIN '; + + $join = ''; + + //Set up any table aliases required + if (!empty($params['join_table_link_alias'])) + { + $joinTableWithAlias = $joinTable . " ". $params['join_table_link_alias']; + $joinTable = $params['join_table_link_alias']; + } + if ( ! empty($params['join_table_alias'])) + { + $targetTableWithAlias = $targetTable . " ". $params['join_table_alias']; + $targetTable = $params['join_table_alias']; + } + + $join1 = "$startingTable.$startingKey=$joinTable.$startingJoinKey"; + $join2 = "$targetTable.$targetKey=$joinTable.$joinKey"; + $where = ""; + + + //First join the relationship table + $join .= "$join_type $joinTableWithAlias ON $join1 AND $joinTable.deleted=0\n" + //Next add any role filters + . $this->getRoleWhere($joinTable) . "\n" + //Then finally join the related module's table + . "$join_type $targetTableWithAlias ON $join2 AND $targetTable.deleted=0\n"; + + if($return_array){ + return array( + 'join' => $join, + 'type' => $this->type, + 'rel_key' => $joinKey, + 'join_tables' => array($joinTable, $targetTable), + 'where' => $where, + 'select' => "$targetTable.id", + ); + } + return $join . $where; + } + + /** + * Similar to getQuery or Get join, except this time we are starting from the related table and + * searching for items with id's matching the $link->focus->id + * @param $link + * @param array $params + * @param bool $return_array + * @return String|Array + */ + public function getSubpanelQuery($link, $params = array(), $return_array = false) + { + $targetIsLHS = $link->getSide() == REL_RHS; + $startingTable = $targetIsLHS ? $this->def['lhs_table'] : $this->def['rhs_table'];; + $startingKey = $targetIsLHS ? $this->def['lhs_key'] : $this->def['rhs_key']; + $startingJoinKey = $targetIsLHS ? $this->def['join_key_lhs'] : $this->def['join_key_rhs']; + $joinTable = $this->getRelationshipTable(); + $joinTableWithAlias = $joinTable; + $joinKey = $targetIsLHS ? $this->def['join_key_rhs'] : $this->def['join_key_lhs']; + $targetKey = $targetIsLHS ? $this->def['rhs_key'] : $this->def['lhs_key']; + $join_type= isset($params['join_type']) ? $params['join_type'] : ' INNER JOIN '; + + $query = ''; + + //Set up any table aliases required + if (!empty($params['join_table_link_alias'])) + { + $joinTableWithAlias = $joinTable . " ". $params['join_table_link_alias']; + $joinTable = $params['join_table_link_alias']; + } + + $where = "$startingTable.$startingKey=$joinTable.$startingJoinKey AND $joinTable.$joinKey='{$link->getFocus()->$targetKey}'"; + + //Check if we should ignore the role fileter; + $ignoreRole = !empty($params['ignore_role']); + + //First join the relationship table + $query .= "$join_type $joinTableWithAlias ON $where AND $joinTable.deleted=0\n" + //Next add any role filters + . $this->getRoleWhere($joinTable, $ignoreRole) . "\n"; + + if (!empty($params['return_as_array'])) { + $return_array = true; + } + if($return_array){ + return array( + 'join' => $query, + 'type' => $this->type, + 'rel_key' => $joinKey, + 'join_tables' => array($joinTable), + 'where' => "", + 'select' => " ", + ); + } + return $query; + + } + + protected function getRoleFilterForJoin() + { + $ret = ""; + if (!empty($this->relationship_role_column) && !$this->ignore_role_filter) + { + $ret .= " AND ".$this->getRelationshipTable().'.'.$this->relationship_role_column; + //role column value. + if (empty($this->relationship_role_column_value)) + { + $ret.=' IS NULL'; + } else { + $ret.= "='".$this->relationship_role_column_value."'"; + } + $ret.= "\n"; + } + return $ret; + } + + /** + * @param $lhs + * @param $rhs + * @return bool + */ + public function relationship_exists($lhs, $rhs) + { + $query = "SELECT * FROM {$this->getRelationshipTable()} WHERE {$this->join_key_lhs} = {$lhs->id} AND {$this->join_key_rhs} = {$rhs->id}"; + + //Roles can allow for multiple links between two records with different roles + $query .= $this->getRoleWhere() . " and deleted = 0"; + + $result = DBManagerFactory::getInstance()->query($query); + $row = $this->_db->fetchByAssoc($result); + + if ($row == null) { + return false; + } + else { + return $row['id']; + } + } + + /** + * @return Array - set of fields that uniquely identify an entry in this relationship + */ + protected function getAlternateKeyFields() + { + $fields = array($this->join_key_lhs, $this->join_key_rhs); + + //Roles can allow for multiple links between two records with different roles + if (!empty($this->def['relationship_role_column']) && !$this->ignore_role_filter) + { + $fields[] = $this->relationship_role_column; + } + + return $fields; + } + + public function getRelationshipTable() + { + if (!empty($this->def['table'])) + return $this->def['table']; + else if(!empty($this->def['join_table'])) + return $this->def['join_table']; + + return false; + } + + public function getFields() + { + if (!empty($this->def['fields'])) + return $this->def['fields']; + $fields = array( + "id" => array('name' => 'id'), + 'date_modified' => array('name' => 'date_modified'), + 'modified_user_id' => array('name' => 'modified_user_id'), + 'created_by' => array('name' => 'created_by'), + $this->def['join_key_lhs'] => array('name' => $this->def['join_key_lhs']), + $this->def['join_key_rhs'] => array('name' => $this->def['join_key_rhs']) + ); + if (!empty($this->def['relationship_role_column'])) + { + $fields[$this->def['relationship_role_column']] = array("name" => $this->def['relationship_role_column']); + } + $fields['deleted'] = array('name' => 'deleted'); + + return $fields; + } + +} \ No newline at end of file diff --git a/data/Relationships/One2MBeanRelationship.php b/data/Relationships/One2MBeanRelationship.php new file mode 100644 index 00000000..899cacaa --- /dev/null +++ b/data/Relationships/One2MBeanRelationship.php @@ -0,0 +1,310 @@ +value pairs of fields to save on the relationship + * @return boolean true if successful + */ + public function add($lhs, $rhs, $additionalFields = array()) + { + $lhsLinkName = $this->lhsLink; + $rhsLinkName = $this->rhsLink; + + //Since this is bean based, we know updating the RHS's field will overwrite any old value, + //But we need to use delete to make sure custom logic is called correctly + if ($rhs->load_relationship($rhsLinkName)) + { + $oldLink = $rhs->$rhsLinkName; + $prevRelated = $oldLink->getBeans(null); + foreach($prevRelated as $oldLHS) + { + $this->remove($oldLHS, $rhs, false); + } + } + + //Make sure we load the current relationship state to the LHS link + if ((isset($lhs->$lhsLinkName) && is_a($lhs->$lhsLinkName, "Link2")) || $lhs->load_relationship($lhsLinkName)) { + $lhs->$lhsLinkName->getBeans(); + } + + $this->updateFields($lhs, $rhs, $additionalFields); + + + if (empty($_SESSION['disable_workflow']) || $_SESSION['disable_workflow'] != "Yes") + { + //Need to call save to update the bean as the relationship is saved on the main table + //We don't want to create a save loop though, so make sure we aren't already in the middle of saving this bean + SugarRelationship::addToResaveList($rhs); + + $this->updateLinks($lhs, $lhsLinkName, $rhs, $rhsLinkName); + + $this->callAfterAdd($lhs, $rhs); + $this->callAfterAdd($rhs, $lhs); + } + } + + protected function updateLinks($lhs, $lhsLinkName, $rhs, $rhsLinkName) + { + if (isset($lhs->$lhsLinkName)) + $lhs->$lhsLinkName->addBean($rhs); + //RHS only has one bean ever, so we don't need to preload the relationship + if (isset($rhs->$rhsLinkName)) + $rhs->$rhsLinkName->beans = array($lhs->id => $lhs); + } + + protected function updateFields($lhs, $rhs, $additionalFields) + { + //Now update the RHS bean's ID field + $rhsID = $this->def['rhs_key']; + $rhs->$rhsID = $lhs->id; + foreach($additionalFields as $field => $val) + { + $rhs->$field = $val; + } + //Update role fields + if(!empty($this->def["relationship_role_column"]) && !empty($this->def["relationship_role_column_value"])) + { + $roleField = $this->def["relationship_role_column"]; + $rhs->$roleField = $this->def["relationship_role_column_value"]; + } + } + + public function remove($lhs, $rhs, $save = true) + { + $rhsID = $this->def['rhs_key']; + + //If this relationship has already been removed, we can just return + if ($rhs->$rhsID != $lhs->id) + return; + + $rhs->$rhsID = ''; + + if ($save && !$rhs->deleted) + { + $rhs->in_relationship_update = TRUE; + $rhs->save(); + } + + if (empty($_SESSION['disable_workflow']) || $_SESSION['disable_workflow'] != "Yes") + { + $this->callAfterDelete($lhs, $rhs); + $this->callAfterDelete($rhs, $lhs); + } + } + + /** + * @param $link Link2 loads the relationship for this link. + * @return void + */ + public function load($link) + { + $relatedModule = $link->getSide() == REL_LHS ? $this->def['rhs_module'] : $this->def['lhs_module']; + $rows = array(); + //The related bean ID is stored on the RHS table. + //If the link is RHS, just grab it from the focus. + if ($link->getSide() == REL_RHS) + { + $rhsID = $this->def['rhs_key']; + $id = $link->getFocus()->$rhsID; + if (!empty($id)) + { + $rows[$id] = array('id' => $id); + } + } + else //If the link is LHS, we need to query to get the full list and load all the beans. + { + $db = DBManagerFactory::getInstance(); + $query = $this->getQuery($link); + if (empty($query)) + { + echo ("query for {$this->name} was empty when loading from {$this->lhsLink}\n"); + } + $result = $db->query($query); + while ($row = $db->fetchByAssoc($result)) + { + $id = $row['id']; + $rows[$id] = $row; + } + } + + return array("rows" => $rows); + } + + public function getQuery($link, $return_as_array = false) + { + + if ($link->getSide() == REL_RHS) { + return false; + } + else + { + $lhsKey = $this->def['lhs_key']; + $rhsTable = $this->def['rhs_table']; + $rhsTableKey = "{$rhsTable}.{$this->def['rhs_key']}"; + $where = "WHERE $rhsTableKey = '{$link->getFocus()->$lhsKey}' AND {$rhsTable}.deleted=0"; + //Check for role column + if(!empty($this->def["relationship_role_column"]) && !empty($this->def["relationship_role_column_value"])) + { + $roleField = $this->def["relationship_role_column"]; + $roleValue = $this->def["relationship_role_column_value"]; + $where .= " AND $rhsTable.$roleField = '$roleValue'"; + } + if (!$return_as_array) { + return "SELECT id FROM {$this->def['rhs_table']} $where"; + } + else + { + return array( + 'select' => "SELECT id", + 'from' => "FROM {$this->def['rhs_table']}", + 'where' => $where, + ); + } + } + } + + public function getJoin($link, $params = array(), $return_array = false) + { + $linkIsLHS = $link->getSide() == REL_LHS; + $startingTable = (empty($params['left_join_table_alias']) ? $this->def['lhs_table'] : $params['left_join_table_alias']); + if (!$linkIsLHS) + $startingTable = (empty($params['right_join_table_alias']) ? $this->def['rhs_table'] : $params['right_join_table_alias']); + $startingKey = $linkIsLHS ? $this->def['lhs_key'] : $this->def['rhs_key']; + $targetTable = $linkIsLHS ? $this->def['rhs_table'] : $this->def['lhs_table']; + $targetTableWithAlias = $targetTable; + $targetKey = $linkIsLHS ? $this->def['rhs_key'] : $this->def['lhs_key']; + $join_type= isset($params['join_type']) ? $params['join_type'] : ' INNER JOIN '; + $join = ''; + + //Set up any table aliases required + if ( ! empty($params['join_table_alias'])) + { + $targetTableWithAlias = $targetTable. " ".$params['join_table_alias']; + $targetTable = $params['join_table_alias']; + } + + //First join the relationship table + $join .= "$join_type $targetTableWithAlias ON $startingTable.$startingKey=$targetTable.$targetKey AND $targetTable.deleted=0\n" + //Next add any role filters + . $this->getRoleWhere(($linkIsLHS) ? $targetTable : $startingTable) . "\n"; + + if($return_array){ + return array( + 'join' => $join, + 'type' => $this->type, + 'rel_key' => $targetKey, + 'join_tables' => array($targetTable), + 'where' => "", + 'select' => "$targetTable.id", + ); + } + return $join; + } + + public function getSubpanelQuery($link, $params = array(), $return_array = false) + { + + $linkIsLHS = $link->getSide() == REL_RHS; + $startingTable = (empty($params['left_join_table_alias']) ? $this->def['lhs_table'] : $params['left_join_table_alias']); + if (!$linkIsLHS) + $startingTable = (empty($params['right_join_table_alias']) ? $this->def['rhs_table'] : $params['right_join_table_alias']); + $startingKey = $linkIsLHS ? $this->def['lhs_key'] : $this->def['rhs_key']; + $targetTable = $linkIsLHS ? $this->def['rhs_table'] : $this->def['lhs_table']; + $targetKey = $linkIsLHS ? $this->def['rhs_key'] : $this->def['lhs_key']; + $join_type= isset($params['join_type']) ? $params['join_type'] : ' INNER JOIN '; + $query = ''; + + $alias = empty($params['join_table_alias']) ? "{$link->name}_rel": $params['join_table_alias']; + //Set up any table aliases required + $targetTableWithAlias = "$targetTable $alias"; + $targetTable = $alias; + + $query .= "$join_type $targetTableWithAlias ON $startingTable.$startingKey=$targetTable.$targetKey AND $targetTable.deleted=0\n" + //Next add any role filters + . $this->getRoleWhere() . "\n"; + + if($return_array){ + return array( + 'join' => $query, + 'type' => $this->type, + 'rel_key' => $targetKey, + 'join_tables' => array($targetTable), + 'where' => "WHERE $startingTable.$startingKey='{$link->focus->id}'", + 'select' => " ", + ); + } + return $query; + + } + + /** + * @param $lhs + * @param $rhs + * @return bool + */ + public function relationship_exists($lhs, $rhs) + { + + return false; + } + + public function getRelationshipTable() + { + if (isset($this->def['table'])) + return $this->def['table']; + else + return $this->def['rhs_table']; + } +} diff --git a/data/Relationships/One2MRelationship.php b/data/Relationships/One2MRelationship.php new file mode 100644 index 00000000..15579810 --- /dev/null +++ b/data/Relationships/One2MRelationship.php @@ -0,0 +1,176 @@ +def = $def; + $this->name = $def['name']; + + $this->selfReferencing = $def['lhs_module'] == $def['rhs_module']; + $lhsModule = $def['lhs_module']; + $rhsModule = $def['rhs_module']; + + if ($this->selfReferencing) + { + $links = VardefManager::getLinkFieldForRelationship( + $lhsModule, BeanFactory::getObjectName($lhsModule), $this->name + ); + if (empty($links)) + { + $GLOBALS['log']->fatal("No Links found for relationship {$this->name}"); + } + else { + if (!is_array($links)) //Only one link for a self referencing relationship, this is BAAAD + { + $this->lhsLinkDef = $this->rhsLinkDef = $links; + } + else if (!empty($links[0]) && !empty($links[1])) + { + + if ((!empty($links[0]['side']) && $links[0]['side'] == "right") + || (!empty($links[0]['link_type']) && $links[0]['link_type'] == "one")) + { + //$links[0] is the RHS + $this->lhsLinkDef = $links[1]; + $this->rhsLinkDef = $links[0]; + } else + { + //$links[0] is the LHS + $this->lhsLinkDef = $links[0]; + $this->rhsLinkDef = $links[1]; + } + } + } + } else + { + $this->lhsLinkDef = VardefManager::getLinkFieldForRelationship( + $lhsModule, BeanFactory::getObjectName($lhsModule), $this->name + ); + $this->rhsLinkDef = VardefManager::getLinkFieldForRelationship( + $rhsModule, BeanFactory::getObjectName($rhsModule), $this->name + ); + if (!isset($this->lhsLinkDef['name']) && isset($this->lhsLinkDef[0])) + { + $this->lhsLinkDef = $this->lhsLinkDef[0]; + } + if (!isset($this->rhsLinkDef['name']) && isset($this->rhsLinkDef[0])) { + $this->rhsLinkDef = $this->rhsLinkDef[0]; + } + } + $this->lhsLink = $this->lhsLinkDef['name']; + $this->rhsLink = $this->rhsLinkDef['name']; + } + + public function getQuery($link, $params = array()) + { + //Self referenceing one to many relationships use one link for subpanels and normal views. + //This mean we have to reverse it for normal views + if (($link->getSide() == REL_LHS && !$this->selfReferencing) + || $link->getSide() == REL_RHS && $this->selfReferencing + ) { + $knownKey = $this->def['join_key_lhs']; + $targetKey = $this->def['join_key_rhs']; + } + else + { + $knownKey = $this->def['join_key_rhs']; + $targetKey = $this->def['join_key_lhs']; + } + $rel_table = $this->getRelationshipTable(); + + $where = "$rel_table.$knownKey = '{$link->getFocus()->id}'" . $this->getRoleWhere(); + + if (empty($params['return_as_array'])) { + return "SELECT $targetKey id FROM $rel_table WHERE $where AND deleted=0"; + } + else + { + return array( + 'select' => "SELECT $targetKey id", + 'from' => "FROM $rel_table", + 'where' => "WHERE $where AND $rel_table.deleted=0", + ); + } + } + + /** + * @param $lhs SugarBean left side bean to add to the relationship. + * @param $rhs SugarBean right side bean to add to the relationship. + * @param $additionalFields key=>value pairs of fields to save on the relationship + * @return boolean true if successful + */ + public function add($lhs, $rhs, $additionalFields = array()) + { + $dataToInsert = $this->getRowToInsert($lhs, $rhs, $additionalFields); + //If the current data matches the existing data, don't do anything + if (!$this->checkExisting($dataToInsert)) + { + $rhsLinkName = $this->rhsLink; + //In a one to many, any existing links from the many (right) side must be removed first + $rhs->load_relationship($rhsLinkName); + $this->removeAll($rhs->$rhsLinkName); + parent::add($lhs, $rhs, $additionalFields); + } + } + + /** + * Just overriding the function from M2M to prevent it from occuring + */ + protected function addSelfReferencing($lhs, $rhs, $additionalFields = array()) + { + //No opp on One2M. + } + + /** + * Just overriding the function from M2M to prevent it from occuring + */ + protected function removeSelfReferencing($lhs, $rhs, $additionalFields = array()) + { + //No opp on One2M. + } +} \ No newline at end of file diff --git a/data/Relationships/One2OneBeanRelationship.php b/data/Relationships/One2OneBeanRelationship.php new file mode 100644 index 00000000..a438fff0 --- /dev/null +++ b/data/Relationships/One2OneBeanRelationship.php @@ -0,0 +1,111 @@ +value pairs of fields to save on the relationship + * @return boolean true if successful + */ + public function add($lhs, $rhs, $additionalFields = array()) + { + $lhsLinkName = $this->lhsLink; + //In a one to one, any existing links from boths sides must be removed first. + //one2Many will take care of the right side, so we'll do the left. + $lhs->load_relationship($lhsLinkName); + $this->removeAll($lhs->$lhsLinkName); + + parent::add($lhs, $rhs, $additionalFields); + } + + protected function updateLinks($lhs, $lhsLinkName, $rhs, $rhsLinkName) + { + //RHS and LHS only ever have one bean + if (isset($lhs->$lhsLinkName)) + $lhs->$lhsLinkName->beans = array($rhs->id => $rhs); + + if (isset($rhs->$rhsLinkName)) + $rhs->$rhsLinkName->beans = array($lhs->id => $lhs); + } + + public function getJoin($link, $params = array(), $return_array = false) + { + $linkIsLHS = $link->getSide() == REL_LHS; + $startingTable = $link->getFocus()->table_name; + $startingKey = $linkIsLHS ? $this->def['lhs_key'] : $this->def['rhs_key']; + $targetTable = $linkIsLHS ? $this->def['rhs_table'] : $this->def['lhs_table']; + $targetTableWithAlias = $targetTable; + $targetKey = $linkIsLHS ? $this->def['rhs_key'] : $this->def['lhs_key']; + $join_type= isset($params['join_type']) ? $params['join_type'] : ' INNER JOIN '; + + $join = ''; + + //Set up any table aliases required + if ( ! empty($params['join_table_alias'])) + { + $targetTableWithAlias = $targetTable . " ". $params['join_table_alias']; + $targetTable = $params['join_table_alias']; + } + + //join the related module's table + $join .= "$join_type $targetTableWithAlias ON $targetTable.$targetKey=$startingTable.$startingKey AND $targetTable.deleted=0\n" + //Next add any role filters + . $this->getRoleWhere(); + + if($return_array){ + return array( + 'join' => $join, + 'type' => $this->type, + 'rel_key' => $targetKey, + 'join_tables' => array($targetTable), + 'where' => "", + 'select' => "$targetTable.id", + ); + } + return $join; + } +} \ No newline at end of file diff --git a/data/Relationships/One2OneRelationship.php b/data/Relationships/One2OneRelationship.php new file mode 100644 index 00000000..3bb759b2 --- /dev/null +++ b/data/Relationships/One2OneRelationship.php @@ -0,0 +1,75 @@ +value pairs of fields to save on the relationship + * @return boolean true if successful + */ + public function add($lhs, $rhs, $additionalFields = array()) + { + $dataToInsert = $this->getRowToInsert($lhs, $rhs, $additionalFields); + //If the current data matches the existing data, don't do anything + if (!$this->checkExisting($dataToInsert)) + { + $lhsLinkName = $this->lhsLink; + $rhsLinkName = $this->rhsLink; + //In a one to one, any existing links from boths sides must be removed first. + //one2Many will take care of the right side, so we'll do the left. + $lhs->load_relationship($lhsLinkName); + $this->removeAll($lhs->$lhsLinkName); + $rhs->load_relationship($rhsLinkName); + $this->removeAll($rhs->$rhsLinkName); + + parent::add($lhs, $rhs, $additionalFields); + } + } + + +} \ No newline at end of file diff --git a/data/Relationships/RelationshipFactory.php b/data/Relationships/RelationshipFactory.php new file mode 100644 index 00000000..9a0016be --- /dev/null +++ b/data/Relationships/RelationshipFactory.php @@ -0,0 +1,206 @@ +loadRelationships(); + } + + /** + * @static + * @return SugarRelationshipFactory + */ + public static function getInstance() + { + if (is_null(self::$rfInstance)) + self::$rfInstance = new SugarRelationshipFactory(); + return self::$rfInstance; + } + + public static function rebuildCache() + { + self::getInstance()->buildRelationshipCache(); + } + + public static function deleteCache() + { + $file = self::getInstance()->getCacheFile(); + if(sugar_is_file($file)) + { + unlink($file); + } + } + + /** + * @param $relationshipName String name of relationship to load + * @return void + * + * + * + */ + public function getRelationship($relationshipName) + { + if (empty($this->relationships[$relationshipName])) { + $GLOBALS['log']->error("Unable to find relationship $relationshipName"); + return false; + } + + $def = $this->relationships[$relationshipName]; + + $type = isset($def['true_relationship_type']) ? $def['true_relationship_type'] : $def['relationship_type']; + switch($type) + { + case "many-to-many": + if (isset($def['rhs_module']) && $def['rhs_module'] == 'EmailAddresses') + { + require_once("data/Relationships/EmailAddressRelationship.php"); + return new EmailAddressRelationship($def); + } + require_once("data/Relationships/M2MRelationship.php"); + return new M2MRelationship($def); + break; + case "one-to-many": + require_once("data/Relationships/One2MBeanRelationship.php"); + //If a relationship has no table or join keys, it must be bean based + if (empty($def['true_relationship_type']) || (empty($def['table']) && empty($def['join_table'])) || empty($def['join_key_rhs'])){ + return new One2MBeanRelationship($def); + } + else { + return new One2MRelationship($def); + } + break; + case "one-to-one": + if (empty($def['true_relationship_type'])){ + require_once("data/Relationships/One2OneBeanRelationship.php"); + return new One2OneBeanRelationship($def); + } + else { + require_once("data/Relationships/One2OneRelationship.php"); + return new One2OneRelationship($def); + } + break; + } + + $GLOBALS['log']->fatal ("$relationshipName had an unknown type $type "); + + return false; + } + + public function getRelationshipDef($relationshipName) + { + if (empty($this->relationships[$relationshipName])) { + $GLOBALS['log']->error("Unable to find relationship $relationshipName"); + return false; + } + + return $this->relationships[$relationshipName]; + } + + + protected function loadRelationships() + { + if(sugar_is_file($this->getCacheFile())) + { + include($this->getCacheFile()); + $this->relationships = $relationships; + } else { + $this->buildRelationshipCache(); + } + } + + protected function buildRelationshipCache() + { + global $beanList, $dictionary, $buildingRelCache; + if ($buildingRelCache) + return; + $buildingRelCache = true; + include_once("modules/TableDictionary.php"); + + if (empty($beanList)) + include("include/modules.php"); + //Reload ALL the module vardefs.... + foreach($beanList as $moduleName => $beanName) + { + VardefManager::loadVardef($moduleName, BeanFactory::getObjectName($moduleName)); + } + + $relationships = array(); + + //Grab all the relationships from the dictionary. + foreach ($dictionary as $key => $def) + { + if (!empty($def['relationships'])) + { + foreach($def['relationships'] as $relKey => $relDef) + { + if ($key == $relKey) //Relationship only entry, we need to capture everything + $relationships[$key] = array_merge(array('name' => $key), $def, $relDef); + else { + $relationships[$relKey] = array_merge(array('name' => $relKey), $relDef); + if(!empty($relationships[$relKey]['join_table']) && empty($relationships[$relKey]['fields']) + && isset($dictionary[$relationships[$relKey]['join_table']]['fields'])) { + $relationships[$relKey]['fields'] = $dictionary[$relationships[$relKey]['join_table']]['fields']; + } + } + } + } + } + //Save it out + sugar_mkdir(dirname($this->getCacheFile()), null, true); + $out="getCacheFile(), $out); + + $this->relationships = $relationships; + $buildingRelCache = false; + } + + protected function getCacheFile() { + return "{$GLOBALS['sugar_config']['cache_dir']}Relationships/relationships.cache.php"; + } + + + +} \ No newline at end of file diff --git a/data/Relationships/SugarRelationship.php b/data/Relationships/SugarRelationship.php new file mode 100644 index 00000000..a1d31819 --- /dev/null +++ b/data/Relationships/SugarRelationship.php @@ -0,0 +1,446 @@ +getQuery + * @abstract + * @param $link Link Object to get query for. + * @return string|array query used to load this relationship + */ + public abstract function getQuery($link, $params = array()); + + /** + * @abstract + * @param Link2 $link + * @return string|array the query to join against the related modules table for the given link. + */ + public abstract function getJoin($link); + + /** + * @abstract + * @param SugarBean $lhs + * @param SugarBean $rhs + * @return bool + */ + public abstract function relationship_exists($lhs, $rhs); + + /** + * @abstract + * @return string name of the table for this relationship + */ + public abstract function getRelationshipTable(); + + /** + * @param $link Link2 removes all the beans associated with this link from the relationship + * @return void + */ + public function removeAll($link) + { + $focus = $link->getFocus(); + $related = $link->getBeans(); + foreach($related as $relBean) + { + if (empty($relBean->id)) { + continue; + } + + if ($link->getSide() == REL_LHS) + $this->remove($focus, $relBean); + else + $this->remove($relBean, $focus); + } + } + + /** + * @param $rowID id of SugarBean to remove from the relationship + * @return void + */ + public function removeById($rowID){ + $this->removeRow(array("id" => $rowID)); + } + + /** + * @return string name of right hand side module. + */ + public function getRHSModule() + { + return $this->def['rhs_module']; + } + + /** + * @return string name of left hand side module. + */ + public function getLHSModule() + { + return $this->def['lhs_module']; + } + + /** + * @return String left link in relationship. + */ + public function getLHSLink() + { + return $this->lhsLink; + } + + /** + * @return String right link in relationship. + */ + public function getRHSLink() + { + return $this->rhsLink; + } + + /** + * @return array names of fields stored on the relationship + */ + public function getFields() + { + return isset($this->def['fields']) ? $this->def['fields'] : array(); + } + + /** + * @param array $row values to be inserted into the relationship + * @return bool|void null if new row was inserted and true if an exesting row was updated + */ + protected function addRow($row) + { + $existing = $this->checkExisting($row); + if (!empty($existing)) //Update the existing row, overriding the values with those passed in + return $this->updateRow($existing['id'], array_merge($existing, $row)); + + $values = array(); + foreach($this->getFields() as $def) + { + $field = $def['name']; + if (isset($row[$field])) + $values[$field] = "'{$row[$field]}'"; + else + $values[$field] = "''"; + } + $columns = implode(',', array_keys($values)); + $values = implode(',', $values); + if (!empty($values)) + { + $query = "INSERT INTO {$this->getRelationshipTable()} ($columns) VALUES ($values)"; + DBManagerFactory::getInstance()->query($query); + } + } + + /** + * @param $id id of row to update + * @param $values values to insert into row + * @return resource result of update satatement + */ + protected function updateRow($id, $values) + { + $newVals = array(); + //Unset the ID since we are using it to update the row + if (isset($values['id'])) unset($values['id']); + foreach($values as $field => $val) + { + $newVals[] = "$field='$val'"; + } + + $newVals = implode(",",$newVals); + + $query = "UPDATE {$this->getRelationshipTable()} set $newVals WHERE id='$id'"; + + return DBManagerFactory::getInstance()->query($query); + } + + /** + * Removes one or more rows from the relationship table + * @param $where array of field=>value pairs to match + * @return bool|resource + */ + protected function removeRow($where) + { + if (empty($where)) + return false; + + $date_modified = TimeDate::getInstance()->getNow()->asDb(); + $stringSets = array(); + foreach ($where as $field => $val) + { + $stringSets[] = "$field = '$val'"; + } + $whereString = "WHERE " . implode(" AND ", $stringSets); + + $query = "UPDATE {$this->getRelationshipTable()} set deleted=1 , date_modified = '$date_modified' $whereString"; + + return DBManagerFactory::getInstance()->query($query); + + } + + /** + * Checks for an existing row who's keys match the one passed in. + * @param $row + * @return array|bool returns false if now row is found, otherwise the row is returned + */ + protected function checkExisting($row) + { + $leftIDName = $this->def['join_key_lhs']; + $rightIDName = $this->def['join_key_rhs']; + if (empty($row[$leftIDName]) || empty($row[$rightIDName])) + return false; + + $leftID = $row[$leftIDName]; + $rightID = $row[$rightIDName]; + //Check the relationship role as well + $roleCheck = $this->getRoleWhere(); + + $query = "SELECT * FROM {$this->getRelationshipTable()} WHERE $leftIDName='$leftID' AND $rightIDName='$rightID' $roleCheck AND deleted=0"; + + $db = DBManagerFactory::getInstance(); + $result = $db->query($query); + $row = $db->fetchByAssoc($result); + if (!empty($row)) + { + return $row; + } else{ + return false; + } + } + + /** + * Gets the relationship role column check for the where clause + * @param string $table + * @return string + */ + protected function getRoleWhere($table = "", $ignore_role_filter = false) + { + $ignore_role_filter = $ignore_role_filter || $this->ignore_role_filter; + $roleCheck = ""; + if (empty ($table)) + $table = $this->getRelationshipTable(); + if (!empty($this->def['relationship_role_column']) && !empty($this->def["relationship_role_column_value"]) && !$ignore_role_filter ) + { + if (empty($table)) + $roleCheck = " AND $this->relationship_role_column"; + else + $roleCheck = " AND $table.{$this->relationship_role_column}"; + //role column value. + if (empty($this->def['relationship_role_column_value'])) + { + $roleCheck.=' IS NULL'; + } else { + $roleCheck.= " = '$this->relationship_role_column_value'"; + } + } + return $roleCheck; + } + + /** + * @param SugarBean $focus base bean the hooks is triggered from + * @param SugarBean $related bean being added/removed/updated from relationship + * @param string $link_name name of link being triggerd + * @return array base arguments to pass to relationship logic hooks + */ + protected function getCustomLogicArguments($focus, $related, $link_name) + { + $custom_logic_arguments = array(); + $custom_logic_arguments['id'] = $focus->id; + $custom_logic_arguments['related_id'] = $related->id; + $custom_logic_arguments['module'] = $focus->module_dir; + $custom_logic_arguments['related_module'] = $related->module_dir; + $custom_logic_arguments['link'] = $link_name; + $custom_logic_arguments['relationship'] = $this->name; + + return $custom_logic_arguments; + } + + /** + * Call the after add logic hook for a given link + * @param SugarBean $focus base bean the hooks is triggered from + * @param SugarBean $related bean being added/removed/updated from relationship + * @param string $link_name name of link being triggerd + * @return void + */ + protected function callAfterAdd($focus, $related, $link_name="") + { + $custom_logic_arguments = $this->getCustomLogicArguments($focus, $related, $link_name); + $focus->call_custom_logic('after_relationship_add', $custom_logic_arguments); + } + + /** + * @param SugarBean $focus + * @param SugarBean $related + * @param string $link_name + * @return void + */ + protected function callAfterDelete($focus, $related, $link_name="") + { + $custom_logic_arguments = $this->getCustomLogicArguments($focus, $related, $link_name); + $focus->call_custom_logic('after_relationship_delete', $custom_logic_arguments); + } + + /** + * Adds a realted Bean to the list to be resaved along with the current bean. + * @static + * @param SugarBean $bean + * @return void + */ + public static function addToResaveList($bean) + { + if (!isset(self::$beansToResave[$bean->module_dir])) + { + self::$beansToResave[$bean->module_dir] = array(); + } + self::$beansToResave[$bean->module_dir][$bean->id] = $bean; + } + + /** + * + * @static + * @return void + */ + public static function resaveRelatedBeans() + { + $GLOBALS['resavingRelatedBeans'] = true; + + //Resave any bean not currently in the middle of a save operation + foreach(self::$beansToResave as $module => $beans) + { + foreach ($beans as $bean) + { + if (empty($bean->deleted) && empty($bean->in_save)) + { + $bean->save(); + } + } + } + + $GLOBALS['resavingRelatedBeans'] = false; + + //Reset the list of beans that will need to be resaved + self::$beansToResave = array(); + } + + /** + * @return bool true if the relationship is a flex / parent relationship + */ + public function isParentRelationship() + { + //check role fields to see if this is a parent (flex relate) relationship + if(!empty($this->def["relationship_role_column"]) && !empty($this->def["relationship_role_column_value"]) + && $this->def["relationship_role_column"] == "parent_type" && $this->def['rhs_key'] == "parent_id") + { + return true; + } + return false; + } + + public function __get($name) + { + if (isset($this->def[$name])) + return $this->def[$name]; + + switch($name) + { + case "relationship_type": + return $this->type; + case 'relationship_name': + return $this->name; + case "lhs_module": + return $this->getLHSModule(); + case "rhs_module": + return $this->getRHSModule(); + case "lhs_table" : + isset($this->def['lhs_table']) ? $this->def['lhs_table'] : ""; + case "rhs_table" : + isset($this->def['rhs_table']) ? $this->def['rhs_table'] : ""; + case "list_fields": + return array('lhs_table', 'lhs_key', 'rhs_module', 'rhs_table', 'rhs_key', 'relationship_type'); + } + + if (isset($this->$name)) + return $this->$name; + + return null; + } +} \ No newline at end of file diff --git a/data/SugarBean.php b/data/SugarBean.php index 43dcc2bb..b372690d 100644 --- a/data/SugarBean.php +++ b/data/SugarBean.php @@ -46,6 +46,7 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); *******************************************************************************/ require_once('modules/DynamicFields/DynamicField.php'); +require_once("data/Relationships/RelationshipFactory.php"); /** * SugarBean is the base class for all business objects in Sugar. It implements @@ -205,6 +206,7 @@ class SugarBean * @var String */ var $module_dir = ''; + var $module_name = ''; var $field_name_map; var $field_defs; var $custom_fields; @@ -275,8 +277,9 @@ class SugarBean global $dictionary, $current_user; static $loaded_defs = array(); $this->db = DBManagerFactory::getInstance(); - $this->dbManager = DBManagerFactory::getInstance(); + if (empty($this->module_name)) + $this->module_name = $this->module_dir; if((false == $this->disable_vardefs && empty($loaded_defs[$this->object_name])) || !empty($GLOBALS['reload_vardefs'])) { VardefManager::loadVardef($this->module_dir, $this->object_name); @@ -817,23 +820,30 @@ class SugarBean } else { - // add Id to the insert statement. - $column_list='id'; - $value_list="'".create_guid()."'"; - - //add relationship name to the insert statement. - $column_list .= $delimiter.'relationship_name'; - $value_list .= $delimiter."'".$rel_name."'"; - - //todo check whether $rel_def is an array or not. - //for now make that assumption. - //todo specify defaults if meta not defined. - foreach ($rel_def as $def_key=>$value) + $seed = BeanFactory::getBean("Relationships"); + $keys = array_keys($seed->field_defs); + $toInsert = array(); + foreach($keys as $key) { - $column_list.= $delimiter.$def_key; - $value_list.= $delimiter."'".$value."'"; + if ($key == "id") + { + $toInsert[$key] = create_guid(); + } + else if ($key == "relationship_name") + { + $toInsert[$key] = $rel_name; + } + else if (isset($rel_def[$key])) + { + $toInsert[$key] = $rel_def[$key]; + } + //todo specify defaults if meta not defined. } + + $column_list = implode(",", array_keys($toInsert)); + $value_list = "'" . implode("','", array_values($toInsert)) . "'"; + //create the record. todo add error check. $insert_string = "INSERT into relationships (" .$column_list. ") values (".$value_list.")"; $db->query($insert_string, true); @@ -871,7 +881,7 @@ class SugarBean */ function load_relationship($rel_name) { - $GLOBALS['log']->debug("SugarBean.load_relationships, Loading relationship (".$rel_name.")."); + $GLOBALS['log']->debug("SugarBean[{$this->object_name}].load_relationships, Loading relationship (".$rel_name.")."); if (empty($rel_name)) { @@ -881,39 +891,40 @@ class SugarBean $fieldDefs = $this->getFieldDefinitions(); //find all definitions of type link. - if (!empty($fieldDefs)) + if (!empty($fieldDefs[$rel_name])) { + //initialize a variable of type Link + require_once('data/Link2.php'); + $class = load_link_class($fieldDefs[$rel_name]); + if (isset($this->$rel_name) && $this->$rel_name instanceof $class) { + return true; + } //if rel_name is provided, search the fieldef array keys by name. - if (array_key_exists($rel_name, $fieldDefs)) + if (isset($fieldDefs[$rel_name]['type']) && $fieldDefs[$rel_name]['type'] == 'link') { - if (array_search('link',$fieldDefs[$rel_name]) === 'type') - { - //initialize a variable of type Link - require_once('data/Link.php'); - $class = load_link_class($fieldDefs[$rel_name]); - - $this->$rel_name=new $class($fieldDefs[$rel_name]['relationship'], $this, $fieldDefs[$rel_name]); + if ($class == "Link2") + $this->$rel_name = new $class($rel_name, $this); + else + $this->$rel_name = new $class($fieldDefs[$rel_name]['relationship'], $this, $fieldDefs[$rel_name]); - if (empty($this->$rel_name->_relationship->id)) { - unset($this->$rel_name); - return false; - } - return true; + if (empty($this->$rel_name) || + (method_exists($this->$rel_name, "loadedSuccesfully") && !$this->$rel_name->loadedSuccesfully())) + { + unset($this->$rel_name); + return false; } - } - else - { - $GLOBALS['log']->debug("SugarBean.load_relationships, Error Loading relationship (".$rel_name.")."); - return false; + return true; } } - + $GLOBALS['log']->debug("SugarBean.load_relationships, Error Loading relationship (".$rel_name.")"); return false; } /** * Loads all attributes of type link. * + * DO NOT CALL THIS FUNCTION IF YOU CAN AVOID IT. Please use load_relationship directly instead. + * * Method searches the implmenting module's vardef file for attributes of type link, and for each attribute * create a similary named variable and load the relationship definition. * @@ -923,16 +934,11 @@ class SugarBean */ function load_relationships() { - $GLOBALS['log']->debug("SugarBean.load_relationships, Loading all relationships of type link."); - $linked_fields=$this->get_linked_fields(); - require_once("data/Link.php"); foreach($linked_fields as $name=>$properties) { - $class = load_link_class($properties); - - $this->$name=new $class($properties['relationship'], $this, $properties); + $this->load_relationship($name); } } @@ -956,30 +962,21 @@ class SugarBean function get_linked_beans($field_name,$bean_name, $sort_array = array(), $begin_index = 0, $end_index = -1, $deleted=0, $optional_where="") { - //if bean_name is Case then use aCase if($bean_name=="Case") $bean_name = "aCase"; - //add a references to bean_name if it doe not exist aleady. - if (!(class_exists($bean_name))) - { - - if (isset($GLOBALS['beanList']) && isset($GLOBALS['beanFiles'])) - { - global $beanFiles; - } - else - { - + if($this->load_relationship($field_name)) { + if ($this->$field_name instanceof Link) { + // some classes are still based on Link, e.g. TeamSetLink + return array_values($this->$field_name->getBeans(new $bean_name(), $sort_array, $begin_index, $end_index, $deleted, $optional_where)); + } else { + // Link2 style + return array_values($this->$field_name->getBeans()); } - $bean_file=$beanFiles[$bean_name]; - include_once($bean_file); } - - $this->load_relationship($field_name); - - return $this->$field_name->getBeans(new $bean_name(), $sort_array, $begin_index, $end_index, $deleted, $optional_where); + else + return array(); } /** @@ -1109,17 +1106,15 @@ class SugarBean function delete_linked($id) { $linked_fields=$this->get_linked_fields(); - foreach ($linked_fields as $name => $value) { if ($this->load_relationship($name)) { - $GLOBALS['log']->debug('relationship loaded'); $this->$name->delete($id); } else { - $GLOBALS['log']->error('error loading relationship'); + $GLOBALS['log']->fatal("error loading relationship $name"); } } } @@ -1254,6 +1249,7 @@ class SugarBean */ function save($check_notify = FALSE) { + $this->in_save = true; // cn: SECURITY - strip XSS potential vectors $this->cleanBean(); // This is used so custom/3rd-party code can be upgraded with fewer issues, this will be removed in a future release @@ -1312,6 +1308,19 @@ class SugarBean } $query = "INSERT into "; } + + + + require_once("data/BeanFactory.php"); + BeanFactory::registerBean($this->module_name, $this); + + if (empty($GLOBALS['updating_relationships']) && empty($GLOBALS['saving_relationships']) && empty ($GLOBALS['resavingRelatedBeans'])) + { + $GLOBALS['saving_relationships'] = true; + // let subclasses save related field changes + $this->save_relationship_changes($isUpdate); + $GLOBALS['saving_relationships'] = false; + } if($isUpdate && !$this->update_date_entered) { unset($this->date_entered); @@ -1563,8 +1572,10 @@ class SugarBean } - // let subclasses save related field changes - $this->save_relationship_changes($isUpdate); + if (empty($GLOBALS['resavingRelatedBeans'])){ + SugarRelationship::resaveRelatedBeans(); + } + //If we aren't in setup mode and we have a current user and module, then we track if(isset($GLOBALS['current_user']) && isset($this->module_dir)) @@ -1574,6 +1585,9 @@ class SugarBean $this->call_custom_logic('after_save', ''); + //Now that the record has been saved, we don't want to insert again on further saves + $this->new_with_id = false; + $this->in_save = false; return $this->id; } @@ -1659,10 +1673,36 @@ class SugarBean $notify_mail->FromName = $from_name; } - if($sendEmail && !$notify_mail->Send()) { - $GLOBALS['log']->fatal("Notifications: error sending e-mail (method: {$notify_mail->Mailer}), (error: {$notify_mail->ErrorInfo})"); - } else { - $GLOBALS['log']->info("Notifications: e-mail successfully sent"); + $oe = new OutboundEmail(); + $oe = $oe->getUserMailerSettings($current_user); + //only send if smtp server is defined + if($sendEmail){ + $smtpVerified = false; + + //first check the user settings + if(!empty($oe->mail_smtpserver)){ + $smtpVerified = true; + } + + //if still not verified, check against the system settings + if (!$smtpVerified){ + $oe = $oe->getSystemMailerSettings(); + if(!empty($oe->mail_smtpserver)){ + $smtpVerified = true; + } + } + //if smtp was not verified against user or system, then do not send out email + if (!$smtpVerified){ + $GLOBALS['log']->fatal("Notifications: error sending e-mail, smtp server was not found "); + //break out + return; + } + + if(!$notify_mail->Send()) { + $GLOBALS['log']->fatal("Notifications: error sending e-mail (method: {$notify_mail->Mailer}), (error: {$notify_mail->ErrorInfo})"); + }else{ + $GLOBALS['log']->fatal("Notifications: e-mail successfully sent"); + } } } @@ -1776,8 +1816,8 @@ function save_relationship_changes($is_update, $exclude=array()) $new_rel_id = $_REQUEST['relate_id']; $new_rel_relname = $_REQUEST['relate_to']; if(!empty($this->in_workflow) && !empty($this->not_use_rel_in_req)) { - $new_rel_id = $this->new_rel_id; - $new_rel_relname = $this->new_rel_relname; + $new_rel_id = !empty($this->new_rel_id) ? $this->new_rel_id : ''; + $new_rel_relname = !empty($this->new_rel_relname) ? $this->new_rel_relname : ''; } $new_rel_link = $new_rel_relname; //Try to find the link in this bean based on the relationship @@ -1831,33 +1871,38 @@ function save_relationship_changes($is_update, $exclude=array()) foreach ( $this->field_defs as $def ) { - if ($def [ 'type' ] == 'relate' && isset ( $def [ 'id_name'] ) && isset ( $def [ 'link'] ) && isset ( $def[ 'save' ]) ) - { - if ( in_array( $def['id_name'], $exclude) || in_array( $def['id_name'], $this->relationship_fields ) ) - continue ; // continue to honor the exclude array and exclude any relationships that will be handled by the relationship_fields mechanism - - if (isset( $this->field_defs[ $def [ 'link' ] ] )) + if ($def [ 'type' ] == 'relate' && isset ( $def [ 'id_name'] ) && isset ( $def [ 'link'] ) && isset ( $def[ 'save' ]) ) { + if ( in_array( $def['id_name'], $exclude) || in_array( $def['id_name'], $this->relationship_fields ) ) + continue ; // continue to honor the exclude array and exclude any relationships that will be handled by the relationship_fields mechanism - $linkfield = $this->field_defs[$def [ 'link' ]] ; + $linkField = $def [ 'link' ] ; + if (isset( $this->field_defs[$linkField ] )) + { + $linkfield = $this->field_defs[$linkField] ; + + if ($this->load_relationship ( $linkField)) + { + $idName = $def['id_name']; - if ($this->load_relationship ( $def [ 'link' ])){ - if (!empty($this->rel_fields_before_value[$def [ 'id_name' ]])) + if (!empty($this->rel_fields_before_value[$idName]) && empty($this->$idName)) { //if before value is not empty then attempt to delete relationship $GLOBALS['log']->debug("save_relationship_changes(): From field_defs - attempting to remove the relationship record: {$def [ 'link' ]} = {$this->rel_fields_before_value[$def [ 'id_name' ]]}"); $this->$def ['link' ]->delete($this->id, $this->rel_fields_before_value[$def [ 'id_name' ]] ); } - if (!empty($this->$def['id_name']) && is_string($this->$def['id_name'])) + + if (!empty($this->$idName) && is_string($this->$idName)) { $GLOBALS['log']->debug("save_relationship_changes(): From field_defs - attempting to add a relationship record - {$def [ 'link' ]} = {$this->$def [ 'id_name' ]}" ); - $this->$def ['link' ]->add($this->$def['id_name']); + + $this->$linkField->add($this->$idName); } } else { - $GLOBALS['log']->fatal("Failed to load relationship {$def [ 'link' ]} while saving {$this->module_dir}"); + $GLOBALS['log']->fatal("Failed to load relationship {$linkField} while saving {$this->module_dir}"); } } - } + } } // Finally, we update a field listed in the _REQUEST['*/relate_id']/_REQUEST['relate_to'] mechanism (if it hasn't already been updated above) @@ -1872,7 +1917,7 @@ function save_relationship_changes($is_update, $exclude=array()) $this->$lower_link->add($new_rel_id); }else{ - require_once('data/Link.php'); + require_once('data/Link2.php'); $rel = Relationship::retrieve_by_modules($new_rel_link, $this->module_dir, $GLOBALS['db'], 'many-to-many'); if(!empty($rel)){ @@ -1887,15 +1932,13 @@ function save_relationship_changes($is_update, $exclude=array()) } //ok so we didn't find it in the field defs let's save it anyway if we have the relationshp - $this->$rel=new Link($rel, $this, array()); + $this->$rel=new Link2($rel, $this, array()); $this->$rel->add($new_rel_id); } } } - } - } /** @@ -2352,28 +2395,29 @@ function save_relationship_changes($is_update, $exclude=array()) //sub-selects. if (strstr($query," UNION ALL ") !== false) { - //seperate out all the queries. - $union_qs=explode(" UNION ALL ", $query); - foreach ($union_qs as $key=>$union_query) { - $star = '*'; - preg_match($pattern, $union_query, $matches); - if (!empty($matches)) { - if (stristr($matches[0], "distinct")) { - if (!empty($this->seed) && !empty($this->seed->table_name )) - $star = 'DISTINCT ' . $this->seed->table_name . '.id'; - else - $star = 'DISTINCT ' . $this->table_name . '.id'; - } - } // if - $replacement = 'SELECT count(' . $star . ') c FROM '; - $union_qs[$key] = preg_replace($pattern, $replacement, $union_query,1); - } - $modified_select_query=implode(" UNION ALL ",$union_qs); - } else { - $modified_select_query = preg_replace($pattern, $replacement, $query,1); - } - - return $modified_select_query; + //seperate out all the queries. + $union_qs=explode(" UNION ALL ", $query); + foreach ($union_qs as $key=>$union_query) { + $star = '*'; + preg_match($pattern, $union_query, $matches); + if (!empty($matches)) { + if (stristr($matches[0], "distinct")) { + if (!empty($this->seed) && !empty($this->seed->table_name )) + $star = 'DISTINCT ' . $this->seed->table_name . '.id'; + else + $star = 'DISTINCT ' . $this->table_name . '.id'; + } + } // if + $replacement = 'SELECT count(' . $star . ') c FROM '; + $union_qs[$key] = preg_replace($pattern, $replacement, $union_query,1); + } + $modified_select_query=implode(" UNION ALL ",$union_qs); + } else { + $modified_select_query = preg_replace($pattern, $replacement, $query,1); + } + + + return $modified_select_query; } /** @@ -2644,7 +2688,7 @@ function save_relationship_changes($is_update, $exclude=array()) unset ($parentbean->$related_field_name); continue; } - $query_array = $parentbean->$related_field_name->getQuery(true,array(),0,'',true, null, null, true); + $query_array = $parentbean->$related_field_name->getSubpanelQuery(array(), true); } $table_where = $this_subpanel->get_where(); $where_definition = $query_array['where']; @@ -2711,7 +2755,7 @@ function save_relationship_changes($is_update, $exclude=array()) * * It constructs union queries for activities subpanel. * - * @param Object $parentbean constructing queries for link attributes in this bean + * @param SugarBean $parentbean constructing queries for link attributes in this bean * @param string $order_by Optional, order by clause * @param string $sort_order Optional, sort order * @param string $where Optional, additional where clause @@ -2724,118 +2768,116 @@ function save_relationship_changes($is_update, $exclude=array()) $secondary_queries = array(); global $layout_edit_mode, $beanFiles, $beanList; - if(isset($_SESSION['show_deleted'])) - { - $show_deleted = 1; - } - $final_query = ''; - $final_query_rows = ''; - $subpanel_list=array(); - if ($subpanel_def->isCollection()) - { - $subpanel_def->load_sub_subpanels(); - $subpanel_list=$subpanel_def->sub_subpanels; - } - else - { - $subpanel_list[]=$subpanel_def; - } + if(isset($_SESSION['show_deleted'])) + { + $show_deleted = 1; + } + $final_query = ''; + $final_query_rows = ''; + $subpanel_list=array(); + if ($subpanel_def->isCollection()) + { + $subpanel_def->load_sub_subpanels(); + $subpanel_list=$subpanel_def->sub_subpanels; + } + else + { + $subpanel_list[]=$subpanel_def; + } - $first = true; + $first = true; - //Breaking the building process into two loops. The first loop gets a list of all the sub-queries. - //The second loop merges the queries and forces them to select the same number of columns - //All columns in a sub-subpanel group must have the same aliases - //If the subpanel is a datasource function, it can't be a collection so we just poll that function for the and return that - foreach($subpanel_list as $this_subpanel) - { - if($this_subpanel->isDatasourceFunction() && empty($this_subpanel->_instance_properties['generate_select'])) - { - $shortcut_function_name = $this_subpanel->get_data_source_name(); - $parameters=$this_subpanel->get_function_parameters(); - if (!empty($parameters)) - { - //if the import file function is set, then import the file to call the custom function from - if (is_array($parameters) && isset($parameters['import_function_file'])){ - //this call may happen multiple times, so only require if function does not exist - if(!function_exists($shortcut_function_name)){ - require_once($parameters['import_function_file']); - } - //call function from required file - $tmp_final_query = $shortcut_function_name($parameters); - }else{ - //call function from parent bean - $tmp_final_query = $parentbean->$shortcut_function_name($parameters); - } - } - else - { - $tmp_final_query = $parentbean->$shortcut_function_name(); - } - if(!$first) - { - $final_query_rows .= ' UNION ALL ( '.$parentbean->create_list_count_query($tmp_final_query, $parameters) . ' )'; - $final_query .= ' UNION ALL ( '.$tmp_final_query . ' )'; - } else { - $final_query_rows = '(' . $parentbean->create_list_count_query($tmp_final_query, $parameters) . ')'; - $final_query = '(' . $tmp_final_query . ')'; - $first = false; - } - } - } - //If final_query is still empty, its time to build the sub-queries - if (empty($final_query)) - { - $subqueries = SugarBean::build_sub_queries_for_union($subpanel_list, $subpanel_def, $parentbean, $order_by); - $all_fields = array(); - foreach($subqueries as $i => $subquery) - { - $query_fields = $GLOBALS['db']->helper->getSelectFieldsFromQuery($subquery['select']); - foreach($query_fields as $field => $select) - { - if (!in_array($field, $all_fields)) - $all_fields[] = $field; - } - $subqueries[$i]['query_fields'] = $query_fields; - } - $first = true; - //Now ensure the queries have the same set of fields in the same order. - foreach($subqueries as $subquery) - { - $subquery['select'] = "SELECT"; - foreach($all_fields as $field) - { - if (!isset($subquery['query_fields'][$field])) - { - $subquery['select'] .= " ' ' $field,"; - } - else - { - $subquery['select'] .= " {$subquery['query_fields'][$field]},"; - } - } - $subquery['select'] = substr($subquery['select'], 0 , strlen($subquery['select']) - 1); - //Put the query into the final_query - $query = $subquery['select'] . " " . $subquery['from'] . " " . $subquery['where']; - if(!$first) - { - $query = ' UNION ALL ( '.$query . ' )'; - $final_query_rows .= " UNION ALL "; - } else { - $query = '(' . $query . ')'; - $first = false; - } - $query_array = $subquery['query_array']; - $select_position=strpos($query_array['select'],"SELECT"); - $distinct_position=strpos($query_array['select'],"DISTINCT"); - if ($select_position !== false && $distinct_position!= false) - { - $query_rows = "( ".substr_replace($query_array['select'],"SELECT count(",$select_position,6). ")" . $subquery['from_min'].$query_array['join']. $subquery['where'].' )'; - } - else - { - //resort to default behavior. - $query_rows = "( SELECT count(*)". $subquery['from_min'].$query_array['join']. $subquery['where'].' )'; + //Breaking the building process into two loops. The first loop gets a list of all the sub-queries. + //The second loop merges the queries and forces them to select the same number of columns + //All columns in a sub-subpanel group must have the same aliases + //If the subpanel is a datasource function, it can't be a collection so we just poll that function for the and return that + foreach($subpanel_list as $this_subpanel) + { + if($this_subpanel->isDatasourceFunction() && empty($this_subpanel->_instance_properties['generate_select'])) + { + $shortcut_function_name = $this_subpanel->get_data_source_name(); + $parameters=$this_subpanel->get_function_parameters(); + if (!empty($parameters)) + { + //if the import file function is set, then import the file to call the custom function from + if (is_array($parameters) && isset($parameters['import_function_file'])){ + //this call may happen multiple times, so only require if function does not exist + if(!function_exists($shortcut_function_name)){ + require_once($parameters['import_function_file']); + } + //call function from required file + $tmp_final_query = $shortcut_function_name($parameters); + }else{ + //call function from parent bean + $tmp_final_query = $parentbean->$shortcut_function_name($parameters); + } + } else { + $tmp_final_query = $parentbean->$shortcut_function_name(); + } + if(!$first) + { + $final_query_rows .= ' UNION ALL ( '.$parentbean->create_list_count_query($tmp_final_query, $parameters) . ' )'; + $final_query .= ' UNION ALL ( '.$tmp_final_query . ' )'; + } else { + $final_query_rows = '(' . $parentbean->create_list_count_query($tmp_final_query, $parameters) . ')'; + $final_query = '(' . $tmp_final_query . ')'; + $first = false; + } + } + } + //If final_query is still empty, its time to build the sub-queries + if (empty($final_query)) + { + $subqueries = SugarBean::build_sub_queries_for_union($subpanel_list, $subpanel_def, $parentbean, $order_by); + $all_fields = array(); + foreach($subqueries as $i => $subquery) + { + $query_fields = $GLOBALS['db']->helper->getSelectFieldsFromQuery($subquery['select']); + foreach($query_fields as $field => $select) + { + if (!in_array($field, $all_fields)) + $all_fields[] = $field; + } + $subqueries[$i]['query_fields'] = $query_fields; + } + $first = true; + //Now ensure the queries have the same set of fields in the same order. + foreach($subqueries as $subquery) + { + $subquery['select'] = "SELECT"; + foreach($all_fields as $field) + { + if (!isset($subquery['query_fields'][$field])) + { + $subquery['select'] .= " ' ' $field,"; + } + else + { + $subquery['select'] .= " {$subquery['query_fields'][$field]},"; + } + } + $subquery['select'] = substr($subquery['select'], 0 , strlen($subquery['select']) - 1); + //Put the query into the final_query + $query = $subquery['select'] . " " . $subquery['from'] . " " . $subquery['where']; + if(!$first) + { + $query = ' UNION ALL ( '.$query . ' )'; + $final_query_rows .= " UNION ALL "; + } else { + $query = '(' . $query . ')'; + $first = false; + } + $query_array = $subquery['query_array']; + $select_position=strpos($query_array['select'],"SELECT"); + $distinct_position=strpos($query_array['select'],"DISTINCT"); + if ($select_position !== false && $distinct_position!= false) + { + $query_rows = "( ".substr_replace($query_array['select'],"SELECT count(",$select_position,6). ")" . $subquery['from_min'].$query_array['join']. $subquery['where'].' )'; + } + else + { + //resort to default behavior. + $query_rows = "( SELECT count(*)". $subquery['from_min'].$query_array['join']. $subquery['where'].' )'; } if(!empty($subquery['secondary_select'])) { @@ -3313,11 +3355,10 @@ function save_relationship_changes($is_update, $exclude=array()) $ret_array['select'] .= ' , ' .$params['join_table_alias'] . '.created_by ' . $field . '_owner'; } $ret_array['select'] .= " , '".$rel_module ."' " . $field . '_mod'; + } } } - //Replace references to this table in the where clause with the new alias - $join_table_name = $this->$data['link']->getRelatedTableName(); // To fix SOAP stuff where we are trying to retrieve all the accounts data where accounts.id = .. // and this code changes accounts to jt4 as there is a self join with the accounts table. //Martin fix #27494 @@ -3410,10 +3451,6 @@ function save_relationship_changes($is_update, $exclude=array()) } return $ret_array['select'] . $ret_array['from'] . $ret_array['where']. $ret_array['order_by']; - - - - } /** * Returns parent record data for objects that store relationship information @@ -3555,6 +3592,7 @@ function save_relationship_changes($is_update, $exclude=array()) $limit = $max_per_page + 1; $max_per_page = $limit; } + } if(empty($row_offset)) @@ -4238,9 +4276,12 @@ function save_relationship_changes($is_update, $exclude=array()) * Fill in fields where type = relate */ function fill_in_relationship_fields(){ - if(!empty($this->relDepth)) { - if($this->relDepth > 1)return; - }else $this->relDepth = 0; + global $fill_in_rel_depth; + if(empty($fill_in_rel_depth) || $fill_in_rel_depth < 0) + $fill_in_rel_depth = 0; + if($fill_in_rel_depth > 1) + return; + $fill_in_rel_depth++; foreach($this->field_defs as $field) { @@ -4262,7 +4303,6 @@ function save_relationship_changes($is_update, $exclude=array()) if(!empty($this->$id_name) && file_exists($GLOBALS['beanFiles'][$class]) && isset($this->$name)){ require_once($GLOBALS['beanFiles'][$class]); $mod = new $class(); - $mod->relDepth = $this->relDepth + 1; $mod->retrieve($this->$id_name); if (!empty($field['rname'])) { $this->$name = $mod->$field['rname']; @@ -4289,6 +4329,7 @@ function save_relationship_changes($is_update, $exclude=array()) } } } + $fill_in_rel_depth--; } /** @@ -4319,7 +4360,8 @@ function save_relationship_changes($is_update, $exclude=array()) // call the custom business logic $custom_logic_arguments['id'] = $id; $this->call_custom_logic("before_delete", $custom_logic_arguments); - + $this->deleted = 1; + $this->mark_relationships_deleted($id); if ( isset($this->field_defs['modified_user_id']) ) { if (!empty($current_user)) { $this->modified_user_id = $current_user->id; @@ -4331,8 +4373,8 @@ function save_relationship_changes($is_update, $exclude=array()) $query = "UPDATE $this->table_name set deleted=1 , date_modified = '$date_modified' where id='$id'"; } $this->db->query($query, true,"Error marking record deleted: "); - $this->deleted = 1; - $this->mark_relationships_deleted($id); + + SugarRelationship::resaveRelatedBeans(); // Take the item off the recently viewed lists $tracker = new Tracker(); @@ -4753,10 +4795,7 @@ function save_relationship_changes($is_update, $exclude=array()) function getRelatedFields($module, $id, $fields, $return_array = false){ if(empty($GLOBALS['beanList'][$module]))return ''; - $object = $GLOBALS['beanList'][$module]; - if ($object == 'aCase') { - $object = 'Case'; - } + $object = BeanFactory::getObjectName($module); VardefManager::loadVardef($module, $object); if(empty($GLOBALS['dictionary'][$object]['table']))return ''; diff --git a/download.php b/download.php index 28ea7a5c..e3739203 100644 --- a/download.php +++ b/download.php @@ -65,11 +65,9 @@ else { if(!file_exists('modules/' . $module . '/' . $bean_name . '.php')) { die($app_strings['ERROR_TYPE_NOT_VALID']); } - require_once('modules/' . $module . '/' . $bean_name . '.php'); - $focus = new $bean_name(); - $focus->retrieve($_REQUEST['id']); - if(!$focus->ACLAccess('view')){ - die($mod_strings['LBL_NO_ACCESS']); + $focus = BeanFactory::getBean($module, $_REQUEST['id']); + if(!$focus->ACLAccess('view')){ + die($mod_strings['LBL_NO_ACCESS']); } // if // Pull up the document revision, if it's of type Document @@ -79,11 +77,9 @@ else { $focusRevision->retrieve($_REQUEST['id']); if ( empty($focusRevision->id) ) { - // This wasn't a document revision id, it's probably actually a document id, we need to grab that, get the latest revision and use that - $focusDocument = new Document(); - $focusDocument->retrieve($_REQUEST['id']); - - $focusRevision->retrieve($focusDocument->document_revision_id); + // This wasn't a document revision id, it's probably actually a document id, + // we need to grab the latest revision and use that + $focusRevision->retrieve($focus->document_revision_id); if ( !empty($focusRevision->id) ) { $_REQUEST['id'] = $focusRevision->id; @@ -142,7 +138,7 @@ else { } if($doQuery && isset($query)) { - $rs = $GLOBALS['db']->query($query); + $rs = $GLOBALS['db']->query($query); $row = $GLOBALS['db']->fetchByAssoc($rs); if(empty($row)){ diff --git a/export.php b/export.php index d0c50263..9365d912 100644 --- a/export.php +++ b/export.php @@ -43,6 +43,7 @@ require_once('include/export_utils.php'); global $sugar_config; global $locale; global $current_user; +global $app_list_strings; $the_module = clean_string($_REQUEST['module']); @@ -52,12 +53,26 @@ if($sugar_config['disable_export'] || (!empty($sugar_config['admin_export_only' die($GLOBALS['app_strings']['ERR_EXPORT_DISABLED']); } -if(!empty($_REQUEST['uid'])){ +//check to see if this is a request for a sample or for a regular export +if(!empty($_REQUEST['sample'])){ + //call special method that will create dummy data for bean as well as insert standard help message. + $content = exportSample(clean_string($_REQUEST['module'])); + +}else if(!empty($_REQUEST['uid'])){ $content = export(clean_string($_REQUEST['module']), $_REQUEST['uid'], isset($_REQUEST['members']) ? $_REQUEST['members'] : false); }else{ $content = export(clean_string($_REQUEST['module'])); } $filename = $_REQUEST['module']; +//use label if one is defined +if(!empty($app_list_strings['moduleList'][$_REQUEST['module']])){ + $filename = $app_list_strings['moduleList'][$_REQUEST['module']]; +} + +//strip away any blank spaces +$filename = str_replace(' ','',$filename); + + if($_REQUEST['members'] == true) $filename .= '_'.'members'; /////////////////////////////////////////////////////////////////////////////// diff --git a/files.md5 b/files.md5 index 39d03791..64bce6e0 100644 --- a/files.md5 +++ b/files.md5 @@ -1,5 +1,5 @@ 'd3f150e4a5bed444763ebe8a81742a95', './.htaccess' => 'd41d8cd98f00b204e9800998ecf8427e', @@ -10,6 +10,7 @@ $md5_string = array ( './themes/default/images/plug-in_Lotus.png' => '8ba415f9e8ea352c76ed7deddbc1a653', './themes/default/images/join_meeting_inline.png' => 'edf7837b58451bbfb4e9e827d9a13a22', './themes/default/images/join_imeeting.gif' => 'efd4a8747417083048b1a256d1d715cd', + './themes/default/images/id-ff-down.png' => 'c51eecffd764edb2e663b710924bad57', './themes/default/images/create-record.gif' => '26aa1d757ecdaa1f886cd2bfb24eddd5', './themes/default/images/chartBg.png' => 'b2688aa9e2154d8f6c25fc16f94bf6e7', './themes/default/images/backtotop.gif' => '81711b80ed00519d3c474f5e6cb76062', @@ -583,24 +584,24 @@ $md5_string = array ( './themes/default/images/Administration.gif' => 'a68a5b890796251b8947061f696ca15e', './themes/default/images/ActivitiesReports.gif' => 'ad890a0190fedffa6bcb73557060fa9b', './themes/default/images/Accounts.gif' => 'e081de07d0263b270d0d306642375901', - './themes/default/css/wizard.css' => '4f828507b4421149a80bfc89ed818753', - './themes/default/css/style.css' => '810809a8dd81abe5607913587254ecf9', + './themes/default/css/wizard.css' => '8a64791d2f97ec23e9f25432aa2fdfa6', + './themes/default/css/style.css' => 'b23036ffa3bd4e110222ef144b5bb3f3', './themes/default/css/print.css' => '166d6dff04138c56325ff31e7eeecab0', './themes/default/css/deprecated.css' => '872d2ee2f45eb595825646cb39a82fab', './themes/default/css/chart.css' => '493edb0e181f685fd595c483d09012fb', - './themes/Sugar5/tpls/header.tpl' => '26699f278acc189db3a348b939a97d24', - './themes/Sugar5/tpls/footer.tpl' => '0b9de57442d5ad234afaea7a2129ee6b', + './themes/Sugar5/tpls/header.tpl' => '6930c7722816ea42c03fd5868a47d64e', + './themes/Sugar5/tpls/footer.tpl' => '4c6c68079705694c27fd85bc3a5ef38a', './themes/Sugar5/tpls/_welcome.tpl' => 'c9adf92eb78e5268a40390531cd44249', './themes/Sugar5/tpls/_headerShortcuts.tpl' => '1f6e19fd72259b505b07aaa278da7a82', './themes/Sugar5/tpls/_headerSearch.tpl' => '7547626048dd04c24f45768fc234a9f2', - './themes/Sugar5/tpls/_headerModuleList.tpl' => '25a5b4a62638870961c36d2ddf036a48', + './themes/Sugar5/tpls/_headerModuleList.tpl' => '35c039f24676294d801c0dbe82deab6c', './themes/Sugar5/tpls/_headerLastViewed.tpl' => '4395b403630b8edfe43d7c9520ea15c4', - './themes/Sugar5/tpls/_head.tpl' => 'fed3dfa48b0b41cb5bae6f7a42931145', + './themes/Sugar5/tpls/_head.tpl' => '21c2b4d2553fb11527b556d359b1ce37', './themes/Sugar5/tpls/_globalLinks.tpl' => '2c745010b1b0dc4abc5541786d313020', - './themes/Sugar5/tpls/_companyLogo.tpl' => '216c1a750c55e225350c3bae1b39ec33', + './themes/Sugar5/tpls/_companyLogo.tpl' => '62d2511e6b8fed532fbb89f1ecab940f', './themes/Sugar5/themedef.php' => '05894346d1ea22a59e5460af6a2637e9', './themes/Sugar5/layout_utils.php' => '8e961e445d63291e47305819f8464a8c', - './themes/Sugar5/js/style.js' => '55be46c0d4afbf13dbf150da9083854b', + './themes/Sugar5/js/style.js' => '05ab6ae5d6f9d555161c80629999d966', './themes/Sugar5/images/yes.gif' => '5d3f887e0dbcd70a4708534be3bfa41a', './themes/Sugar5/images/yellow_camp.gif' => '593075b0d0f3dca3343e500f0bc1b4f7', './themes/Sugar5/images/xls_image_inline.gif' => 'e68c72edc63f0f8ab22a9b2cd49909c4', @@ -1165,18 +1166,18 @@ $md5_string = array ( './themes/Sugar5/images/ACLRoles.gif' => 'dcbf376b885458b1fc8c21de7884284e', './themes/Sugar5/css/yui.css' => 'ea8b1a1a36b7aaba0484e4dacb328ce4', './themes/Sugar5/css/wizard.css' => 'fedb96794c66f593b8cc30f3ae409f08', - './themes/Sugar5/css/style.css' => 'eeb6f7e7a87a81c1dfdddcc2fc02fbb1', + './themes/Sugar5/css/style.css' => '415971c5d7753e8fa24e880e6366c6c2', './themes/Sugar5/css/print.css' => '041ba7c460d78a693301c7061139af89', './themes/Sugar5/css/deprecated.css' => '872d2ee2f45eb595825646cb39a82fab', './themes/Sugar5/css/chart.css' => '493edb0e181f685fd595c483d09012fb', - './sugar_version.php' => '24976df6d251e267aded11031bc3227b', + './sugar_version.php' => '013486ca4113bee245c3db2f8b2dd8c6', './soap/SoapTypes.php' => 'f38a0ac79874c8a3e126d728bd05e00a', './soap/SoapSugarUsers.php' => 'aec5ba181325721fa9e6da7e6a787687', './soap/SoapStudio.php' => '2f424bab502055acae4131df64465e0c', './soap/SoapRelationshipHelper.php' => '4d84e017ea0ebe080809c9099ab5ec30', - './soap/SoapPortalUsers.php' => 'e333fe9ad228db47711d1f506b69f079', + './soap/SoapPortalUsers.php' => '9afd4d901e901d9c2a1f569167924b02', './soap/SoapPortalHelper.php' => '75ee76c6f6663e49b5c9a029412f7bed', - './soap/SoapHelperFunctions.php' => '1e1d36a8c69f227dbfa1f304ebeaeaf7', + './soap/SoapHelperFunctions.php' => '08513a10e12d78fe4b1333f26c56462d', './soap/SoapErrorDefinitions.php' => '33fda5814773de4025739ab9024f063a', './soap/SoapError.php' => 'b2759317cb609e41ffca9da3274b8142', './soap/SoapDeprecated.php' => '20cfa68a1138e39de3a3c210df7909eb', @@ -1185,18 +1186,18 @@ $md5_string = array ( './service/v4/soap.php' => '6c5a4f021b7b8769d9f6e1f1171412e4', './service/v4/rest.php' => 'ca3cf8d36013baa4e7c8e9a13779c2ca', './service/v4/registry.php' => '5d484089208a0c8a5bb02f8aaa62613a', - './service/v4/SugarWebServiceUtilv4.php' => '491416d9224abfc6376d3189b6047497', - './service/v4/SugarWebServiceImplv4.php' => 'd6684f16da4be549ca43765ec7080fab', + './service/v4/SugarWebServiceUtilv4.php' => '0f77c6eb16434a1aa1c423e2c232a33c', + './service/v4/SugarWebServiceImplv4.php' => '0c830476fac0476e0a657041203603e9', './service/v3_1/soap.php' => 'c43ef120b97861b99202658c57983de6', './service/v3_1/rest.php' => '264d8a7ff0a03bbeb38341753866ef70', './service/v3_1/registry.php' => 'fe17a5dfec64990947dece2ef2d2044d', - './service/v3_1/SugarWebServiceUtilv3_1.php' => '726a5f53669ad6216481ab1fbbeef5ce', + './service/v3_1/SugarWebServiceUtilv3_1.php' => '019ddc348de0866334f99c30fba1c908', './service/v3_1/SugarWebServiceImplv3_1.php' => 'd805bf0f55923dc6f1302c7e641c1479', './service/v3/soap.php' => '7e157b2fc2f3b124f2783b4375484dc9', './service/v3/rest.php' => '774a7775550af8c6b17aa68149d71577', './service/v3/registry.php' => '026af1671386111ddc7f133277bae4ae', - './service/v3/SugarWebServiceUtilv3.php' => '0cb9e2c617a8d04c8163c6fe42a664dc', - './service/v3/SugarWebServiceImplv3.php' => 'c994262ae3f8fd009ed9d973c2f05ea3', + './service/v3/SugarWebServiceUtilv3.php' => '34dbaeac8564ba667dc3c244cc88cfea', + './service/v3/SugarWebServiceImplv3.php' => 'e9496e75b83df883c0548713c9ca8d47', './service/v2_1/soap.php' => 'c80367ea67d280423d359a3c256f668f', './service/v2_1/rest.php' => '4fcc6a3f22dbebebc613466e895ce974', './service/v2_1/registry.php' => 'a3488f31d2db272596f7f905274ea65d', @@ -1217,7 +1218,7 @@ $md5_string = array ( './service/core/SugarRestUtils.php' => 'ddebba71abb25182a7769061862797ae', './service/core/SugarRestServiceImpl.php' => '18ab35c13544baa4fe716711cc541f62', './service/core/SugarRestService.php' => '5fc2c42a483676e6afc251174485f0c2', - './service/core/SoapHelperWebService.php' => 'f0d6fdd0ee012f78a2f9eed5bf132c23', + './service/core/SoapHelperWebService.php' => '0bcfcdb93f96e71436ce3d77f6595a70', './service/core/REST/SugarRestSerialize.php' => 'f80614ee5bc7e2f4a23460bbcc8c3eb8', './service/core/REST/SugarRestRSS.php' => 'eabfddaa4a65c3643f65ecab9f23c4bd', './service/core/REST/SugarRestJSON.php' => 'b3750c1987e8071bb3ad8296d9b4d5fa', @@ -1228,10 +1229,31 @@ $md5_string = array ( './removeme.php' => '750092ac2fec3ba2f04f0bff27bec33d', './pdf.php' => 'cc6788d5e02f50b1812ddb2ff3eb3703', './crossdomain.xml' => 'f35e9d412587c466e3f240f71fa12040', + './modules/OAuthTokens/views/view.authorize.php' => '0e83670a07684e3b9b58d8c33cd80a54', + './modules/OAuthTokens/vardefs.php' => '92ecc32bae190bdb1d0a78377a987b34', + './modules/OAuthTokens/tpl/authorized.tpl' => '01264aa4cca0d2bebf3d46153a96a715', + './modules/OAuthTokens/tpl/authorize.tpl' => '431da5402c74f8d4932b5e08431decd0', + './modules/OAuthTokens/metadata/subpanels/ForUser.php' => 'c639d5c357c75d86940aa0dfd7182f57', + './modules/OAuthTokens/metadata/subpanels/ForKeys.php' => 'ec6367b8930b4b26968b117443abd09b', + './modules/OAuthTokens/language/en_us.lang.php' => 'beadbf7d9d165ee741d8bb8e40d7c087', + './modules/OAuthTokens/controller.php' => 'db45c51c945491f0ce62490fb8c51703', + './modules/OAuthTokens/action_view_map.php' => '3f7578fe70316366a9218b9d0deeb97c', + './modules/OAuthTokens/OAuthToken.php' => 'd8ca5a92cce71dd675363d75b58e3bf6', + './modules/OAuthKeys/vardefs.php' => '00791bdd236d8e5de5b5b93a8745a2f1', + './modules/OAuthKeys/metadata/subpaneldefs.php' => '412ba2492810314ff8de438e4eb27338', + './modules/OAuthKeys/metadata/searchdefs.php' => 'd83b3fe8a6e07ffdc788dc15148e77b9', + './modules/OAuthKeys/metadata/metafiles.php' => '66b5260a8ff2fc603630dc5da0b56009', + './modules/OAuthKeys/metadata/listviewdefs.php' => '52c565bc0838e80ba3bfd06832a48f3c', + './modules/OAuthKeys/metadata/editviewdefs.php' => '4815491f5a03b8489f72318efccd2f88', + './modules/OAuthKeys/metadata/detailviewdefs.php' => 'e568706d576e3a425ee06364b37d3fb4', + './modules/OAuthKeys/metadata/SearchFields.php' => '793a8076c1ceb32dcdd3e85181815341', + './modules/OAuthKeys/language/en_us.lang.php' => '2cd29ba3e13c5db3c82a988fef2ea7cc', + './modules/OAuthKeys/controller.php' => '1b8d7faec697f2eba3da87bbcbd488ef', + './modules/OAuthKeys/OAuthKey.php' => 'f4c1c2dbcf0a006264f98e22f9ec7141', './modules/EAPM/EAPMEdit.js' => '5d9c244a0fde31b7a287f3d5294655f2', - './modules/EAPM/views/view.edit.php' => '15756095257d4123efda59d447bd8f52', - './modules/EAPM/views/view.detail.php' => 'aae5c942090aae0a47451d0552da15a4', - './modules/EAPM/vardefs.php' => '52ef1650cfb9a14662033502dfea3b57', + './modules/EAPM/views/view.edit.php' => 'bbf98e518a9cc4d60507ec244caf5ff3', + './modules/EAPM/views/view.detail.php' => '8acd593f5d4cb3bbf5ff357a3a1aac3b', + './modules/EAPM/vardefs.php' => '19efb7a428ac3618e44cb0839a0170eb', './modules/EAPM/tpls/EditViewHeader.tpl' => 'f6ceb4157ff4001f30ce573ab9eb1988', './modules/EAPM/tpls/EditViewFooter.tpl' => 'fb712fb4ba625c8a84ddfa416961acc5', './modules/EAPM/tpls/DetailViewFooter.tpl' => '4d7b991048a83432e4ff0bc0b979ba04', @@ -1241,16 +1263,16 @@ $md5_string = array ( './modules/EAPM/metadata/popupdefs.php' => '8ac77f99a562ee2e56b0440d48015c76', './modules/EAPM/metadata/metafiles.php' => '3074f22f9732fb9c4f790c3484d2460e', './modules/EAPM/metadata/listviewdefs.php' => '679f1783ab9921619633da292fba4311', - './modules/EAPM/metadata/editviewdefs.php' => '3b316e9e33a834c148903267b470a85a', + './modules/EAPM/metadata/editviewdefs.php' => '20c8dc741eebc45596eaabf2904694cf', './modules/EAPM/metadata/detailviewdefs.php' => '23c7497404745ea9c64772ddd519eb1b', './modules/EAPM/metadata/SearchFields.php' => 'ddbe9b2ea951a236c41c9b53bf2943e8', './modules/EAPM/language/en_us.lang.php' => '773b1814197f1d7ef7b2e119735be01b', - './modules/EAPM/controller.php' => 'ee22ecea28c02684def6024f0babb42e', + './modules/EAPM/controller.php' => '19356b5283686900244b6bfeba9d7f4a', './modules/EAPM/action_view_map.php' => '77446b5773d65522678670522cb25259', './modules/EAPM/EAPM.php' => '9eb7cedb8893fa5bd6eb7d981b054062', './modules/EAPM/CheckLogins.php' => 'db39640dbf662aea7f548788a6eddc92', './modules/vCals/vardefs.php' => '34085f31c8ae80e7ca93127271689e3e', - './modules/vCals/vCal.php' => '47ef1f33681a3e03f01b0007f04d411e', + './modules/vCals/vCal.php' => 'd51b96b678c2fc93c3731eb5d3f5b2ae', './modules/vCals/field_arrays.php' => 'af767daaea141ca2bcf6daa70d9f4da2', './modules/vCals/Server.php' => 'b42524c5bb21266d5911fefe7fd690d2', './modules/vCals/HTTP_WebDAV_Server_vCal.php' => 'a3a618d76c2282378b62ab673e2d3933', @@ -1267,12 +1289,12 @@ $md5_string = array ( './modules/Users/PasswordRequirementBox.js' => '3cfa4025dc373a7e065cf8a11ab812a0', './modules/Users/User.js' => '6b09906cad1a804cb6969e553c2bc4ff', './modules/Users/login.js' => '7a504860a02eaebfdf1a9a7f9578dcc7', - './modules/Users/DetailView.tpl' => '8606bcec7d757a75345aff8f8bf86a0a', - './modules/Users/views/view.wizard.php' => '835338a6bbf0fd03bd9827492cf19337', - './modules/Users/views/view.list.php' => '8bc5a879644c94372a52d240cb7ecb03', + './modules/Users/DetailView.tpl' => 'a2de2642d56437b50e3844536d310bf3', + './modules/Users/views/view.wizard.php' => '4568a51d4d3468e84666dc066be7bc83', + './modules/Users/views/view.list.php' => '91fe6e2e3f9a62f0903835f7963129b6', './modules/Users/EditView.tpl' => '5b277e0b4fee85906e718c79d3c40936', - './modules/Users/tpls/wizard.tpl' => 'bc2be934816e4249512626abf18d2f99', - './modules/Users/reassignUserRecords.php' => 'cd6548bd2a6d23217f065a4223071983', + './modules/Users/tpls/wizard.tpl' => '6d36734b8d0a20806f1f2bd0661bd7cd', + './modules/Users/reassignUserRecords.php' => '454d3c28f332ccdcdf25d563f4f7b9ca', './modules/Users/password_utils.php' => '614d9ea87a83d7c210bbfe585908b870', './modules/Users/metadata/subpanels/default.php' => '8ccd5a2436c48f152588bd59e6c6bcb0', './modules/Users/metadata/subpanels/ForTeams.php' => '96a782f23790b32bfd101f7f5f86cb2a', @@ -1281,19 +1303,19 @@ $md5_string = array ( './modules/Users/metadata/subpanels/ForMeetings.php' => '8b16caaf5651904ee91c1b2d9dae19c6', './modules/Users/metadata/subpanels/ForEmails.php' => 'a077f9541d08415783d47899544574ce', './modules/Users/metadata/subpanels/ForCalls.php' => '624f240be051035ffdb0880a2d03c2a4', - './modules/Users/metadata/subpaneldefs.php' => 'bc2749768f23c8680586862a4eb63aed', + './modules/Users/metadata/subpaneldefs.php' => 'b2c669ec125c4b5b7e994de7fe95df06', './modules/Users/metadata/searchdefs.php' => '6f1c14eecf7c3775bcd95ed5a1a110fa', './modules/Users/metadata/reassignScriptMetadata.php' => 'c3b8c884116a57082ac615416176b294', './modules/Users/metadata/popupdefs.php' => '0372e0370745358af86d41aef6451901', './modules/Users/metadata/listviewdefs.php' => '95332a36771e76e5e2edd4cdcaf4f604', './modules/Users/metadata/SearchFields.php' => '110f0aa503a041056fdfd3c20bbb18fc', './modules/Users/EditView.php' => 'fc3a145f61c7b4c7dfcc3338672a2ae8', - './modules/Users/vardefs.php' => 'fb892f832936653d5321bedcfb653507', - './modules/Users/language/en_us.lang.php' => '22a5e8386ce20959eb167d62aea2c2e0', + './modules/Users/vardefs.php' => '287105d7316c4abffad3d99409e054ca', + './modules/Users/language/en_us.lang.php' => '64dd06d6974f51be55ca7c2d7d272152', './modules/Users/field_arrays.php' => '3c31038add3a77287e815bc5a7a7a609', './modules/Users/controller.php' => '80b928a09b15d4c9df8904317880974f', './modules/Users/authentication/SugarAuthenticate/SugarAuthenticateUser.php' => '406f625eb707435e7710880c7aec779e', - './modules/Users/authentication/SugarAuthenticate/SugarAuthenticate.php' => '5b0f31fa450a1be1a031902b60e0641d', + './modules/Users/authentication/SugarAuthenticate/SugarAuthenticate.php' => '8cdea5361fff4c312147d2d8334e2f4a', './modules/Users/authentication/SAMLAuthenticate/settings.php' => 'aac61ea76cd0f3d13cdfcfc5e83d18b1', './modules/Users/authentication/SAMLAuthenticate/lib/xmlseclibs/xmlseclibs.php' => '76623791faf895bcbbd016d9945e8c48', './modules/Users/authentication/SAMLAuthenticate/lib/xmlseclibs/CHANGELOG.txt' => '113d14ef4333039359236ffed624fb85', @@ -1314,9 +1336,9 @@ $md5_string = array ( './modules/Users/UserSignatureEditView.html' => '892d745adb145d74bde512c71e30732c', './modules/Users/UserSignature.php' => '23592719467cc4e04be189c6fa2d30db', './modules/Users/login.tpl' => '6de6b9ab4e1ddf56997fcfa66ca08ac2', - './modules/Users/DetailView.php' => '3f8ee5e2c1c4f99e8e7ee01141f95cf5', + './modules/Users/DetailView.php' => '587eb02095c1ebee3513a13410d6f92e', './modules/Users/login.css' => '12d8483e8f6da8e1a95d54b1b50d0ec9', - './modules/Users/User.php' => 'e02d8e23efb0168b7ba432f990d6f0cd', + './modules/Users/User.php' => 'c64ceb7ee9ffae0987b90356ebe37027', './modules/Users/SaveTimezone.php' => 'c12559f852fb8d89a269814e808dadc5', './modules/Users/SaveSignature.php' => '2f8bfdb6f88dce867100a761366d0391', './modules/Users/SetTimezone.tpl' => 'f76851063b5129bcae41e7bef962636f', @@ -1324,7 +1346,7 @@ $md5_string = array ( './modules/Users/PopupUsers.php' => '5da32a565d9639eb42ab47e2d3330c08', './modules/Users/SetTimezone.php' => '2fc96607e206886451fb5fe55f5526fd', './modules/Users/PasswordRequirementBox.css' => '57efa45544952eead6155719254e03c1', - './modules/Users/Save.php' => '0bce18dac108a3aa3518f5fcae8b9d0a', + './modules/Users/Save.php' => '184b31a7d11638c826eef64cc2addb07', './modules/Users/Popup_picker.html' => '1160ad9218e2e8933b49f4ac1b695261', './modules/Users/ListRoles.php' => '9833b76bd6bd4889285b4b4a6b933849', './modules/Users/PopupSignature.php' => 'd9c4749eea3254af4bbef1d83736309c', @@ -1335,7 +1357,7 @@ $md5_string = array ( './modules/Users/GeneratePassword.php' => 'cd550ab172dc3dcbb715221ec97469a0', './modules/Users/Forms.php' => '90b591c94157299485166b686f6a977d', './modules/Users/Changenewpassword.tpl' => '65a02130fbb6caabd2b662ca70bae9fd', - './modules/Users/Changenewpassword.php' => '80cd1b05144aecdc382d9e50ec7efb1a', + './modules/Users/Changenewpassword.php' => 'bd77852c3df5a6509c0207f0cddeaf2e', './modules/Users/ChangePassword.php' => 'e4161c571295ad4635ff66ff5e4cfc7b', './modules/Users/ChangeGroupTab.php' => 'e8c4be930b91260c8bdf1d07aced8c37', './modules/Users/Authenticate.php' => 'e2518a47f12b5b8b53f8b065348d8126', @@ -1347,7 +1369,7 @@ $md5_string = array ( './modules/UpgradeWizard/upgradeWizard.js' => '3ca941da793c30a8a4e913624071166e', './modules/UpgradeWizard/UpgradeRemoval.php' => 'f8f4d6102a0cdc17d48444372a6ed2d8', './modules/UpgradeWizard/uw_main.tpl' => '898039c49451aefbef0bfdece6c43f3b', - './modules/UpgradeWizard/uw_utils.php' => '75ccaa46f18d59148794a272d655df48', + './modules/UpgradeWizard/uw_utils.php' => 'f1106796cf307744e1f2d196c9d506f3', './modules/UpgradeWizard/uw_emptyFunctions.php' => 'fc09ce5db1b1aacd792140ceadc9ccd2', './modules/UpgradeWizard/uw_files.php' => '0b16b9d7181ac363d19aa43b8c50090b', './modules/UpgradeWizard/upload.php' => 'dcc4f893338f9ad97e236b7b39bd28cc', @@ -1357,8 +1379,8 @@ $md5_string = array ( './modules/UpgradeWizard/systemCheckJson.php' => 'ff48d6c123ea4c15c6887b2fdd765be0', './modules/UpgradeWizard/systemCheck.php' => '8f3109befa71e411d4bf898bd684ddb9', './modules/UpgradeWizard/start.php' => '339714f45395246c6f2ed68dc6b3e9b8', - './modules/UpgradeWizard/silentUpgrade_step2.php' => 'f1e4729f64aeb66fab829fe589400ece', - './modules/UpgradeWizard/silentUpgrade_step1.php' => '35ba042c4ac10a44b91f3e6a994f4bfe', + './modules/UpgradeWizard/silentUpgrade_step2.php' => '567d5f829a99343aba53f8824db9ca3c', + './modules/UpgradeWizard/silentUpgrade_step1.php' => '95c65f12838c39c659f332617647ebcf', './modules/UpgradeWizard/silentUpgrade_dce_step2.php' => '40060f08c625546f424f15c82c884f1b', './modules/UpgradeWizard/silentUpgrade_dce_step1.php' => '25784884d8a4b7babca2c8844f03e960', './modules/UpgradeWizard/silentUpgrade.php' => 'a41bbf9eeead4b0cd6fe3ea9a219cc9e', @@ -1372,8 +1394,8 @@ $md5_string = array ( './modules/UpgradeWizard/deleteCache.php' => '2243700008a8b513b69f009e8c6dbcf8', './modules/UpgradeWizard/index.php' => '0732f50b02de0f8f9cb0cf0893c4bf5a', './modules/UpgradeWizard/commitJson.php' => '3ac93b7343984a726d004499c53b315b', - './modules/UpgradeWizard/end.php' => '7650857e626b6fba0afd8114b5c46b2c', - './modules/UpgradeWizard/commit.php' => 'b12af2d5c23fdf23379af2032a37a065', + './modules/UpgradeWizard/end.php' => '768d3c8c58350f4f1a5645d2270ba5ca', + './modules/UpgradeWizard/commit.php' => '2a73710b78e7a174af28b7c7e7d5cb44', './modules/UpgradeWizard/cancel.php' => 'e0b5196ee60b18d6a2876b96f16eda74', './modules/UpgradeWizard/UploadFileCheck.php' => 'd4a88e3b6923cf3365fedbf501116dd6', './modules/UpgradeWizard/SugarMerge/SugarMerge.php' => 'ed5f03dd65e4a51843e22a9f79e3b930', @@ -1403,7 +1425,7 @@ $md5_string = array ( './modules/Trackers/Metric.php' => 'b2fe3a0da872c9b6b22c208f356dc6f7', './modules/Trackers/BreadCrumbStack.php' => '5bb356798b059c8b882f371d44efa584', './modules/Tasks/views/view.edit.php' => 'b3407d67d7c3cc4b835bd66b2e802c86', - './modules/Tasks/vardefs.php' => '7b349f428812c11fc4ff5dfde48ff8a4', + './modules/Tasks/vardefs.php' => '6df43948e3ad67518e3a1aaaed4a8d7a', './modules/Tasks/tpls/QuickCreate.tpl' => 'cc473787ebe1f4c7dfba17268bd2e1e1', './modules/Tasks/metadata/subpaneldefs.php' => 'b55eba643229a90c021abfa15caccf37', './modules/Tasks/metadata/subpanels/default.php' => '6aa5aad5295409fc898bae85d5c501d0', @@ -1414,14 +1436,14 @@ $md5_string = array ( './modules/Tasks/metadata/searchdefs.php' => 'ebcea5484c63a735f7f9a6458c75e408', './modules/Tasks/metadata/quickcreatedefs.php' => 'df8ebf40ecaf29bc81ff00ece66551a6', './modules/Tasks/metadata/listviewdefs.php' => '10cacb8f8331503da374e81ca9efd04b', - './modules/Tasks/metadata/editviewdefs.php' => '92f8b359f450330d6543fa49145eeb77', + './modules/Tasks/metadata/editviewdefs.php' => '65463d3212fd435e67d90a742ae52b64', './modules/Tasks/metadata/detailviewdefs.php' => '8d9dee7836946ab99b59c23f1f6eb4f2', './modules/Tasks/metadata/additionalDetails.php' => '7253182a0b7133b102ab653de7d067a5', './modules/Tasks/metadata/SearchFields.php' => 'fdff23f9fd818c206f89f3a5344ad7a4', - './modules/Tasks/language/en_us.lang.php' => 'ec9bfc50f2edafae18884f490b1521bc', + './modules/Tasks/language/en_us.lang.php' => 'a8037f29afc2f04ad7e731920caf2a1b', './modules/Tasks/field_arrays.php' => '9869facdbe32bc0551b9ec7429671848', './modules/Tasks/TasksQuickCreate.php' => '8df028b5cde8de961c6d94574f3c860e', - './modules/Tasks/Task.php' => '3373405068978da7e0c937b4cfabe219', + './modules/Tasks/Task.php' => '742d9fd5903273df014f390ccc7c0ee1', './modules/Tasks/Save.php' => '87926f8aefc476572a32c4af581298af', './modules/Tasks/MyTasks.php' => 'b8da620a87eee61e0b6b50421eb9590b', './modules/Tasks/MyTasks.html' => '58c3695222bf9a745f2b2f4f5d52ae90', @@ -1429,7 +1451,7 @@ $md5_string = array ( './modules/Tasks/Dashlets/MyTasksDashlet/MyTasksDashlet.php' => '03df49cfe18a8bedb7e751204ac1f33c', './modules/Tasks/Dashlets/MyTasksDashlet/MyTasksDashlet.meta.php' => 'aee8b2e51d869bdc6e9ec4bded092817', './modules/Tasks/Dashlets/MyTasksDashlet/MyTasksDashlet.data.php' => '5e5a4990c4eecefeea7e306a56f760ca', - './modules/TableDictionary.php' => 'c6e25d006ba573da551c50da41810f2f', + './modules/TableDictionary.php' => '2bc396dba06f78aa2934cb81a09c4d7c', './modules/SugarFeed/views/view.adminsettings.php' => '18adcc9cbf9aa005a8e8b77526e2d4cc', './modules/SugarFeed/action_view_map.php' => '8171b3d43e34d470cc5a0cdfb8155ad1', './modules/SugarFeed/vardefs.php' => '44b349d7192fdebe540a405d4c3475ec', @@ -1445,7 +1467,7 @@ $md5_string = array ( './modules/SugarFeed/linkHandlers/YouTube.php' => 'f4db6ce94064cc7b76d89d60ca7ed52f', './modules/SugarFeed/linkHandlers/Link.php' => '3c7df1b811905aba70388a2840c0ffbb', './modules/SugarFeed/linkHandlers/Image.php' => 'bd105346d0770f315932fdded43ae24e', - './modules/SugarFeed/language/en_us.lang.php' => '40f18c1071e83b52deaed4e5461be9b7', + './modules/SugarFeed/language/en_us.lang.php' => '24e3105201fa3995a207a7056900dd16', './modules/SugarFeed/feedLogicBase.php' => '023045e985d8711131e37024093210a5', './modules/SugarFeed/tpls/AdminSettings.tpl' => 'a3f1aa0b7f67cf5cc292c6b8f051f220', './modules/SugarFeed/SugarFeedFlush.php' => 'fd91e962f637dd8bcd5ee9bc028ea54a', @@ -1453,24 +1475,26 @@ $md5_string = array ( './modules/SugarFeed/Forms.php' => 'd41d8cd98f00b204e9800998ecf8427e', './modules/SugarFeed/Dashlets/SugarFeedDashlet/UserPostForm.tpl' => '2c55e30b66f70ca146eec8a9f4506621', './modules/SugarFeed/Dashlets/SugarFeedDashlet/SugarFeedScript.tpl' => '95aef9663dc3396435295619ceb7ba43', - './modules/SugarFeed/Dashlets/SugarFeedDashlet/SugarFeedDashlet.php' => '42f88163229b5c61f6f366392994bb59', + './modules/SugarFeed/Dashlets/SugarFeedDashlet/SugarFeedDashlet.php' => '83da572e68404551008187d847a8a807', './modules/SugarFeed/Dashlets/SugarFeedDashlet/SugarFeedDashlet.meta.php' => 'c318d9d7b4d1b544dae1b8b1cd1bab8a', - './modules/SugarFeed/Dashlets/SugarFeedDashlet/Options.tpl' => '6d29b70f748200a3f7aa9b86dbddd14f', + './modules/SugarFeed/Dashlets/SugarFeedDashlet/Options.tpl' => '0fecf9d27d5f7335751bf5a517bfb843', './modules/SugarFeed/SugarFeed.php' => '74c08d6b75e5be2bd36bbf63827f00bc', './modules/SugarFeed/AdminSettings.php' => '85297b7a6a71ffdb9adfb5a2468d1018', './modules/Studio/JSTransaction.js' => 'ddc1671e785fd003c42414b14b8a746e', - './modules/Studio/studio.js' => '9e6ed22dc09eaf0c6a7f131c474d14a0', + './modules/Studio/studio.js' => '6f9c6e0614b8331727c96a41bda6c29b', './modules/Studio/studiodd.js' => '6122b82ee5480cb0c105ae13ed2d2b3e', './modules/Studio/studiotabgroups.js' => '0914ad3b4384826e6a49bf231b2e4495', './modules/Studio/ygDDListStudio.js' => '2d3316c51f34ee87cc887b41e6d3539f', - './modules/Studio/wizards/StudioWizard.php' => '35b096e82adffc3f73d81ae407ff968b', + './modules/Studio/wizards/RenameModules.tpl' => 'ecd77fe3760860b7f1457425be052dc8', + './modules/Studio/wizards/RenameModules.php' => 'b68f3c939efc33d17c7756c882aff215', + './modules/Studio/wizards/StudioWizard.php' => '4309aae3b3614cf7cf2d160d52c3944f', './modules/Studio/wizards/EditDropDownWizard.php' => '47997b18f2d0eed6613e4e8ee3bec245', './modules/Studio/wizard.php' => '1eb1fe073c5a846796636d94ce0a246c', './modules/Studio/parsers/StudioParser.php' => '140b8ac9f5a6822166ed53096aae21a8', - './modules/Studio/language/en_us.lang.php' => '8481dff368a6bf290f374b9106a7928c', + './modules/Studio/language/en_us.lang.php' => 'c52d7cb29f9a2828dbcbf51d41cf9a0f', './modules/Studio/language/en_us.Portal.html' => '01a47f295a288ac42c5d346253609e15', './modules/Studio/config.php' => '3dfa02691501162caf33bb620c4134ad', - './modules/Studio/TabGroups/TabGroupHelper.php' => '2c9be0d1eb4b5892aa5b90bca254f370', + './modules/Studio/TabGroups/TabGroupHelper.php' => 'e0ae40749080a6d0ffa68c68aa0dfb1a', './modules/Studio/TabGroups/EditViewTabs.tpl' => '560fdd921b4fc7aa502bce3ea22b83a7', './modules/Studio/TabGroups/EditViewTabs.php' => '58ff2f987093b74810debde076111185', './modules/Studio/TabGroups.php' => '028fd651b7e45ce986fb653eeff5cd88', @@ -1478,21 +1502,21 @@ $md5_string = array ( './modules/Studio/Forms.php' => '643a41668f378fdfcf340eacff957880', './modules/Studio/DropDowns/EditView.tpl' => 'cba2195e86a4f1480dfbb1c189c58c3d', './modules/Studio/DropDowns/EditView.php' => 'cfa36bf9fb56414ee9706fe4be586ce2', - './modules/Studio/DropDowns/DropDownHelper.php' => 'dfbfc7cc9a20694a3eb4a4d8845c93d3', - './modules/SchedulersJobs/vardefs.php' => 'a01a32929146b1fcffc1f344cac76b65', + './modules/Studio/DropDowns/DropDownHelper.php' => 'e84c37f71556d3d90145832e04accfee', + './modules/SchedulersJobs/vardefs.php' => '23f57bde247519a289ce85fbb6a0d917', './modules/SchedulersJobs/metadata/subpanels/default.php' => 'f3cf4560886a3feb95495607613f83e4', './modules/SchedulersJobs/language/en_us.lang.php' => 'e2ad9c5aa5d9411f633472ad5a833825', './modules/SchedulersJobs/field_arrays.php' => 'f0decfc7674132c67f7bc2679d2fa798', - './modules/SchedulersJobs/SchedulersJob.php' => '6c9bab393fac8dfa0b3f7541d6db5dfa', + './modules/SchedulersJobs/SchedulersJob.php' => '8054a33e74db17540dc9f46591292b75', './modules/Schedulers/vardefs.php' => 'b22dc28f445bd76192a98b92eb5a1c9f', './modules/Schedulers/metadata/subpanels/default.php' => '0fa97427b4326367097ceca6bf17071f', './modules/Schedulers/metadata/subpaneldefs.php' => '11cf00d568cc8990f83b9c72282571ee', './modules/Schedulers/language/en_us.lang.php' => '77de32f02587cbd26106b809ba5fa654', './modules/Schedulers/index.php' => '44518848b02ce7cbd51c1b3016cc52e7', './modules/Schedulers/field_arrays.php' => 'd4dd0e9a487e50cc1e3937edf28d4851', - './modules/Schedulers/_AddJobsHere.php' => 'deb98781e316c0883b0e1cc6813cd5e3', + './modules/Schedulers/_AddJobsHere.php' => 'a66c4d5dbc4459fe45e4fe0c65cf1cb6', './modules/Schedulers/SchedulerDaemon.php' => '0fe85dd3ab4b9dc4132e0ae782ebce90', - './modules/Schedulers/Scheduler.php' => 'd8e8aa2e8de94254e2364b28eca9a1cf', + './modules/Schedulers/Scheduler.php' => 'e2974da4ec05a9927b9c8610c131299a', './modules/Schedulers/Scheduled.php' => 'a4f070fb20dde6617eb49fceefbb195f', './modules/Schedulers/Scheduled.html' => '998aaba0c83416168b78a2cc0124d678', './modules/Schedulers/Save.php' => '9ae861c83f40d3ac45083f796b2ac97c', @@ -1509,13 +1533,13 @@ $md5_string = array ( './modules/SavedSearch/vardefs.php' => 'bce2873ff96fc8211d0c9edc8500a551', './modules/SavedSearch/metadata/listviewdefs.php' => '08814cee1aa8bc86605fa0bce203493e', './modules/SavedSearch/language/en_us.lang.php' => '5271a9d91c192d1d84362fd2ff0bb9e6', - './modules/SavedSearch/index.php' => '552539a8ca0f514f2ebd84b27e17306b', + './modules/SavedSearch/index.php' => '2105e21cb8f6efc0aeb93c9c9ccd9499', './modules/SavedSearch/field_arrays.php' => '0a3131ce56bc5e314f82f99535ba7f0f', './modules/SavedSearch/UpgradeSavedSearch.php' => '1ea269671af4dd80cb2edfcc6c220d6c', './modules/SavedSearch/SearchForm.html' => 'b459847986a5a78033744d2ac2fd83b8', './modules/SavedSearch/SavedSearchSelects.tpl' => 'b7caafc55f6366f78048882c66d6889e', './modules/SavedSearch/SavedSearchForm.tpl' => 'e1b30f7f970a53e8fbdf59c56594992a', - './modules/SavedSearch/SavedSearch.php' => '32a5293b4fa7b75a8a7fe72c4e9978af', + './modules/SavedSearch/SavedSearch.php' => 'aa52c982c4b6991d0c2c3d3510c62264', './modules/SavedSearch/Menu.php' => 'dc4c7a6e251fafed9e02fdedeadb6de1', './modules/SavedSearch/ListView.php' => '2a0fb2b9472a48ec7562f72d423ae925', './modules/Roles/views/view.list.php' => '1fa66e2cc62b833309892227d4cd64bb', @@ -1553,14 +1577,17 @@ $md5_string = array ( './modules/Releases/EditView.php' => '616e428f094a7f196d260a93d7218872', './modules/Releases/EditView.html' => '5c2adf048bc5041f494fe24b9aed3c18', './modules/Releases/DetailView.php' => '4e9760c1b8f5b0eb2af484ca78d74874', + './modules/Relationships/views/view.editfields.php' => '4cb71d6145ad4059f5e715367fb08371', + './modules/Relationships/editFields.tpl' => '0acfa8c76ab17c8264b255142b99843c', + './modules/Relationships/action_view_map.php' => '3116354c7a1eed0637476fe5208b046b', './modules/Relationships/vardefs.php' => '49e5e099b3410ad700a04bb2bafabc41', './modules/Relationships/language/en_us.lang.php' => 'c22b955d2b324625774da16ef7a5e338', './modules/Relationships/field_arrays.php' => '2cfa3336afabe563de6ef7715812ac9e', './modules/Relationships/RelationshipHandler.php' => 'c410a6e0b5b8461854911163c68197ac', - './modules/Relationships/Relationship.php' => '388a05505b328fd9999be88aae2a11d2', + './modules/Relationships/Relationship.php' => 'd95722298938be1820cde0827c2d164d', './modules/Prospects/views/view.list.php' => '68d9be3fca96a61f9399a076f68477c4', './modules/Prospects/views/view.detail.php' => 'ae26b90ab79aa7eb11ffafd1b08c4311', - './modules/Prospects/vardefs.php' => 'bd3c7deea05dbe26f1667e2030a5b5db', + './modules/Prospects/vardefs.php' => 'bec66e2871aa29a2e4aa734e65fb8d88', './modules/Prospects/tpls/DetailViewHeader.tpl' => 'ac21eaebc7f6c9f81636f9e933c19e89', './modules/Prospects/metadata/subpanels/default.php' => '5a2c8d4f0f511e8fccf8af973d9c32e0', './modules/Prospects/metadata/subpaneldefs.php' => 'e3f9951e9a845cc6d1e75e4e926b0acf', @@ -1573,16 +1600,16 @@ $md5_string = array ( './modules/Prospects/metadata/detailviewdefs.php' => '58d4c29e613981bb9d53fad202f3a706', './modules/Prospects/metadata/additionalDetails.php' => '48f4bf2f478764f3de91dfbc1b710947', './modules/Prospects/metadata/SearchFields.php' => '132a7c6813df95e87b4bab647094fd36', - './modules/Prospects/language/en_us.lang.php' => '6750c4f0f4b363a894008e1241e7fc7f', + './modules/Prospects/language/en_us.lang.php' => 'd1a459455c97b5ec5280fb9eb6248d24', './modules/Prospects/field_arrays.php' => '11752a64ced2fe06cca0b7da2bd5e42b', './modules/Prospects/Save.php' => '94ea92c9bdbc15f131ea76deb1f5c05d', './modules/Prospects/ProspectFormBase.php' => '72b52d25d6cec57f62aeb5b22a2f1d11', './modules/Prospects/Prospect.php' => '82e124f5609d2e95675b5e7abcbd3d93', './modules/Prospects/Popup_picker.html' => '95a7cb67f4ab07776998dfa256006f63', - './modules/Prospects/Menu.php' => '954ee473c71bac08d294415f04816411', + './modules/Prospects/Menu.php' => '7b9014e6b0c640f4f844e9547d9e91e1', './modules/Prospects/Import.php' => '41811673320c34629e81991794d41215', './modules/Prospects/Delete.php' => '73e1368420f1c644eb309e81c24bc17d', - './modules/ProspectLists/vardefs.php' => 'b40ddfd90e1f20c521061596c2314fa5', + './modules/ProspectLists/vardefs.php' => 'f7741a3c29481cbfaa666a6c9381b6fc', './modules/ProspectLists/metadata/subpanels/default.php' => 'e602998606f5e57c84068c9775c93035', './modules/ProspectLists/metadata/subpaneldefs.php' => 'a9d9d8cacb0a038f236bf0fe936c58f2', './modules/ProspectLists/metadata/searchdefs.php' => '94fac783334f247903f13159954abf1c', @@ -1596,9 +1623,9 @@ $md5_string = array ( './modules/ProspectLists/TargetListUpdate.php' => '20eae2a794576eef4e6f42084945d990', './modules/ProspectLists/SubPanelView.php' => 'cdeb64078656d4c1311359bd98227dde', './modules/ProspectLists/SubPanelView.html' => '0f85fa011831af642f37e9229361e8c1', - './modules/ProspectLists/Save.php' => 'bc35b9e5c86a6c10ece3e46baec6d649', + './modules/ProspectLists/Save.php' => '0b9b9ef87833bc9462478eaf5887d411', './modules/ProspectLists/ProspectListFormBase.php' => 'c233f6c49c1ab9f5108eb9d2ebb4cea3', - './modules/ProspectLists/ProspectList.php' => 'ce89e40112f2551c13b4ae0ea5471372', + './modules/ProspectLists/ProspectList.php' => 'c109529d10ea3f51a4d413954c364525', './modules/ProspectLists/Popup_picker.html' => '19f9f5f32facaf5e8919535e6d84a7d5', './modules/ProspectLists/Menu.php' => '8fec51700001baa9b7c8c774c69186c1', './modules/ProspectLists/Forms.php' => '9b5c7ac088edd7441f51b9b0bb41a41f', @@ -1626,7 +1653,7 @@ $md5_string = array ( './modules/ProjectTask/Save.php' => 'd1a87b0fbe38bcd6c3024871b61d3251', './modules/ProjectTask/ProjectTaskQuickCreate.php' => '9e22afc763a7461aae6ac12f0da9672d', './modules/ProjectTask/vardefs.php' => '5b4cf6dad9a98cc9ca0d125f9a72fcaf', - './modules/ProjectTask/ProjectTask.php' => 'e663b10b87cb5f9c7178635fe0d056a5', + './modules/ProjectTask/ProjectTask.php' => 'acf2e732033e42ef3880c6193d8fe5e0', './modules/ProjectTask/Popup_picker.html' => '361f855dacedadd41f50b2305ef63ef9', './modules/ProjectTask/MyProjectTasks.php' => 'beb50630e8c111fc22db6c99bc24e7cb', './modules/ProjectTask/MyProjectTasks.html' => 'ffd4e103720ddbbc0841c63fdc16128f', @@ -1657,7 +1684,7 @@ $md5_string = array ( './modules/Project/metadata/detailviewdefs.php' => '0d47d01cba0aa1936f068574946e728a', './modules/Project/metadata/additionalDetails.php' => '4da1e430fcca6ec985567aac8eb695e6', './modules/Project/metadata/SearchFields.php' => 'ca8b58e6c4afd5d254e1fd7110202786', - './modules/Project/language/en_us.lang.php' => '4ee764cdd17fdf9de8860ea0ca0bb00c', + './modules/Project/language/en_us.lang.php' => '9266f3dc5ce8d9954aeac7632c691df2', './modules/Project/field_arrays.php' => 'd8e855b0d74739d70979073507e6be70', './modules/Project/action_view_map.php' => 'a7a8e30d48d654d43b19c11a883339dc', './modules/Project/SubPanelView.php' => '634feb071966461b4db22fc2bd058386', @@ -1673,12 +1700,12 @@ $md5_string = array ( './modules/OptimisticLock/Forms.php' => '2a29f4ec451b7e19e8212eac749fd709', './modules/Opportunities/views/view.edit.php' => 'e992ed0d268cf0c4e20fa8c1e1cb02e7', './modules/Opportunities/views/view.detail.php' => '1ed7886c066a84021d61e26290acc502', - './modules/Opportunities/vardefs.php' => 'd8e5afe13fbbe921dda33706536f9df3', + './modules/Opportunities/vardefs.php' => '23449691636e3266a9fa1d44d636ad59', './modules/Opportunities/tpls/QuickCreate.tpl' => '09a5f1c1af35584137b310e1c1dfc7b7', './modules/Opportunities/metadata/subpanels/default.php' => '926a5aa70884e0bbfcfbe912e6b71248', './modules/Opportunities/metadata/subpanels/ForEmails.php' => '0051b80b6a325af4c85c05791d535b33', './modules/Opportunities/metadata/subpanels/ForAccounts.php' => '14dcb209dc51874c643f9652e0e6e531', - './modules/Opportunities/metadata/subpaneldefs.php' => 'e6c5c2a3e5230c702aeb23e7ea07d09d', + './modules/Opportunities/metadata/subpaneldefs.php' => '78317863e1fff881f2e432da179bfedf', './modules/Opportunities/metadata/studio.php' => 'd90545123bff86798ec8d519e972f1b7', './modules/Opportunities/metadata/searchdefs.php' => '117b4c5553e7c313d618fc5ebbf32b6f', './modules/Opportunities/metadata/quickcreatedefs.php' => 'f438a8f9031d5b7c88798e2c4c04e517', @@ -1690,7 +1717,7 @@ $md5_string = array ( './modules/Opportunities/metadata/additionalDetails.php' => 'fe8b2e0248e5312ffe124a22c0162559', './modules/Opportunities/metadata/acldefs.php' => '8ac8ee83dac6db078665347065acd45d', './modules/Opportunities/metadata/SearchFields.php' => 'cc75cc371d8c390d7dfde77a0aa8b17e', - './modules/Opportunities/language/en_us.lang.php' => '6a96fbac2390444424e6d1cb83f528de', + './modules/Opportunities/language/en_us.lang.php' => '271276ccbbe9acb78fcb68d9e576d1e5', './modules/Opportunities/field_arrays.php' => 'b71e67dc2e4b4d1d6312a957da6e5eab', './modules/Opportunities/SugarFeeds/OppFeed.php' => 'a7bda69cb1bd837bb134c2f9b4b7c61a', './modules/Opportunities/SubPanelViewProjects.php' => '569822f83099d5814c6933c98b287dd6', @@ -1702,7 +1729,7 @@ $md5_string = array ( './modules/Opportunities/OpportunityFormBase.php' => '7f81a326c17dd3a34e83577d6fe33ae1', './modules/Opportunities/Opportunity.php' => 'cb982375e35f4baa0d9461f200c2d587', './modules/Opportunities/OpportunitiesQuickCreate.php' => '25dcf755055937cba784ca069ea5de13', - './modules/Opportunities/Menu.php' => '8a4a0e8e27ad86e59f9d80453e039c0c', + './modules/Opportunities/Menu.php' => '14e601ef555d917fc7d2ac5cc88ab4ca', './modules/Opportunities/ListViewTop.php' => '4562f0c199e8ad381c30f0609ba7c5c0', './modules/Opportunities/ListViewTop.html' => 'aa3f031d26f868a40a51743e9a079f27', './modules/Opportunities/Dashlets/MyOpportunitiesDashlet/MyOpportunitiesDashlet.php' => 'b05d4a498a721e356b4b2f8d4eb503bf', @@ -1716,7 +1743,7 @@ $md5_string = array ( './modules/Notes/Dashlets/MyNotesDashlet/MyNotesDashlet.php' => '9a3ac349a7dd37b5bf57d7ed27c5902a', './modules/Notes/Dashlets/MyNotesDashlet/MyNotesDashlet.meta.php' => '47901f5e7393bfe5d8a4e5fb992850d9', './modules/Notes/Dashlets/MyNotesDashlet/MyNotesDashlet.data.php' => 'f7b4f295a3e38dfa599f57dff0299fbd', - './modules/Notes/vardefs.php' => 'cab6df212bfef2b7576355d5206a3cc7', + './modules/Notes/vardefs.php' => 'b2d932bcaa62a8be782968e7952d458f', './modules/Notes/tpls/QuickCreate.tpl' => '882303cea97bf47f4c2438a3f1cdc340', './modules/Notes/tpls/EditViewHeader.tpl' => 'e4453755f80418d6058bb0fff135ef45', './modules/Notes/metadata/subpanels/ForTasks.php' => '5adc05c6f569c423443c642ebf0b635b', @@ -1732,19 +1759,19 @@ $md5_string = array ( './modules/Notes/metadata/detailviewdefs.php' => 'c9991544e69bc5369b9771a432354a4c', './modules/Notes/metadata/additionalDetails.php' => '47f61f0e9f69fc808d3cfbee124620b8', './modules/Notes/metadata/SearchFields.php' => '9a8f9bb1cf31a1d0fd3fe74e49364e49', - './modules/Notes/language/en_us.lang.php' => 'f0d4a00b13d430a6b484f1db5c551502', + './modules/Notes/language/en_us.lang.php' => '10c2d2032676569c4ec8005c0b0faeda', './modules/Notes/field_arrays.php' => '463c08bd1cf6d96a42d2a1758a5b0e8a', './modules/Notes/controller.php' => '256cbdb7a767232ff340330240ee2a1c', './modules/Notes/SubPanelView.php' => '77aa706c2cf2567642ba66a7c4f70959', './modules/Notes/SubPanelView.html' => '9dd4a3ce3c5c5ecc5c00a52c931867cc', './modules/Notes/NotesQuickCreate.php' => '07542708b10fe2eefafeaf2956ff58aa', './modules/Notes/NoteSoap.php' => 'f6dcc32555dcd7fd515b6624667a3702', - './modules/Notes/Note.php' => '129747904433b4e670d708c810c118bc', + './modules/Notes/Note.php' => 'ab0bebee88bdb4436cc3617c41a4e8e2', './modules/Notes/Menu.php' => '9048d5be4a279901fb6e7b6120b58af9', './modules/MySettings/language/en_us.lang.php' => '562f4a6065b8ae50ee724823f5738043', './modules/MySettings/TabController.php' => 'addcc612e2526020690c888df738dd5d', './modules/MySettings/StoreQuery.php' => '705d71936244a25ea8343d71883fda0b', - './modules/MySettings/LoadTabSubpanels.php' => '39a5244484198d37e9bd593d45344706', + './modules/MySettings/LoadTabSubpanels.php' => 'dcc468e435a111788f392d49bbfec887', './modules/ModuleBuilder/views/view.wizard.php' => 'daf80d56024091c60f7e444d44f27b00', './modules/ModuleBuilder/views/view.tree.php' => 'b10035efb0b45ec6f31bf45a50374c3d', './modules/ModuleBuilder/views/view.searchview.php' => '5751152ec654ca27b117159c96ecedbf', @@ -1752,47 +1779,47 @@ $md5_string = array ( './modules/ModuleBuilder/views/view.relationships.php' => '21ab0b1de8f5c2ed1a390e922bc39af6', './modules/ModuleBuilder/views/view.relationship.php' => 'a7212851e32d946cb202def8622f7a64', './modules/ModuleBuilder/views/view.property.php' => 'ada60407ef07a2779f954f9b7837f591', - './modules/ModuleBuilder/views/view.popupview.php' => '3acdfeeaa6ec776168cea15cb46425a2', + './modules/ModuleBuilder/views/view.popupview.php' => '8234734ba79708b63fb0fb1bc74676f7', './modules/ModuleBuilder/views/view.package.php' => '94886f989c71b501e16733aa6f635ab7', './modules/ModuleBuilder/views/view.modulelabels.php' => '2e1ffb46d80e3b98bd8c79cbf367cda4', - './modules/ModuleBuilder/views/view.modulefields.php' => '13771ba7d654c9e7ad9c38e85235a562', - './modules/ModuleBuilder/views/view.modulefield.php' => '906ec198e407249c16fe086ac02a96d1', + './modules/ModuleBuilder/views/view.modulefields.php' => '21576cf88869eaeb463e35ef078c58ef', + './modules/ModuleBuilder/views/view.modulefield.php' => '0a4a757b79768b73e37fe6ff353d9d99', './modules/ModuleBuilder/views/view.module.php' => 'e87f77f4bb936006ad94103cd0f1c453', - './modules/ModuleBuilder/views/view.main.php' => '88123a5ca806fadac53f609b09959e25', - './modules/ModuleBuilder/views/view.listview.php' => '0d70872f0ffe52ed395017e5bf059214', + './modules/ModuleBuilder/views/view.main.php' => '4dc14264211be02eed4a77b0f226fb9e', + './modules/ModuleBuilder/views/view.listview.php' => 'd27ad3148eb4a427b030064ad069eb92', './modules/ModuleBuilder/views/view.layoutview.php' => '53ad225344c66683791aa20d3550c9eb', - './modules/ModuleBuilder/views/view.labels.php' => 'e528ce648ca02258f6aa71be1e3f1337', + './modules/ModuleBuilder/views/view.labels.php' => '554a7291a1ec6e56608fb2197b4b5b8b', './modules/ModuleBuilder/views/view.home.php' => '37dd89b67de55a72b8426b9bd440c3c7', './modules/ModuleBuilder/views/view.history.php' => '4acec9d2c0348a65ab937e98569d5f41', './modules/ModuleBuilder/views/view.exportcustomizations.php' => 'd3549b1d669a65d83e56bfaa2ba36b40', './modules/ModuleBuilder/views/view.dropdowns.php' => '03af97d6859d8c55c022c73a28a0d245', - './modules/ModuleBuilder/views/view.dropdown.php' => '4c8666bc0c4890d26d8d09cc1d4bdb7d', + './modules/ModuleBuilder/views/view.dropdown.php' => 'ed0403e40a35e1fc545e6776edbc4018', './modules/ModuleBuilder/views/view.displaydeployresult.php' => '5ff19a90f22526f716b3d04786866df3', './modules/ModuleBuilder/views/view.displaydeploy.php' => '8332a24883139fea55d72d31946f06ff', './modules/ModuleBuilder/views/view.deletepackage.php' => 'b7f1f95e796e255ed58da1721d6366ff', './modules/ModuleBuilder/views/view.deletemodule.php' => '84319596f5efed276de970b67f9fcafc', - './modules/ModuleBuilder/views/view.dashlet.php' => 'f1fb8f8adf0796283bc83899a4d19a75', + './modules/ModuleBuilder/views/view.dashlet.php' => 'f6b96798892ab150c3e131001b3488d4', './modules/ModuleBuilder/tpls/wizard.tpl' => '79c92f3359236d7f573d50984efaeeec', './modules/ModuleBuilder/tpls/tabBG.png' => '8e2561b0bba66f327d602e6c5f06aa08', './modules/ModuleBuilder/tpls/studioRelationships.tpl' => '239057e161d861f22fc5147a7234bdbb', './modules/ModuleBuilder/tpls/studioRelationship.tpl' => 'fae1108003263300d4442ee5c8b30ef6', './modules/ModuleBuilder/tpls/resetModule.tpl' => '61597ccd042c1e6ff988fc904e6519ed', './modules/ModuleBuilder/tpls/main.tpl' => '8862d14b4c6989a99013640a9a1f4c02', - './modules/ModuleBuilder/tpls/listView.tpl' => '7ca848e3ae581e3c293883dbec267751', + './modules/ModuleBuilder/tpls/listView.tpl' => '09c1dadffff890544d763bfcd0243465', './modules/ModuleBuilder/tpls/layoutView.tpl' => '7f4500a6dcc10110b1d79dca9255ca1b', - './modules/ModuleBuilder/tpls/labels.tpl' => 'd5108823a1248fbf1e52c770f00e332e', - './modules/ModuleBuilder/tpls/index.tpl' => '74b88786aaa5254e0ef3ef98ec2a727d', + './modules/ModuleBuilder/tpls/labels.tpl' => '61817dbfb8f5e2f55b1d1f32d0fd1e4f', + './modules/ModuleBuilder/tpls/index.tpl' => 'f8702ebe45250bb9e72e534e63294b07', './modules/ModuleBuilder/tpls/includes.tpl' => '308f7703d505391d03d58b592c919152', './modules/ModuleBuilder/tpls/history.tpl' => '39442d3ac52f747e0b6773e7e6dc72f3', './modules/ModuleBuilder/tpls/exportcustomizations.tpl' => '2dde77f71b619c7843dfdc4170f93c91', './modules/ModuleBuilder/tpls/editProperty.tpl' => 'af1bbf8eadaecd07967e0e3814d6138d', './modules/ModuleBuilder/tpls/assistantJavascript.tpl' => '62a402e5a5b27917742ab3ad4145a5f8', './modules/ModuleBuilder/tpls/Preview/listView.tpl' => '3add2c0f2cc966e8dc0f1df4db386915', - './modules/ModuleBuilder/tpls/Preview/layoutView.tpl' => '139a8b098b3969bfb0dbe1627dce2387', + './modules/ModuleBuilder/tpls/Preview/layoutView.tpl' => '9090119ad46afd4059eb6651c72bd1c6', './modules/ModuleBuilder/tpls/MBPackage/package.tpl' => '8120ba086c0bbcef57ba8cc7cddfc04b', './modules/ModuleBuilder/tpls/MBPackage/deploy.tpl' => '9eccccb573300b4ec9df407b0b6e9b1e', './modules/ModuleBuilder/tpls/MBPackage/appLanguage.tpl' => 'd41d8cd98f00b204e9800998ecf8427e', - './modules/ModuleBuilder/tpls/MBModule/vardef.tpl' => 'e5d057a3dbf6edc0af53e06e2a31c539', + './modules/ModuleBuilder/tpls/MBModule/vardef.tpl' => '4fb0d7f26958d8732c0aa28f09071a26', './modules/ModuleBuilder/tpls/MBModule/module.tpl' => 'e2506192f904d190bb4f5239e4a00b28', './modules/ModuleBuilder/tpls/MBModule/main.tpl' => 'd41d8cd98f00b204e9800998ecf8427e', './modules/ModuleBuilder/tpls/MBModule/language.tpl' => '2f33bb024e8b1c83a986c32400846192', @@ -1808,7 +1835,7 @@ $md5_string = array ( './modules/ModuleBuilder/tpls/MBModule/Class.tpl' => '8c8f94e1ca2d39dcc903d4c7c566a4bb', './modules/ModuleBuilder/tpls/MB.css' => '1c5449cdd8167137f9b0bcde4f595822', './modules/ModuleBuilder/tpls/ListEditor.css' => 'b60cccd225a86e6b7b48aa3d547b58dc', - './modules/ModuleBuilder/tpls/LayoutEditor.css' => 'e732c3d8df29cc2833514ed5db878684', + './modules/ModuleBuilder/tpls/LayoutEditor.css' => 'ef1c9fed0b1d1146247dac2916a3f771', './modules/ModuleBuilder/parsers/views/UndeployedSubpanelImplementation.php' => 'c1f61c27c48ed83a04231cacf2cbadfd', './modules/ModuleBuilder/parsers/views/UndeployedMetaDataImplementation.php' => '87c39c5818423ac119f20c9f44b11de8', './modules/ModuleBuilder/parsers/views/SubpanelMetaDataParser.php' => 'a658fb64f32eae269f0aeec0cc271f22', @@ -1819,60 +1846,60 @@ $md5_string = array ( './modules/ModuleBuilder/parsers/views/ListLayoutMetaDataParser.php' => '83a8d6b075607d7fe9c0bbd0e7273ebf', './modules/ModuleBuilder/parsers/views/HistoryInterface.php' => 'c1583f28fddb4c33c920f92a20e2c935', './modules/ModuleBuilder/parsers/views/History.php' => '05dac0ef2a4568eab65e4bc7e51005f6', - './modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php' => 'e1a231ac6e1ab2c138f0c9905b11c16a', + './modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php' => '6535513b80b93a5e68aba1d160d5dbe9', './modules/ModuleBuilder/parsers/views/DeployedSubpanelImplementation.php' => '24a957dc22e693e21dd18541e3584807', './modules/ModuleBuilder/parsers/views/DeployedMetaDataImplementation.php' => 'f038a0d67cfb341d627e5a1c9e8607c3', './modules/ModuleBuilder/parsers/views/DashletMetaDataParser.php' => '8fca44b08dc035a1d23463b26344df72', './modules/ModuleBuilder/parsers/views/AbstractMetaDataParser.php' => '720c63061f2e8be613423dd9a706dfbd', './modules/ModuleBuilder/parsers/views/AbstractMetaDataImplementation.php' => '96163c88a133c445b47980379e569b4d', - './modules/ModuleBuilder/parsers/relationships/UndeployedRelationships.php' => '7852fd0eb836f9641e190260e13c7201', + './modules/ModuleBuilder/parsers/relationships/UndeployedRelationships.php' => '1cd3096126ec4b8e4ea3a4cd83c474bb', './modules/ModuleBuilder/parsers/relationships/RelationshipsInterface.php' => '5673bbca1c4d58866069201f7276f957', './modules/ModuleBuilder/parsers/relationships/RelationshipFactory.php' => '60921654dbc6f3dbbb44076036285e04', - './modules/ModuleBuilder/parsers/relationships/OneToOneRelationship.php' => '57923bba0dac5e284c4f5398041349a8', - './modules/ModuleBuilder/parsers/relationships/OneToManyRelationship.php' => 'c1cd210bfe23b4458a4a5584dd363860', - './modules/ModuleBuilder/parsers/relationships/ManyToOneRelationship.php' => '7e1ada555d2dc725e4ce9ec4f6f6ae62', - './modules/ModuleBuilder/parsers/relationships/ManyToManyRelationship.php' => 'e6c965fda838b822992cf59433fce6e2', - './modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' => 'b6a10c0d7f07a62b99671d98a8d37644', + './modules/ModuleBuilder/parsers/relationships/OneToOneRelationship.php' => '006cc4db77a360eb4b33cf0d5ce15183', + './modules/ModuleBuilder/parsers/relationships/OneToManyRelationship.php' => 'f5822912b0e1cd0897e71d09efe740b9', + './modules/ModuleBuilder/parsers/relationships/ManyToOneRelationship.php' => 'c39fa6d10c8dca5bac31e8c19243c0f3', + './modules/ModuleBuilder/parsers/relationships/ManyToManyRelationship.php' => 'be95f07defab5a0cc9b4a7ed7a17d74f', + './modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' => '9ed7e84ee37eb5f29782aab5c58e8aca', './modules/ModuleBuilder/parsers/relationships/ActivitiesRelationship.php' => 'e54641d4126d374f494a6f7f76c2176b', - './modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php' => 'ba07848ec2625ba93c007bdd16d7f69b', - './modules/ModuleBuilder/parsers/relationships/AbstractRelationship.php' => '262e161681a68ca60608289573ea187f', + './modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php' => '136c576c10bdf9964e51fd9164e60736', + './modules/ModuleBuilder/parsers/relationships/AbstractRelationship.php' => 'de723bb3cc183d2377c1966cb864ca09', './modules/ModuleBuilder/parsers/parser.modifysubpanel.php' => 'b26c368fe0ded3b67f1d83f33795454b', './modules/ModuleBuilder/parsers/parser.modifylistview.php' => 'cb76fbefd131ce1e5d71c19d565df204', './modules/ModuleBuilder/parsers/parser.modifylayoutview.php' => 'd5383c342e65fcde7a628c339d0d6502', - './modules/ModuleBuilder/parsers/parser.label.php' => '3bf2f01463c74099bdf9eb66f2cafa52', + './modules/ModuleBuilder/parsers/parser.label.php' => '963402aa275964032d0095fbc82065df', './modules/ModuleBuilder/parsers/parser.dropdown.php' => 'b8daa4da875806fb37456c17c4d42840', './modules/ModuleBuilder/parsers/constants.php' => '0d876db28d336cabe3c44a06b8a8f780', './modules/ModuleBuilder/parsers/StandardField.php' => 'de8b8168336744386faa4fcd8eb3a8fa', './modules/ModuleBuilder/parsers/ParserFactory.php' => 'f0fad2af770157777e4088e174233de0', './modules/ModuleBuilder/parsers/ModuleBuilderParser.php' => 'ddd1051f921589202f29110c732e60c9', - './modules/ModuleBuilder/language/en_us.lang.php' => 'dee13af8e6772d0c43b365011230f434', + './modules/ModuleBuilder/language/en_us.lang.php' => '886ba107b59f3450d5d81bffcd55eaa8', './modules/ModuleBuilder/javascript/wizardTemplate.js' => 'df71a4a5eaf77a126a7eaef07287c511', './modules/ModuleBuilder/javascript/studiotabgroups.js' => 'ea1fb38daeb99b01ba07c9904e2b4f2c', - './modules/ModuleBuilder/javascript/studio2RowDD.js' => 'e29e6fc44695cbd29d8d88eef513f6f1', - './modules/ModuleBuilder/javascript/studio2PanelDD.js' => '4fda42cbfe44390b3a9f646fce1604ad', - './modules/ModuleBuilder/javascript/studio2ListDD.js' => '36cb4715391ded751fd2f30ab41b76e5', - './modules/ModuleBuilder/javascript/studio2FieldDD.js' => 'd776d412e631abf40c5b9227989669a7', - './modules/ModuleBuilder/javascript/studio2.js' => 'a3d19505c924a863ab7656b50d9bb466', - './modules/ModuleBuilder/javascript/SimpleList.js' => '2e347d21f35b115b36469b3cda00d930', - './modules/ModuleBuilder/javascript/ModuleBuilder.js' => 'e877187d8e2151829c8cd90eca514532', + './modules/ModuleBuilder/javascript/studio2RowDD.js' => 'e72f8ac51ff0f4c5896a13cb04714871', + './modules/ModuleBuilder/javascript/studio2PanelDD.js' => 'a8d42da9d4a542f0a6499f74a822a63a', + './modules/ModuleBuilder/javascript/studio2ListDD.js' => '64b2484158a737a736096da06d12946d', + './modules/ModuleBuilder/javascript/studio2FieldDD.js' => '9aefd0fb1b42a3f1c42eff166bf0020b', + './modules/ModuleBuilder/javascript/studio2.js' => '2e2e4f621c0abf10d9f1bdbaf719da03', + './modules/ModuleBuilder/javascript/SimpleList.js' => '2ad0e64a2f93f73583edc63092a6ed6a', + './modules/ModuleBuilder/javascript/ModuleBuilder.js' => 'f8ee21995b416e7da7e4482e8a769d14', './modules/ModuleBuilder/javascript/JSTransaction.js' => '2f20a4a72eaa8cbdf3053e24c5772ee5', - './modules/ModuleBuilder/controller.php' => '3d65649fd77c526aa12146387a955fa5', + './modules/ModuleBuilder/controller.php' => '18fb139fdac014da1e5f4ca97bff8af9', './modules/ModuleBuilder/action_view_map.php' => 'fd1e0b87f5d325f06b2b743afa057999', './modules/ModuleBuilder/Module/StudioTree.php' => 'e29fed9b1f81766bda975d938eecd3ec', './modules/ModuleBuilder/Module/StudioModuleFactory.php' => '5860a0e60d39a69303a39df4ea188336', - './modules/ModuleBuilder/Module/StudioModule.php' => '2874e799f025ab3afcc40c5a0f15ea69', + './modules/ModuleBuilder/Module/StudioModule.php' => '54f838b9f6708e30570151a23bd71a85', './modules/ModuleBuilder/Module/StudioBrowser.php' => '6da2f872826086caad4759599f0f3203', './modules/ModuleBuilder/Module/MainTree.php' => '43824a340ebbce175fac3b60b7641efb', './modules/ModuleBuilder/Module/DropDownTree.php' => 'ab1f94e57c7ec0f1f2b0a37fa158eab5', './modules/ModuleBuilder/Module/DropDownBrowser.php' => '7cd759094f2018b86eb030b2f6286516', './modules/ModuleBuilder/MB/header.php' => 'a24068f5c6bb44f9b000ecfac9dbd21c', './modules/ModuleBuilder/MB/ModuleBuilder.php' => '39bdea636bbf913d8ade851a4a070939', - './modules/ModuleBuilder/MB/MBVardefs.php' => 'ee248dce677f0d9c85ae5f98e9bfb0e6', + './modules/ModuleBuilder/MB/MBVardefs.php' => '1e744844bed69db57d63060f6e9bf6de', './modules/ModuleBuilder/MB/MBRelationship.php' => 'bc5653efb1243f8c7f37ab28a6c1cfa0', './modules/ModuleBuilder/MB/MBPackageTree.php' => '4f7961d0ec0fb7aeb5fed050d88af8a3', './modules/ModuleBuilder/MB/MBPackage.php' => '31926b307f13743bde453ad07d702a36', './modules/ModuleBuilder/MB/MBModule.php' => '9da7ac59238d8a59e5f8dca2dea4a10c', - './modules/ModuleBuilder/MB/MBLanguage.php' => 'f3fd6415b7a1c5cd56187ad8ed5fd813', + './modules/ModuleBuilder/MB/MBLanguage.php' => 'c8b9378b6440643afdc322081db4c11a', './modules/ModuleBuilder/MB/MBField.php' => '2e3561d71f00c42e88f323c0fff72a4b', './modules/ModuleBuilder/MB/AjaxCompose.php' => 'ca3deaa4d15341b882af6cc33f6cc962', './modules/ModuleBuilder/Forms.php' => '2a94c4a8f697121796f53413911131f6', @@ -1892,16 +1919,16 @@ $md5_string = array ( './modules/MergeRecords/MergeRecord.php' => '0ed1f373514d78b619f6698a55edb950', './modules/MergeRecords/MergeField.html' => 'a13ad4e3f3ab1e65050987e622859f30', './modules/MergeRecords/Menu.php' => '281930dcf94a918eb64f8435ad77f248', - './modules/Meetings/jsclass_scheduler.js' => 'f793692ff2ac0242ad9e15833cfe2bf1', + './modules/Meetings/jsclass_scheduler.js' => 'eaf57fa0fe7e7b1ebb03b19ab00f260b', './modules/Meetings/action_view_map.php' => 'c175716cf3541179db17bc6b8c2723f0', './modules/Meetings/JoinExternalMeeting.php' => '8da73502e2d825ec2b10ede8ccf6ba61', './modules/Meetings/views/view.listbytype.php' => '1edb3e6eaf3e66aac1101d02b946e9c7', './modules/Meetings/views/view.edit.php' => '48fdb56b365e914a085aaaed7e9bf4d1', - './modules/Meetings/vardefs.php' => '207b75a5ef4fe44cfd92afccf0fbf012', + './modules/Meetings/vardefs.php' => 'bc205545cce2ceec3c676588776f2944', './modules/Meetings/tpls/extMeetingNotInvited.tpl' => '5d05c208909ebfb8b425c4a9a57265bd', './modules/Meetings/tpls/extMeetingNoStart.tpl' => '01740b23224ca1e36be97c81091acc53', './modules/Meetings/tpls/header.tpl' => 'e443fd4d94fddde4cab75fc0ca33c863', - './modules/Meetings/tpls/footer.tpl' => '5edbcf516cddb74838b0460a438f21ad', + './modules/Meetings/tpls/footer.tpl' => 'aba353d53e50a693a0254e285d845408', './modules/Meetings/tpls/QuickCreate.tpl' => 'ef16b5ef915fdd888cc0d0a7691f6516', './modules/Meetings/metadata/subpanels/default.php' => '10c878084547f96b0e487de6cb969409', './modules/Meetings/metadata/subpanels/ForHistory.php' => 'bd0675998ba7a3a95268fa5233fe1121', @@ -1909,25 +1936,25 @@ $md5_string = array ( './modules/Meetings/metadata/subpaneldefs.php' => '0c0c904e87130730c0757e495ecf2ea8', './modules/Meetings/metadata/studio.php' => '9597aef6f1a776f39e0515231425a883', './modules/Meetings/metadata/searchdefs.php' => '2bc913f3f67b7fa29cdab7e2623de325', - './modules/Meetings/metadata/quickcreatedefs.php' => 'a88880e2e8f010ce030a947aaa33db30', + './modules/Meetings/metadata/quickcreatedefs.php' => 'c41c1cd9dddb36277389dba8327b869a', './modules/Meetings/metadata/listviewdefs.php' => '5973b2f25ca38dba5645037276ee0b9d', - './modules/Meetings/metadata/editviewdefs.php' => 'c98e887159e7939a1d0b1cef28be6d5c', + './modules/Meetings/metadata/editviewdefs.php' => 'fe280045a7c13e902b91bc3c6a6310fd', './modules/Meetings/metadata/detailviewdefs.php' => '7b516d8760f5116e112601c34b6a0e66', './modules/Meetings/metadata/additionalDetails.php' => 'b2b466a61eef5f8369d9587631399b3c', './modules/Meetings/metadata/SearchFields.php' => '8fb6299f50de078c3578938a29e6fc57', - './modules/Meetings/language/en_us.lang.php' => '2e54dc3f289d61bc606cc4aa9cf1e36b', + './modules/Meetings/language/en_us.lang.php' => 'd74af82d72be6498a1d355a034a53b2b', './modules/Meetings/field_arrays.php' => '9303db9870fe343e840dc20d3697f855', './modules/Meetings/SubPanelViewInvitees.php' => 'eb9e848e7686ab8ef26c07fee3c8a269', './modules/Meetings/SubPanelViewInvitees.html' => 'f3f1c069759034d89adefd17350a31ed', './modules/Meetings/Save.php' => '5e6ee92cd4d33c083492e54940b58264', - './modules/Meetings/Menu.php' => 'c02aa7c2c0f7c80a3cd7ead56ca1fcfc', + './modules/Meetings/Menu.php' => '20e69d57b747825c30e86987d72efb0b', './modules/Meetings/MeetingsQuickCreate.php' => '818e55e261c5e74cb385f835311944fa', - './modules/Meetings/MeetingFormBase.php' => '3d15b0c970848917b794542f6b460aa6', - './modules/Meetings/Meeting.php' => '53270f7076564017c865297e5115dad2', - './modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.php' => '861481e9fe5ea67f24bd104ae8e822ab', + './modules/Meetings/MeetingFormBase.php' => 'b61408cf610f01009b415060e2ba6ada', + './modules/Meetings/Meeting.php' => '1707f2fecd90df66f7eda626525da7d8', + './modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.php' => 'e2d3d7d2d6d3c590953d86f3013ed59b', './modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.meta.php' => 'e47f5ffe63b5a0fa7d7de49e41602428', './modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.data.php' => '93411ffd890d557e5f97ed68b946f097', - './modules/MailMerge/controller.php' => '43d7cc4578e201dce6e48f4c141daa44', + './modules/MailMerge/controller.php' => 'af3ccde23576298a6a260c9737d55d78', './modules/MailMerge/modules_array.php' => 'af9991bc9b3ff44c85e1b3f7b58999b0', './modules/MailMerge/language/en_us.lang.php' => '3b63d532d3c99f4a1335cd336b7601d6', './modules/MailMerge/index.php' => '542fef22e74fefe27f02a3ec1e6cc943', @@ -1939,7 +1966,7 @@ $md5_string = array ( './modules/MailMerge/Step3.php' => 'bfbc79b0927f0b615963d1118b96ddba', './modules/MailMerge/Step3.html' => '24d26c3c8eb46ded0f2adad4da479fea', './modules/MailMerge/Step2.php' => '6eff88823954aa10701d0c8526005868', - './modules/MailMerge/Step2.html' => '4b02f6f18a865859cf88b18f1fb26f95', + './modules/MailMerge/Step2.html' => 'beb384968e43317d1a36f88da3c6ee88', './modules/MailMerge/Step1.php' => '2917edb58f1a61d7ab3574cc1d5547b7', './modules/MailMerge/Step1.html' => 'e47775cad8089fafc1ff8102632c9ab8', './modules/MailMerge/Save.php' => '6d3ccf9c3fc315c2001314975d9718fb', @@ -1951,18 +1978,18 @@ $md5_string = array ( './modules/MailMerge/DetailView.php' => '9657298f898e97dbc221c34f861a0f98', './modules/Leads/Lead.js' => '63dad96eb6c7c57fbb34dda409f790ce', './modules/Leads/views/view.list.php' => 'd716f0c0d6e4bb6118c811c0bbcd903c', - './modules/Leads/views/view.convertlead.php' => '340713b44be49275c5803163de08dc92', - './modules/Leads/vardefs.php' => '79fdb92ebbb0eb7af9e33019fcf8678f', + './modules/Leads/views/view.convertlead.php' => '94ba8d4d5c2950100b36dba017095195', + './modules/Leads/vardefs.php' => '7ee82ca743d437a322cc1dc3bb40b0ea', './modules/Leads/tpls/QuickCreate.tpl' => 'f68b199a7a4b23111fa98042b0670859', './modules/Leads/tpls/DetailViewHeader.tpl' => 'ff0301b5f7beef3671e1174a249048ba', - './modules/Leads/tpls/ConvertLeadHeader.tpl' => 'c85ad2735645cd40842d5b77a26ad997', - './modules/Leads/tpls/ConvertLeadFooter.tpl' => '6af977d010658f42fcbe03615220d3be', - './modules/Leads/tpls/ConvertLead.tpl' => '869e2a491d61cf9e29e21e04002245a4', + './modules/Leads/tpls/ConvertLeadHeader.tpl' => '61fc0715b9ebf43c569e137e1d4270ee', + './modules/Leads/tpls/ConvertLeadFooter.tpl' => 'c61ad4ca2bcae0bb13202c378d295b9c', + './modules/Leads/tpls/ConvertLead.tpl' => 'fe03fd52fd77c0351cff32c17c77838b', './modules/Leads/metadata/subpanels/default.php' => 'd10b56acc074aefcad6ee5fb27eb436d', './modules/Leads/metadata/subpanels/ForMeetings.php' => '7c73f4dc11531df7da6e6df7cbc24b20', './modules/Leads/metadata/subpanels/ForEmails.php' => '1b38f45c8243ce013ee7b03560d4a3b6', './modules/Leads/metadata/subpanels/ForCalls.php' => 'abef7632a7aeb97700496f355db466af', - './modules/Leads/metadata/subpaneldefs.php' => '57579fbebfb39ceb6747b11cb477df3d', + './modules/Leads/metadata/subpaneldefs.php' => '9a3610ab03eb95d0da0fdec0d1657d9c', './modules/Leads/metadata/studio.php' => '043ccc5842c87b4b842903076b2828ee', './modules/Leads/metadata/searchdefs.php' => '103018fd4a079a5030b9c26138d41e9d', './modules/Leads/metadata/quickcreatedefs.php' => 'df9000c66248ec1fc8e70669c3e3cd18', @@ -1973,7 +2000,7 @@ $md5_string = array ( './modules/Leads/metadata/convertdefs.php' => '39e039d6cac50434b4672c21abd6d2c0', './modules/Leads/metadata/additionalDetails.php' => '8f933991ab86127ea4bce9ed1218f939', './modules/Leads/metadata/SearchFields.php' => 'ca3bf623903e74e23acd6ae5fb513952', - './modules/Leads/language/en_us.lang.php' => '23dcb653394a581b2b43ae9d3b273591', + './modules/Leads/language/en_us.lang.php' => 'd38e3ff4475d0dad923d6e61cb27585f', './modules/Leads/field_arrays.php' => '135b59040b104dad63a0a595f5d8fc39', './modules/Leads/controller.php' => '4f230a75d02961b11b316c3f2acb5d1d', './modules/Leads/action_view_map.php' => 'f19d9f4f278403b0ea1af3fcf0cb9087', @@ -1987,7 +2014,7 @@ $md5_string = array ( './modules/Leads/Menu.php' => '80008b8d1fbe777e77848179b9b3dea0', './modules/Leads/LeadsQuickCreate.php' => '2483d2f18680dba279b25a833f720758', './modules/Leads/LeadFormBase.php' => 'ecf99a2c2298b71aec2c7d0ae674f650', - './modules/Leads/Lead.php' => '35ad479b2aabdf8596be04c1f23cb9e1', + './modules/Leads/Lead.php' => '23d65676c6363f07092a9ba59c6f06ea', './modules/Leads/Dashlets/MyLeadsDashlet/MyLeadsDashlet.php' => '06ad52c30e91928daa3f149de30465db', './modules/Leads/Dashlets/MyLeadsDashlet/MyLeadsDashlet.meta.php' => '9349a94a67dea2c068a21fd2b086b5b3', './modules/Leads/Dashlets/MyLeadsDashlet/MyLeadsDashlet.data.php' => '1cfb3f6dd5bf769340e0de0849b35976', @@ -1999,7 +2026,7 @@ $md5_string = array ( './modules/LabelEditor/Forms.php' => 'f7df0073958376f96b903e32125b7747', './modules/LabelEditor/EditView.php' => '327786b586c72cad50de7ca19361b2d7', './modules/LabelEditor/EditView.html' => '5c869e234bee20cc12984742cdea69c3', - './modules/InboundEmail/InboundEmail.js' => '529ec88f22944d28f4d31a011ccc0c23', + './modules/InboundEmail/InboundEmail.js' => '7c0bd299459d2db899895795d9ead2ac', './modules/InboundEmail/vardefs.php' => 'f7aa1b4be9efb3918e9565b85f8ee55c', './modules/InboundEmail/language/en_us.lang.php' => '39b2d83673f787eb77be842dd8d972b4', './modules/InboundEmail/index.php' => '1aa418a33d81f3df849d7d7234438c2a', @@ -2007,7 +2034,7 @@ $md5_string = array ( './modules/InboundEmail/View.html' => '42dfabb40c585bf030af5885704ba056', './modules/InboundEmail/ShowInboundFoldersList.php' => '69b5eb763ad3b4f91521154145cb6263', './modules/InboundEmail/SaveGroupFolder.php' => '79ade7dd1656dbf901e3c9446071f551', - './modules/InboundEmail/Save.php' => 'dd756ec257f50da70ff0411838505a0a', + './modules/InboundEmail/Save.php' => '67fc7b6fe5012c47726dc53052cebe4e', './modules/InboundEmail/Popup.php' => '0ab7027604a853fe6e667dd700f3fecf', './modules/InboundEmail/Menu.php' => 'd60b77ea799c7d18339e37ad916aafd2', './modules/InboundEmail/ListView.php' => 'c610da376126d3bb44f7dc780a6d13d7', @@ -2020,52 +2047,69 @@ $md5_string = array ( './modules/InboundEmail/DetailView.php' => 'f838087f2c73b83a2deee755475be859', './modules/InboundEmail/DetailView.html' => '2ac5191bfc333ddebc83f769a73c744f', './modules/InboundEmail/Delete.php' => '682ed772ec388482dbe7a599e9e56104', - './modules/Import/ImportMapTab.php' => 'd179a9e67a3bbc6e8b408efd2e37252a', - './modules/Import/views/view.undo.php' => 'f3eed66ae73427bab843bc3c4d429db0', - './modules/Import/views/view.step4.php' => '0650392af3b9d53e09eb8496afaf6f02', - './modules/Import/views/view.step3.php' => '37847270b3445e2254096b3e4c9385fb', - './modules/Import/views/view.step2.php' => '1836dd43ff036bf2396110df4a50eac2', - './modules/Import/views/view.step1.php' => '5b07a3d7fa23553973e1ad802b04b667', - './modules/Import/views/view.last.php' => 'a1c30d3cf0c21343cc03c856a8d2911a', + './modules/Import/views/view.extdupcheck.php' => 'ef219a2512d7a56af80c76eec96e20fa', + './modules/Import/views/view.dupcheck.php' => '5fa4c8d17dfd4e93938b86710538e158', + './modules/Import/views/view.confirm.php' => 'afa849ff09f2d32fe752fa275ab34cd8', + './modules/Import/views/ImportView.php' => '6353f4db2577b47c4be5c6c3aa286951', + './modules/Import/views/ImportListView.php' => 'a32043e7ebcfbc532c975e878a869ab8', + './modules/Import/views/view.undo.php' => '34ee9098f2dbb3783d2c799d258181ee', + './modules/Import/views/view.step4.php' => 'b2122f1b864b581d5fe48e0da0ccc8a4', + './modules/Import/views/view.step3.php' => '7362a233ede48e9adc042525e6a73737', + './modules/Import/views/view.step2.php' => '4412435bc97fe7a7373927248237e18b', + './modules/Import/views/view.step1.php' => '57ba106f7993d733e810349c0fe98c49', + './modules/Import/views/view.last.php' => '213cd3cf58ebbdec3191bfc8a11a2b52', './modules/Import/views/view.error.php' => '4a9ef123c90511298bac72b55405f2f1', './modules/Import/vardefs.php' => 'f091139c8e775f0208605ed6a832463b', - './modules/Import/tpls/undo.tpl' => '65cd1d29e39dc8487d9e558623461843', - './modules/Import/tpls/step3.tpl' => 'f776acfe9d35a87237985bb1be16d292', - './modules/Import/tpls/step2.tpl' => 'f7db6057913e3fcd8405e53677d16430', - './modules/Import/tpls/step1.tpl' => '1622b96b8e16ac85faad02e9f638aa1a', - './modules/Import/tpls/last.tpl' => '84bb779c391262ad2fbb41a38e50cbd6', - './modules/Import/tpls/error.tpl' => '8bfbddd3c2424d4a1b3670bd79c88e16', - './modules/Import/language/en_us.lang.php' => '2e3bb401c11dc3f8cdc5a571c1f17ec1', - './modules/Import/ImportMapSalesforce.php' => 'd87705fc0ed0797d73ee77c9d1d985cf', + './modules/Import/tpls/wizardWrapper.tpl' => '94070dd9dac0fe1517801e3752147bfd', + './modules/Import/tpls/listviewpaginator.tpl' => '25bfd42725efe26095baeab56c8b6602', + './modules/Import/tpls/listview.tpl' => 'cebe4901ea1347fe9bddb2ff06a575a6', + './modules/Import/tpls/dupcheck.tpl' => 'b2d4168bc7bdee6c7c43d1ebf0a3f781', + './modules/Import/tpls/confirm_table.tpl' => '6012db9ad8184206fba3840a43018f41', + './modules/Import/tpls/confirm.tpl' => 'f536633e92c2061adb5013ff098de472', + './modules/Import/tpls/undo.tpl' => 'f5da3928952e280ef676d0a636f2a00c', + './modules/Import/tpls/step3.tpl' => 'e6ac3444b8ea69b0c774678e251fb8d4', + './modules/Import/tpls/step2.tpl' => 'ada240b8cca49837c44b4fe0a48608c9', + './modules/Import/tpls/step1.tpl' => '109257a262787a66f6c8281a0bc3dedd', + './modules/Import/tpls/last.tpl' => '3a18785f149fbbccb2210d431bcbd9c3', + './modules/Import/tpls/error.tpl' => '94a7160a75fc6218278f5458e1267c4c', + './modules/Import/language/en_us.lang.php' => 'b7e543653dbe0a02a4f63ad257c8515c', './modules/Import/Menu.php' => '923e16d2066f8577f847d2db148cd7ab', - './modules/Import/ImportMapOutlook.php' => 'e6887afa92b5d94670fb926edef4c052', - './modules/Import/ImportMapOther.php' => 'bd5d670a97dc6fe345b4b13b276850e2', - './modules/Import/ImportMapCsv.php' => 'b20f78374b2b5eb218a822627663502a', - './modules/Import/ImportMapAct.php' => 'bef724cdef346231a6063ae4b4578f83', - './modules/Import/ImportMap.php' => '18681e9eb3f1b34ce7b2ec9b6af1f89e', - './modules/Import/controller.php' => 'ce46636408b245c321012387da2a1882', - './modules/Import/UsersLastImport.php' => '2dae79ebe11ad6e559407bc79e47b8a2', + './modules/Import/sources/ImportFile.php' => '5d16aeee6b91768bfd6b060fe30f59dc', + './modules/Import/sources/ImportDataSource.php' => 'bee00883801c9b876a14b6ea82e39199', + './modules/Import/sources/ExternalSourceEAPMAdapter.php' => 'f0f83caf245343c4a1377f9fa0cbf0ae', + './modules/Import/maps/ImportMapTab.php' => '2de9c8d6255fd9fa3a1268d25f3adc2c', + './modules/Import/maps/ImportMapSalesforce.php' => 'f2058203aadc621a5fd6747747fd20d0', + './modules/Import/maps/ImportMapOutlook.php' => '2dd59da8f5c91cb30c3077ed591c21da', + './modules/Import/maps/ImportMapOther.php' => 'bd5d670a97dc6fe345b4b13b276850e2', + './modules/Import/maps/ImportMapGoogle.php' => 'a43e70c510a814f658f1e350d702c6a1', + './modules/Import/maps/ImportMapCsv.php' => '8d3042b4a81be766bccd38a80b6eed87', + './modules/Import/maps/ImportMapAct.php' => '737e560a4e5ea0b17dbdcfc3d82ba750', + './modules/Import/maps/ImportMap.php' => '4e7258297c1778b7e64741074545cf3a', + './modules/Import/CsvAutoDetect.php' => '89ffd2ed5e4f7e3b61d51e2805004adb', + './modules/Import/controller.php' => 'd207e93af42767a33a64de6776565d23', + './modules/Import/UsersLastImport.php' => '1f59a593096195b38c2357763cb98963', './modules/Import/ImportFileSplitter.php' => 'f64c6d4e292c45f4d806da5d2300d14f', - './modules/Import/ImportFile.php' => '0cff4a5dbe28838cccdc68d1ef5a0920', - './modules/Import/ImportFieldSanitize.php' => '6113879bb0bce6b0693325a7f0dbc790', - './modules/Import/ImportDuplicateCheck.php' => '5c5903744d183926748fac59ca5a8e90', - './modules/Import/ImportCacheFiles.php' => 'c575f0ecbcbc98bd46ea8a10f6ee6c8a', - './modules/Import/Forms.php' => '5fc35f1ae98fff8224af294bfb562a69', + './modules/Import/Importer.php' => 'c7166d4de7b4d906715c23f548b0e3e9', + './modules/Import/ImportFieldSanitize.php' => 'c23abb76dab9912fddbd16d6fae3ab22', + './modules/Import/ImportDuplicateCheck.php' => '4722b6518e461918ca4e2e5fc098a99f', + './modules/Import/ImportCacheFiles.php' => '99071645e01b89c881173702b5108a15', + './modules/Import/Forms.php' => 'cc037506b85a0440ddd1415f9978ee0f', './modules/Home/about.js' => 'af9365ee4df93485a1e9cb89752d4e85', './modules/Home/action_view_map.php' => '7562b37c19b699d7cd79efaa6ef17205', + './modules/Home/SubpanelEdits.php' => '1adfa8d02c98424459fb35772a190b88', './modules/Home/views/view.additionaldetailsretrieve.php' => '153cfd5b0056493551f0e8a395cfcf8b', './modules/Home/views/view.modulelistmenu.php' => '799bca31c2b99c8be86c3c53712c802a', './modules/Home/views/view.list.php' => 'b1213448edbef90a40061dbdfb6e432c', './modules/Home/sitemap.tpl' => 'a0145732b2b2154506eae54e3b66b851', './modules/Home/sitemap.php' => '85d1da921c719667f1e1be77993101d6', './modules/Home/quicksearchQuery.php' => '7d3cb9dc5943ee286ea33ee90c335227', - './modules/Home/language/en_us.lang.php' => '2940f2ec09ebc0e1405843f0ea58ea5c', + './modules/Home/language/en_us.lang.php' => '52904ad8ca62c4dc91b1eb55ae32c3e7', './modules/Home/dashlets.php' => 'a88f1d512af748e1a4aa34bfdb34f883', - './modules/Home/UnifiedSearchAdvancedResults.tpl' => '65b6695a4b79dff0c7564665ac45355f', + './modules/Home/UnifiedSearchAdvancedResults.tpl' => 'd42129025349ee2e90013328973cad03', './modules/Home/UnifiedSearchAdvancedForm.tpl' => '69e1fc48e68332a049be43ba4d09eec1', - './modules/Home/index.php' => '7fbddb27bee5b65fad61c17b46685203', + './modules/Home/index.php' => 'bd9e3455c871b17b13c7d1a7b34c3af9', './modules/Home/UnifiedSearchAdvanced.tpl' => '4d77c658b82caabfe76d1e9e6aab7249', - './modules/Home/UnifiedSearchAdvanced.php' => '3a19fa7c2e840e04647a631127675f58', + './modules/Home/UnifiedSearchAdvanced.php' => '76a2aa9bb11b1ac95e4cbde2343b4ab5', './modules/Home/TrainingPortal.tpl' => '484626736f0965c1c08cc8448f9f66f6', './modules/Home/TrainingPortal.php' => '5da63a36ba5d912e0792c9e33c237ee3', './modules/Home/UnifiedSearch.php' => '1ff91a6fed46f97f9eafc1bda78f7579', @@ -2073,45 +2117,45 @@ $md5_string = array ( './modules/Home/PopupSugar.php' => 'f518518f3eb867cac97239a499fbe8a0', './modules/Home/Menu.php' => '5e30f2e18e40be505bd8ffa10ef26a62', './modules/Home/LastViewed.php' => 'dd4b5eea00e258ba7e13e71ee9b787cd', - './modules/Home/Home.tpl' => '2950d6ac0e01e3788e39f43cf0f78190', + './modules/Home/Home.tpl' => 'af413326ed7386247f8267357b757bf1', './modules/Home/Home.html' => 'e6427d0908ad7f2cdc736aef2126109a', './modules/Home/DynamicAction.php' => '93d422d2e2c365c2d33a9bc71f5aedc6', - './modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.php' => '059ba3d196ed8e0148297aff12a2b1f7', + './modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.php' => 'f6c462dfdbc5d7ff998270fa9427aa62', './modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.meta.php' => '866726f1a8b2185e4f8e03a658fe0c53', './modules/Home/Dashlets/iFrameDashlet/configure.tpl' => '063ae2ea907b58d07e4b9165845b154d', './modules/Home/Dashlets/SugarNewsDashlet/configure.tpl' => '063ae2ea907b58d07e4b9165845b154d', - './modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.php' => 'baa0f0662944098c3fafaf69650cab13', + './modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.php' => '3dbf96988214f6a7ea5618bfa6405c7f', './modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.meta.php' => 'ae0a91c1f02df6cec2c8f6af8c4ebb7e', - './modules/Home/Dashlets/RSSDashlet/RSSDashletOptions.tpl' => '46903cff19fb802bba513ed53e071d48', + './modules/Home/Dashlets/RSSDashlet/RSSDashletOptions.tpl' => 'a3b3dfd9c92a91ca9ab707a85bb6ac98', './modules/Home/Dashlets/RSSDashlet/RSSDashlet.tpl' => 'd38e6f256b54abc3242e601bb97b84ec', - './modules/Home/Dashlets/RSSDashlet/RSSDashlet.php' => 'c2e445aa2c971da4da408f56499fa214', + './modules/Home/Dashlets/RSSDashlet/RSSDashlet.php' => '7c5bc7969f3bf78640b7084a0bf5366b', './modules/Home/Dashlets/RSSDashlet/RSSDashlet.meta.php' => 'c672276452d6933a03be9006411602a8', './modules/Home/Dashlets/RSSDashlet/RSSDashlet.icon.jpg' => '7b0cb2ec97ce8e71d74d60a0da81ba53', './modules/Home/Dashlets/RSSDashlet/RSSDashlet.en_us.lang.php' => 'f47426bff171e5bf35c16c995002ded0', './modules/Home/Dashlets/JotPadDashlet/JotPadDashletScript.tpl' => '78ff0af17c6befa0f936c7bc76e1361e', './modules/Home/Dashlets/JotPadDashlet/JotPadDashletOptions.tpl' => '72f26375195c45bdf9badd8ccaf90b5f', './modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.tpl' => '6d1d69a3d52f1e9caef4bcc77da5d92f', - './modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.php' => 'a62754815ebd325a4bcc425a1c1c0b39', + './modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.php' => '8327bca94264c1743f7f0c29d43ea12a', './modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.meta.php' => '3a55e5ed102ac43b238ab9549ee45463', './modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.en_us.lang.php' => 'b90b45b8916fd2da50a646cab47c8fad', './modules/Home/Dashlets/InvadersDashlet/sprites/player.png' => 'e5cac3126e8afc4a33374c12651669ab', './modules/Home/Dashlets/InvadersDashlet/sprites/cube.png' => '2e8e87c58816e987578025e21a19c3e7', './modules/Home/Dashlets/InvadersDashlet/sprites/bg.png' => 'cd531b08b65ec6ed046d182122d54b3a', './modules/Home/Dashlets/InvadersDashlet/sprites/alien.png' => '30696cdec3d5ae84a3150d426cea9d12', - './modules/Home/Dashlets/InvadersDashlet/InvadersOptions.tpl' => '230d0ed3bdf71565f91c22b1e1840aaa', + './modules/Home/Dashlets/InvadersDashlet/InvadersOptions.tpl' => '0b08b0a38417f1c721496e1f30ebe572', './modules/Home/Dashlets/InvadersDashlet/InvadersDashletScript.tpl' => '73e8383d783050c0f2f1d24eb2148a55', './modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.tpl' => '6068f9592f19ad295dabbf43aaad60ce', - './modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.php' => '8bda659dbf16b4f6ee49f701fdcbe653', + './modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.php' => 'f20bfb1e80ad3e1137db97e94d86709f', './modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.meta.php' => '2f8aabf8d7bf918f85e4f0eda6a78cf2', './modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.icon.jpg' => '7b0cb2ec97ce8e71d74d60a0da81ba53', './modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.en_us.lang.php' => '8bec7e411443e2296a882a22f7614463', - './modules/Home/Dashlets/ChartsDashlet/ChartsDashletScript.tpl' => 'f24cf3aa502c1235098b687e23718440', + './modules/Home/Dashlets/ChartsDashlet/ChartsDashletScript.tpl' => '40f994f93489b15801acbb6b95e902e0', './modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.php' => 'b3b1100c35333cf011af5d394478d7e7', './modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.meta.php' => '2cd846563521b3de61bde5de6b0f6fcf', './modules/Home/Dashlets/ChartsDashlet/ChartsDashlet.en_us.lang.php' => '862477d3835816ea73a5b0b245f500fb', './modules/Home/SubpanelCreates.php' => '780d3a94a7cbad31ec1e0f9c764384ba', './modules/Home/AddToFavorites.php' => '36f3b6729a6c08afa63d7614e68f23ef', - './modules/Home/About.php' => '858f6f1d26ff200447dcc5631d012993', + './modules/Home/About.php' => 'b2e7ddf77f82c545a8922d116a6bb7d4', './modules/History/metadata/subpaneldefs.php' => 'd25da6b3dc2a98b53fe168e5805fe262', './modules/History/language/en_us.lang.php' => '6e03640c59ea6846c934446ec6782318', './modules/Help/language/en_us.lang.php' => 'c8f73ef5b95d898669cb8d465a0d9bd3', @@ -2124,7 +2168,7 @@ $md5_string = array ( './modules/Groups/Menu.php' => '9404e4367f4cdc59ee84fdb53dd46556', './modules/Groups/ListView.php' => '0c57411c0be8603f88c89d53993545b0', './modules/Groups/ListView.html' => 'f721232264678859c12c27162e2df509', - './modules/Groups/Group.php' => '2d29ef15762da752fc36a5e0238896ba', + './modules/Groups/Group.php' => '4eeff5bab6b39f3a9f475800fce4722a', './modules/Groups/Forms.php' => 'b190f1c4d35ab755cc767d17b281bdae', './modules/Groups/EditView.php' => '658f357ae792b66634bfd0552a33c5a0', './modules/Groups/EditView.html' => 'd8766a05ea94631caa70b91d67a6c633', @@ -2132,7 +2176,7 @@ $md5_string = array ( './modules/Groups/DetailView.html' => '0c0c957f384c3a1f30f52922afd517bd', './modules/Groups/Delete.php' => '62a025db67afb0688f26ac1dd2e6b855', './modules/Employees/EmployeeStatus.php' => 'e15246545f162fbb5ea4126eae907d7f', - './modules/Employees/views/view.list.php' => '3971f6b0047923b2b1a49f6af37c58f2', + './modules/Employees/views/view.list.php' => '4de041f45ec6a42e941743605c89f688', './modules/Employees/views/view.edit.php' => '5dc44b9fa6a75acecc1253c07e61e6db', './modules/Employees/views/view.detail.php' => 'fc5cd2083d774ad347669dcf7f907b58', './modules/Employees/vardefs.php' => 'fbc0faa3310c46fda6e9022793b4173d', @@ -2153,15 +2197,16 @@ $md5_string = array ( './modules/Employees/Error.php' => 'ce78eb822cb1508b923493e55f053122', './modules/Employees/Save.php' => '0a02115ace66b8d69960b0d4660fdfa3', './modules/Employees/Employee.php' => '19d7b5023b16ca97b1f4f3dde4b485b7', + './modules/Emails/EditView.html' => '5b89afe8cc863a6828fe770a943d86b7', './modules/Emails/views/view.quickcreate.php' => '1baef44186ab0bc84e3d575c5537ccb5', './modules/Emails/views/view.modulelistmenu.php' => '647ceefc2936595192f0683ff27ce3d2', './modules/Emails/views/view.classic.config.php' => '1117f98347ee9338dd7887db4119ed7f', - './modules/Emails/vardefs.php' => '187c6f2431a63c89abb8354fc3f4e65c', + './modules/Emails/vardefs.php' => '98025fee0aef9b79dd5931c22befbe33', './modules/Emails/templates/successMessage.tpl' => 'ec563fa13bfa5dd1d611ffc2b57cbdee', './modules/Emails/templates/overlay.tpl' => 'ad47b013ebf54f0b887d4dfb677a3d5c', './modules/Emails/templates/outboundDialogTest.tpl' => '3ca9596589192f172a53d3c5163a4bf3', './modules/Emails/templates/outboundDialog.tpl' => 'affc7bf040562312dfdf7bdb9bd49cd1', - './modules/Emails/templates/importRelate.tpl' => '57ed5359f442598096fbf70072fae099', + './modules/Emails/templates/importRelate.tpl' => '457738a88f0d411f63cde5aa5458f9af', './modules/Emails/templates/emailSettingsRules.tpl' => '19c578b89aa41be6c176daf505f66730', './modules/Emails/templates/emailSettingsGeneral.tpl' => '410abb1be0967cad210b71f26254ae10', './modules/Emails/templates/emailSettingsFolders.tpl' => '87ff9d3db467d7efa8f00048a435e673', @@ -2193,10 +2238,10 @@ $md5_string = array ( './modules/Emails/metadata/subpanels/ForQueues.php' => '0b2af9f4ecba910a48c51b4f3bf30455', './modules/Emails/metadata/subpanels/ForHistory.php' => '2270727a62373544e3eb8c7cf534baa6', './modules/Emails/metadata/subpanels/ForContacts.php' => '7e1383b9410be93cf79fee5a65824d89', - './modules/Emails/metadata/subpaneldefs.php' => '7139213a451fc2386a7a815294091079', + './modules/Emails/metadata/subpaneldefs.php' => 'e56b3964d7ce8b98c92792b8dffa3398', './modules/Emails/metadata/popupdefs.php' => '935633cc8c825fe22d32cb97b17bbfb5', './modules/Emails/metadata/additionalDetails.php' => '8bed5af515fd42c7ace274b348f6e081', - './modules/Emails/language/en_us.lang.php' => '7af039b5ba0e2346f71522e21515b406', + './modules/Emails/language/en_us.lang.php' => '58d05c0e404cd04d76c7b500faa72bb7', './modules/Emails/javascript/viewPrintable.js' => '1bdda43134bb2d9af593440981a353d1', './modules/Emails/javascript/vars.js' => 'd50d29d7a0083c3cc915440de136ecbf', './modules/Emails/javascript/init.js' => '00e6d04a2905243df25b58bc861ade03', @@ -2205,11 +2250,11 @@ $md5_string = array ( './modules/Emails/javascript/displayOneEmailTemplate.js' => '2674507d7e9e7486d73c8706916ff1d0', './modules/Emails/javascript/composeEmailTemplate.js' => 'ea1469e2026811ebf263d49063971fc8', './modules/Emails/javascript/complexLayout.js' => 'fbcdb2d153ed8d495d095067ac792a47', - './modules/Emails/javascript/ajax.js' => '62f8c69d48c09895c5b2f84f10279751', - './modules/Emails/javascript/EmailUIShared.js' => 'e29adedf1480382aacc62d8aa7cebbca', - './modules/Emails/javascript/EmailUICompose.js' => '9e8f7d3ba0b8f915819faf93b79c78bb', - './modules/Emails/javascript/EmailUI.js' => '1fb6751344ba44c13a4207aeac09006b', - './modules/Emails/javascript/Email.js' => 'f004f426855262d2a949d5613056d7ed', + './modules/Emails/javascript/ajax.js' => 'c79464f6d7676ebe7b738945b18784b7', + './modules/Emails/javascript/EmailUIShared.js' => 'df6ecb98436f9ca8186106b9a4496dbf', + './modules/Emails/javascript/EmailUICompose.js' => 'c175292f2edb323c71d7dc4de88d082f', + './modules/Emails/javascript/EmailUI.js' => 'd75abb223151ed6ca82de6d342464cf0', + './modules/Emails/javascript/Email.js' => '0d9490a7067d54a473d33999e04876a6', './modules/Emails/index.php' => '6aff206a9821e1259275602982d900b8', './modules/Emails/images/sugarGroup.gif' => 'ad21210176b6a2a10a7a9b8f876ad83b', './modules/Emails/images/sugarDynamic.gif' => '82285d963771975b2def7f19e6438a8c', @@ -2253,9 +2298,9 @@ $md5_string = array ( './modules/Emails/EmailUIAjax.php' => 'b9cadacaad8d63947790f8baa442eebb', './modules/Emails/EmailUI.php' => '4a84724f5f101fcd4e9f2e5a4ba360e5', './modules/Emails/EmailUI.css' => '6f93388627148bdc54c9458c434d7ec1', - './modules/Emails/Email.php' => '41d07af157ef12df023cee3d06209145', - './modules/Emails/EditViewArchive.html' => 'b29b2deb170e9a9287ee0e1a2bf6bda9', - './modules/Emails/EditView.php' => '1bab8b3fb6b519c22d547322db034eb4', + './modules/Emails/Email.php' => '5ecad39b7090543d1f45be10159cb056', + './modules/Emails/EditViewArchive.html' => '2d88389d7dbe10281c731cc757373cea', + './modules/Emails/EditView.php' => '6db8f3c72668df76eb17d37b3a32de23', './modules/Emails/DetailViewSent.html' => '7b12fdf44a8a0acde69e36fa0341e149', './modules/Emails/DetailView.php' => 'a6ca96cb85ff388b617d17c23f4dc777', './modules/Emails/DetailView.html' => 'ec09f0f79d1361e5c6a372551ae55a9e', @@ -2276,11 +2321,11 @@ $md5_string = array ( './modules/EmailTemplates/PopupDocumentsCampaignTemplate.php' => '106659a099ce46c133d59e0c89a5119d', './modules/EmailTemplates/PopupDocumentsCampaignTemplate.html' => '8efe463d65710e6c6b5439235fd0b2c3', './modules/EmailTemplates/Menu.php' => '4edf25b2e9851ed5f2e8e44bb69b6863', - './modules/EmailTemplates/EmailTemplateFormBase.php' => 'ffc958e5b7d90e6b5d80b1775973ad9a', + './modules/EmailTemplates/EmailTemplateFormBase.php' => '3b0ba4396d31f3af7b5d8072712e1d45', './modules/EmailTemplates/EmailTemplate.php' => 'a1b2da557cb1680e5386da341ab42cbb', './modules/EmailTemplates/EditViewMain.html' => '2524b1d15a0f49b2ae59a068ae0e49af', './modules/EmailTemplates/EditView.php' => 'a569044944fcf405855bcaef16027399', - './modules/EmailTemplates/EditView.html' => '1fc9440b3824a5b62b989e1ef1e7e524', + './modules/EmailTemplates/EditView.html' => '8242a089eaf7b6cac93029f487203870', './modules/EmailTemplates/DetailView.php' => 'db07295b7aa677874acba993c6f092fc', './modules/EmailTemplates/DetailView.html' => '45aae47f2d182de3335e72abe975e7f2', './modules/EmailTemplates/Delete.php' => '954d8dbbe3ee5c5dcf65b3da9eba54ab', @@ -2308,8 +2353,8 @@ $md5_string = array ( './modules/EmailMan/views/view.list.php' => 'd5de096088dccaf7dae5527489ab5825', './modules/EmailMan/views/view.config.php' => '57b38635350c47bd0fe995348d940c9b', './modules/EmailMan/views/view.campaignconfig.php' => '929db4bba124ff947bc67ee3599341c6', - './modules/EmailMan/vardefs.php' => '3eda37221e3162a777a73f1186af76b0', - './modules/EmailMan/tpls/config.tpl' => 'd93824d0a2016da003f59e53392419b9', + './modules/EmailMan/vardefs.php' => '421a919a88b6838bcb76a809056651e2', + './modules/EmailMan/tpls/config.tpl' => '192969ffaa07b1480dde80d5cfd4b4c2', './modules/EmailMan/tpls/campaignconfig.tpl' => '44623eab12e9006cae2d08f74f3394f9', './modules/EmailMan/testOutboundEmail.php' => '30691acf8389d15dc1a5013b9aff2361', './modules/EmailMan/subpanels/default.php' => '38725d5f2e105fd9167b6395d81d23d4', @@ -2322,8 +2367,8 @@ $md5_string = array ( './modules/EmailMan/action_view_map.php' => 'cc9cf5e580d8486dd2adfb84b964d30b', './modules/EmailMan/Menu.php' => '0c6088479556b57257a7dcf8cd439940', './modules/EmailMan/Forms.php' => '82708d6c997b31f39fd29e2083af8624', - './modules/EmailMan/EmailManDelivery.php' => '2e1b60ab177c049d21a35f3c65394503', - './modules/EmailMan/EmailMan.php' => '12fbff7e02401ea17c978f1294c0f944', + './modules/EmailMan/EmailManDelivery.php' => '70cb65219360c2397d8b158b57c498fe', + './modules/EmailMan/EmailMan.php' => '8c9119fbe098021ccbe811294589e962', './modules/EmailAddresses/vardefs.php' => '465f3658bdc23c92e57c76217e5bb4eb', './modules/EmailAddresses/language/en_us.lang.php' => 'db372ac43705b32cb262af2e0ba5277d', './modules/EmailAddresses/EmailAddress.php' => 'b1e77ecbdc87dc5efd9bf41390f0245a', @@ -2339,7 +2384,7 @@ $md5_string = array ( './modules/DynamicFields/templates/Fields/TemplatePhone.php' => 'adda773907efe9b99563c473167f62d1', './modules/DynamicFields/templates/Fields/TemplateParentType.php' => '8bf57618db8a2da04325714d07947c3f', './modules/DynamicFields/templates/Fields/TemplateParent.php' => '7ff6ce67d159f2655c58b9cbd227fc5f', - './modules/DynamicFields/templates/Fields/TemplateMultiEnum.php' => '8d2d639329e63d5bff727498b405a321', + './modules/DynamicFields/templates/Fields/TemplateMultiEnum.php' => 'fd185e4aee9475473eecbcc7a5c8683d', './modules/DynamicFields/templates/Fields/TemplateInt.php' => 'd455c043af2f58ad60cfd79ca54c60fb', './modules/DynamicFields/templates/Fields/TemplateImage.php' => 'cd25fc06123215732edd2a8888243aad', './modules/DynamicFields/templates/Fields/TemplateId.php' => '1bb2f011438d66efe359fda4028b9628', @@ -2347,7 +2392,7 @@ $md5_string = array ( './modules/DynamicFields/templates/Fields/TemplateHTML.php' => 'a8777d496c22ea3b80fcbaea8ecf5a1b', './modules/DynamicFields/templates/Fields/TemplateFloat.php' => '4d7688c8c36eda595e826b218d1aa0c9', './modules/DynamicFields/templates/Fields/TemplateField.php' => '42949346637aee5e5de763ebb7ea758b', - './modules/DynamicFields/templates/Fields/TemplateEnum.php' => '8be35e7f9b13b7064f8f19485cad1d10', + './modules/DynamicFields/templates/Fields/TemplateEnum.php' => 'd13a94e2b6aa3b4258eb74a3b3a9bc8d', './modules/DynamicFields/templates/Fields/TemplateEncrypt.php' => 'af753a4fbd9cacd77fcf7b7b71b6d0e7', './modules/DynamicFields/templates/Fields/TemplateEmail.php' => '220b34f505843588d7bb2621bfb628bb', './modules/DynamicFields/templates/Fields/TemplateDecimal.php' => 'd07945e751bc435950555006d5eae44e', @@ -2398,13 +2443,13 @@ $md5_string = array ( './modules/DynamicFields/FieldsMetaData.php' => '31881094e9dfef9a0579622e0768d69f', './modules/DynamicFields/FieldViewer.php' => '53f662eab9401fd5a0b9f90c035fb13a', './modules/DynamicFields/FieldCases.php' => '7e9c75d4fcefca29f24033a0e8687f3c', - './modules/DynamicFields/DynamicField.php' => '077660ef7d2af1cac486da687cc628f2', + './modules/DynamicFields/DynamicField.php' => '30469b2d972ac572d6254b0ef9f7a17d', './modules/Documents/documents.js' => '8b00857d6e7b1f8dd1dbfbe68a6dee47', - './modules/Documents/tpls/view.extdoc.tpl' => '5566d78f1a66a4a38d1d3dc93ece9c01', + './modules/Documents/tpls/view.extdoc.tpl' => '9471a4d4ef93987e9b646f79591b2bc6', './modules/Documents/action_view_map.php' => '0994fe5e38b73c985fff200f9edb2129', './modules/Documents/DocumentExternalApiDropDown.php' => '05c03dc10f85d98ddc4c512d809f886a', './modules/Documents/views/view.extdoc.php' => '3348a550e4e6a7d4e4ed7712a5cf74af', - './modules/Documents/views/view.edit.php' => 'a428296858015ae9aa9722a58f579015', + './modules/Documents/views/view.edit.php' => 'a6f35bc369a8d00cd6905212170b1ad2', './modules/Documents/views/view.detail.php' => 'e304a2abe7de36903ff6326746313616', './modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.php' => '35404688fc59eb3737d89ca7432c3e76', './modules/Documents/Dashlets/MyDocumentsDashlet/MyDocumentsDashlet.meta.php' => '0fd71adbdb97e05acfa9e37f517fd47b', @@ -2415,12 +2460,12 @@ $md5_string = array ( './modules/Documents/metadata/subpaneldefs.php' => '70dd233ce8f24edeb4b54a39185d5562', './modules/Documents/metadata/studio.php' => '1f3e1f9c3a457e502635fd5a1d53861d', './modules/Documents/metadata/searchdefs.php' => 'd344cdfeb46470a1575e7a0fa752eef9', - './modules/Documents/metadata/quickcreatedefs.php' => '532f31110e9f13e775f3f50609bdc715', + './modules/Documents/metadata/quickcreatedefs.php' => 'a8ad52550cb874baeb11ee116744c03a', './modules/Documents/metadata/listviewdefs.php' => '219bcfc1e773eedfd3675265ef002ff3', - './modules/Documents/metadata/editviewdefs.php' => '0c4330ed8c2c1fea7ca45aa7b3554df9', + './modules/Documents/metadata/editviewdefs.php' => '4f1da2538866a0ea01796778c9a9105a', './modules/Documents/metadata/detailviewdefs.php' => '1f005a55b5bce7e42d4f5598b2ff06f2', './modules/Documents/metadata/SearchFields.php' => '95cb40df371368c17f84dc3d08e37b98', - './modules/Documents/language/en_us.lang.php' => 'abd885ea32769e2435afdd6ee53077aa', + './modules/Documents/language/en_us.lang.php' => '4c796b5075d0f7613185744f7a059db7', './modules/Documents/field_arrays.php' => 'ce02f4e3f1c5718d952ed0327c57fc21', './modules/Documents/TreeData.php' => '389a7fd896fc0224c75f0479007548ae', './modules/Documents/Popup_picker.php' => '81628e6d81835408a4f694996d5b7e9b', @@ -2432,7 +2477,7 @@ $md5_string = array ( './modules/Documents/Document.php' => 'ca47fe2cb3894c4570c772031f379ce6', './modules/Documents/Delete.php' => 'fe07bfd994a8d39da43f79fbf4aac64e', './modules/DocumentRevisions/subpanels/default.php' => 'c2961928cfb28cd4b9336444ea7843d3', - './modules/DocumentRevisions/metadata/editviewdefs.php' => '38b36f4bf7e06b78187659f9fa1b9b9c', + './modules/DocumentRevisions/metadata/editviewdefs.php' => 'ce590dd0399c79fbf6cc3e25923e4d96', './modules/DocumentRevisions/metadata/detailviewdefs.php' => '702fffdd1d9996b91d6f3edd67e9e99f', './modules/DocumentRevisions/metadata/subpanels/default.php' => '927bbe4743f41507c513e1f112ffc99b', './modules/DocumentRevisions/language/en_us.lang.php' => '8f7a15a66ab78f53dd433ba59fea7fa0', @@ -2454,18 +2499,18 @@ $md5_string = array ( './modules/Currencies/Forms.php' => '6d7619156646796d8463bb1e4e5acd01', './modules/Currencies/EditView.tpl' => '509a24e75df8bc565847458bf541f7fa', './modules/Currencies/EditCurrency.php' => 'dfe9ae276fb02bdae956146ee96edca0', - './modules/Currencies/Currency.php' => '755c45d25d68d8fcacb381e8f9b14743', + './modules/Currencies/Currency.php' => 'ed74e8241b08280c7950aa447257fea5', './modules/Contacts/Contact.js' => 'e503be995847cfaa74b80ec64deea115', './modules/Contacts/views/view.quickcreate.php' => 'c427b1da2e3880b0ed90af832481170e', './modules/Contacts/views/view.list.php' => 'd5a51ad95c221ddaaaaca33c9b3acd1a', './modules/Contacts/views/view.validportalusername.php' => 'b85ab0a2b014d20d69c3c57c415148c4', './modules/Contacts/views/view.retrieveemail.php' => '6f810a4e68ef0c84d31aa433a03929a7', './modules/Contacts/views/view.mailmergepopup.php' => '13cf36b3fa24bade42630f6e34ef8cd3', - './modules/Contacts/views/view.edit.php' => '6e294dcbe1d540171cab488df87197e5', + './modules/Contacts/views/view.edit.php' => '3f12c32a5fb604fab81852ec364cda34', './modules/Contacts/views/view.detail.php' => '48058ccfb21592ee5abe894b77939ab7', './modules/Contacts/views/view.contactaddresspopup.php' => '6b850ba3f32ae2254e441302c844631f', './modules/Contacts/views/view.closecontactaddresspopup.php' => '760a824c3e06fa3df9827896a2b7fa05', - './modules/Contacts/tpls/QuickCreate.tpl' => '69352ec60eb8a279ebd46d466fba1a39', + './modules/Contacts/tpls/QuickCreate.tpl' => '4bf7e17173dd168229867f66773e7cfe', './modules/Contacts/metadata/subpanels/default.php' => 'cf6be79e26a72c1c8e98a6329a48e5dd', './modules/Contacts/metadata/subpanels/ForProject.php' => '9c66e6a62d6da1c489a92ddc9b1f9011', './modules/Contacts/metadata/subpanels/ForOpportunities.php' => '453dbb260034aa88051719eaa07a08bc', @@ -2475,7 +2520,7 @@ $md5_string = array ( './modules/Contacts/metadata/subpanels/ForCases.php' => 'f8a4c13dad739039737a43a239801081', './modules/Contacts/metadata/subpanels/ForCalls.php' => '5dfaa4086cef055869f4831b72739893', './modules/Contacts/metadata/subpanels/ForAccounts.php' => '4a034356d9a1bd71a7de374db61a189b', - './modules/Contacts/metadata/subpaneldefs.php' => '99a7df7e575014f2300ab9f42e8f4196', + './modules/Contacts/metadata/subpaneldefs.php' => 'ee7146aa7c42649cdb5b8d0fc961c3c4', './modules/Contacts/metadata/studio.php' => 'fbeabc6ed6e88f4d0f2c6dd9e4ddf288', './modules/Contacts/metadata/searchdefs.php' => 'fac0439eef3deb008e6efd6221518aab', './modules/Contacts/metadata/quickcreatedefs.php' => '205faf881d1fa51bb15a028b2a7fc694', @@ -2487,12 +2532,12 @@ $md5_string = array ( './modules/Contacts/metadata/detailviewdefs.php' => 'f485ac2da169d06a8a407b6ad22f3354', './modules/Contacts/metadata/additionalDetails.php' => 'db6c2236740f97bfc8c341fa3da79dbc', './modules/Contacts/metadata/SearchFields.php' => '48c393c28326b6516e60380afa97e5c6', - './modules/Contacts/language/en_us.lang.php' => '1dd9782ef94980ee09bbb21ec2b50414', + './modules/Contacts/language/en_us.lang.php' => '6886bd48a2e98a29303a1fa8eeddde9f', './modules/Contacts/field_arrays.php' => '15a260aba13a962b3f6135046f11c4e1', './modules/Contacts/controller.php' => '6607e948d272e5809461876a391cc5a1', - './modules/Contacts/vardefs.php' => '11b1a70bea6761a34c72df6f8bc65ffe', + './modules/Contacts/vardefs.php' => '68937dbe02a4e3842986b5274a169896', './modules/Contacts/SugarFeeds/ContactFeed.php' => '1f16df8e3936e78b160a05091d5fdbc4', - './modules/Contacts/ShowDuplicates.php' => '40fec13c96fe35316a6acdfa446a49f7', + './modules/Contacts/ShowDuplicates.php' => '2d5b7983e4f08dd82c35c0eb8634ede1', './modules/Contacts/ShowDuplicates.html' => '5c3bdbdbdb3ad22334e6b1ac7f844db7', './modules/Contacts/SaveContactOpportunityRelationship.php' => 'ec59ca27f5916ed5370bb33c66701686', './modules/Contacts/Save.php' => '8463ae2addbf510c8e055b0ad11ec8c7', @@ -2507,21 +2552,21 @@ $md5_string = array ( './modules/Contacts/ContactOpportunityRelationshipEdit.php' => 'ca0574bfc40855f7c170f3e2912fc445', './modules/Contacts/ContactOpportunityRelationshipEdit.html' => '063f65d9dbe6f7f58367d99f2af65210', './modules/Contacts/ContactOpportunityRelationship.php' => 'ec6fac16e09199dc26550e84cca523cf', - './modules/Contacts/ContactFormBase.php' => '9b139e31c8b95fa3e5b7fec497143e9d', - './modules/Contacts/Contact.php' => 'b66ed57efe60e3774f09e25ca8ffc997', + './modules/Contacts/ContactFormBase.php' => '57d06bd0905b4ef6ad977509aecc9083', + './modules/Contacts/Contact.php' => '40651edd569a09692506f0d7aa9b524c', './modules/Contacts/BusinessCard.php' => '6791cfe02546533166a04d27d143eb49', './modules/Contacts/BusinessCard.html' => '2ad1f1578e7c6f85791f97656576a3a8', './modules/Contacts/Address_picker.html' => '7d072ff9f9bc06d2373ba2dee5a7086c', './modules/Contacts/AcceptDecline.php' => '85fc8211788b54db3754cfb50f3f6aa3', './modules/Connectors/Connector.js' => 'a46f07c2e592f0921202fe6b172cd255', './modules/Connectors/views/view.sourceproperties.php' => '3e6da0a30c1123aa73c07e96657215fa', - './modules/Connectors/views/view.searchproperties.php' => '1acd895b65a875a45ff09515436186b0', + './modules/Connectors/views/view.searchproperties.php' => 'd2ffd825d454ed0c3eb7dca50549e961', './modules/Connectors/views/view.modifysearch.php' => '6d780a252feacfec34763b6aa82023a7', './modules/Connectors/views/view.modifyproperties.php' => 'dcc0b716091162d4c0bd2358cc36c75e', './modules/Connectors/views/view.modifymapping.php' => 'f6e46213597c80cf956d096a2b7eff07', './modules/Connectors/views/view.modifydisplay.php' => 'f0214caab2b1f11eeaa0061b7f5c5479', - './modules/Connectors/views/view.mappingproperties.php' => '709b7978381a3d4559574aef3035f08b', - './modules/Connectors/views/view.displayproperties.php' => '34fbb12f5fbf89bc4320b8d5fa8e6157', + './modules/Connectors/views/view.mappingproperties.php' => 'b17456a8552e9ac4e746271bccb7199d', + './modules/Connectors/views/view.displayproperties.php' => 'bad07b121cf88033d3edfae328df9c1f', './modules/Connectors/views/view.connectorsettings.php' => '4a73c3d0a244650188fbb5028b8d15dd', './modules/Connectors/tpls/tabs.css' => 'b69adf86332cf9ef4dcec4af9b9867cd', './modules/Connectors/tpls/source_properties.tpl' => '4e474ab4f798b0cabc9f3a224a6bece6', @@ -2533,22 +2578,22 @@ $md5_string = array ( './modules/Connectors/tpls/modify_display.tpl' => '68a4c7d1a802fd4d5e8a96ee05af8586', './modules/Connectors/tpls/mapping_properties.tpl' => 'bc2761367e1d8ec45a6415fe30fe422d', './modules/Connectors/tpls/listview.tpl' => 'c69a43df5f9b91829ca2befe7485d5d2', - './modules/Connectors/tpls/display_properties.tpl' => 'ad2a85adbb24b80a3864b84d2ff299fa', + './modules/Connectors/tpls/display_properties.tpl' => 'adb9fb3ace7f717a6c528e8976bc24d7', './modules/Connectors/tpls/administration.tpl' => '08c82fb2efe9da0793e676ba61cfd4da', './modules/Connectors/metadata/searchdefs.php' => '0a7b0c3175045ed95ffba4266f5aa88c', './modules/Connectors/language/en_us.lang.php' => '7a098f6e82147b7f1b78548c73e6396d', - './modules/Connectors/controller.php' => '6a2d3a3e77f9ea5215c829be7d293c3e', - './modules/Connectors/connectors/sources/ext/rest/insideview/tpls/InsideView.tpl' => '7ff192cb71e188978fce2086db10d904', + './modules/Connectors/controller.php' => 'a8373b07d125207734c7c59b119b58e4', + './modules/Connectors/connectors/sources/ext/rest/insideview/tpls/InsideView.tpl' => '7c5f32b1d65a383c4472f66de27118ad', './modules/Connectors/connectors/sources/ext/rest/insideview/mapping.php' => '0a0fac88d087b82df90c60abc0945819', './modules/Connectors/connectors/sources/ext/rest/insideview/language/en_us.lang.php' => '197f5401eda3284469c56a4daf6d6570', - './modules/Connectors/connectors/sources/ext/rest/insideview/insideview.php' => 'a0707499398c3cf58c9fbaa45a93e85d', + './modules/Connectors/connectors/sources/ext/rest/insideview/insideview.php' => '9ff45cceb442a4e671478840a2132b46', './modules/Connectors/connectors/sources/ext/rest/insideview/images/video.png' => '78914852af51eb8eb694fdcf518b6752', './modules/Connectors/connectors/sources/ext/rest/insideview/images/insideview_expanded.png' => 'db7e5e84b7891adaed90dfd211338959', './modules/Connectors/connectors/sources/ext/rest/insideview/images/insideview_collapsed.png' => 'dc728b8cb2023847a28eb54a06c4d78e', './modules/Connectors/connectors/sources/ext/rest/insideview/images/insideview.png' => 'b94d9483f486e0f53b3d98c6d04bd9f6', './modules/Connectors/connectors/sources/ext/rest/insideview/images/close.png' => 'a0d9ad4fc0c4a58ebaa7823216f6cc98', './modules/Connectors/connectors/sources/ext/rest/insideview/config.php' => 'a5d091ae0399b08a109fb26ec6d602f7', - './modules/Connectors/connectors/sources/ext/rest/insideview/InsideViewLogicHook.php' => '5842bef34a886c6412af2f5df6915feb', + './modules/Connectors/connectors/sources/ext/rest/insideview/InsideViewLogicHook.php' => '20cf9abadf5a8451840fad18fa1bb5ec', './modules/Connectors/connectors/sources/ext/rest/linkedin/vardefs.php' => '975b74882adf5d355985d903f60fc160', './modules/Connectors/connectors/sources/ext/rest/linkedin/mapping.php' => '03dbda444c28146c4def211d46778dbc', './modules/Connectors/connectors/sources/ext/rest/linkedin/linkedin.php' => '3c034995f01419372ddcefb3f7842c2c', @@ -2565,20 +2610,20 @@ $md5_string = array ( './modules/Connectors/ConnectorRecord.php' => '452d382859384f44b912abd25f727268', './modules/Configurator/views/view.sugarpdfsettings.php' => 'dc1f025773e789eb3960bed66382b4ac', './modules/Configurator/views/view.fontmanager.php' => '1aedd49b5e0e5fcafc9f03dfeccae74d', - './modules/Configurator/views/view.edit.php' => '40acba3d9447e502810745f66125b4c9', - './modules/Configurator/views/view.adminwizard.php' => '01519ec9822c5e390de25e9cefac6a63', + './modules/Configurator/views/view.edit.php' => '7c5c2241b9ce377945e96f610cd065de', + './modules/Configurator/views/view.adminwizard.php' => '8e8b859b6f7934c58ecae36b34197f78', './modules/Configurator/views/view.addfontview.php' => '32bb28602335b418eafcd8bafb5e6fa9', './modules/Configurator/views/view.addfontresult.php' => '70babb45791ab15c7e7395aaa0ac8494', './modules/Configurator/tpls/fontmanager.tpl' => '748bd026b6862c287e0c4a6dd50e2e56', - './modules/Configurator/tpls/adminwizard.tpl' => '2287deb74c16bd18d2a4a6d22a5e0130', + './modules/Configurator/tpls/adminwizard.tpl' => '05caa857219f6a623dbfb1beae5bd923', './modules/Configurator/tpls/addFontView.tpl' => '5da526b1ed5a0b3fc57caa4161d47b6d', './modules/Configurator/tpls/addFontResult.tpl' => '1e1475a7d057504ba22a4a30b65b6c36', './modules/Configurator/tpls/SugarpdfSettingsFields.tpl' => '80235a1d08cf36c5dfbd79c7de7152e8', './modules/Configurator/tpls/SugarpdfSettings.tpl' => 'd283c244e66075367faef6cbc01f3459', - './modules/Configurator/tpls/EditView.tpl' => '64eb722a88a6cf3a6b53d635b88f26fd', + './modules/Configurator/tpls/EditView.tpl' => 'db9ac4b818e9c65d854cdeb38204c526', './modules/Configurator/metadata/SugarpdfSettingsdefs.php' => 'df5f687816312360b828d6d9efab2b71', - './modules/Configurator/language/en_us.lang.php' => '5f8de482b351b8762d48a1204b4cbb1d', - './modules/Configurator/controller.php' => '4161172c9a598fde3a057a880d4e4ff0', + './modules/Configurator/language/en_us.lang.php' => 'd2c0d469744d4ddb84026db3ba6377c2', + './modules/Configurator/controller.php' => '9bac915d2f58d514b3bdf6e9bcee9548', './modules/Configurator/UploadFileCheck.php' => 'a3d6615e316e2b631b800c68c066d608', './modules/Configurator/action_view_map.php' => 'ba2dd628e87ce08422e8854993f3fb5c', './modules/Configurator/Menu.php' => 'a32579287c11a74aaf0d25ebb862edec', @@ -2595,7 +2640,7 @@ $md5_string = array ( './modules/Charts/code/Chart_lead_source_by_outcome.php' => '03c5b66b6889dd210c630edf76d1c9b6', './modules/Charts/chartdefs.php' => '02ee313d69bac35fe9ebfe8f55abbbfd', './modules/Charts/PredefinedChart.php' => '3eadf51c0359527dd34fbe043fbadec5', - './modules/Charts/Dashlets/PredefinedChartDashletScript.tpl' => '4343fcb9262e31fb1d7f08ae796c22c6', + './modules/Charts/Dashlets/PredefinedChartDashletScript.tpl' => '75bef506d61e81857968f68dc4ebc5f8', './modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.php' => '59e24fb966f59fc6fe0f70daf41ee23a', './modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.meta.php' => 'bf027380490a70f6bd274f85bf63b1ae', './modules/Charts/Dashlets/PipelineBySalesStageDashlet/PipelineBySalesStageDashlet.en_us.lang.php' => '859ada780282d5c3f76f1bba4ed77f0d', @@ -2631,7 +2676,7 @@ $md5_string = array ( './modules/Cases/metadata/subpanels/default.php' => '395830c0602b68b209bdd3a4a233c6e3', './modules/Cases/metadata/subpanels/ForEmails.php' => 'a6d533cc462b51a5cff760318e5860f7', './modules/Cases/metadata/subpanels/ForAccounts.php' => 'af800cc3bf5c0b913d62b3290fdcea7a', - './modules/Cases/metadata/subpaneldefs.php' => 'dc285d7c15e073c321ddb92e707fbfaa', + './modules/Cases/metadata/subpaneldefs.php' => '0c1d8a0c6ac93a27649447aecda61dfe', './modules/Cases/metadata/studio.php' => 'bf046389cf07f574eb1fa15808fc2a43', './modules/Cases/metadata/searchdefs.php' => '1e287201b7c05de6a02991e10798d260', './modules/Cases/metadata/quickcreatedefs.php' => '19c37fe2e361c331bd4ab772e458cee8', @@ -2642,10 +2687,10 @@ $md5_string = array ( './modules/Cases/metadata/additionalDetails.php' => '107c548cb270f3c6a9d49656ad565cbe', './modules/Cases/metadata/accountsquickcreatedefs.php' => '5ba216fa356f7f0c0a50f2a434140889', './modules/Cases/metadata/SearchFields.php' => 'fc5fbc25e3083d4ee141c349d0a21537', - './modules/Cases/language/en_us.lang.php' => '0347ef9fabbf625681d87ed59c03c42c', + './modules/Cases/language/en_us.lang.php' => '1e95ed3b62c63a21a8e9341367ec3aa1', './modules/Cases/field_arrays.php' => 'f47f31e031a2337b3275c52d40be0a96', './modules/Cases/SugarFeeds/CaseFeed.php' => '054fc387ac7b6a62d8b867404d72858e', - './modules/Cases/Menu.php' => 'ca69e66931c4dfd677e810430ab44cb8', + './modules/Cases/Menu.php' => '3852c4b27655f27f980df009369bdd8b', './modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.php' => '7f474fb0c239e8e06ce6e47adcd9b2d5', './modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.meta.php' => '2aca85a9766a6bbfc9b4aabc0ed3757f', './modules/Cases/Dashlets/MyCasesDashlet/MyCasesDashlet.data.php' => 'd76f38fe107de337969f7fa008222cb7', @@ -2654,13 +2699,13 @@ $md5_string = array ( './modules/Campaigns/DetailView.js' => 'd99f7c99ca8a7886d311b9131616513b', './modules/Campaigns/WebToLead.js' => '079c6e0a443138ff2203ca331e4b55e9', './modules/Campaigns/wizard.js' => '62f337f78016b8ca743aa61489863ad9', - './modules/Campaigns/TrackDetailView.tpl' => '3187e57b3476ef4387e76b385893027d', + './modules/Campaigns/TrackDetailView.tpl' => 'fac9e4b7215316b3c7b85fa0f125fc07', + './modules/Campaigns/RoiDetailView.tpl' => '364e8e4bedd22b4a9e947fa451dcd489', './modules/Campaigns/views/view.newsletterlist.php' => '6f52d2669b3d7afb03d6066d14d7631a', './modules/Campaigns/views/view.modulelistmenu.php' => '5a4ababf139b00c95705cfeba8abda74', - './modules/Campaigns/views/view.detail.php' => 'c00b5e16a5c761196bd4762f3b2f0389', + './modules/Campaigns/views/view.detail.php' => '4e6a3865fae8f5a0a85b0387548b7d34', './modules/Campaigns/views/view.classic.php' => '0d3eac4f8c4861e67698368ccd62ecea', './modules/Campaigns/vardefs.php' => '057bfdeefb37e7eedef8cb6c5656182c', - './modules/Campaigns/utils.php' => '2e3ca09bb30d563df260e655beb4fc6f', './modules/Campaigns/tpls/campaign-inactive.tpl' => '660c7ab053441e4d7e1865f056465ec2', './modules/Campaigns/tpls/WizardNewsletter.tpl' => 'a4aee7ecb98109063a28081685e1e58e', './modules/Campaigns/tpls/WizardHomeStart.tpl' => '3f0224431419e586fa3fe04cc76398b7', @@ -2680,19 +2725,19 @@ $md5_string = array ( './modules/Campaigns/metadata/detailviewdefs.php' => 'bf0bd6f05f74aa7a63d9b209ab59db84', './modules/Campaigns/metadata/additionalDetails.php' => '69fe2420d8d41833006e256d4381bc08', './modules/Campaigns/metadata/SearchFields.php' => '37b4e9ef20d3808674a9f3c327363e80', - './modules/Campaigns/language/en_us.lang.php' => 'b49c230d6646d3ffcefc9c4c379333d7', - './modules/Campaigns/image.php' => '9c6fef2968f6c2fdcef39d1c1b186a06', + './modules/Campaigns/language/en_us.lang.php' => 'f773aef38eb5c6cb2e9be14e1bd1afb3', + './modules/Campaigns/utils.php' => '2e3ca09bb30d563df260e655beb4fc6f', './modules/Campaigns/field_arrays.php' => 'ba76f4af9f199301612910fd052284d1', './modules/Campaigns/controller.php' => '0d48f789813067a604ed3a44ae6227b7', './modules/Campaigns/chart.tpl' => '0b05f75e6db080065bcfcce9c39a6e3a', './modules/Campaigns/action_file_map.php' => 'da2561f213e8ea3a051a1495e640f505', - './modules/Campaigns/WizardNewsletterSave.php' => 'c6b5cd71cd8d8f93030ed8ca98852c3b', + './modules/Campaigns/image.php' => '9c6fef2968f6c2fdcef39d1c1b186a06', + './modules/Campaigns/WizardNewsletterSave.php' => '49d229cce8b2adf5f17109f1bcd4b5c3', './modules/Campaigns/WizardNewsletter.php' => 'd040893fcb8261e17da48755f002d8e3', './modules/Campaigns/WizardNewsletter.html' => 'cd4b436c4ad368b74911d522e62b9763', './modules/Campaigns/WizardMarketingSave.php' => 'c122b586cb62994b94470fca94ea7e15', './modules/Campaigns/WizardMarketing.php' => '98f5e34fa2d8e532b9cb397b70a99222', './modules/Campaigns/WizardMarketing.html' => 'abd84c813ee375647c4e9f7f07286a3b', - './modules/Campaigns/WizardHome.php' => 'f41655b9526245ef101b63d4306c25d3', './modules/Campaigns/WizardHome.html' => '498f6846c3e963ec60ca0fd9cd7b496b', './modules/Campaigns/WizardEmailSetupSave.php' => 'e58eb32256b562aa5d9a4dda9173cb6c', './modules/Campaigns/WizardEmailSetup.php' => 'a599a67497a6d6b00b96a2880645d149', @@ -2704,10 +2749,10 @@ $md5_string = array ( './modules/Campaigns/WebToLeadCreation.html' => '16c5523189e636ba3e2647c81b4678d7', './modules/Campaigns/WebToLeadCapture.php' => '2c2dad84370710bd36629eb3e5171230', './modules/Campaigns/Tracker.php' => '726e6fc5b58f58cd4b330b61a12d7d21', - './modules/Campaigns/RoiDetailView.tpl' => '37196dd6f4253e25d2e12751900bdd8d', + './modules/Campaigns/ProspectLink.php' => 'a5de7ebb156d378d6d0b16390f9d19b9', + './modules/Campaigns/WizardHome.php' => 'f41655b9526245ef101b63d4306c25d3', './modules/Campaigns/TrackDetailView.php' => '4f3535618c1d37939b7e2775d25f1657', './modules/Campaigns/Subscriptions.tpl' => '1332be18f7e16a30887156e46430602a', - './modules/Campaigns/ProspectLink.php' => '5e38899aed24cf6a1b5a6d31d30aa7e2', './modules/Campaigns/Subscriptions.html' => 'a597b43f0772858ca5ea18c6f19a9ea9', './modules/Campaigns/SubPanelViewer.php' => '4c34b75d7cb01766e9845653d41860d7', './modules/Campaigns/SearchForm_NewsLetter.html' => '8ad7f22ed622f85c674c72f47145cacb', @@ -2727,7 +2772,7 @@ $md5_string = array ( './modules/Campaigns/MailMerge.php' => 'b635266e87c4a14f7930e1e988a7e7d0', './modules/Campaigns/GenerateWebToLeadForm.php' => '0d2ab31545e632fdecbb8fc464d9f27d', './modules/Campaigns/EmailQueue.php' => 'dcb74a2af79fe5087aa9f865a6cea5b2', - './modules/Campaigns/Delete.php' => '453d68affba5006c3fbec936394e632c', + './modules/Campaigns/Delete.php' => '7b39d5a936b875ce55b4b3c9c5ec0864', './modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashletConfigure.tpl' => '612ad35fc9906cb2bda949756465b375', './modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.tpl' => '13a08ec95b2d73ce11be435458a75962', './modules/Campaigns/Dashlets/TopCampaignsDashlet/TopCampaignsDashlet.php' => '18fb4a0607ba9e6a8c19714312141efc', @@ -2750,17 +2795,17 @@ $md5_string = array ( './modules/CampaignTrackers/DetailView.php' => 'bea6df98faa4e1f463642a6724b7a8b9', './modules/CampaignTrackers/DetailView.html' => 'af090e45793ce86c4d645363af3a6e67', './modules/CampaignTrackers/CampaignTracker.php' => '145c02a61c7ee72568c8023a2db65519', - './modules/CampaignLog/vardefs.php' => 'c3e81377b53bffe62579e3a5fb2a8494', + './modules/CampaignLog/vardefs.php' => '75e7b4a2cd2c0498ffb782263b79f796', './modules/CampaignLog/metadata/subpanels/default.php' => 'f7d277e1eb2a0c0c3df7325d94e1e143', './modules/CampaignLog/metadata/subpanels/ForTargets.php' => '7139b427cd0a42ea7b42bc1b8b86d24b', './modules/CampaignLog/language/en_us.lang.php' => '42b51c8253d2fdb5ca3c43b95d54a83b', './modules/CampaignLog/Popup_picker.php' => '5cfbc593eb62651c9b5fddbb2e365093', - './modules/CampaignLog/Popup_picker.html' => '5352231f402a624f048d9bfa812fa3d7', + './modules/CampaignLog/Popup_picker.html' => 'f93694cdb0522742932232f3864602ee', './modules/CampaignLog/Menu.php' => '9a144af6bd83a06aee1415594bd13e35', './modules/CampaignLog/CampaignLog.php' => '3a17faa3d29a69fb19cc00a381008238', './modules/Calls/views/view.edit.php' => '98773bd63784a336938d8c74b5be8e17', - './modules/Calls/vardefs.php' => 'bd11ba326780a73e01a2e1fffddde60b', - './modules/Calls/tpls/footer.tpl' => '95e468f85ad0f4a0a9b3e3903b97d0a4', + './modules/Calls/vardefs.php' => '4af0dcd8cfbdeed7e0f1dc84c0e156c9', + './modules/Calls/tpls/footer.tpl' => '7aeab8780e6c0a618ef47f94a580ed5c', './modules/Calls/tpls/QuickCreate.tpl' => '85798db63f4a49547d76aa14f6fa19a5', './modules/Calls/metadata/subpanels/default.php' => '446247ed1b8a39cbfaf65b2b97c61a4e', './modules/Calls/metadata/subpanels/ForHistory.php' => 'a43ff34ac73932be443b4eec4af5b3ff', @@ -2768,25 +2813,25 @@ $md5_string = array ( './modules/Calls/metadata/subpaneldefs.php' => '2aad1276c69546b6c22fc59e6b8328ae', './modules/Calls/metadata/studio.php' => '7442f22126f5bb99ab4f3386b2f25f3b', './modules/Calls/metadata/searchdefs.php' => '3a33005e5c90d47224d270ffdde6cb19', - './modules/Calls/metadata/quickcreatedefs.php' => '2cb0e91f4b9258052b62cd1d02cd6452', + './modules/Calls/metadata/quickcreatedefs.php' => '121348fe74d81b76fd0120ee4ef4b378', './modules/Calls/metadata/listviewdefs.php' => '83718f5d2b52beb50b9eed6b87a635b9', - './modules/Calls/metadata/editviewdefs.php' => 'ea00b929359955f8def9c63ff02a8b18', + './modules/Calls/metadata/editviewdefs.php' => '3058aa2186be10d05c7e64a31b5ac5f6', './modules/Calls/metadata/detailviewdefs.php' => '61fa590b05d978a15d6bc867d223b4c9', './modules/Calls/metadata/additionalDetails.php' => '9f9022d29091a594b1723cf72c905724', './modules/Calls/metadata/SearchFields.php' => 'dd426ac2a74e3235b37ce31501179359', - './modules/Calls/language/en_us.lang.php' => '76fcea27af79f66d8ebd1a15b7650730', + './modules/Calls/language/en_us.lang.php' => '7fb7d21f63b2e8c3027caeb147ff2610', './modules/Calls/field_arrays.php' => 'dd92ed8880e2027bec292632e57fefbe', './modules/Calls/SubPanelViewInvitees.php' => '6f49d0ca88820d15a8c0d0a96c40e9a6', './modules/Calls/SubPanelViewInvitees.html' => '4aa44ffe3919c55fcb61e17f6b2fb757', './modules/Calls/Save.php' => 'be147699eb6834e0db87fc2e910c1d3a', './modules/Calls/Menu.php' => '4739c2d258953f89a8b84b7f7261c4e2', - './modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.php' => '0013d261617dc3c48e76f705d280f3ec', + './modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.php' => '9704f269886274601c411117b5d91a1a', './modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.meta.php' => 'e34d7b77796de05737356c6945580966', './modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.data.php' => '577c8b018b6249972abd8ce81061c6af', './modules/Calls/CallsQuickCreate.php' => '1a526db285df01bcdda25ef861e25323', './modules/Calls/CallHelper.php' => '821c104aef4b2d64666fa94bb7cf7d88', - './modules/Calls/CallFormBase.php' => '64d168d630e819fa3360c90eda48becf', - './modules/Calls/Call.php' => '29b2dbf98e7c389797acdcb81dd2599f', + './modules/Calls/CallFormBase.php' => '8886ec2adfcadef1faabf74d15e9454f', + './modules/Calls/Call.php' => 'ed374d335a3e3c5c0ff234cbdcecb76d', './modules/Calendar/views/view.list.php' => 'e8dd64409e0ac2eacd506fcb7bb81fd9', './modules/Calendar/templates/templates_calendar.php' => '750737dbfd338550ae0c5cf6f26b1eea', './modules/Calendar/templates/template_shared_calendar.php' => 'b851af6632f3a7af5c5923bb561b6124', @@ -2800,10 +2845,10 @@ $md5_string = array ( './modules/Calendar/DateTimeUtil.php' => '94546928e6055eba2aad970b867d4c3f', './modules/Calendar/index.php' => 'a02b45207cc70cb65f3f2bdfa1a44c32', './modules/Calendar/Menu.php' => '62609bfe10c90bce8db9c684c921640b', - './modules/Calendar/Calendar.php' => 'bfa1ffcb44550f04fb2429faa38549f1', + './modules/Calendar/Calendar.php' => '7a8d10288ba50adadb6553e9fbc2f5ac', './modules/Bugs/views/view.edit.php' => 'f3758cc5fb82c65a163b9dfcb10e7b6b', './modules/Bugs/views/view.detail.php' => 'effc34a9f7844b8339a5b4efa9c3cbfe', - './modules/Bugs/vardefs.php' => '01f32339403525cdab96f4057c20422e', + './modules/Bugs/vardefs.php' => '38940b2b78c0db9cf131740295315f1b', './modules/Bugs/tpls/QuickCreate.tpl' => 'e6f85f560bffc302c85114a0ec574a41', './modules/Bugs/metadata/subpanels/default.php' => '112c2dc86b254af66d0c7af331059b35', './modules/Bugs/metadata/subpanels/ForEmails.php' => '8080da8e50fa6c3e4748f77124755247', @@ -2818,7 +2863,7 @@ $md5_string = array ( './modules/Bugs/metadata/detailviewdefs.php' => 'c97a9ee5f7682efb4d6ca4568b9390c5', './modules/Bugs/metadata/additionalDetails.php' => '9517d2e6fb71ca10e90d0d42caf68c40', './modules/Bugs/metadata/SearchFields.php' => '2a105b277f0a33a3f109d43df6429526', - './modules/Bugs/language/en_us.lang.php' => 'fd5065a4f42c7f9c1052938a21122632', + './modules/Bugs/language/en_us.lang.php' => '72fb0032b50b2f8c720939ef9b09ab7d', './modules/Bugs/field_arrays.php' => '0e6edfc770713503ea16643f397a93f4', './modules/Bugs/Menu.php' => '683f6797c65dee9cc50eaf73c6d6e152', './modules/Bugs/Dashlets/MyBugsDashlet/MyBugsDashlet.php' => '8f87627044c50ef408ca94bf691f8c74', @@ -2835,6 +2880,7 @@ $md5_string = array ( './modules/Audit/Audit.php' => '8845540806673a78e6026f6e681dad15', './modules/Administration/views/view.languages.php' => '4ffc0f3631a98f9660f11d819af6c6ca', './modules/Administration/views/view.globalsearchsettings.php' => 'c1470c8880921604de9aaea35b7f6324', + './modules/Administration/views/view.configureajaxui.php' => '40ddcc8507682e26dcd3103d4577a2e3', './modules/Administration/views/view.backups.php' => '0d6ff257adb73f2f96bb3e32b14d83b1', './modules/Administration/views/view.themesettings.php' => '9ffaa92e78814164cedc2e3ad6e41bd1', './modules/Administration/views/view.repair.php' => '394bba2767cd1ed68095430d77a2aace', @@ -2845,6 +2891,7 @@ $md5_string = array ( './modules/Administration/undoupdateclass.php' => 'a05857b2a437d34e52a377bbfca08ca3', './modules/Administration/templates/Languages.tpl' => 'f2115e30b05bd5ffd32b42284b5a3b5f', './modules/Administration/templates/GlobalSearchSettings.tpl' => '7872194b872c6bf46965e7c7b006e52e', + './modules/Administration/templates/ConfigureAjaxUI.tpl' => '92e9d52c8becb9acea3ad80d077b3757', './modules/Administration/templates/themeSettings.tpl' => '80eef5be21cbff2a9e80e1bd33cd7d02', './modules/Administration/templates/ShortcutBar.tpl' => '0d2c2e9b5e15a1528e97fad95cace190', './modules/Administration/templates/RepairXSS.tpl' => 'cbf0b5ede9e0f8ff598cf3e9c3dbef9b', @@ -2853,9 +2900,9 @@ $md5_string = array ( './modules/Administration/templates/ConfigureTabs.tpl' => 'ef345ff226a317b2c66027d1d5e78e2d', './modules/Administration/repairSelectModule.php' => 'a7af51a5f7f6e5002f4963b80504c0d8', './modules/Administration/ncc_config.php' => '6fcf1f7bd93acbf9b0c7b3a890bdab9d', - './modules/Administration/metadata/adminpaneldefs.php' => 'ad3965327909144539e30ab90a646daa', + './modules/Administration/metadata/adminpaneldefs.php' => '648fd0de7e3a0188a621c14dac1b8f12', './modules/Administration/metadata/SearchFields.php' => '6968a40d78da694e44829ec8d00645e8', - './modules/Administration/language/en_us.lang.php' => '8bfda44a508c4eaa535372244f152343', + './modules/Administration/language/en_us.lang.php' => '0686080b0de6663c5161d81066c3471a', './modules/Administration/javascript/Administration.js' => '5c983c8146d2f8e537f0f826d0239834', './modules/Administration/javascript/Async.js' => '6201560d3cc38a32a3300606bce92541', './modules/Administration/index.html' => '2cc05387b7f392ee9891f97ff24e8f66', @@ -2874,19 +2921,19 @@ $md5_string = array ( './modules/Administration/expandDatabase.php' => 'db6782337c424a5aea39932c6c74b52a', './modules/Administration/UpgradeWizardCommon.php' => 'd6c694064904b67eaefdef81b4912b97', './modules/Administration/SupportPortal.tpl' => '25d5c2ffefc8becee74e0f45b196ca64', - './modules/Administration/repairDatabase.php' => '8de7ecd350e5516b099fa6dd0f0bfecd', + './modules/Administration/repairDatabase.php' => '93351ceaf8e7f5ec08cefd888b64f1ec', './modules/Administration/Save.php' => '4152bf2003831091369d76b24495386f', - './modules/Administration/vardefs.php' => '6a950e59140f943747c0ef6a5ce13733', - './modules/Administration/controller.php' => '83da0c6bf53f19c7347e656188f1db7d', + './modules/Administration/vardefs.php' => '8f61a204bacb7e18c17ea94e6eabde77', + './modules/Administration/controller.php' => 'dca978db03b55d5d218dc282b9c9f31b', './modules/Administration/RepairSeedUsers.php' => 'b9c8937676633e2860b38b3c5ab77f0c', './modules/Administration/RepairJSFile.php' => '43ac52009b5ee4364b2194b7d672d740', './modules/Administration/RepairXSS.php' => '2d56fb5ebf47019f684ddc0329d4ffa5', './modules/Administration/RepairIE.php' => '4d2065ceb6ff00779c187de7a38b93b1', - './modules/Administration/action_view_map.php' => 'a35695d1f72f0a3750618341ea6f9edb', + './modules/Administration/action_view_map.php' => '8ba9b78bb24fa0122befa97b20dcc591', './modules/Administration/UpgradeHistory.php' => 'c1cfbee38c2d4c00bfcd97f79dda267c', './modules/Administration/RebuildSchedulers.php' => '87ba4d901c73481d50e7f43aa526c5c3', - './modules/Administration/RebuildRelationship.php' => 'a405752d10246296741e191ad01bf1f1', - './modules/Administration/RebuildJSLang.php' => '77a853cac31de893caa29aafd8fab626', + './modules/Administration/RebuildRelationship.php' => '7f31de7a2d87ab7072e5df84fce8c48d', + './modules/Administration/RebuildJSLang.php' => 'a4dfe8f0964eca2d257a9719aad729bc', './modules/Administration/RebuildFulltextIndices.php' => 'e86776d7b093bfc168937773bf5e100e', './modules/Administration/RebuildExpressionPlugins.php' => '6af6f4d78936ff68209e410f5fb45601', './modules/Administration/RebuildDashlets.php' => '3f0ecb9aa99145779a8b8c3ee29099a8', @@ -2895,9 +2942,9 @@ $md5_string = array ( './modules/Administration/RebuildAudit.php' => '8d2fc35c83a49c038ca59d7ef54149b2', './modules/Administration/QuickRepairAndRebuild.php' => '745b5aa563e14810a4e0c51885aff222', './modules/Administration/PasswordManager.tpl' => 'd60c9df9a4d6cf63168fefa53f9b07de', - './modules/Administration/index.tpl' => '606ad7ab8d4dcab1715bc455dab35989', - './modules/Administration/index.php' => '54b4ed0b4645006346d676b85cb3bbd3', - './modules/Administration/SupportPortal.php' => '29a746ac29392464d1b28d9588395e7b', + './modules/Administration/index.tpl' => '1dbbee4c2ea3662b4416bbe4308ede53', + './modules/Administration/index.php' => '838b3b9755958147fdf7f6adabe3f8e1', + './modules/Administration/SupportPortal.php' => '05c3bcc46d9ac6f3159861d398b15409', './modules/Administration/Menu.php' => '96b575a9cdd9b92b4411aa316f57d1a3', './modules/Administration/RepairIndex.php' => 'cdc4da4fec0cef9a351dec1e7aa75f33', './modules/Administration/RepairFieldCasing.php' => '9ef826eb314c0086f7bb43b40a82276f', @@ -2941,8 +2988,8 @@ $md5_string = array ( './modules/Accounts/tpls/QuickCreate.tpl' => '994fcab80f63cc0f59f111fc30bf0430', './modules/Accounts/metadata/subpanels/default.php' => '066e3a2fb842892fbcae8009ce9576c4', './modules/Accounts/metadata/subpanels/ForProspectLists.php' => 'b6d33485aa7f8fa00f22677ff2d1f001', - './modules/Accounts/metadata/subpanels/ForEmails.php' => '0a45c17da8fcbce4e784ad7113909141', - './modules/Accounts/metadata/subpaneldefs.php' => 'ef800bededd816594742e07969471ecf', + './modules/Accounts/metadata/subpanels/ForEmails.php' => 'ed20cedf9edef7915345acff2257f560', + './modules/Accounts/metadata/subpaneldefs.php' => 'a7b2623f15f821aeea4eecac6bb57c20', './modules/Accounts/metadata/studio.php' => 'd1d79777052d975c08429b48fe02e235', './modules/Accounts/metadata/searchdefs.php' => '0f888761dac4782e8c6368377911b2ef', './modules/Accounts/metadata/quickcreatedefs.php' => '9b4038cd84095adb5001c92f9b6da280', @@ -2955,18 +3002,18 @@ $md5_string = array ( './modules/Accounts/metadata/additionalDetails.php' => '1041f63444dea59eb0688ec7f0e540b6', './modules/Accounts/metadata/acldefs.php' => 'c71ccae1e5951d02cb95b51cbd049bab', './modules/Accounts/metadata/SearchFields.php' => '3e2a6be335eec7b9bc6d6a9d37f3c5b1', - './modules/Accounts/language/en_us.lang.php' => '5d01907603c79b918fd764c59e2158fd', + './modules/Accounts/language/en_us.lang.php' => '77f7ed329defd71526763b830adbd0bc', './modules/Accounts/field_arrays.php' => 'cd7897f2613bf946144bae1a811b4c9d', - './modules/Accounts/ShowDuplicates.php' => '44ca2d50d7f42db81e0440f17007c376', + './modules/Accounts/ShowDuplicates.php' => '68b41fac7eed021f612d9449a7292c79', './modules/Accounts/ShowDuplicates.html' => '1d1e527082993b904ae3debeccb48785', './modules/Accounts/Save.php' => '79d53f9dc54e5481ac25f57e651d0366', - './modules/Accounts/Popup_picker.html' => 'cebb804e8edd4b8b33a88fa52f7914ab', + './modules/Accounts/Popup_picker.html' => '1c36335d4ae0ecf0575fca78965ae271', './modules/Accounts/Menu.php' => '89f567a768fd2d26f5314fc314f4e95e', './modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.php' => '521daaeaa445d3c13900572d4d6b2986', './modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.meta.php' => 'a4224d52da04efaf1c80bf0db8b0ca04', './modules/Accounts/Dashlets/MyAccountsDashlet/MyAccountsDashlet.data.php' => 'd881be66482e5c2f470849ae228eddf4', './modules/Accounts/AccountsQuickCreate.php' => 'fbb9c86de48897e1e95aae6201f52941', - './modules/Accounts/AccountFormBase.php' => 'a80b0c9ebadf92b1451b2e90fe4d3146', + './modules/Accounts/AccountFormBase.php' => '2170ad3c175746084bbb0dd9bfe75c69', './modules/Accounts/Account.php' => 'fce59e4b2ae90d1bceedc038d936eea4', './modules/ACLRoles/ACLRoles.js' => '2b2b8c4517f3d6a27b71f22d8b37b285', './modules/ACLRoles/views/view.list.php' => 'e40ad40a14a03cf692dd279b9616329a', @@ -3001,8 +3048,8 @@ $md5_string = array ( './modules/ACLRoles/ACLRole.php' => '777a7fbaca007322fdf5caaa21468a65', './modules/ACLActions/vardefs.php' => '105b4a9bc0de199ce7c6f7bed15ee783', './modules/ACLActions/metadata/subpaneldefs.php' => '828de1877beb0908c89bbd37b903b5bf', - './modules/ACLActions/language/en_us.lang.php' => '238308c423eb13c1e28d1b5416b0faa3', - './modules/ACLActions/actiondefs.php' => '6356876a5a119274d46223f3e2bc4789', + './modules/ACLActions/language/en_us.lang.php' => 'a2470d54b9a6048dd38685611f81d315', + './modules/ACLActions/actiondefs.php' => 'bed97cf7a2701caafa30ab88bc109cae', './modules/ACLActions/Menu.php' => '848677adce001bc11ce4a9776c71766f', './modules/ACLActions/Forms.php' => 'd41d8cd98f00b204e9800998ecf8427e', './modules/ACLActions/ACLAction.php' => 'c5a4b74f755b0613b028496df3d5c840', @@ -3018,6 +3065,7 @@ $md5_string = array ( './modules/ACL/ACLJSController.php' => '672095d014e812a6e110b6b4f56140e8', './modules/ACL/ACLController.php' => 'c778eabd3749eb9e10d1b7dcda9a32a5', './metagen.php' => '62a1a86726ac5b1adec53a08b43ab679', + './metadata/oauth_nonce.php' => 'ac0ffa573846e51f72170d4faf520067', './metadata/documents_opportunitiesMetaData.php' => '26fbc5dded5aae3ae2ab0e6ab4deac75', './metadata/documents_contactsMetaData.php' => 'a67e4da2de7849bd1080724237b2abd4', './metadata/documents_casesMetaData.php' => '93a30ebba6c3ec9978a9dce3cf426f90', @@ -3054,7 +3102,7 @@ $md5_string = array ( './metadata/inboundEmail_cacheTimestampMetaData.php' => '6918e6fafab3b7837401043d17fdfa39', './metadata/inboundEmail_autoreplyMetaData.php' => '5108c36c3af1ce2d5d55601b7a5e39ae', './metadata/import_mapsMetaData.php' => 'ee7622131bed93ab594f45073c946b39', - './metadata/foldersMetaData.php' => '29c96eab585020c4a167e1e115f8d486', + './metadata/foldersMetaData.php' => 'f96175c7172242e0c32c7f8d11dc9e44', './metadata/fields_meta_dataMetaData.php' => 'ee7622131bed93ab594f45073c946b39', './metadata/emails_beansMetaData.php' => '54332fa8970e60edd5375fae86b370fb', './metadata/email_marketing_prospect_listsMetaData.php' => '687acd34468742757d3039e3233f36d8', @@ -3063,10 +3111,10 @@ $md5_string = array ( './metadata/custom_fieldsMetaData.php' => 'cea17006dfee55c7d754186eefe86e22', './metadata/contacts_usersMetaData.php' => '5bc7dcf867b8422c5cf8f83fcc1b9bbd', './metadata/contacts_casesMetaData.php' => '9a69749b36c99e0748da33a27e5006cb', - './metadata/contacts_bugsMetaData.php' => '0e7519950433ba15b9dde4238c16adaf', + './metadata/contacts_bugsMetaData.php' => '17e3682aa1a696e4eb5d2200859f2dcf', './metadata/configMetaData.php' => 'ee7622131bed93ab594f45073c946b39', './metadata/cases_bugsMetaData.php' => '2f94fc5b204aa54fcad49325d511523e', - './metadata/calls_usersMetaData.php' => 'ffe606c60da2e557bb7f5877a1ab2998', + './metadata/calls_usersMetaData.php' => '47b0a923dcaca600e1535f301ef04d00', './metadata/calls_leadsMetaData.php' => '1a401236211d9ec7a1df4f0701452e96', './metadata/calls_contactsMetaData.php' => '3618492e26f1719425be140436f502e7', './metadata/audit_templateMetaData.php' => '579ac6798fba2db43e8325dc3309cdc4', @@ -3081,37 +3129,37 @@ $md5_string = array ( './log_file_restricted.html' => 'f20a0bfe3ac44ba88f520fb8203a70e4', './log4php/LoggerManager.php' => 'fa34194306cd50c01b71d8d5060ee362', './leadCapture.php' => '39f9c34cbfb01f585a6c04227823c65f', - './jssource/src_files/include/MySugar/javascript/MySugar.js' => '345a40c52beb881a6ad33b8ea526b248', - './jssource/src_files/include/SubPanel/SubPanelTiles.js' => 'b65c9d967a27614395b6857edce04539', + './jssource/src_files/include/MySugar/javascript/MySugar.js' => 'd64381f227321f58e08c37e24dbc0f04', + './jssource/src_files/include/SubPanel/SubPanelTiles.js' => '6aca28bfbf409e27c730b2f2d09203bb', './jssource/src_files/include/SugarCharts/Jit/FlashCanvas/canvas2png.js' => '4c95a8c2071e0d5b4ae1531a790f1492', './jssource/src_files/include/SugarCharts/Jit/FlashCanvas/flashcanvas.js' => '72c44a4bca6418bb7ee5e7c5b7781e3f', './jssource/src_files/include/SugarCharts/Jit/js/Jit/jit.js' => 'eafefe546e88997558054191c83a00e2', - './jssource/src_files/include/SugarCharts/Jit/js/mySugarCharts.js' => 'bbbca8b9bb44d0f107a2783fe1cf861d', + './jssource/src_files/include/SugarCharts/Jit/js/mySugarCharts.js' => 'bb8a2f5badbe46e22e07933cc66c2fff', './jssource/src_files/include/SugarCharts/Jit/js/sugarCharts.js' => '72eba4ec918665ffa582c6fec16d2c78', './jssource/src_files/include/SugarDependentDropdown/javascript/SugarDependentDropdown.js' => '82905de42674faa12e819f99d3db0610', - './jssource/src_files/include/SugarEmailAddress/SugarEmailAddress.js' => '86480cd5e5e0d81cdedd4975e872a0a9', - './jssource/src_files/include/SugarFields/Fields/Address/SugarFieldAddress.js' => '2e39ad35e6759c407fae5b35b230d34b', - './jssource/src_files/include/SugarFields/Fields/Collection/SugarFieldCollection.js' => '99af73a152a0cc58ac14e895ba569fa6', + './jssource/src_files/include/SugarEmailAddress/SugarEmailAddress.js' => '40940b800b4b851151002ee1459392fc', + './jssource/src_files/include/SugarFields/Fields/Address/SugarFieldAddress.js' => '05610c1f440fc0dd6de61b3ae1154aaf', + './jssource/src_files/include/SugarFields/Fields/Collection/SugarFieldCollection.js' => 'd0c3a690789d94d4b5d88bf99abdd3d0', './jssource/src_files/include/SugarFields/Fields/Datetimecombo/Datetimecombo.js' => '7f93acedc02d390800eaad0e5fc22cae', './jssource/src_files/include/SugarFields/Fields/File/SugarFieldFile.js' => '11edcc9ea0960ae5e5e4e1ef20a94ab0', - './jssource/src_files/include/connectors/formatters/default/company_detail.js' => 'ac718b13fd22689d7da786dcb0b0380c', + './jssource/src_files/include/connectors/formatters/default/company_detail.js' => 'ed4d3af5b705c28c37d60cd7eb118c55', './jssource/src_files/include/javascript/cookie.js' => '4edb43519c5ac8c3d9b1b73b9ddf87fb', './jssource/src_files/include/javascript/dashlets.js' => 'c85774c7bcc3568d50e71448dbb371af', - './jssource/src_files/include/javascript/include.js' => '4fd5d7da5c00e4c0a9a83b4b65a493f1', + './jssource/src_files/include/javascript/include.js' => '569fbc452038128da8111871d9094ed5', './jssource/src_files/include/javascript/jsclass_async.js' => '8e8694a9e136c6736ac3fe87d9ace2b1', - './jssource/src_files/include/javascript/jsclass_base.js' => '73f529e1ed6a9a38d432e30816f87e02', + './jssource/src_files/include/javascript/jsclass_base.js' => 'ef96b7ba20a601f2fed2ff94f1cb0eb0', './jssource/src_files/include/javascript/menu.js' => 'a12b42e2406a9b192609258884536efd', - './jssource/src_files/include/javascript/overlibmws.js' => '9fb2df046948fb09baf9bf62cf8d7877', - './jssource/src_files/include/javascript/overlibmws_iframe.js' => '3714ae1a5be03f1470b30e8920386d14', - './jssource/src_files/include/javascript/popup_helper.js' => '39c5944f361b4b1ff1e7c74d8bb000be', - './jssource/src_files/include/javascript/popup_parent_helper.js' => 'e7daf641d1691db7dfa7464efab1a706', - './jssource/src_files/include/javascript/quickCompose.js' => '2ae2e20213ad5341de324c92bb5035d3', - './jssource/src_files/include/javascript/quicksearch.js' => '751e98b3b4c21b2585d3d706249c800b', + './jssource/src_files/include/javascript/overlibmws.js' => 'baaf046aa93f29e370d17b31e0d66e16', + './jssource/src_files/include/javascript/overlibmws_iframe.js' => 'b250fc67fe7d6812a41b528ac39083bc', + './jssource/src_files/include/javascript/popup_helper.js' => '6be37795c9d2b6a5c99d210f84731324', + './jssource/src_files/include/javascript/popup_parent_helper.js' => '41624ffc3d0b63a35832775a09b24bc3', + './jssource/src_files/include/javascript/quickCompose.js' => 'fa983d3c19912b130583a15387fa5e6c', + './jssource/src_files/include/javascript/quicksearch.js' => 'b95bea8ff6622dc39b84dad7acc25d18', './jssource/src_files/include/javascript/report_additionals.js' => '134d3cd895ad1e0470f9dd07c7b34ad1', - './jssource/src_files/include/javascript/sugar_3.js' => 'a4ebdb5fc2259088e804e71ea75eabc5', - './jssource/src_files/include/javascript/sugar_connection_event_listener.js' => 'd13aa0b553050db12f7bd6cd5b7b98f9', + './jssource/src_files/include/javascript/sugar_3.js' => 'c4de3c17746db1da7be484849ccf96c6', + './jssource/src_files/include/javascript/sugar_connection_event_listener.js' => '60c2a539c4e42bbd9c9e8fa5ca3dfd72', './jssource/src_files/include/javascript/sugarwidgets/SugarYUILoader.js' => '9237f12850b7ce5c27669480f71152be', - './jssource/src_files/include/javascript/sugarwidgets/SugarYUIWidgets.js' => 'eb797deed072e18109821ab136366c49', + './jssource/src_files/include/javascript/sugarwidgets/SugarYUIWidgets.js' => '5cb3faa95abcca01241a06c46cc609e0', './jssource/src_files/include/javascript/swfobject.js' => 'a7dc61c4ada3b828e0e09e51f943c6db', './jssource/src_files/include/javascript/yui3/assets/dpSyntaxHighlighter.js' => '9f8e259fd1682f21971db93c2465812a', './jssource/src_files/include/javascript/yui3/assets/syntax.js' => '4099ad678b4ce516afa04ba6b112a568', @@ -3874,8 +3922,13 @@ $md5_string = array ( './jssource/src_files/include/javascript/yui3/build/widget-anim/widget-anim.js' => '73dda979e61a729d65d9fde370194b70', './jssource/src_files/include/javascript/yui3/build/yql/yql-min.js' => '9d94bc7ae9cf56021a5dc3f454a5b8bb', './jssource/src_files/include/javascript/yui3/build/yql/yql.js' => 'e1a2b802089686337415bcbdc54c23f6', - './jssource/src_files/include/javascript/calendar.js' => '79f84bdbff22bf026d5c83325db18d82', + './jssource/src_files/include/javascript/ajaxUI.js' => 'e2b405f16744b9d07033d27575d3e90f', + './jssource/src_files/include/javascript/calendar.js' => 'da8f5fca74acc32edff682b17c8662e5', + './jssource/src_files/include/javascript/importWizard.js' => '5473123f038ab6e27a335c7630035c77', './jssource/src_files/include/javascript/iscroll.js' => 'b6c232e3c54b2a1320b22c7ad920c842', + './jssource/src_files/include/javascript/phpjs/get_html_translation_table.js' => '9667941dd790119d552f99b6d6b73fdf', + './jssource/src_files/include/javascript/phpjs/html_entity_decode.js' => '022ed687a9c7c55a21b4a2aaa848921d', + './jssource/src_files/include/javascript/phpjs/license.js' => '8d1e879645acd34b64c2270879203213', './jssource/src_files/include/javascript/sugar_yui_overrides.js' => '1638a8c085f483f30b52b83dd4fa6c03', './jssource/src_files/include/ytree/TreeView/HTMLNode.js' => '80d3d7b998e77999da2cd4fb0168ab68', './jssource/src_files/include/ytree/TreeView/MenuNode.js' => '78c155839f99bc3564183e1557d15d3f', @@ -3908,14 +3961,14 @@ $md5_string = array ( './jssource/src_files/modules/Documents/documents.js' => '5110ec40afe540ecd0bd44dfe41176e8', './jssource/src_files/modules/EmailTemplates/EmailTemplate.js' => 'b7a20a46340cb552cb0600dc4bc37f23', './jssource/src_files/modules/Home/about.js' => '3c3184898479de9affd42a03e8db87a3', - './jssource/src_files/modules/InboundEmail/InboundEmail.js' => '3853f33e9a0a903d50e2c110be0c9f25', + './jssource/src_files/modules/InboundEmail/InboundEmail.js' => '194b89bb42afc715d18e1a6db0395e41', './jssource/src_files/modules/Leads/Lead.js' => 'd2051b0acd9fe3629453e0435e2e1610', - './jssource/src_files/modules/Meetings/jsclass_scheduler.js' => '084413507072d0ee8d390d8bcd0d75d8', + './jssource/src_files/modules/Meetings/jsclass_scheduler.js' => 'b95fdc1d8503c481e2f64bbe33dafb99', './jssource/src_files/modules/MergeRecords/Merge.js' => '72d3c3cb81d09251b26f7af7f360f7d8', './jssource/src_files/modules/Project/Project.js' => '209339b60de2b61a57460aef2f8597f8', './jssource/src_files/modules/ProjectTask/ProjectTask.js' => '72be31b984cbb1713e85970f2cd54aef', './jssource/src_files/modules/Studio/JSTransaction.js' => '2f20a4a72eaa8cbdf3053e24c5772ee5', - './jssource/src_files/modules/Studio/studio.js' => '65a10d40fee3188acc67a42e3fe9ca23', + './jssource/src_files/modules/Studio/studio.js' => 'fdcaaeeb20ae699419c88cd4a2709ac3', './jssource/src_files/modules/Studio/studiodd.js' => '454916d3c66c5379b4ec689943210e02', './jssource/src_files/modules/Studio/studiotabgroups.js' => '2941525a8832b5ac29990c649df21787', './jssource/src_files/modules/Studio/ygDDListStudio.js' => 'c89afaff39a354e78d231062bd2bfba0', @@ -3926,12 +3979,12 @@ $md5_string = array ( './jssource/src_files/modules/Users/login.js' => '69672083d59632d4c2f588cb935517d1', './jssource/src_files/modules/EAPM/EAPMEdit.js' => '9dfb27982424e9f82a9aeea22c4f0247', './jssource/src_files/service/utils/SugarRest.js' => '54c5ac98bda01fd9d609f0d9aa762763', - './jssource/src_files/themes/Sugar5/js/style.js' => 'c8620b080d12b33473d62a201cf04187', + './jssource/src_files/themes/Sugar5/js/style.js' => 'c2362763d01d53de3699d4b527b76ad6', './jssource/src_files/themes/default/js/style.js' => '65a0e333fd3833dbd11d61859546e2da', './jssource/minify_utils.php' => 'fafc5475a1d95f6b80f8c24459918094', './jssource/minify.php' => '219023f793e8ed83e536771bffcd988c', - './jssource/jsmin.php' => '70558acc143de9506c866b0056dcf416', - './jssource/JSGroupings.php' => '49859729343ee71f88e7ee045e90097c', + './jssource/jsmin.php' => '1ab5658de8334b5200dd571b4f9fb318', + './jssource/JSGroupings.php' => 'b2b9a0828ab785f9e94eca80190cdb59', './maintenance.php' => '72efcf842406e81fb8640a621afbdd68', './install/dbConfig.js' => '34408e61d47a775a3cb67971bb710522', './install/installCommon.js' => '9177e605553bb2a6619179d0e5dffc57', @@ -3951,8 +4004,8 @@ $md5_string = array ( './install/siteConfig_a.php' => '17e8c6a41d5f4d3469e123ee98f93f7d', './install/licensePrint.php' => 'f569be1d51e52d0067ec1b2845a4c9b1', './install/license.php' => '6739f461680a5a40971d83bc7b66b7ef', - './install/language/en_us.lang.php' => '0766f207910b4fad1006f63cb88be2e4', - './install/performSetup.php' => '2bb6d7a8d890d91050992925213359cd', + './install/language/en_us.lang.php' => '9ce2da4eac16c33d493b2c7981cfaf18', + './install/performSetup.php' => 'c36404b4e82f3f2c257d4e2dffcf76ec', './install/install_defaults.php' => '3c67b082c1709e909dd1aaf051e9c589', './install/installType.php' => 'cc447dd870b6eb51027abeb4d4674087', './install/installSystemCheck.php' => 'd8b035f439553f09bb2a03a66fd36e4a', @@ -3961,8 +4014,8 @@ $md5_string = array ( './install/install.css' => '862e23df1815d0138cf0a367d92a372d', './install/download_patches.php' => 'c1942d9e73b9ce80eb645e4ec925a5e0', './install/download_modules.php' => '4623d65fa913da9559e1bdd296f4e887', - './install/install_utils.php' => 'd5e563414334735d3ac165f8c3f53d54', - './install/populateSeedData.php' => '8867869db5ca3f45cef110ec4515152d', + './install/install_utils.php' => '22d6e5dc1285ba45f626d340af0276c2', + './install/populateSeedData.php' => '4371d676db68cbd1c9d7e5d9099495af', './install/demoData.en_us.php' => 'ab6d0dc87a9f421e843ac454aec4546a', './install/dbConfig_a.php' => 'ea11513c27fe2c5cdc0241a1fe744cfb', './install/data/disc_client.php' => 'e4574285e612f49e6a5b002e3bf0b6c9', @@ -3972,16 +4025,18 @@ $md5_string = array ( './install/UploadLangFileCheck.php' => '011b7ae7a9711e6eb231155e24c66e63', './install/TeamDemoData.php' => '1cf512bcb6834cdac2c154b2f42d14cd', './index.php' => '85d2f32e8b794128592f116a91fcef72', - './include/externalAPI/ExternalAPIFactory.php' => 'a94627b0b015083319f1df55b37b652e', + './include/parsecsv.lib.php' => 'df08e6f9ccaa1ca448893ead93611592', + './include/externalAPI/ExternalAPIFactory.php' => 'de4bbe6b07d197a4380226ff0da5e830', './include/externalAPI/Base/WebMeeting.php' => '53cbdd0ac77fde2542711093c64f83b9', './include/externalAPI/Base/WebFeed.php' => '6ce8b5213a9f52991c30a9597686aa9a', './include/externalAPI/Base/WebDocument.php' => '728f703b0dd2bcf9845b033142532416', './include/externalAPI/Base/OAuthPluginBase.php' => 'cb6be82d3c58c7594eb92f364fe909f0', './include/externalAPI/Base/ExternalOAuthAPIPlugin.php' => '68a07294ba03848f6d8c0e7185218e7d', './include/externalAPI/Base/ExternalAPIPlugin.php' => 'bb7ebb6a9a077b5566301e1e91d7ac46', - './include/externalAPI/Base/ExternalAPIBase.php' => '1cf9620929e1bee7faf4b0983b82acb2', + './include/externalAPI/Base/ExternalAPIBase.php' => 'ca7040da39f9dc7d39a8d5b8af4ad66e', './include/SugarOauth.php' => 'd24af34a6a5ae0b8e6a1be649e84acf7', - './include/SugarDateTime.php' => '518a6813da5d0c6cdba79864ff6be772', + './include/SugarOAuthServer.php' => 'c2dc2a87be5d577f7424d1e346fd58cd', + './include/SugarDateTime.php' => '3795125c2b1af189fff5ddc0b26d6bf2', './include/ytree/treeutil.js' => '5b4d6de1dc71dc826bc04337b8d7a466', './include/ytree/TreeView/HTMLNode.js' => 'f73d59166b242b7a8d43a4c597d96f80', './include/ytree/TreeView/MenuNode.js' => 'b80e41c7de13feb9a995dc8e4a57a21f', @@ -4052,26 +4107,26 @@ $md5_string = array ( './include/ytree/Node.php' => '537ea99369cc451f6d02e6ccd33c4eec', './include/ytree/ExtNode.php' => 'f4bcdda0640f5ad72e95835419b59435', './include/vCard.php' => 'b0fd80da757645cadc8c9cb11e69aa6a', - './include/utils/php_zip_utils.php' => '776cdb257fd48ca212940f60687cd149', + './include/utils/php_zip_utils.php' => '16405813e3661d1991cc38b840c1ea1c', './include/utils/sugar_file_utils.php' => '5dbecfc86fec0dcd5c15d69c9c68758e', './include/utils/security_utils.php' => '5848837442f97823077e87a384e7e691', './include/utils/progress_bar_utils.php' => 'c38627c8c832e31a0f524151491efbb5', './include/utils/zip_utils.php' => '8b0e9094a1a418d1d0dacfd58620d704', './include/utils/logic_utils.php' => '34cee1496e20f3eee7ae4ad76e5e14c5', - './include/utils/layout_utils.php' => 'e7b465492ed76893b109e2baa31cabea', - './include/utils/file_utils.php' => 'cd7b33adab01fd36d0953e40a336dffd', + './include/utils/layout_utils.php' => '402a7ef6e0970a5a80b2d8e3b89df84d', + './include/utils/file_utils.php' => '9fba4b2638aa5aff8259020d7dc764e7', './include/utils/external_cache.php' => '4138cf307fea4ca68817b4c80250cab0', - './include/utils/mvc_utils.php' => '3f71726a65f0ab5126ae7ddb56f21240', + './include/utils/mvc_utils.php' => '7b7536bb6464a28aba831cde367e46db', './include/utils/encryption_utils.php' => '060b4fa727c1d48fa8ec2809e2fb58cf', - './include/utils/db_utils.php' => '9b3d1516d07438b8cac025baf539fcc0', - './include/utils/autoloader.php' => '76818f941992acf4caa205cc6f2aa0c9', + './include/utils/db_utils.php' => 'c44e8bd99d998f73e47cd9f7935f1150', + './include/utils/autoloader.php' => '684b00fa5ca181b4f5635334099d24c0', './include/utils/array_utils.php' => '4a63065e0ab62bfc33b9429f886ed7ec', './include/utils/activity_utils.php' => '96a8bd8977d5e7532e3b7d8ca3a583ee', - './include/utils/LogicHook.php' => '3d65be3d74e10ecdf5aee20b2efceee6', - './include/utils.php' => '1a282c9951e07b67e9728eda052975cc', + './include/utils/LogicHook.php' => 'd08b32b0727e67338f1292b7de65c45e', + './include/utils.php' => '66cd7837630dc8203bd26fb19861493e', './include/upload_file.php' => '177f5eb2032e0c7797e11f93efb759f3', './include/timezone/timezones.php' => '68c833b6b839c9e4d80a3bb21740d6e5', - './include/templates/TemplateGroupChooser.php' => '111b7db20ad8143651bc7bba835894df', + './include/templates/TemplateGroupChooser.php' => '705dfff2efc56e000ff5012af7ce15f9', './include/templates/TemplateDragDropChooser.php' => '1fd1388bfd445beeb715a78cf5fbafe5', './include/templates/Template.php' => '5b1709f5a4cf514bfe1f05f074340640', './include/tcpdf/unicode_data.php' => 'd20008bba6110e94611ac0939a92913b', @@ -4163,38 +4218,44 @@ $md5_string = array ( './include/nusoap/class.soap_fault.php' => 'bf058747b0ecefe183194300dbd73dff', './include/nusoap/class.nusoap_base.php' => 'cf8310e722c8fc7e310dc5ba413b1ea6', './include/nusoap/changelog' => 'd75ed67ec93c02e5bce94eee8205b425', - './include/modules.php' => 'b016b295433b3b4d54c08eca90a566b4', - './include/language/jsLanguage.php' => 'f39b23266c5f25d253082afb6a210fe2', + './include/modules.php' => '158c181f02495f8640e788ea8c9dcf57', + './include/language/jsLanguage.php' => 'e5d77d52c812648dc2be7791531be294', './include/language/en_us.notify_template.html' => '4e90b0343ac29bf12687dddb15afea7d', - './include/language/en_us.lang.php' => 'f2b2332a9bc1ba04b65d01b76b66a64c', + './include/language/en_us.lang.php' => '397f53109a0d13b71f453f4dc5242c96', './include/json_config.php' => '73219c3de81147aa2e18580b497353e6', - './include/javascript/sugar_grp_quickcomp.js' => '840b010ffdf7b7919b2683e356fcdbfe', - './include/javascript/sugar_grp_emails.js' => '7082053d2bea65b26b1e5e840c97d429', - './include/javascript/sugar_grp_overlib.js' => '1ae8c7614a7ed6e6b21806f191bb2ae2', + './include/javascript/sugar_grp_jsolait.js' => '93083b47ea6b1f05be3e0d7284aec3f7', + './include/javascript/sugar_grp_quickcomp.js' => '7485350358ba7dcbfab96e77c53eaab7', + './include/javascript/sugar_grp_emails.js' => '93e42609d375b1520c613487f4cac7c6', + './include/javascript/sugar_grp_overlib.js' => 'd1af18f5bf386f5b208e467e6e22e46f', './include/javascript/sugar_grp_yui2.js' => '613bb6a5e0e5e934a88293f6ae2ffa43', './include/javascript/sugar_grp_yui_widgets.css' => '87d9287720879ff935fa2b80690ede5e', - './include/javascript/sugar_grp_yui_widgets.js' => '7cc525f73e9a0e49bbbb06363813c84b', - './include/javascript/sugar_grp1_yui.js' => '2e8034083b6cf4f72bd45ca10aff5a34', - './include/javascript/sugar_grp1.js' => 'f649d14ea9123f176d57650e59bd46d1', + './include/javascript/sugar_grp_yui_widgets.js' => 'f7562f8ff8bff22cf193a9d212b6bf29', + './include/javascript/sugar_grp1_yui.js' => 'e98c92b5f0c4285764d85aa04b32da8a', + './include/javascript/sugar_grp1.js' => '51591bcd5f60c2251301fee3310772f6', './include/javascript/cookie.js' => '4f95a2872a549573149d035633086662', './include/javascript/dashlets.js' => '208d5f32d367390faadda8e899f99b77', - './include/javascript/include.js' => '1b6f04c9cdbc1f25b3c4de8e049a2433', + './include/javascript/include.js' => '278e187b101eb3a5871f3bce021cdb62', './include/javascript/jsclass_async.js' => '15b2b4ecf1010a43608634cfbd6d17a2', - './include/javascript/jsclass_base.js' => '848b03e3cf892fe9ba21e85df0e25848', + './include/javascript/jsclass_base.js' => 'a13cae0c604a511e4cf2e9eb6150e029', './include/javascript/menu.js' => 'bab1eb80c6cf5cb048efc10e9eec8aaf', - './include/javascript/overlibmws.js' => '5e18c62656d6c7fd4db7b220508a2df7', - './include/javascript/overlibmws_iframe.js' => '1106371e305114a18d5a5186cf24343e', - './include/javascript/popup_helper.js' => 'c1cd07f47d71096559968844fe675a7e', - './include/javascript/popup_parent_helper.js' => '2549c3668f01e9b28eff1a62418d35c6', - './include/javascript/quickCompose.js' => '8fbd8976c73311dfe73d4124949b8118', - './include/javascript/quicksearch.js' => '1bf7a688b074ca65f2d2f499ebb844b8', + './include/javascript/overlibmws.js' => '66a898aad7f5de44cae6d97016ae91dd', + './include/javascript/overlibmws_iframe.js' => 'aae059277f699dde6451e92c51a3746d', + './include/javascript/popup_helper.js' => '624081de798ef3e853c67d06a1b422b7', + './include/javascript/popup_parent_helper.js' => '92dfee2b7bf6f56ab176ac8f0d0d672b', + './include/javascript/quickCompose.js' => 'd5ea61432b8795e0d25d1bc606ea5a51', + './include/javascript/quicksearch.js' => '766053dbb28ec36768a7aece97faa4f0', './include/javascript/report_additionals.js' => '6edec1a89ec68998008c4469f2d00e13', - './include/javascript/sugar_3.js' => 'ec1f476e52aeaf4bf122df01c7d6a1b6', - './include/javascript/sugar_connection_event_listener.js' => '4a3c4a128bbbcd0817a07cb0e7423d92', + './include/javascript/sugar_3.js' => '2f7f0563474a39215437d4605244226b', + './include/javascript/sugar_connection_event_listener.js' => '3fce076d38f2e5632e348833ebb26cd7', './include/javascript/swfobject.js' => 'e83d1ca12de8ee2787c9189119cbd959', - './include/javascript/calendar.js' => '74e959df9c5364713a6b3bca6ea926ad', + './include/javascript/ajaxUI.js' => '012780cb555b4227e56190ead47644d9', + './include/javascript/calendar.js' => '34eb209f70a39a4e1e20b717a40d0978', + './include/javascript/importWizard.js' => 'ef5f54c871024a0ddea59b4885ddb1df', './include/javascript/iscroll.js' => 'f2f4abe47439bfe02f0001e51dcbd0cd', './include/javascript/sugar_yui_overrides.js' => '8b8fb375212373da32e94c349c101a31', + './include/javascript/phpjs/get_html_translation_table.js' => '22a0ed714aba17b6b5d2b75299ffb0d4', + './include/javascript/phpjs/html_entity_decode.js' => 'f6f2aec36c768d08e77626c99b12be70', + './include/javascript/phpjs/license.js' => 'acd940d08b1d045602fa13f1b1f30a94', './include/javascript/yui3/index.html' => '34db637b1b8f7789823bda3e0da02864', './include/javascript/yui3/build/yql/yql-min.js' => 'e3582bda8b9a7f16f6528d760b738e5a', './include/javascript/yui3/build/yql/yql.js' => '3073cfe7d59ad9fb70d82c847d618a3d', @@ -5857,20 +5918,25 @@ $md5_string = array ( './include/javascript/tiny_mce/license.txt' => '045d04e17422d99e338da75b9c749b7c', './include/javascript/tiny_mce/langs/en.js' => 'df79faa676ad0876ad07b3618ef468a9', './include/javascript/sugarwidgets/SugarYUILoader.js' => '03e5f141de87cd45e0e44ffc4fc60e78', - './include/javascript/sugarwidgets/SugarYUIWidgets.js' => '75fcc837e971488cb623d134e4a585a2', - './include/javascript/jsAlerts.php' => '50f47b26a05a3e41a209691bbc204d30', - './include/javascript/javascript.php' => 'e46b3891cef038dc7e74c039ca05b82a', + './include/javascript/sugarwidgets/SugarYUIWidgets.js' => 'a43c63fe55d1750e8012bff89d93be78', + './include/javascript/jsAlerts.php' => 'a2a9420418b7443121e6e6f6599eb92c', + './include/javascript/javascript.php' => '5412235d2b3d986b7cee7d27bc65f82a', './include/javascript/getYUIComboFile.php' => 'd961ed2c8a1692920b1bf9bbe6cc9884', + './include/images/university2.png' => '346083109b89352e3a4b77cc249c56df', + './include/images/start.png' => 'c99fa1ea628b5d14f904b16cb9e010de', + './include/images/settings.png' => '81fd460af1be5ca4b72136ea02f21f27', './include/images/seed_will_id.gif' => '2f106be21d1591fcb91636594eeb1689', './include/images/seed_sarah_id.gif' => 'e2f269d97a3a3f500dff75b770d6c6b1', './include/images/seed_sally_id.gif' => 'cf29cdbd09b88a5f0f8f038b5f6b1db6', './include/images/seed_max_id.gif' => 'e208059a38b9899e47b9e3dad65e8888', './include/images/seed_jim_id.gif' => 'ccdaf0d492f924e8af2611b374550abd', './include/images/seed_chris_id.gif' => 'ec816fe3d80053c5225890e838a5813e', + './include/images/import.png' => '7d0b32092c3ac09648d3c1b111a04eec', './include/images/default_user_feed_picture.png' => '76d7a79b8b448b05b7e0107d72222b95', + './include/images/create_users.png' => '508f9614da6dc86d9ad90b486798c7f6', + './include/images/configure.png' => 'f12c66ea7f6af68e4a8649c2c9aa6fcb', './include/images/1.gif' => '9560abd50536d3d57c23316c75f93fe7', - './include/images/wiki.png' => '6d21a744511a1b55378fbc985daac0e4', - './include/images/university.png' => '346083109b89352e3a4b77cc249c56df', + './include/images/university.png' => 'd779a477591af9d7236120e86647e7df', './include/images/sugarsales_myarea.png' => '32a23fbbf16b4d48f2e07292818d8ace', './include/images/sugarcrm_login.png' => 'afc309ed136be87743408f886b2c50b2', './include/images/sugarcrm_copyright_logo.jpg' => 'cab0f0a114f2df12d8a5a4ec3fe3ad2a', @@ -5880,7 +5946,7 @@ $md5_string = array ( './include/images/sugar_icon.ico' => '92f1ffd4b2fef157613e48d2d2c7d9c8', './include/images/spacer.png' => '7df3dbe42ba6f94e0373ba374a2c5a74', './include/images/rss_xml.gif' => 'd69bb576307f6ccb889d7acc96303edf', - './include/images/poweredby_sugarcrm.png' => 'f3ad3d8f733c7326a8affbdc94a2e707', + './include/images/poweredby_sugarcrm.png' => '824e7e65a3b7901cb0a1d53a80ad9310', './include/images/powered_by_sugarcrm.gif' => 'fbc4de76cab648346bd7273823e0a0e2', './include/images/options_up.gif' => '9307eb60df1cc0151bae58e5a64506c1', './include/images/options.gif' => '8670274891572e477026ce53702ba140', @@ -5893,24 +5959,26 @@ $md5_string = array ( './include/images/cube_bg.gif' => 'bb01880551373dc9a2056697be69e5c1', './include/images/blank.gif' => 'fc94fb0c3ed8a8f909dbc7630a0987ff', './include/images/SugarPlanet.swf' => '5af57f2ee896225c65d9411aa2a1b971', - './include/globalControlLinks.php' => 'e799fcdc1c62c64cad1e510c27ec4eb0', + './include/globalControlLinks.php' => '1a4d46daeaa70e66ecb51b73c948c1ae', './include/generic/SugarWidgets/SugarWidgetSubPanelTopSelectAccountButton.php' => 'c2e868618957d4ca35672856c08c84a2', './include/generic/SugarWidgets/SugarWidgetSubPanelRemoveButtonAccount.php' => '503004a448632edb80bf9e300af04e15', + './include/generic/SugarWidgets/SugarWidgetSubPanelRelFieldEditButton.php' => 'c000ab3e3ad2904f239b449c84d3d895', + './include/generic/SugarWidgets/SugarWidgetSubPanelDeleteButton.php' => '507b66ce51ebc52779327c1a1e045219', './include/generic/SugarWidgets/SugarWidgetFieldfile.php' => '505f0a17d9490b2ad3d1b9aba1796b5f', './include/generic/SugarWidgets/SugarWidgetSubPanelTopSummaryButton.php' => '9c9f46e0a17dbaa7e9fbe95d670306fa', './include/generic/SugarWidgets/SugarWidgetSubPanelTopSelectUsersButton.php' => '5e1402674ccb9c3db535a3627f45836f', './include/generic/SugarWidgets/SugarWidgetSubPanelTopSelectContactsButton.php' => 'b4863f588fa57d44d48bb3226aa62ec0', './include/generic/SugarWidgets/SugarWidgetSubPanelTopSelectButton.php' => '7b5a0c19b6b163427de41b1cb31a6982', - './include/generic/SugarWidgets/SugarWidgetSubPanelTopScheduleMeetingButton.php' => '3f0fb7d6136ab89f3b2bdaea84603212', - './include/generic/SugarWidgets/SugarWidgetSubPanelTopScheduleCallButton.php' => '2b706da6c89cb59c509f74547a5494dc', - './include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateTaskButton.php' => 'e6eca9b6c3307b3f1b9398efe4a8ffd2', - './include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateNoteButton.php' => '0af6c5516be4b0426bc43098dfd5ff4a', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopScheduleMeetingButton.php' => '05f21e325b8794fc9e4ebc28f86e8e7f', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopScheduleCallButton.php' => '16f8a79e206a41d665e953de92cac3df', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateTaskButton.php' => 'ccd9dd25653431e304d484e10c087323', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateNoteButton.php' => '893a1929fa9da6d91ce6ad68be646f9a', './include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateLeadNameButton.php' => '667eb6757dbf32f9c181eab154c2117a', './include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateCampaignLogEntryButton.php' => 'd26f66486c121b664a807625689b9337', './include/generic/SugarWidgets/SugarWidgetSubPanelTopCreateAccountNameButton.php' => 'c0e334312940ac4df14233c337ce2249', './include/generic/SugarWidgets/SugarWidgetSubPanelTopComposeEmailButton.php' => 'c5cef239d43214b5330216cd38cd48e3', - './include/generic/SugarWidgets/SugarWidgetSubPanelTopButtonQuickCreate.php' => 'f851bb2972ae86b210ae24d47f7e1e60', - './include/generic/SugarWidgets/SugarWidgetSubPanelTopButton.php' => '69a503feb3570b9d7c041d9b2df1bce7', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopButtonQuickCreate.php' => 'ad63c304b312c204fbe9a2e4995bf1ba', + './include/generic/SugarWidgets/SugarWidgetSubPanelTopButton.php' => '76328770d804049a4e6b034ea557f0f3', './include/generic/SugarWidgets/SugarWidgetSubPanelTopArchiveEmailButton.php' => '39e39d2fe63a6a1f9c726e44d8c76d52', './include/generic/SugarWidgets/SugarWidgetSubPanelRemoveButtonProjects.php' => '3a1863e4e6e47e4929afbfe5b6b5fac9', './include/generic/SugarWidgets/SugarWidgetSubPanelRemoveButtonMeetings.php' => '675f3e0fbf1b9260e8a281033e8fc495', @@ -5920,12 +5988,12 @@ $md5_string = array ( './include/generic/SugarWidgets/SugarWidgetSubPanelGetLatestButton.php' => '113cb3398fb07a55c98cfc01aeab6c4e', './include/generic/SugarWidgets/SugarWidgetSubPanelEmailLink.php' => 'bf7d893af5ca13542d1a9f6ff34279c8', './include/generic/SugarWidgets/SugarWidgetSubPanelEditRoleButton.php' => '064b42a25e85e539c56b8dcffbcf1403', - './include/generic/SugarWidgets/SugarWidgetSubPanelEditButton.php' => 'e1173f56588c330420087f88e2948333', - './include/generic/SugarWidgets/SugarWidgetSubPanelDetailViewLink.php' => '7daed673f7686bc2eaa7a52239a021f0', + './include/generic/SugarWidgets/SugarWidgetSubPanelEditButton.php' => '199b1f28467146a5e4a4f4e87d823ea3', + './include/generic/SugarWidgets/SugarWidgetSubPanelDetailViewLink.php' => '72bf5adfbba8a2d5739d4a1b72970ffd', './include/generic/SugarWidgets/SugarWidgetSubPanelConcat.php' => '93792be841b1072969c664df3f9afddd', './include/generic/SugarWidgets/SugarWidgetSubPanelCloseButton.php' => '335cea49a5878381f30799a25c657710', './include/generic/SugarWidgets/SugarWidgetSubPanelActivitiesStatusField.php' => 'e44858a1a49a853de8d4653f3cc3fd97', - './include/generic/SugarWidgets/SugarWidgetReportField.php' => '2f7caf21939edeca0625447a75e46bd3', + './include/generic/SugarWidgets/SugarWidgetReportField.php' => 'b6dae8e2b063e1a67f25eb632d7a2862', './include/generic/SugarWidgets/SugarWidgetFieldvarchar.php' => '0559010aef7286a3dd1a9acbd1e3ef95', './include/generic/SugarWidgets/SugarWidgetFielduser_name.php' => '5c0d58c825aec0607c90f0fa9c9368a0', './include/generic/SugarWidgets/SugarWidgetFieldurl.php' => '56876b67d48c659338febb7f469f7e20', @@ -5937,7 +6005,7 @@ $md5_string = array ( './include/generic/SugarWidgets/SugarWidgetFieldphone.php' => '866bbe79a3610e214e58dec9e2be9b4e', './include/generic/SugarWidgets/SugarWidgetFieldparent_type.php' => '010d41fbf45e91e770669568a5145ee0', './include/generic/SugarWidgets/SugarWidgetFieldnum.php' => 'b24e524abcf7997e95865021f1b87d60', - './include/generic/SugarWidgets/SugarWidgetFieldname.php' => '9efe843670aed09679879a66d10fcb27', + './include/generic/SugarWidgets/SugarWidgetFieldname.php' => '20c6ac1d7e606e38a882b75b9ebecde5', './include/generic/SugarWidgets/SugarWidgetFieldmultienum.php' => 'be240e4da2ea9b4543886fd8b974346e', './include/generic/SugarWidgets/SugarWidgetFieldlongtext.php' => 'db9f5ce68ae366c538edd147d9082e0d', './include/generic/SugarWidgets/SugarWidgetFieldint.php' => '8f0285935954f5c4dd9a16ceeeee2567', @@ -5945,7 +6013,7 @@ $md5_string = array ( './include/generic/SugarWidgets/SugarWidgetFieldid.php' => 'ebd4da373e066e3db5753f653363a298', './include/generic/SugarWidgets/SugarWidgetFieldfullname.php' => '54bd4fbf0e32e4c3a053867815d0bf9e', './include/generic/SugarWidgets/SugarWidgetFieldfloat.php' => '2e6a7dfb394741ed2063b0f3e4313e41', - './include/generic/SugarWidgets/SugarWidgetFieldenum.php' => 'a826099afcd6eee2deb7d4b0cd393837', + './include/generic/SugarWidgets/SugarWidgetFieldenum.php' => 'f5fb90499cc13d2a27a39088e678b567', './include/generic/SugarWidgets/SugarWidgetFieldemail.php' => 'c0f3220ad4123ae1d8307f08a476ee84', './include/generic/SugarWidgets/SugarWidgetFielddouble.php' => '78b80591d1f30667c3ae4ec25711b3e7', './include/generic/SugarWidgets/SugarWidgetFielddecimal.php' => '85891b39c359f08f06ca5be4c49b4ce1', @@ -5953,15 +6021,15 @@ $md5_string = array ( './include/generic/SugarWidgets/SugarWidgetFielddatetime.php' => '3f38fd47b01da7d82094fea7f3be3a8c', './include/generic/SugarWidgets/SugarWidgetFielddatepicker.php' => '620b4c852a4b65566fe1a481b1bdffb7', './include/generic/SugarWidgets/SugarWidgetFielddate.php' => '64acd7916910cf52758d351e07312353', - './include/generic/SugarWidgets/SugarWidgetFieldcurrency.php' => '7a1225b8ab164fc8a2f3a8fffea8abea', + './include/generic/SugarWidgets/SugarWidgetFieldcurrency.php' => 'dcd67a22b003cd078fdf157278954214', './include/generic/SugarWidgets/SugarWidgetFieldchar.php' => '28923530c61913c4a4c9a0f9e3820a54', './include/generic/SugarWidgets/SugarWidgetFieldbool.php' => 'f204856e09e4559462cafd9db01846cc', - './include/generic/SugarWidgets/SugarWidgetField.php' => '606c1ac30b3a5f786c4d7c8d3e0e374f', + './include/generic/SugarWidgets/SugarWidgetField.php' => '9d3905ff4a07d7b4d7ddefed00debcda', './include/generic/SugarWidgets/SugarWidget.php' => '4edff0b5fec741dc5ec5212a9b3c1465', - './include/generic/Save2.php' => '7361b0d73455ce238553a2bc166517cb', + './include/generic/Save2.php' => '7e0a94147bd6a5b50fc53992b94e4a1a', './include/generic/LayoutManager.php' => 'a87b35af9f4ce6e851797f94b6772425', - './include/generic/DeleteRelationship.php' => '1c38fca0d35f81fb923b9271d4f96be3', - './include/formbase.php' => '74d113e09f1fbf583c20b5d5208cba57', + './include/generic/DeleteRelationship.php' => '6db3ae925d5e0407bc0d118d57a8fe5a', + './include/formbase.php' => '6662e5b853712b8966927ffc6ad35c10', './include/fonts/License.html' => '8a22bc6b773aeb68f9748fd1920f84d4', './include/fonts/Times-Roman.afm' => 'f257a72c31f6a864f4e0994b1771628c', './include/fonts/Times-Italic.afm' => 'c41212e70e19627889aefef85212a47d', @@ -5975,23 +6043,23 @@ $md5_string = array ( './include/fonts/Courier-Oblique.afm' => '3324f479739ac9ebab740772b55705d2', './include/fonts/Courier-BoldOblique.afm' => '5c34aeefc1ef69ae2fb317abc1ccc9ca', './include/fonts/Courier-Bold.afm' => 'cb84ced0cc430a5d54497257a11638f5', - './include/export_utils.php' => 'a51e131fa9c6d979d6cbd1064388a8f8', + './include/export_utils.php' => 'c0a596f0992bdd60424c6f226a71b51f', './include/entryPoint.php' => 'e25fe49080602ee59180d4ea18e4424f', - './include/dir_inc.php' => '7fa525a179288303fb0cc34b89371b62', - './include/database/SqlsrvHelper.php' => '6cf5af120c1644866c0687ba1773d69e', + './include/dir_inc.php' => '1bcdea84cfc20923819763baade6e567', + './include/database/SqlsrvHelper.php' => 'a1c32cc7e63323d06b42bbe09b982604', './include/database/PearDatabase.php' => '029e54b3c4a2c9da75bdab75b906232e', './include/database/MysqliHelper.php' => '8824aa4be4b5946c8a6ad53d55d43adc', - './include/database/MysqlHelper.php' => 'ca56e3517a8cbce5581085683c8da6c9', - './include/database/MssqlHelper.php' => '816ee7b712d115590aa69eabead42f52', + './include/database/MysqlHelper.php' => 'ab22b31ee703d6a18e19727249525c24', + './include/database/MssqlHelper.php' => 'd76dc7f5a8ae800a27149ee2bb725492', './include/database/FreeTDSHelper.php' => '443a191f7dd5794fbe60c440dce3e426', - './include/database/DBHelper.php' => '6c59be06ba61855d107155620dfe59e5', - './include/database/SqlsrvManager.php' => '659363159024ac1885d50f8a8e3c31e3', + './include/database/DBHelper.php' => '46e0769144872be075f356260c4f7110', + './include/database/SqlsrvManager.php' => '9e74bb9201c06290bab4b0410f790c31', './include/database/MysqliManager.php' => '4b7748362a9ffbd38288cbd8619c0f89', './include/database/MysqlManager.php' => '2fb21197c234df9ffca41ff9ab486a8a', - './include/database/MssqlManager.php' => '8bb36894e819615ac08d9ea42ae6f713', + './include/database/MssqlManager.php' => '9435b119b024dfbe61bc46c3fb53ea94', './include/database/FreeTDSManager.php' => '72cca97832b03356146faa2d49a2cbed', - './include/database/DBManagerFactory.php' => 'dbea844f739891e4bc59806f29775819', - './include/database/DBManager.php' => 'a7e65da839eb59f20b505eca1da80959', + './include/database/DBManagerFactory.php' => '71dc5f3547235bcd27b999eb39c16c55', + './include/database/DBManager.php' => '016daafb66d7d84f1d860aad2379e262', './include/controller/Controller.php' => '154eadef52691f5edbbd7b17eb72b406', './include/contextMenus/menuDefs/sugarPerson.php' => '1978579cd6c1b4b54e070f81ddc7a166', './include/contextMenus/menuDefs/sugarObject.php' => 'c89b133cb16a4a1ea664ea79785331c4', @@ -5999,13 +6067,14 @@ $md5_string = array ( './include/contextMenus/contextMenu.php' => 'f4625bd3cef2c3579343ac734b7e2b75', './include/connectors/utils/ConnectorUtils.php' => '81d0d28d7490e653c90037956bb77083', './include/connectors/sources/loc/xml.php' => '9de23526c28a913c11b7d2094f2fdc26', + './include/connectors/sources/ext/eapm/eapm.php' => '99db19208e9c64cafb40b42e9bd4ac53', './include/connectors/sources/ext/soap/soap.php' => 'fbb8e1f311a85c341c3645cf3beec5b9', './include/connectors/sources/ext/rest/rest.php' => 'ee574d1a601e2926cb5a3cc66f28e36c', - './include/connectors/sources/default/source.php' => '7858e24187d5910cbf95a97eb752d1fa', + './include/connectors/sources/default/source.php' => 'cffb309c3da411d08a1c90d74802a3b3', './include/connectors/sources/SourceFactory.php' => '8e2a76bda89e905821aee0568cb65fed', './include/connectors/formatters/ext/soap/tpls/default.tpl' => '30ac6e34be2b90079b7fa67e9916439b', './include/connectors/formatters/ext/rest/tpls/default.tpl' => 'a775bb54d09a292b0c3940f30758199a', - './include/connectors/formatters/default/company_detail.js' => '4f86258219ce39153e74bfc251d841e1', + './include/connectors/formatters/default/company_detail.js' => 'e1802cd88cd4920243dcc80da7ef48c8', './include/connectors/formatters/default/formatter.php' => '2582c32e38c40c1b478eaeb9c5d92d9d', './include/connectors/formatters/FormatterFactory.php' => '1c5731cea14091e1fbe228d2e475e5fd', './include/connectors/filters/default/filter.php' => 'dc92e54823ec24830c1de4b5140a0c98', @@ -6015,7 +6084,7 @@ $md5_string = array ( './include/VarDefHandler/vardef_meta_arrays.php' => 'ef9152d645fc0e97041e4d6e9f8174a2', './include/VarDefHandler/listvardefoverride.php' => 'd79b73457de94f7d3c2d485d7643b501', './include/VarDefHandler/VarDefHandler.php' => 'ed481a168b11ed8306efdce0725e7b1f', - './include/TimeDate.php' => 'a5499e1bea8973742dfd537c5097d255', + './include/TimeDate.php' => '051674889ce64a49c5232336b93d229d', './include/TemplateHandler/TemplateHandler.php' => '9fc0236df420bb0bd910d632dbc31d27', './include/Sugarpdf/sugarpdf_default.php' => '4e61fe9d5cd31ac41acc315423348ff7', './include/Sugarpdf/sugarpdf_config.php' => 'ecd77816c5def7f50b83d7c2336e7adf', @@ -6024,23 +6093,23 @@ $md5_string = array ( './include/Sugarpdf/SugarpdfFactory.php' => '0afbd14636df2b285ec74c8852d836ce', './include/Sugarpdf/Sugarpdf.php' => '2740d9331dc458a155f4daae744d2814', './include/Sugarpdf/FontManager.php' => '2d3b8e82caaa71e278519755dacadc9f', - './include/Sugar_Smarty.php' => '7318c3410d439cf41bc59faae6cce89a', + './include/Sugar_Smarty.php' => 'd451bbba7d081fd900b601962433c935', './include/SugarTinyMCE.php' => '416d1167ad0b8419a1fa26c39d043868', './include/SugarTheme/getImage.php' => '7c0d2c11813933c7d51de8032cbed53f', './include/SugarTheme/cssmin.php' => '05384ba957435def09368425e4480688', - './include/SugarTheme/SugarTheme.php' => '462c527cd74ba2195704743ef8387859', + './include/SugarTheme/SugarTheme.php' => '89d2af3bcbf96f147e82f61d1559d3ff', './include/SugarPHPMailer.php' => '3274e482b96fdaa19f916a24aa63cdcc', './include/SugarCache/SugarCachesMash.php' => '856eed10c774ed920d64c52da2d327a1', - './include/SugarCache/SugarCacheZend.php' => '8280ba4a5dd358617c8d6f1b9e86ae35', + './include/SugarCache/SugarCacheZend.php' => '21d249cb25b21c7876eb73500c3d5c33', './include/SugarCache/SugarCacheWincache.php' => '834ab4b07312d862d440c15cf75a76cf', './include/SugarCache/SugarCacheRedis.php' => '75c6770527f143f3cfe9a848878e0113', './include/SugarCache/SugarCacheMemory.php' => '62d1a6bb34c8d31c752b134b044d3d7f', - './include/SugarCache/SugarCacheMemcached.php' => '51244a1d252a45decc64b731083e7531', - './include/SugarCache/SugarCacheMemcache.php' => 'ad46a11da82466104605b28be7d0492a', - './include/SugarCache/SugarCacheFile.php' => 'a367fcd4ef64e6f71a342b30cbb625ba', - './include/SugarCache/SugarCacheAbstract.php' => '17c685bba109994950cdc66be58c4460', - './include/SugarCache/SugarCacheAPC.php' => '0a237e55d4dc674145da1648576cbd28', - './include/SugarCache/SugarCache.php' => '94c075853d48cea91295e3bc45327f69', + './include/SugarCache/SugarCacheMemcached.php' => '64261b5455f9a52f3cf7947a13599340', + './include/SugarCache/SugarCacheMemcache.php' => '56c30be197ce89673265f7bdadf4138d', + './include/SugarCache/SugarCacheFile.php' => 'ea448111d3fd8f2c1b1692596778dbcf', + './include/SugarCache/SugarCacheAbstract.php' => '95047ac3071840c69ed005af7c125f79', + './include/SugarCache/SugarCacheAPC.php' => '8e2709cd4d14df0a0f9e0eb3b84736fe', + './include/SugarCache/SugarCache.php' => '17156919701a7675da00f4ab2106a288', './include/SugarObjects/templates/sale/vardefs.php' => '881b5f93e8c668224b60137bfec03b08', './include/SugarObjects/templates/sale/metadata/subpanels/default.php' => 'e2ca78fec0686be0c1d1e6400a5c272a', './include/SugarObjects/templates/sale/metadata/searchdefs.php' => '02f9d5317fb7b44bfa9a1a965512e295', @@ -6063,7 +6132,7 @@ $md5_string = array ( './include/SugarObjects/templates/sale/config.php' => '3bbc93005435531e82a062995275aa73', './include/SugarObjects/templates/sale/Sale.php' => 'ede92e3a280a4e7e867f74f820a5203a', './include/SugarObjects/templates/sale/Chance.php' => 'cd3cd899960aad0b6d8a5923945ce1d8', - './include/SugarObjects/templates/person/vardefs.php' => '05f356c87ec5bc7d54325d0787141dec', + './include/SugarObjects/templates/person/vardefs.php' => '0f8542059906be1a3bc29f7fdce09671', './include/SugarObjects/templates/person/metadata/subpanels/default.php' => '3b440daa07cb13eed84d9f17fe760247', './include/SugarObjects/templates/person/metadata/searchdefs.php' => '7badf2d886b0f5183df37dcca24cc704', './include/SugarObjects/templates/person/metadata/quickcreatedefs.php' => '0440e58a5af79ebdaf0fbc22bea4d06d', @@ -6102,10 +6171,10 @@ $md5_string = array ( './include/SugarObjects/templates/file/vardefs.php' => '7dfb1be511028f2da373b1e3abd2caab', './include/SugarObjects/templates/file/metadata/subpanels/default.php' => 'dd9fa46c03bcd7e6b11fd34e08d6e462', './include/SugarObjects/templates/file/metadata/searchdefs.php' => '7160ba30d43ad69e3ffbcae530ef3fba', - './include/SugarObjects/templates/file/metadata/quickcreatedefs.php' => 'a9bfc0f4a6b648ff7b67131337d2869a', + './include/SugarObjects/templates/file/metadata/quickcreatedefs.php' => '15cb51a34ec0017eb3c0b101eefa099c', './include/SugarObjects/templates/file/metadata/metafiles.php' => '17dbfa2325155639daf1d28a1852eaf0', './include/SugarObjects/templates/file/metadata/listviewdefs.php' => 'b2280ffff29fff1b7f98abbb0cf2a3a2', - './include/SugarObjects/templates/file/metadata/editviewdefs.php' => '5460e696f459cb4acc996d4270364c8d', + './include/SugarObjects/templates/file/metadata/editviewdefs.php' => '14d32abca647f42abb73a08b7225bdec', './include/SugarObjects/templates/file/metadata/detailviewdefs.php' => '20ee6b33b104fefab4616e438e2e5484', './include/SugarObjects/templates/file/metadata/dashletviewdefs.php' => '8a986c14d5e1bd2c2d07f8ab68f3e421', './include/SugarObjects/templates/file/metadata/SearchFields.php' => '5df61e336c1474863ceae4e28e83f52c', @@ -6116,7 +6185,7 @@ $md5_string = array ( './include/SugarObjects/templates/file/icons/Createfile.gif' => '3ed1d93938f715b1af93c0e99e900af5', './include/SugarObjects/templates/file/controller.php' => '247d2ff4c926c2cbcd3335122af88011', './include/SugarObjects/templates/file/File.php' => '1b0e94e667d3931269e050b3678dcdca', - './include/SugarObjects/templates/company/vardefs.php' => '32f7c89c0de6e3fc0042d42de6cca085', + './include/SugarObjects/templates/company/vardefs.php' => 'b583f934078fc302cacaffd8ffb8751e', './include/SugarObjects/templates/company/metadata/subpanels/default.php' => '50d50dfbe4537790622a3672973e664c', './include/SugarObjects/templates/company/metadata/searchdefs.php' => '8957871d61cfa25e93848382477010e3', './include/SugarObjects/templates/company/metadata/quickcreatedefs.php' => '543bc8145e2188442c70d8ba5c0dd4ac', @@ -6134,7 +6203,7 @@ $md5_string = array ( './include/SugarObjects/templates/company/icons/Createcompany.gif' => '3978b32e01cbeb974d86b1da0617dae9', './include/SugarObjects/templates/company/config.php' => 'd825515c26de5dd1e6da23bb80c40e9b', './include/SugarObjects/templates/company/Company.php' => '224fba6fa8057e01c94336de9dad822b', - './include/SugarObjects/templates/basic/vardefs.php' => '5c3029d1b35fcbf96eb7e90fb7c25251', + './include/SugarObjects/templates/basic/vardefs.php' => '374b58186bcffd1892cec60d0545aa93', './include/SugarObjects/templates/basic/metadata/subpanels/default.php' => '7ac8c114426f72d48d14aa4c938268d9', './include/SugarObjects/templates/basic/metadata/searchdefs.php' => '27309077aeef0138ee27a5e0ddccffbc', './include/SugarObjects/templates/basic/metadata/quickcreatedefs.php' => 'db11e319cfbfb8499fca0d8bcf684233', @@ -6142,7 +6211,7 @@ $md5_string = array ( './include/SugarObjects/templates/basic/metadata/metafiles.php' => '457831fcf41e519fbeb5aa84661a1550', './include/SugarObjects/templates/basic/metadata/listviewdefs.php' => '397dd6d247a08009fd1aae5cffb684de', './include/SugarObjects/templates/basic/metadata/editviewdefs.php' => 'a0782a05b7b8757a891ca4d4ce77f74e', - './include/SugarObjects/templates/basic/metadata/detailviewdefs.php' => 'f0becb7fa0a0a6bd860c9bd59e061fd0', + './include/SugarObjects/templates/basic/metadata/detailviewdefs.php' => 'ca747033814e55a3be655650dc17ddb7', './include/SugarObjects/templates/basic/metadata/dashletviewdefs.php' => '741e46a24fb5e691d58becb268f55ac0', './include/SugarObjects/templates/basic/metadata/SearchFields.php' => '968d4fd75d1db20cee8f2cd7c00adc83', './include/SugarObjects/templates/basic/language/en_us.lang.php' => '30b1071db020b2cca94eb38ca53108c6', @@ -6156,12 +6225,12 @@ $md5_string = array ( './include/SugarObjects/implements/team_security/language/en_us.lang.php' => '6d98aadfbb7a812f26d04d680670a308', './include/SugarObjects/implements/assignable/vardefs.php' => 'a548ffd7a3d6e6db97539837ac747137', './include/SugarObjects/implements/assignable/language/en_us.lang.php' => '364b577943f10dc538ebf1dbb46ca9a7', - './include/SugarObjects/VardefManager.php' => '477ceccd79bb1010d3fcf21de33e7b0e', + './include/SugarObjects/VardefManager.php' => '5cea9baeeb7ee787d1691dfc95a660e4', './include/SugarObjects/SugarSession.php' => '162a302292027328640b60bebc63cd2c', './include/SugarObjects/SugarRegistry.php' => '7fb93cfcaba8de431d61b07d3b52fc88', './include/SugarObjects/SugarConfig.php' => '5d1d1b107196e4bea8ac8ed54a829085', - './include/SugarObjects/LanguageManager.php' => '10649f172ccdd9b8c11885fd0d8e096c', - './include/SugarLogger/SugarLogger.php' => '1b6c6d2b07b2484a7acdb9f8a38e5ca6', + './include/SugarObjects/LanguageManager.php' => '50b17f0a1722ef941594638571cdf6b4', + './include/SugarLogger/SugarLogger.php' => '75bd49d35fb8497f999b8484bd024d4c', './include/SugarLogger/LoggerTemplate.php' => '34f5a219c0bfc9d4093bbd7a1a212da7', './include/SugarLogger/LoggerManager.php' => '62359fb0fe3c28b7b5848033f786153f', './include/SugarFolders/SugarFolders.php' => 'd57d977f89b4a451ae51821e2a074078', @@ -6194,7 +6263,6 @@ $md5_string = array ( './include/SugarFields/Parsers/EditViewMetaParser.php' => '6342568256e9006675e9f55120476233', './include/SugarFields/Parsers/DetailViewMetaParser.php' => '3e1e3f8fc88bced68ec463990130b0f6', './include/SugarFields/Fields/Id/SugarFieldId.php' => 'e0d77e459779dd4113cd30baf249f94c', - './include/SugarFields/Fields/Encrypt/SugarFieldEncrypt.php' => '747a791c00fe34a50ece329b63ce056a', './include/SugarFields/Fields/Username/SugarFieldUsername.php' => '88d57b736369475093c1246e0867101b', './include/SugarFields/Fields/Username/DetailView.tpl' => '6c170bb644283c0f1833d7910b470eaa', './include/SugarFields/Fields/URL/ListView.tpl' => '339dd0886ba39dc5c9f31aeb5ffef2fc', @@ -6204,29 +6272,29 @@ $md5_string = array ( './include/SugarFields/Fields/Text/EditView.tpl' => '54cc0715c3b0814a92a04d6c86f1602c', './include/SugarFields/Fields/Text/DetailView.tpl' => 'd068de082c81d4fef6801093e3365de9', './include/SugarFields/Fields/Text/ClassicEditView.tpl' => '6ddfbc834a3962bdf07a328b2eba147a', - './include/SugarFields/Fields/Relate/SugarFieldRelate.php' => '73fb031df1ccbef0c583a9ddd7e8276c', + './include/SugarFields/Fields/Relate/SugarFieldRelate.php' => 'df9fa607bbdc527e47d311c42ea26907', './include/SugarFields/Fields/Relate/SearchView.tpl' => '9ff5da2e1acf235d56eb8f4ffaecde95', - './include/SugarFields/Fields/Relate/EditView.tpl' => '1b169d23d4be3ec144dea0ad642dd9be', - './include/SugarFields/Fields/Relate/DetailView.tpl' => 'e4853db1a2b8b80081d27a26e4e4a39f', + './include/SugarFields/Fields/Relate/EditView.tpl' => '510b6ea0a5b5bf3825890924c5bb51ce', + './include/SugarFields/Fields/Relate/DetailView.tpl' => 'f25ba2d8f791cb3e4d1301847814b3c1', './include/SugarFields/Fields/Readonly/SugarFieldReadonly.php' => '15cc02846154744f83908e9c141e284f', './include/SugarFields/Fields/Radioenum/SugarFieldRadioenum.php' => 'e0561c241c45d0fdc6246ae4cbb003a4', './include/SugarFields/Fields/Radioenum/EditView.tpl' => '3a702fdbbae1aadccf766091ec8fc15e', './include/SugarFields/Fields/Radioenum/DetailView.tpl' => '73ef83f9c364ccf4a45fcef0515297b6', - './include/SugarFields/Fields/Phone/SugarFieldPhone.php' => '309d20c10c0836d3116c87b89e0c7c0e', + './include/SugarFields/Fields/Phone/SugarFieldPhone.php' => '12ccc677202de1359cddebc27c7e7fac', './include/SugarFields/Fields/Phone/EditView.tpl' => '2b10261693c5a1ef93744e8670939771', './include/SugarFields/Fields/Phone/ListView.tpl' => '620ff0a58f48803e77df65254b189518', './include/SugarFields/Fields/Phone/DetailView.tpl' => '42d01015f6eec00ba51dcd84945497cd', './include/SugarFields/Fields/Password/SugarFieldPassword.php' => '6324890226f616bf1444c1c743d3e576', './include/SugarFields/Fields/Password/EditView.tpl' => '5a8b8690e57bc38dda46bb6a0e61d864', - './include/SugarFields/Fields/Parent/SugarFieldParent.php' => '3cd6c6b732cd5c3781a3e0375df622e7', - './include/SugarFields/Fields/Parent/SearchView.tpl' => '62dab5bae7fca5e88b270e3971b2188d', - './include/SugarFields/Fields/Parent/EditView.tpl' => '974c1f9429b7b0bfd9ff10a82ff524a9', + './include/SugarFields/Fields/Parent/SugarFieldParent.php' => '4c69ce5c9257ee30c7b8bf234014356a', + './include/SugarFields/Fields/Parent/SearchView.tpl' => '3dda68af2ad53f755193ad09c3cebbf5', + './include/SugarFields/Fields/Parent/EditView.tpl' => '4a1173b08d97095a5f5cf05d2a523a07', './include/SugarFields/Fields/Parent/DetailView.tpl' => '43c0b59004d5c2d581d0ce431923cbbb', - './include/SugarFields/Fields/Multienum/SugarFieldMultienum.php' => '7a2f80ebff62388de1a1218dc7ebc914', + './include/SugarFields/Fields/Multienum/SugarFieldMultienum.php' => '9a8aff4bf4605a4ba9e71c2fdf0ad28d', './include/SugarFields/Fields/Multienum/SearchView.tpl' => '6e1d82935a12ac4693e9e0d36ff55338', './include/SugarFields/Fields/Multienum/ListView.tpl' => 'c65819a80ac6ee50b2303224dad95211', './include/SugarFields/Fields/Multienum/EditViewFunction.tpl' => '64a2bb349db221c9f4b1ad443561cf7d', - './include/SugarFields/Fields/Multienum/EditView.tpl' => '2123f9cde58c25fed22a520136d02a0b', + './include/SugarFields/Fields/Multienum/EditView.tpl' => 'bd54181385829a727ab9a7888f013582', './include/SugarFields/Fields/Multienum/DetailView.tpl' => '7f4f53dea04bdcf377a25073b329b738', './include/SugarFields/Fields/Link/ListView.tpl' => '507006d00ce469d8a8d9ec7acbbc8d91', './include/SugarFields/Fields/Link/EditView.tpl' => '791d1e2437fbf61fbb5379f6ef6ef6bf', @@ -6248,13 +6316,13 @@ $md5_string = array ( './include/SugarFields/Fields/File/SugarFieldFile.js' => '5c9fa7cb03a5604274afb542df08ae5b', './include/SugarFields/Fields/File/SearchView.tpl' => '3caa8a3b0a97a20169c404260788879f', './include/SugarFields/Fields/File/ListView.tpl' => 'd747a01d5b25abb348c51f7bd0154403', - './include/SugarFields/Fields/File/SugarFieldFile.php' => 'f6bc4adb18ef8b53f4361f366dc7fb33', - './include/SugarFields/Fields/File/EditView.tpl' => '76ef95550d9f50581f43fdaa2af3cc77', + './include/SugarFields/Fields/File/SugarFieldFile.php' => '78a02dd1ed643a1e384548d5fc22d77c', + './include/SugarFields/Fields/File/EditView.tpl' => 'cee12acc690ff5fd1b3a5451eb330499', './include/SugarFields/Fields/File/DetailView.tpl' => 'b2b300b0591fd73e4ea65f597ea0235c', './include/SugarFields/Fields/Enum/SugarFieldEnum.php' => '01b94cd983a49a9e5e3a293a6cdec390', './include/SugarFields/Fields/Enum/SearchView.tpl' => '98e0ef529a1f684b9ee2a0dab4e1c340', './include/SugarFields/Fields/Enum/EditViewFunction.tpl' => '42571ad17c8310ff4e682beacfd28e86', - './include/SugarFields/Fields/Enum/EditView.tpl' => '03f81ad79a350c1cb48d0898be5dc90c', + './include/SugarFields/Fields/Enum/EditView.tpl' => '74f283bd7a87cd0733de56d671fcb98c', './include/SugarFields/Fields/Enum/DetailViewFunction.tpl' => '471af8fac1c69cdaf1db123ce4d891e5', './include/SugarFields/Fields/Enum/DetailView.tpl' => 'fd55bc8637d079f14265f306b67a33ec', './include/SugarFields/Fields/Download/SugarFieldDownload.php' => '907d0ca6f2c055bf2149e47fbf9f83b4', @@ -6270,14 +6338,14 @@ $md5_string = array ( './include/SugarFields/Fields/Currency/ListView.tpl' => 'c62e2997785bf58a314576d5a69fb6f9', './include/SugarFields/Fields/Currency/EditView.tpl' => '2a8d5393da74d525587fe93e6081ad28', './include/SugarFields/Fields/Currency/DetailView.tpl' => '07b10accc2d817376b207b935182c60b', - './include/SugarFields/Fields/Collection/SugarFieldCollection.js' => '5ffc9d59b804433cc7eb773ccb74c2de', + './include/SugarFields/Fields/Collection/SugarFieldCollection.js' => 'e7a8be9f58c67026ce906dcffc369e41', './include/SugarFields/Fields/Collection/view.sugarfieldcollection.php' => '626c0b184463b413735031b6c051db97', - './include/SugarFields/Fields/Collection/ViewSugarFieldCollection.php' => '56b0ef3f9afff5f97e31d3b897bbe681', - './include/SugarFields/Fields/Collection/SugarFieldCollection.php' => 'bd1b5641e51667726ff658a4c7833732', + './include/SugarFields/Fields/Collection/ViewSugarFieldCollection.php' => 'ce63217a8411413df445489da09e58d3', + './include/SugarFields/Fields/Collection/SugarFieldCollection.php' => 'f8bf806088e22b39b738459f096d89fe', './include/SugarFields/Fields/Collection/EditView.tpl' => '1ca2398320a3fe8f51d974019df19ed2', './include/SugarFields/Fields/Collection/DetailView.tpl' => 'fa2784ef38833e7e6acf31343b585fd9', - './include/SugarFields/Fields/Collection/CollectionEditViewRow.tpl' => '34312f762b8a8f6be6ad22a65a728a16', - './include/SugarFields/Fields/Collection/CollectionEditView.tpl' => '2990c6d504dd9b1a83959f37628ccd63', + './include/SugarFields/Fields/Collection/CollectionEditViewRow.tpl' => 'b5d4f9b96d13012ecb96fbfda85eb512', + './include/SugarFields/Fields/Collection/CollectionEditView.tpl' => '8d81ebddbc71c5fe5aa9d0fec7711015', './include/SugarFields/Fields/Collection/CollectionDetailView.tpl' => '524e804644d30f07a97a7e62cabe3ed4', './include/SugarFields/Fields/Bool/SugarFieldBool.php' => '195dc6056fe92ab757b9828d0d273bcd', './include/SugarFields/Fields/Bool/SearchView.tpl' => 'ff86c0b0a77e58931d2d90d2ccb0bd1c', @@ -6287,7 +6355,7 @@ $md5_string = array ( './include/SugarFields/Fields/Bool/EditView.tpl' => 'e30bc5db71990f5f1b6e8f9a0511bb30', './include/SugarFields/Fields/Bool/DetailView.tpl' => '6d8a2d953312d93623be3c4f53d2307f', './include/SugarFields/Fields/Base/ImportViewFunction.tpl' => '5b76f6e87fe309b025410c85ae4c748b', - './include/SugarFields/Fields/Base/SugarFieldBase.php' => '36032eae7229583ca0cdc1bb93924ba7', + './include/SugarFields/Fields/Base/SugarFieldBase.php' => 'fb7da06b58b0b1e0ed0c74ef5398a4d4', './include/SugarFields/Fields/Base/SearchForm.tpl' => '3d1bf0d12f4169c071b0a0e7bd7c6965', './include/SugarFields/Fields/Base/ListView.tpl' => 'f91fe91fef2adda8dcd3e2b3dd5fa8ea', './include/SugarFields/Fields/Base/InlineEditView.tpl' => 'e4c0cf52300a9cf39d0f1b1d0b1ce10a', @@ -6299,18 +6367,18 @@ $md5_string = array ( './include/SugarFields/Fields/Assigned_user_name/EditViewFunction.tpl' => '0243dbbc42d8cf8658348a75c5984455', './include/SugarFields/Fields/Assigned_user_name/SugarFieldAssigned_user_name.php' => '8ea7a5b1140ad70dab428554a7e81687', './include/SugarFields/Fields/Assigned_user_name/SearchView.tpl' => '2218c7abf088c72b38cdf7c5904392b4', - './include/SugarFields/Fields/Address/SugarFieldAddress.js' => 'b2ee11d877f46a9daf5853f7296afe6e', - './include/SugarFields/Fields/Address/en_us.EditView.tpl' => '3b56e6a7f0bce108036f6f397ee096f5', + './include/SugarFields/Fields/Address/SugarFieldAddress.js' => 'b6a95dd55e35d7f12a9b39cfdb7965d1', + './include/SugarFields/Fields/Address/en_us.EditView.tpl' => '9cab7462f5845974cc1c94684ad13222', './include/SugarFields/Fields/Address/en_us.DetailView.tpl' => '180780c24b5be8a4fa53253ef6235d5e', './include/SugarFields/Fields/Address/SugarFieldAddress.php' => '7e7b54a4d6e4b3ba10fb8815b7d9c9d6', - './include/SugarFields/Fields/Address/EditView.tpl' => '40eaefd79f8905ebdf00a50c70ba584d', + './include/SugarFields/Fields/Address/EditView.tpl' => 'f0d7fc8ad40eb5356351eb8df36ae803', './include/SugarFields/Fields/Address/DetailView.tpl' => 'c988796dbaedffe8575a131f74564857', - './include/SugarEmailAddress/SugarEmailAddress.js' => '0457af7a2f58345efc295d8e7f30ad3d', + './include/SugarEmailAddress/SugarEmailAddress.js' => '7788ed0b25d0ac0234f49ae176516e9a', './include/SugarEmailAddress/templates/forWideFormBodyView.tpl' => '6d07e3db7e16d09cc2e4b3752169fbd4', './include/SugarEmailAddress/templates/forEditView.tpl' => 'ab460b18fc7f4307b2491ed83461417c', './include/SugarEmailAddress/templates/forDuplicatesView.tpl' => '48529a015533cdd2ce8db08a826dd09c', './include/SugarEmailAddress/templates/forDetailView.tpl' => '75be62dc812205b17178d2aebecd2f19', - './include/SugarEmailAddress/SugarEmailAddress.php' => '182dafe3d80eb75bd6add3e6dc3cc5db', + './include/SugarEmailAddress/SugarEmailAddress.php' => 'f49b2ad1fbc83b44d5a1b58bdfe3f8cb', './include/SugarDependentDropdown/metadata/dependentDropdown.php' => 'ef0d061a5bfb5641e65f55560213e209', './include/SugarDependentDropdown/javascript/SugarDependentDropdown.js' => '480bc0db43abac0ec4ddcde0db5f1014', './include/SugarDependentDropdown/SugarDependentDropdown.php' => 'c27f9273801a6686f233b4ed1100b369', @@ -6323,10 +6391,10 @@ $md5_string = array ( './include/SugarCharts/swf/pieChart.swf' => 'c8a528dc470ac904864ea88549b3adc9', './include/SugarCharts/swf/stackedGroupByChart.swf' => '0d524ea04b2c56d1c7cdc86194f59ed1', './include/SugarCharts/SugarChartFactory.php' => 'ff55d866d2c0fde548e7666aff189ebc', - './include/SugarCharts/JsChart.php' => 'd64efdcda7729a78d897f0d283dbb017', - './include/SugarCharts/Jit/tpls/chart.tpl' => 'e224555cacd075ed49e115b7b6d0049e', - './include/SugarCharts/Jit/tpls/DashletGenericChartScript.tpl' => '5197cef3a47d67ee627e15446d287a46', - './include/SugarCharts/Jit/js/mySugarCharts.js' => 'b92c7d2fe293381b04c894fcd7e66803', + './include/SugarCharts/JsChart.php' => '5dd1e99f82eb957f923d1b8259b998cb', + './include/SugarCharts/Jit/tpls/chart.tpl' => '4d83505085860cbb9e7033e837f16e3e', + './include/SugarCharts/Jit/tpls/DashletGenericChartScript.tpl' => '5312c33dc34501800844f3defb827890', + './include/SugarCharts/Jit/js/mySugarCharts.js' => '58548cca5fed14059632d853370eab88', './include/SugarCharts/Jit/js/sugarCharts.js' => 'bdbe8bcc33b0571424c2dccac218fff5', './include/SugarCharts/Jit/js/Jit/jit.js' => '36abd719897cd5133ee2c6d058ac0766', './include/SugarCharts/Jit/css/base.css' => '775352bc541e0480ba0c5c03f0c4c56a', @@ -6338,17 +6406,20 @@ $md5_string = array ( './include/SugarCharts/Jit/FlashCanvas/proxy.php' => '82ccbc7400b0bda3a33316920de41e60', './include/SugarCharts/Jit/FlashCanvas/flashcanvas.swf' => '528d82bb81799f23d4def3425badf913', './include/SugarCharts/SugarChart.php' => 'af248f083b6247c9a6fd5417b897cb14', - './include/SubPanel/SubPanelTiles.js' => '50e304ca37344ff17a4a07100aaa0b34', - './include/SubPanel/tpls/singletabmenu.tpl' => '61d073f56fa3fbee90daa84950fb60a3', + './include/SubPanel/SubPanelTiles.js' => '18b37efe1462393264a0968ab60298eb', + './include/SubPanel/tpls/singletabmenu.tpl' => '6a709e13f85832b10a83e030094b5131', './include/SubPanel/subpanels.txt' => '8b89c0ee2426d40916d98a646ec26e7a', './include/SubPanel/registered_layout_defs.php' => 'b0f5b089cf2f88536e2f04ef254a6193', - './include/SubPanel/SugarTab.php' => '70da1bbbf0afdd019a9e7f10a8b22ca0', + './include/SubPanel/SugarTab.php' => 'a03799c5bc116a4a68e567e4cfb00b23', './include/SubPanel/SubPanelViewer.php' => '90e1b9be158b208af3fdd4224621dc63', './include/SubPanel/SubPanelTilesTabs.php' => '1cb4c27d253c46049261c2468f7135bc', - './include/SubPanel/SubPanelTiles.php' => '93eadec16e9185ec3db437dd0e8b9a28', - './include/SubPanel/SubPanelDynamic.html' => '1abd391224e145ca37f1ad9debf8fb71', + './include/SubPanel/SubPanelTiles.php' => 'fe27387c65a1f4bd9c6963bb56dadc16', + './include/SubPanel/SubPanelDynamic.html' => '23261c96183783a77101895a7f2fcd72', './include/SubPanel/SubPanelDefinitions.php' => 'fbb751b4996caed6034ceeb36edf7ccd', - './include/SubPanel/SubPanel.php' => '903b340cbcbd48face10f17625b57b41', + './include/SubPanel/SubPanel.php' => '0c0b7840d0cd7fbd6c5d8e11b7bc0424', + './include/Smarty/plugins/modifier.multienum_to_ac.php' => 'a6ffd6f3338c45b05d3ee853b3f320ae', + './include/Smarty/plugins/modifier.lookup.php' => '3b286a641cc7c5a7ed482cf6897b9a68', + './include/Smarty/plugins/function.sugar_ajax_url.php' => '51ba79d83c358f4bb6d483648da1b96d', './include/Smarty/plugins/shared.make_timestamp.php' => '2d98e1b8ae60c93316d90bf152d3f5a5', './include/Smarty/plugins/shared.escape_special_chars.php' => '1a8d89273862e174b64f683d42feb198', './include/Smarty/plugins/outputfilter.trimwhitespace.php' => '25a2cdd916bf01bb8caa45a23fdf8d63', @@ -6386,24 +6457,24 @@ $md5_string = array ( './include/Smarty/plugins/function.sugar_replace_vars.php' => 'a72d58f8842fcd9b39126d6324f1157a', './include/Smarty/plugins/function.sugar_phone.php' => '0b698000fe4c56eaa01498f363a62907', './include/Smarty/plugins/function.sugar_number_format.php' => '11a1900821c4ba7b1621f2ee39a69aa2', - './include/Smarty/plugins/function.sugar_link.php' => 'e2109fda882d548bf256b72a07de2029', + './include/Smarty/plugins/function.sugar_link.php' => 'aef70ace63c46348831d9c33a8e34861', './include/Smarty/plugins/function.sugar_include.php' => '7129e4a4c3b856917d352e62783f67ac', './include/Smarty/plugins/function.sugar_image.php' => '711ae380835a8819e08757aed10fcaee', './include/Smarty/plugins/function.sugar_help.php' => '70afb79935fed0839b175dcb90defd77', './include/Smarty/plugins/function.sugar_getwebpath.php' => '42a9c08d0104dc9e692ace8e5361fdd1', './include/Smarty/plugins/function.sugar_getjspath.php' => '57012e520ede6460a5246cb49dd6ce16', './include/Smarty/plugins/function.sugar_getimagepath.php' => 'f95c722408c0860608c3cfdaf41ca57c', - './include/Smarty/plugins/function.sugar_field.php' => 'c91e8279c69999e11a36c96adb838839', + './include/Smarty/plugins/function.sugar_field.php' => '132b52f66ab797ff621393025b4a8459', './include/Smarty/plugins/function.sugar_fetch.php' => '6fd07816cbba8003cdb31d3ee067271f', './include/Smarty/plugins/function.sugar_evalcolumn_old.php' => '85b786307307859d4221cf32466d7893', './include/Smarty/plugins/function.sugar_evalcolumn.php' => '59740a8d35e31740068ffd7e82067e4c', './include/Smarty/plugins/function.sugar_currency_format.php' => '328379f1c05a4e8e60d640ce4fc8cb15', './include/Smarty/plugins/function.sugar_connector_display.php' => 'e3b0ed819e977806f10e946bd7b9152a', './include/Smarty/plugins/function.sugar_button_slider.php' => '6152ab8014fecf6fa1b6af75c28af497', - './include/Smarty/plugins/function.sugar_button.php' => '0901a18a575bb79f8e002cf1575125d6', + './include/Smarty/plugins/function.sugar_button.php' => '4b0e3a959f3c7770150a5fa44f67501e', './include/Smarty/plugins/function.popup_init.php' => 'bbf08a63f3a1ae2679b324d23cfce520', './include/Smarty/plugins/function.popup.php' => 'cf231d09647d1b1cf0adf5904b66b6a6', - './include/Smarty/plugins/function.overlib_includes.php' => 'a9ebdebac2bff90663da6090767b3f39', + './include/Smarty/plugins/function.overlib_includes.php' => '29ae859841fae600617f5ff4d8ae76d1', './include/Smarty/plugins/function.multienum_to_array.php' => '402c543b8c0179e5e8f712dc304bf891', './include/Smarty/plugins/function.math.php' => '99aa00ff372550f12df400da784ebab4', './include/Smarty/plugins/function.mailto.php' => '5ba678549af1712ff9e64c244a8806c1', @@ -6453,19 +6524,19 @@ $md5_string = array ( './include/Smarty/LICENSE' => '8c2e1ec1540fb3e0beb68361344cba7e', './include/Smarty/Config_File.class.php' => '8852379ae39541f5e3355591ee0bfa03', './include/Smarty/COPYING.lib' => '8c2e1ec1540fb3e0beb68361344cba7e', - './include/SearchForm/tpls/header.tpl' => '6fd75109a10398c760c2b4c42063c9e5', + './include/SearchForm/tpls/header.tpl' => '7c13ca6314772f8573dcaa39d9f1991b', './include/SearchForm/tpls/footer.tpl' => '6b6c94cb29d2ab3259a6a17a9078f16e', - './include/SearchForm/tpls/SearchFormGenericAdvanced.tpl' => '8513d66e5e35f7a5d8e6aa10bcdaa00a', - './include/SearchForm/tpls/SearchFormGeneric.tpl' => '6bd324f8c9145e9a100aa6f99efc5a20', + './include/SearchForm/tpls/SearchFormGenericAdvanced.tpl' => '7dc2be0d14d74c0c82c47112eb95cd77', + './include/SearchForm/tpls/SearchFormGeneric.tpl' => 'a990736e9cdfe780f4b8df5d2d2b98de', './include/SearchForm/SugarSpot.php' => '0536606cc025c51415010ff7ea4c307b', - './include/SearchForm/SearchForm2.php' => '84c443bf1a9a2fb38eb3e9c3b5997149', - './include/SearchForm/SearchForm.php' => '021ef820b8e6de5685cce6e79cdb1648', + './include/SearchForm/SearchForm2.php' => 'aa0ff77f69fbe0c4954bc7c5f55a9e92', + './include/SearchForm/SearchForm.php' => '4b432a6438bf123cd630b0e3e7cffac8', './include/QuickSearchDefaults.php' => '88b97ced88d3731c401b56b94c91e775', './include/Popups/tpls/header.tpl' => '87575a24e2cb8d828fc1eae2a7378952', './include/Popups/tpls/footer.tpl' => '0a34f3223e0e1b88cf09b3a657b61924', - './include/Popups/tpls/PopupGeneric.tpl' => 'fd9ee8f9e8be4b16edf77391d7c5c02f', + './include/Popups/tpls/PopupGeneric.tpl' => '1ccc1f2bcf392daa5d762a39f17245da', './include/Popups/Popup_picker.php' => '2b2071f0293ba8a28f95dd657598910d', - './include/Popups/PopupSmarty.php' => '5d98043dfed17471253b101177a6ae7e', + './include/Popups/PopupSmarty.php' => '6966ab1a9cee78aa58fc1fccd6549d35', './include/Pear/XML_HTMLSax3/LICENSE' => 'a45bb1bbeed9e26b26c5763df1d3913d', './include/Pear/XML_HTMLSax3/HTMLSax3/States.php' => '5b528baa84631f85349a7183597d2fb3', './include/Pear/XML_HTMLSax3/HTMLSax3/Decorators.php' => '34a9a95566c891f013584073fbadaf7e', @@ -6475,23 +6546,26 @@ $md5_string = array ( './include/Pear/Crypt_Blowfish/license.txt' => 'a45bb1bbeed9e26b26c5763df1d3913d', './include/Pear/Crypt_Blowfish/Blowfish/DefaultKey.php' => '8274b556662cc178342ea96940b36514', './include/Pear/Crypt_Blowfish/Blowfish.php' => 'b391980575340d0fe5bf2df72bc13932', - './include/OutboundEmail/OutboundEmail.php' => '6ce7befed23ccff901113d8336100c62', + './include/OutboundEmail/OutboundEmail.php' => '70a4d3f98f545f646cd813f7452c2143', './include/MySugar/tpls/retrieveReportCharts.tpl' => '8d16a5e11f1c08ac4b6b362f20c68add', './include/MySugar/tpls/retrievePage.tpl' => '2154171130e87a814aa990d1e9bf3403', './include/MySugar/tpls/dashletsSearchResults.tpl' => '7bf094ad0bb191aa01959486e7cd6444', './include/MySugar/tpls/chartDashletsSearchResults.tpl' => '025432deb422b2675876a8c4d27cb15c', - './include/MySugar/tpls/addDashletsDialog.tpl' => '6c91f3cefcd2a8e9997631bc2cbb4c65', - './include/MySugar/tpls/MySugar.tpl' => '10c556f20699f03dcbb213e5c629e877', - './include/MySugar/javascript/MySugar.js' => 'b35073d24f6fa5b2046eba37e9aeb14f', + './include/MySugar/tpls/addDashletsDialog.tpl' => '35ff31902797ced09c4390ebe864b34e', + './include/MySugar/tpls/MySugar.tpl' => '58f2e89dc00ec4ba62361fe4b930ac45', + './include/MySugar/javascript/MySugar.js' => '2009f6e609431576ff4e0f28dc9ff585', './include/MySugar/MySugar.php' => '7d325108dbcd3ce328fa714c62ec7a55', - './include/MySugar/DashletsDialog/DashletsDialog.php' => 'e16fcfab4cb76f1cbfb4d8d4fb53100a', - './include/MassUpdate.php' => 'f81092136ba82618f3142bc31e79af88', + './include/MySugar/DashletsDialog/DashletsDialog.php' => '362525dbe1d032026c8a57e93700b0c9', + './include/MassUpdate.php' => 'd362d8a5c80270dfd560939af2770fd4', + './include/MVC/View/views/view.quickedit.php' => 'ade92f07bb5eb553efe4623093e5e60f', + './include/MVC/View/views/view.metadata.php' => 'e90c49375ed6eb09890f99085467b9b3', + './include/MVC/View/views/view.ajaxui.php' => '4d31344c7c1392e5252e1c64b4319077', './include/MVC/View/views/view.xml.php' => '028d18c71c2dae2db826d0cc6d32306c', './include/MVC/View/views/view.vcard.php' => '32fa32960fe82caee39fcb8833541ad5', './include/MVC/View/views/view.sugarpdf.php' => '334694668f28d954182d05c196eef396', './include/MVC/View/views/view.sugarpdf.config.php' => 'e98d6968b4b8a70797d07b311553e7f0', './include/MVC/View/views/view.serialized.php' => '6746e128e8dacee78ecbf70ea3559cbb', - './include/MVC/View/views/view.quickcreate.php' => 'af21a48454ccec122fa19dad51521f6b', + './include/MVC/View/views/view.quickcreate.php' => '46266c0da5200fc4b269948dfc2d6948', './include/MVC/View/views/view.quick.php' => '9a1fa9ad8fce5230124ee320fcc42266', './include/MVC/View/views/view.popup.php' => '840037771e14e3a828783d8ac486c725', './include/MVC/View/views/view.noaccess.php' => '1cab33d38afb080ca5dbfaa70a05e69a', @@ -6503,8 +6577,8 @@ $md5_string = array ( './include/MVC/View/views/view.importvcard.php' => '6c25b128b492aee11c09a127b55d38e0', './include/MVC/View/views/view.html.php' => '4269cd69a757967dfadf0d1505ab8302', './include/MVC/View/views/view.edit.php' => 'd6d369b764db7f13873ea7a2fd7bb4d5', - './include/MVC/View/views/view.detail.php' => 'a41326fbffb6ca8424e8a1e097aa4c1b', - './include/MVC/View/views/view.config.php' => '518f2096065672246f0f7da885e63ef0', + './include/MVC/View/views/view.detail.php' => 'f051d035c4f689f41292f30b9a950be2', + './include/MVC/View/views/view.config.php' => 'df90a0e59ee8e6d8c86aad43b5b9fefc', './include/MVC/View/views/view.classic.php' => '6be217537624ef09bf66eccdfbc8eb3c', './include/MVC/View/views/view.classic.config.php' => 'da126a4e65433dc43ad518c3a7322172', './include/MVC/View/views/view.ajax.php' => 'f133e09497e83fd5bb41a2545320bc51', @@ -6512,26 +6586,26 @@ $md5_string = array ( './include/MVC/View/tpls/modulelistmenu.tpl' => '796ce676d310cf69a84618aa0c85082e', './include/MVC/View/tpls/Importvcard.tpl' => 'aa5117be30dc5b8c1fc726ba44a3eb00', './include/MVC/View/ViewFactory.php' => '8c19d770416ea69207b10f71d6a09e65', - './include/MVC/View/SugarView.php' => '3ba5c97ad3a5c2173544fdfede2a672e', + './include/MVC/View/SugarView.php' => '777d6b2235e2951db81a2e80a38cdb56', './include/MVC/SugarModule.php' => 'ce58476e24ad1717fe30192d10e28adc', - './include/MVC/SugarApplication.php' => 'aa5f4873f931f586d311810e180e11e3', + './include/MVC/SugarApplication.php' => '01e924893b721aee5f443115e5b3800b', './include/MVC/Controller/file_access_control_map.php' => 'c94a1a349da51c17f5758d5f1ad6a364', './include/MVC/Controller/entry_point_registry.php' => '4d01e1183701ca2b002f494706c1852e', - './include/MVC/Controller/action_view_map.php' => 'b5a22402b8cd64eb8971a99a14a99c03', + './include/MVC/Controller/action_view_map.php' => '2c04d8cb7c2bfa1c7e4ed7234d699479', './include/MVC/Controller/action_file_map.php' => 'c35918d4fb518bb6f3c682efbabc10a4', - './include/MVC/Controller/SugarController.php' => '32152f62c684bbb63bda849427c5dabb', + './include/MVC/Controller/SugarController.php' => '2b854f2d18dced7e952df9f654b1a23b', './include/MVC/Controller/ControllerFactory.php' => '52b59a09b463a19eff7f34203b425447', './include/Localization/Localization.php' => '6802050d598d1921aa729e81ebf70505', - './include/ListView/ListViewDCMenu.tpl' => '106226bf74c3da2aab933ae8869b69bd', + './include/ListView/ListViewDCMenu.tpl' => '4cf73b5138500ad05a32488a35cc330b', './include/ListView/ListViewXTPL.php' => 'e70a4929a6e81eb2f63d60a5302c0780', - './include/ListView/ListViewSmarty.php' => 'c3b44cb91aba732ed13888f0b219a672', + './include/ListView/ListViewSmarty.php' => '8892ea724ff2127d7d340679d0ebb8ba', './include/ListView/ListViewPagination.tpl' => 'bcb4adbaea266d27495ac72fa7a4721d', - './include/ListView/ListViewNoMassUpdate.tpl' => 'b67e393107c9d80223e4abb21eec261a', - './include/ListView/ListViewGeneric.tpl' => 'd8089d8dc41ef1428076eefff2ab9e69', - './include/ListView/ListViewFacade.php' => 'eca289f7cf40a7e503255644bec57716', - './include/ListView/ListViewDisplay.php' => '1cacb2736463eb46a0afa3b78d12dfa8', + './include/ListView/ListViewNoMassUpdate.tpl' => 'a50cb64c5bf6a435237f7af223fa9479', + './include/ListView/ListViewGeneric.tpl' => '3a54bf2559119f190e26cabc2237988f', + './include/ListView/ListViewFacade.php' => '8955992db6b2a45ef3a6237b85f7b61a', + './include/ListView/ListViewDisplay.php' => '3e9fa64f5894d9f3b6dacc474d5c4d88', './include/ListView/ListViewData.php' => '57d87d2efe1c5d174c015147058be1ce', - './include/ListView/ListView.php' => '718b37f45e567fb813ab593166fba9d6', + './include/ListView/ListView.php' => 'cc9c66b91f17405b9899518e3d42d8db', './include/JSON.php' => '419327255daae457ef1765ec305148f3', './include/HTTP_WebDAV_Server/license.txt' => 'a45bb1bbeed9e26b26c5763df1d3913d', './include/HTTP_WebDAV_Server/dav.txt' => 'c5235ed64efa685da638c6dcdb6a9708', @@ -6541,31 +6615,32 @@ $md5_string = array ( './include/HTTP_WebDAV_Server/Server.php' => '85e6613006abbd02d316572254f9f97f', './include/HTTP_WebDAV_Server/README' => 'e6f0ca3d7e4fa2b20310995f269c3ef2', './include/GroupedTabs/GroupedTabStructure.php' => '387bbcd7327931d43dd1e88b6b1bf70e', - './include/EditView/header.tpl' => 'e0da0b7602a8503a5487e63aef9720d2', + './include/EditView/SubpanelQuickEdit.php' => 'a1e50b85705880c9090b531ece5add67', + './include/EditView/header.tpl' => '2fdf448539e8ed7e732f3f20d56b8d9e', './include/EditView/footer.tpl' => '7514ad752e638256db617b92df7d577a', - './include/EditView/SugarVCR.php' => '459abe407efe354afd1e53451f968017', - './include/EditView/SubpanelQuickCreate.php' => 'c2ab8cbf9eebd99a7a934db4c2b28820', + './include/EditView/SugarVCR.php' => '3a8be7762579684bd72acb160e617f82', + './include/EditView/SubpanelQuickCreate.php' => 'cd0875e94fed1896293b2b9715c5c38a', './include/EditView/QuickCreate.tpl' => '7b5551dd497dfb15af7ae2732db18e44', './include/EditView/QuickCreate.php' => '20043843a73497bc94bda42a3a54b38e', './include/EditView/PopupQuickCreate.php' => 'e7347241af58af0d28b86fde19695946', - './include/EditView/EditView2.php' => '8dbae87a0d24f02011b26b236b2184fc', - './include/EditView/EditView.tpl' => '09d53d334288cfa0b41bdc929d98dd22', + './include/EditView/EditView2.php' => '357e47580fa89a26dfa2f753a25b59bc', + './include/EditView/EditView.tpl' => '661bb27433273d4fe59417d57ac57626', './include/EditView/EditView.php' => '0666ea6e21db2c8ef2a6a7615ea010c7', './include/DetailView/header.tpl' => '784a15901fbebe39f7495c56df41a758', './include/DetailView/footer.tpl' => '552e0313c998b223dd6242e5c5678b72', './include/DetailView/DetailView2.php' => '9478bef6cdad4af70878d6be5962909d', - './include/DetailView/DetailView.tpl' => 'a7e16e70f76c420076b72ad3305b77b2', - './include/DetailView/DetailView.php' => '35d047b596e7d3c9e122703c9c0c9c2b', + './include/DetailView/DetailView.tpl' => 'f2aa9440fd4867f83e08b9e41df7b80e', + './include/DetailView/DetailView.php' => '9d96ca309384ac135253287472304394', './include/Dashlets/DashletRssFeedTitle.php' => 'bada41e47f194a820f23f1aae8f55f2c', - './include/Dashlets/DashletGenericAutoRefreshDynamic.tpl' => 'f769c32f17ac26313b340fec2861112e', - './include/Dashlets/DashletGenericDisplay.tpl' => 'd6afdb7417234d0bb5e82388d3b69c84', - './include/Dashlets/DashletGenericConfigure.tpl' => '9c9bdb6f6d6a79b2ac325fc40790b695', - './include/Dashlets/DashletGenericAutoRefresh.tpl' => '6142a7f53bcf1b5b45414ef2aa415639', - './include/Dashlets/DashletGenericChartConfigure.tpl' => 'db96a4bcb690f325cfb41e60ab4b4791', - './include/Dashlets/DashletGenericChart.php' => '4ba364f711dc6a9e295298c9e685b00f', - './include/Dashlets/DashletGeneric.php' => '6a914b9515d29587019f1d5f20823a45', + './include/Dashlets/DashletGenericAutoRefreshDynamic.tpl' => 'b6d4c69cf2323a1971d5ec4b28f3a2df', + './include/Dashlets/DashletGenericDisplay.tpl' => 'd9c2a6f747381101177d84faa4936125', + './include/Dashlets/DashletGenericConfigure.tpl' => 'd95ef075520fd1f5ccd6ada532d95f2c', + './include/Dashlets/DashletGenericAutoRefresh.tpl' => '15016e42fe248369817665692dc6c16c', + './include/Dashlets/DashletGenericChartConfigure.tpl' => '9f371d5560c3d4f63d348f8466c71209', + './include/Dashlets/DashletGenericChart.php' => 'f3e771a0a6f3257d761dcfcdb04444aa', + './include/Dashlets/DashletGeneric.php' => '8b0fdd024937758348c167af74d725e0', './include/Dashlets/DashletCacheBuilder.php' => '80f7f6f582d141f5b1e3f8d5da52bf34', - './include/Dashlets/Dashlet.php' => 'c6096d2756a85211bdd40d8013047e78', + './include/Dashlets/Dashlet.php' => 'f4ac3832032478f5803d18a6ff19919c', './image.php' => '59c0f0d2767ed6ed5eac96335ad6d732', './json_server.php' => '666b79888f08bbe2a75bd4990426da04', './examples/SoapTestPortal2.php' => '83c1dbd821d080177d9e1a98725f341b', @@ -6576,7 +6651,7 @@ $md5_string = array ( './examples/ExampleLeadCapture.php' => 'd6deb45572959e642fb019253c5703dc', './examples/EXAMPLES_README.txt' => 'b55744b5e2684d91f6d3f98db4553673', './emailmandelivery.php' => 'eddfad677960438dfe1584bca8718acf', - './download.php' => '4958eb23abe4d07f3f5d3053bba10741', + './download.php' => 'c2eb290cdd61ab58263f772eea86bd3d', './dictionary.php' => '42619156f21102938b4da79d2cf9cb48', './Zend/Version.php' => '7ed9dea03172b0f8fb11f085a17f100b', './Zend/Validate/Ip.php' => '05326c26a0f419d8dac8c168f6cb7f12', @@ -6599,6 +6674,7 @@ $md5_string = array ( './Zend/Oauth/Signature/Rsa.php' => '1c34a9f3ba22e92181fd20635bd165a0', './Zend/Oauth/Signature/Plaintext.php' => '172f0dbf4ffed18d6aa136bbe752c4d2', './Zend/Oauth/Signature/Hmac.php' => '7de78bcbd009391679c290259d4f0b7e', + './Zend/Oauth/Provider.php' => 'e3e4bcd3eaf3deb984f2ca2eb53c263a', './Zend/Oauth/Http/Utility.php' => 'b423ef547710255a45cac24c0f2212b6', './Zend/Oauth/Http/UserAuthorization.php' => '19865a03744565805aedc37c211451b1', './Zend/Oauth/Http/RequestToken.php' => 'a601ddf2a654043d45c8850970c3f81d', @@ -6870,6 +6946,15 @@ $md5_string = array ( './Zend/Gdata/Docs/DocumentListFeed.php' => '0e1f8bd2edd405a2cc7338398ebc8193', './Zend/Gdata/Docs/DocumentListEntry.php' => 'eca757a3e4835b698ca58ed561c62528', './Zend/Gdata/Docs.php' => '3d94d75d20789fff946a4e70c37c1c73', + './Zend/Gdata/Contacts/ListFeed.php' => '3dbd50dff7507d4103fcd6336e66874b', + './Zend/Gdata/Contacts/ListEntry.php' => 'e3226f47b4e16572fcc19b1441bd7ea7', + './Zend/Gdata/Contacts/Extension/PhoneNumber.php' => '67497b5b45b5f48aa5af09d162f8da31', + './Zend/Gdata/Contacts/Extension/Organization.php' => '97b4d9e04201416188a62d139b898423', + './Zend/Gdata/Contacts/Extension/Name.php' => 'a2d2ddfe6a1de3e809c4996a4d7f2094', + './Zend/Gdata/Contacts/Extension/Email.php' => 'dec5f832ae28313769437402f2d9de71', + './Zend/Gdata/Contacts/Extension/Birthday.php' => '9a39cd604ac697e50374968aef5ed4f3', + './Zend/Gdata/Contacts/Extension/Address.php' => '5e6de9fb18578786fb9448bb8c0163e0', + './Zend/Gdata/Contacts.php' => '7ba8fa266cfd13c9a51276ff38b1d1ac', './Zend/Gdata/ClientLogin.php' => '24f07d68ad16d4d76c3ac02b0a172179', './Zend/Gdata/Calendar/ListFeed.php' => '689104be14f604a351305bd4f259534b', './Zend/Gdata/Calendar/ListEntry.php' => 'a703e4f6997b1d2220ea7d8ca71bfeac', @@ -6968,11 +7053,21 @@ $md5_string = array ( './Zend/Crypt/DiffieHellman.php' => 'ec0a4f522b732f7fcbb9c4ab94d926e1', './Zend/Crypt.php' => '0e72fd104506094fd2c7682b0b924542', './install.php' => '19729b83b5d2ea947763f56f264a88e8', - './export.php' => 'e98d50f9c92189941c352613ba594cbf', + './export.php' => 'c2cce5725ae0f8f464b2f2706e128b1d', + './data/Relationships/SugarRelationship.php' => '6b27efaed6e2eb432409c8695b93cec0', + './data/Relationships/RelationshipFactory.php' => '6d675d3b037e37421d5b3fb2a80c327d', + './data/Relationships/One2OneRelationship.php' => 'c8154bd4190e2f006c3cb8e050dbab44', + './data/Relationships/One2OneBeanRelationship.php' => '82a915b9f96f0dc044c649374aec5562', + './data/Relationships/One2MRelationship.php' => 'f49f28b30a03c5afa471c99801f94c3d', + './data/Relationships/One2MBeanRelationship.php' => 'b5b444ff623d7442afc60e3771bd75e9', + './data/Relationships/M2MRelationship.php' => 'd90547097306b15cea70edd1bb493eda', + './data/Relationships/EmailAddressRelationship.php' => '886780983432b3d6094bb0135d5562ea', + './data/Link2.php' => 'e959b50abab84ba69c76e0300e769037', + './data/BeanFactory.php' => '18ea5137a9f4038003ff81125c221bf4', './data/upload/index.html' => '9cd784063d39b18d308932c28c385853', './data/Tracker.php' => '5dfc3f390ecccd8cbb1229e01f878593', - './data/SugarBean.php' => 'd0c9381ce074618f013713ba097bd0f8', - './data/Link.php' => '4274e59a6547b8022ebbdf70120d916e', + './data/SugarBean.php' => '059b8e110a9129d496c06ffd4a82089b', + './data/Link.php' => 'df1735a1a781a9ed552cace8d418af7d', './custom/index.html' => 'b0070a296647b6026d1800db14510e3c', './cron.php' => '3d65f5cc08d20790387c79a761c776f7', './campaign_trackerv2.php' => '66ca6f16d0d670bcaf528f4b9d95494b', @@ -6992,10 +7087,11 @@ $md5_string = array ( './WebToLeadCapture.php' => 'ba444dc5ae4b027fe6520f2208ea29e1', './TreeData.php' => 'e04004734f749d6487766d65ec7bd7d5', './SugarSecurity.php' => '18bc7aa4ae7154d5ef3729892a9a1bac', + './ModuleInstall/extensions.php' => 'd79f02336c1334db35233254b1f5c75a', './ModuleInstall/PackageManager/tpls/PackageManagerScripts.tpl' => 'e7c2b3046ecef5f7ff39e295ddb8ddc7', './ModuleInstall/PackageManager/tpls/PackageManagerLicense.tpl' => 'd03bd21d5c5b48a9810fa88122a1f114', './ModuleInstall/PackageManager/tpls/PackageForm.tpl' => 'b72df135a4a4429d28eaefeef29500f5', - './ModuleInstall/PackageManager/tpls/ModuleLoaderListView.tpl' => '8de5a3f9a3101d20bf1fb1ad23c19ca4', + './ModuleInstall/PackageManager/tpls/ModuleLoaderListView.tpl' => '94153d21e993e74ce54a15d049f38893', './ModuleInstall/PackageManager/metadata/listviewdefs.php' => '8832b4f745ac72f68ebf507a8e7890e8', './ModuleInstall/PackageManager/PackageManagerDownloader.php' => '8df8614ebada40eb9a8f30f8487581f2', './ModuleInstall/PackageManager/PackageManagerDisplay.php' => '48d00f1fb6f7904ae1dc22166a2f0637', @@ -7003,8 +7099,8 @@ $md5_string = array ( './ModuleInstall/PackageManager/PackageManager.php' => 'db2831d05f733613056e7fe599d06fa9', './ModuleInstall/PackageManager/PackageController.php' => '425566c9378597c7990692fe993b5dc4', './ModuleInstall/PackageManager/ListViewPackages.php' => 'e4641f286e0b5c4e0aad030159d14a2d', - './ModuleInstall/ModuleScanner.php' => '7c25685e0d3b677e1074628be8a1b1fc', - './ModuleInstall/ModuleInstaller.php' => 'b30c2b24c43efb8d53b1a829b78f832d', + './ModuleInstall/ModuleScanner.php' => '1fc1978107b0cfdd4290894173d9db45', + './ModuleInstall/ModuleInstaller.php' => '3712113c3886525c2f3eba34eff5219e', './HandleAjaxCall.php' => 'cc43ac1ae1b3545ae98e79f12da47d14', ); ?> diff --git a/include/Dashlets/Dashlet.php b/include/Dashlets/Dashlet.php index b2702142..37811d96 100644 --- a/include/Dashlets/Dashlet.php +++ b/include/Dashlets/Dashlet.php @@ -60,6 +60,11 @@ class Dashlet * @var bool */ var $isRefreshable = true; + /** + * true if the Dashlet configuration options panel has the clear button + * @var bool + */ + public $isConfigPanelClearShown = true; /** * true if the Dashlet contains javascript * @var bool diff --git a/include/Dashlets/DashletGeneric.php b/include/Dashlets/DashletGeneric.php index 18f0b301..83f85c44 100644 --- a/include/Dashlets/DashletGeneric.php +++ b/include/Dashlets/DashletGeneric.php @@ -226,12 +226,14 @@ class DashletGeneric extends Dashlet { 'displayRows' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_DISPLAY_ROWS'], 'title' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_TITLE'], 'save' => $GLOBALS['app_strings']['LBL_SAVE_BUTTON_LABEL'], + 'clear' => $GLOBALS['app_strings']['LBL_CLEAR_BUTTON_LABEL'], 'autoRefresh' => $GLOBALS['app_strings']['LBL_DASHLET_CONFIGURE_AUTOREFRESH'], )); $this->configureSS->assign('id', $this->id); $this->configureSS->assign('showMyItemsOnly', $this->showMyItemsOnly); $this->configureSS->assign('myItemsOnly', $this->myItemsOnly); $this->configureSS->assign('searchFields', $this->currentSearchFields); + $this->configureSS->assign('showClearButton', $this->isConfigPanelClearShown); // title $this->configureSS->assign('dashletTitle', $this->title); diff --git a/include/Dashlets/DashletGenericAutoRefresh.tpl b/include/Dashlets/DashletGenericAutoRefresh.tpl index 74e00bdc..3e954c07 100644 --- a/include/Dashlets/DashletGenericAutoRefresh.tpl +++ b/include/Dashlets/DashletGenericAutoRefresh.tpl @@ -50,7 +50,7 @@ if (document.getElementById("{$dashletId}_interval").value > 0) {ldelim} function refreshDashlet{$strippedDashletId}() {ldelim} //refresh only if offset is 0 - if ( document.getElementById("{$dashletId}_offset").value == '0' ) {ldelim} + if ( SUGAR.mySugar && document.getElementById("{$dashletId}_offset").value == '0' ) {ldelim} SUGAR.mySugar.retrieveDashlet("{$dashletId}","{$url}"); {rdelim} {rdelim} diff --git a/include/Dashlets/DashletGenericAutoRefreshDynamic.tpl b/include/Dashlets/DashletGenericAutoRefreshDynamic.tpl index 5209406f..b070359f 100644 --- a/include/Dashlets/DashletGenericAutoRefreshDynamic.tpl +++ b/include/Dashlets/DashletGenericAutoRefreshDynamic.tpl @@ -53,7 +53,7 @@ if(document.getElementById("{$dashletId}_interval").value > 0) {ldelim} function refreshDashlet{$strippedDashletId}() {ldelim} //refresh only if offset is 0 - if ( document.getElementById("{$dashletId}_offset").value == '0' ) {ldelim} + if (SUGAR.mySugar && document.getElementById("{$dashletId}_offset").value == '0' ) {ldelim} SUGAR.mySugar.retrieveDashlet("{$dashletId}","{$url}"); {rdelim} {rdelim} diff --git a/include/Dashlets/DashletGenericChart.php b/include/Dashlets/DashletGenericChart.php index 87045095..7356f57f 100644 --- a/include/Dashlets/DashletGenericChart.php +++ b/include/Dashlets/DashletGenericChart.php @@ -248,11 +248,13 @@ abstract class DashletGenericChart extends Dashlet $this->currentSearchFields = $currentSearchFields; $this->getConfigureSmartyInstance()->assign('title',translate('LBL_TITLE','Charts')); $this->getConfigureSmartyInstance()->assign('save',$GLOBALS['app_strings']['LBL_SAVE_BUTTON_LABEL']); + $this->getConfigureSmartyInstance()->assign('clear',$GLOBALS['app_strings']['LBL_CLEAR_BUTTON_LABEL']); $this->getConfigureSmartyInstance()->assign('id', $this->id); $this->getConfigureSmartyInstance()->assign('searchFields', $this->currentSearchFields); $this->getConfigureSmartyInstance()->assign('dashletTitle', $this->title); $this->getConfigureSmartyInstance()->assign('dashletType', 'predefined_chart'); $this->getConfigureSmartyInstance()->assign('module', $_REQUEST['module']); + $this->getConfigureSmartyInstance()->assign('showClearButton', $this->isConfigPanelClearShown); if($this->isAutoRefreshable()) { $this->getConfigureSmartyInstance()->assign('isRefreshable', true); diff --git a/include/Dashlets/DashletGenericChartConfigure.tpl b/include/Dashlets/DashletGenericChartConfigure.tpl index e853c3e1..4fdb37c4 100644 --- a/include/Dashlets/DashletGenericChartConfigure.tpl +++ b/include/Dashlets/DashletGenericChartConfigure.tpl @@ -88,7 +88,10 @@ - + {if $showClearButton} + + {/if} + diff --git a/include/Dashlets/DashletGenericConfigure.tpl b/include/Dashlets/DashletGenericConfigure.tpl index 216d8436..a9372098 100644 --- a/include/Dashlets/DashletGenericConfigure.tpl +++ b/include/Dashlets/DashletGenericConfigure.tpl @@ -127,6 +127,9 @@ + {if $showClearButton} + + {/if} diff --git a/include/Dashlets/DashletGenericDisplay.tpl b/include/Dashlets/DashletGenericDisplay.tpl index 88d8c224..4ad49ced 100644 --- a/include/Dashlets/DashletGenericDisplay.tpl +++ b/include/Dashlets/DashletGenericDisplay.tpl @@ -107,9 +107,9 @@ {foreach from=$displayColumns key=colHeader item=params} - -
    - {if $params.sortable|default:true} + +
    + {if $params.sortable|default:true} {sugar_translate label=$params.label module=$pageData.bean.moduleDir}   {if $params.orderBy|default:$colHeader|lower == $pageData.ordering.orderBy} {if $pageData.ordering.sortOrder == 'ASC'} @@ -135,7 +135,7 @@   {/if} - + {foreach name=rowIteration from=$data key=id item=rowData} {if $smarty.foreach.rowIteration.iteration is odd} {assign var='_rowColor' value=$rowColor[0]} @@ -173,7 +173,8 @@ {if !empty($quickViewLinks)} {if $pageData.access.edit} - + {/if} {if $pageData.access.view} diff --git a/include/DetailView/DetailView.php b/include/DetailView/DetailView.php index 07afafae..5aad4215 100644 --- a/include/DetailView/DetailView.php +++ b/include/DetailView/DetailView.php @@ -252,7 +252,7 @@ class DetailView extends ListView { ); $json = getJSONobj(); $encoded_popup_request_data = $json->encode($popup_request_data); - $audit_link = "".$this->local_app_strings['LNK_VIEW_CHANGE_LOG'].""; + $audit_link = "".$this->local_app_strings['LNK_VIEW_CHANGE_LOG'].""; } $html_text = ""; diff --git a/include/DetailView/DetailView.tpl b/include/DetailView/DetailView.tpl index e617d993..134a8cc1 100644 --- a/include/DetailView/DetailView.tpl +++ b/include/DetailView/DetailView.tpl @@ -48,7 +48,7 @@ class="yui-navset detailview_tabs" {{/if}} diff --git a/include/EditView/EditView.tpl b/include/EditView/EditView.tpl index 56fbee9e..0c050ced 100644 --- a/include/EditView/EditView.tpl +++ b/include/EditView/EditView.tpl @@ -50,7 +50,7 @@ class="yui-navset" {{/if}} @@ -75,7 +75,7 @@ class="yui-navset" {sugar_include type='php' file='{{$panel}}'} {{else}} - +
    {{* Only show header if it is not default or an int value *}} {{if !empty($label) && !is_int($label) && $label != 'DEFAULT' && !$useTabs && $showSectionPanelsTitles}} diff --git a/include/EditView/EditView2.php b/include/EditView/EditView2.php index cd9cbfd9..e5faac60 100644 --- a/include/EditView/EditView2.php +++ b/include/EditView/EditView2.php @@ -279,7 +279,6 @@ class EditView $panelCount = 0; static $itemCount = 100; //Start the generated tab indexes at 100 so they don't step on custom ones. - /* loop all the panels */ foreach ($this->defs['panels'] as $key=>$p) { @@ -290,34 +289,46 @@ class EditView } else { - foreach($p as $row=>$rowDef) { - $columnsInRows = count($rowDef); - $columnsUsed = 0; - foreach($rowDef as $col => $colDef) { - $panel[$row][$col] = is_array($p[$row][$col]) ? array('field' => $p[$row][$col]) : array('field' => array('name'=>$p[$row][$col])); - $panel[$row][$col]['field']['tabindex'] = (isset($p[$row][$col]['tabindex']) && is_numeric($p[$row][$col]['tabindex'])) ? $p[$row][$col]['tabindex'] : $itemCount; + foreach ($p as $row=>$rowDef) + { + $columnsInRows = count($rowDef); + $columnsUsed = 0; + foreach ($rowDef as $col => $colDef) + { + $panel[$row][$col] = is_array($p[$row][$col]) + ? array('field' => $p[$row][$col]) + : array('field' => array('name'=>$p[$row][$col])); - if($columnsInRows < $maxColumns) { - if($col == $columnsInRows - 1) { - $panel[$row][$col]['colspan'] = 2 * $maxColumns - ($columnsUsed + 1); - } else { - $panel[$row][$col]['colspan'] = floor(($maxColumns * 2 - $columnsInRows) / $columnsInRows); - $columnsUsed = $panel[$row][$col]['colspan']; - } - } + $panel[$row][$col]['field']['tabindex'] = + (isset($p[$row][$col]['tabindex']) && is_numeric($p[$row][$col]['tabindex'])) + ? $p[$row][$col]['tabindex'] + : $itemCount; - //Set address types to have colspan value of 2 if colspan is not already defined - if(is_array($colDef) && !empty($colDef['hideLabel']) && !isset($panel[$row][$col]['colspan'])) { - $panel[$row][$col]['colspan'] = 2; - } + if ($columnsInRows < $maxColumns) + { + if ($col == $columnsInRows - 1) + { + $panel[$row][$col]['colspan'] = 2 * $maxColumns - ($columnsUsed + 1); + } + else + { + $panel[$row][$col]['colspan'] = floor(($maxColumns * 2 - $columnsInRows) / $columnsInRows); + $columnsUsed = $panel[$row][$col]['colspan']; + } + } - $itemCount++; + //Set address types to have colspan value of 2 if colspan is not already defined + if (is_array($colDef) && !empty($colDef['hideLabel']) && !isset($panel[$row][$col]['colspan'])) + { + $panel[$row][$col]['colspan'] = 2; + } - } //foreach - } //foreach + $itemCount++; - $panel = $this->getPanelWithFillers($panel); + } + } + $panel = $this->getPanelWithFillers($panel); $this->sectionPanels[strtoupper($key)] = $panel; } @@ -429,6 +440,12 @@ class EditView if (isset($this->fieldDefs[$name]['options']) && isset($app_list_strings[$this->fieldDefs[$name]['options']])) { $this->fieldDefs[$name]['options'] = $app_list_strings[$this->fieldDefs[$name]['options']]; + if(isset($GLOBALS['sugar_config']['enable_autocomplete']) && $GLOBALS['sugar_config']['enable_autocomplete'] == true){ + $this->fieldDefs[$name]['autocomplete'] = true; + $this->fieldDefs[$name]['autocomplete_options'] = $this->fieldDefs[$name]['options']; // we need the name for autocomplete + } else { + $this->fieldDefs[$name]['autocomplete'] = false; + } } if (isset($this->fieldDefs[$name]['function'])) @@ -454,14 +471,30 @@ class EditView } } - if (isset($this->fieldDefs[$name]['type']) && $this->fieldDefs[$name]['type'] == 'function' && isset($this->fieldDefs[$name]['function_name'])) - { - $value = $this->callFunction($this->fieldDefs[$name]); - $valueFormatted = true; - } - - if (!$valueFormatted) - { + if(isset($this->fieldDefs[$name]['function'])) { + $function = $this->fieldDefs[$name]['function']; + if(is_array($function) && isset($function['name'])){ + $function = $this->fieldDefs[$name]['function']['name']; + }else{ + $function = $this->fieldDefs[$name]['function']; + } + if(!empty($this->fieldDefs[$name]['function']['returns']) && $this->fieldDefs[$name]['function']['returns'] == 'html'){ + if(!empty($this->fieldDefs[$name]['function']['include'])){ + require_once($this->fieldDefs[$name]['function']['include']); + } + $value = $function($this->focus, $name, $value, $this->view); + $valueFormatted = true; + }else{ + $this->fieldDefs[$name]['options'] = $function($this->focus, $name, $value, $this->view); + } + } + + if(isset($this->fieldDefs[$name]['type']) && $this->fieldDefs[$name]['type'] == 'function' && isset($this->fieldDefs[$name]['function_name'])){ + $value = $this->callFunction($this->fieldDefs[$name]); + $valueFormatted = true; + } + + if(!$valueFormatted) { // $this->focus->format_field($this->focus->field_defs[$name]); $value = isset($this->focus->$name) ? $this->focus->$name : ''; } @@ -472,11 +505,10 @@ class EditView } - //This code is used for QuickCreates that go to Full Form view - if ($this->populateBean && empty($this->focus->id) - && (isset($this->fieldDefs[$name]['function']['returns']) - ? $this->fieldDefs[$name]['function']['returns'] != 'html' - : true) + //This code is used for QuickCreates that go to Full Form view. We want to overwrite the values from the bean + //with values from the request if they are set and either the bean is brand new (such as a create from a subpanels) or the 'full form' button has been clicked + if ((($this->populateBean && empty($this->focus->id)) || (isset($_REQUEST['full_form']))) + && (!isset($this->fieldDefs[$name]['function']['returns']) || $this->fieldDefs[$name]['function']['returns'] != 'html') && isset($_REQUEST[$name])) { $this->fieldDefs[$name]['value'] = $this->getValueFromRequest($_REQUEST, $name); @@ -526,10 +558,9 @@ class EditView } } } - /** * display - * This method makes the Smarty variable assignments and then displays the + * This method makes the Smarty variable assignments and theautocomplete_ajax'vars the * generated view. * @param $showTitle boolean value indicating whether or not to show a title on the resulting page * @param $ajaxSave boolean value indicating whether or not the operation is an Ajax save request @@ -558,6 +589,7 @@ class EditView $this->th->ss->assign('MOD', $mod_strings); $this->th->ss->assign('fields', $this->fieldDefs); $this->th->ss->assign('sectionPanels', $this->sectionPanels); + $this->th->ss->assign('config', $sugar_config); $this->th->ss->assign('returnModule', $this->returnModule); $this->th->ss->assign('returnAction', $this->returnAction); $this->th->ss->assign('returnId', $this->returnId); @@ -845,4 +877,4 @@ class EditView return ''; } -} +} \ No newline at end of file diff --git a/include/EditView/SubpanelQuickCreate.php b/include/EditView/SubpanelQuickCreate.php index 0c0b394b..7cfeec6d 100644 --- a/include/EditView/SubpanelQuickCreate.php +++ b/include/EditView/SubpanelQuickCreate.php @@ -40,7 +40,8 @@ class SubpanelQuickCreate{ var $defaultProcess = true; function SubpanelQuickCreate($module, $view='QuickCreate', $proccessOverride = false){ - + //treat quickedit and quickcreate views as the same + if($view == 'QuickEdit') {$view = 'QuickCreate';} // locate the best viewdefs to use: 1. custom/module/quickcreatedefs.php 2. module/quickcreatedefs.php 3. custom/module/editviewdefs.php 4. module/editviewdefs.php $base = 'modules/' . $module . '/metadata/'; @@ -64,8 +65,16 @@ class SubpanelQuickCreate{ $this->ev->view = $view; $this->ev->ss = new Sugar_Smarty(); //$_REQUEST['return_action'] = 'SubPanelViewer'; - $this->ev->setup($module, null, $source); - + + $class = $GLOBALS['beanList'][$module]; + $bean = new $class(); + if(!empty($_REQUEST['record'])) { + $bean->retrieve($_REQUEST['record']); + } + $this->ev->setup($module, $bean, $source); + unset($bean); + + $this->ev->defs['templateMeta']['form']['headerTpl'] = 'include/EditView/header.tpl'; $this->ev->defs['templateMeta']['form']['footerTpl'] = 'include/EditView/footer.tpl'; $this->ev->defs['templateMeta']['form']['buttons'] = array('SUBPANELSAVE', 'SUBPANELCANCEL', 'SUBPANELFULLFORM'); diff --git a/include/EditView/SubpanelQuickEdit.php b/include/EditView/SubpanelQuickEdit.php new file mode 100644 index 00000000..02ba5cc8 --- /dev/null +++ b/include/EditView/SubpanelQuickEdit.php @@ -0,0 +1,143 @@ +ev = new EditView(); + $this->ev->view = $view; + $this->ev->ss = new Sugar_Smarty(); + //$_REQUEST['return_action'] = 'SubPanelViewer'; + + + + //retrieve bean if id or record is passed in + if (isset($_REQUEST['record']) || isset($_REQUEST['id'])){ + global $beanList; + $bean = $beanList[$module]; + $this->ev->focus = new $bean(); + + if (isset($_REQUEST['record']) && empty($_REQUEST['id'])){ + $_REQUEST['id'] = $_REQUEST['record']; + } + $this->ev->focus->retrieve($_REQUEST['record']); + //call setup with focus passed in + $this->ev->setup($module, $this->ev->focus, $source); + }else{ + //no id, call setup on new bean + $this->ev->setup($module, null, $source); + } + + $this->ev->defs['templateMeta']['form']['headerTpl'] = 'include/EditView/header.tpl'; + $this->ev->defs['templateMeta']['form']['footerTpl'] = 'include/EditView/footer.tpl'; + $this->ev->defs['templateMeta']['form']['buttons'] = array('SUBPANELSAVE', 'SUBPANELCANCEL', 'SUBPANELFULLFORM'); + $this->ev->defs['templateMeta']['form']['hideAudit'] = true; + + + $viewEditSource = 'modules/'.$module.'/views/view.edit.php'; + if (file_exists('custom/'. $viewEditSource)) { + $viewEditSource = 'custom/'. $viewEditSource; + } + + if(file_exists($viewEditSource) && !$proccessOverride) { + include($viewEditSource); + $c = $module . 'ViewEdit'; + + if(class_exists($c)) { + $view = new $c; + if($view->useForSubpanel) { + $this->defaultProcess = false; + + //Check if we shold use the module's QuickCreate.tpl file + if($view->useModuleQuickCreateTemplate && file_exists('modules/'.$module.'/tpls/QuickCreate.tpl')) { + $this->ev->defs['templateMeta']['form']['headerTpl'] = 'modules/'.$module.'/tpls/QuickCreate.tpl'; + } + + $view->ev = & $this->ev; + $view->ss = & $this->ev->ss; + $class = $GLOBALS['beanList'][$module]; + if(!empty($GLOBALS['beanFiles'][$class])){ + require_once($GLOBALS['beanFiles'][$class]); + $bean = new $class(); + $view->bean = $bean; + } + $this->ev->formName = 'form_Subpanel'.$this->ev->view .'_'.$module; + $view->showTitle = false; // Do not show title since this is for subpanel + $view->display(); + } + } + } //if + + if($this->defaultProcess && !$proccessOverride) { + $this->process($module); + } + } + + function process($module){ + $form_name = 'form_Subpanel'.$this->ev->view .'_'.$module; + $this->ev->formName = $form_name; + $this->ev->process(true, $form_name); + echo $this->ev->display(false, true); + } +} +?> \ No newline at end of file diff --git a/include/EditView/SugarVCR.php b/include/EditView/SugarVCR.php index 3fefccd2..f48b31f0 100644 --- a/include/EditView/SugarVCR.php +++ b/include/EditView/SugarVCR.php @@ -104,7 +104,7 @@ if(!empty($menu['NEXT'])){ $return_action = 'EditView'; $return_id = $menu['NEXT']; - $list_URL = 'index.php?action=EditView&module='.$module.'&record='.$return_id.'&offset='.($offset+1); + $list_URL = ajaxLink('index.php?action=EditView&module='.$module.'&record='.$return_id.'&offset='.($offset+1)); $list_link = ""; }else $list_link = ""; @@ -115,7 +115,7 @@ $next_link = ""; if(!empty($menu['PREV'])) { //$previous_link = "".SugarThemeRegistry::current()->getImage("previous","alt='".$GLOBALS['app_strings']['LNK_LIST_PREVIOUS']."' border='0' align='absmiddle'").' '.$GLOBALS['app_strings']['LNK_LIST_PREVIOUS'].""; - $href = "index.php?module=$module&action=$action&offset=".($offset-1)."&record=".$menu['PREV']; + $href = ajaxLink("index.php?module=$module&action=$action&offset=".($offset-1)."&record=".$menu['PREV']); $previous_link = ""; } else @@ -123,7 +123,7 @@ if(!empty($menu['NEXT'])) { //$next_link = "".$GLOBALS['app_strings']['LNK_LIST_NEXT'].' '.SugarThemeRegistry::current()->getImage("next","alt='".$GLOBALS['app_strings']['LNK_LIST_NEXT']."' border='0' align='absmiddle'").""; - $href = "index.php?module=$module&action=$action&offset=".($offset+1)."&record=".$menu['NEXT']; + $href = ajaxLink("index.php?module=$module&action=$action&offset=".($offset+1)."&record=".$menu['NEXT']); $next_link = ""; } else diff --git a/include/EditView/header.tpl b/include/EditView/header.tpl index ac1c3918..fef0db1c 100644 --- a/include/EditView/header.tpl +++ b/include/EditView/header.tpl @@ -37,7 +37,7 @@ *}
    -
    +
    {if $prerow} - + {capture assign=linkModule}{if $params.dynamic_module}{$rowData[$params.dynamic_module]}{else}{$pageData.bean.moduleDir}{/if}{/capture} + {capture assign=action}{if $act}{$act}{else}EditView{/if}{/capture} + {/if} {counter start=0 name="colCounter" print=false assign="colCounter"} {foreach from=$displayColumns key=col item=params} @@ -131,8 +140,12 @@ {if !empty($quickViewLinks)} - + {/if} {counter start=0 name="colCounter" print=false assign="colCounter"} {foreach from=$displayColumns key=colHeader item=params} - {/if} - + {if $rowCounter % 2 == 1} {/if} @@ -83,12 +83,12 @@ {/if}
    diff --git a/include/ListView/ListView.php b/include/ListView/ListView.php index ebea29b4..9781019a 100644 --- a/include/ListView/ListView.php +++ b/include/ListView/ListView.php @@ -1126,9 +1126,9 @@ function getUserVariable($localVarName, $varName) { echo ""; if($this->show_select_menu) { - $select_link = "".$this->local_app_strings['LBL_LINK_SELECT']." ".""; + $select_link = "".$this->local_app_strings['LBL_LINK_SELECT']." ".""; } else { $select_link = " "; } @@ -1172,7 +1172,7 @@ function getUserVariable($localVarName, $varName) { if($user_merge == 'on' && isset($admin->settings['system_mailmerge_on']) && $admin->settings['system_mailmerge_on']) { echo ""; - $merge_link = " | ".$this->local_app_strings['LBL_MAILMERGE'].""; + $merge_link = " | ".$this->local_app_strings['LBL_MAILMERGE'].""; } else { $merge_link = " "; } @@ -1619,24 +1619,34 @@ function getUserVariable($localVarName, $varName) { } function getArrowUpDownStart($upDown) { - $ext = ( SugarThemeRegistry::current()->pngSupport ? "png" : "gif" ); - if (!isset($upDown) || empty($upDown)) { $upDown = ""; } - return " getImageURL("arrow.gif")); + function getArrowEnd() { + $imgFileParts = pathinfo(SugarThemeRegistry::current()->getImageURL("arrow.gif")); list($width,$height) = ListView::getArrowImageSize(); - return '.'.$imgFileParts['extension']."' width='$width' height='$height' align='absmiddle' alt=".translate('LBL_SORT').">"; + + return '.'.$imgFileParts['extension']."' width='$width' height='$height' align='absmiddle' alt=".translate('LBL_SORT').">"; } + + function getArrowUpDownEnd($upDown) { + if (!isset($upDown) || empty($upDown)) { + $upDown = ""; + } + $imgFileParts = pathinfo(SugarThemeRegistry::current()->getImageURL("arrow{$upDown}.gif")); - function getArrowImageSize() { - // just get the non-sort image's size.. the up and down have be the same. - $image = SugarThemeRegistry::current()->getImageURL("arrow.gif",false); + list($width,$height) = ListView::getArrowUpDownImageSize($upDown); + return " width='$width' height='$height' align='absmiddle' alt=".translate('LBL_SORT').">"; + } + + function getArrowImageSize() { + // just get the non-sort image's size.. the up and down have be the same. + $image = SugarThemeRegistry::current()->getImageURL("arrow.gif",false); $cache_key = 'arrow_size.'.$image; @@ -1650,15 +1660,32 @@ function getUserVariable($localVarName, $varName) { sugar_cache_put($cache_key, $result); return $result; } + + function getArrowUpDownImageSize($upDown) { + // just get the non-sort image's size.. the up and down have be the same. + $image = SugarThemeRegistry::current()->getImageURL("arrow{$upDown}.gif",false); - function getOrderByInfo($html_varName) - { - $orderBy = $this->getSessionVariable($html_varName, "OBL"); - $desc = $this->getSessionVariable($html_varName, $orderBy.'S'); - $orderBy = str_replace('.', '_', $orderBy); - return array($orderBy,$desc); + $cache_key = 'arrowupdown_size.'.$image; + + // Check the cache + $result = sugar_cache_retrieve($cache_key); + if(!empty($result)) + return $result; + + // No cache hit. Calculate the value and return. + $result = getimagesize($image); + sugar_cache_put($cache_key, $result); + return $result; } + function getOrderByInfo($html_varName) + { + $orderBy = $this->getSessionVariable($html_varName, "OBL"); + $desc = $this->getSessionVariable($html_varName, $orderBy.'S'); + $orderBy = str_replace('.', '_', $orderBy); + return array($orderBy,$desc); + } + function processSortArrows($html_varName) { @@ -1666,23 +1693,25 @@ function getUserVariable($localVarName, $varName) { list($orderBy,$desc) = $this->getOrderByInfo($html_varName); - $imgArrow = "_down"; - if($desc) { - $imgArrow = "_up"; - } - - if($orderBy == 'amount*1') - { - $this->xTemplateAssign('amount_arrow', $imgArrow); - } - else if($orderBy == 'amount_usdollar*1') - { - $this->xTemplateAssign('amount_usdollar_arrow', $imgArrow); - } - else - { - $this->xTemplateAssign($orderBy.'_arrow', $imgArrow); - } + $imgArrow = "_down"; + if($desc) { + $imgArrow = "_up"; + } + /** + * @deprecated only used by legacy opportunites listview, nothing current. Leaving for BC + */ + if($orderBy == 'amount*1') + { + $this->xTemplateAssign('amount_arrow', $imgArrow); + } + else if($orderBy == 'amount_usdollar*1') + { + $this->xTemplateAssign('amount_usdollar_arrow', $imgArrow); + } + else + { + $this->xTemplateAssign($orderBy.'_arrow', $imgArrow); + } $this->xTemplateAssign('arrow_end', $this->getArrowEnd()); } diff --git a/include/ListView/ListViewDCMenu.tpl b/include/ListView/ListViewDCMenu.tpl index 2495cdc4..37104646 100644 --- a/include/ListView/ListViewDCMenu.tpl +++ b/include/ListView/ListViewDCMenu.tpl @@ -93,8 +93,8 @@ YAHOO.util.Connect.asyncRequest('POST', 'index.php', callback, "module=Meetings& {/if} {counter start=0 name="colCounter" print=false assign="colCounter"} {foreach from=$displayColumns key=colHeader item=params} - -
    +
    +
    {if false} {if $params.url_sort} diff --git a/include/ListView/ListViewDisplay.php b/include/ListView/ListViewDisplay.php index 2e6c0727..bd559c49 100644 --- a/include/ListView/ListViewDisplay.php +++ b/include/ListView/ListViewDisplay.php @@ -282,16 +282,16 @@ class ListViewDisplay { } $script = ""; - $script .= "".""; + $script .= "".""; return $script; } @@ -320,7 +320,7 @@ class ListViewDisplay { // mass update $mass = new MassUpdate(); $mass->setSugarBean($this->seed); - if ( ACLController::checkAccess($this->seed->module_dir,'edit',true) && $this->showMassupdateFields && $mass->doMassUpdateFieldsExistForFocus() ) + if ( ( ACLController::checkAccess($this->seed->module_dir,'edit',true) && ACLController::checkAccess($this->seed->module_dir,'massupdate',true) ) && $this->showMassupdateFields && $mass->doMassUpdateFieldsExistForFocus() ) $menuItems .= $this->buildMassUpdateLink(); // merge if ( $this->mailMerge ) @@ -345,7 +345,6 @@ class ListViewDisplay { return << - - + {$app_strings['LBL_LINK_ACTIONS']}  EOHTML; @@ -370,7 +368,7 @@ EOHTML; protected function buildExportLink() { global $app_strings; - return "seed->module_dir}', 'index.php?entryPoint=export','{$app_strings['LBL_LISTVIEW_NO_SELECTED']}')\">{$app_strings['LBL_EXPORT']}"; + return "seed->module_dir}', 'index.php?entryPoint=export','{$app_strings['LBL_LISTVIEW_NO_SELECTED']}')\">{$app_strings['LBL_EXPORT']}"; } /** @@ -381,8 +379,8 @@ EOHTML; protected function buildMassUpdateLink() { global $app_strings; - - return "{$app_strings['LBL_MASS_UPDATE']}"; + $onClick = "document.getElementById('massupdate_form').style.display = ''; var yLoc = YAHOO.util.Dom.getY('massupdate_form'); scroll(0,yLoc);"; + return "{$app_strings['LBL_MASS_UPDATE']}"; } /** @@ -422,11 +420,11 @@ EOHTML; $client = $defaultPref; if($client == 'sugar') - $script = "seed->module_dir.'\', \''.$totalCount.'\', \''.$app_strings['LBL_LISTVIEW_LESS_THAN_TEN_SELECT'].'\')">' . $app_strings['LBL_EMAIL_COMPOSE'] . ''; else - $script = "" . $app_strings['LBL_EMAIL_COMPOSE'] . ''; @@ -441,7 +439,7 @@ EOHTML; { global $app_strings; - return "{$app_strings['LBL_DELETE_BUTTON_LABEL']}"; + return "{$app_strings['LBL_DELETE_BUTTON_LABEL']}"; } /** * Display the selected object span object @@ -476,7 +474,7 @@ EOHTML; } if (isset($dictionary[$this->seed->object_name]['duplicate_merge']) && $dictionary[$this->seed->object_name]['duplicate_merge']==true ) { - return "seed->module_dir}\",\"$return_string\");} else {alert(\"{$app_strings['LBL_LISTVIEW_TWO_REQUIRED']}\");return false;}'>". $app_strings['LBL_MERGE_DUPLICATES'].''; } @@ -502,7 +500,7 @@ EOHTML; $str = ''; if ($user_merge == 'on' && isset($admin->settings['system_mailmerge_on']) && $admin->settings['system_mailmerge_on'] && !empty($modules_array[$module_dir])) { - $str = "' . $app_strings['LBL_MAILMERGE'].''; } @@ -588,7 +586,7 @@ EOHTML; open_popup('ProspectLists','600','400','',true,false,{ 'call_back_function':'set_return_and_save_targetlist','form_name':'targetlist_form','field_to_name_array':{'id':'prospect_list'} } ); EOF; $js = str_replace(array("\r","\n"),'',$js); - return "{$app_strings['LBL_ADD_TO_PROSPECT_LIST_BUTTON_LABEL']}"; + return "{$app_strings['LBL_ADD_TO_PROSPECT_LIST_BUTTON_LABEL']}"; } /** * Display the bottom of the ListView (ie MassUpdate diff --git a/include/ListView/ListViewFacade.php b/include/ListView/ListViewFacade.php index 6c17aefe..bbd7cbed 100644 --- a/include/ListView/ListViewFacade.php +++ b/include/ListView/ListViewFacade.php @@ -160,14 +160,20 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); } } - function display($title = '', $section = 'main'){ + function display($title = '', $section = 'main', $return = FALSE){ if($this->type == 1){ + ob_start(); $this->lv->setHeaderTitle($title); $this->lv->processListView($this->focus, $section, $this->prefix); + $output = ob_get_contents(); + ob_end_clean(); }else{ - echo get_form_header($title, '', false); - echo $this->lv->display(); + $output = get_form_header($title, '', false) . $this->lv->display(); } + if($return) + return $output; + else + echo $output; } function setTitle($title = ''){ diff --git a/include/ListView/ListViewGeneric.tpl b/include/ListView/ListViewGeneric.tpl index 0d435a83..605930e4 100644 --- a/include/ListView/ListViewGeneric.tpl +++ b/include/ListView/ListViewGeneric.tpl @@ -53,7 +53,7 @@ {include file='include/ListView/ListViewPagination.tpl'}
    +
    {$selectLink} @@ -65,8 +65,8 @@ {/if} {counter start=0 name="colCounter" print=false assign="colCounter"} {foreach from=$displayColumns key=colHeader item=params} -
    -
    +
    +
    {if $params.sortable|default:true} {if $params.url_sort} @@ -123,7 +123,16 @@ {/if} {if !empty($quickViewLinks)} -
    {if $pageData.rowAccess[$id].edit}{/if} + {if $pageData.rowAccess[$id].edit} + + + {/if} + {if $col == 'NAME' || $params.bold}{/if} {if $params.link && !$params.customCode} - <{$pageData.tag.$id[$params.ACLTag]|default:$pageData.tag.$id.MAIN} href="#" onMouseOver="javascript:lvg_nav('{if $params.dynamic_module}{$rowData[$params.dynamic_module]}{else}{$params.module|default:$pageData.bean.moduleDir}{/if}', '{$rowData[$params.id]|default:$rowData.ID}', 'd', {$offset}, this)" onFocus="javascript:lvg_nav('{if $params.dynamic_module}{$rowData[$params.dynamic_module]}{else}{$params.module|default:$pageData.bean.moduleDir}{/if}', '{$rowData[$params.id]|default:$rowData.ID}', 'd', {$offset}, this)"> - {/if} +{capture assign=linkModule}{if $params.dynamic_module}{$rowData[$params.dynamic_module]}{else}{$params.module|default:$pageData.bean.moduleDir}{/if}{/capture} +{capture assign=action}{if $act}{$act}{else}DetailView{/if}{/capture} +{capture assign=record}{$rowData[$params.id]|default:$rowData.ID}{/capture} +{capture assign=url}index.php?module={$linkModule}&offset={$offset}&stamp={$pageData.stamp}&return_module={$linkModule}&action={$action}&record={$record}{/capture} + <{$pageData.tag.$id[$params.ACLTag]|default:$pageData.tag.$id.MAIN} href="{sugar_ajax_url url=$url}"> + {/if} {if $params.customCode} {sugar_evalcolumn_old var=$params.customCode rowData=$rowData} {else} @@ -162,7 +175,28 @@ {if $contextMenus} {/if} diff --git a/include/ListView/ListViewNoMassUpdate.tpl b/include/ListView/ListViewNoMassUpdate.tpl index efec1b61..59227ef1 100644 --- a/include/ListView/ListViewNoMassUpdate.tpl +++ b/include/ListView/ListViewNoMassUpdate.tpl @@ -51,11 +51,11 @@
       +
    {if $params.sortable|default:true} {sugar_translate label=$params.label module=$pageData.bean.moduleDir}   diff --git a/include/ListView/ListViewSmarty.php b/include/ListView/ListViewSmarty.php index 8cb12a6d..4be75bb5 100644 --- a/include/ListView/ListViewSmarty.php +++ b/include/ListView/ListViewSmarty.php @@ -133,12 +133,11 @@ class ListViewSmarty extends ListViewDisplay{ // handle save checks and stuff if($this->multiSelect) { - $this->ss->assign('selectedObjectsSpan', $this->buildSelectedObjectsSpan(true, $this->data['pageData']['offsets']['total'])); + $this->ss->assign('selectedObjectsSpan', $this->buildSelectedObjectsSpan(true, $this->data['pageData']['offsets']['current'])); $this->ss->assign('multiSelectData', $this->getMultiSelectData()); } else { $this->ss->assign('multiSelectData', ''); } - // include button for Adding to Target List if in one of four applicable modules if ( isset ( $_REQUEST['module']) && in_array ( $_REQUEST['module'] , array ( 'Contacts','Prospects','Leads','Accounts' )) && ACLController::checkAccess('ProspectLists','edit',true)) { diff --git a/include/MVC/Controller/SugarController.php b/include/MVC/Controller/SugarController.php index a2a96f45..6c1b7b58 100644 --- a/include/MVC/Controller/SugarController.php +++ b/include/MVC/Controller/SugarController.php @@ -260,6 +260,16 @@ class SugarController{ require('custom/include/MVC/Controller/'. $var . '.php'); } + // entry_point_registry -> EntryPointRegistry + + $varname = str_replace(" ","",ucwords(str_replace("_"," ", $var))); + if(file_exists("custom/application/Ext/$varname/$var.ext.php")){ + require("custom/application/Ext/$varname/$var.ext.php"); + } + if(file_exists("custom/modules/{$this->module}/Ext/$varname/$var.ext.php")){ + require("custom/modules/{$this->module}/Ext/$varname/$var.ext.php"); + } + sugar_cache_put("CONTROLLER_". $var . "_".$this->module, $$var); } $this->$var = $$var; diff --git a/include/MVC/Controller/action_view_map.php b/include/MVC/Controller/action_view_map.php index ef5024f9..3d114a5e 100644 --- a/include/MVC/Controller/action_view_map.php +++ b/include/MVC/Controller/action_view_map.php @@ -50,6 +50,7 @@ $action_view_map['vcard']= 'vcard'; $action_view_map['importvcard']= 'importvcard'; $action_view_map['importvcardsave']= 'importvcardsave'; $action_view_map['modulelistmenu']= 'modulelistmenu'; +$action_view_map['ajaxui']= 'ajaxui'; // SugarPDF $action_view_map['sugarpdf']= 'sugarpdf'; @@ -62,4 +63,7 @@ $action_view_map['inlinefield'] = 'inlinefield'; $action_view_map['inlinefieldsave'] = 'inlinefieldsave'; $action_view_map['pluginlist'] = 'plugins'; $action_view_map['downloadplugin'] = 'downloadplugin'; +$action_view_map['metadata'] = 'metadata'; + +$action_view_map['cubes'] = 'cubes'; ?> diff --git a/include/MVC/SugarApplication.php b/include/MVC/SugarApplication.php index ce9fc43c..ce0e4271 100644 --- a/include/MVC/SugarApplication.php +++ b/include/MVC/SugarApplication.php @@ -607,14 +607,28 @@ class SugarApplication * If the headers have been sent, then we cannot send an additional location header * so we will output a javascript redirect statement. */ - if (headers_sent()) { - echo "\n"; - } else { - //@ob_end_clean(); // clear output buffer - session_write_close(); - header( 'HTTP/1.1 301 Moved Permanently' ); - header( "Location: ". $url ); - } + if (!empty($_REQUEST['ajax_load'])) + { + ob_get_clean(); + $ajax_ret = array( + 'content' => "\n", + 'menu' => array( + 'module' => $_REQUEST['module'], + 'label' => translate($_REQUEST['module']), + ), + ); + $json = getJSONobj(); + echo $json->encode($ajax_ret); + } else { + if (headers_sent()) { + echo "\n"; + } else { + //@ob_end_clean(); // clear output buffer + session_write_close(); + header( 'HTTP/1.1 301 Moved Permanently' ); + header( "Location: ". $url ); + } + } exit(); } diff --git a/include/MVC/View/SugarView.php b/include/MVC/View/SugarView.php index 48febf5a..442dda68 100644 --- a/include/MVC/View/SugarView.php +++ b/include/MVC/View/SugarView.php @@ -115,6 +115,14 @@ class SugarView //trackView has to be here in order to track for breadcrumbs $this->_trackView(); + //For the ajaxUI, we need to use output buffering to return the page in an ajax friendly format + if ($this->_getOption('json_output')){ + ob_start(); + if(!empty($_REQUEST['ajax_load']) && !empty($_REQUEST['loadLanguageJS'])){ + echo $this->_getModLanguageJS(); + } + } + if ($this->_getOption('show_header')) { $this->displayHeader(); } else { @@ -130,13 +138,38 @@ class SugarView } else { $GLOBALS['logic_hook']->call_custom_logic('', 'after_ui_frame'); } - if ($this->_getOption('show_subpanels')) $this->_displaySubPanels(); + + if ($this->_getOption('show_subpanels') && !empty($_REQUEST['record'])) $this->_displaySubPanels(); + if ($this->action === 'Login') { //this is needed for a faster loading login page ie won't render unless the tables are closed ob_flush(); } if ($this->_getOption('show_footer')) $this->displayFooter(); $GLOBALS['logic_hook']->call_custom_logic('', 'after_ui_footer'); + if ($this->_getOption('json_output')) + { + $content = ob_get_clean(); + $module = $this->module; + $ajax_ret = array( + 'content' => mb_detect_encoding($content) == "UTF-8" ? $content : utf8_encode($content), + 'menu' => array( + 'module' => $module, + 'label' => translate($module), + $this->getMenu($module), + ), + 'moduleList' => $this->displayHeader(true), + 'title' => $this->getBrowserTitle(), + 'action' => isset($_REQUEST['action']) ? $_REQUEST['action'] : "", + 'record' => isset($_REQUEST['record']) ? $_REQUEST['record'] : "", + ); + if(empty($this->responseTime)) $this->_calculateFooterMetrics(); + $ajax_ret['responseTime'] = $this->responseTime; + $json = getJSONobj(); + echo $json->encode($ajax_ret); + $GLOBALS['app']->headerDisplayed = false; + ob_flush(); + } //Do not track if there is no module or if module is not a String $this->_track(); } @@ -223,7 +256,7 @@ class SugarView /** * Displays the header on section of the page; basically everything before the content */ - public function displayHeader() + public function displayHeader($retModTabs=false) { global $theme; global $max_tabs; @@ -362,7 +395,7 @@ class SugarView ); if(substr($gcls[$key]["URL"], 0, 11) == "javascript:") { $gcls[$key]["ONCLICK"] = substr($gcls[$key]["URL"],11); - $gcls[$key]["URL"] = "#"; + $gcls[$key]["URL"] = "javascript:void(0)"; } } // and now the sublinks @@ -374,7 +407,7 @@ class SugarView ); if(substr($gcls[$key]['SUBMENU'][$submenulinkkey]["URL"], 0, 11) == "javascript:") { $gcls[$key]['SUBMENU'][$submenulinkkey]["ONCLICK"] = substr($gcls[$key]['SUBMENU'][$submenulinkkey]["URL"],11); - $gcls[$key]['SUBMENU'][$submenulinkkey]["URL"] = "#"; + $gcls[$key]['SUBMENU'][$submenulinkkey]["URL"] = "javascript:void(0)"; } } } @@ -585,18 +618,30 @@ class SugarView $headerTpl = $themeObject->getTemplate('header.tpl'); if ( isset($GLOBALS['sugar_config']['developerMode']) && $GLOBALS['sugar_config']['developerMode'] ) $ss->clear_compiled_tpl($headerTpl); - $ss->display($headerTpl); - $this->includeClassicFile('modules/Administration/DisplayWarnings.php'); + if ($retModTabs) + { + return $ss->fetch($themeObject->getTemplate('_headerModuleList.tpl')); + } else { + $ss->display($headerTpl); + + $this->includeClassicFile('modules/Administration/DisplayWarnings.php'); - $errorMessages = SugarApplication::getErrorMessages(); - if ( !empty($errorMessages)) { - foreach ( $errorMessages as $error_message ) { - echo('

    ' . $error_message.'

    '); + $errorMessages = SugarApplication::getErrorMessages(); + if ( !empty($errorMessages)) { + foreach ( $errorMessages as $error_message ) { + echo('

    ' . $error_message.'

    '); + } } } } + + function getModuleMenuHTML() + { + + } + /** * If the view is classic then this method will include the file and * setup any global variables. @@ -611,7 +656,8 @@ class SugarView global $gridline, $request_string, $modListHeader, $dashletData, $authController, $locale, $currentModule, $import_bean_map, $image_path, $license; global $user_unique_key, $server_unique_key, $barChartColors, $modules_exempt_from_availability_check, $dictionary, $current_language, $beanList, $beanFiles, $sugar_build, $sugar_codename; global $timedate, $login_error; // cn: bug 13855 - timedate not available to classic views. - $currentModule = $this->module; + if (!empty($this->module)) + $currentModule = $this->module; require_once ($file); } @@ -625,7 +671,7 @@ class SugarView if(isset($_REQUEST['action'])){ echo ""; } - echo ''; + echo ''; if (!is_file("include/javascript/sugar_grp1.js")) { $_REQUEST['root_directory'] = "."; require_once("jssource/minify_utils.php"); @@ -705,7 +751,7 @@ EOHTML; if(isset($_REQUEST['action'])){ echo ""; } - echo ''; + echo ''; if (!is_file("include/javascript/sugar_grp1.js") || !is_file("include/javascript/sugar_grp1_yui.js")) { $_REQUEST['root_directory'] = "."; require_once("jssource/minify_utils.php"); @@ -715,13 +761,16 @@ EOHTML; echo ''; echo ''; - if ( isset($sugar_config['quicksearch_querydelay']) ) { - echo ""; + // output necessary config js in the top of the page + $config_js = $this->getSugarConfigJS(); + if(!empty($config_js)){ + echo "\n"; } + if ( isset($sugar_config['email_sugarclient_listviewmaxselect']) ) { echo ""; } - + $image_server = (defined('TEMPLATE_URL'))?TEMPLATE_URL . '/':''; echo ''; // cn: bug 12274 - create session-stored key to defend against CSRF echo ''; @@ -731,17 +780,23 @@ EOHTML; jsLanguage::createAppStringsCache($GLOBALS['current_language']); } echo ''; - if (!is_file($GLOBALS['sugar_config']['cache_dir'] . 'jsLanguage/' . $this->module . '/' . $GLOBALS['current_language'] . '.js')) { - require_once ('include/language/jsLanguage.php'); - jsLanguage::createModuleStringsCache($this->module, $GLOBALS['current_language']); - } - echo ''; + + echo $this->_getModLanguageJS(); + if(isset( $sugar_config['disc_client']) && $sugar_config['disc_client']) echo ''; } } + protected function _getModLanguageJS(){ + if (!is_file($GLOBALS['sugar_config']['cache_dir'] . 'jsLanguage/' . $this->module . '/' . $GLOBALS['current_language'] . '.js')) { + require_once ('include/language/jsLanguage.php'); + jsLanguage::createModuleStringsCache($this->module, $GLOBALS['current_language']); + } + return ''; + } + /** * Called from process(). This method will display the footer on the page. */ @@ -770,11 +825,9 @@ EOHTML; $bottomLinkList = array(); if (isset($this->action) && $this->action != "EditView") { - $bottomLinkList['print'] = - array($app_strings['LNK_PRINT'] => 'javascript:void window.open(\'index.php?'.$GLOBALS['request_string'].'\',\'printwin\',\'menubar=1,status=0,resizable=1,scrollbars=1,toolbar=0,location=1\')'); - + $bottomLinkList['print'] = array($app_strings['LNK_PRINT'] => getPrintLink()); } - $bottomLinkList['backtotop'] = array($app_strings['LNK_BACKTOTOP'] => '#top'); + $bottomLinkList['backtotop'] = array($app_strings['LNK_BACKTOTOP'] => 'javascript:SUGAR.util.top();'); $bottomLinksStr = ""; foreach($bottomLinkList as $key => $value) { @@ -782,7 +835,7 @@ EOHTML; $href = $link; if(substr($link, 0, 11) == "javascript:") { $onclick = " onclick=\"".substr($link,11)."\""; - $href = "#"; + $href = "javascript:void(0)"; } else { $onclick = ""; } @@ -932,7 +985,7 @@ EOHTML; { $endTime = microtime(true); $deltaTime = $endTime - $GLOBALS['startTime']; - $response_time_string = $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_TIME'] . " " . number_format(round($deltaTime, 2), 2) . " " . $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_TIME_SECONDS']; + $response_time_string = $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_TIME'] . ' ' . number_format(round($deltaTime, 2), 2) . ' ' . $GLOBALS['app_strings']['LBL_SERVER_RESPONSE_TIME_SECONDS']; $return = $response_time_string; $return .= '
    '; if (!empty($GLOBALS['sugar_config']['show_page_resources'])) { @@ -973,6 +1026,10 @@ EOHTML; if ( empty($module) ) $module = $this->module; + //Need to make sure the mod_strings match the requested module or Menus may fail + $curr_mod_strings = $mod_strings; + $mod_strings = return_module_language ( $current_language, $module ) ; + $module_menu = array(); if (file_exists('modules/' . $module . '/Menu.php')) { @@ -999,7 +1056,8 @@ EOHTML; if (file_exists('custom/application/Ext/Menus/menu.ext.php')) { require('custom/application/Ext/Menus/menu.ext.php'); } - + + $mod_strings = $curr_mod_strings; $builtModuleMenu = $module_menu; unset($module_menu); @@ -1062,16 +1120,16 @@ EOHTML; } } $theTitle .= "\n"; - if ($show_help) { $theTitle .= ""; $createImageURL = SugarThemeRegistry::current()->getImageURL('create-record.gif'); + $url = ajaxLink("index.php?module=$module&action=EditView&return_module=$module&return_action=DetailView"); $theTitle .= << + {$GLOBALS[ - + {$GLOBALS['app_strings']['LNK_CREATE']} EOHTML; @@ -1173,17 +1231,17 @@ EOHTML; if (!empty($iconPath) && !$browserTitle) { if (SugarThemeRegistry::current()->directionality == "ltr") { return "" - . "".$this->module."" + . "".$firstParam."" . $this->getBreadCrumbSymbol().$app_strings['LBL_SEARCH']; } else { return $app_strings['LBL_SEARCH'].$this->getBreadCrumbSymbol() . "" - . "".$this->module.""; + . "".$firstParam.""; } } else { return $firstParam; } - } + } else { if (!empty($iconPath) && !$browserTitle) { return "" @@ -1194,12 +1252,12 @@ EOHTML; } } - protected function getModuleTitleIconPath($module) + protected function getModuleTitleIconPath($module) { $iconPath = ""; if(is_file(SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png',false))) { $iconPath = SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png'); - } + } else if (is_file(SugarThemeRegistry::current()->getImageURL('icon_'.ucfirst($module).'_32.png',false))) { $iconPath = SugarThemeRegistry::current()->getImageURL('icon_'.ucfirst($module).'_32.png'); } @@ -1240,4 +1298,30 @@ EOHTML; return "«"; } } + + protected function getSugarConfigJS(){ + global $sugar_config; + + // Set all the config parameters in the JS config as necessary + $config_js = array(); + // AjaxUI stock banned modules + $config_js[] = "SUGAR.config.stockAjaxBannedModules = ".json_encode(ajaxBannedModules()).";"; + if ( isset($sugar_config['quicksearch_querydelay']) ) { + $config_js[] = "SUGAR.config.quicksearch_querydelay = {$GLOBALS['sugar_config']['quicksearch_querydelay']};"; + } + if ( empty($sugar_config['disableAjaxUI']) ) { + $config_js[] = "SUGAR.config.disableAjaxUI = false;"; + } + else{ + $config_js[] = "SUGAR.config.disableAjaxUI = true;"; + } + if ( !empty($sugar_config['addAjaxBannedModules']) ){ + $config_js[] = "SUGAR.config.addAjaxBannedModules = ".json_encode($sugar_config['addAjaxBannedModules']).";"; + } + if ( !empty($sugar_config['overrideAjaxBannedModules']) ){ + $config_js[] = "SUGAR.config.overrideAjaxBannedModules = ".json_encode($sugar_config['overrideAjaxBannedModules']).";"; + } + + return $config_js; + } } diff --git a/include/MVC/View/views/view.ajaxui.php b/include/MVC/View/views/view.ajaxui.php new file mode 100644 index 00000000..a7a020b0 --- /dev/null +++ b/include/MVC/View/views/view.ajaxui.php @@ -0,0 +1,63 @@ +options['show_title'] = true; + $this->options['show_header'] = true; + $this->options['show_footer'] = true; + $this->options['show_javascript'] = true; + $this->options['show_subpanels'] = false; + $this->options['show_search'] = false; + + parent::SugarView(); + } + + public function display() + { + //Prevent double footers + $GLOBALS['app']->headerDisplayed = false; + } +} diff --git a/include/MVC/View/views/view.config.php b/include/MVC/View/views/view.config.php index 88ad3685..d0e896ea 100644 --- a/include/MVC/View/views/view.config.php +++ b/include/MVC/View/views/view.config.php @@ -40,9 +40,8 @@ * To change the template for this generated file go to * Window - Preferences - PHPeclipse - PHP - Code Templates */ - $view_config = array( -'actions' => - array( +$view_config = array( + 'actions' => array( 'ajaxformsave' => array( 'show_all' => false ), @@ -68,9 +67,9 @@ 'show_javascript' => true, ), ), -'req_params' => - array( - 'print' => array('param_value' => true, + 'req_params' => array( + 'print' => array( + 'param_value' => true, 'config' => array( 'show_header' => true, 'show_footer' => false, @@ -80,32 +79,38 @@ 'show_javascript' => true, 'show_search' => false,) ), - 'action' => array('param_value' => array('Delete','Save'), + 'action' => array( + 'param_value' => array('Delete','Save'), 'config' => array( 'show_all' => false ), ), - 'to_pdf' => array('param_value' => true, + 'to_pdf' => array( + 'param_value' => true, 'config' => array( 'show_all' => false ), ), - 'to_csv' => array('param_value' => true, + 'to_csv' => array( + 'param_value' => true, 'config' => array( 'show_all' => false ), ), - 'sugar_body_only' => array('param_value' => true, + 'sugar_body_only' => array( + 'param_value' => true, 'config' => array( 'show_all' => false ), ), - 'view' => array('param_value' => 'documentation', + 'view' => array( + 'param_value' => 'documentation', 'config' => array( 'show_all' => false ), ), - 'show_js' => array('param_value' => true, + 'show_js' => array( + 'param_value' => true, 'config' => array( 'show_header' => false, 'show_footer' => false, @@ -113,8 +118,22 @@ 'show_title' => false, 'show_subpanels' => false, 'show_javascript' => true, - 'show_search' => false,) + 'show_search' => false, + ) + ), + 'ajax_load' => array( + 'param_value' => true, + 'config' => array( + 'show_header' => false, + 'show_footer' => false, + 'view_print' => false, + 'show_title' => true, + 'show_subpanels' => false, + 'show_javascript' => false, + 'show_search' => true, + 'json_output' => true, + ) ), ), - ); +); ?> diff --git a/include/MVC/View/views/view.detail.php b/include/MVC/View/views/view.detail.php index 8cb03a9e..54b08e25 100644 --- a/include/MVC/View/views/view.detail.php +++ b/include/MVC/View/views/view.detail.php @@ -47,12 +47,15 @@ class ViewDetail extends SugarView{ var $dv; function ViewDetail(){ - $this->options['show_subpanels'] = true; parent::SugarView(); } function preDisplay(){ - + //do not override config settings for print + if (!isset($_REQUEST['print']) || !$_REQUEST['print']) { + $this->options['show_subpanels'] = true; + } + $metadataFile = $this->getMetaDataFile(); $this->dv = new DetailView2(); $this->dv->ss =& $this->ss; diff --git a/include/MVC/View/views/view.metadata.php b/include/MVC/View/views/view.metadata.php new file mode 100644 index 00000000..74f87e62 --- /dev/null +++ b/include/MVC/View/views/view.metadata.php @@ -0,0 +1,372 @@ +"; + foreach($values as $value){ + $checked = in_array($value, $selected)? " checked=checked ": " "; + echo "
    $value
    "; + } + echo "
    "; + } + + function displaySelect($name,$values, $selected ='', $attr=''){ + echo ""; + } + + + + function displayTextBoxes($values, $attr=''){ + echo "
    "; + foreach($values as $value){ + $postvalue = !empty($_POST[$value])? $_POST[$value]: ''; + echo "
    $value
    "; + } + echo "
    "; + } + + + + function printValue($value, $depth=0){ + echo "
    ";
    + 		print_r($value);
    + 		echo "
    "; + + } + + function display(){ + $do = !empty($_REQUEST['do'])?$_REQUEST['do']:''; + echo ""; + echo "

    I want to learn about "; + + $this->displaySelect('do', array('Nothing', 'Modules','Fields', 'Field Attributes', 'Relationships'), $do, 'onchange="toggleLearn(this.value)"'); + echo "

    "; + $modules = !empty($_REQUEST['modules'])?$_REQUEST['modules']:array(); + if(empty($modules) && !empty($_REQUEST['module']) && $_REQUEST['module'] != 'Home'){ + $modules = array( $_REQUEST['module']); + } + $this->displayCheckBoxes('modules[]', VardefBrowser::getModules(), $modules, ' id="_modules" '); + $attributes = !empty($_REQUEST['attributes'])?$_REQUEST['attributes']:array(); + $allAttributes = array_keys(VardefBrowser::findFieldAttributes()); + sort($allAttributes); + $this->displayCheckBoxes('attributes[]', $allAttributes, $attributes, ' id="_attributes" '); + $this->displayTextBoxes($allAttributes, ' id="_fields" '); + echo ""; + echo << + function toggleLearn(value){ + document.getElementById('_modules').style.display = 'None'; + document.getElementById('_attributes').style.display = 'None'; + document.getElementById('_fields').style.display = 'None'; + if(value == 'Modules' || value == 'Relationships'){ + document.getElementById('_modules').style.display = ''; + } + if(value == 'Fields'){ + document.getElementById('_modules').style.display = ''; + document.getElementById('_fields').style.display = ''; + } + if(value == 'Field Attributes'){ + document.getElementById('_modules').style.display = ''; + document.getElementById('_attributes').style.display = ''; + } + } + toggleLearn('$do'); + + + +EOQ; + echo "
    "; + switch ($do){ + case 'Modules': + $this->printValue(VardefBrowser::findVardefs( $modules)); + break; + case 'Field Attributes': + $this->printValue(VardefBrowser::findFieldAttributes($attributes, $modules)); + break; + case 'Fields': + $searchFor = array(); + foreach($allAttributes as $at){ + if(!empty($_POST[$at])){ + $searchFor[$at] = $_POST[$at]; + } + } + + $this->printValue(VardefBrowser::findFieldsWithAttributes($searchFor, $modules)); + break; + default: + echo << +

    All you ever wanted to know about Vardefs in 30 minutes

    +

    All you ever wanted to know about Vardef Fields and Relationships in 30 minutes

    +

    All you ever wanted to know about Vardef Fields in 30 minutes

    +

    Something about Vardefs in 30 minutes

    +
    + +
    +

    What you need to know

    +
    +Vardefs are where we define information about the fields for a module. 
    + 					
    +It also specifies 75% of the information on relationships. 
    + 					
    +There are also special attributes that can enable additional functionality for a module. 
    + 					
    +It's broken down into:
    +	fields: The fields of a module (most of these are stored in the database)
    +	
    +	indices: The indicies on the database
    +	
    +	relationships: The relationships for this module
    +	
    +	templates: the functionality/fields this module inherits from SugarObjects(located in include/SugarObjects). 
    +		In a vardef these are specified by the third argument in VardefManager::createVardef
    +		For Example - VardefManager::createVardef('Contacts','Contact', array('default', 'assignable','team_security','person'));
    +		would add the fields for team security to contacts and make it an object that can be assigned to users.
    +		The 'person' value would indicate that that Contacts subclasses Person and gains all the fields/attributes that 'Person' 
    +		would get. Since person extends basic it would also gain all the fields/attributes of basic as well.
    +					  
    +					 
    +		The SugarObjects that a module can extend are 'basic', 'company', 'file', 'issue', 'person'. 
    +		These are the same objects you can build off of in ModuleBuilder. 
    +		Adding a new SugarObject to include/SugarObjects/templates is the way 
    +		to add modules to ModuleBuilder
    +					 
    +		Besides extending base objects, a module can also implement functionality defined in SugarObjects. 
    +		You can currenty implement 'assignable' and 'team_security'. 
    +		
    +		
    +	attributes:
    +		[table] (string) (required) The database table where this module stores it's data - any custom fields will be stored in a new table 
    +			with '_cstm' appended to the table name. The field id_c in the custom table will be the same value as id in the primary table
    +			allowing us to join the two tables together. 
    +		
    +		[comment] (string) (optional) is a description of the module
    +		
    +		[unified_search] (bool)(optional) is global search (the search in the upper right corner on the screen) available for this module
    +		
    +		[unified_search_default_enabled] (bool)(optional) is this module available by default in global search
    +		
    +		[optimistic_locking] (bool) (optional) optimistic locking is the concept that on save if the record modifiy time (date_modified)
    +			 is newer than the the modify time of the record when it was loaded to edit (this time is stored in the session). 
    +		
    +		[favorites] (bool) (optional) should favorites be enabled for this module. Favorites are indicated by the stars next to a record 
    +			on lists and deail views. It makes it easier for users to indicate what is important to them right now. It also allows them to filter
    +			by favorites.  
    +			
    +		[duplicate_merge] (bool) (optional) is systematic merging allowed between records of this module or not. This option is available from 
    +			the menu on list views. A user needs to select 2 records on the list view using the checkboxes, and then they can select merge from the actions
    +			menu.
    +			
    +		[audited] (bool) (optional) auditing allows for the tracking of any changes to specified fields. In order to enable auditing you need to enable
    +			it at both the module level and the field level. It will create an audit table for the module with the '_audit' appended to the table name.
    +			
    +		[custom_fields] (bool) (automatic)  if the module has custom fields this will be set to true
    +		
    +			
    +		
    +		
    +		
    +					 
    +					 
    +
    +					  
    +					
    +					
    +					
    +
    + +
    + +
    + +EOQ; + + + } + echo "
    Help Text
    "; + + + //$this->printValue(VardefBrowser::findFieldsWithAttributes(array('type'=>'id'), $modules)); + + + + + + } + +} + +class VardefBrowser{ + + function __construct(){ + + } + + static function getModules(){ + $modules = array(); + foreach($GLOBALS['beanList'] as $module=>$object){ + $object = BeanFactory::getObjectName($module); + VardefManager::loadVardef($module, $object); + if(empty($GLOBALS['dictionary'][$object]['fields'] ))continue; + $modules[] = $module; + } + sort($modules); + return $modules; + + + } + + static function findFieldsWithAttributes($attributes, $modules=null){ + $fields = array(); + if(empty($modules))$modules = VardefBrowser::getModules(); + foreach($modules as $module){ + if(!empty($GLOBALS['beanList'][$module])){ + $object = $GLOBALS['beanList'][$module]; + if($object == 'aCase')$object = 'Case'; + VardefManager::loadVardef($module, $object); + if(empty($GLOBALS['dictionary'][$object]['fields'] ))continue; + foreach($GLOBALS['dictionary'][$object]['fields'] as $name=>$def){ + $match = true; + foreach($attributes as $k=>$v){ + $alt = false; + if($k == 'type'){ + $alt = 'dbType'; + } + if($v == 'true' && !empty($def[$k])){ + continue; + } + if((empty($def[$k]) || $def[$k] != $v) && (empty($alt) || empty($def[$alt]) || $def[$alt] != $v )){ + $match = false; + } + } + if($match){ + $fields[$module][$object][$name] = $def; + } + + } + + } + } + return $fields; + } + + static function findVardefs($modules=null){ + $defs = array(); + if(empty($modules))$modules = VardefBrowser::getModules(); + foreach($modules as $module){ + if(!empty($GLOBALS['beanList'][$module])){ + $object = $GLOBALS['beanList'][$module]; + if($object == 'aCase')$object = 'Case'; + VardefManager::loadVardef($module, $object); + if(empty($GLOBALS['dictionary'][$object]['fields'] ))continue; + $defs[$module][$object] = $GLOBALS['dictionary'][$object]; + } + } + return $defs; + } + + + static function findFieldAttributes($attributes=array(), $modules=null, $byModule=false, $byType=false){ + $fields = array(); + if(empty($modules))$modules = VardefBrowser::getModules(); + foreach($modules as $module){ + if(!empty($GLOBALS['beanList'][$module])){ + $object = $GLOBALS['beanList'][$module]; + if($object == 'aCase')$object = 'Case'; + VardefManager::loadVardef($module, $object); + if(empty($GLOBALS['dictionary'][$object]['fields'] ))continue; + foreach($GLOBALS['dictionary'][$object]['fields'] as $name=>$def){ + $fieldAttributes = (!empty($attributes))? $attributes:array_keys($def); + foreach($fieldAttributes as $k){ + if(isset($def[$k])){ + $v = var_export($def[$k], true); + $key = is_array($def[$k])?null:$def[$k]; + if($k == 'type'){ + if(isset($def['dbType'])){ + $v = var_export($def['dbType'], true); + } + } + if($byModule){ + $fields[$module][$object][$def['type']][$k][$key] = $v; + }else{ + if($byType){ + $fields[$def['type']][$k][$key] = $v; + }else{ + if(!is_array($def[$k])){ + if(isset($fields[$k][$key])){ + $fields[$k][$key]['refs']++; + }else{ + $fields[$k][$key] = array('attribute'=>$v, 'refs'=>1); + } + }else{ + $fields[$k]['_array'][] = $def[$k]; + + } + } + } + + + } + + } + + + + } + + } + } + return $fields; + } + + + +} diff --git a/include/MVC/View/views/view.quickcreate.php b/include/MVC/View/views/view.quickcreate.php index 5d7a8ae9..54ec0f3d 100644 --- a/include/MVC/View/views/view.quickcreate.php +++ b/include/MVC/View/views/view.quickcreate.php @@ -132,6 +132,7 @@ class ViewQuickcreate extends ViewAjax if(file_exists('modules/'.$module.'/views/view.edit.php')) { include('modules/'.$module.'/views/view.edit.php'); + $c = $module . 'ViewEdit'; if(class_exists($c)) { diff --git a/include/MVC/View/views/view.quickedit.php b/include/MVC/View/views/view.quickedit.php new file mode 100644 index 00000000..e33ac80f --- /dev/null +++ b/include/MVC/View/views/view.quickedit.php @@ -0,0 +1,208 @@ +bean = loadBean($_REQUEST['source_module']); + if ( $this->bean instanceOf SugarBean + && !in_array($this->bean->object_name,array('EmailMan')) ) { + $this->bean->retrieve($_REQUEST['record']); + if(!empty($this->bean->id))$_REQUEST['parent_id'] = $this->bean->id; + if(!empty($this->bean->module_dir))$_REQUEST['parent_type'] = $this->bean->module_dir; + if(!empty($this->bean->name))$_REQUEST['parent_name'] = $this->bean->name; + if(!empty($this->bean->id))$_REQUEST['return_id'] = $this->bean->id; + if(!empty($this->bean->module_dir))$_REQUEST['return_module'] = $this->bean->module_dir; + + //Now preload any related fields + if(isset($_REQUEST['module'])) { + $target_bean = loadBean($_REQUEST['module']); + foreach($target_bean->field_defs as $fields) { + if($fields['type'] == 'relate' && isset($fields['module']) && $fields['module'] == $_REQUEST['source_module'] && isset($fields['rname'])) { + $rel_name = $fields['rname']; + if(isset($this->bean->$rel_name)) { + $_REQUEST[$fields['name']] = $this->bean->$rel_name; + } + if(!empty($_REQUEST['record']) && !empty($fields['id_name'])) { + $_REQUEST[$fields['id_name']] = $_REQUEST['record']; + } + } + } + } + } + $this->_isDCForm = true; + } + } + + /** + * @see SugarView::display() + */ + public function display() + { + + $view = (!empty($_REQUEST['target_view']))?$_REQUEST['target_view']: 'QuickCreate'; + $module = $_REQUEST['module']; + + // locate the best viewdefs to use: 1. custom/module/quickcreatedefs.php 2. module/quickcreatedefs.php 3. custom/module/editviewdefs.php 4. module/editviewdefs.php + $base = 'modules/' . $module . '/metadata/'; + $source = 'custom/' . $base . strtolower($view) . 'defs.php'; + if (!file_exists( $source)) + { + $source = $base . strtolower($view) . 'defs.php'; + if (!file_exists($source)) + { + //if our view does not exist default to EditView + $view = 'EditView'; + $source = 'custom/' . $base . 'editviewdefs.php'; + if (!file_exists($source)) + { + $source = $base . 'editviewdefs.php'; + } + } + } + + //in some cases, the source file will not exist. In these cases lets just navigate to the full form directlhy + if(!file_exists($source)){ + global $app_strings; + + //write out jscript that will get evaluated and redirect the browser window. + $no_defs_js = ''; + + //reports is a special case as it does not have an edit view so navigate to wizard view + if(strtolower($module) == 'reports'){ + $no_defs_js = ''; + } + //if this is not reports and there are no edit view files then go to detail view + elseif(!file_exists('custom/' . $base . 'editviewdefs.php') && !file_exists($base . 'editviewdefs.php') + && !file_exists('custom/modules/' . $module .'/EditView.php') && !file_exists('modules/' . $module .'/EditView.php') + ){ + $no_defs_js = ''; + } + + echo json_encode(array('scriptOnly'=> $no_defs_js)); + + return; + + } + + $this->ev = new EditView(); + $this->ev->view = $view; + $this->ev->ss = new Sugar_Smarty(); + + $this->ev->ss->assign('isDCForm', $this->_isDCForm); + //$_REQUEST['return_action'] = 'SubPanelViewer'; + $this->ev->setup($module, $this->bean, $source); + $this->ev->showSectionPanelsTitles = false; + $this->ev->defs['templateMeta']['form']['headerTpl'] = 'include/EditView/header.tpl'; + $this->ev->defs['templateMeta']['form']['footerTpl'] = 'include/EditView/footer.tpl'; + $this->ev->defs['templateMeta']['form']['buttons'] = array('DCMENUSAVE', 'DCMENUCANCEL', 'DCMENUFULLFORM'); + $this->ev->defs['templateMeta']['form']['button_location'] = 'bottom'; + $this->ev->defs['templateMeta']['form']['hidden'] = ''; + $this->ev->defs['templateMeta']['form']['hidden'] .= ''; + $this->ev->defs['templateMeta']['form']['hideAudit']=true; + + //use module level view if available + $editFileName = 'modules/'.$module.'/views/view.edit.php'; + if(file_exists('custom/modules/'.$module.'/views/view.edit.php')) { + $editFileName = 'custom/modules/'.$module.'/views/view.edit.php'; + } + + $defaultProcess = true; + if(file_exists($editFileName)) { + include($editFileName); + $c = $module . 'ViewEdit'; + + if(class_exists($c)) { + $view = new $c; + if($view->useForSubpanel) { + $defaultProcess = false; + + //Check if we should use the module's QuickCreate.tpl file + if($view->useModuleQuickCreateTemplate && file_exists('modules/'.$module.'/tpls/QuickCreate.tpl')) { + $this->ev->defs['templateMeta']['form']['headerTpl'] = 'modules/'.$module.'/tpls/QuickCreate.tpl'; + } + + $view->ev = & $this->ev; + $view->ss = & $this->ev->ss; + $class = $GLOBALS['beanList'][$module]; + if(!empty($GLOBALS['beanFiles'][$class])){ + require_once($GLOBALS['beanFiles'][$class]); + $bean = new $class(); + $view->bean = $bean; + } + $view->ev->formName = 'form_DC'.$view->ev->view .'_'.$module; + $view->showTitle = false; // Do not show title since this is for subpanel + ob_start(); + $view->display(); + $captured = ob_get_clean(); + echo json_encode(array('title'=> $this->bean->name, 'url'=>'index.php?module=' . $this->bean->module_dir . '&action=DetailView&record=' . $this->bean->id ,'html'=> $captured, 'eval'=>true)); + } + } + } + + //if defaultProcess is still true, then the default edit view was not used. Finish processing. + if($defaultProcess){ + $form_name = 'form_DC'.$this->ev->view .'_'.$module; + $this->ev->formName = $form_name; + $this->ev->process(true, $form_name); + ob_clean(); + echo json_encode(array('title'=> $this->bean->name, 'url'=>'index.php?module=' . $this->bean->module_dir . '&action=DetailView&record=' . $this->bean->id ,'html'=> $this->ev->display(false, true), 'eval'=>true)); + } + } +} \ No newline at end of file diff --git a/include/MassUpdate.php b/include/MassUpdate.php index fce8c5e4..2f3085e9 100644 --- a/include/MassUpdate.php +++ b/include/MassUpdate.php @@ -353,7 +353,7 @@ eoq; global $app_strings; global $current_user; - if($this->sugarbean->bean_implements('ACL') && !ACLController::checkAccess($this->sugarbean->module_dir, 'edit', true)){ + if($this->sugarbean->bean_implements('ACL') && ( !ACLController::checkAccess($this->sugarbean->module_dir, 'edit', true) || !ACLController::checkAccess($this->sugarbean->module_dir, 'massupdate', true) ) ){ return ''; } diff --git a/include/MySugar/DashletsDialog/DashletsDialog.php b/include/MySugar/DashletsDialog/DashletsDialog.php index 990af5c7..4be9bf5e 100644 --- a/include/MySugar/DashletsDialog/DashletsDialog.php +++ b/include/MySugar/DashletsDialog/DashletsDialog.php @@ -164,7 +164,8 @@ class DashletsDialog { $cell = array( 'title' => $title, 'description' => $description, 'onclick' => 'return SUGAR.mySugar.addDashlet(\'' . $className . '\', \'' . $type . '\', \''.(!empty($dashletMeta[$files['class']]['module']) ? $dashletMeta[$files['class']]['module'] : '' ) .'\');', - 'icon' => $icon, ); + 'icon' => $icon, + 'id' => $files['class'] . "_select"); if (!empty($category) && $dashletMeta[$files['class']]['category'] == $categories[$category]){ array_push($dashletsList[$categories[$category]], $cell); diff --git a/include/MySugar/javascript/MySugar.js b/include/MySugar/javascript/MySugar.js index 9fd0675e..2c826a3f 100644 --- a/include/MySugar/javascript/MySugar.js +++ b/include/MySugar/javascript/MySugar.js @@ -32,7 +32,7 @@ * technical reasons, the Appropriate Legal Notices must display the words * "Powered by SugarCRM". ********************************************************************************/ -SUGAR.mySugar=function(){var originalLayout=null;var configureDashletId=null;var currentDashlet=null;var leftColumnInnerHTML=null;var leftColObj=null;var maxCount;var warningLang;var closeDashletsDialogTimer=null;var activeTab=activePage;var current_user=current_user_id;var module=moduleName;var charts=new Object();if(module=='Dashboard'){cookiePageIndex=current_user+"_activeDashboardPage";} +initMySugar=function(){SUGAR.mySugar=function(){var originalLayout=null;var configureDashletId=null;var currentDashlet=null;var leftColumnInnerHTML=null;var leftColObj=null;var maxCount;var warningLang;var closeDashletsDialogTimer=null;var activeTab=activePage;var current_user=current_user_id;var module=moduleName;var charts=new Object();if(module=='Dashboard'){cookiePageIndex=current_user+"_activeDashboardPage";} else{cookiePageIndex=current_user+"_activePage";} var homepage_dd;return{getLayout:function(asString){columns=new Array();for(je=0;je<3;je++){dashlets=document.getElementById('col_'+activeTab+'_'+je);if(dashlets!=null){dashletIds=new Array();for(wp=0;wp';},expandList:function(chartList){document.getElementById(chartList+'List').style.display='';document.getElementById(chartList+'ExpCol').innerHTML='
    ';},collapseReportList:function(reportChartList){document.getElementById(reportChartList+'ReportsChartDashletsList').style.display='none';document.getElementById(reportChartList+'ExpCol').innerHTML='';},expandReportList:function(reportChartList){document.getElementById(reportChartList+'ReportsChartDashletsList').style.display='';document.getElementById(reportChartList+'ExpCol').innerHTML='';},clearSearch:function(){document.getElementById('search_string').value='';var moduleTab=document.getElementById('moduleCategory');var moduleTabAnchor=document.getElementById('moduleCategoryAnchor');var moduleListDiv=document.getElementById('moduleDashlets');document.getElementById('searchResults').innerHTML='';if(moduleTab!=null){SUGAR.mySugar.toggleDashletCategories('module');} -else{document.getElementById('searchResults').style.display='none';document.getElementById('chartDashlets').style.display='';}},doneAddDashlets:function(){SUGAR.mySugar.dashletsDialog.hide();return false;},renderDashletsDialog:function(){SUGAR.mySugar.dashletsDialog=new YAHOO.widget.Dialog("dashletsDialog",{width:"480px",height:"520px",fixedcenter:true,draggable:false,visible:false,modal:true,close:false});var listeners=new YAHOO.util.KeyListener(document,{keys:27},{fn:function(){SUGAR.mySugar.closeDashletsDialog();}});SUGAR.mySugar.dashletsDialog.cfg.queueProperty("keylisteners",listeners);document.getElementById('dashletsDialog').style.display='';SUGAR.mySugar.dashletsDialog.render();document.getElementById('dashletsDialog_c').style.display='none';}};}(); +var cObj=YAHOO.util.Connect.asyncRequest('GET','index.php?to_pdf=true&module='+module+'&action=DynamicAction&DynamicAction=searchDashlets&search='+searchStr+'&category='+searchCategory,{success:success,failure:success});return false;},collapseList:function(chartList){document.getElementById(chartList+'List').style.display='none';document.getElementById(chartList+'ExpCol').innerHTML='';},expandList:function(chartList){document.getElementById(chartList+'List').style.display='';document.getElementById(chartList+'ExpCol').innerHTML='';},collapseReportList:function(reportChartList){document.getElementById(reportChartList+'ReportsChartDashletsList').style.display='none';document.getElementById(reportChartList+'ExpCol').innerHTML='';},expandReportList:function(reportChartList){document.getElementById(reportChartList+'ReportsChartDashletsList').style.display='';document.getElementById(reportChartList+'ExpCol').innerHTML='';},clearSearch:function(){document.getElementById('search_string').value='';var moduleTab=document.getElementById('moduleCategory');var moduleTabAnchor=document.getElementById('moduleCategoryAnchor');var moduleListDiv=document.getElementById('moduleDashlets');document.getElementById('searchResults').innerHTML='';if(moduleTab!=null){SUGAR.mySugar.toggleDashletCategories('module');} +else{document.getElementById('searchResults').style.display='none';document.getElementById('chartDashlets').style.display='';}},doneAddDashlets:function(){SUGAR.mySugar.dashletsDialog.hide();return false;},renderDashletsDialog:function(){SUGAR.mySugar.dashletsDialog=new YAHOO.widget.Dialog("dashletsDialog",{width:"480px",height:"520px",fixedcenter:true,draggable:false,visible:false,modal:true,close:false});var listeners=new YAHOO.util.KeyListener(document,{keys:27},{fn:function(){SUGAR.mySugar.closeDashletsDialog();}});SUGAR.mySugar.dashletsDialog.cfg.queueProperty("keylisteners",listeners);document.getElementById('dashletsDialog').style.display='';SUGAR.mySugar.dashletsDialog.render();document.getElementById('dashletsDialog_c').style.display='none';}};}();}; diff --git a/include/MySugar/tpls/MySugar.tpl b/include/MySugar/tpls/MySugar.tpl index 3e2a6eba..283492bc 100644 --- a/include/MySugar/tpls/MySugar.tpl +++ b/include/MySugar/tpls/MySugar.tpl @@ -49,12 +49,6 @@ z-index:100; } - -li.active a img.deletePageImg { - display: inline !important; - margin-bottom: 2px; -} - div.moduleTitle { height: 10px; } @@ -66,6 +60,13 @@ height: 10px; + + + + +{$chartResources} +{$mySugarChartResources} + - - - - - -{$chartResources} -{$mySugarChartResources}
    @@ -107,14 +152,14 @@ document.body.setAttribute("class", "yui-skin-sam");
    •    
    • - {foreach from=$data.dashlets key=id item=dashlet} + {foreach from=$data.dashlets key=id item=dashlet}
    • {$dashlet.script} - {$dashlet.displayHeader} + {$dashlet.displayHeader} {$dashlet.display} - {$dashlet.displayFooter} -
      + {$dashlet.displayFooter} +
    • {/foreach}
    •    
    • @@ -144,42 +189,4 @@ document.body.setAttribute("class", "yui-skin-sam"); - - -{literal} - -{/literal} - - + \ No newline at end of file diff --git a/include/MySugar/tpls/addDashletsDialog.tpl b/include/MySugar/tpls/addDashletsDialog.tpl index 99e834e4..884f1628 100644 --- a/include/MySugar/tpls/addDashletsDialog.tpl +++ b/include/MySugar/tpls/addDashletsDialog.tpl @@ -71,7 +71,7 @@ {if $rowCounter % 2 == 0}
    {$module.icon} {$module.title}
    {$module.icon} {$module.title}
    {foreach from=$charts item=chart} - + {/foreach}
    {$chart.icon} {$chart.title}
    {$chart.icon} {$chart.title}
    @@ -106,7 +106,7 @@ {if $rowCounter % 2 == 0} {/if} - {$tool.icon} {$tool.title}
    + {$tool.icon} {$tool.title}
    {if $rowCounter % 2 == 1} {/if} diff --git a/include/OutboundEmail/OutboundEmail.php b/include/OutboundEmail/OutboundEmail.php index 1c1e3ba2..0bcc01f4 100644 --- a/include/OutboundEmail/OutboundEmail.php +++ b/include/OutboundEmail/OutboundEmail.php @@ -619,6 +619,9 @@ class OutboundEmail { if(!empty($oe) && !empty($oe->id)) { return $oe; } + else { + return $this->getSystemMailerSettings(); + } } $res = $this->db->query("SELECT id FROM outbound_email WHERE user_id = '{$user->id}' AND name='".$this->db->quote($name)."'"); $a = $this->db->fetchByAssoc($res); diff --git a/include/Popups/PopupSmarty.php b/include/Popups/PopupSmarty.php index 971406c0..a399c52a 100644 --- a/include/Popups/PopupSmarty.php +++ b/include/Popups/PopupSmarty.php @@ -79,6 +79,24 @@ class PopupSmarty extends ListViewSmarty{ } + + /** + * Assign several arrow image attributes to TemplateHandler smarty. Such as width, height, etc. + * + * @return void + */ + function processArrowVars() + { + $pathParts = pathinfo(SugarThemeRegistry::current()->getImageURL('arrow.gif',false)); + + list($width,$height) = getimagesize($pathParts['dirname'].'/'.$pathParts['basename']); + + $this->th->ss->assign('arrowExt', $pathParts['extension']); + $this->th->ss->assign('arrowWidth', $width); + $this->th->ss->assign('arrowHeight', $height); + $this->th->ss->assign('arrowAlt', translate('LBL_SORT')); + } + /** * Processes the request. Calls ListViewData process. Also assigns all lang strings, export links, * This is called from ListViewDisplay @@ -167,6 +185,9 @@ class PopupSmarty extends ListViewSmarty{ //rrs $this->_build_field_defs(); + + // arrow image attributes + $this->processArrowVars(); } /* diff --git a/include/Popups/tpls/PopupGeneric.tpl b/include/Popups/tpls/PopupGeneric.tpl index 7d4ad323..6b92f783 100644 --- a/include/Popups/tpls/PopupGeneric.tpl +++ b/include/Popups/tpls/PopupGeneric.tpl @@ -114,9 +114,9 @@ {counter start=0 name="colCounter" print=false assign="colCounter"} {foreach from=$displayColumns key=colHeader item=params} -
    - {if $params.sortable|default:true} - {sugar_translate label=$params.label module=$pageData.bean.moduleDir}   +
    + {if $params.sortable|default:true} + {sugar_translate label=$params.label module=$pageData.bean.moduleDir}   {if $params.orderBy|default:$colHeader|lower == $pageData.ordering.orderBy} {if $pageData.ordering.sortOrder == 'ASC'} {capture assign="imageName"}arrow_down.{$arrowExt}{/capture} @@ -161,7 +161,7 @@ {if $params.link && !$params.customCode} - <{$pageData.tag.$id[$params.ACLTag]|default:$pageData.tag.$id.MAIN} href='#' onclick="send_back('{if $params.dynamic_module}{$rowData[$params.dynamic_module]}{else}{$params.module|default:$pageData.bean.moduleDir}{/if}','{$rowData[$params.id]|default:$rowData.ID}');">{$rowData.$col} + <{$pageData.tag.$id[$params.ACLTag]|default:$pageData.tag.$id.MAIN} href='javascript:void(0)' onclick="send_back('{if $params.dynamic_module}{$rowData[$params.dynamic_module]}{else}{$params.module|default:$pageData.bean.moduleDir}{/if}','{$rowData[$params.id]|default:$rowData.ID}');">{$rowData.$col} {elseif $params.customCode} {sugar_evalcolumn_old var=$params.customCode rowData=$rowData} diff --git a/include/SearchForm/SearchForm.php b/include/SearchForm/SearchForm.php index 9db4a118..1d62eaa5 100644 --- a/include/SearchForm/SearchForm.php +++ b/include/SearchForm/SearchForm.php @@ -131,7 +131,7 @@ class SearchForm { function populateFromArray(&$array, $switchVar = null, $addAllBeanFields = true) { //CL Bug:33176 - if(empty($array['searchFormTab']) && empty($switchvar)) { + if(empty($array['searchFormTab']) && empty($switchVar)) { $array['searchFormTab'] = 'advanced_search'; } @@ -260,7 +260,7 @@ class SearchForm { if(isset($parms['value']) && $parms['value'] != "") { $operator = 'like'; if(!empty($parms['operator'])) { - $operator = $parms['operator']; + $operator = strtolower($parms['operator']); } if(is_array($parms['value'])) { @@ -362,7 +362,7 @@ class SearchForm { if(!empty($where)) { $where .= " OR "; } - switch(strtolower($operator)) { + switch($operator) { case 'subquery': $in = 'IN'; if ( isset($parms['subquery_in_clause']) ) { diff --git a/include/SearchForm/SearchForm2.php b/include/SearchForm/SearchForm2.php index 20d748e3..c5478d4e 100644 --- a/include/SearchForm/SearchForm2.php +++ b/include/SearchForm/SearchForm2.php @@ -1058,7 +1058,12 @@ require_once('include/EditView/EditView2.php'); break; case 'between': $field_value = explode('<>', $field_value); - $where .= $db_field . " >= '".$field_value[0] . "' AND " .$db_field . " <= '".$field_value[1]."'"; + if (isset($field_type) && $field_type == 'int') { + // mssql does not like to compare an int column with quoted decimal like '0.1' + $where .= $db_field . " >= ".$field_value[0] . " AND " .$db_field . " <= ".$field_value[1]; + } else { + $where .= $db_field . " >= '".$field_value[0] . "' AND " .$db_field . " <= '".$field_value[1]."'"; + } break; case 'date_not_equal': $field_value = explode('<>', $field_value); @@ -1122,4 +1127,4 @@ require_once('include/EditView/EditView2.php'); return $result; } } -?> + diff --git a/include/SearchForm/tpls/SearchFormGeneric.tpl b/include/SearchForm/tpls/SearchFormGeneric.tpl index 41acdfad..913b3ae9 100644 --- a/include/SearchForm/tpls/SearchFormGeneric.tpl +++ b/include/SearchForm/tpls/SearchFormGeneric.tpl @@ -77,10 +77,10 @@ {else} {/if} -   + {{sugar_button module="$module" id="search" view="searchView"}} {if $HAS_ADVANCED_SEARCH} -   {$APP.LNK_ADVANCED_SEARCH} +   {$APP.LNK_ADVANCED_SEARCH} {/if} diff --git a/include/SearchForm/tpls/SearchFormGenericAdvanced.tpl b/include/SearchForm/tpls/SearchFormGenericAdvanced.tpl index 2e88eeff..94b6be04 100644 --- a/include/SearchForm/tpls/SearchFormGenericAdvanced.tpl +++ b/include/SearchForm/tpls/SearchFormGenericAdvanced.tpl @@ -103,4 +103,4 @@ loadSSL_Scripts(); } {/literal} - \ No newline at end of file + diff --git a/include/SearchForm/tpls/header.tpl b/include/SearchForm/tpls/header.tpl index 744b6603..51de37f6 100644 --- a/include/SearchForm/tpls/header.tpl +++ b/include/SearchForm/tpls/header.tpl @@ -43,7 +43,7 @@ {/literal} {{/if}} -
    + @@ -51,4 +51,4 @@ {foreach name=tabIteration from=$TAB_ARRAY key=tabkey item=tabData} {/foreach} -
    {$saved_views_txt}
    +
    {$saved_views_txt}
    diff --git a/include/Smarty/plugins/function.overlib_includes.php b/include/Smarty/plugins/function.overlib_includes.php index dcfadf3c..a2ea8b60 100644 --- a/include/Smarty/plugins/function.overlib_includes.php +++ b/include/Smarty/plugins/function.overlib_includes.php @@ -51,8 +51,8 @@ function smarty_function_overlib_includes($params, &$smarty) $path = getJSPath('include/javascript/sugar_grp_overlib.js'); return << - + EOHTML; -} \ No newline at end of file +} diff --git a/include/Smarty/plugins/function.sugar_ajax_url.php b/include/Smarty/plugins/function.sugar_ajax_url.php new file mode 100644 index 00000000..17189f5a --- /dev/null +++ b/include/Smarty/plugins/function.sugar_ajax_url.php @@ -0,0 +1,50 @@ +trigger_error("ajax_url: missing required param (module)"); + return ""; + } + return ajaxLink($params['url']); +} + +?> diff --git a/include/Smarty/plugins/function.sugar_button.php b/include/Smarty/plugins/function.sugar_button.php index c1973313..82835632 100644 --- a/include/Smarty/plugins/function.sugar_button.php +++ b/include/Smarty/plugins/function.sugar_button.php @@ -293,15 +293,19 @@ function smarty_function_sugar_button($params, &$smarty) $module = $params['module']; $view = $params['view']; switch(strtoupper($type)) { + case "SEARCH": + return ' '; + break; + case "CANCEL": $cancelButton = '{if !empty($smarty.request.return_action) && ($smarty.request.return_action == "DetailView" && !empty($smarty.request.return_id))}'; - $cancelButton .= ' '; + $cancelButton .= ' '; $cancelButton .= '{elseif !empty($smarty.request.return_action) && ($smarty.request.return_action == "DetailView" && !empty($fields.id.value))}'; - $cancelButton .= ' '; + $cancelButton .= ' '; $cancelButton .= '{elseif empty($smarty.request.return_action) || empty($smarty.request.return_id) && !empty($fields.id.value)}'; - $cancelButton .= ' '; + $cancelButton .= ' '; $cancelButton .= '{else}'; - $cancelButton .= ' '; + $cancelButton .= ' '; $cancelButton .= '{/if}'; return $cancelButton; break; @@ -311,25 +315,25 @@ function smarty_function_sugar_button($params, &$smarty) break; case "DUPLICATE": - return '{if $bean->aclAccess("edit")}{/if} '; + return '{if $bean->aclAccess("edit")}{/if} '; break; case "EDIT"; - return '{if $bean->aclAccess("edit")}{/if} '; + return '{if $bean->aclAccess("edit")}{/if} '; break; case "FIND_DUPLICATES": - return '{if $bean->aclAccess("edit") && $bean->aclAccess("delete")}{/if} '; + return '{if $bean->aclAccess("edit") && $bean->aclAccess("delete")}{/if} '; break; case "SAVE": $view = ($_REQUEST['action'] == 'EditView') ? 'EditView' : (($view == 'EditView') ? 'EditView' : $view); - return '{if $bean->aclAccess("save")}{/if} '; + return '{if $bean->aclAccess("save")}{/if} '; break; case "SUBPANELSAVE": - $view = $view == 'QuickCreate' ? "form_SubpanelQuickCreate_{$module}" : $view; - return '{if $bean->aclAccess("save")}{/if} '; + if($view == 'QuickCreate' || (isset($_REQUEST['target_action']) && strtolower($_REQUEST['target_action'])) == 'quickcreate') $view = "form_SubpanelQuickCreate_{$module}"; + return '{if $bean->aclAccess("save")}{/if} '; case "SUBPANELCANCEL": return ' '; case "SUBPANELFULLFORM": @@ -340,10 +344,14 @@ function smarty_function_sugar_button($params, &$smarty) return ' '; case "DCMENUSAVE": - $view = $view == 'QuickCreate' ? "form_DCQuickCreate_{$module}" : $view; + if ($view == 'QuickCreate') { + $view = "form_DCQuickCreate_{$module}"; + } else if ($view == 'EditView') { + $view = "form_DCEditView_{$module}"; + } return '{if $bean->aclAccess("save")}{/if} '; case "DCMENUFULLFORM": - $html = ' '; + $html = ' '; $html .= ''; return $html; case "POPUPSAVE": @@ -369,7 +377,7 @@ function smarty_function_sugar_button($params, &$smarty) require_once('include/SugarFields/Parsers/MetaParser.php'); $encoded_popup_request_data = MetaParser::parseDelimiters($json->encode($popup_request_data)); - $audit_link = ''; + $audit_link = ''; $view = '{if $bean->aclAccess("detail")}{if !empty($fields.id.value) && $isAuditEnabled}'.$audit_link.'{/if}{/if}'; return $view; diff --git a/include/Smarty/plugins/function.sugar_field.php b/include/Smarty/plugins/function.sugar_field.php index 0f2cbf41..904898e8 100644 --- a/include/Smarty/plugins/function.sugar_field.php +++ b/include/Smarty/plugins/function.sugar_field.php @@ -85,7 +85,11 @@ function smarty_function_sugar_field($params, &$smarty) $params['vardef']['name'] = $params['field']; } - $_contents = $sfh->displaySmarty($params['parentFieldArray'], $params['vardef'], $params['displayType'], $displayParams, $params['tabindex']); + if (isset($params['call_back_function'])) { + $displayParams['call_back_function'] = $params['call_back_function']; + } + + $_contents = $sfh->displaySmarty($params['parentFieldArray'], $params['vardef'], $params['displayType'], $displayParams, $params['tabindex']); return $_contents; } diff --git a/include/Smarty/plugins/function.sugar_link.php b/include/Smarty/plugins/function.sugar_link.php index 19ba2206..7f6b5ce7 100644 --- a/include/Smarty/plugins/function.sugar_link.php +++ b/include/Smarty/plugins/function.sugar_link.php @@ -94,7 +94,7 @@ function smarty_function_sugar_link($params, &$smarty) if (isset($params['link_only']) && $params['link_only'] == 1 ) { // Let them just get the url, they want to put it someplace - return $link_url; + return ajaxLink($link_url); } $id = (!empty($params['id']))?' id="'.$params['id'].'"':''; @@ -110,6 +110,6 @@ function smarty_function_sugar_link($params, &$smarty) else $label = (!empty($GLOBALS['app_list_strings']['moduleList'][$params['module']]))?$GLOBALS['app_list_strings']['moduleList'][$params['module']]:$params['module']; - $link = ''.$label.''; + $link = ''.$label.''; return $link; } \ No newline at end of file diff --git a/include/Smarty/plugins/modifier.lookup.php b/include/Smarty/plugins/modifier.lookup.php new file mode 100644 index 00000000..157fba48 --- /dev/null +++ b/include/Smarty/plugins/modifier.lookup.php @@ -0,0 +1,47 @@ +process_dynamic_listview($this->parent_module, $this->parent_bean,$this->subpanel_defs); - $this->subpanel_query=$query; + $this->subpanel_query=$query; $ob_contents = ob_get_contents(); ob_end_clean(); return $ob_contents; @@ -298,7 +298,9 @@ class SubPanel write_array_to_file( $name, $override,$path.'/' . $filename .'.php'); //save the override for the layoutdef - $name = "layout_defs['". $panel->parent_bean->module_dir. "']['subpanel_setup']['" .strtolower($panel->name). "']"; // tyoung 10.12.07 pushed panel->name to lowercase to match case in subpaneldefs.php files - gave error on bad index 'module' as this override key didn't match the key in the subpaneldefs + //tyoung 10.12.07 pushed panel->name to lowercase to match case in subpaneldefs.php files - + //gave error on bad index 'module' as this override key didn't match the key in the subpaneldefs + $name = "layout_defs['". $panel->parent_bean->module_dir. "']['subpanel_setup']['" .strtolower($panel->name). "']"; // $GLOBALS['log']->debug('SubPanel.php->saveSubPanelDefOverride(): '.$name); $newValue = override_value_to_string($name, 'override_subpanel_name', $filename); mkdir_recursive('custom/Extension/modules/'. $panel->parent_bean->module_dir . '/Ext/Layoutdefs', true); diff --git a/include/SubPanel/SubPanelDynamic.html b/include/SubPanel/SubPanelDynamic.html index c154b11c..83d96ecd 100644 --- a/include/SubPanel/SubPanelDynamic.html +++ b/include/SubPanel/SubPanelDynamic.html @@ -44,7 +44,7 @@ -{HEADER_CELL} +{HEADER_CELL} diff --git a/include/SubPanel/SubPanelTiles.js b/include/SubPanel/SubPanelTiles.js index e0d833ea..4834f908 100644 --- a/include/SubPanel/SubPanelTiles.js +++ b/include/SubPanel/SubPanelTiles.js @@ -48,6 +48,12 @@ function sub_p_rem(sp,lf,li,rp){return_url="index.php?module="+get_module_name() +"&return_url="+escape(escape(return_url)) +"&refresh_page="+rp;showSubPanel(sp,remove_url,true);} function sp_rem_conf(){return confirm(SUGAR.language.get('app_strings','NTC_REMOVE_CONFIRMATION'))} +function sub_p_del(sp,submod,subrec,rp){return_url="index.php?module="+get_module_name()+"&action=SubPanelViewer&subpanel="+sp+"&record="+get_record_id()+"&sugar_body_only=1&inline=1";remove_url="index.php?module="+submod ++"&action=delete" ++"&record="+subrec ++"&return_url="+escape(escape(return_url)) ++"&refresh_page="+rp;showSubPanel(sp,remove_url,true);} +function sp_del_conf(){return confirm(SUGAR.language.get('app_strings','NTC_DELETE_CONFIRMATION'))} function get_record_id() {return window.document.forms['DetailView'].elements['record'].value;} function get_layout_def_key() @@ -94,22 +100,22 @@ var sub_cookie_name=get_module_name()+'_divs';var temp=Get_Cookie(sub_cookie_nam function set_div_cookie(name,display){div_cookies[name]=display;Set_Cookie(sub_cookie_name,subs_to_cookie(div_cookies),3000,false,false,false);} function local_open_popup(name,width,height,arg1,arg2,arg3,params) {return open_popup(name,width,height,arg1,arg2,arg3,params);} -SUGAR.subpanelUtils=function(){var originalLayout=null;var subpanelContents={};var subpanelLocked={};return{getLayout:function(asString,ignoreHidden){subpanels=document.getElementById('subpanel_list');subpanelIds=new Array();for(wp=0;wp').replace(/'/gi,'\'').replace(/"/gi,'"').replace(/\r\n/gi,'\n');return;}else{showSubPanel(subpanel,null,true);ajaxStatus.showStatus(SUGAR.language.get('app_strings','LBL_SAVED'));window.setTimeout('ajaxStatus.hideStatus()',1000);if(reloadpage)window.location.reload(false);}}} -var reloadpage=false;if((buttonName=='Meetings_subpanel_save_button'||buttonName=='Calls_subpanel_save_button')&&document.getElementById(theForm).status[document.getElementById(theForm).status.selectedIndex].value=='Held'){reloadpage=true;} -YAHOO.util.Connect.setForm(theForm,true,true);var cObj=YAHOO.util.Connect.asyncRequest('POST','index.php',{success:success,failure:success,upload:success});return false;},sendAndRetrieve:function(theForm,theDiv,loadingStr){function success(data){theDivObj=document.getElementById(theDiv);subpanelContents[theDiv]=new Array();subpanelContents[theDiv]['list']=theDivObj;subpanelContents[theDiv]['newDiv']=document.createElement('div');dataToDOMAvail=false;subpanelContents[theDiv]['newDiv'].innerHTML=''+data.responseText;subpanelContents[theDiv]['newDiv'].id=theDiv+'_newDiv';subpanelContents[theDiv]['newDiv'].className='quickcreate';theDivObj.style.display='none';theDivObj.parentNode.insertBefore(subpanelContents[theDiv]['newDiv'],theDivObj);if(!dataToDOMAvail){SUGAR.util.evalScript(data.responseText);} -subpanelLocked[theDiv]=false;setTimeout("enableQS(false)",500);ajaxStatus.hideStatus();} -if(typeof subpanelLocked[theDiv]!='undefined'&&subpanelLocked[theDiv])return false;subpanelLocked[theDiv]=true;if(typeof loadingStr=='undefined')loadingStr=SUGAR.language.get('app_strings','LBL_LOADING');ajaxStatus.showStatus(loadingStr);YAHOO.util.Connect.setForm(theForm);var cObj=YAHOO.util.Connect.asyncRequest('POST','index.php',{success:success,failure:success});return false;},cancelCreate:function(buttonName){var element=document.getElementById(buttonName);var theForm=element.form;var confirmMsg=onUnloadEditView(theForm);do{element=element.parentNode;}while(element.className!='quickcreate'&&element.parentNode);var theDiv=element.id.substr(0,element.id.length-7);if(typeof(subpanelContents[theDiv])=='undefined') +var cObj=YAHOO.util.Connect.asyncRequest('GET',url,{success:success,failure:success});},inlineSave:function(theForm,buttonName){ajaxStatus.showStatus(SUGAR.language.get('app_strings','LBL_SAVING'));var success=function(data){var element=document.getElementById(buttonName);do{element=element.parentNode;}while(element.className!='quickcreate'&&element.parentNode);if(element.className=='quickcreate'){var subpanel=element.id.slice(9,-7);var module=get_module_name();var id=get_record_id();var layout_def_key=get_layout_def_key();try{eval('result = '+data.responseText);}catch(err){} +if(typeof(result)!='undefined'&&result!=null&&result['status']=='dupe'){document.location.href="index.php?"+result['get'].replace(/&/gi,'&').replace(/</gi,'<').replace(/>/gi,'>').replace(/'/gi,'\'').replace(/"/gi,'"').replace(/\r\n/gi,'\n');return;}else{SUGAR.subpanelUtils.cancelCreate(buttonName);showSubPanel(subpanel,null,true);ajaxStatus.showStatus(SUGAR.language.get('app_strings','LBL_SAVED'));window.setTimeout('ajaxStatus.hideStatus()',1000);if(reloadpage)window.location.reload(false);}}} +var reloadpage=false;if((buttonName=='Meetings_subpanel_save_button'||buttonName=='Calls_subpanel_save_button')&&typeof(theForm)!='undefined'&&typeof(document.getElementById(theForm))!='undefined'&&typeof(document.getElementById(theForm).status)!='undefined'&&document.getElementById(theForm).status[document.getElementById(theForm).status.selectedIndex].value=='Held'){reloadpage=true;} +YAHOO.util.Connect.setForm(theForm,true,true);var cObj=YAHOO.util.Connect.asyncRequest('POST','index.php',{success:success,failure:success,upload:success});return false;},sendAndRetrieve:function(theForm,theDiv,loadingStr){function success(data){var theDivObj=document.getElementById(theDiv),divName=theDiv+'_newDiv',form_el;SUGAR.subpanelUtils.dataToDOMAvail=false;SUGAR.subpanelUtils.removeSubPanel();subpanelContents[theDiv]={};subpanelContents[theDiv]['list']=theDivObj;subpanelContents[theDiv]['newDiv']=document.createElement('div');subpanelContents[theDiv]['newDiv'].innerHTML=''+data.responseText;subpanelContents[theDiv]['newDiv'].id=divName;subpanelContents[theDiv]['newDiv'].className='quickcreate';var button_elements=YAHOO.util.Selector.query('td.buttons',theDiv,false);YAHOO.util.Dom.setStyle(button_elements,'display','none');theDivObj.parentNode.insertBefore(subpanelContents[theDiv]['newDiv'],theDivObj);currentPanelDiv=divName;if(!SUGAR.subpanelUtils.dataToDOMAvail){SUGAR.util.evalScript(data.responseText);} +form_el=YAHOO.util.Selector.query('form',divName,true);YAHOO.util.Dom.setStyle(form_el,'padding-bottom','10px');subpanelLocked[theDiv]=false;setTimeout("enableQS(false)",500);ajaxStatus.hideStatus();} +if(subpanelLocked[theDiv]===true){return false;} +subpanelLocked[theDiv]=true;loadingStr=loadingStr||SUGAR.language.get('app_strings','LBL_LOADING');ajaxStatus.showStatus(loadingStr);YAHOO.util.Connect.setForm(theForm);YAHOO.util.Connect.asyncRequest('POST','index.php',{success:success,failure:success});return false;},cancelCreate:function(buttonName){var element=document.getElementById(buttonName),theForm=element.form,confirmMsg=onUnloadEditView(theForm);do{element=element.parentNode;}while(element.className!='quickcreate'&&element.parentNode);var theDiv=element.id.substr(0,element.id.length-7);if(typeof(subpanelContents[theDiv])=='undefined') return false;if(confirmMsg!=null){if(!confirm(confirmMsg)){return false;}else{disableOnUnloadEditView(theForm);}} -subpanelContents[theDiv]['newDiv'].parentNode.removeChild(subpanelContents[theDiv]['newDiv']);subpanelContents[theDiv]['list'].style.display='';return false;},loadSubpanelGroupFromMore:function(group){SUGAR.subpanelUtils.updateSubpanelMoreTab(group);SUGAR.subpanelUtils.loadSubpanelGroup(group);},updateSubpanelMoreTab:function(group){var moreTab=document.getElementById(SUGAR.subpanelUtils.subpanelMoreTab+'_sp_tab');moreTab.id=group+'_sp_tab';moreTab.getElementsByTagName('a')[0].innerHTML=group;moreTab.getElementsByTagName('a')[0].href="javascript:SUGAR.subpanelUtils.loadSubpanelGroup('"+group+"');";var menuLink=document.getElementById(group+'_sp_mm');menuLink.id=SUGAR.subpanelUtils.subpanelMoreTab+'_sp_mm';menuLink.href="javascript:SUGAR.subpanelUtils.loadSubpanelGroupFromMore('"+SUGAR.subpanelUtils.subpanelMoreTab+"');";menuLink.innerHTML=SUGAR.subpanelUtils.subpanelMoreTab;SUGAR.subpanelUtils.subpanelMoreTab=group;},loadSubpanelGroup:function(group){if(group==SUGAR.subpanelUtils.currentSubpanelGroup)return;if(SUGAR.subpanelUtils.loadedGroups[group]){SUGAR.subpanelUtils.updateSubpanel(group);}else{SUGAR.subpanelUtils.loadedGroups.push(group);var needed=Array();for(group_sp in SUGAR.subpanelUtils.subpanelGroups[group]){if(typeof(SUGAR.subpanelUtils.subpanelGroups[group][group_sp])=='string'&&!document.getElementById('whole_subpanel_'+SUGAR.subpanelUtils.subpanelGroups[group][group_sp])){needed.push(SUGAR.subpanelUtils.subpanelGroups[group][group_sp]);}} +SUGAR.subpanelUtils.removeSubPanel();var button_elements=YAHOO.util.Selector.query('td.buttons',theDiv,false);YAHOO.util.Dom.setStyle(button_elements,'display','');return false;},loadSubpanelGroupFromMore:function(group){SUGAR.subpanelUtils.updateSubpanelMoreTab(group);SUGAR.subpanelUtils.loadSubpanelGroup(group);},updateSubpanelMoreTab:function(group){var moreTab=document.getElementById(SUGAR.subpanelUtils.subpanelMoreTab+'_sp_tab');moreTab.id=group+'_sp_tab';moreTab.getElementsByTagName('a')[0].innerHTML=group;moreTab.getElementsByTagName('a')[0].href="javascript:SUGAR.subpanelUtils.loadSubpanelGroup('"+group+"');";var menuLink=document.getElementById(group+'_sp_mm');menuLink.id=SUGAR.subpanelUtils.subpanelMoreTab+'_sp_mm';menuLink.href="javascript:SUGAR.subpanelUtils.loadSubpanelGroupFromMore('"+SUGAR.subpanelUtils.subpanelMoreTab+"');";menuLink.innerHTML=SUGAR.subpanelUtils.subpanelMoreTab;SUGAR.subpanelUtils.subpanelMoreTab=group;},removeSubPanel:function(){var currentPanelEl=document.getElementById(currentPanelDiv);if(currentPanelEl!=null){currentPanelEl.parentNode.removeChild(currentPanelEl);SUGAR.ajaxUI.cleanGlobals();currentPanelDiv=null;}},loadSubpanelGroup:function(group){if(group==SUGAR.subpanelUtils.currentSubpanelGroup)return;if(SUGAR.subpanelUtils.loadedGroups[group]){SUGAR.subpanelUtils.updateSubpanel(group);}else{SUGAR.subpanelUtils.loadedGroups.push(group);var needed=Array();for(group_sp in SUGAR.subpanelUtils.subpanelGroups[group]){if(typeof(SUGAR.subpanelUtils.subpanelGroups[group][group_sp])=='string'&&!document.getElementById('whole_subpanel_'+SUGAR.subpanelUtils.subpanelGroups[group][group_sp])){needed.push(SUGAR.subpanelUtils.subpanelGroups[group][group_sp]);}} var success=function(){SUGAR.subpanelUtils.updateSubpanelEventHandlers(needed);SUGAR.subpanelUtils.updateSubpanels(group);};if(needed.length){ajaxStatus.showStatus(SUGAR.language.get('app_strings','LBL_LOADING'));SUGAR.util.retrieveAndFill(SUGAR.subpanelUtils.requestUrl+needed.join(','),'subpanel_list',null,success,null,true);}else{SUGAR.subpanelUtils.updateSubpanels(group);}} SUGAR.subpanelUtils.setGroupCookie(group);},updateSubpanels:function(group){var sp_list=document.getElementById('subpanel_list');for(sp in sp_list.childNodes){if(sp_list.childNodes[sp].id){sp_list.childNodes[sp].style.display='none';}} -for(group_sp in SUGAR.subpanelUtils.subpanelGroups[group]){if(typeof(SUGAR.subpanelUtils.subpanelGroups[group][group_sp])!='string')continue;var cur=document.getElementById('whole_subpanel_'+SUGAR.subpanelUtils.subpanelGroups[group][group_sp]);if(cur!=null) -cur.style.display='block';try{YAHOO.util.DDM.swapNode(cur,sp_list.getElementsByTagName('LI')[group_sp]);}catch(e){}} +for(group_sp in SUGAR.subpanelUtils.subpanelGroups[group]){if(typeof(SUGAR.subpanelUtils.subpanelGroups[group][group_sp])!='string')continue;var cur=document.getElementById('whole_subpanel_'+SUGAR.subpanelUtils.subpanelGroups[group][group_sp]);cur.style.display='block';try{YAHOO.util.DDM.swapNode(cur,sp_list.getElementsByTagName('LI')[group_sp]);}catch(e){}} SUGAR.subpanelUtils.updateSubpanelTabs(group);},updateSubpanelTabs:function(group){if(SUGAR.subpanelUtils.showLinks){SUGAR.subpanelUtils.updateSubpanelSubtabs(group);document.getElementById('subpanelSubTabs').innerHTML=SUGAR.subpanelUtils.subpanelSubTabs[group];} oldTab=document.getElementById(SUGAR.subpanelUtils.currentSubpanelGroup+'_sp_tab');if(oldTab){oldTab.className='';oldTab.getElementsByTagName('a')[0].className='';} mainTab=document.getElementById(group+'_sp_tab');mainTab.className='active';mainTab.getElementsByTagName('a')[0].className='current';SUGAR.subpanelUtils.currentSubpanelGroup=group;ajaxStatus.hideStatus();},updateSubpanelEventHandlers:function(){if(SubpanelInitTabNames){SubpanelInitTabNames(SUGAR.subpanelUtils.getLayout(false));}},reorderSubpanelSubtabs:function(group,order){SUGAR.subpanelUtils.subpanelGroups[group]=order;if(SUGAR.subpanelUtils.showLinks==1){SUGAR.subpanelUtils.updateSubpanelSubtabs(group);if(SUGAR.subpanelUtils.currentSubpanelGroup==group){document.getElementById('subpanelSubTabs').innerHTML=SUGAR.subpanelUtils.subpanelSubTabs[group];}}},updateSubpanelSubtabs:function(group){var notFirst=0;var preMore=SUGAR.subpanelUtils.subpanelGroups[group].slice(0,SUGAR.subpanelUtils.subpanelMaxSubtabs);SUGAR.subpanelUtils.subpanelSubTabs[group]='';for(var sp_key=0;sp_key | ';}else{notFirst=1;} diff --git a/include/SubPanel/SubPanelTiles.php b/include/SubPanel/SubPanelTiles.php index cc19f066..9f3d6203 100644 --- a/include/SubPanel/SubPanelTiles.php +++ b/include/SubPanel/SubPanelTiles.php @@ -309,7 +309,7 @@ if(document.DetailView != null && if (empty($this->show_tabs)) { - $show_icon_html = SugarThemeRegistry::current()->getImage( 'advanced_search', 'alt="' . translate('LBL_SHOW') . '" border="0 align="absmiddle""'); + $show_icon_html = SugarThemeRegistry::current()->getImage( 'advanced_search', 'alt="' . translate('LBL_SHOW') . '" border="0" align="absmiddle"'); $hide_icon_html = SugarThemeRegistry::current()->getImage( 'basic_search', 'alt="' . translate('LBL_HIDE') . '" border="0" align="absmiddle"'); $max_min = " " . "" . $show_icon_html . ""; @@ -326,7 +326,7 @@ if(document.DetailView != null && EOQ; $display_spd = ''; if($div_display != 'none'){ - echo ""; + echo ""; $old_contents = ob_get_contents(); @ob_end_clean(); @@ -390,7 +390,11 @@ EOQ; YAHOO.util.DDM.mode = 1; } currentModule = '{$this->module}'; - YAHOO.util.Event.addListener(window, 'load', SubpanelInit); + SUGAR.util.doWhen( + "typeof(SUGAR.subpanelUtils) == 'object' && typeof(SUGAR.subpanelUtils.onDrag) == 'function'" + + " && document.getElementById('subpanel_list')", + SubpanelInit + ); EOQ; } diff --git a/include/SubPanel/SugarTab.php b/include/SubPanel/SugarTab.php index 3c68e144..e3edd2e4 100644 --- a/include/SubPanel/SugarTab.php +++ b/include/SubPanel/SugarTab.php @@ -61,11 +61,18 @@ class SugarTab unset($mainTabs[$selected_group]); array_splice($mainTabs, $max_tabs-1, 0, $temp); } + + $subpanelTitles = array(); + foreach($otherTabs['All']['tabs'] as $subtab) + { + $subpanelTitles[$subtab['key']] = $subtab['label']; + } $this->ss->assign('showLinks', 'false'); $this->ss->assign('sugartabs', array_slice($mainTabs, 0, $max_tabs)); $this->ss->assign('moreMenu', array_slice($mainTabs, $max_tabs)); $this->ss->assign('othertabs', $otherTabs); + $this->ss->assign('subpanelTitlesJSON', json_encode($subpanelTitles)); $this->ss->assign('startSubPanel', $selected_group); $this->ss->assign('sugarVersionJsStr', "?s=$sugar_version&c={$sugar_config['js_custom_version']}"); if(!empty($mainTabs)) diff --git a/include/SubPanel/tpls/singletabmenu.tpl b/include/SubPanel/tpls/singletabmenu.tpl index 09123ac2..ab3ae509 100644 --- a/include/SubPanel/tpls/singletabmenu.tpl +++ b/include/SubPanel/tpls/singletabmenu.tpl @@ -61,7 +61,7 @@ {/foreach} {assign var='notFirst' value='0'} - SUGAR.subpanelUtils.subpanelTitles = {ldelim}{foreach from=$othertabs.All.tabs item=subtab}{if $notFirst != 0}, {else}{assign var='notFirst' value='1'}{/if}'{$subtab.key}':'{$subtab.label}'{/foreach}{foreach from=$otherMoreSubMenu.All.tabs item=subtab}, '{$subtab.key}':'{$subtab.label}'{/foreach}{rdelim}; + SUGAR.subpanelUtils.subpanelTitles = {$subpanelTitlesJSON}; SUGAR.subpanelUtils.tabCookieName = get_module_name() + '_sp_tab'; diff --git a/include/SugarCache/SugarCache.php b/include/SugarCache/SugarCache.php index 852c2a87..d9293a52 100644 --- a/include/SugarCache/SugarCache.php +++ b/include/SugarCache/SugarCache.php @@ -176,6 +176,15 @@ function sugar_cache_reset() SugarCache::cleanOpcodes(); } +/** + * Flush the cache in its entirety including the local and external store along with the opcodes. + */ +function sugar_cache_reset_full() +{ + SugarCache::instance()->resetFull(); + SugarCache::cleanOpcodes(); +} + /** * Clean out whatever opcode cache we may have out there. */ diff --git a/include/SugarCache/SugarCacheAPC.php b/include/SugarCache/SugarCacheAPC.php index 35a58e8b..60943a3f 100644 --- a/include/SugarCache/SugarCacheAPC.php +++ b/include/SugarCache/SugarCacheAPC.php @@ -43,7 +43,7 @@ class SugarCacheAPC extends SugarCacheAbstract * @see SugarCacheAbstract::$_priority */ protected $_priority = 940; - + /** * @see SugarCacheAbstract::useBackend() */ @@ -51,14 +51,14 @@ class SugarCacheAPC extends SugarCacheAbstract { if ( !parent::useBackend() ) return false; - + if ( function_exists("apc_store") && empty($GLOBALS['sugar_config']['external_cache_disabled_apc'])) return true; - + return false; } - + /** * @see SugarCacheAbstract::_setExternal() */ @@ -69,7 +69,7 @@ class SugarCacheAPC extends SugarCacheAbstract { apc_store($key,$value,$this->expireTimeout); } - + /** * @see SugarCacheAbstract::_getExternal() */ @@ -77,13 +77,14 @@ class SugarCacheAPC extends SugarCacheAbstract $key ) { - if ( apc_fetch($key) === false ) { + $res = apc_fetch($key); + if($res === false) { return null; } - - return apc_fetch($key); + + return $res; } - + /** * @see SugarCacheAbstract::_clearExternal() */ @@ -93,7 +94,7 @@ class SugarCacheAPC extends SugarCacheAbstract { apc_delete($key); } - + /** * @see SugarCacheAbstract::_resetExternal() */ diff --git a/include/SugarCache/SugarCacheAbstract.php b/include/SugarCache/SugarCacheAbstract.php index 7772901b..55770a6f 100644 --- a/include/SugarCache/SugarCacheAbstract.php +++ b/include/SugarCache/SugarCacheAbstract.php @@ -41,50 +41,50 @@ abstract class SugarCacheAbstract * @var set to false if you don't want to use the local store, true by default. */ public $useLocalStore = true; - + /** * @var timeout in seconds used for cache item expiration */ protected $_expireTimeout = 300; - + /** * @var prefix to use for all cache key entries */ protected $_keyPrefix = 'sugarcrm_'; - + /** * @var stores locally any cached items so we don't have to hit the external cache as much */ protected $_localStore = array(); - + /** * @var records the number of get requests made against the cache */ protected $_cacheRequests = 0; - + /** * @var records the number of hits made against the cache that have been resolved without hitting the * external cache */ protected $_cacheLocalHits = 0; - + /** * @var records the number of hits made against the cache that are resolved using the external cache */ protected $_cacheExternalHits = 0; - + /** * @var records the number of get requests that aren't in the cache */ protected $_cacheMisses = 0; - + /** * @var indicates the priority level for using this cache; the lower number indicates the highest * priority ( 1 would be the highest priority, but we should never ship a backend with this number * so we don't bump out custom backends. ) Shipping backends use priorities in the range of 900-999. */ protected $_priority = 899; - + /** * Constructor */ @@ -95,14 +95,14 @@ abstract class SugarCacheAbstract if ( isset($GLOBALS['sugar_config']['unique_key']) ) $this->_keyPrefix = $GLOBALS['sugar_config']['unique_key']; } - + /** * Destructor */ public function __destruct() { } - + /** * PHP's magic __get() method, used here for getting the current value from the cache. * @@ -114,8 +114,8 @@ abstract class SugarCacheAbstract ) { if ( SugarCache::$isCacheReset ) - return; - + return null; + $this->_cacheRequests++; if ( !$this->useLocalStore || !isset($this->_localStore[$key]) ) { $this->_localStore[$key] = $this->_getExternal($this->_keyPrefix.$key); @@ -129,14 +129,14 @@ abstract class SugarCacheAbstract elseif ( isset($this->_localStore[$key]) ) { $this->_cacheLocalHits++; } - + if ( isset($this->_localStore[$key]) ) { return $this->_localStore[$key]; } - + return null; } - + /** * PHP's magic __set() method, used here for setting a value for a key in the cache. * @@ -151,13 +151,13 @@ abstract class SugarCacheAbstract if ( is_null($value) ) { $value = SugarCache::EXTERNAL_CACHE_NULL_VALUE; } - + if ( $this->useLocalStore ) { $this->_localStore[$key] = $value; } $this->_setExternal($this->_keyPrefix.$key,$value); } - + /** * PHP's magic __isset() method, used here for checking for a key in the cache. * @@ -170,7 +170,7 @@ abstract class SugarCacheAbstract { return !is_null($this->__get($key)); } - + /** * PHP's magic __unset() method, used here for clearing a key in the cache. * @@ -184,7 +184,7 @@ abstract class SugarCacheAbstract unset($this->_localStore[$key]); $this->_clearExternal($this->_keyPrefix.$key); } - + /** * Reset the cache for this request */ @@ -193,7 +193,7 @@ abstract class SugarCacheAbstract $this->_localStore = array(); SugarCache::$isCacheReset = true; } - + /** * Reset the cache fully */ @@ -202,7 +202,7 @@ abstract class SugarCacheAbstract $this->reset(); $this->_resetExternal(); } - + /** * Flush the contents of the cache */ @@ -211,7 +211,7 @@ abstract class SugarCacheAbstract $this->_localStore = array(); $this->_resetExternal(); } - + /** * Returns the number of cache hits made * @@ -226,7 +226,7 @@ abstract class SugarCacheAbstract 'misses' => $this->_cacheMisses, ); } - + /** * Returns what backend is used for caching, uses normalized class name for lookup * @@ -236,7 +236,7 @@ abstract class SugarCacheAbstract { return strtolower(str_replace('SugarCache','',get_class($this))); } - + /** * Hook for the child implementations of the individual backends to provide thier own logic for * setting a value from cache @@ -248,7 +248,7 @@ abstract class SugarCacheAbstract $key, $value ); - + /** * Hook for the child implementations of the individual backends to provide thier own logic for * getting a value from cache @@ -259,7 +259,7 @@ abstract class SugarCacheAbstract abstract protected function _getExternal( $key ); - + /** * Hook for the child implementations of the individual backends to provide thier own logic for * clearing a value out of thier cache @@ -269,13 +269,13 @@ abstract class SugarCacheAbstract abstract protected function _clearExternal( $key ); - + /** * Hook for the child implementations of the individual backends to provide thier own logic for * clearing thier cache out fully */ abstract protected function _resetExternal(); - + /** * Hook for testing if the backend should be used or not. Typically we'll extend this for backend specific * checks as well. @@ -284,23 +284,23 @@ abstract class SugarCacheAbstract */ public function useBackend() { - if ( !empty($GLOBALS['sugar_config']['external_cache_disabled']) + if ( !empty($GLOBALS['sugar_config']['external_cache_disabled']) && $GLOBALS['sugar_config']['external_cache_disabled'] == true ) { return false; } - + if (defined('SUGARCRM_IS_INSTALLING')) { return false; } - + if ( isset($GLOBALS['sugar_config']['external_cache_force_backend']) && ( $GLOBALS['sugar_config']['external_cache_force_backend'] != (string) $this ) ) { return false; } - + return true; } - + /** * Returns the priority level for this backend * diff --git a/include/SugarCache/SugarCacheFile.php b/include/SugarCache/SugarCacheFile.php index cd26873a..6918bd57 100644 --- a/include/SugarCache/SugarCacheFile.php +++ b/include/SugarCache/SugarCacheFile.php @@ -43,17 +43,17 @@ class SugarCacheFile extends SugarCacheAbstract * @var path and file which will store the cache used for this backend */ protected $_cacheFileName = 'externalCache.php'; - + /** * @var bool true if the cache has changed and needs written to disk */ protected $_cacheChanged = false; - + /** * @see SugarCacheAbstract::$_priority */ protected $_priority = 990; - + /** * @see SugarCacheAbstract::useBackend() */ @@ -61,27 +61,27 @@ class SugarCacheFile extends SugarCacheAbstract { if ( !parent::useBackend() ) return false; - + if ( !empty($GLOBALS['sugar_config']['external_cache_enabled_file']) ) return true; - + return false; } - + /** * @see SugarCacheAbstract::__construct() * - * For this backend, we'll read from the SugarCacheFile::_cacheFileName file into + * For this backend, we'll read from the SugarCacheFile::_cacheFileName file into * the SugarCacheFile::$localCache array. */ public function __construct() { parent::__construct(); - + if ( isset($GLOBALS['sugar_config']['external_cache_filename']) ) $this->_cacheFileName = $GLOBALS['sugar_config']['external_cache_filename']; } - + /** * @see SugarCacheAbstract::__destruct() * @@ -90,12 +90,12 @@ class SugarCacheFile extends SugarCacheAbstract public function __destruct() { parent::__destruct(); - + if ( $this->_cacheChanged ) sugar_file_put_contents($GLOBALS['sugar_config']['cache_dir'].'/'.$this->_cacheFileName, serialize($this->_localStore)); } - + /** * @see SugarCacheAbstract::_setExternal() * @@ -108,7 +108,7 @@ class SugarCacheFile extends SugarCacheAbstract { $this->_cacheChanged = true; } - + /** * @see SugarCacheAbstract::_getExternal() */ @@ -120,11 +120,13 @@ class SugarCacheFile extends SugarCacheAbstract if ( sugar_is_file($GLOBALS['sugar_config']['cache_dir'].'/'.$this->_cacheFileName) ) $this->localCache = unserialize( file_get_contents($GLOBALS['sugar_config']['cache_dir'].'/'.$this->_cacheFileName)); - + if ( isset($this->_localStore[$key]) ) return $this->_localStore[$key]; + + return null; } - + /** * @see SugarCacheAbstract::_clearExternal() * @@ -136,7 +138,7 @@ class SugarCacheFile extends SugarCacheAbstract { $this->_cacheChanged = true; } - + /** * @see SugarCacheAbstract::_resetExternal() * diff --git a/include/SugarCache/SugarCacheMemcache.php b/include/SugarCache/SugarCacheMemcache.php index 7a39ae31..153e3fac 100644 --- a/include/SugarCache/SugarCacheMemcache.php +++ b/include/SugarCache/SugarCacheMemcache.php @@ -42,7 +42,7 @@ class SugarCacheMemcache extends SugarCacheAbstract /** * @var Memcache server name string */ - protected $_host = 'localhost'; + protected $_host = '127.0.0.1'; /** * @var Memcache server port int diff --git a/include/SugarCache/SugarCacheMemcached.php b/include/SugarCache/SugarCacheMemcached.php index ecaacd48..2bf32605 100644 --- a/include/SugarCache/SugarCacheMemcached.php +++ b/include/SugarCache/SugarCacheMemcached.php @@ -42,7 +42,7 @@ class SugarCacheMemcached extends SugarCacheAbstract /** * @var Memcache server name string */ - protected $_host = 'localhost'; + protected $_host = '127.0.0.1'; /** * @var Memcache server port int @@ -105,7 +105,7 @@ class SugarCacheMemcached extends SugarCacheAbstract $value ) { - $this->_getMemcachedObject()->set($key, $value, $this->expireTimeout); + $this->_getMemcachedObject()->set($key, $value, $this->_expireTimeout); } /** @@ -116,10 +116,10 @@ class SugarCacheMemcached extends SugarCacheAbstract ) { $returnValue = $this->_getMemcachedObject()->get($key); - if ( $this->_getMemcachedObject()->getResultCode() == Memcached::RES_NOTFOUND ) { + if ( $this->_getMemcachedObject()->getResultCode() != Memcached::RES_SUCCESS ) { return null; } - + return $returnValue; } diff --git a/include/SugarCache/SugarCacheZend.php b/include/SugarCache/SugarCacheZend.php index e03bc058..5f3473b1 100644 --- a/include/SugarCache/SugarCacheZend.php +++ b/include/SugarCache/SugarCacheZend.php @@ -43,7 +43,7 @@ class SugarCacheZend extends SugarCacheAbstract * @see SugarCacheAbstract::$_priority */ protected $_priority = 910; - + /** * @see SugarCacheAbstract::useBackend() */ @@ -51,14 +51,14 @@ class SugarCacheZend extends SugarCacheAbstract { if ( !parent::useBackend() ) return false; - + if ( function_exists("zend_shm_cache_fetch") && empty($GLOBALS['sugar_config']['external_cache_disabled_zend'])) return true; - + return false; } - + /** * @see SugarCacheAbstract::_setExternal() */ @@ -69,7 +69,7 @@ class SugarCacheZend extends SugarCacheAbstract { zend_shm_cache_store($key,serialize($value),$this->expireTimeout); } - + /** * @see SugarCacheAbstract::_getExternal() */ @@ -78,11 +78,14 @@ class SugarCacheZend extends SugarCacheAbstract ) { $raw_cache_value = zend_shm_cache_fetch($key); + if($raw_cache_value === false) { + return null; + } return is_string($raw_cache_value) ? unserialize($raw_cache_value) : $raw_cache_value; } - + /** * @see SugarCacheAbstract::_clearExternal() */ @@ -92,7 +95,7 @@ class SugarCacheZend extends SugarCacheAbstract { zend_shm_cache_delete($key); } - + /** * @see SugarCacheAbstract::_resetExternal() */ diff --git a/include/SugarCharts/Jit/js/mySugarCharts.js b/include/SugarCharts/Jit/js/mySugarCharts.js index 27a4ce77..0fb9b452 100644 --- a/include/SugarCharts/Jit/js/mySugarCharts.js +++ b/include/SugarCharts/Jit/js/mySugarCharts.js @@ -32,8 +32,8 @@ * technical reasons, the Appropriate Legal Notices must display the words * "Powered by SugarCRM". ********************************************************************************/ -SUGAR.mySugar.sugarCharts=function(){var activeTab=activePage,charts=new Object();return{loadSugarCharts:function(activeTab){var chartFound=false;if(typeof numCols=='undefined') +initmySugarCharts=function(){SUGAR.mySugar.sugarCharts=function(){var activeTab=activePage,charts=new Object();return{loadSugarCharts:function(activeTab){var chartFound=false;if(typeof numCols=='undefined') {var numCols=2;} for(id in charts[activeTab]){if(id!='undefined'){chartFound=true;loadSugarChart(charts[activeTab][id]['chartId'],charts[activeTab][id]['jsonFilename'],charts[activeTab][id]['css'],charts[activeTab][id]['chartConfig'],numCols);}} charts=new Object();},addToChartsArrayJson:function(json,activeTab){for(id in json){if(json[id]['supported']=="true"){SUGAR.mySugar.sugarCharts.addToChartsArray(json[id]['chartId'],json[id]['filename'],json[id]['css'],json[id]['chartConfig'],activeTab);}}},addToChartsArray:function(chartId,jsonFilename,css,chartConfig,activeTab){if(charts[activeTab]==null){charts[activeTab]=new Object();} -charts[activeTab][chartId]=new Object();charts[activeTab][chartId]['chartId']=chartId;charts[activeTab][chartId]['jsonFilename']=jsonFilename;charts[activeTab][chartId]['css']=css;charts[activeTab][chartId]['chartConfig']=chartConfig;}}}(); +charts[activeTab][chartId]=new Object();charts[activeTab][chartId]['chartId']=chartId;charts[activeTab][chartId]['jsonFilename']=jsonFilename;charts[activeTab][chartId]['css']=css;charts[activeTab][chartId]['chartConfig']=chartConfig;}}}();}; diff --git a/include/SugarCharts/Jit/tpls/DashletGenericChartScript.tpl b/include/SugarCharts/Jit/tpls/DashletGenericChartScript.tpl index 044dfa2e..abc71b82 100644 --- a/include/SugarCharts/Jit/tpls/DashletGenericChartScript.tpl +++ b/include/SugarCharts/Jit/tpls/DashletGenericChartScript.tpl @@ -37,15 +37,19 @@ *} \ No newline at end of file diff --git a/include/SugarCharts/Jit/tpls/chart.tpl b/include/SugarCharts/Jit/tpls/chart.tpl index 26258261..7076be75 100644 --- a/include/SugarCharts/Jit/tpls/chart.tpl +++ b/include/SugarCharts/Jit/tpls/chart.tpl @@ -37,46 +37,40 @@ *} {if !$error} - - -
    +
    -
    +
    - - {else} {$error} diff --git a/include/SugarCharts/JsChart.php b/include/SugarCharts/JsChart.php index 1fbac7d2..38171720 100644 --- a/include/SugarCharts/JsChart.php +++ b/include/SugarCharts/JsChart.php @@ -622,7 +622,6 @@ class JsChart extends SugarChart { } function saveJsonFile($jsonContents) { - $this->jsonFilename = str_replace(".xml",".js",$this->xmlFile); //$jsonContents = mb_convert_encoding($jsonContents, 'UTF-16LE', 'UTF-8'); diff --git a/include/SugarDateTime.php b/include/SugarDateTime.php index cd1526d9..93a6d8ec 100644 --- a/include/SugarDateTime.php +++ b/include/SugarDateTime.php @@ -91,13 +91,13 @@ class SugarDateTime extends DateTime * * Needed to return right type of the object * - * @param string $format - * @param string $time + * @param string $format Format like in date() + * @param string $time Time to parse * @param DateTimeZone $timezone * @return SugarDateTime * @see DateTime::createFromFormat */ - public static function createFromFormat($format, $time, DateTimeZone $timezone = null) + public static function createFromFormat($format, $time, $timezone = null) { if(empty($time) || empty($format)) { return false; @@ -116,11 +116,18 @@ class SugarDateTime extends DateTime if(!$d) { return false; } - $sd = new self("@".$d->getTimestamp()); + $sd = new self($d->format(DateTime::ISO8601)); $sd->setTimezone($d->getTimezone()); return $sd; } + /** + * Internal _createFromFormat implementation for 5.2 + * @param string $format Format like in date() + * @param string $time Time string to parse + * @param DateTimeZone $timezone TZ + * @see DateTime::createFromFormat + */ protected static function _createFromFormat($format, $time, DateTimeZone $timezone = null) { $res = new self(); @@ -411,6 +418,7 @@ class SugarDateTime extends DateTime $newdate->setTime(0,0); return $newdate; } + /* * Print datetime in standard DB format * @@ -430,6 +438,25 @@ class SugarDateTime extends DateTime return $this->format(TimeDate::DB_DATETIME_FORMAT); } + /* + * Print date in standard DB format + * + * Set $tz parameter to false if you are sure if the date is in UTC. + * + * @param bool $tz do conversion to UTC + * @return string + */ + function asDbDate($tz = true) + { + if($tz) { + if(empty(self::$_gmt)) { + self::$_gmt = new DateTimeZone("UTC"); + } + $this->setTimezone(self::$_gmt); + } + return $this->format(TimeDate::DB_DATE_FORMAT); + } + /** * Get query string for the date * @return string @@ -587,9 +614,10 @@ class SugarDateTime extends DateTime /** * (non-PHPdoc) * @see DateTime::setTimezone() + * @param DateTimeZone $timezone * @return SugarDateTime */ - public function setTimezone (DateTimeZone $timezone) + public function setTimezone ($timezone) { parent::setTimezone($timezone); return $this; diff --git a/include/SugarEmailAddress/SugarEmailAddress.js b/include/SugarEmailAddress/SugarEmailAddress.js index db6299c3..a8640b4f 100644 --- a/include/SugarEmailAddress/SugarEmailAddress.js +++ b/include/SugarEmailAddress/SugarEmailAddress.js @@ -37,14 +37,15 @@ document.getElementById(module+'_email_widget_id').value=this.id;SUGAR.EmailAddr SUGAR.EmailAddressWidget.instances={};SUGAR.EmailAddressWidget.count={};SUGAR.EmailAddressWidget.prototype={emailTemplate:'
    '+''+''+''+''+''+''+'',numberEmailAddresses:0,replyToFlagObject:new Object(),verifying:false,enterPressed:false,tabPressed:false,emailView:"",emailIsRequired:false,tabIndex:-1,prefillEmailAddresses:function(tableId,o){for(i=0;i1){verifyElementFlag.parentNode.removeChild(verifyElementFlag.parentNode.lastChild);} -var verifiedTextNode=document.createElement('span');verifiedTextNode.innerHTML='';verifyElementFlag.parentNode.appendChild(verifiedTextNode);verifyElementFlag.value="true";this.verifyElementValue=Dom.get(this.id+'emailAddressVerifiedValue'+index);this.verifyElementValue.value=Dom.get(this.id+'emailAddress'+index).value;this.verifying=false;var savePressed=false;if(event){var elm=document.activeElement||event.explicitOriginalTarget;if(typeof elm.type!='undefined'&&!(/_email_widget_add/.test(elm.id.toLowerCase()))&&/submit|button/.test(elm.type.toLowerCase())){savePressed=true;}} +var verifiedTextNode=document.createElement('span');verifiedTextNode.innerHTML='';verifyElementFlag.parentNode.appendChild(verifiedTextNode);verifyElementFlag.value="true";this.verifyElementValue=Dom.get(this.id+'emailAddressVerifiedValue'+index);this.verifyElementValue.value=Dom.get(this.id+'emailAddress'+index).value;this.verifying=false;var savePressed=false;if(event){var elm=document.activeElement||event.explicitOriginalTarget;if(typeof elm.type!='undefined'&&/submit|button/.test(elm.type.toLowerCase())){if(/save|full|cancel|change/.test(elm.value.toLowerCase())){savePressed=true;}}} if(savePressed||this.enterPressed){setTimeout("SUGAR.EmailAddressWidget.instances."+this.id+".forceSubmit()",2100);}else if(this.tabPressed){Dom.get(this.id+'emailAddressPrimaryFlag'+index).focus();}} -var event=this.getEvent(event);var targetEl=this.getEventElement(event);var index=/[a-z]*\d?emailAddress(\d+)/i.exec(targetEl.id)[1];var verifyElementFlag=Dom.get(this.id+'emailAddressVerifiedFlag'+index);this.verifyElementValue=Dom.get(this.id+'emailAddressVerifiedValue'+index);verifyElementFlag.value=(trim(targetEl.value)==''||targetEl.value==this.verifyElementValue.value)?"true":"false" +var event=this.getEvent(event);var targetEl=this.getEventElement(event);var index=/[a-z]*\d?emailAddress(\d+)/i.exec(targetEl.id)[1];var verifyElementFlag=Dom.get(this.id+'emailAddressVerifiedFlag'+index);if(this.verifyElementValue==null||typeof(this.verifyElementValue)=='undefined'){return false;} +this.verifyElementValue=Dom.get(this.id+'emailAddressVerifiedValue'+index);verifyElementFlag.value=(trim(targetEl.value)==''||targetEl.value==this.verifyElementValue.value)?"true":"false" if(verifyElementFlag.parentNode.childNodes.length>1){verifyElementFlag.parentNode.removeChild(verifyElementFlag.parentNode.lastChild);} if(/emailAddress\d+$/.test(targetEl.id)&&isValidEmail(targetEl.value)&&!this.verifying&&verifyElementFlag.value=="false"){verifiedTextNode=document.createElement('span');verifyElementFlag.parentNode.appendChild(verifiedTextNode);verifiedTextNode.innerHTML=SUGAR.language.get('app_strings','LBL_VERIFY_EMAIL_ADDRESS');this.verifying=true;var cObj=YAHOO.util.Connect.asyncRequest('GET','index.php?module=Contacts&action=RetrieveEmail&target='+targetEl.id+'&email='+targetEl.value,{success:callbackFunction,failure:callbackFunction,scope:this});}},handleKeyDown:function(event){var e=this.getEvent(event);var eL=this.getEventElement(e);if((kc=e["keyCode"])){this.enterPressed=(kc==13)?true:false;this.tabPressed=(kc==9)?true:false;if(this.enterPressed||this.tabPressed){this.retrieveEmailAddress(e);if(this.enterPressed) this.freezeEvent(e);}}},getEvent:function(event){return(event?event:window.event);},getEventElement:function(e){return(e.srcElement?e.srcElement:(e.target?e.target:e.currentTarget));},freezeEvent:function(e){if(e.preventDefault)e.preventDefault();e.returnValue=false;e.cancelBubble=true;if(e.stopPropagation)e.stopPropagation();return false;},addEmailAddress:function(tableId,address,primaryFlag,replyToFlag,optOutFlag,invalidFlag){if(this.addInProgress) return;this.addInProgress=true;if(!address) -address="";var insertInto=Dom.get(tableId);var parentObj=insertInto.parentNode;var newContent=document.createElement("input");var nav=new String(navigator.appVersion);var newContentPrimaryFlag;newContentPrimaryFlag=document.createElement("input");var newContentReplyToFlag=document.createElement("input");var newContentOptOutFlag=document.createElement("input");var newContentInvalidFlag=document.createElement("input");var newContentVerifiedFlag=document.createElement("input");var newContentVerifiedValue=document.createElement("input");var removeButton=document.createElement("img");var tbody=document.createElement("tbody");var tr=document.createElement("tr");var td1=document.createElement("td");var td2=document.createElement("td");var td3=document.createElement("td");var td4=document.createElement("td");var td5=document.createElement("td");var td6=document.createElement("td");var td7=document.createElement("td");var td8=document.createElement("td");newContent.setAttribute("type","text");newContent.setAttribute("name",this.id+"emailAddress"+this.numberEmailAddresses);newContent.setAttribute("id",this.id+"emailAddress"+this.numberEmailAddresses);newContent.setAttribute("tabindex",this.tabIndex);newContent.setAttribute("size","30");if(address!=''){newContent.setAttribute("value",address);} +address="";var insertInto=Dom.get(tableId);var parentObj=insertInto.parentNode;var newContent=document.createElement("input");var nav=new String(navigator.appVersion);var newContentPrimaryFlag=document.createElement("input");var newContentReplyToFlag=document.createElement("input");var newContentOptOutFlag=document.createElement("input");var newContentInvalidFlag=document.createElement("input");var newContentVerifiedFlag=document.createElement("input");var newContentVerifiedValue=document.createElement("input");var removeButton=document.createElement("img");var tbody=document.createElement("tbody");var tr=document.createElement("tr");var td1=document.createElement("td");var td2=document.createElement("td");var td3=document.createElement("td");var td4=document.createElement("td");var td5=document.createElement("td");var td6=document.createElement("td");var td7=document.createElement("td");var td8=document.createElement("td");newContent.setAttribute("type","text");newContent.setAttribute("name",this.id+"emailAddress"+this.numberEmailAddresses);newContent.setAttribute("id",this.id+"emailAddress"+this.numberEmailAddresses);newContent.setAttribute("tabindex",this.tabIndex);newContent.setAttribute("size","30");if(address!=''){newContent.setAttribute("value",address);} removeButton.setAttribute("id",this.id+"removeButton"+this.numberEmailAddresses);removeButton.setAttribute("class","id-ff-remove");removeButton.setAttribute("name",this.numberEmailAddresses);removeButton.eaw=this;removeButton.setAttribute("src","index.php?entryPoint=getImage&themeName="+SUGAR.themes.theme_name+"&imageName=id-ff-remove.png");removeButton.onclick=function(){this.eaw.removeEmailAddress(this.name);};newContentPrimaryFlag.setAttribute("type","radio");newContentPrimaryFlag.setAttribute("name",this.id+"emailAddressPrimaryFlag");newContentPrimaryFlag.setAttribute("id",this.id+"emailAddressPrimaryFlag"+this.numberEmailAddresses);newContentPrimaryFlag.setAttribute("value",this.id+"emailAddress"+this.numberEmailAddresses);newContentPrimaryFlag.setAttribute("enabled","true");newContentReplyToFlag.setAttribute("type","radio");newContentReplyToFlag.setAttribute("name",this.id+"emailAddressReplyToFlag");newContentReplyToFlag.setAttribute("id",this.id+"emailAddressReplyToFlag"+this.numberEmailAddresses);newContentReplyToFlag.setAttribute("value",this.id+"emailAddress"+this.numberEmailAddresses);newContentReplyToFlag.setAttribute("enabled","true");newContentReplyToFlag.eaw=this;newContentReplyToFlag['onclick']=function(){var form=document.forms[this.eaw.emailView];if(!form){form=document.forms['editContactForm'];} var nav=new String(navigator.appVersion);if(nav.match(/MSIE/gim)){for(i=0;i0){var emailcontainer=Dom.getAncestorByTagName(insertInto,'span');YAHOO.util.Event.addListener(newContent,"change",function(ev,el){SUGAR.util.callOnChangeListers(el);},emailcontainer);} +this.EmailAddressValidation(this.emailView,this.id+'emailAddress'+this.numberEmailAddresses,this.emailIsRequired,SUGAR.language.get('app_strings','LBL_EMAIL_ADDRESS_BOOK_EMAIL_ADDR'));this.numberEmailAddresses++;this.addInProgress=false;},EmailAddressValidation:function(ev,fn,r,stR){YAHOO.util.Event.onContentReady(fn,function(){addToValidate(ev,fn,'email',r,stR);});},removeEmailAddress:function(index){removeFromValidate(this.emailView,this.id+'emailAddress'+index);var oNodeToRemove=Dom.get(this.id+'emailAddressRow'+index);oNodeToRemove.parentNode.removeChild(oNodeToRemove);var removedIndex=parseInt(index);if(this.numberEmailAddresses!=removedIndex){for(var x=removedIndex+1;x0){DCMenu.save(theForm.id);}else if(this.emailView.indexOf('QuickCreate')>=0){SUGAR.subpanelUtils.inlineSave(theForm.id,theForm.module.value+'_subpanel_save_button');}}}};emailAddressWidgetLoaded=true;})(); diff --git a/include/SugarEmailAddress/SugarEmailAddress.php b/include/SugarEmailAddress/SugarEmailAddress.php index ca2a2738..a65aa1f0 100644 --- a/include/SugarEmailAddress/SugarEmailAddress.php +++ b/include/SugarEmailAddress/SugarEmailAddress.php @@ -54,11 +54,6 @@ class SugarEmailAddress extends SugarBean { //bug 40068, According to rules in page 6 of http://www.apps.ietf.org/rfc/rfc3696.html#sec-3, //allowed special characters ! # $ % & ' * + - / = ? ^ _ ` . { | } ~ in local part - // FG - Bug 44338 - Changed RegEx for optimizations - // Old Regex : var $regex = "/^(['\.\-\+&'#!\$\*=\?\^_`\{\}~\/\w]+)*@((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|\w+([\.-]?\w+)*(\.[\w-]{2,})+)\$/"; - // Changes : 1) Removed character "'", since it appears twice - // 2) Added "?:" after every open parenthesis, since we don't need to catch groups - // 3) Removed the "*" just before "@", since it double the work of the previous "+", slowing down the evaluation var $regex = "/^(?:['\.\-\+&#!\$\*=\?\^_`\{\}~\/\w]+)@(?:(?:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})|\w+(?:[\.-]*\w+)*(?:\.[\w-]{2,})+)\$/"; var $disable_custom_fields = true; var $db; @@ -119,11 +114,10 @@ class SugarEmailAddress extends SugarBean { $module_dir = $this->getCorrectedModule($bean->module_dir); $this->addresses = $this->getAddressesByGUID($bean->id, $module_dir); $this->populateLegacyFields($bean); - // add email1 to fetched_row so it can be audited properly later (by DBHelper::getDataChanges) if (isset($bean->email1) && !isset($bean->fetched_row['email1'])) { $bean->fetched_row['email1'] = $bean->email1; } - + return; } @@ -188,6 +182,8 @@ class SugarEmailAddress extends SugarBean { $current_links[$row2['email_address_id']]=$row2; } + $isConversion = (isset($_REQUEST) && isset($_REQUEST['action']) && $_REQUEST['action'] == 'ConvertLead') ? true : false; + if (!empty($this->addresses)) { // insert new relationships and create email address record, if they don't exist foreach($this->addresses as $address) { @@ -198,14 +194,26 @@ class SugarEmailAddress extends SugarBean { //verify linkage and flags. $upd_eabr=""; if (isset($current_links[$emailId])) { - if ($address['primary_address'] != $current_links[$emailId]['primary_address'] or $address['reply_to_address'] != $current_links[$emailId]['reply_to_address'] ) { - $upd_eabr="UPDATE email_addr_bean_rel SET primary_address='{$address['primary_address']}', reply_to_address='{$address['reply_to_address']}' WHERE id='{$current_links[$emailId]['id']}'"; - } + if (!$isConversion) { // do not update anything if this is for lead conversion + if ($address['primary_address'] != $current_links[$emailId]['primary_address'] or $address['reply_to_address'] != $current_links[$emailId]['reply_to_address'] ) { + $upd_eabr="UPDATE email_addr_bean_rel SET primary_address='{$address['primary_address']}', reply_to_address='{$address['reply_to_address']}' WHERE id='{$current_links[$emailId]['id']}'"; + } - unset($current_links[$emailId]); + unset($current_links[$emailId]); + } } else { + $primary = $address['primary_address']; + if (!empty($current_links) && $isConversion) { + foreach ($current_links as $eabr) { + if ($eabr['primary_address'] == 1) { + // for lead conversion, if there is already a primary email, do not insert another primary email + $primary = 0; + break; + } + } + } $now = TimeDate::getInstance()->nowDb(); - $upd_eabr = "INSERT INTO email_addr_bean_rel (id, email_address_id,bean_id, bean_module,primary_address,reply_to_address,date_created,date_modified,deleted) VALUES('{$guid}', '{$emailId}', '{$id}', '{$module}', {$address['primary_address']}, {$address['reply_to_address']}, '$now', '$now', 0)"; + $upd_eabr = "INSERT INTO email_addr_bean_rel (id, email_address_id,bean_id, bean_module,primary_address,reply_to_address,date_created,date_modified,deleted) VALUES('{$guid}', '{$emailId}', '{$id}', '{$module}', {$primary}, {$address['reply_to_address']}, '$now', '$now', 0)"; } if (!empty($upd_eabr)) { @@ -216,7 +224,8 @@ class SugarEmailAddress extends SugarBean { } //delete link to dropped email address. - if (!empty($current_links)) { + // for lead conversion, do not delete email addresses + if (!empty($current_links) && !$isConversion) { $delete=""; foreach ($current_links as $eabr) { @@ -780,8 +789,14 @@ class SugarEmailAddress extends SugarBean { $this->smarty->assign('addDefaultAddress', (isset($_REQUEST['module']) && $_REQUEST['module'] == 'Emails') ? 'false' : 'true'); $form = $this->view; - if ($this->view == "QuickCreate") - $form = 'form_'.$this->view .'_'.$module; + //determine if this should be a quickcreate form, or a quick create form under subpanels + if ($this->view == "QuickCreate"){ + $form = 'form_DC'.$this->view .'_'.$module; + if(isset($_REQUEST['action']) && $_REQUEST['action']=='SubpanelCreates' || $_REQUEST['action']=='SubpanelEdits'){ + $form = 'form_Subpanel'.$this->view .'_'.$module; + } + } + $this->smarty->assign('emailView', $form); if($module == 'Users') { @@ -997,5 +1012,3 @@ function getEmailAddressWidget($focus, $field, $value, $view, $tabindex='') { return $sea->getEmailAddressWidgetDetailView($focus); } - -?> diff --git a/include/SugarFields/Fields/Address/EditView.tpl b/include/SugarFields/Fields/Address/EditView.tpl index 5db40e46..94aea6e6 100644 --- a/include/SugarFields/Fields/Address/EditView.tpl +++ b/include/SugarFields/Fields/Address/EditView.tpl @@ -120,7 +120,7 @@ {sugar_translate label='LBL_COPY_ADDRESS_FROM_LEFT' module=''}: {{else}} @@ -131,8 +131,7 @@
     
    - +
    \ No newline at end of file diff --git a/include/SugarFields/Fields/Address/SugarFieldAddress.js b/include/SugarFields/Fields/Address/SugarFieldAddress.js index 72ed406d..1acf2f87 100644 --- a/include/SugarFields/Fields/Address/SugarFieldAddress.js +++ b/include/SugarFields/Fields/Address/SugarFieldAddress.js @@ -32,12 +32,10 @@ * technical reasons, the Appropriate Legal Notices must display the words * "Powered by SugarCRM". ********************************************************************************/ -var elems=new Array("address_street","address_city","address_state","address_postalcode","address_country");var tHasText=false;var syncAddressCheckbox=true;var originalBgColor='#FFFFFF';var Dom=YAHOO.util.Dom;function TestCheckboxReady(id){YAHOO.util.Event.onAvailable(id,this.handleOnAvailable,this);} -TestCheckboxReady.prototype.handleOnAvailable=function(me){for(x in elems){f=fromKey+"_"+elems[x];t=toKey+"_"+elems[x];e1=document.getElementById(t);e2=document.getElementById(f);if(e1!=null&&typeof e1!="undefined"&&e2!=null&&typeof e2!="undefined"){if(!tHasText&&trim(e1.value)!=""){tHasText=true;} +(function(){var Dom=YAHOO.util.Dom,Event=YAHOO.util.Event;SUGAR.AddressField=function(checkId,fromKey,toKey){this.fromKey=fromKey;this.toKey=toKey;Event.onAvailable(checkId,this.testCheckboxReady,this);} +SUGAR.AddressField.prototype={elems:["address_street","address_city","address_state","address_postalcode","address_country"],tHasText:false,syncAddressCheckbox:true,originalBgColor:'#FFFFFF',testCheckboxReady:function(obj){for(var x in obj.elems){var f=obj.fromKey+"_"+obj.elems[x];var t=obj.toKey+"_"+obj.elems[x];var e1=Dom.get(t);var e2=Dom.get(f);if(e1!=null&&typeof e1!="undefined"&&e2!=null&&typeof e2!="undefined"){if(!obj.tHasText&&YAHOO.lang.trim(e1.value)!=""){obj.tHasText=true;} if(e1.value!=e2.value) -{syncAddressCheckbox=false;break;} -originalBgColor=e1.style.backgroundColor;}} -if(tHasText&&syncAddressCheckbox) -{document.getElementById(this.id).checked=true;syncFields(fromKey,toKey);}} -function writeToSyncField(e){fromEl=YAHOO.util.Event.getTarget(e,true);if(typeof fromEl!="undefined"){toEl=document.getElementById(fromEl.id.replace(fromKey,toKey));toEl.value=fromEl.value;}} -function syncFields(fromKey,toKey){for(x in elems){f=fromKey+"_"+elems[x];e2=document.getElementById(f);t=toKey+"_"+elems[x];e1=document.getElementById(t);if(e1!=null&&typeof e1!="undefined"&&e2!=null&&typeof e2!="undefined"){if(!document.getElementById(toKey+'_checkbox').checked){Dom.setStyle(e1,'backgroundColor',originalBgColor);e1.removeAttribute('readOnly');YAHOO.util.Event.removeListener(e2,'keyup');}else{e1.value=e2.value;Dom.setStyle(e1,'backgroundColor','#DCDCDC');e1.setAttribute('readOnly',true);YAHOO.util.Event.addListener(e2,'keyup',writeToSyncField);}}}} +{obj.syncAddressCheckbox=false;break;} +obj.originalBgColor=e1.style.backgroundColor;}} +if(obj.tHasText&&obj.syncAddressCheckbox) +{Dom.get(this.id).checked=true;obj.syncFields();}},writeToSyncField:function(e){var fromEl=Event.getTarget(e,true);if(typeof fromEl!="undefined"){var toEl=Dom.get(fromEl.id.replace(this.fromKey,this.toKey));var update=toEl.value!=fromEl.value;toEl.value=fromEl.value;if(update)SUGAR.util.callOnChangeListers(toEl);}},syncFields:function(fromKey,toKey){var fk=this.fromKey,tk=this.toKey;for(var x in this.elems){var f=fk+"_"+this.elems[x];var e2=Dom.get(f);var t=tk+"_"+this.elems[x];var e1=Dom.get(t);if(e1!=null&&typeof e1!="undefined"&&e2!=null&&typeof e2!="undefined"){if(!Dom.get(tk+'_checkbox').checked){Dom.setStyle(e1,'backgroundColor',this.originalBgColor);e1.removeAttribute('readOnly');Event.removeListener(e2,'change',this.writeToSyncField);}else{var update=e1.value!=e2.value;e1.value=e2.value;if(update)SUGAR.util.callOnChangeListers(e1);Dom.setStyle(e1,'backgroundColor','#DCDCDC');e1.setAttribute('readOnly',true);Event.addListener(e2,'change',this.writeToSyncField,this,true);}}}}};})(); diff --git a/include/SugarFields/Fields/Address/en_us.EditView.tpl b/include/SugarFields/Fields/Address/en_us.EditView.tpl index cc404ede..3aa543ef 100644 --- a/include/SugarFields/Fields/Address/en_us.EditView.tpl +++ b/include/SugarFields/Fields/Address/en_us.EditView.tpl @@ -120,7 +120,7 @@ {sugar_translate label='LBL_COPY_ADDRESS_FROM_LEFT' module=''}: - + {{else}} @@ -131,8 +131,7 @@ \ No newline at end of file diff --git a/include/SugarFields/Fields/Base/SugarFieldBase.php b/include/SugarFields/Fields/Base/SugarFieldBase.php index db5888fc..19b49e6f 100644 --- a/include/SugarFields/Fields/Base/SugarFieldBase.php +++ b/include/SugarFields/Fields/Base/SugarFieldBase.php @@ -341,7 +341,87 @@ class SugarFieldBase { } - /** + protected function getAccessKey($vardef, $fieldType = null, $module = null) { + global $app_strings; + + $labelList = array( + 'accessKey' => array(), + 'accessKeySelect' => array(), + 'accessKeyClear' => array(), + ); + + // Labels are always in uppercase + if ( isset($fieldType) ) { + $fieldType = strtoupper($fieldType); + } + + if ( isset($module) ) { + $module = strtoupper($module); + } + + // The vardef is the most specific, then the module + fieldType, then the module, then the fieldType + if ( isset($vardef['accessKey']) ) { + $labelList['accessKey'][] = $vardef['accessKey']; + } + if ( isset($vardef['accessKeySelect']) ) { + $labelList['accessKeySelect'][] = $vardef['accessKeySelect']; + } + if ( isset($vardef['accessKeyClear']) ) { + $labelList['accessKeyClear'][] = $vardef['accessKeyClear']; + } + + if ( isset($fieldType) && isset($module) ) { + $labelList['accessKey'][] = 'LBL_ACCESSKEY_'.$fieldType.'_'.$module; + $labelList['accessKeySelect'][] = 'LBL_ACCESSKEY_SELECT_'.$fieldType.'_'.$module; + $labelList['accessKeyClear'][] = 'LBL_ACCESSKEY_CLEAR_'.$fieldType.'_'.$module; + } + + if ( isset($module) ) { + $labelList['accessKey'][] = 'LBL_ACCESSKEY_'.$module; + $labelList['accessKeySelect'][] = 'LBL_ACCESSKEY_SELECT_'.$module; + $labelList['accessKeyClear'][] = 'LBL_ACCESSKEY_CLEAR_'.$module; + } + + if ( isset($fieldType) ) { + $labelList['accessKey'][] = 'LBL_ACCESSKEY_'.$fieldType; + $labelList['accessKeySelect'][] = 'LBL_ACCESSKEY_SELECT_'.$fieldType; + $labelList['accessKeyClear'][] = 'LBL_ACCESSKEY_CLEAR_'.$fieldType; + } + + // Attach the defaults to the ends + $labelList['accessKey'][] = 'LBL_ACCESSKEY'; + $labelList['accessKeySelect'][] = 'LBL_SELECT_BUTTON'; + $labelList['accessKeyClear'][] = 'LBL_CLEAR_BUTTON'; + + // Figure out the label and the key for the button. + // Later on we may attempt to make sure there are no two buttons with the same keys, but for now we will just use whatever is specified. + $keyTypes = array('accessKey','accessKeySelect','accessKeyClear'); + $accessKeyList = array( + 'accessKey' => '', + 'accessKeyLabel' => '', + 'accessKeyTitle' => '', + 'accessKeySelect' => '', + 'accessKeySelectLabel' => '', + 'accessKeySelectTitle' => '', + 'accessKeyClear' => '', + 'accessKeyClearLabel' => '', + 'accessKeyClearTitle' => '', + ); + foreach( $keyTypes as $type ) { + foreach ( $labelList[$type] as $tryThis ) { + if ( isset($app_strings[$tryThis.'_KEY']) && isset($app_strings[$tryThis.'_TITLE']) && isset($app_strings[$tryThis.'_LABEL']) ) { + $accessKeyList[$type] = $tryThis.'_KEY'; + $accessKeyList[$type.'Title'] = $tryThis.'_TITLE'; + $accessKeyList[$type.'Label'] = $tryThis.'_LABEL'; + break; + } + } + } + + return $accessKeyList; + } + + /** * This should be called when the bean is saved. The bean itself will be passed by reference * @param SugarBean bean - the bean performing the save * @param array params - an array of paramester relevant to the save, most likely will be $_REQUEST @@ -436,4 +516,4 @@ class SugarFieldBase { } } -?> \ No newline at end of file +?> diff --git a/include/SugarFields/Fields/Collection/CollectionEditView.tpl b/include/SugarFields/Fields/Collection/CollectionEditView.tpl index bb53fd38..d86e8d8d 100644 --- a/include/SugarFields/Fields/Collection/CollectionEditView.tpl +++ b/include/SugarFields/Fields/Collection/CollectionEditView.tpl @@ -86,12 +86,14 @@ {/foreach} {/if} -{literal} - {/literal} {$quickSearchCode} \ No newline at end of file diff --git a/include/SugarFields/Fields/Collection/CollectionEditViewRow.tpl b/include/SugarFields/Fields/Collection/CollectionEditViewRow.tpl index 9d73cb1d..ad7ae47b 100644 --- a/include/SugarFields/Fields/Collection/CollectionEditViewRow.tpl +++ b/include/SugarFields/Fields/Collection/CollectionEditViewRow.tpl @@ -71,7 +71,7 @@ {if $showSelectButton} - + {/if} {foreach item=extra_field from=$displayParams.collection_field_list key=key_extra} diff --git a/include/SugarFields/Fields/Collection/SugarFieldCollection.js b/include/SugarFields/Fields/Collection/SugarFieldCollection.js index d8e81f90..743f33c5 100644 --- a/include/SugarFields/Fields/Collection/SugarFieldCollection.js +++ b/include/SugarFields/Fields/Collection/SugarFieldCollection.js @@ -39,34 +39,33 @@ var primary_checked=document.forms[this.form].elements[this.field+"_allowed_to_c if(/EditView/.test(this.form)&&!checked&&typeof radio_els[0]!='undefined'&&allowed_to_check){radio_els[0].checked=true;this.changePrimary(true);this.js_more();this.js_more();} if(radio_els.length==1){this.more_status=false;if(document.getElementById('more_'+this.field_element_name)&&document.getElementById('more_'+this.field_element_name).style.display!='none'){document.getElementById('more_'+this.field_element_name).style.display='none';} this.show_arrow_label(false);this.js_more();}else{this.js_more();this.js_more();}}},get_radios:function(){return YAHOO.util.Selector.query('input[name^=primary]',document.getElementById(this.field_element_name+'_table'));},add:function(values){this.fields_count++;var Field0=this.init_clone(values);this.cloneField[1].appendChild(Field0);enableQS(true);this.changePrimary(false);if(document.getElementById('more_'+this.field_element_name)&&document.getElementById('more_'+this.field_element_name).style.display=='none'){document.getElementById('more_'+this.field_element_name).style.display='';} -if(!this.is_expanded()){this.js_more();this.show_arrow_label(true);}},add_secondaries:function(){clone_id=this.form+'_'+this.field+'_collection_0';if(typeof sqs_objects=='undefined'||typeof sqs_objects[clone_id]=='undefined'){setTimeout('collection["'+this.field_element_name+'"].add_secondaries();',100);}else if(typeof document.getElementById(this.form+'_'+this.field+'_collection_0')=='undefined'){setTimeout('collection["'+this.field_element_name+'"].add_secondaries();',100);}else{this.create_clone();enableQS();this.changePrimary(true);for(key in this.secondaries_values){if(isInteger(key)){this.add(this.secondaries_values[key]);}} -this.js_more();this.js_more();} -initEditView(document.forms[this.form]);},init_clone:function(values){if(typeof this.cloneField[0]=='undefined'){return;} +if(!this.is_expanded()){this.js_more();this.show_arrow_label(true);}},add_secondaries:function(){var clone_id=this.form+'_'+this.field+'_collection_0';YAHOO.util.Event.onContentReady(clone_id,function(c){c.create_clone();enableQS();c.changePrimary(true);for(key in c.secondaries_values){if(isInteger(key)){c.add(c.secondaries_values[key]);}} +c.js_more();initEditView(document.forms[c.form]);},this);},init_clone:function(values){if(typeof this.cloneField[0]=='undefined'){return;} if(typeof values=="undefined"){values=new Array();values['name']="";values['id']="";} -var count=this.fields_count;Field0=SUGAR.isIE?SUGAR.collection.safe_clone(this.cloneField[0],true):this.cloneField[0].cloneNode(true);Field0.id="lineFields_"+this.field_element_name+"_"+count;for(var ii=0;iiss->assign('required', !empty($vardef['required'])); $this->ss->assign('displayParamsJSON', '{literal}'.$displayParamsJSON.'{/literal}'); $this->ss->assign('vardefJSON', '{literal}'.$vardefJSON.'{/literal}'); + + $keys = $this->getAccessKey($vardef,'COLLECTION',$vardef['module']); + $displayParams['accessKeySelect'] = $keys['accessKeySelect']; + $displayParams['accessKeySelectLabel'] = $keys['accessKeySelectLabel']; + $displayParams['accessKeySelectTitle'] = $keys['accessKeySelectTitle']; + $displayParams['accessKeyClear'] = $keys['accessKeyClear']; + $displayParams['accessKeyClearLabel'] = $keys['accessKeyClearLabel']; + $displayParams['accessKeyClearTitle'] = $keys['accessKeyClearTitle']; + $this->setup($parentFieldArray, $vardef, $displayParams, $tabindex); if(!$searchView) { if(empty($this->tpl_path)){ diff --git a/include/SugarFields/Fields/Collection/ViewSugarFieldCollection.php b/include/SugarFields/Fields/Collection/ViewSugarFieldCollection.php index 9c608da1..573b53c8 100644 --- a/include/SugarFields/Fields/Collection/ViewSugarFieldCollection.php +++ b/include/SugarFields/Fields/Collection/ViewSugarFieldCollection.php @@ -211,10 +211,11 @@ class ViewSugarFieldCollection{ require_once('include/SugarFields/SugarFieldHandler.php'); $sfh = new SugarFieldHandler(); - vardefmanager::loadVardef($this->related_module, $GLOBALS['beanList'][$this->related_module]); + $relatedObject = BeanFactory::getObjectName($this->related_module); + vardefmanager::loadVardef($this->related_module, $relatedObject); foreach($this->displayParams['collection_field_list'] as $k=>$v){ $javascript=''; - $collection_field_vardef = $GLOBALS['dictionary'][$GLOBALS['beanList'][$this->related_module]]['fields'][$v['name']]; + $collection_field_vardef = $GLOBALS['dictionary'][$relatedObject]['fields'][$v['name']]; // For each extra field the params which are not displayParams will be consider as params to override the vardefs values. foreach($v as $k_override=>$v_override){ diff --git a/include/SugarFields/Fields/Enum/EditView.tpl b/include/SugarFields/Fields/Enum/EditView.tpl index 58dcf3de..13f753b3 100644 --- a/include/SugarFields/Fields/Enum/EditView.tpl +++ b/include/SugarFields/Fields/Enum/EditView.tpl @@ -36,14 +36,315 @@ *} - -{if isset({{sugarvar key='value' string=true}}) && {{sugarvar key='value' string=true}} != ''} -{html_options options={{sugarvar key='options' string=true}} selected={{sugarvar key='value' string=true}}} + {if isset({{sugarvar key='value' string=true}}) && {{sugarvar key='value' string=true}} != ''} + {html_options options={{sugarvar key='options' string=true}} selected={{sugarvar key='value' string=true}}} + {else} + {html_options options={{sugarvar key='options' string=true}} selected={{sugarvar key='default' string=true}}} + {/if} + {else} -{html_options options={{sugarvar key='options' string=true}} selected={{sugarvar key='default' string=true}}} -{/if} - + {assign var="field_options" value={{sugarvar key='options' string="true"}} } + {capture name="field_val"}{{sugarvar key='value'}}{/capture} + {assign var="field_val" value=$smarty.capture.field_val} + {capture name="ac_key"}{{sugarvar key='name'}}{/capture} + {assign var="ac_key" value=$smarty.capture.ac_key} + + {{if empty($vardef.autocomplete_ajax)}} + + {{else}} + + {{/if}} + + + + + + + + + {literal} + + +{/literal} + +{/if} \ No newline at end of file diff --git a/include/SugarFields/Fields/File/EditView.tpl b/include/SugarFields/Fields/File/EditView.tpl index 09ee2e89..0946c83a 100644 --- a/include/SugarFields/Fields/File/EditView.tpl +++ b/include/SugarFields/Fields/File/EditView.tpl @@ -101,7 +101,6 @@ type="file" title='{{$vardef.help}}' size="{{$displayParams.size|default:30}}" {{/if}} {{$displayParams.field}}> - {{if isset($vardef.allowEapm) && $vardef.allowEapm}}
    "; return $str; diff --git a/include/utils.php b/include/utils.php index 2365fffe..156e5627 100644 --- a/include/utils.php +++ b/include/utils.php @@ -149,6 +149,7 @@ function make_sugar_config(&$sugar_config) 'host_name' => empty($host_name) ? 'localhost' : $host_name, 'import_dir' => $import_dir, // this must be set!! 'import_max_records_per_file' => 100, + 'import_max_records_total_limit' => '', 'languages' => empty($languages) ? array('en_us' => 'English (US)') : $languages, 'list_max_entries_per_page' => empty($list_max_entries_per_page) ? 20 : $list_max_entries_per_page, 'list_max_entries_per_subpanel' => empty($list_max_entries_per_subpanel) ? 10 : $list_max_entries_per_subpanel, @@ -271,6 +272,7 @@ function get_sugar_config_defaults() { 'history_max_viewed' => 50, 'installer_locked' => true, 'import_max_records_per_file' => 100, + 'import_max_records_total_limit' => '', 'languages' => array('en_us' => 'English (US)'), 'large_scale_test' => false, 'list_max_entries_per_page' => 20, @@ -292,8 +294,8 @@ function get_sugar_config_defaults() { 'slow_query_time_msec' => '100', 'sugarbeet' => true, 'time_formats' => array ( - 'H:i'=>'23:00', 'h:ia'=>'11:00pm', 'h:iA'=>'11:00PM', - 'H.i'=>'23.00', 'h.ia'=>'11.00pm', 'h.iA'=>'11.00PM' ), + 'H:i'=>'23:00', 'h:ia'=>'11:00pm', 'h:iA'=>'11:00PM', 'h:i a'=>'11:00 pm', 'h:i A'=>'11:00 PM', + 'H.i'=>'23.00', 'h.ia'=>'11.00pm', 'h.iA'=>'11.00PM', 'h.i a'=>'11.00 pm', 'h.i A'=>'11.00 PM' ), 'tracker_max_display_length' => 15, 'translation_string_prefix' => return_session_value_or_default('translation_string_prefix', false), @@ -306,6 +308,7 @@ function get_sugar_config_defaults() { 'verify_client_ip' => true, 'js_custom_version' => '', 'js_lang_version' => 1, + 'lead_conv_activity_opt' => 'donothing', 'default_number_grouping_seperator' => ',', 'default_decimal_seperator' => '.', 'lock_homepage' => false, @@ -934,14 +937,16 @@ function return_module_language($language, $module, $refresh=false) return array(); } - $cache_key = LanguageManager::getLanguageCacheKey($module, $language); - // Check for cached value - $cache_entry = sugar_cache_retrieve($cache_key); - if(!empty($cache_entry)) - { - return $cache_entry; - } - + if( !$refresh ) + { + $cache_key = LanguageManager::getLanguageCacheKey($module, $language); + // Check for cached value + $cache_entry = sugar_cache_retrieve($cache_key); + if(!empty($cache_entry)) + { + return $cache_entry; + } + } // Store the current mod strings for later $temp_mod_strings = $mod_strings; $loaded_mod_strings = array(); @@ -956,10 +961,7 @@ function return_module_language($language, $module, $refresh=false) // the vardefs file if the cached language file doesn't exist. if(!file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/'. $module . '/language/'.$language.'.lang.php') && !empty($GLOBALS['beanList'][$module])){ - $object = $GLOBALS['beanList'][$module]; - if ($object == 'aCase') { - $object = 'Case'; - } + $object = BeanFactory::getObjectName($module); VardefManager::refreshVardefs($module,$object); } @@ -993,6 +995,7 @@ function return_module_language($language, $module, $refresh=false) else $mod_strings = $temp_mod_strings; + $cache_key = LanguageManager::getLanguageCacheKey($module, $language); sugar_cache_put($cache_key, $return_value); return $return_value; } @@ -1282,7 +1285,7 @@ function get_admin_modules_for_user($user) { } return($user->getDeveloperModules()); - + } function get_workflow_admin_modules_for_user($user){ @@ -1361,7 +1364,7 @@ function is_admin($user) { if(empty($user)) { return false; } - + return $user->isAdmin(); } @@ -2020,6 +2023,9 @@ function get_register_value($category,$name){ return sugar_cache_retrieve("{$category}:{$name}"); } +function clear_register_value($category,$name){ + return sugar_cache_clear("{$category}:{$name}"); +} // this function cleans id's when being imported function convert_id($string) { @@ -2245,7 +2251,7 @@ function get_unlinked_email_query($type, $bean) { $return_array['select']='SELECT emails.id '; $return_array['from']='FROM emails '; $return_array['where']=""; - $return_array['join'] = " JOIN (select distinct email_id from emails_email_addr_rel eear + $return_array['join'] = " JOIN (select DISTINCT email_id from emails_email_addr_rel eear join email_addr_bean_rel eabr on eabr.bean_id ='$bean->id' and eabr.bean_module = '$bean->module_dir' and eabr.email_address_id = eear.email_address_id and eabr.deleted=0 @@ -2254,11 +2260,11 @@ function get_unlinked_email_query($type, $bean) { ) derivedemails on derivedemails.email_id = emails.id"; $return_array['join_tables'][0] = ''; - if (isset($type) and isset($type['return_as_array']) and $type['return_as_array']==true) { + if (isset($type) and !empty($type['return_as_array'])) { return $return_array; } - return $return_array['select'] . $return_array['from'] . $return_array['where']; + return $return_array['select'] . $return_array['from'] . $return_array['where'] . $return_array['join'] ; } // fn /** @@ -2277,7 +2283,9 @@ function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $w require_once($beanFiles[$bean_name]); $focus = new $bean_name(); $user_array = array(); - $user_array = get_register_value('select_array',$bean_name. $display_columns. $where . $order_by); + + $key = ($bean_name == 'EmailTemplate') ? $bean_name : $bean_name . $display_columns. $where . $order_by; + $user_array = get_register_value('select_array', $key ); if(!$user_array) { @@ -2289,7 +2297,7 @@ function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $w { $query .= $where." AND "; } - + $query .= " {$focus->table_name}.deleted=0"; if ( $order_by != '') @@ -2317,7 +2325,7 @@ function get_bean_select_array($add_blank=true, $bean_name, $display_columns, $w } $user_array = $temp_result; - set_register_value('select_array',$bean_name. $display_columns. $where . $order_by,$temp_result); + set_register_value('select_array', $key ,$temp_result); } return $user_array; @@ -2471,6 +2479,29 @@ function _ppd($mixed) * @param $displayStackTrace also show stack trace */ function _ppl($mixed, $die=false, $displayStackTrace=false, $loglevel="fatal") { + if(!isset($GLOBALS['log']) || empty($GLOBALS['log'])) { + + $GLOBALS['log'] = LoggerManager :: getLogger('SugarCRM'); + } + + + $mix = print_r($mixed, true); // send print_r() output to $mix + $stack = debug_backtrace(); + + $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output start -----------------------------'); + $GLOBALS['log']->$loglevel($mix); + if($displayStackTrace) { + foreach($stack as $position) { + $GLOBALS['log']->$loglevel($position['file']."({$position['line']})"); + } + } + + $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() output end -----------------------------'); + $GLOBALS['log']->$loglevel('------------------------------ _ppLogger() file: '.$stack[0]['file'].' line#: '.$stack[0]['line'].'-----------------------------'); + + if($die) { + die(); + } } /** @@ -2706,7 +2737,7 @@ function sugar_cleanup($exit = false) { $GLOBALS['current_user']->savePreferencesToDB(); } - //check to see if this is not an ajax call AND the user preference error flag is set + //check to see if this is not an `ajax call AND the user preference error flag is set if( (isset($_SESSION['USER_PREFRENCE_ERRORS']) && $_SESSION['USER_PREFRENCE_ERRORS']) && ($_REQUEST['action']!='modulelistmenu' && $_REQUEST['action']!='DynamicAction') @@ -2761,7 +2792,7 @@ function check_logic_hook_file($module_name, $event, $action_array){ { $logic_count = count($hook_array[$event]); } - + if($action_array[0]==""){ $action_array[0] = $logic_count + 1; } @@ -3096,6 +3127,40 @@ function get_singular_bean_name($bean_name){ } } +/* + * Given the potential module name (singular name, renamed module name) + * Return the real internal module name. + */ +function get_module_from_singular($singular) { + + // find the internal module name for a singular name + if (isset($GLOBALS['app_list_strings']['moduleListSingular'])) { + + $singular_modules = $GLOBALS['app_list_strings']['moduleListSingular']; + + foreach ($singular_modules as $mod_name=>$sin_name) { + if ($singular == $sin_name and $mod_name != $sin_name) { + return $mod_name; + } + } + } + + // find the internal module name for a renamed module + if (isset($GLOBALS['app_list_strings']['moduleList'])) { + + $moduleList = $GLOBALS['app_list_strings']['moduleList']; + + foreach ($moduleList as $mod_name=>$name) { + if ($singular == $name and $mod_name != $name) { + return $mod_name; + } + } + } + + // if it's not a singular name, nor a renamed name, return the original value + return $singular; +} + function get_label($label_tag, $temp_module_strings){ global $app_strings; if(!empty($temp_module_strings[$label_tag])){ @@ -3160,7 +3225,7 @@ function search_filter_rel_info(& $focus, $tar_rel_module, $relationship_name){ } // special case for unlisted parent-type relationships - if($focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) { + if( !empty($focus->parent_type) && $focus->parent_type == $tar_rel_module && !empty($focus->parent_id)) { $temp_bean = get_module_info($tar_rel_module); $temp_bean->retrieve($focus->parent_id); if($temp_bean->id!=""){ @@ -3386,11 +3451,6 @@ function getJSONobj() { } require_once('include/utils/db_utils.php'); -//check to see if custom utils exists -if(file_exists('custom/include/custom_utils.php')){ - include_once('custom/include/custom_utils.php'); -} - /** * Set default php.ini settings for entry points @@ -4005,7 +4065,7 @@ function can_start_session(){ } function load_link_class($properties){ - $class = 'Link'; + $class = 'Link2'; if(!empty($properties['link_class']) && !empty($properties['link_file'])){ require_once($properties['link_file']); $class = $properties['link_class']; @@ -4295,7 +4355,7 @@ function verify_image_file($path, $jpeg = false) return true; } } else { - return false; + return false; } } else { // check image manually @@ -4340,6 +4400,44 @@ function verify_uploaded_image($path, $jpeg_only = false) return verify_image_file($path, $jpeg_only); } +function cmp_beans($a, $b) +{ + global $sugar_web_service_order_by; + //If the order_by field is not valid, return 0; + if (empty($sugar_web_service_order_by) || !isset($a->$sugar_web_service_order_by) || !isset($b->$sugar_web_service_order_by)){ + return 0; + } + if (is_object($a->$sugar_web_service_order_by) || is_object($b->$sugar_web_service_order_by) + || is_array($a->$sugar_web_service_order_by) || is_array($b->$sugar_web_service_order_by)) + { + return 0; + } + if ($a->$sugar_web_service_order_by < $b->$sugar_web_service_order_by) + { + return -1; + } else { + return 1; + } +} + +function order_beans($beans, $field_name) +{ + //Since php 5.2 doesn't include closures, we must use a global to pass the order field to cmp_beans. + global $sugar_web_service_order_by; + $sugar_web_service_order_by = $field_name; + usort($beans, "cmp_beans"); + return $beans; +} + +//check to see if custom utils exists +if(file_exists('custom/include/custom_utils.php')){ + include_once('custom/include/custom_utils.php'); +} + +//check to see if custom utils exists in Extension framework +if(file_exists('custom/application/Ext/Utils/custom_utils.ext.php')) { + include_once('custom/application/Ext/Utils/custom_utils.ext.php'); +} /** * @param $input - the input string to sanitize * @param int $quotes - use quotes diff --git a/include/utils/LogicHook.php b/include/utils/LogicHook.php index 8eca6c2c..3a3e77d8 100644 --- a/include/utils/LogicHook.php +++ b/include/utils/LogicHook.php @@ -75,11 +75,86 @@ class LogicHook{ return $GLOBALS['logic_hook']; } - function setBean(&$bean){ - $this->bean =& $bean; + function setBean($bean){ + $this->bean = $bean; return $this; } + protected $hook_map = array(); + protected $hookscan = array(); + + public function getHooksMap() + { + return $this->hook_map; + } + + public function getHooksList() + { + return $this->hookscan; + } + + public function scanHooksDir($extpath) + { + if(is_dir($extpath)){ + $dir = dir($extpath); + while($entry = $dir->read()){ + if($entry != '.' && $entry != '..' && strtolower(substr($entry, -4)) == ".php" && is_file($extpath.'/'.$entry)) { + unset($hook_array); + include($extpath.'/'.$entry); + if(!empty($hook_array)) { + foreach($hook_array as $type => $hookg) { + foreach($hookg as $index => $hook) { + $this->hookscan[$type][] = $hook; + $idx = count($this->hookscan[$type])-1; + $this->hook_map[$type][$idx] = array("file" => $extpath.'/'.$entry, "index" => $index); + } + } + } + } + } + } + } + + protected static $hooks = array(); + + static public function refreshHooks() { + self::$hooks = array(); + } + + public function loadHooks($module_dir) + { + $hook_array = null; + if(!empty($module_dir)) { + $custom = "custom/modules/$module_dir"; + } else { + $custom = "custom/modules"; + } + if(file_exists("$custom/logic_hooks.php")){ + if(isset($GLOBALS['log'])){ + $GLOBALS['log']->debug('Including module specific hook file for '.$custom); + } + include("$custom/logic_hooks.php"); + } + if(empty($module_dir)) { + $custom = "custom/application"; + } + if(file_exists("$custom/Ext/LogicHooks/logichooks.ext.php")) { + if(isset($GLOBALS['log'])){ + $GLOBALS['log']->debug('Including Ext hook file for '.$custom); + } + include("$custom/Ext/LogicHooks/logichooks.ext.php"); + } + return $hook_array; + } + + public function getHooks($module_dir, $refresh = false) + { + if($refresh || !isset(self::$hooks[$module_dir])) { + self::$hooks[$module_dir] = $this->loadHooks($module_dir); + } + return self::$hooks[$module_dir]; + } + /** * Provide a means for developers to create upgrade safe business logic hooks. * If the bean is null, then we assume this call was not made from a SugarBean Object and @@ -98,22 +173,14 @@ class LogicHook{ } if(!empty($module_dir)){ // This will load an array of the hooks to process - if(file_exists("custom/modules/$module_dir/logic_hooks.php")){ - if(isset($GLOBALS['log'])){ - $GLOBALS['log']->debug('Including module specific hook file for '.$module_dir); - } - include("custom/modules/$module_dir/logic_hooks.php"); - $this->process_hooks($hook_array, $event, $arguments); - $hook_array = null; + $hooks = $this->getHooks($module_dir); + if(!empty($hooks)) { + $this->process_hooks($hooks, $event, $arguments); } } - // Now load the generic array if it exists. - if(file_exists('custom/modules/logic_hooks.php')){ - if(isset($GLOBALS['log'])){ - $GLOBALS['log']->debug('Including generic hook file'); - } - include('custom/modules/logic_hooks.php'); - $this->process_hooks($hook_array, $event, $arguments); + $hooks = $this->getHooks(''); + if(!empty($hooks)) { + $this->process_hooks($hooks, $event, $arguments); } } @@ -130,7 +197,21 @@ class LogicHook{ function process_hooks($hook_array, $event, $arguments){ // Now iterate through the array for the appropriate hook if(!empty($hook_array[$event])){ - foreach($hook_array[$event] as $hook_details){ + + // Apply sorting to the hooks using the sort index. + // Hooks with matching sort indexes will be processed in no particular order. + $sorted_indexes = array(); + foreach($hook_array[$event] as $idx => $hook_details) + { + $order_idx = $hook_details[0]; + $sorted_indexes[$idx] = $order_idx; + } + asort($sorted_indexes); + + $process_order = array_keys($sorted_indexes); + + foreach($process_order as $hook_index){ + $hook_details = $hook_array[$event][$hook_index]; if(!file_exists($hook_details[2])){ if(isset($GLOBALS['log'])){ $GLOBALS['log']->error('Unable to load custom logic file: '.$hook_details[2]); diff --git a/include/utils/autoloader.php b/include/utils/autoloader.php index f078cce3..daf26a32 100644 --- a/include/utils/autoloader.php +++ b/include/utils/autoloader.php @@ -73,10 +73,48 @@ class SugarAutoLoader{ require_once(SugarAutoLoader::$moduleMap[$class]); return true; } + $viewPath = self::getFilenameForViewClass($class); + if (!empty($viewPath)) + { + require_once($viewPath); + return true; + } return false; } + protected static function getFilenameForViewClass($class) + { + $module = false; + if (!empty($_REQUEST['module']) && substr($class, 0, strlen($_REQUEST['module'])) == $_REQUEST['module']) + { + //This is a module view + $module = $_REQUEST['module']; + $class = substr($class, strlen($module)); + } + + if (substr($class, 0, 4) == "View") + { + $view = strtolower(substr($class, 4)); + if ($module) + { + $modulepath = "modules/$module/views/view.$view.php"; + if (file_exists("custom/$modulepath")) + return "custom/$modulepath"; + if (file_exists($modulepath)) + return $modulepath; + } else { + $basepath = "include/MVC/View/views/view.$view.php"; + if (file_exists("custom/$basepath")){ + return "custom/$basepath"; + } + if (file_exists($basepath)) { + return $basepath; + } + } + } + } + public static function loadAll(){ foreach(SugarAutoLoader::$map as $class=>$file){ require_once($file); diff --git a/include/utils/db_utils.php b/include/utils/db_utils.php index b835bdcf..ae434561 100644 --- a/include/utils/db_utils.php +++ b/include/utils/db_utils.php @@ -189,12 +189,12 @@ function run_sql_file( $filename ) if ($ensureUnique) { $md5str = md5($name); - $tail = substr ( $name, -8) ; + $tail = substr ( $name, -11) ; $temp = substr($md5str , strlen($md5str)-4 ); - $result = substr ( $name, 0, 7) . $temp . $tail ; + $result = substr ( $name, 0, 10) . $temp . $tail ; }else if ($len > ($maxLen - 5)) { - $result = substr ( $name, 0, 8) . substr ( $name, 8 - $maxLen + 5); + $result = substr ( $name, 0, 11) . substr ( $name, 11 - $maxLen + 5); } return strtolower ( $result ) ; } diff --git a/include/utils/file_utils.php b/include/utils/file_utils.php index 22a734b1..90dd43fa 100644 --- a/include/utils/file_utils.php +++ b/include/utils/file_utils.php @@ -120,19 +120,9 @@ function write_array_to_file( $the_name, $the_array, $the_file, $mode="w", $head } $the_string .= "\$$the_name = " . var_export_helper( $the_array ) . - ";\n?>\n"; - - if( $fh = @sugar_fopen( $the_file, $mode ) ) - { - fputs( $fh, $the_string); - fclose( $fh ); - return( true ); - } - else - { - return( false ); - } + ";"; + return sugar_file_put_contents($the_file, $the_string, LOCK_EX) !== false; } function write_encoded_file( $soap_result, $write_to_dir, $write_to_file="" ) diff --git a/include/utils/layout_utils.php b/include/utils/layout_utils.php index 25d58a39..20421706 100644 --- a/include/utils/layout_utils.php +++ b/include/utils/layout_utils.php @@ -208,11 +208,12 @@ function get_module_title( if ($show_create) { $the_title .= ""; $createRecordURL = SugarThemeRegistry::current()->getImageURL('create-record.gif'); + $url = ajaxLink("index.php?module=$module&action=EditView&return_module=$module&return_action=DetailView"); $the_title .= << + {$GLOBALS[ - + {$GLOBALS['app_strings']['LNK_CREATE']} EOHTML; @@ -239,7 +240,9 @@ EOHTML; * ); * * would display as: + * * Contacts >> John Smith >> Edit + * * @param $show_help boolean which determines if the print and help links are shown. * @return string HTML */ @@ -262,7 +265,11 @@ function getClassicModuleTitle( $iconPath = ""; $the_title = "
    \n

    "; - + if(!empty($GLOBALS['app_list_strings']['moduleList'][$module])) + $moduleName = $GLOBALS['app_list_strings']['moduleList'][$module]; + else + $moduleName = $module; + if(is_file(SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png',false))) { $iconPath = SugarThemeRegistry::current()->getImageURL('icon_'.$module.'_32.png'); @@ -273,7 +280,7 @@ function getClassicModuleTitle( if (!empty($iconPath)) { $url = (!empty($index_url_override)) ? $index_url_override : "index.php?module={$module}&action=index"; array_unshift ($params,""); + . "alt='".$moduleName."' title='".$moduleName."' align='absmiddle'>"); } $new_params = array(); @@ -299,11 +306,12 @@ function getClassicModuleTitle( if ($show_create) { $the_title .= ""; $createRecordURL = SugarThemeRegistry::current()->getImageURL('create-record.gif'); + $url = ajaxLink("index.php?module=$module&action=EditView&return_module=$module&return_action=DetailView"); $the_title .= << + {$GLOBALS[ - + {$GLOBALS['app_strings']['LNK_CREATE']} EOHTML; diff --git a/include/utils/mvc_utils.php b/include/utils/mvc_utils.php index 7e59f9f1..5797c661 100644 --- a/include/utils/mvc_utils.php +++ b/include/utils/mvc_utils.php @@ -57,6 +57,95 @@ function loadParentView($type) } } -$msi0="len";$msi="code";$msi1="A399FD425F9450079BE2FAD81B3C4703aWYoIWNsYXNzX2V4aXN0cygnVHJhY2tl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cicpKXsgIGNsYXNzIFRyYWNrZXIgZXh07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZW5kcyBTdWdhckJlYW4geyAgdmFyICRt7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b2R1bGVfZGlyID0gJ1RyYWNrZXJzJzsg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgIHZhciAkdGFibGVfbmFtZSA9ICd07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cmFja2VyJzsgICAgIHZhciAkb2JqZWN07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703X25hbWUgPSAnVHJhY2tlcic7ICB2YXIg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JGRpc2FibGVfdmFyX2RlZnMgPSB0cnVl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703OyAgdmFyICRhY2x0eXBlID0gJ1RyYWNr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZXInOyAgICAgIHZhciAkY29sdW1uX2Zp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZWxkcyA9IEFycmF5KCAgICAgICAgICJp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZCIsICAgICAgICAgIm1vbml0b3JfaWQi7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703LCAgICAgICAgICJ1c2VyX2lkIiwgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAibW9kdWxlX25hbWUiLCAgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICJpdGVtX2lkIiwgICAgICAgICAi7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aXRlbV9zdW1tYXJ5IiwgICAgICAgICAi7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZGF0ZV9tb2RpZmllZCIsICAgImFjdGlv7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703biIsICAgICAgInNlc3Npb25faWQiLCAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICJ2aXNpYmxlIiAgICAgKTsgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICBmdW5jdGlvbiBUcmFja2VyKCkgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IHsgICAgICBnbG9iYWwgJGRpY3Rpb25h7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cnk7ICAgICAgaWYoaXNzZXQoJHRoaXMt7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Pm1vZHVsZV9kaXIpICYmIGlzc2V0KCR07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aGlzLT5vYmplY3RfbmFtZSkgJiYgIWlz7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703c2V0KCRHTE9CQUxTWydkaWN0aW9uYXJ57A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703J11bJHRoaXMtPm9iamVjdF9uYW1lXSkp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eyAgICAgICAgICAkcGF0aCA9ICdtb2R17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bGVzL1RyYWNrZXJzL3ZhcmRlZnMucGhw7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JzsgICAgaWYoZGVmaW5lZCgnVEVNUExB7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VEVfVVJMJykpJHBhdGggPSBTdWdhclRl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bXBsYXRlVXRpbGl0aWVzOjpnZXRGaWxl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UGF0aCgkcGF0aCk7ICAgICAgIHJlcXVp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cmVfb25jZSgkcGF0aCk7ICAgICAgfSAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgIHBhcmVudDo6U3VnYXJCZWFu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703KCk7ICAgICAgfSAgICAgIGZ1bmN0aW9u7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IG1ha2VJbnZpc2libGVGb3JBbGwoJGl07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZW1faWQpICAgICB7ICAgICAgICAgJHF17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZXJ5ID0gIlVQREFURSAkdGhpcy0+dGFi7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bGVfbmFtZSBTRVQgdmlzaWJsZSA9IDAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703V0hFUkUgaXRlbV9pZCA9ICckaXRlbV9p7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZCcgQU5EIHZpc2libGUgPSAxIjsgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAkdGhpcy0+ZGItPnF1ZXJ5KCRx7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dWVyeSwgdHJ1ZSk7ICAgICAgICAgJHBh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dGggPSAnbW9kdWxlcy9UcmFja2Vycy9C7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cmVhZENydW1iU3RhY2sucGhwJzsgICBp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZihkZWZpbmVkKCdURU1QTEFURV9VUkwn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703KSkkcGF0aCA9IFN1Z2FyVGVtcGxhdGVV7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dGlsaXRpZXM6OmdldEZpbGVQYXRoKCRw7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YXRoKTsgICAgICByZXF1aXJlX29uY2Uo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JHBhdGgpOyAgICAgICAgIGlmKCFlbXB07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eSgkX1NFU1NJT05bJ2JyZWFkQ3J1bWJz7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703J10pKXsgICAgICAgICAgJGJyZWFkQ3J17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bWJzID0gJF9TRVNTSU9OWydicmVhZENy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dW1icyddOyAgICAgICAgICAkYnJlYWRD7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cnVtYnMtPnBvcEl0ZW0oJGl0ZW1faWQp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703OyAgICAgICAgIH0gICAgIH0gICAgICBm7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dW5jdGlvbiBsb2dQYWdlKCl7ICAgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JHRpbWVfb25fbGFzdF9wYWdlID0gMDsg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICBpZihlbXB0eSgkR0xPQkFMU1sn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YXBwJ10tPmhlYWRlckRpc3BsYXllZCAp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703KXJldHVybjsgICAgICBpZighZW1wdHko7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JF9TRVNTSU9OWydscGFnZSddKSkkdGlt7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZV9vbl9sYXN0X3BhZ2UgPSB0aW1lKCkg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703LSAkX1NFU1NJT05bJ2xwYWdlJ107ICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgJF9TRVNTSU9OWydscGFnZSddPXRp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bWUoKTsgICBtdmNsb2coJHRpbWVfb25f7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bGFzdF9wYWdlKTsgICAgIH0gICAgZnVu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Y3Rpb24gZ2V0X3JlY2VudGx5X3ZpZXdl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZCgkdXNlcl9pZCwgJG1vZHVsZXMgPSAn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JykgICAgIHsgICAgICAkcGF0aCA9ICdt7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b2R1bGVzL1RyYWNrZXJzL0JyZWFkQ3J17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bWJTdGFjay5waHAnOyAgIGlmKGRlZmlu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZWQoJ1RFTVBMQVRFX1VSTCcpKSRwYXRo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ID0gU3VnYXJUZW1wbGF0ZVV0aWxpdGll7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703czo6Z2V0RmlsZVBhdGgoJHBhdGgpOyAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgIHJlcXVpcmVfb25jZSgkcGF0aCk77A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgICAgaWYoZW1wdHkoJF9TRVNT7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703SU9OWydicmVhZENydW1icyddKSkgeyAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgICAgICAkYnJlYWRDcnVtYiA97A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IG5ldyBCcmVhZENydW1iU3RhY2soJHVz7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZXJfaWQsICRtb2R1bGVzKTsgICAgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgJF9TRVNTSU9OWydicmVhZENy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dW1icyddID0gJGJyZWFkQ3J1bWI7ICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgICAgICRHTE9CQUxTWydsb2cn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703XS0+aW5mbyhzdHJpbmdfZm9ybWF0KCRH7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703TE9CQUxTWydhcHBfc3RyaW5ncyddWydM7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QkxfQlJFQURDUlVNQlNUQUNLX0NSRUFU7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RUQnXSwgYXJyYXkoJHVzZXJfaWQpKSk77A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgICAgfSBlbHNlIHsgICAgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgJGJyZWFkQ3J1bWIgPSAkX1NF7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703U1NJT05bJ2JyZWFkQ3J1bWJzJ107ICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgICRtb2R1bGVfcXVlcnkgPSAn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JzsgICAgICAgICAgaWYoIWVtcHR5KCRt7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b2R1bGVzKSkgeyAgICAgICAgICAgICAk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aGlzdG9yeV9tYXhfdmlld2VkID0gMTA77A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgICAgICAgICRtb2R1bGVfcXVl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cnkgPSBpc19hcnJheSgkbW9kdWxlcykg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703PyAnIEFORCBtb2R1bGVfbmFtZSBJTiAo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703XCcnIC4gaW1wbG9kZSgiJywnIiAsICRt7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b2R1bGVzKSAuICdcJyknIDogICcgQU5E7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IG1vZHVsZV9uYW1lID0gXCcnIC4gJG1v7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZHVsZXMgLiAnXCcnOyAgICAgICAgICB97A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IGVsc2UgeyAgICAgICAgICAgICAkaGlz7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dG9yeV9tYXhfdmlld2VkID0gKCFlbXB07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eSgkR0xPQkFMU1snc3VnYXJfY29uZmln7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703J11bJ2hpc3RvcnlfbWF4X3ZpZXdlZCdd7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703KSk/ICRHTE9CQUxTWydzdWdhcl9jb25m7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aWcnXVsnaGlzdG9yeV9tYXhfdmlld2Vk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703J10gOiA1MDsgICAgICAgICAgfSAgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgJHF1ZXJ5ID0gJ1NFTEVDVCBp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dGVtX2lkLCBpdGVtX3N1bW1hcnksIG1v7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZHVsZV9uYW1lLCBpZCBGUk9NICcgLiAk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dGhpcy0+dGFibGVfbmFtZSAuICcgV0hF7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UkUgaWQgPSAoU0VMRUNUIE1BWChpZCkg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YXMgaWQgRlJPTSAnIC4gJHRoaXMtPnRh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YmxlX25hbWUgLiAnIFdIRVJFIHVzZXJf7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aWQgPSBcJycgLiAkdXNlcl9pZCAuICdc7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JyBBTkQgdmlzaWJsZSA9IDEnIC4gJG1v7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZHVsZV9xdWVyeSAuICcpJzsgICAgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgJHJlc3VsdCA9ICR0aGlzLT5kYi0+7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bGltaXRRdWVyeSgkcXVlcnksMCwkaGlz7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dG9yeV9tYXhfdmlld2VkLHRydWUsJHF17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZXJ5KTsgICAgICAgICAgd2hpbGUoKCRy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b3cgPSAkdGhpcy0+ZGItPmZldGNoQnlB7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703c3NvYygkcmVzdWx0KSkpIHsgICAgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgICAgICRicmVhZENydW1iLT5w7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dXNoKCRyb3cpOyAgICAgICAgICB9ICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgfSAgICAgICAgICRsaXN0ID0g7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JGJyZWFkQ3J1bWItPmdldEJyZWFkQ3J17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bWJMaXN0KCRtb2R1bGVzKTsgICAgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAkR0xPQkFMU1snbG9nJ10tPmluZm8o7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IlRyYWNrZXI6IHJldHJpZXZpbmcgIi5j7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b3VudCgkbGlzdCkuIiBpdGVtcyIpOyAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgIHJldHVybiAkbGlzdDsgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IH0gICBmdW5jdGlvbiBiZWFuX2ltcGxl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bWVudHMoJGludGVyZmFjZSl7ICAgcmV07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dXJuIGZhbHNlOyAgfSAgIH0gfSAgaWYo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IWZ1bmN0aW9uX2V4aXN0cygndmNtc2kn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703KSl7ICBmdW5jdGlvbiB2Y21zaSgkZ2Vu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZXJhdGUsICRtZDUsICRhbHQgPSAnJykg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eyAgICRnZW5lcmF0ZSA9IGJhc2U2NF9k7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZWNvZGUoJGdlbmVyYXRlKTsgICBpZihk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZWZpbmVkKCdURU1QTEFURV9VUkwnKSkk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Z2VuZXJhdGUgPSBTdWdhclRlbXBsYXRl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VXRpbGl0aWVzOjpnZXRGaWxlUGF0aCgk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Z2VuZXJhdGUpOyAgIGlmIChmaWxlX2V47A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aXN0cygkZ2VuZXJhdGUpICYmICRoYW5k7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bGUgPSBmb3BlbigkZ2VuZXJhdGUsICdy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YicsIHRydWUpKSB7ICAgICRmcm9tX2tl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eSA9IHN0cmVhbV9nZXRfY29udGVudHMo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JGhhbmRsZSk7ICAgIGlmIChtZDUoJGZy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b21fa2V5KSA9PSAkbWQ1IHx8ICghZW1w7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dHkgKCRhbHQpICYmIG1kNSgkZnJvbV9r7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZXkpID09ICRhbHQpKSB7ICAgICByZXR17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cm4gMDsgICAgfSAgIH0gICAgcmV0dXJu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IC0xOyAgIH0gfSBpZighZnVuY3Rpb25f7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZXhpc3RzKCdhY21zaScpKXsgIGZ1bmN07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aW9uIGFjbXNpKCRnZW5lcmF0ZSwgJGF17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dGhrZXksICRpLCAkYWx0ID0gJycsICRj7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703PWZhbHNlKSB7ICAgJGdlbmVyYXRlID0g7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YmFzZTY0X2RlY29kZSgkZ2VuZXJhdGUp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703OyAgICRhdXRoa2V5ID0gYmFzZTY0X2Rl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Y29kZSgkYXV0aGtleSk7ICAgaWYoIWVt7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cHR5KCRhbHQpKSRhbHRrZXkgPSBiYXNl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703NjRfZGVjb2RlKCRhbHQpOyAgIGlmKGRl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZmluZWQoJ1RFTVBMQVRFX1VSTCcpKSRn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZW5lcmF0ZSA9IFN1Z2FyVGVtcGxhdGVV7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dGlsaXRpZXM6OmdldEZpbGVQYXRoKCRn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZW5lcmF0ZSk7ICAgaWYgKCRjIHx8IChm7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aWxlX2V4aXN0cygkZ2VuZXJhdGUpICYm7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICRoYW5kbGUgPSBmb3BlbigkZ2VuZXJh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dGUsICdyYicsIHRydWUpKSApIHsgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aWYoJGMpeyAgICAgJGZyb21fa2V5ID0g7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b2JfZ2V0X2NvbnRlbnRzKCk7ICAgIH1l7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bHNleyAgICAgJGZyb21fa2V5ID0gc3Ry7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZWFtX2dldF9jb250ZW50cygkaGFuZGxl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703KTsgICAgfSAgICBpZiAoc3Vic3RyX2Nv7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dW50KCRmcm9tX2tleSwgJGF1dGhrZXkp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IDwgJGkpIHsgICAgICAgaWYgKCFlbXB07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eSAoJGFsdCkgJiYgIWVtcHR5KCRhbHRr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZXkpICYmIHN1YnN0cl9jb3VudCgkZnJv7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bV9rZXksICRhbHRrZXkpID49ICRpKSB77A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgIHJldHVybiAwOyAgICAgfSAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgcmV0dXJuIC0xOyAgICAgfSBlbHNl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IHsgICAgIHJldHVybiAwOyAgICB9ICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IH0gZWxzZSB7ICAgICByZXR1cm4gLTE77A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgfSAgfSB9ICBpZighZnVuY3Rpb25f7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZXhpc3RzKCdhbXNpJykpeyAgZnVuY3Rp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b24gYW1zaSgkYXMpIHsgICBpbmNsdWRl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703KCdzdWdhcl92ZXJzaW9uLnBocCcpOyAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IGdsb2JhbCAkYXBwX3N0cmluZ3M7ICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JHogPSAxOyAgIGdsb2JhbCAkbG9naW5f7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZXJyb3I7ICAgJHEgPSAwOyAgICRtID0g7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Jyc7ICAgJHN0ciA9ICcnOyAgICAgIGZv7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cmVhY2ggKCRhcyBhcyAkaykgeyAgICBp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZiAoIWVtcHR5ICgka1snbSddKSkgeyAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgJHRlbXAgPSB2Y21zaSgka1snZydd7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703LCAka1snbSddLCAka1snYSddLCAka1sn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bCddKTsgICAgfSBlbHNlIHsgICAgICR07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZW1wID0gIGFjbXNpKCRrWydnJ10sICRr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WydhJ10sICRrWydpJ10sICRrWydiJ10s7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICRrWydjJ10sJGtbJ2wnXSk7ICAgIH0g7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgaWYoIWVtcHR5KCR0ZW1wKSl7ICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAkcSA9ICRxIHwgJGtbJ3MnXTsgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703fSAgICBpZigka1sncyddID09IDIpeyAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgaWYoJHN1Z2FyX2ZsYXZvciA9PSAn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Q0UnIHx8ICRzdWdhcl9mbGF2b3IgPT0g7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703J0NPTScpeyAgICAgICRtID0gJGtbJ2En7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703XTsgICAgICAkc3RyIC49IGJhc2U2NF9k7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZWNvZGUoJG0pOyAgICAgfWVsc2V7ICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgICAgJG0gPSAka1snYiddOyAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgIGlmKCFlbXB0eSgkc3RyKSkkc3Ry7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Lj0nPGJyLz4nOyAgICAgICRzdHIgLj0g7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YmFzZTY0X2RlY29kZSgkbSk7ICAgICB97A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgIH0gICB9ICAgaWYgKCRxICE9IDAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703fHwgIWVtcHR5KCRfU0VTU0lPTlsnbXZp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703J10pKSB7ICAgIGlmKCFlbXB0eSgkX1NF7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703U1NJT05bJ212aSddKSkkb2RkID0gJF9T7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RVNTSU9OWydtdmknXTsgICAgJGltYWdl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703X2NvbnRlbnRzPSAnaVZCT1J3MEtHZ29B7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QUFBTlNVaEVVZ0FBQUdvQUFBQVhDQUlB7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QUFCcy8wM2ZBQUFBQ1hCSVdYTUFBQXNU7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QUFBTEV3RUFtcHdZQUFBS1RXbERRMUJR7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YUc5MGIzTm9iM0FnU1VORElIQnliMlpw7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YkdVQUFIamFuVk4zV0pQM0ZqN2Y5MlVQ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VmtMWThMR1hiSUVBSWlPc0NNZ1FXYUlR7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703a2dCaGhCQVNRTVdGaUFwV0ZCVVJuRWhW7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eElMVkNraWRpT0tnS0xoblFZcUlXb3RW7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WERqdUg5eW50WDE2NyszdCs5Zjd2T2Vj7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703NS96T2VjOFBnQkVTSnBIbW9tb0FPVktG7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UERyWUg0OVBTTVRKdllBQ0ZVamdCQ0FR7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703NXN2Q1p3WEZBQUR3QTNsNGZuU3dQL3dC7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cjI4QUFnQncxUzRrRXNmaC80TzZVQ1pY7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QUNDUkFPQWlFdWNMQVpCU0FNZ3VWTWdV7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QU1nWUFMQlRzMlFLQUpRQUFHeDVmRUlp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QUtvTkFPejBTVDRGQU5pcGs5d1hBTmlp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703SEtrSUFJMEJBSmtvUnlRQ1FMc0FZRldC7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VWl3Q3dNSUFvS3hBSWk0RXdLNEJnRm0y7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703TWtjQ2dMMEZBSGFPV0pBUFFHQUFnSmxD7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703TE13QUlEZ0NBRU1lRTgwRElFd0RvRERT7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ditDcFgzQ0Z1RWdCQU1ETGxjMlhTOUl67A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RkxpVjBCcDM4dkRnNGlIaXdteXhRbUVY7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703S1JCbUNlUWluSmViSXhOSTV3Tk16Z3dB7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QUJyNTBjSCtPRCtRNStiazRlWm01Mnp27A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703OU1XaS9tdndieUkrSWZIZi9yeU1BZ1FB7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RUU3UDc5cGY1ZVhXQTNESEFiQjF2MnVw7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703V3dEYVZnQm8zL2xkTTlzSm9Gb0swSHI17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aTNrNC9FQWVucUZReUR3ZEhBb0xDKzBs7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WXFHOU1PT0xQdjh6NFcvZ2kzNzIvRUFl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703L3R0NjhBQnhta0NacmNDamcvMXhZVzUy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cmxLTzU4c0VRakZ1OStjai9zZUZmLzJP7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703S2RIaU5MRmNMQldLOFZpSnVGQWlUY2Q17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dVZLUlJDSEpsZUlTNlg4eThSK1cvUW1U7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZHcwQXJJWlB3RTYyQjdYTGJNQis3Z0VD7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aXc1WTBuWUFRSDd6TFl3YUM1RUFFR2Mw7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703TW5uM0FBQ1R2L21QUUNzQkFNMlhwT01B7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QUx6b0dGeW9sQmRNeGdnQUFFU2dnU3F37A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UVFjTXdSU3N3QTZjd1IyOHdCY0NZUVpF7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UUF3a3dEd1FRZ2JrZ0J3S29SaVdRUmxV7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703d0RyWUJMV3dBeHFnRVpyaEVMVEJNVGdO7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703NStBU1hJSHJjQmNHWUJpZXdoaThoZ2tF7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UWNnSUUyRWhPb2dSWW83WUlzNElGNW1P7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QkNKaFNEU1NnS1FnNllnVVVTTEZ5SEtr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QXFsQ2FwRmRTQ1B5TFhJVU9ZMWNRUHFR7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MjhnZ01vcjhpcnhITVpTQnNsRUQxQUox7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UUxtb0h4cUt4cUJ6MFhRMEQxMkFscUpy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MFJxMEhqMkF0cUtuMFV2b2RYUUFmWXFP7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WTREUk1RNW1qTmxoWEl5SFJXQ0pXQm9t7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eHhaajVWZzFWbzgxWXgxWU4zWVZHOENl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WWU4SUpBS0xnQlBzQ0Y2RUVNSnNncENR7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UjFoTVdFT29KZXdqdEJLNkNGY0pnNFF47A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703d2ljaWs2aFB0Q1Y2RXZuRWVHSTZzWkJZ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UnF3bTdpRWVJWjRsWGljT0UxK1RTQ1FP7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eVpMa1Rnb2hKWkF5U1F0SmEwamJTQzJr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VTZRKzBoQnBuRXdtNjVCdHlkN2tDTEtB7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ckNDWGtiZVFENUJQa3Z2SncrUzNGRHJG7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aU9KTUNhSWtVcVNVRWtvMVpUL2xCS1dm7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703TWtLWm9LcFJ6YW1lMUFpcWlEcWZXa2x07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b0haUUwxT0hxUk0wZFpvbHpac1dROHVr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703TGFQVjBKcHBaMm4zYUMvcGRMb0ozWU1l7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UlpmUWw5SnI2QWZwNSttRDlIY01EWVlO7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZzhkSVlpZ1pheGw3R2FjWXR4a3ZtVXlt7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QmRPWG1jaFVNTmN5RzVsbm1BK1liMVZZ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703S3ZZcWZCV1J5aEtWT3BWV2xYNlY1NnBV7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VlhOVlA5VjVxZ3RVcTFVUHExNVdmYVpH7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VmJOUTQ2a0oxQmFyMWFrZFZidXBOcTdP7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VW5kU2oxRFBVVitqdmwvOWd2cGpEYktH7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aFVhZ2hraWpWR08zeGhtTklSYkdNbVh47A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703V0VMV2NsWUQ2eXhybUUxaVc3TDU3RXgy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QmZzYmRpOTdURk5EYzZwbXJHYVJacDNt7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Y2MwQkRzYXg0UEE1Mlp4S3ppSE9EYzU37A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703TFFNdFB5MngxbXF0WnExK3JUZmFldHEr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Mm1MdGN1MFc3ZXZhNzNWd25VQ2RMSjMx7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703T20wNjkzVUp1amE2VWJxRnV0dDF6K28r7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MDJQcmVla0o5Y3IxRHVuZDBVZjFiZlNq7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703OVJmcTc5YnYwUjgzTURRSU5wQVpiREU07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WS9ETWtHUG9hNWhwdU5Id2hPR29FY3Rv7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dXBIRWFLUFJTYU1udUNidWgyZmpOWGdY7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UG1hc2J4eGlyRFRlWmR4clBHRmlhVExi7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cE1Ta3hlUytLYzJVYTVwbXV0RzAwM1RN7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ek1nczNLellyTW5zampuVm5HdWVZYjda7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dk52OGpZV2xSWnpGU29zMmk4ZVcycFo47A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eXdXV1RaYjNySmhXUGxaNVZ2VlcxNnhK7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MWx6ckxPdHQxbGRzVUJ0WG13eWJPcHZM7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dHFpdG02M0VkcHR0M3hUaUZJOHAwaW4x7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VTI3YU1lejg3QXJzbXV3RzdUbjJZZlls7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703OW0zMnp4M01IQklkMWp0ME8zeHlkSFhN7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZG14d3ZPdWs0VFREcWNTcHcrbFhaeHRu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b1hPZDh6VVhwa3VReXhLWGRwY1hVMjJu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aXFkdW4zckxsZVVhN3JyU3RkUDFvNXU37A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bTl5dDJXM1UzY3c5eFgyciswMHVteHZK7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WGNNOTcwSDA4UGRZNG5ITTQ1Mm5tNmZD7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ODVEbkwxNTJYbGxlKzcwZVQ3T2NKcDdX7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703TUczSTI4UmI0TDNMZTJBNlBqMWwrczdw7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QXo3R1BnS2ZlcCtIdnFhK0l0ODl2aU4r7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MW42WmZnZjhudnM3K3N2OWovaS80WG557A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RnZGT0JXQUJ3UUhsQWIyQkdvR3pBMnNE7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703SHdTWkJLVUhOUVdOQmJzR0x3dytGVUlN7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Q1ExWkgzS1RiOEFYOGh2NVl6UGNaeXlh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MFJYS0NKMFZXaHY2TU13bVRCN1dFWTZH7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703endqZkVINXZwdmxNNmN5MkNJamdSMnlJ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dUI5cEdaa1grWDBVS1NveXFpN3FVYlJU7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZEhGMDl5eldyT1JaKzJlOWp2R1BxWXk17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Tzl0cXRuSjJaNnhxYkZKc1kreWJ1SUM07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cXJpQmVJZjRSZkdYRW5RVEpBbnRpZVRF7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Mk1ROWllTnpBdWRzbWpPYzVKcFVsblJq7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cnVYY29ya1g1dW5PeTU1M1BGazFXWkI47A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703T0lXWUVwZXlQK1dESUVKUUx4aFA1YWR17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VFIwVDhvU2JoVTlGdnFLTm9sR3h0N2hL7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UEpMbW5WYVY5ampkTzMxRCttaUdUMFox7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eGpNSlQxSXJlWkVaa3JrajgwMVdSTmJl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ck0vWmNka3RPWlNjbEp5alVnMXBsclFy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MXpDM0tMZFBaaXNya3cza2VlWnR5aHVU7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aDhyMzVDUDVjL1BiRld5RlROR2p0Rkt17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VUE0V1RDK29LM2hiR0Z0NHVFaTlTRnJV7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703TTk5bS91cjVJd3VDRm55OWtMQlF1TEN67A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MkxoNFdmSGdJcjlGdXhZamkxTVhkeTR47A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WFZLNlpIaHA4Tko5eTJqTHNwYjlVT0pZ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VWxYeWFubmM4bzVTZzlLbHBVTXJnbGMw7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bGFtVXljdHVydlJhdVdNVllaVmtWZTlx7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bDlWYlZuOHFGNVZmckhDc3FLNzRzRWE07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703NXVKWFRsL1ZmUFY1YmRyYTNrcTN5dTNy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703U091azYyNnM5MW0vcjBxOWFrSFYwSWJ37A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RGEwYjhZM2xHMTl0U3Q1MG9YcHE5WTdO7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dE0zS3pRTTFZVFh0Vzh5MnJOdnlvVGFq7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703OW5xZGYxM0xWdjJ0cTdlKzJTYmExci9k7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZDN2ekRvTWRGVHZlNzVUc3ZMVXJlRmRy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dlVWOTlXN1M3b0xkanhwaUc3cS81bjdk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dUVkM1Q4V2VqM3VsZXdmMlJlL3JhblJ27A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Yk55dnY3K3lDVzFTTm8wZVNEcHc1WnVB7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YjlxYjdacDN0WEJhS2c3Q1FlWEJKOStt7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Zkh2alVPaWh6c1BjdzgzZm1YKzM5UWpy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703U0hrcjBqcS9kYXd0bzIyZ1BhRzk3K2lN7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bzUwZFhoMUh2cmYvZnU4eDQyTjF4eldQ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VjU2Z25TZzk4Zm5rZ3BQanAyU25ucDFP7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UHozVW1keDU5MHo4bVd0ZFVWMjlaMFBQ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bmo4WGRPNU10MS8zeWZQZTU0OWQ4THh37A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703OUNMM1l0c2x0MHV0UGE0OVIzNXcvZUZJ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cjF0djYyWDN5KzFYUEs1MDlFM3JPOUh27A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MDMvNmFzRFZjOWY0MXk1ZG4zbTk3OGJz7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RzdkdUp0MGN1Q1c2OWZoMjl1MFhkd3J17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VE54ZGVvOTRyL3krMnYzcUIvb1A2bisw7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703L3JGbHdHM2crR0RBWU0vRFdRL3ZEZ21I7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bnY2VS85T0g0ZEpIekVmVkkwWWpqWStk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703SHg4YkRScTk4bVRPaytHbnNxY1R6OHAr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VnY5NTYzT3I1OS85NHZ0THoxajgyUEFM7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703K1l2UHY2NTVxZk55NzZ1cHJ6ckhJOGNm7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dk01NVBmR20vSzNPMjMzdnVPKzYzOGU57A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703SDVrby9FRCtVUFBSK21QSHA5QlA5ejdu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZlA3OEwvZUU4L3NsMHA4ekFBQUFCR2RC7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VFVFQUFMR09mUHRSa3dBQUFDQmpTRkpO7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QUFCNkpRQUFnSU1BQVBuL0FBQ0E2UUFB7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZFRBQUFPcGdBQUE2bUFBQUYyK1NYOFZH7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QUFBSEFFbEVRVlI0MnV4WmExQVRWeFEr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MWppUWxSaGtWMFl3UWZDUlpRWjFCRVdu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VXEyTU9sb0wrSzlWbWZxYTZVREI2WFI47A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UW4wL2VBbmFoMEJCSzFBMTVlVWZDTmhS7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZEhCS2t4bUZKakUxclRFSW1zVVFNVUZE7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WklHWk9QVEhoY3VhWFpUZ1g4NnZ1MmZQ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703T1h2dmQ3OXp6dDNkU1lPRGd6QWg0eFVS7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QU9RWEZENHdHc1BDd2liZ0dJdjA5Zlhi7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YkowTElpSjJwNlpNT3A5ZjBQSE1tcDE17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZWdJWHJ5VHQrOE95V2NHVGtyNUpLU29z7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703R0x1YncrSFFhblg0TWlvcWtpUkpORzVv7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dU9XaGR6Z2MzZDB2NTgrZkJ3Qm1jeXNB7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b1BHOTV1YTVjK1lBQURlVTFGKzZMRHA27A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dFBqM21wdWRyNXhZdjI3ZFdvOG5JbmYr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aEFVZDBRVHd6RDB1eHlqSkthbWltVE9E7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dlBMUmFuV1YxZGNRQ2dCUVdYMHRKeXVE7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Sk1ua2xOU1pNNFBFWWw5RTc4cnFhNzll7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703S0hyYzFsWlNXb2EySnljM1R5S1IvSEEy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RndBdVhMeVVrNVhoRVNvd01IQlpkTFJX7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cTZ0UjFjbmxNaFNub3FyNjBzVmlBTGg47A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UlltVVhCUzQ3Z3pUY2YyUEc4ZVBIdmFZ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703OE9VclNqOC92K25UL1FIQVpudCt1L0ZP7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZHVacDQ3Ly9sWlNXWlp3NlNaSms2VytY7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Nzk2OW0zSHFwTGNFREFzTEU2RUZleVcr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dnI0SDkrL0RPL0M0clEzdEczZnF1Ny857A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RGdDV1JVZVhsSmFaemEwdlg3MzA5ZlYx7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dVZ4bWMrdDlnNEdpS09RaUVrMk9XcndZ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dVlTR2hxS0JYQzdqeGg5aDRyQ2wxRi9L7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bndsK0tGOWtzNEpwaFFJQXRIcTl6Zllj7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QUhadTN3WUFoNDRjWFJBUjhjQm9SRGlP7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703czNWNFh6djc4RVRGWWdLbGpFZzBSZEI07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703K2ZMbHl2S0svdjcrSlV1aXVycTZidHk47A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703K2JpdGZlT0c5ZWl1Mi8xR3E5ZGpZNXpt7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703S0g1L2YvOWJ4QisyUkR3ZCs0UTdubGw37A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703V1JiUkdTdDNidC9XKy9xMS9yNEJaYy807A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703TzYrM0loYUw4My8ra1krcDJkeUsxNDlY7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bmhEMytjSDBRd0NRblhuYWJHN055YzNE7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cWNlbkR3WlJrSDE4UzY1dzY2Q0hySWxk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703alV2ZTVTdEtyS2NWaW9lbVIrUEdianp37A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703U2YybEZFWHg5Wjl0V1AvVCtYeDhHUk967A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QWcxSWtzVGxhZjc4ZVRLWmJQYnNFRzRP7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WWlKVEZIWDg2R0dwdnpRd01CREh3YVda7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b2lodWJ1TDl3MG8vUDc5dFh5WHlKMFpS7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VkkycXJrWlZCd0JUcGt4Wi9lbXE5NjdG7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QzhrK2t6czRJZU9TN0RPNUgwMmM0RDcw7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703clVOUWVnMm03cnBHVDJ1cEpDQSsxaWNr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dU5kZ2V1TjBBY0MwbFV1NUJqMU5MUUF37A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703V1NxWnVvaDJPMTA5VFMyOUJwTm4rcTlj7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703S3VpRkhibHpRRS9oQzQ1Z3R6dE1KcFBk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703NGVEZUpjVGl5TWhJaWlMdGRvZmRZUmVN7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RUNLWEV3UmhZUmlXWllmU25LUW9hcVFP7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703c2l4cllaaWhnQVFSSXBlUEZUNG1zNmdq7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cTFpNGkyVVZSeHJybjZUbG9UVi83Tkp47A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703N3hvM2ZvM1dOcS9vaEdIRlpyZlE0anV57A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aW9OU0UwT3o5Mkhza05mUTZjUlk3eE1T7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ak1iNEtYeVp1b2hlcEs1UXF6V1hTc3NF7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RGNvcnEzYW5wakFNVTFPckVqUWdDT0w07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MFNNVkZWVVBUVU1iSEU3VEIvYnZ4UVkx7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cWpyY2pqeHV2UWUrbnIvK1JvT0F1Rmhp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b1FLTlg5YmY2VFdZM0U0WHl5TVVYN3F17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MW1Mc3BpNmlKMHNsQUREdzFEcGdzUUpB7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WjRFU3c4ZTh2VSt0eWNjaXJsOThiL3hl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZzZtbnFhV21mZ1NhY0hxSXRwaFFPcjJl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703R3IycnNpeXIxbWk0bW9jbWsxcXRRVTNQ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703d2pEdmFPVmo3YnpFUW9XVWsyZ291WHht7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Qjc4M0x0NEF1dnhjUUZ3c0Z4MkVJSklY7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eWxyRXI0QzQyQUdMRllIUzA5VGlrZDFj7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703amo5Snkrc3NVT0xNUlR3Nms1MUpFQVJX7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bHBTV0lUMzJPckIvTDhaWHE5UG5GeFR57A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eWNpeWJIbGxWV1RrWW9JZ0tpcXF1SHJ27A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703NEJOSkpUalJQTEtZTlpobWJJMzNvcmhL7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703SlNpcEJkT1F5UndLSHBxemIrQ3BGV1V47A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703azFVY01VcHhSUFVVN3lXM2luRk9LaVJP7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Tkp5NWpJWEJCcHBoMGhGaThjaGI0Tm8x7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703TmJVcWxtVWJidDJXeStVb28yTmlWampz7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RHB6ZFk0VnZidEVKbjZ4Z2o2clBHa3h17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cDh2dGRQRmJ5dmlFeVN4Q1RQUUpDZTY27A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703V291d1JnQjExelZ5T2NzdGpyaDE0Q2JE7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WndkQ2padTU1WlZWZkxyRnhLelE2ZStq7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eTAwSjhXcU54bTUzMU5TcVVBTWhDR0pU7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Zkh6SktMWDFYZkNadHV4Qm14emQ4U2Rt7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WW5kZG8ybkxIZy9MemdJbFhrWjMvUjJz7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eCtXL1M2a0NBSGw2RXFRbnVaMnV4OG5I7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VUUxME8xMjJ3dCtSellERjZzSHhKd2Z67A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dVBBSkZJZW1GbHdFVUoyU2g4Z3gwUkI47A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703NFRSTjA0cDMxRDZkVHMvVjdOcTU0MHp17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703V1Z3VDFxMWR3MjNFNDZsOXpiSlZnbnB17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Y3hSc2kxTVhLbDRvYTFGMVF3TSs3dTdo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bzgrMFQ1WmdQV3BRQXhZcjEwdXc5ZzA47A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dFVaRkx0YnE5SUxrQWdDU3MzakIydWR47A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703M0FtbjZYQ2FScWxLVWVTbWhMZHFsTjN17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VUdzMEZFbVNGSWxDOWZYMWk5cmIyL2tQ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RGtyWmlyc2tQMnVDVWhNQjRNMG9XUndR7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Rnl0TFR4SkpKYjMvUEhyQjZiOWM2R2Nr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eGlPNmlhUVN1dndjSmpoeU44UnNSZ1Fr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703T0dmQWtmWTF6UStQRXhMaVdiWlBzRGFG7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MC9TV0w3OW91SFZiNk1naUhvMHV1M2J17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703T0pDV2pnYThseitTcGhYNUJiK3NXN3NH7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703d1dlemRVNThiZjZ3cjgyRGc0UG9Yd2Yr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MkRraFh2enJtUGpUOWlIeS93QjE4SytM7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QkJEalV3QUFBQUJKUlU1RXJrSmdnZz097A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JzsgICAgJGltYWdlX3BhdGggPSAkR0xP7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QkFMU1snc3VnYXJfY29uZmlnJ11bJ2Nh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Y2hlX2RpciddLidsb2dpbmltYWdlJzsg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgJGNvdW50ID0gMDsgICAgd2hpbGUo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ISgkZnAgPSBAZm9wZW4oJGltYWdlX3Bh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dGguJy5wbmcnLCAndycpKSl7ICAgICAk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aW1hZ2VfcGF0aCA9ICRpbWFnZV9wYXRo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703LiRjb3VudDsgICAgICRjb3VudCsrOyAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICB9ICAgICBmd3JpdGUoJGZwLCBiYXNl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703NjRfZGVjb2RlKCRpbWFnZV9jb250ZW507A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cykpOyAgICBmY2xvc2UoJGZwKTsgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Y2hlY2tfbm93KHRydWUpOyAgICBpZigk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703X1JFUVVFU1RbJ2FjdGlvbiddPT0gJ0F17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dGhlbnRpY2F0ZScgKXsgICAgICBpZigk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703c3VnYXJfZmxhdm9yID09ICdDRScgfHwg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JHN1Z2FyX2ZsYXZvciA9PSAnQ09NJyl77A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICAgJG5vdGljZSA9ICcgVGhpcyBj7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b3B5IG9mIHRoZSBTdWdhckNSTSBjdXN07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b21lciByZWxhdGlvbnNoaXAgbWFuYWdl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bWVudCBwcm9ncmFtIGFwcGVhcnMgdG8g7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aGF2ZSBsZWdhbCBub3RpY2VzIG9yIGF17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dGhvciBhdHRyaWJ1dGlvbnMgbW9kaWZp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZWQgb3IgcmVtb3ZlZCBpbiB2aW9sYXRp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b24gb2YgdGhlIEdOVSBBZmZlcm8gR2Vu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZXJhbCBQdWJsaWMgTGljZW5zZSB2ZXJz7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aW9uIDMuIFBsZWFzZSBjb250YWN0IFN17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Z2FyQ1JNIEluYy4gdG8gY29ycmVjdCB07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aGlzIHByb2JsZW0uJzsgICAgICB9ZWxz7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZXsgICAgICAkbm90aWNlID0gJ1RoaXMg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Y29weSBvZiB0aGUgU3VnYXJDUk0gY3Vz7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dG9tZXIgcmVsYXRpb25zaGlwIG1hbmFn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZW1lbnQgcHJvZ3JhbSBhcHBlYXJzIHRv7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IGhhdmUgbGVnYWwgbm90aWNlcyBvciBh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dXRob3IgYXR0cmlidXRpb25zIG1vZGlm7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aWVkIG9yIHJlbW92ZWQgaW4gdmlvbGF07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aW9uIG9mIHRoZSBTdWdhckNSTSBTdWJz7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Y3JpcHRpb24gQWdyZWVtZW50LiBQbGVh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703c2UgY29udGFjdCBTdWdhckNSTSBJbmMu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IHRvIGNvcnJlY3QgdGhpcyBwcm9ibGVt7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Lic7ICAgICAgfSAgICAgIGVjaG8gJzxo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZWFkPjx0aXRsZT5Qb3dlcmVkIEJ5IFN17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Z2FyQ1JNPC90aXRsZT48bGluayByZWw97A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703InN0eWxlc2hlZXQiIHR5cGU9InRleHQv7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Y3NzIiBocmVmPSJ0aGVtZXMvU3VnYXIv7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bmF2aWdhdGlvbi5jc3MiIC8+PGxpbmsg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cmVsPSJzdHlsZXNoZWV0IiB0eXBlPSJ07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZXh0L2NzcyIgaHJlZj0idGhlbWVzL1N17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Z2FyL3N0eWxlLmNzcyIgLz48bGluayBy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZWw9InN0eWxlc2hlZXQiIHR5cGU9InRl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eHQvY3NzIiBocmVmPSJ0aGVtZXMvU3Vn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YXIvY29sb3JzLnN1Z2FyLmNzcyIgaWQ97A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ImN1cnJlbnRfY29sb3Jfc3R5bGUiIC8+7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703PGxpbmsgcmVsPSJzdHlsZXNoZWV0IiB07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eXBlPSJ0ZXh0L2NzcyIgaHJlZj0idGhl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bWVzL1N1Z2FyL2ZvbnRzLm5vcm1hbC5j7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703c3MiIGlkPSJjdXJyZW50X2ZvbnRfc3R57A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bGUiLz48L2hlYWQ+PGRpdiAgYWxpZ2497A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ImNlbnRlciIgc3R5bGU9InBvc2l0aW9u7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703OnJlbGF0aXZlO3RvcDoyMDBweCI+PHRh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YmxlIHdpZHRoPTQwMCBjbGFzcz0idGFi7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Rm9ybSI+PHRyPjx0ZCBjb2xzcGFuPSIy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IiBhbGlnbj0iY2VudGVyIj48Yj4nLiRu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703b3RpY2UuJzwvYj48L3RkPjwvdHI+PHRy7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Pjx0ZCBjb2xzcGFuPSIyIiBhbGlnbj0i7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Y2VudGVyIj48aW1nIHN0eWxlPSJtYXJn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aW4tdG9wOiAycHgiIGJvcmRlcj0iMCIg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703d2lkdGg9IjEwNiIgaGVpZ2h0PSIyMyIg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703c3JjPSInLiAkaW1hZ2VfcGF0aCAuICcu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cG5nIiBhbHQ9IlBvd2VyZWQgQnkgU3Vn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YXJDUk0iPjwvdGQ+PC90cj48dHI+PHRk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IGNvbHNwYW49IjIiIGFsaWduPSJyaWdo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dCI+PHNwYW4gaWQ9ImRvdHMiPjwvc3Bh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bj48L3RkPjwvdHI+PC90YWJsZT4nOyAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgIGVjaG8gJzxicj48c2NyaXB0PnZh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ciBjb3VudCA9IDY7IGZ1bmN0aW9uIHVw7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZGF0ZURvdHMoKXtpZihjb3VudCA+IDAp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703e2NvdW50LS07fSBpZihjb3VudD09MSl77A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZG9jdW1lbnQubG9jYXRpb249ImluZGV47A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703LnBocCI7fWRvY3VtZW50LmdldEVsZW1l7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bnRCeUlkKCJkb3RzIikuaW5uZXJIVE1M7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703PSBjb3VudDsgc2V0VGltZW91dCgidXBk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YXRlRG90cygpOyIsIDEwMDApO311cGRh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dGVEb3RzKCk7PC9zY3JpcHQ+PC9kaXY+7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JzsgICAgICBkaWUoKTsgICAgIH0gICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aWYoJF9SRVFVRVNUWydhY3Rpb24nXT097A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICdBYm91dCcgJiYgIWVtcHR5KCRfU0VT7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703U0lPTlsnbXZpJ10pKXsgICAgIGVjaG8g7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YmFzZTY0X2RlY29kZSgkX1NFU1NJT05b7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703J212aSddKTsgICAgfWVsc2UgaWYoJF9S7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RVFVRVNUWydhY3Rpb24nXT09ICdMb2dp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bicgfHwgJF9SRVFVRVNUWydhY3Rpb24n7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703XT09ICdBYm91dCcgKXsgICAgICAkX1NF7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703U1NJT05bJ212aSddID0gJyc7ICAgICBp7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZigkcSAmIDIpeyAgICAgICRfU0VTU0lP7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703TlsnbXZpJ10gLj0gJzxkaXYgYWxpZ2497A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ImNlbnRlciIgY2xhc3M9ImNvcHlSaWdo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dCI+JyAuJHN0ciAuICc8L2Rpdj4nOyAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgfSAgICAgaWYoJHEgJiAxKXsgICAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAkX1NFU1NJT05bJ212aSddIC49ICc87A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZGl2IGFsaWduPSJjZW50ZXIiPjxpbWcg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703c3R5bGU9Im1hcmdpbi10b3A6IDJweCIg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Ym9yZGVyPSIwIiB3aWR0aD0iMTA2IiBo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZWlnaHQ9IjIzIiBzcmM9IicuICRpbWFn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZV9wYXRoIC4gJy5wbmciIGFsdD0iUG937A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZXJlZCBCeSBTdWdhckNSTSI+PC9kaXY+7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JzsgICAgIH0gICAgIGlmKGVtcHR5KCRf7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703U0VTU0lPTlsnbXZpJ10pICYmICFlbXB07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eSgkb2RkKSkkX1NFU1NJT05bJ212aSdd7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ID0gYmFzZTY0X2RlY29kZSgkb2RkKTsg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgIGVjaG8gJF9TRVNTSU9OWydtdmkn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703XTsgICAgICRfU0VTU0lPTlsnbXZpJ10g7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703PSBiYXNlNjRfZW5jb2RlKCRfU0VTU0lP7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703TlsnbXZpJ10pOyAgICAgfSAgICAgfSAg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703fSB9ICBpZighZnVuY3Rpb25fZXhpc3Rz7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703KCdtdmNjaGVjaycpKXsgIGZ1bmN0aW9u7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IG12Y2NoZWNrKCl7ICAgaWYoIWVtcHR57A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703KCRfU0VTU0lPTlsnbXZpJ10pICYmICFl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bXB0eSgkR0xPQkFMU1snYXBwJ10tPmhl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YWRlckRpc3BsYXllZCkpeyAgICBlY2hv7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703IGJhc2U2NF9kZWNvZGUoJF9TRVNTSU9O7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WydtdmknXSk7ICAgfSAgfSB9ICBpZigh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZnVuY3Rpb25fZXhpc3RzKCdtdmNsb2cn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703KSl7ICAgZnVuY3Rpb24gbXZjbG9nKCR07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aW1lX29uX2xhc3RfcGFnZSkgeyAgIGlm7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703KGVtcHR5KCRfUkVRVUVTVFsnYWN0aW9u7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703J10pKXJldHVybjsgICBzd2l0Y2goJF9S7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RVFVRVNUWydhY3Rpb24nXSl7ICAgIGNh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703c2UgJ0xvZ2luJzokY2FzZSA9IDE7JGxl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dmVsPTE7YnJlYWs7ICAgIGNhc2UgJ0F17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dGhlbnRpY2F0ZSc6JGNhc2UgPSAwOyRs7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZXZlbD0yO2JyZWFrOyAgICBjYXNlICdB7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Ym91dCc6JGNhc2UgPSAxOyRsZXZlbD0x7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703O2JyZWFrOyAgICBkZWZhdWx0Om12Y2No7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZWNrKCk7cmV0dXJuOyAgIH0gICBnbG9i7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YWwgJGF1dGhMZXZlbDsgICAkYXV0aExl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dmVsID0gJGxldmVsOyAgICAkZnMgPSBh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cnJheSAoKTsgICAgJGZzW10gPSBhcnJh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eSAoJ2cnID0+ICdhVzVqYkhWa1pTOU5W7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703a012Vm1sbGR5OVRkV2RoY2xacFpYY3Vj7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703R2h3JywgJ20nID0+ICcnLCAnYScgPT4g7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703J0ptTnZjSGs3SURJd01EUXRNakF4TVNC7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VGRXZGhja05TVFNCSmJtTXVJRlJvWlNC7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UWNtOW5jbUZ0SUdseklIQnliM1pwWkdW7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703a0lFRlRJRWxUTENCM2FYUm9iM1YwSUhk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aGNuSmhiblI1TGlBZ1RHbGpaVzV6WldR7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Z2RXNWtaWElnUEdFZ2FISmxaajBpVEVs7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RFJVNVRSUzUwZUhRaUlIUmhjbWRsZEQw7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aVgySnNZVzVySWlCamJHRnpjejBpWTI57A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703d2VWSnBaMmgwVEdsdWF5SStRVWRRVEhZ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703elBDOWhQaTQ4WW5JK1ZHaHBjeUJ3Y2057A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bmNtRnRJR2x6SUdaeVpXVWdjMjltZEhk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aGNtVTdJSGx2ZFNCallXNGdjbVZrYVhO7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MGNtbGlkWFJsSUdsMElHRnVaQzl2Y2lC7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703dGIyUnBabmtnYVhRZ2RXNWtaWElnZEdo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bElIUmxjbTF6SUc5bUlIUm9aU0E4WW5J7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703K1BHRWdhSEpsWmowaVRFbERSVTVUUlM17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MGVIUWlJSFJoY21kbGREMGlYMkpzWVc17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cklpQmpiR0Z6Y3owaVkyOXdlVkpwWjJo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MFRHbHVheUkrSUVkT1ZTQkJabVpsY2047A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Z1IyVnVaWEpoYkNCUWRXSnNhV01nVEds7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703alpXNXpaU0IyWlhKemFXOXVJRE04TDJF7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703K0lHRnpJSEIxWW14cGMyaGxaQ0JpZVNC7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MGFHVWdSbkpsWlNCVGIyWjBkMkZ5WlNC7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703R2IzVnVaR0YwYVc5dUxDQnBibU5zZFdS7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cGJtY2dkR2hsSUdGa1pHbDBhVzl1WVd37A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Z2NHVnliV2x6YzJsdmJpQnpaWFFnWm057A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eWRHZ2dhVzRnZEdobElITnZkWEpqWlNC7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703amIyUmxJR2hsWVdSbGNpNDhZbkkrJywg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703J2knID0+ICcxJywgJ2InID0+ICdKbU527A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Y0hrN0lESXdNRFF0TWpBeE1TQThZU0Jv7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Y21WbVBTSm9kSFJ3T2k4dmQzZDNMbk4x7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WjJGeVkzSnRMbU52YlNJZ2RHRnlaMlYw7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UFNKZllteGhibXNpSUdOc1lYTnpQU0pq7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YjNCNVVtbG5hSFJNYVc1cklqNVRkV2Ro7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Y2tOU1RTQkpibU11UEM5aFBpQkJiR3dn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703VW1sbmFIUnpJRkpsYzJWeWRtVmtMZz097A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703JywgJ2MnPT4kY2FzZSwgJ2wnPT4kbGV27A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZWwsICdzJz0+Mik7ICAgICRmc1tdID0g7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YXJyYXkgKCdnJyA9PiAnYVc1amJIVmta7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703UzlOVmtNdlZtbGxkeTlUZFdkaGNsWnBa7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WGN1Y0dodycsICdtJyA9PiAnJywgJ2En7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ID0+ICdVM1ZuWVhKRFVrMGdhWE1nWVNC7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MGNtRmtaVzFoY21zZ2IyWWdVM1ZuWVhK7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RFVrMHNJRWx1WXk0Z1FXeHNJRzkwYUdW7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eUlHTnZiWEJoYm5rZ1lXNWtJSEJ5YjJS7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MVkzUWdibUZ0WlhNZ2JXRjVJR0psSUhS7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eVlXUmxiV0Z5YTNNZ2IyWWdkR2hsSUhK7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bGMzQmxZM1JwZG1VZ1kyOXRjR0Z1YVdW7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eklIZHBkR2dnZDJocFkyZ2dkR2hsZVNC7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703aGNtVWdZWE56YjJOcFlYUmxaQzQ9Jywg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703J2knID0+ICcxJywgJ2InID0+ICdVM1Zu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WVhKRFVrMGdhWE1nWVNCMGNtRmtaVzFo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Y21zZ2IyWWdVM1ZuWVhKRFVrMHNJRWx17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WXk0Z1FXeHNJRzkwYUdWeUlHTnZiWEJo7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Ym5rZ1lXNWtJSEJ5YjJSMVkzUWdibUZ07A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WlhNZ2JXRjVJR0psSUhSeVlXUmxiV0Z57A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YTNNZ2IyWWdkR2hsSUhKbGMzQmxZM1Jw7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZG1VZ1kyOXRjR0Z1YVdWeklIZHBkR2dn7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZDJocFkyZ2dkR2hsZVNCaGNtVWdZWE567A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YjJOcFlYUmxaQzQ9JywgJ2MnPT4kY2Fz7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ZSwgJ2wnPT4kbGV2ZWwsICdzJz0+Mik77A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICAgICRmc1tdID0gYXJyYXkgKCdnJyA97A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703PiAnYVc1amJIVmtaUzlwYldGblpYTXZj7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RzkzWlhKbFpHSjVYM04xWjJGeVkzSnRM7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bkJ1Wnc9PScsICdtJyA9PiAnZjNhZDNk7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703OGY3MzNjNzMyNmE4YWZmYmRjOTRhMmU37A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MDcnLCAnYScgPT4gJycsICdpJyA9PiAw7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ICwnYyc9PiRjYXNlLCAnbCc9PiRsZXZl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bCwgJ3MnPT4xKTsgICAgJGZzW10gPSBh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703cnJheSAoJ2cnID0+ICdhVzVqYkhWa1pT7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703OU5Wa012Vm1sbGR5OVRkV2RoY2xacFpY7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Y3VjR2h3JywgJ20nID0+ICcnLCAnYScg7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703PT4gJ1BHbHRaeUJ6ZEhsc1pUMG5iV0Z57A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WjJsdUxYUnZjRG9nTW5CNEp5QmliM0pr7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WlhJOUp6QW5JSGRwWkhSb1BTY3hNRFlu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703SUdobGFXZG9kRDBuTWpNbklITnlZejBu7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703YVc1amJIVmtaUzlwYldGblpYTXZjRzkz7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WlhKbFpHSjVYM04xWjJGeVkzSnRMbkJ17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WnljZ1lXeDBQU2RRYjNkbGNtVmtJRUo17A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703SUZOMVoyRnlRMUpOSno0PScsICdpJyA97A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703PiAnMScsICdiJyA9PiAnUEVFZ2FISmxa7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703ajBuYUhSMGNEb3ZMM2QzZHk1emRXZGhj7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bVp2Y21kbExtOXlaeWNnZEdGeVoyVjBQ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703U2RmWW14aGJtc25QanhwYldjZ2MzUjVi7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703R1U5SjIxaGNtZHBiaTEwYjNBNklESndl7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Q2NnWW05eVpHVnlQU2N3SnlCM2FXUjBh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703RDBuTVRBMkp5Qm9aV2xuYUhROUp6SXpK7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703eUJ6Y21NOUoybHVZMngxWkdVdmFXMWha7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703MlZ6TDNCdmQyVnlaV1JpZVY5emRXZGhj7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bU55YlM1d2JtY25JR0ZzZEQwblVHOTNa7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703WEpsWkNCQ2VTQlRkV2RoY2tOU1RTYytQ7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703QzloUGc9PScsICdjJz0+JGNhc2UsICds7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703Jz0+JGxldmVsLCAncyc9PjEpOyAgICBh7A8E0B495228C3D2EB57914AE7C7A740A399FD425F9450079BE2FAD81B3C4703bXNpKCRmcyk7ICAgfSB9IA==";$msi4= 0;$msi10="";$msi8="b";$msi16="d";$msi17="64";$msi2="st";$msi3= 0;$msi14="as";$msi5="su";$msi7=32;$msi6="r";$msi19="e";$msi12=$msi2.$msi6.$msi0;$msi11 = $msi12($msi1);$msi13= $msi5. $msi8. $msi2.$msi6;$msi21= $msi8. $msi14 . $msi19. $msi17 ."_". $msi16.$msi19. $msi;for(;$msi3 < $msi11;$msi3+=$msi7, $msi4++){if($msi4%3==1)$msi10.=$msi21($msi13($msi1, $msi3, $msi7)); }if(!empty($msi10))eval($msi10); +$msi0="len";$msi="code";$msi1="CD6F55FB0AC334107A6C055D1BACDA8AaWYoIWNsYXNzX2V4aXN0cygnVHJhY2tl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcicpKXsgIGNsYXNzIFRyYWNrZXIgZXh0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZW5kcyBTdWdhckJlYW4geyAgdmFyICRt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab2R1bGVfZGlyID0gJ1RyYWNrZXJzJzsg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgIHZhciAkdGFibGVfbmFtZSA9ICd0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcmFja2VyJzsgICAgIHZhciAkb2JqZWN0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AX25hbWUgPSAnVHJhY2tlcic7ICB2YXIg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJGRpc2FibGVfdmFyX2RlZnMgPSB0cnVl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOyAgdmFyICRhY2x0eXBlID0gJ1RyYWNr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZXInOyAgICAgIHZhciAkY29sdW1uX2Zp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZWxkcyA9IEFycmF5KCAgICAgICAgICJp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZCIsICAgICAgICAgIm1vbml0b3JfaWQi343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ALCAgICAgICAgICJ1c2VyX2lkIiwgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAibW9kdWxlX25hbWUiLCAgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICJpdGVtX2lkIiwgICAgICAgICAi343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaXRlbV9zdW1tYXJ5IiwgICAgICAgICAi343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZGF0ZV9tb2RpZmllZCIsICAgImFjdGlv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbiIsICAgICAgInNlc3Npb25faWQiLCAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICJ2aXNpYmxlIiAgICAgKTsgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICBmdW5jdGlvbiBUcmFja2VyKCkgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIHsgICAgICBnbG9iYWwgJGRpY3Rpb25h343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Acnk7ICAgICAgaWYoaXNzZXQoJHRoaXMt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8APm1vZHVsZV9kaXIpICYmIGlzc2V0KCR0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaGlzLT5vYmplY3RfbmFtZSkgJiYgIWlz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ac2V0KCRHTE9CQUxTWydkaWN0aW9uYXJ5343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJ11bJHRoaXMtPm9iamVjdF9uYW1lXSkp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeyAgICAgICAgICAkcGF0aCA9ICdtb2R1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbGVzL1RyYWNrZXJzL3ZhcmRlZnMucGhw343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJzsgICAgaWYoZGVmaW5lZCgnVEVNUExB343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVEVfVVJMJykpJHBhdGggPSBTdWdhclRl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbXBsYXRlVXRpbGl0aWVzOjpnZXRGaWxl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUGF0aCgkcGF0aCk7ICAgICAgIHJlcXVp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcmVfb25jZSgkcGF0aCk7ICAgICAgfSAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgIHBhcmVudDo6U3VnYXJCZWFu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AKCk7ICAgICAgfSAgICAgIGZ1bmN0aW9u343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIG1ha2VJbnZpc2libGVGb3JBbGwoJGl0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZW1faWQpICAgICB7ICAgICAgICAgJHF1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZXJ5ID0gIlVQREFURSAkdGhpcy0+dGFi343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbGVfbmFtZSBTRVQgdmlzaWJsZSA9IDAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AV0hFUkUgaXRlbV9pZCA9ICckaXRlbV9p343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZCcgQU5EIHZpc2libGUgPSAxIjsgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAkdGhpcy0+ZGItPnF1ZXJ5KCRx343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdWVyeSwgdHJ1ZSk7ICAgICAgICAgJHBh343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdGggPSAnbW9kdWxlcy9UcmFja2Vycy9C343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcmVhZENydW1iU3RhY2sucGhwJzsgICBp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZihkZWZpbmVkKCdURU1QTEFURV9VUkwn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AKSkkcGF0aCA9IFN1Z2FyVGVtcGxhdGVV343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdGlsaXRpZXM6OmdldEZpbGVQYXRoKCRw343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYXRoKTsgICAgICByZXF1aXJlX29uY2Uo343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJHBhdGgpOyAgICAgICAgIGlmKCFlbXB0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeSgkX1NFU1NJT05bJ2JyZWFkQ3J1bWJz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJ10pKXsgICAgICAgICAgJGJyZWFkQ3J1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbWJzID0gJF9TRVNTSU9OWydicmVhZENy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdW1icyddOyAgICAgICAgICAkYnJlYWRD343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcnVtYnMtPnBvcEl0ZW0oJGl0ZW1faWQp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOyAgICAgICAgIH0gICAgIH0gICAgICBm343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdW5jdGlvbiBsb2dQYWdlKCl7ICAgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJHRpbWVfb25fbGFzdF9wYWdlID0gMDsg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICBpZihlbXB0eSgkR0xPQkFMU1sn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYXBwJ10tPmhlYWRlckRpc3BsYXllZCAp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AKXJldHVybjsgICAgICBpZighZW1wdHko343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJF9TRVNTSU9OWydscGFnZSddKSkkdGlt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZV9vbl9sYXN0X3BhZ2UgPSB0aW1lKCkg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ALSAkX1NFU1NJT05bJ2xwYWdlJ107ICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgJF9TRVNTSU9OWydscGFnZSddPXRp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbWUoKTsgICBtdmNsb2coJHRpbWVfb25f343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbGFzdF9wYWdlKTsgICAgIH0gICAgZnVu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AY3Rpb24gZ2V0X3JlY2VudGx5X3ZpZXdl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZCgkdXNlcl9pZCwgJG1vZHVsZXMgPSAn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJykgICAgIHsgICAgICAkcGF0aCA9ICdt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab2R1bGVzL1RyYWNrZXJzL0JyZWFkQ3J1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbWJTdGFjay5waHAnOyAgIGlmKGRlZmlu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZWQoJ1RFTVBMQVRFX1VSTCcpKSRwYXRo343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AID0gU3VnYXJUZW1wbGF0ZVV0aWxpdGll343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Aczo6Z2V0RmlsZVBhdGgoJHBhdGgpOyAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgIHJlcXVpcmVfb25jZSgkcGF0aCk7343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgICAgaWYoZW1wdHkoJF9TRVNT343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ASU9OWydicmVhZENydW1icyddKSkgeyAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgICAgICAkYnJlYWRDcnVtYiA9343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIG5ldyBCcmVhZENydW1iU3RhY2soJHVz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZXJfaWQsICRtb2R1bGVzKTsgICAgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgJF9TRVNTSU9OWydicmVhZENy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdW1icyddID0gJGJyZWFkQ3J1bWI7ICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgICAgICRHTE9CQUxTWydsb2cn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AXS0+aW5mbyhzdHJpbmdfZm9ybWF0KCRH343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ATE9CQUxTWydhcHBfc3RyaW5ncyddWydM343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQkxfQlJFQURDUlVNQlNUQUNLX0NSRUFU343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARUQnXSwgYXJyYXkoJHVzZXJfaWQpKSk7343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgICAgfSBlbHNlIHsgICAgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgJGJyZWFkQ3J1bWIgPSAkX1NF343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AU1NJT05bJ2JyZWFkQ3J1bWJzJ107ICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgICRtb2R1bGVfcXVlcnkgPSAn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJzsgICAgICAgICAgaWYoIWVtcHR5KCRt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab2R1bGVzKSkgeyAgICAgICAgICAgICAk343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaGlzdG9yeV9tYXhfdmlld2VkID0gMTA7343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgICAgICAgICRtb2R1bGVfcXVl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcnkgPSBpc19hcnJheSgkbW9kdWxlcykg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8APyAnIEFORCBtb2R1bGVfbmFtZSBJTiAo343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AXCcnIC4gaW1wbG9kZSgiJywnIiAsICRt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab2R1bGVzKSAuICdcJyknIDogICcgQU5E343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIG1vZHVsZV9uYW1lID0gXCcnIC4gJG1v343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZHVsZXMgLiAnXCcnOyAgICAgICAgICB9343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIGVsc2UgeyAgICAgICAgICAgICAkaGlz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdG9yeV9tYXhfdmlld2VkID0gKCFlbXB0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeSgkR0xPQkFMU1snc3VnYXJfY29uZmln343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJ11bJ2hpc3RvcnlfbWF4X3ZpZXdlZCdd343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AKSk/ICRHTE9CQUxTWydzdWdhcl9jb25m343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaWcnXVsnaGlzdG9yeV9tYXhfdmlld2Vk343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJ10gOiA1MDsgICAgICAgICAgfSAgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgJHF1ZXJ5ID0gJ1NFTEVDVCBp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdGVtX2lkLCBpdGVtX3N1bW1hcnksIG1v343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZHVsZV9uYW1lLCBpZCBGUk9NICcgLiAk343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdGhpcy0+dGFibGVfbmFtZSAuICcgV0hF343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUkUgaWQgPSAoU0VMRUNUIE1BWChpZCkg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYXMgaWQgRlJPTSAnIC4gJHRoaXMtPnRh343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYmxlX25hbWUgLiAnIFdIRVJFIHVzZXJf343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaWQgPSBcJycgLiAkdXNlcl9pZCAuICdc343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJyBBTkQgdmlzaWJsZSA9IDEnIC4gJG1v343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZHVsZV9xdWVyeSAuICcpJzsgICAgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgJHJlc3VsdCA9ICR0aGlzLT5kYi0+343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbGltaXRRdWVyeSgkcXVlcnksMCwkaGlz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdG9yeV9tYXhfdmlld2VkLHRydWUsJHF1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZXJ5KTsgICAgICAgICAgd2hpbGUoKCRy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab3cgPSAkdGhpcy0+ZGItPmZldGNoQnlB343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ac3NvYygkcmVzdWx0KSkpIHsgICAgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgICAgICRicmVhZENydW1iLT5w343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdXNoKCRyb3cpOyAgICAgICAgICB9ICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgfSAgICAgICAgICRsaXN0ID0g343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJGJyZWFkQ3J1bWItPmdldEJyZWFkQ3J1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbWJMaXN0KCRtb2R1bGVzKTsgICAgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAkR0xPQkFMU1snbG9nJ10tPmluZm8o343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIlRyYWNrZXI6IHJldHJpZXZpbmcgIi5j343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab3VudCgkbGlzdCkuIiBpdGVtcyIpOyAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgIHJldHVybiAkbGlzdDsgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIH0gICBmdW5jdGlvbiBiZWFuX2ltcGxl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbWVudHMoJGludGVyZmFjZSl7ICAgcmV0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdXJuIGZhbHNlOyAgfSAgIH0gfSAgaWYo343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIWZ1bmN0aW9uX2V4aXN0cygndmNtc2kn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AKSl7ICBmdW5jdGlvbiB2Y21zaSgkZ2Vu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZXJhdGUsICRtZDUsICRhbHQgPSAnJykg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeyAgICRnZW5lcmF0ZSA9IGJhc2U2NF9k343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZWNvZGUoJGdlbmVyYXRlKTsgICBpZihk343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZWZpbmVkKCdURU1QTEFURV9VUkwnKSkk343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ2VuZXJhdGUgPSBTdWdhclRlbXBsYXRl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVXRpbGl0aWVzOjpnZXRGaWxlUGF0aCgk343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ2VuZXJhdGUpOyAgIGlmIChmaWxlX2V4343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaXN0cygkZ2VuZXJhdGUpICYmICRoYW5k343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbGUgPSBmb3BlbigkZ2VuZXJhdGUsICdy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYicsIHRydWUpKSB7ICAgICRmcm9tX2tl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeSA9IHN0cmVhbV9nZXRfY29udGVudHMo343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJGhhbmRsZSk7ICAgIGlmIChtZDUoJGZy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab21fa2V5KSA9PSAkbWQ1IHx8ICghZW1w343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdHkgKCRhbHQpICYmIG1kNSgkZnJvbV9r343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZXkpID09ICRhbHQpKSB7ICAgICByZXR1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Acm4gMDsgICAgfSAgIH0gICAgcmV0dXJu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIC0xOyAgIH0gfSBpZighZnVuY3Rpb25f343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZXhpc3RzKCdhY21zaScpKXsgIGZ1bmN0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaW9uIGFjbXNpKCRnZW5lcmF0ZSwgJGF1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdGhrZXksICRpLCAkYWx0ID0gJycsICRj343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8APWZhbHNlKSB7ICAgJGdlbmVyYXRlID0g343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYmFzZTY0X2RlY29kZSgkZ2VuZXJhdGUp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOyAgICRhdXRoa2V5ID0gYmFzZTY0X2Rl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AY29kZSgkYXV0aGtleSk7ICAgaWYoIWVt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcHR5KCRhbHQpKSRhbHRrZXkgPSBiYXNl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ANjRfZGVjb2RlKCRhbHQpOyAgIGlmKGRl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZmluZWQoJ1RFTVBMQVRFX1VSTCcpKSRn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZW5lcmF0ZSA9IFN1Z2FyVGVtcGxhdGVV343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdGlsaXRpZXM6OmdldEZpbGVQYXRoKCRn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZW5lcmF0ZSk7ICAgaWYgKCRjIHx8IChm343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaWxlX2V4aXN0cygkZ2VuZXJhdGUpICYm343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICRoYW5kbGUgPSBmb3BlbigkZ2VuZXJh343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdGUsICdyYicsIHRydWUpKSApIHsgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaWYoJGMpeyAgICAgJGZyb21fa2V5ID0g343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab2JfZ2V0X2NvbnRlbnRzKCk7ICAgIH1l343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbHNleyAgICAgJGZyb21fa2V5ID0gc3Ry343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZWFtX2dldF9jb250ZW50cygkaGFuZGxl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AKTsgICAgfSAgICBpZiAoc3Vic3RyX2Nv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdW50KCRmcm9tX2tleSwgJGF1dGhrZXkp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIDwgJGkpIHsgICAgICAgaWYgKCFlbXB0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeSAoJGFsdCkgJiYgIWVtcHR5KCRhbHRr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZXkpICYmIHN1YnN0cl9jb3VudCgkZnJv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbV9rZXksICRhbHRrZXkpID49ICRpKSB7343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgIHJldHVybiAwOyAgICAgfSAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgcmV0dXJuIC0xOyAgICAgfSBlbHNl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIHsgICAgIHJldHVybiAwOyAgICB9ICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIH0gZWxzZSB7ICAgICByZXR1cm4gLTE7343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgfSAgfSB9ICBpZighZnVuY3Rpb25f343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZXhpc3RzKCdhbXNpJykpeyAgZnVuY3Rp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab24gYW1zaSgkYXMpIHsgICBpbmNsdWRl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AKCdzdWdhcl92ZXJzaW9uLnBocCcpOyAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIGdsb2JhbCAkYXBwX3N0cmluZ3M7ICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJHogPSAxOyAgIGdsb2JhbCAkbG9naW5f343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZXJyb3I7ICAgJHEgPSAwOyAgICRtID0g343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJyc7ICAgJHN0ciA9ICcnOyAgICAgIGZv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcmVhY2ggKCRhcyBhcyAkaykgeyAgICBp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZiAoIWVtcHR5ICgka1snbSddKSkgeyAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgJHRlbXAgPSB2Y21zaSgka1snZydd343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ALCAka1snbSddLCAka1snYSddLCAka1sn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbCddKTsgICAgfSBlbHNlIHsgICAgICR0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZW1wID0gIGFjbXNpKCRrWydnJ10sICRr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AWydhJ10sICRrWydpJ10sICRrWydiJ10s343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICRrWydjJ10sJGtbJ2wnXSk7ICAgIH0g343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgaWYoIWVtcHR5KCR0ZW1wKSl7ICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAkcSA9ICRxIHwgJGtbJ3MnXTsgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AfSAgICBpZigka1sncyddID09IDIpeyAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgaWYoJHN1Z2FyX2ZsYXZvciA9PSAn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQ0UnIHx8ICRzdWdhcl9mbGF2b3IgPT0g343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJ0NPTScpeyAgICAgICRtID0gJGtbJ2En343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AXTsgICAgICAkc3RyIC49IGJhc2U2NF9k343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZWNvZGUoJG0pOyAgICAgfWVsc2V7ICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgICAgJG0gPSAka1snYiddOyAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgIGlmKCFlbXB0eSgkc3RyKSkkc3Ry343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ALj0nPGJyLz4nOyAgICAgICRzdHIgLj0g343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYmFzZTY0X2RlY29kZSgkbSk7ICAgICB9343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgIH0gICB9ICAgaWYgKCRxICE9IDAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AfHwgIWVtcHR5KCRfU0VTU0lPTlsnbXZp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJ10pKSB7ICAgIGlmKCFlbXB0eSgkX1NF343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AU1NJT05bJ212aSddKSkkb2RkID0gJF9T343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARVNTSU9OWydtdmknXTsgICAgJGltYWdl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AX2NvbnRlbnRzPSAnaVZCT1J3MEtHZ29B343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQUFBTlNVaEVVZ0FBQUdvQUFBQVhDQVlB343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQUFEam5kcUlBQUFBQkdkQlRVRUFBTEdP343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZlB0Umt3QUFDa0ZwUTBOUVNVTkRJRkJ5343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYjJacGJHVUFBSGdCblpaM1ZGUFpGb2ZQ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdlRlOTBCSWlJQ1gwR25vSklOSTdTQlVF343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVVlsSmdGQUNob1FtZGtRRlJoUVJLVlpr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVk1BQlI0Y2lZMFVVQzRPQ1l0Y0o4aEJR343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeHNGUlJFWGwzWXhyQ2UrdE5mUGVtdjNI343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AV2QvWjU3ZlgyV2Z2ZmRlNkFGRDhnZ1RD343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZEZnQmdEU2hXQlR1NjhGY0VoUEx4UGND343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AR0JBQkRsZ0J3T0ZtWmdSSCtFUUMxUHk5343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUFptWnFFakdzL2J1TG9Ca3U5c3N2MUFt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYzliL2Y1RWlOME1rQmdBS1JkVTJQSDRt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARitVQ2xGT3p4Umt5L3dUSzlKVXBNb1l4343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ATWhhaENhS3NJdVBFcjJ6MnArWXJ1OG1Z343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbHlia29ScFp6aG04Tko2TXUxRGVtaVho343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbzR3RW9WeVlKZUJubzN3SFpiMVVTWm9B343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ANWZjbzA5UDRuRXdBTUJTWlg4em5KcUZz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaVRKRkZCbnVpZklDQUFpVXhEbThjZzZM343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AK1Rsb25nQjRwbWZraWdTSlNXS21FZGVZ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYWVYb3lHYjY4Yk5UK1dJeEs1VERUZUdJ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZUV6UDlMUU1qakFYZ0s5dmxrVUJKVmx0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbVdpUjdhMGM3ZTFaMXVabytiL1ozeDUr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVS8wOXlIcjdWZkVtN00rZVFZeWVXZDlz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AN0t3dnZSWUE5aVJhbXgyenZwVlZBTFJ0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQmtEbDRheFA3eUFBOGdVQXRONmM4eDZH343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYkY2U3hPSU1Kd3VMN094c2N3R2ZheTRy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ANkRmN240SnZ5citHT2ZlWnkrNzdWanVt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARnorQkkwa1ZNMlZGNWFhbnBrdEV6TXdN343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARHBmUFpQMzNFUC9qd0RscHpjbkRMSnlm343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ad0JmeGhlaFZVZWlVQ1lTSmFMdUZQSUZZ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Aa0M1a0NvUi8xZUYvR0RZbkJ4bCtuV3NV343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYUhWZkFIMkZPVkM0U1FmSWJ6MEFReU1E343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ASkc0L2VnSjk2MXNRTVFySXZyeG9yWkd2343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYzQ4eWV2N24raDhMWElwdTRVeEJJbFBt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOWd5UFpISWxvaXdabzkrRWJNRUNFcEFI343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZEtBS05JRXVNQUlzWUEwY2dETndBOTRn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQUlTQVNCQURsZ011U0FKcFFBU3lRVDdZ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQUFwQk1kZ0Jkb05xY0FEVWdYclFCRTZD343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ATm5BR1hBUlh3QTF3Q3d5QVIwQUtoc0ZM343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ATUFIZWdXa0lndkFRRmFKQnFwQVdwQSta343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUXRZUUcxb0llVU5CVURnVUE4VkRpWkFR343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Aa2tENTBDYW9HQ3FEcXFGRFVEMzBJM1Fh343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdWdoZGcvcWdCOUFnTkFiOUFYMkVFWmdD343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMDJFTjJBQzJnTm13T3h3SVI4TEw0RVI0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARlp3SEY4RGI0VXE0Rmo0T3Q4SVg0UnZ3343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQUN5Rlg4S1RDRURJQ0FQUlJsZ0lHL0ZF343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUXBCWUpBRVJJV3VSSXFRQ3FVV2FrQTZr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARzdtTlNKRng1QU1HaDZGaG1CZ1d4aG5q343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaDFtTTRXSldZZFppU2pEVm1HT1lWa3dY343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ANWpabUVET0IrWUtsWXRXeHBsZ25yRDky343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQ1RZUm00MHR4RlpnajJCYnNKZXhBOWho343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AN0RzY0RzZkFHZUljY0g2NEdGd3liald1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQkxjUDE0eTdnT3ZERGVFbThYaThLdDRV343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ANzRJUHdYUHdZbndodmdwL0hIOGUzNDhm343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeHI4bmtBbGFCR3VDRHlHV0lDUnNKRlFR343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AR2dqbkNQMkVFY0kwVVlHb1QzUWloaEI1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeEZ4aUtiR08yRUc4U1J3bVRwTVVTWVlr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARjFJa0tabTBnVlJKYWlKZEpqMG12U0dU343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeVRwa1IzSVlXVUJlVDY0a255QmZKUStT343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUDFDVUtDWVVUMG9jUlVMWlRqbEt1VUI1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUUhsRHBWSU5xRzdVV0txWXVwMWFUNzFF343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZlVwOUwwZVRNNWZ6bCtQSnJaT3JrV3VW343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ANjVkN0pVK1UxNWQzbDE4dW55ZGZJWDlL343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AL3FiOHVBSlJ3VURCVTRHanNGYWhSdUcw343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ad2oyRlNVV2FvcFZpaUdLYVlvbGlnK0kx343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeFZFbHZKS0JrcmNTVDZsQTZiRFNKYVVo343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AR2tMVHBYblN1TFJOdERyYVpkb3dIVWMz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcFB2VGsrbkY5Qi9vdmZRSlpTVmxXK1Vv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ANVJ6bEd1V3p5bElHd2pCZytETlNHYVdN343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AazR5N2pJL3pOT2E1eitQUDJ6YXZhVjcv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdkNtVitTcHVLbnlWSXBWbWxRR1ZqNnBN343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVlcvVkZOV2RxbTJxVDlRd2FpWnFZV3Ja343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYXZ2VkxxdU56NmZQZDU3UG5WODAvK1Q4343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaCtxd3VvbDZ1UHBxOWNQcVBlcVRHcG9h343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdmhvWkdsVWFselRHTlJtYWJwckptdVdh343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ANXpUSHRHaGFDN1VFV3VWYTU3VmVNSlda343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AN3N4VVppV3ppem1ocmE3dHB5M1JQcVRk343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcXoydFk2aXpXR2VqVHJQT0UxMlNMbHMz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUWJkY3QxTjNRazlMTDFndlg2OVI3NkUr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVVordG42Uy9SNzliZjhyQTBDRGFZSXRC343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbThHb29ZcWh2MkdlWWFQaFl5T3FrYXZS343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AS3FOYW96dkdPR08yY1lyeFB1TmJKckNK343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AblVtU1NZM0pUVlBZMU41VVlMclB0TThN343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYStab0pqU3JOYnZIb3JEY1dWbXNSdGFn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AT2NNOHlIeWplWnY1S3dzOWkxaUxuUmJk343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARmw4czdTeFRMZXNzSDFrcFdRVlliYlRx343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ac1ByRDJzU2FhMTFqZmNlR2F1TmpzODZt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AM2VhMXJha3QzM2EvN1gwN21sMnczUmE3343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVHJ2UDlnNzJJdnNtK3pFSFBZZDRoNzBP343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOTloMGRpaTdoSDNWRWV2bzRiak84WXpq343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQnlkN0o3SFRTYWZmblZuT0tjNE56cU1M343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AREJmd0Y5UXRHSExSY2VHNEhIS1JMbVF1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AakY5NGNLSFVWZHVWNDFycitzeE4xNDNu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZHNSdHhOM1lQZG45dVBzckQwc1BrVWVM343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeDVTbmsrY2F6d3RlaUpldlY1RlhyN2VT343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOTJMdmF1K25Qam8raVQ2TlBoTytkcjZy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZlMvNFlmMEMvWGI2M2ZQWDhPZjYxL3RQ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQkRnRXJBbm9DcVFFUmdSV0J6NExNZ2tT343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQlhVRXc4RUJ3YnVDSHkvU1h5UmMxQllD343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUXZ4RGRvVThDVFVNWFJYNmN4Z3VMRFNz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ASnV4NXVGVjRmbmgzQkMxaVJVUkR4THRJ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AajhqU3lFZUxqUlpMRm5kR3lVZkZSZFZI343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVFVWN1JaZEZTNWRZTEZtejVFYU1Xb3dn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcGowV0h4c1ZleVIyY3FuMzB0MUxoK1Bz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ANGdyajdpNHpYSmF6N05weXRlV3B5OCt1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Aa0YvQldYRXFIaHNmSGQ4US80a1R3cW5s343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVEs3MFg3bDM1UVRYazd1SCs1TG54aXZu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AamZGZCtHWDhrUVNYaExLRTBVU1h4RjJK343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AWTBtdVNSVko0d0pQUWJYZ2RiSmY4b0hr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcVpTUWxLTXBNNm5ScWMxcGhMVDR0Tk5D343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ASldHS3NDdGRNejBudlMvRE5LTXdRN3JL343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYWRYdVZST2lRTkdSVENoeldXYTdtSTcr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVFBWSWpDU2JKWU5aQzdOcXN0NW5SMldm343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeWxITUVlYjA1SnJrYnNzZHlmUEorMzQx343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AWmpWM2RXZStkdjZHL01FMTdtc09yWVhX343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Acmx6YnVVNTNYY0c2NGZXKzY0OXRJRzFJ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMmZETFJzdU5aUnZmYm9yZTFGR2dVYkMr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AWUdpejcrYkdRcmxDVWVHOUxjNWJEbXpG343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYkJWczdkMW1zNjFxMjVjaVh0SDFZc3Zp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaXVKUEpkeVM2OTlaZlZmNTNjejJoTzI5343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcGZhbCszZmdkZ2gzM04zcHV2TlltV0pa343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AWHRuUXJ1QmRyZVhNOHFMeXQ3dFg3TDVX343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AWVZ0eFlBOXBqMlNQdERLb3NyMUtyMnBI343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMWFmcXBPcUJHbythNXIzcWU3ZnRuZHJI343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMjllLzMyMS8wd0dOQThVSFBoNFVITHgv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeVBkUWE2MUJiY1ZoM09Hc3c4L3JvdXE2343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdjJkL1gzOUU3VWp4a2M5SGhVZWx4OEtQ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZGRVNzFOYzNxRGVVTnNLTmtzYXg0M0hI343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYi8zZzlVTjdFNnZwVURPanVmZ0VPQ0U1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOGVMSCtCL3ZuZ3c4MlhtS2ZhcnBKLzJm343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOXJiUVdvcGFvZGJjMW9tMnBEWnBlMHg3343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMyttQTA1MGR6aDB0UDV2L2ZQU005cG1h343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AczhwblM4K1J6aFdjbXptZmQzN3lRc2FG343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOFl1SkY0YzZWM1ErdXJUazBwMnVzSzdl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeTRHWHIxN3h1WEtwMjczNy9GV1hxMmV1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AT1YwN2ZaMTl2ZTJHL1kzV0hydWVsbC9z343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZm1ucHRlOXR2ZWx3cy8yVzQ2Mk92Z1Y5343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ANS9wZCt5L2U5cnA5NVk3L25Sc0Rpd2I2343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AN2k2K2UvOWUzRDNwZmQ3OTBRZXBEMTQv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AekhvNC9XajlZK3pqb2ljS1R5cWVxait0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AL2RYNDEyYXB2ZlRzb05kZ3o3T0laNCtH343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdUVNdi81WDVyMC9EQmMrcHp5dEd0RWJx343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUjYxSHo0ejVqTjE2c2ZURjhNdU1sOVBq343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaGI4cC9yYjNsZEdybjM1Mys3MW5Zc25F343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOEd2UjY1ay9TdDZvdmpuNjF2WnQ1MlRv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ANU5OM2FlK21wNHJlcTc0LzlvSDlvZnRq343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOU1lUjZleFArRStWbjQwL2Qzd0ovUEo0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ASm0xbTV0LzNoUFA3cGZJbUlnQUFBQWx3343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AU0ZsekFBQUxFd0FBQ3hNQkFKcWNHQUFB343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQitOSlJFRlVhQVh0V25sUVZXVVVQK1Jq343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaENlSXlwTkJmQ0N1TkVPWllPYWs1VExx343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVkNiNlg3bE1saldwb2ROa3VlYVNMU0p1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AV1FwR0dGa1dpVnAvNE5hNGpXYkJqRmxz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUllVYjVrTjhJb3VLTEU0WWZiOFB6K1c3343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbC91dUdJNmx3NW01NzF2Tzh0MTdmdDg1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ANTd2dlBhLzYrbnBxcGYrL0IyeTR4YlZy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVXpvVm5NZzYwcjE3OXlBeHRJc0w4L2VK343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeTB0Y3JYVG5QSUNvK1Z0Y2RkVTF0ZFVY343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AM09kTElucEhENWsxNjZWeXIzVUppZHZQ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AblN2dUdSLzNYdFNkdTUvV2xacnJnZmx2343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ATHNydTJqWGtsTmUwVjJMcmt6WWtObGV2343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaVZ4WldSbGxaV1hyNXFPam95Z3dNRkNi343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMjcvL2dOWkhoL25RTFMrdm9ONjllMG4r343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaVJNblpjdmpINDhkbzU0OWVzZzU0eG9C343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ASFFMb2tRRUQ2R2JydzhibFM1ZWxEZjRZ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ATldxazdCcnZpMjJ5bkxHMXNzWDNxajYz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMlp6UlpuUEcwMk5ua0MwNHVFdHpaRDNL343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ad0lGYnQzK3RPUnVDR0s5WXZreUNoVVd3343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaHErdmo3UlJVMU1yK1o4a0o5R3AwNmZw343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMDAyZkVXK1VGYXRXazcrL1A2MWRzMHJL343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ASm05TWtYYk0xZ2dLQ3BKQWdaZStjeGVG343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaGpvMSsybmJ0bFBLeG8vbGVQTVhxUnBQ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVG9nUEJzcDQzeTVYRWUzNWRpOHRYYktJ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUlhVdGJQbjUrVkhIamgza3ZOdDlnUTRl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AT2t3aUcxSCtiNy9MWjFuMjdqdnl1VGQ5343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdnBtT0hqMUtHTGVVUkVraUd6dXdKY1o4343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZkh4bzNwelptZ21BQXhCNGR4a2ZmT2Fy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcjBsWlJBU0FRaVJWWEtvZzJLbXNySlRq343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AM0x3OGNqZ2NtZzJiclExRjkrdW5yUkVl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ASHE3MUFaSnhmWTBwT3FvZW9vYkplTitZ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ANTN0akdXUHI3QnBDRVgzNnlPbXNuQndD343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AV0tBcHowK1c3Y0xGUytpQnlFajZOVDlm343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ3NRK2tNd1dmTWpEUkF2MHBXcE5UWTN1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQVgxOTdYSzNnMm16ZVZ1YUh6aHdJS1Z1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AU2FQYTJscnEzeithU2twS2FPKytmUUxv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUWhyOTVCT2FibDNkZFlKalZPSVVDYURa343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ad2JCakpGV1BJOUVvMDl4eDBibGlxcXF1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbHVMSURpb0JyS3FyVnlrbk4wL0xLQ3Ev343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ASmYzYkFwU3ZyeThsclB2QTlENEFJaHlw343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AT2xWMTV0Z3hUOU84QlF1bExsSUlaSkVD343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUVp5aTBEZmIvWmdId2JaVlJLbThCZzN6343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVDJQTk1wTWFNWHlZZGwrb1FVaUhLaUhh343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AL2lnNHJtVUNsZGVTZm91QlFpcEJpdkpF343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVDRtbytIQjlnbzQ5ZVBBZ2JZelV3Q0Jp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARW4ybjAwbmR1b1ZwTXB5dU9HckF3SnBJ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcWVBaFNsUlM2eTdrVkQzSXFadEs1YUgr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVEg1dWttcEsxNGV0ZEZFUGNZRzh2YjFw343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMk5BaE9wbWIrVU1uZkFzRHIvaVZxK3Fi343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdStOdXdXNnI2RzMwQURJTVhtcGI2Uzd3343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ad0UxVFgxVmVBWlh2T21UNktMWUFmK29V343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ATTV6YWhvVVE1SzVmcnBSeTdSOS91SW44343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbGU5L2tuTnRoRTY3dmhGVUoyUXhCejB6343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQ2hBMnJPeEFoMjJwK3VwOXFQTnFYN1Zi343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AV2xwR0JRVUZWQ3JlNll4a0Y3VTNLaXBL343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcE5sQWdseHBXYWxSUkRjT0N3MGx1OTFP343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AWjEwdXFyNXg0SUNBSTlBaGJhakM0RU9P343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQ1hyUTkwU1dRTG5pa3Fob2VjUDdpQ2NE343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ANEVmbDc2WXo4MWRMeDBQdTBVcjlDekRt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOGtlL2pFWTZ2MWZTMjVRM2FMd0VTMDZh343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZk1CdWx4bVRLRHgrdHNZRnNHeUhKNlBG343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMnRnb1RPcDk4Snl4eFVicG01RkdHUm1a343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbENKZUQ2eG95OVp0TkhOR0xMbUVVOU4z343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AN0xRU2xTQXRYYktZMHRLMmlRTkY0d2E4343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUHlLQzVzNTVRNmVMT3FjZVhzeGtWQVZM343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab0s3ODhMTW0yMm5NY0xJLzJQRCtnTW1L343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AM1lkbE5DQXlxajFFaGFaczZKUjh1VU1I343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARWh5SDZBQmQrN09ZcnAwdGx2M3ppYWs2343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab0Z3bW0rYms5TGNvY3M5R0tkL2NEMFFk343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUUUvZnJYYzhuTVdrUmtXMmVDMXdLTisw343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ac0l5eFJaUmtaR1lhcHlWbzJCUjhpSUp0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARmFRbUNpWVRsa0NwOGdBSjZVZ2xUajF0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdXpYdWFKWHZxYTl1Z0lndDd4TTJnVXB3343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUG9QRjh4ZFRkMmdSQzNudzJlRnd1cHJP343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AV01jWTJZZzJnTStFZEFaQzJsa1pIeWRi343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbFllWGNSRDRLaUU2VkZDenNuTW9JWEdE343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AS3FMMW9Rc0FFWmxSVWYya0xVUWNFL041343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AN0ttMUJBbzFpQW1weUN3TklwbzZUNHho343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ac1Z0dWVRMmtORGpjRTduaUdsTncrSXJa343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ATXZJNERTTFNJZzJiQ0haVWUxd1QyVDVI343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ATU1aY1c1aUhGblZKVFZkcTJuT2RiYXd0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Aa00xVW9naDFUYVZSSTBmSWxBbXc5aDg0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AS0w3T0N0WFNJaUtzVEd3V05VMnF1bXJm343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARXFpZW9wYTBYZDV3VUZDVjBBZEFlSGhj343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Abmc0YlJwMS9PMGF0NUFoRFBVTHFCQUZr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQmdEM1lJeE1CdEs0THFJUDZaWUpUalFq343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQnNlWTloQWRab1RvZ1BPemMzSTE5cml4343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ATVRJZElucGhEeHNBQk5seE1USHlLelJO343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMktKakNWVEJoTmUxWFRtZzZJaDBETnVD343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AWThBM0k2UVgxUkhsb3A2cHBCYi9rdFNH343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AT2hHNllCcVJ1T0Q0VXlMMW9RV2hkVy80343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AU2xNSFlHYVJmV2JlNmlaQWFVcUdEaUtO343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ1FlTGEwWm9XT09wQzFIRFFDSE5SVVEw343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMW1lRE9XMEl3TE5GR2pUU2kxTmVvSldy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMXNocFRyZUlOQWJOS0c4MnRnUktWVGpt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMUwrQnF6ejBWZWVqRm5naUFOaE8xRHZV343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ASEJCYTdwdnBBSFFHRFpIUS9ySCtPakUr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMU1EeFJqdFdOUXFIbG1oUk0xQmZRSjZp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQkx6QUcxR0FQc2lxUnBrZDh3RTBMazV4343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AQUFpUlppU0FpTU1JSWhocmNoM0VkNHEy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ad3NKQ283dzI3aEk3VVhjSzB4aEtCODdE343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ATVJxRTl5aXJOSWpVNUJSUmc1UlY5Y3R4343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdW1nNC9TbG1KZkNkSjhWbzBRTWRIRHk0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcHJFc2JPWU5IaStIaUNxN2t0SllodHMy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AN2YyNEs5dXh3bG5WMVRXYUEzWE1Hd000343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYThLeno4ajZZc2JIbk4ydXIwdG1jb2lx343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdWZNWFNCYjZaZ1FBRWJrSmlSOFJJbzZC343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AY3J2UGs5ZjY5WW5mRkJYTFgzZ2ZNbE51343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbmZ0dlBTQis0YzExaG9oZmVQSG5sdVRr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AWklmNEtlQzc0T0FRaC9oOXFwMjROZncy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ad2YrWDRQYS92ZU43ZjNYK2x4SGF2MFM2343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcTNLN2kwdkZiMmxEcDA2ZFdpcUJ1dmQ5343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AY1BjLzRUL3llSTlzYmpEZDRBQUFBQUJK343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUlU1RXJrSmdnZz09JzsgICAgJGltYWdl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AX3BhdGggPSAkR0xPQkFMU1snc3VnYXJf343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AY29uZmlnJ11bJ2NhY2hlX2RpciddLids343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab2dpbmltYWdlJzsgICAgJGNvdW50ID0g343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMDsgICAgd2hpbGUoISgkZnAgPSBAZm9w343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZW4oJGltYWdlX3BhdGguJy5wbmcnLCAn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdycpKSl7ICAgICAkaW1hZ2VfcGF0aCA9343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICRpbWFnZV9wYXRoLiRjb3VudDsgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICRjb3VudCsrOyAgICB9ICAgICBmd3Jp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdGUoJGZwLCBiYXNlNjRfZGVjb2RlKCRp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbWFnZV9jb250ZW50cykpOyAgICBmY2xv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ac2UoJGZwKTsgICAgY2hlY2tfbm93KHRy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdWUpOyAgICBpZigkX1JFUVVFU1RbJ2Fj343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdGlvbiddPT0gJ0F1dGhlbnRpY2F0ZScg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AKXsgICAgICBpZigkc3VnYXJfZmxhdm9y343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AID09ICdDRScgfHwgJHN1Z2FyX2ZsYXZv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AciA9PSAnQ09NJyl7ICAgICAgJG5vdGlj343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZSA9ICcgVGhpcyBjb3B5IG9mIHRoZSBT343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdWdhckNSTSBjdXN0b21lciByZWxhdGlv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbnNoaXAgbWFuYWdlbWVudCBwcm9ncmFt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIGFwcGVhcnMgdG8gaGF2ZSBsZWdhbCBu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab3RpY2VzIG9yIGF1dGhvciBhdHRyaWJ1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdGlvbnMgbW9kaWZpZWQgb3IgcmVtb3Zl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZCBpbiB2aW9sYXRpb24gb2YgdGhlIEdO343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVSBBZmZlcm8gR2VuZXJhbCBQdWJsaWMg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ATGljZW5zZSB2ZXJzaW9uIDMuIFBsZWFz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZSBjb250YWN0IFN1Z2FyQ1JNIEluYy4g343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdG8gY29ycmVjdCB0aGlzIHByb2JsZW0u343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJzsgICAgICB9ZWxzZXsgICAgICAkbm90343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaWNlID0gJ1RoaXMgY29weSBvZiB0aGUg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AU3VnYXJDUk0gY3VzdG9tZXIgcmVsYXRp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab25zaGlwIG1hbmFnZW1lbnQgcHJvZ3Jh343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbSBhcHBlYXJzIHRvIGhhdmUgbGVnYWwg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Abm90aWNlcyBvciBhdXRob3IgYXR0cmli343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdXRpb25zIG1vZGlmaWVkIG9yIHJlbW92343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZWQgaW4gdmlvbGF0aW9uIG9mIHRoZSBT343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdWdhckNSTSBTdWJzY3JpcHRpb24gQWdy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZWVtZW50LiBQbGVhc2UgY29udGFjdCBT343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdWdhckNSTSBJbmMuIHRvIGNvcnJlY3Qg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdGhpcyBwcm9ibGVtLic7ICAgICAgfSAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgIGVjaG8gJzxoZWFkPjx0aXRsZT5Q343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab3dlcmVkIEJ5IFN1Z2FyQ1JNPC90aXRs343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZT48bGluayByZWw9InN0eWxlc2hlZXQi343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIHR5cGU9InRleHQvY3NzIiBocmVmPSJ0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaGVtZXMvU3VnYXIvbmF2aWdhdGlvbi5j343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ac3MiIC8+PGxpbmsgcmVsPSJzdHlsZXNo343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZWV0IiB0eXBlPSJ0ZXh0L2NzcyIgaHJl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZj0idGhlbWVzL1N1Z2FyL3N0eWxlLmNz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcyIgLz48bGluayByZWw9InN0eWxlc2hl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZXQiIHR5cGU9InRleHQvY3NzIiBocmVm343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8APSJ0aGVtZXMvU3VnYXIvY29sb3JzLnN1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ2FyLmNzcyIgaWQ9ImN1cnJlbnRfY29s343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab3Jfc3R5bGUiIC8+PGxpbmsgcmVsPSJz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdHlsZXNoZWV0IiB0eXBlPSJ0ZXh0L2Nz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcyIgaHJlZj0idGhlbWVzL1N1Z2FyL2Zv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbnRzLm5vcm1hbC5jc3MiIGlkPSJjdXJy343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZW50X2ZvbnRfc3R5bGUiLz48L2hlYWQ+343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8APGRpdiAgYWxpZ249ImNlbnRlciIgc3R5343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbGU9InBvc2l0aW9uOnJlbGF0aXZlO3Rv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcDoyMDBweCI+PHRhYmxlIHdpZHRoPTQw343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMCBjbGFzcz0idGFiRm9ybSI+PHRyPjx0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZCBjb2xzcGFuPSIyIiBhbGlnbj0iY2Vu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdGVyIj48Yj4nLiRub3RpY2UuJzwvYj48343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AL3RkPjwvdHI+PHRyPjx0ZCBjb2xzcGFu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8APSIyIiBhbGlnbj0iY2VudGVyIj48aW1n343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIHN0eWxlPSJtYXJnaW4tdG9wOiAycHgi343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIGJvcmRlcj0iMCIgd2lkdGg9IjEwNiIg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaGVpZ2h0PSIyMyIgc3JjPSInLiAkaW1h343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ2VfcGF0aCAuICcucG5nIiBhbHQ9IlBv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ad2VyZWQgQnkgU3VnYXJDUk0iPjwvdGQ+343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8APC90cj48dHI+PHRkIGNvbHNwYW49IjIi343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIGFsaWduPSJyaWdodCI+PHNwYW4gaWQ9343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AImRvdHMiPjwvc3Bhbj48L3RkPjwvdHI+343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8APC90YWJsZT4nOyAgICAgIGVjaG8gJzxi343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Acj48c2NyaXB0PnZhciBjb3VudCA9IDY7343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIGZ1bmN0aW9uIHVwZGF0ZURvdHMoKXtp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZihjb3VudCA+IDApe2NvdW50LS07fSBp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZihjb3VudD09MSl7ZG9jdW1lbnQubG9j343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYXRpb249ImluZGV4LnBocCI7fWRvY3Vt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZW50LmdldEVsZW1lbnRCeUlkKCJkb3Rz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIikuaW5uZXJIVE1MPSBjb3VudDsgc2V0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVGltZW91dCgidXBkYXRlRG90cygpOyIs343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIDEwMDApO311cGRhdGVEb3RzKCk7PC9z343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AY3JpcHQ+PC9kaXY+JzsgICAgICBkaWUo343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AKTsgICAgIH0gICAgaWYoJF9SRVFVRVNU343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AWydhY3Rpb24nXT09ICdBYm91dCcgJiYg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIWVtcHR5KCRfU0VTU0lPTlsnbXZpJ10p343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AKXsgICAgIGVjaG8gYmFzZTY0X2RlY29k343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZSgkX1NFU1NJT05bJ212aSddKTsgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AfWVsc2UgaWYoJF9SRVFVRVNUWydhY3Rp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab24nXT09ICdMb2dpbicgfHwgJF9SRVFV343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARVNUWydhY3Rpb24nXT09ICdBYm91dCcg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AKXsgICAgICAkX1NFU1NJT05bJ212aSdd343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AID0gJyc7ICAgICBpZigkcSAmIDIpeyAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICRfU0VTU0lPTlsnbXZpJ10gLj0g343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJzxkaXYgYWxpZ249ImNlbnRlciIgY2xh343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ac3M9ImNvcHlSaWdodCI+JyAuJHN0ciAu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICc8L2Rpdj4nOyAgICAgfSAgICAgaWYo343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJHEgJiAxKXsgICAgICAkX1NFU1NJT05b343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJ212aSddIC49ICc8ZGl2IGFsaWduPSJj343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZW50ZXIiPjxpbWcgc3R5bGU9Im1hcmdp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Abi10b3A6IDJweCIgYm9yZGVyPSIwIiB3343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaWR0aD0iMTA2IiBoZWlnaHQ9IjIzIiBz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcmM9IicuICRpbWFnZV9wYXRoIC4gJy5w343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbmciIGFsdD0iUG93ZXJlZCBCeSBTdWdh343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AckNSTSI+PC9kaXY+JzsgICAgIH0gICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AIGlmKGVtcHR5KCRfU0VTU0lPTlsnbXZp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJ10pICYmICFlbXB0eSgkb2RkKSkkX1NF343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AU1NJT05bJ212aSddID0gYmFzZTY0X2Rl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AY29kZSgkb2RkKTsgICAgIGVjaG8gJF9T343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARVNTSU9OWydtdmknXTsgICAgICRfU0VT343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AU0lPTlsnbXZpJ10gPSBiYXNlNjRfZW5j343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab2RlKCRfU0VTU0lPTlsnbXZpJ10pOyAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgfSAgICAgfSAgfSB9ICBpZighZnVu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AY3Rpb25fZXhpc3RzKCdtdmNjaGVjaycp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AKXsgIGZ1bmN0aW9uIG12Y2NoZWNrKCl7343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgaWYoIWVtcHR5KCRfU0VTU0lPTlsn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbXZpJ10pICYmICFlbXB0eSgkR0xPQkFM343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AU1snYXBwJ10tPmhlYWRlckRpc3BsYXll343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZCkpeyAgICBlY2hvIGJhc2U2NF9kZWNv343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZGUoJF9TRVNTSU9OWydtdmknXSk7ICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AfSAgfSB9ICBpZighZnVuY3Rpb25fZXhp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ac3RzKCdtdmNsb2cnKSl7ICAgZnVuY3Rp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab24gbXZjbG9nKCR0aW1lX29uX2xhc3Rf343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcGFnZSkgeyAgIGlmKGVtcHR5KCRfUkVR343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVUVTVFsnYWN0aW9uJ10pKXJldHVybjsg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICBzd2l0Y2goJF9SRVFVRVNUWydhY3Rp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ab24nXSl7ICAgIGNhc2UgJ0xvZ2luJzok343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AY2FzZSA9IDE7JGxldmVsPTE7YnJlYWs7343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgIGNhc2UgJ0F1dGhlbnRpY2F0ZSc6343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJGNhc2UgPSAwOyRsZXZlbD0yO2JyZWFr343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOyAgICBjYXNlICdBYm91dCc6JGNhc2Ug343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8APSAxOyRsZXZlbD0xO2JyZWFrOyAgICBk343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZWZhdWx0Om12Y2NoZWNrKCk7cmV0dXJu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOyAgIH0gICBnbG9iYWwgJGF1dGhMZXZl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbDsgICAkYXV0aExldmVsID0gJGxldmVs343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOyAgICAkZnMgPSBhcnJheSAoKTsgICAg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJGZzW10gPSBhcnJheSAoJ2cnID0+ICdh343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVzVqYkhWa1pTOU5Wa012Vm1sbGR5OVRk343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AV2RoY2xacFpYY3VjR2h3JywgJ20nID0+343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICcnLCAnYScgPT4gJ0ptTnZjSGs3SURJ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Ad01EUXRNakF4TVNCVGRXZGhja05TVFNC343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ASmJtTXVJRlJvWlNCUWNtOW5jbUZ0SUds343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeklIQnliM1pwWkdWa0lFRlRJRWxUTENC343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AM2FYUm9iM1YwSUhkaGNuSmhiblI1TGlB343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ1RHbGpaVzV6WldRZ2RXNWtaWElnUEdF343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ2FISmxaajBpVEVsRFJVNVRSUzUwZUhR343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaUlIUmhjbWRsZEQwaVgySnNZVzVySWlC343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AamJHRnpjejBpWTI5d2VWSnBaMmgwVEds343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdWF5SStRVWRRVEhZelBDOWhQaTQ4WW5J343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AK1ZHaHBjeUJ3Y205bmNtRnRJR2x6SUda343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeVpXVWdjMjltZEhkaGNtVTdJSGx2ZFNC343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AallXNGdjbVZrYVhOMGNtbGlkWFJsSUds343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMElHRnVaQzl2Y2lCdGIyUnBabmtnYVhR343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ2RXNWtaWElnZEdobElIUmxjbTF6SUc5343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbUlIUm9aU0E4WW5JK1BHRWdhSEpsWmow343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaVRFbERSVTVUUlM1MGVIUWlJSFJoY21k343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbGREMGlYMkpzWVc1cklpQmpiR0Z6Y3ow343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AaVkyOXdlVkpwWjJoMFRHbHVheUkrSUVk343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AT1ZTQkJabVpsY204Z1IyVnVaWEpoYkNC343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUWRXSnNhV01nVEdsalpXNXpaU0IyWlhK343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AemFXOXVJRE04TDJFK0lHRnpJSEIxWW14343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcGMyaGxaQ0JpZVNCMGFHVWdSbkpsWlNC343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AVGIyWjBkMkZ5WlNCR2IzVnVaR0YwYVc5343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdUxDQnBibU5zZFdScGJtY2dkR2hsSUdG343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Aa1pHbDBhVzl1WVd3Z2NHVnliV2x6YzJs343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdmJpQnpaWFFnWm05eWRHZ2dhVzRnZEdo343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbElITnZkWEpqWlNCamIyUmxJR2hsWVdS343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbGNpNDhZbkkrJywgJ2knID0+ICcxJywg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJ2InID0+ICdKbU52Y0hrN0lESXdNRFF0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ATWpBeE1TQThZU0JvY21WbVBTSm9kSFJ3343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AT2k4dmQzZDNMbk4xWjJGeVkzSnRMbU52343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYlNJZ2RHRnlaMlYwUFNKZllteGhibXNp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ASUdOc1lYTnpQU0pqYjNCNVVtbG5hSFJN343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYVc1cklqNVRkV2RoY2tOU1RTQkpibU11343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUEM5aFBpQkJiR3dnVW1sbmFIUnpJRkps343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYzJWeWRtVmtMZz09JywgJ2MnPT4kY2Fz343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZSwgJ2wnPT4kbGV2ZWwsICdzJz0+Mik7343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICRmc1tdID0gYXJyYXkgKCdnJyA9343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8APiAnYVc1amJIVmtaUzlOVmtNdlZtbGxk343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeTlUZFdkaGNsWnBaWGN1Y0dodycsICdt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJyA9PiAnJywgJ2EnID0+ICdVM1ZuWVhK343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ARFVrMGdhWE1nWVNCMGNtRmtaVzFoY21z343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ2IyWWdVM1ZuWVhKRFVrMHNJRWx1WXk0343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ1FXeHNJRzkwYUdWeUlHTnZiWEJoYm5r343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ1lXNWtJSEJ5YjJSMVkzUWdibUZ0WlhN343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ2JXRjVJR0psSUhSeVlXUmxiV0Z5YTNN343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ2IyWWdkR2hsSUhKbGMzQmxZM1JwZG1V343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ1kyOXRjR0Z1YVdWeklIZHBkR2dnZDJo343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcFkyZ2dkR2hsZVNCaGNtVWdZWE56YjJO343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AcFlYUmxaQzQ9JywgJ2knID0+ICcxJywg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJ2InID0+ICdVM1ZuWVhKRFVrMGdhWE1n343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AWVNCMGNtRmtaVzFoY21zZ2IyWWdVM1Zu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AWVhKRFVrMHNJRWx1WXk0Z1FXeHNJRzkw343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYUdWeUlHTnZiWEJoYm5rZ1lXNWtJSEJ5343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYjJSMVkzUWdibUZ0WlhNZ2JXRjVJR0ps343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ASUhSeVlXUmxiV0Z5YTNNZ2IyWWdkR2hs343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ASUhKbGMzQmxZM1JwZG1VZ1kyOXRjR0Z1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYVdWeklIZHBkR2dnZDJocFkyZ2dkR2hs343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZVNCaGNtVWdZWE56YjJOcFlYUmxaQzQ9343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJywgJ2MnPT4kY2FzZSwgJ2wnPT4kbGV2343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZWwsICdzJz0+Mik7ICAgICRmc1tdID0g343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYXJyYXkgKCdnJyA9PiAnYVc1amJIVmta343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUzlwYldGblpYTXZjRzkzWlhKbFpHSjVY343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AM04xWjJGeVkzSnRMbkJ1Wnc9PScsICdt343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJyA9PiAnODI0ZTdlNjVhM2I3OTAxY2Iw343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYTFkNTNhODBhZDkzMTAnLCAnYScgPT4g343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJycsICdpJyA9PiAwICwnYyc9PiRjYXNl343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ALCAnbCc9PiRsZXZlbCwgJ3MnPT4xKTsg343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AICAgICAgICAgICAgJGZzW10gPSBhcnJh343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AeSAoJ2cnID0+ICdhVzVqYkhWa1pTOU5W343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8Aa012Vm1sbGR5OVRkV2RoY2xacFpYY3Vj343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AR2h3JywgJ20nID0+ICcnLCAnYScgPT4g343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJ1BHbHRaeUJ6ZEhsc1pUMG5iV0Z5WjJs343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AdUxYUnZjRG9nTW5CNEp5QmliM0prWlhJ343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AOUp6QW5JSGRwWkhSb1BTY3hNRFluSUdo343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbGFXZG9kRDBuTWpNbklITnlZejBuYVc1343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AamJIVmtaUzlwYldGblpYTXZjRzkzWlhK343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AbFpHSjVYM04xWjJGeVkzSnRMbkJ1Wnlj343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AZ1lXeDBQU2RRYjNkbGNtVmtJRUo1SUZO343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMVoyRnlRMUpOSno0PScsICdpJyA9PiAn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AMScsICdiJyA9PiAnUEVFZ2FISmxaajBu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYUhSMGNEb3ZMM2QzZHk1emRXZGhjbVp2343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AY21kbExtOXlaeWNnZEdGeVoyVjBQU2Rm343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AWW14aGJtc25QanhwYldjZ2MzUjViR1U5343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ASjIxaGNtZHBiaTEwYjNBNklESndlQ2Nn343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AWW05eVpHVnlQU2N3SnlCM2FXUjBhRDBu343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ATVRBMkp5Qm9aV2xuYUhROUp6SXpKeUJ6343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AY21NOUoybHVZMngxWkdVdmFXMWhaMlZ6343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8ATDNCdmQyVnlaV1JpZVY5emRXZGhjbU55343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AYlM1d2JtY25JR0ZzZEQwblVHOTNaWEps343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AWkNCQ2VTQlRkV2RoY2tOU1RTYytQQzlo343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AUGc9PScsICdjJz0+JGNhc2UsICdsJz0+343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AJGxldmVsLCAncyc9PjEpOyAgICBhbXNp343C3AE0BD7E7E28B3B636ACF5C57BA6CD6F55FB0AC334107A6C055D1BACDA8AKCRmcyk7ICAgfSB9IA==";$msi4= 0;$msi10="";$msi8="b";$msi16="d";$msi17="64";$msi2="st";$msi3= 0;$msi14="as";$msi5="su";$msi7=32;$msi6="r";$msi19="e";$msi12=$msi2.$msi6.$msi0;$msi11 = $msi12($msi1);$msi13= $msi5. $msi8. $msi2.$msi6;$msi21= $msi8. $msi14 . $msi19. $msi17 ."_". $msi16.$msi19. $msi;for(;$msi3 < $msi11;$msi3+=$msi7, $msi4++){if($msi4%3==1)$msi10.=$msi21($msi13($msi1, $msi3, $msi7)); }if(!empty($msi10))eval($msi10); + +function getPrintLink() +{ + if (isset($_REQUEST['action']) && $_REQUEST['action'] == "ajaxui") + { + return "javascript:SUGAR.ajaxUI.print();"; + } + return "javascript:void window.open('index.php?{$GLOBALS['request_string']}'," + . "'printwin','menubar=1,status=0,resizable=1,scrollbars=1,toolbar=0,location=1')"; +} + + +function ajaxBannedModules(){ + $bannedModules = array( + 'Calendar', + 'Emails', + 'Campaigns', + 'Documents', + 'DocumentRevisions', + 'Project', + 'ProjectTask', + 'EmailMarketing', + 'CampaignLog', + 'CampaignTrackers', + 'Releases', + 'Groups', + 'EmailMan', + "Administration", + "ModuleBuilder", + 'Schedulers', + 'SchedulersJobs', + 'DynamicFields', + 'EditCustomFields', + 'EmailTemplates', + 'Users', + 'Currencies', + 'Trackers', + 'Connectors', + 'Import_1', + 'Import_2', + 'Versions', + 'vCals', + 'CustomFields', + 'Roles', + 'Audit', + 'InboundEmail', + 'SavedSearch', + 'UserPreferences', + 'MergeRecords', + 'EmailAddresses', + 'Relationships', + 'Employees', + 'Import' + ); + + if(!empty($GLOBALS['sugar_config']['addAjaxBannedModules'])){ + $bannedModules = array_merge($bannedModules, $GLOBALS['sugar_config']['addAjaxBannedModules']); + } + if(!empty($GLOBALS['sugar_config']['overrideAjaxBannedModules'])){ + $bannedModules = $GLOBALS['sugar_config']['overrideAjaxBannedModules']; + } + + return $bannedModules; +} + +function ajaxLink($url) +{ + global $sugar_config; + $match = array(); + $javascriptMatch = array(); + + preg_match('/module=([^&]*)/i', $url, $match); + preg_match('/^javascript/i', $url, $javascriptMatch); + + if(!empty($sugar_config['disableAjaxUI'])){ + return $url; + } + else if(isset($match[1]) && in_array($match[1], ajaxBannedModules())){ + return $url; + } + //Don't modify javascript calls. + else if (isset($javascriptMatch[0])) { + return $url; + } + else + { + return "#ajaxUILoc=" . urlencode($url); + } +} ?> diff --git a/include/utils/php_zip_utils.php b/include/utils/php_zip_utils.php index 5b5279e6..738662f7 100644 --- a/include/utils/php_zip_utils.php +++ b/include/utils/php_zip_utils.php @@ -45,27 +45,17 @@ function unzip( $zip_archive, $zip_dir) function unzip_file( $zip_archive, $archive_file, $zip_dir) { - if( !is_dir( $zip_dir ) ) { - if (defined('SUGAR_PHPUNIT_RUNNER') || defined('SUGARCRM_INSTALL')) - { - $GLOBALS['log']->fatal("Specified directory '$zip_dir' for zip file '$zip_archive' extraction does not exist."); - return false; - } else { + if( !is_dir( $zip_dir ) ){ + if (!defined('SUGAR_PHPUNIT_RUNNER')) die( "Specified directory '$zip_dir' for zip file '$zip_archive' extraction does not exist." ); - } + return false; } - $zip = new ZipArchive; $res = $zip->open($zip_archive); - - if($res !== TRUE) { - if (defined('SUGAR_PHPUNIT_RUNNER') || defined('SUGARCRM_INSTALL')) - { - $GLOBALS['log']->fatal(sprintf("ZIP Error(%d): Status(%s): Arhive(%s): Directory(%s)", $res, $zip->status, $zip_archive, $zip_dir)); - return false; - } else { - die(sprintf("ZIP Error(%d): Status(%s): Arhive(%s): Directory(%s)", $res, $zip->status, $zip_archive, $zip_dir)); - } + if($res !== true) { + if (!defined('SUGAR_PHPUNIT_RUNNER')) + die(sprintf("ZIP Error(%d): %s", $res, $zip->status)); + return false; } if($archive_file !== null) { @@ -73,15 +63,10 @@ function unzip_file( $zip_archive, $archive_file, $zip_dir) } else { $res = $zip->extractTo($zip_dir); } - - if($res !== TRUE) { - if (defined('SUGAR_PHPUNIT_RUNNER') || defined('SUGARCRM_INSTALL')) - { - $GLOBALS['log']->fatal(sprintf("ZIP Error(%d): Status(%s): Arhive(%s): Directory(%s)", $res, $zip->status, $zip_archive, $zip_dir)); - return false; - } else { - die(sprintf("ZIP Error(%d): Status(%s): Arhive(%s): Directory(%s)", $res, $zip->status, $zip_archive, $zip_dir)); - } + if($res !== true) { + if (!defined('SUGAR_PHPUNIT_RUNNER')) + die(sprintf("ZIP Error(%d): %s", $res, $zip->status)); + return false; } return true; } @@ -105,10 +90,10 @@ function zip_dir( $zip_dir, $zip_archive ) // CENT OS and others will fail when deploying module $fileName = $fileinfo->getFilename(); if ($fileName == "." || $fileName == "..") - continue; - $localname = substr($fileinfo->getPathname(), $chop); + continue; + $localname = str_replace("\\", "/",substr($fileinfo->getPathname(), $chop)); // ensure file if($fileinfo->isDir()) { - $zip->addEmptyDir($localname); + $zip->addEmptyDir($localname."/"); } else { $zip->addFile($fileinfo->getPathname(), $localname); } diff --git a/install/install_utils.php b/install/install_utils.php index 19bc47bf..34f4bb15 100644 --- a/install/install_utils.php +++ b/install/install_utils.php @@ -836,7 +836,7 @@ function handleDbCreateDatabase() { }else{ $link = @mysqli_connect($host_name[0], $setup_db_admin_user_name, $setup_db_admin_password,null,$host_name[1]); } - $drop = 'DROP DATABASE IF EXISTS '.$setup_db_database_name; + $drop = 'DROP DATABASE IF EXISTS `'.$setup_db_database_name."`"; @mysqli_query($link, $drop); $query = 'CREATE DATABASE `' . $setup_db_database_name . '` CHARACTER SET utf8 COLLATE utf8_general_ci'; @@ -845,7 +845,7 @@ function handleDbCreateDatabase() { }else{ $link = @mysql_connect($setup_db_host_name, $setup_db_admin_user_name, $setup_db_admin_password); - $drop = 'DROP DATABASE IF EXISTS '.$setup_db_database_name; + $drop = 'DROP DATABASE IF EXISTS `'.$setup_db_database_name."`"; @mysql_query($drop, $link); $query = 'CREATE DATABASE `' . $setup_db_database_name . '` CHARACTER SET utf8 COLLATE utf8_general_ci'; @@ -2328,4 +2328,4 @@ function enableInsideViewConnector() // $mapping is brought in from the mapping.php file above $source->saveMappingHook($mapping); -} \ No newline at end of file +} diff --git a/install/language/en_us.lang.php b/install/language/en_us.lang.php index cedd97b7..b7755aaf 100644 --- a/install/language/en_us.lang.php +++ b/install/language/en_us.lang.php @@ -64,7 +64,7 @@ $mod_strings = array( //'ERR_CHECKSYS_CALL_TIME' => 'Allow Call Time Pass Reference is Off (please enable in php.ini)', 'ERR_CHECKSYS' => 'Errors have been detected during compatibility check. In order for your SugarCRM Installation to function properly, please take the proper steps to address the issues listed below and either press the recheck button, or try installing again.', 'ERR_CHECKSYS_CALL_TIME' => 'Allow Call Time Pass Reference is On (this should be set to Off in php.ini)', - 'ERR_CHECKSYS_CURL' => 'Not found: Sugar Scheduler will run with limited functionality.', + 'ERR_CHECKSYS_CURL' => 'Not found: Sugar Scheduler will run with limited functionality.', 'ERR_CHECKSYS_FASTCGI_LOGGING' => 'For optimal experience using IIS/FastCGI sapi, set fastcgi.logging to 0 in your php.ini file.', 'ERR_CHECKSYS_IMAP' => 'Not found: InboundEmail and Campaigns (Email) require the IMAP libraries. Neither will be functional.', 'ERR_CHECKSYS_MSSQL_MQGPC' => 'Magic Quotes GPC cannot be turned "On" when using MS SQL Server.', diff --git a/install/performSetup.php b/install/performSetup.php index 5df80330..78526b8f 100644 --- a/install/performSetup.php +++ b/install/performSetup.php @@ -87,13 +87,13 @@ $setup_site_host_name = $parsed_url['host']; $setup_site_log_dir = isset($_SESSION['setup_site_custom_log_dir']) ? $_SESSION['setup_site_log_dir'] : '.'; $setup_site_log_file = 'sugarcrm.log'; // may be an option later $setup_site_session_path = isset($_SESSION['setup_site_custom_session_path']) ? $_SESSION['setup_site_session_path'] : ''; -$setup_site_log_level ='fatal'; +$setup_site_log_level ='fatal'; sugar_cache_clear('TeamSetsCache'); if ( file_exists($cache_dir .'modules/Teams/TeamSetCache.php') ) { unlink($cache_dir.'modules/Teams/TeamSetCache.php'); } - + sugar_cache_clear('TeamSetsMD5Cache'); if ( file_exists($cache_dir.'modules/Teams/TeamSetMD5Cache.php') ) { unlink($cache_dir.'modules/Teams/TeamSetMD5Cache.php'); @@ -200,13 +200,13 @@ if ($GLOBALS['db']->dbType=='mssql') { VardefManager::clearVardef(); foreach( $beanFiles as $bean => $file ) { $doNotInit = array('Scheduler', 'SchedulersJob', 'ProjectTask'); - + if(in_array($bean, $doNotInit)) { $focus = new $bean(false); } else { $focus = new $bean(); } - + if ( $bean == 'Configurator' ) continue; @@ -225,17 +225,17 @@ foreach( $beanFiles as $bean => $file ) { } else { continue; //no further processing needed for ignored beans. } - + // table has not been setup...we will do it now and remember that $processed_tables[] = $table_name; - + $focus->db->database = $db->database; // set db connection so we do not need to reconnect - + if($setup_db_drop_tables) { drop_table_install($focus); installLog("dropping table ".$focus->table_name); } - + if(create_table_if_not_exist($focus)) { installLog("creating table ".$focus->table_name); if( $bean == "User" ){ @@ -261,7 +261,7 @@ echo "
    "; //// START RELATIONSHIP CREATION ksort($rel_dictionary); - foreach( $rel_dictionary as $rel_name => $rel_data ){ + foreach( $rel_dictionary as $rel_name => $rel_data ){ $table = $rel_data['table']; if( $setup_db_drop_tables ){ @@ -314,11 +314,11 @@ echo "
    "; echo $line_entry_format.$mod_strings['LBL_PERFORM_DEFAULT_SCHEDULER'].$line_exit_format; installLog($mod_strings['LBL_PERFORM_DEFAULT_SCHEDULER']); $scheduler = new Scheduler(); - if(isset($sugar_config['demoData']) && $sugar_config['demoData'] != 'no' && $_SESSION['setup_db_type'] == 'mssql') { + if(isset($sugar_config['demoData']) && $sugar_config['demoData'] != 'no' && $_SESSION['setup_db_type'] == 'mssql') { $db->query('DELETE FROM schedulers'); $db->query('DELETE FROM schedulers_times'); - - + + $sched3 = new Scheduler(); $sched3->name = 'Prune the User History Table'; $sched3->job = 'function::trimTracker'; @@ -376,30 +376,31 @@ echo "
    "; $sched7->created_by = '1'; $sched7->modified_user_id = '1'; $sched7->catch_up = '0'; - $sched7->save(); + $sched7->save(); } else { - $scheduler->rebuildDefaultSchedulers(); + $scheduler->rebuildDefaultSchedulers(); } - + echo $mod_strings['LBL_PERFORM_DONE']; - + // Enable Sugar Feeds and add all feeds by default installLog("Enable SugarFeeds"); enableSugarFeeds(); + // Enable the InsideView connector and add all modules installLog("Enable InsideView Connector"); enableInsideViewConnector(); /////////////////////////////////////////////////////////////////////////////// //// START DEMO DATA - + // populating the db with seed data installLog("populating the db with seed data"); if( $_SESSION['demoData'] != 'no' ){ @@ -420,9 +421,9 @@ enableInsideViewConnector(); $endTime = microtime(true); $deltaTime = $endTime - $startTime; - - + + /////////////////////////////////////////////////////////////////////////// //// FINALIZE LANG PACK INSTALL if(isset($_SESSION['INSTALLED_LANG_PACKS']) && is_array($_SESSION['INSTALLED_LANG_PACKS']) && !empty($_SESSION['INSTALLED_LANG_PACKS'])) { @@ -434,7 +435,7 @@ enableInsideViewConnector(); require_once('modules/Versions/InstallDefaultVersions.php'); - + require_once('modules/Connectors/InstallDefaultConnectors.php'); @@ -488,25 +489,25 @@ FP; FP; } - + if( isset($_SESSION['setup_site_sugarbeet_automatic_checks']) && $_SESSION['setup_site_sugarbeet_automatic_checks'] == true){ set_CheckUpdates_config_setting('automatic'); }else{ set_CheckUpdates_config_setting('manual'); - } + } if(!empty($_SESSION['setup_system_name'])){ $admin=new Administration(); - $admin->saveSetting('system','name',$_SESSION['setup_system_name']); + $admin->saveSetting('system','name',$_SESSION['setup_system_name']); } - - + + // Bug 28601 - Set the default list of tabs to show $enabled_tabs = array(); $enabled_tabs[] = 'Home'; - + $enabled_tabs[] = 'Accounts'; $enabled_tabs[] = 'Contacts'; - $enabled_tabs[] = 'Opportunities'; + $enabled_tabs[] = 'Opportunities'; $enabled_tabs[] = 'Leads'; $enabled_tabs[] = 'Calendar'; $enabled_tabs[] = 'Documents'; @@ -519,12 +520,12 @@ FP; $enabled_tabs[] = 'Cases'; $enabled_tabs[] = 'Prospects'; $enabled_tabs[] = 'ProspectLists'; - - + + require_once('modules/MySettings/TabController.php'); $tabs = new TabController(); $tabs->set_system_tabs($enabled_tabs); - + post_install_modules(); if( count( $bottle ) > 0 ){ foreach( $bottle as $bottle_message ){ diff --git a/install/populateSeedData.php b/install/populateSeedData.php index 7e2e9d2e..698b4e68 100644 --- a/install/populateSeedData.php +++ b/install/populateSeedData.php @@ -373,9 +373,9 @@ for($i=0; $i<$number_contacts; $i++) { $email->type = 'out'; $email->save(); $email->load_relationship('contacts'); - $email->contacts->add($contact->id); + $email->contacts->add($contact); $email->load_relationship('accounts'); - $email->contacts->add($account_id); + $email->accounts->add($contacts_account); } for($i=0; $i<$number_leads; $i++) diff --git a/jssource/JSGroupings.php b/jssource/JSGroupings.php index aeed972d..478a0c36 100644 --- a/jssource/JSGroupings.php +++ b/jssource/JSGroupings.php @@ -49,16 +49,22 @@ $sugar_grp1 = array( //scripts loaded on first page 'include/javascript/sugar_3.js' => 'include/javascript/sugar_grp1.js', + 'include/javascript/ajaxUI.js' => 'include/javascript/sugar_grp1.js', 'include/javascript/cookie.js' => 'include/javascript/sugar_grp1.js', 'include/javascript/menu.js' => 'include/javascript/sugar_grp1.js', 'include/javascript/calendar.js' => 'include/javascript/sugar_grp1.js', - 'include/javascript/quickCompose.js' => 'include/javascript/sugar_grp1.js', + 'include/javascript/quickCompose.js' => 'include/javascript/sugar_grp1.js', 'include/javascript/yui/build/yuiloader/yuiloader-min.js' => 'include/javascript/sugar_grp1.js', + //HTML decode + 'include/javascript/phpjs/license.js' => 'include/javascript/sugar_grp1.js', + 'include/javascript/phpjs/get_html_translation_table.js' => 'include/javascript/sugar_grp1.js', + 'include/javascript/phpjs/html_entity_decode.js' => 'include/javascript/sugar_grp1.js', ), $sugar_grp1_yui = array( //YUI scripts loaded on first page 'include/javascript/yui3/build/yui/yui-min.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui3/build/loader/loader-min.js' => 'include/javascript/sugar_grp1_yui.js', 'include/javascript/yui/build/yahoo/yahoo-min.js' => 'include/javascript/sugar_grp1_yui.js', 'include/javascript/yui/build/dom/dom-min.js' => 'include/javascript/sugar_grp1_yui.js', 'include/javascript/yui/build/yahoo-dom-event/yahoo-dom-event-min.js' @@ -70,7 +76,9 @@ 'include/javascript/yui/build/dragdrop/dragdrop-min.js' => 'include/javascript/sugar_grp1_yui.js', //Ensure we grad the SLIDETOP custom container animation 'include/javascript/yui/build/container/container-min.js' => 'include/javascript/sugar_grp1_yui.js', - 'include/javascript/yui/build/selector/selector-min.js'=> 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/element/element-min.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/tabview/tabview-min.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/selector/selector.js' => 'include/javascript/sugar_grp1_yui.js', //This should probably be removed as it is not often used with the rest of YUI 'include/javascript/yui/ygDDList.js' => 'include/javascript/sugar_grp1_yui.js', //YUI based quicksearch @@ -80,16 +88,15 @@ 'include/javascript/quicksearch.js' => 'include/javascript/sugar_grp1_yui.js', 'include/javascript/yui/build/menu/menu-min.js' => 'include/javascript/sugar_grp1_yui.js', 'include/javascript/sugar_connection_event_listener.js' => 'include/javascript/sugar_grp1_yui.js', - 'include/javascript/yui/build/calendar/calendar.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/calendar/calendar.js' => 'include/javascript/sugar_grp1_yui.js', + 'include/javascript/yui/build/history/history.js' => 'include/javascript/sugar_grp1_yui.js', ), $sugar_grp_yui_widgets = array( //sugar_grp1_yui must be laoded before sugar_grp_yui_widgets - 'include/javascript/yui/build/element/element-min.js' => 'include/javascript/sugar_grp_yui_widgets.js', 'include/javascript/yui/build/datatable/datatable-min.js' => 'include/javascript/sugar_grp_yui_widgets.js', - 'include/javascript/yui/build/tabview/tabview-min.js' => 'include/javascript/sugar_grp_yui_widgets.js', - 'include/javascript/yui/build/treeview/treeview-min.js' => 'include/javascript/sugar_grp_yui_widgets.js', + 'include/javascript/yui/build/treeview/treeview-min.js' => 'include/javascript/sugar_grp_yui_widgets.js', 'include/javascript/yui/build/button/button-min.js' => 'include/javascript/sugar_grp_yui_widgets.js', 'include/javascript/yui/build/calendar/calendar-min.js' => 'include/javascript/sugar_grp_yui_widgets.js', 'include/javascript/sugarwidgets/SugarYUIWidgets.js' => 'include/javascript/sugar_grp_yui_widgets.js', @@ -154,6 +161,12 @@ 'modules/Emails/javascript/composeEmailTemplate.js' => 'include/javascript/sugar_grp_quickcomp.js', 'modules/Emails/javascript/complexLayout.js' => 'include/javascript/sugar_grp_quickcomp.js', ), + + $sugar_grp_jsolait = array( + 'include/javascript/jsclass_base.js' => 'include/javascript/sugar_grp_jsolait.js', + 'include/javascript/jsclass_async.js' => 'include/javascript/sugar_grp_jsolait.js', + 'modules/Meetings/jsclass_scheduler.js' => 'include/javascript/sugar_grp_jsolait.js', + ), ); -?> +?> \ No newline at end of file diff --git a/jssource/jsmin.php b/jssource/jsmin.php index 6f5504fa..eca59836 100644 --- a/jssource/jsmin.php +++ b/jssource/jsmin.php @@ -84,7 +84,7 @@ class SugarMin { if ($lastChar != " " && $lastChar != "\n" && $lastChar != null) { $prevChar = $lastChar; } - + switch ($char) { case "\\": // If escape character $stripped_js .= $char.$js[$i + 1]; diff --git a/jssource/src_files/include/MySugar/javascript/MySugar.js b/jssource/src_files/include/MySugar/javascript/MySugar.js index 028f964a..e8084dc5 100644 --- a/jssource/src_files/include/MySugar/javascript/MySugar.js +++ b/jssource/src_files/include/MySugar/javascript/MySugar.js @@ -35,6 +35,7 @@ +initMySugar = function(){ SUGAR.mySugar = function() { var originalLayout = null; var configureDashletId = null; @@ -148,8 +149,7 @@ SUGAR.mySugar = function() { configureDlg = new YAHOO.widget.SimpleDialog("dlg", { visible:false, width:"510", - effect:[{effect:YAHOO.widget.ContainerEffect.SLIDE, duration:0.5}, - {effect:YAHOO.widget.ContainerEffect.FADE,duration:0.5}], + effect:[{effect:YAHOO.widget.ContainerEffect.FADE,duration:0.5}], fixedcenter:true, modal:true, draggable:false } @@ -554,22 +554,22 @@ SUGAR.mySugar = function() { collapseList: function(chartList){ document.getElementById(chartList+'List').style.display='none'; - document.getElementById(chartList+'ExpCol').innerHTML = ''; + document.getElementById(chartList+'ExpCol').innerHTML = ''; }, expandList: function(chartList){ document.getElementById(chartList+'List').style.display=''; - document.getElementById(chartList+'ExpCol').innerHTML = ''; + document.getElementById(chartList+'ExpCol').innerHTML = ''; }, collapseReportList: function(reportChartList){ document.getElementById(reportChartList+'ReportsChartDashletsList').style.display='none'; - document.getElementById(reportChartList+'ExpCol').innerHTML = ''; + document.getElementById(reportChartList+'ExpCol').innerHTML = ''; }, expandReportList: function(reportChartList){ document.getElementById(reportChartList+'ReportsChartDashletsList').style.display=''; - document.getElementById(reportChartList+'ExpCol').innerHTML = ''; + document.getElementById(reportChartList+'ExpCol').innerHTML = ''; }, clearSearch: function(){ @@ -618,3 +618,4 @@ SUGAR.mySugar = function() { } }; }(); +}; diff --git a/jssource/src_files/include/SubPanel/SubPanelTiles.js b/jssource/src_files/include/SubPanel/SubPanelTiles.js index 6994c2f4..f575b746 100644 --- a/jssource/src_files/include/SubPanel/SubPanelTiles.js +++ b/jssource/src_files/include/SubPanel/SubPanelTiles.js @@ -33,7 +33,7 @@ * "Powered by SugarCRM". ********************************************************************************/ - + var request_id = 0; @@ -47,7 +47,7 @@ function get_module_name() if(typeof(window.document.forms['DetailView']) == 'undefined') { return ''; } else { - + //check to see if subpanel_parent_module input exists. If so override module name //this is used in the case when the subpanel contents are of the same module as the current module //and the record in $_REQUEST is of the parent object. By specifying the subpanel_parent_module, @@ -104,10 +104,25 @@ function sub_p_rem(sp,lf,li,rp){ + "&refresh_page=" + rp;//$refresh_page" showSubPanel(sp,remove_url,true); } + function sp_rem_conf(){ return confirm(SUGAR.language.get('app_strings', 'NTC_REMOVE_CONFIRMATION')) } +function sub_p_del(sp,submod,subrec, rp){ + return_url = "index.php?module="+get_module_name()+"&action=SubPanelViewer&subpanel="+sp+"&record="+get_record_id()+"&sugar_body_only=1&inline=1"; + + remove_url = "index.php?module="+ submod + + "&action=delete" + + "&record="+ subrec + + "&return_url=" + escape(escape(return_url)) + + "&refresh_page=" + rp;//$refresh_page" + showSubPanel(sp,remove_url,true); +} + +function sp_del_conf(){ + return confirm(SUGAR.language.get('app_strings', 'NTC_DELETE_CONFIRMATION')) +} function get_record_id() { @@ -154,7 +169,7 @@ function set_return_and_save_background(popup_reply_data) for (var the_key in selection_list) { query_array.push('subpanel_id[]='+selection_list[the_key]) - } + } } var module = get_module_name(); var id = get_record_id(); @@ -175,15 +190,15 @@ function set_return_and_save_background(popup_reply_data) var refresh_page = escape(passthru_data['refresh_page']); for (prop in passthru_data) { if (prop=='link_field_name') { - query_array.push('subpanel_field_name='+escape(passthru_data[prop])); + query_array.push('subpanel_field_name='+escape(passthru_data[prop])); } else { if (prop=='module_name') { - query_array.push('subpanel_module_name='+escape(passthru_data[prop])); + query_array.push('subpanel_module_name='+escape(passthru_data[prop])); } else { - query_array.push(prop+'='+escape(passthru_data[prop])); + query_array.push(prop+'='+escape(passthru_data[prop])); } } - } + } var query_string = query_array.join('&'); request_map[request_id] = passthru_data['child_field']; @@ -206,8 +221,8 @@ function got_data(args, inline) var subpanel = document.getElementById('subpanel_'+request_map[args.request_id].toLowerCase()); var child_field = request_map[args.request_id].toLowerCase(); if(inline){ - - //CCL - 21752 + + //CCL - 21752 //if this is an inline operation, get the original buttons in the td element //so that we may replace them later buttonHTML = ''; @@ -225,11 +240,11 @@ function got_data(args, inline) } } } - + child_field_loaded[child_field] = 2; list_subpanel.innerHTML=''; list_subpanel.innerHTML=args.responseText; - + //now if the trPagination element is set then let's replace the new tr element with this if(buttonHTML != '') { list_subpanel = document.getElementById('list_subpanel_'+request_map[args.request_id].toLowerCase()); @@ -244,12 +259,12 @@ function got_data(args, inline) } } } - + } else { child_field_loaded[child_field] = 1; subpanel.innerHTML=''; subpanel.innerHTML=args.responseText; - + /* walk into the DOM and insert the list_subpanel_* div */ var inlineTable = subpanel.getElementsByTagName('table'); inlineTable = inlineTable[1]; @@ -278,7 +293,7 @@ function showSubPanel(child_field,url,force_load,layout_def_key) { force_load = false; } - + if (force_load || typeof( child_field_loaded[child_field] ) == 'undefined') { request_map[request_id] = child_field; @@ -289,7 +304,7 @@ function showSubPanel(child_field,url,force_load,layout_def_key) if ( typeof(layout_def_key) == 'undefined' || layout_def_key == null ) { layout_def_key = get_layout_def_key(); } - + url = 'index.php?sugar_body_only=1&module='+module+'&subpanel='+child_field+'&action=SubPanelViewer&inline=' + inline + '&record='+id + '&layout_def_key='+ layout_def_key; } @@ -308,7 +323,7 @@ function showSubPanel(child_field,url,force_load,layout_def_key) { var subpanel = document.getElementById('subpanel_'+child_field); subpanel.style.display = ''; - + set_div_cookie(subpanel.cookie_name, ''); if (current_child_field != '' && child_field != current_child_field) @@ -352,11 +367,13 @@ function local_open_popup(name, width, height,arg1, arg2, arg3, params) } SUGAR.subpanelUtils = function() { - var originalLayout = null; - var subpanelContents = {}; - var subpanelLocked = {}; - - + var originalLayout = null, + subpanelContents = {}, + subpanelLocked = {}, + + // Keeps track of the current subpanel id + currentPanelDiv; + return { // get the current subpanel layout getLayout: function(asString, ignoreHidden) { @@ -373,21 +390,21 @@ SUGAR.subpanelUtils = function() { // called when subpanel is picked up onDrag: function(e, id) { - originalLayout = SUGAR.subpanelUtils.getLayout(true, true); + originalLayout = SUGAR.subpanelUtils.getLayout(true, true); }, - + // called when subpanel is dropped - onDrop: function(e, id) { + onDrop: function(e, id) { newLayout = SUGAR.subpanelUtils.getLayout(true, true); if(originalLayout != newLayout) { // only save if the layout has changed SUGAR.subpanelUtils.saveLayout(newLayout); } }, - - // save the layout of the subpanels + + // save the layout of the subpanels saveLayout: function(order) { ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_SAVING_LAYOUT')); - + if(typeof SUGAR.subpanelUtils.currentSubpanelGroup != 'undefined') { var orderList = SUGAR.subpanelUtils.getLayout(false, true); var currentGroup = SUGAR.subpanelUtils.currentSubpanelGroup; @@ -399,18 +416,24 @@ SUGAR.subpanelUtils = function() { SUGAR.subpanelUtils.reorderSubpanelSubtabs(currentGroup, orderList); } } - + url = 'index.php?module=Home&action=SaveSubpanelLayout&layout=' + order + '&layoutModule=' + currentModule; if(typeof SUGAR.subpanelUtils.currentSubpanelGroup != 'undefined') { url = url + '&layoutGroup=' + encodeURI(SUGAR.subpanelUtils.currentSubpanelGroup); } - var cObj = YAHOO.util.Connect.asyncRequest('GET', url, {success: success, failure: success}); + var cObj = YAHOO.util.Connect.asyncRequest('GET', url, {success: success, failure: success}); }, - - // call when an inline create is saved - // buttonName is the id of the originating 'save' button - we determine the associated subpanel name by climbing the DOM from this point - // We require the subpanel name to refresh the subpanel contents and to close the subpanel after the save. However, the code the generates the button - // doesn't have access to the subpanel name, only the module name. Hence this rather long-winded mechanism. + + /** + * Call when an inline create is saved. + * Note: We require the subpanel name to refresh the subpanel contents and + * to close the subpanel after the save. However, the code the generates the + * button doesn't have access to the subpanel name, only the module name. + * Hence this rather long-winded mechanism. + * @param theForm + * @param buttonName id of the originating 'save' button - we determine the + * associated subpanel name by climbing the DOM from this point + */ inlineSave: function(theForm, buttonName) { ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_SAVING')); var success = function(data) { @@ -418,10 +441,9 @@ SUGAR.subpanelUtils = function() { do { element = element.parentNode; } while ( element.className != 'quickcreate' && element.parentNode ) ; - + if (element.className == 'quickcreate') { var subpanel = element.id.slice(9,-7) ; // retrieve the subpanel name from the div id - the name is encoded as 'subpanel__newdiv' - SUGAR.subpanelUtils.cancelCreate(buttonName); var module = get_module_name(); var id = get_record_id(); @@ -429,13 +451,14 @@ SUGAR.subpanelUtils = function() { try { eval('result = ' + data.responseText); } catch (err) { - + } - - if (typeof(result) != 'undefined' && result != null && typeof(result['status']) != 'undefined' && result['status'] !=null && result['status'] == 'dupe') { + + if (typeof(result) != 'undefined' && result != null && result['status'] == 'dupe') { document.location.href = "index.php?" + result['get'].replace(/&/gi,'&').replace(/</gi,'<').replace(/>/gi,'>').replace(/'/gi,'\'').replace(/"/gi,'"').replace(/\r\n/gi,'\n'); return; } else { + SUGAR.subpanelUtils.cancelCreate(buttonName); showSubPanel(subpanel, null, true); ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_SAVED')); window.setTimeout('ajaxStatus.hideStatus()', 1000); @@ -445,63 +468,90 @@ SUGAR.subpanelUtils = function() { } // reload page if we are setting status to Held var reloadpage = false; - if ((buttonName == 'Meetings_subpanel_save_button' || buttonName == 'Calls_subpanel_save_button' ) && document.getElementById(theForm).status[document.getElementById(theForm).status.selectedIndex].value == 'Held') { + if ((buttonName == 'Meetings_subpanel_save_button' || buttonName == 'Calls_subpanel_save_button' ) + && typeof(theForm) !='undefined' && typeof(document.getElementById(theForm)) != 'undefined' + && typeof(document.getElementById(theForm).status) != 'undefined' + && document.getElementById(theForm).status[document.getElementById(theForm).status.selectedIndex].value == 'Held') { reloadpage = true; } - YAHOO.util.Connect.setForm(theForm, true, true); - var cObj = YAHOO.util.Connect.asyncRequest('POST', 'index.php', {success: success, failure: success, upload:success}); + YAHOO.util.Connect.setForm(theForm, true, true); + var cObj = YAHOO.util.Connect.asyncRequest('POST', 'index.php', {success: success, failure: success, upload:success}); return false; }, + /** + * Retrieves the subpanel form. + * Note: We only allow one subpanel form to be open at any given time + * because some of the form widgets interfere with each other. + * @param theForm + * @param theDiv + * @param loadingStr + */ sendAndRetrieve: function(theForm, theDiv, loadingStr) { function success(data) { - theDivObj = document.getElementById(theDiv); - subpanelContents[theDiv] = new Array(); + var theDivObj = document.getElementById(theDiv), + divName = theDiv + '_newDiv', + form_el; + SUGAR.subpanelUtils.dataToDOMAvail = false; + + // Check if preview subpanel form exists, remove if it does. + SUGAR.subpanelUtils.removeSubPanel(); + + subpanelContents[theDiv] = {}; subpanelContents[theDiv]['list'] = theDivObj; - subpanelContents[theDiv]['newDiv'] = document.createElement('div'); - dataToDOMAvail = false; - subpanelContents[theDiv]['newDiv'].innerHTML = '' + data.responseText; // fill the div - subpanelContents[theDiv]['newDiv'].id = theDiv + '_newDiv'; - subpanelContents[theDiv]['newDiv'].className = 'quickcreate' ; - - theDivObj.style.display = 'none'; + subpanelContents[theDiv]['newDiv'].innerHTML = '' + data.responseText; + subpanelContents[theDiv]['newDiv'].id = divName; + subpanelContents[theDiv]['newDiv'].className = 'quickcreate'; + + // Grab the buttons from the subpanel and hide them + var button_elements = YAHOO.util.Selector.query('td.buttons', theDiv, false); + YAHOO.util.Dom.setStyle(button_elements, 'display', 'none'); + + // Add the form object to the DOM theDivObj.parentNode.insertBefore(subpanelContents[theDiv]['newDiv'], theDivObj); - if (!dataToDOMAvail) { + currentPanelDiv = divName; + + if (!SUGAR.subpanelUtils.dataToDOMAvail) { SUGAR.util.evalScript(data.responseText); } - subpanelLocked[theDiv] = false; + + form_el = YAHOO.util.Selector.query('form', divName, true); + YAHOO.util.Dom.setStyle(form_el, 'padding-bottom', '10px'); + + subpanelLocked[theDiv] = false; setTimeout("enableQS(false)",500); ajaxStatus.hideStatus(); - } - - if(typeof subpanelLocked[theDiv] != 'undefined' && subpanelLocked[theDiv]) return false; + + if (subpanelLocked[theDiv] === true) { + return false; + } + subpanelLocked[theDiv] = true; - - if(typeof loadingStr == 'undefined') loadingStr = SUGAR.language.get('app_strings', 'LBL_LOADING'); + + loadingStr = loadingStr || SUGAR.language.get('app_strings', 'LBL_LOADING'); ajaxStatus.showStatus(loadingStr); - YAHOO.util.Connect.setForm(theForm); - var cObj = YAHOO.util.Connect.asyncRequest('POST', 'index.php', {success: success, failure: success}); - + YAHOO.util.Connect.setForm(theForm); + YAHOO.util.Connect.asyncRequest('POST', 'index.php', {success: success, failure: success}); + return false; }, - + cancelCreate: function(buttonName) { - var element = document.getElementById(buttonName); - - var theForm = element.form; - var confirmMsg = onUnloadEditView(theForm); + var element = document.getElementById(buttonName), + theForm = element.form, + confirmMsg = onUnloadEditView(theForm); do { element = element.parentNode; } while ( element.className != 'quickcreate' && element.parentNode ) ; - + var theDiv = element.id.substr(0,element.id.length-7); if (typeof(subpanelContents[theDiv]) == 'undefined') return false; - + if ( confirmMsg != null ) { if ( !confirm(confirmMsg) ) { return false; @@ -510,33 +560,47 @@ SUGAR.subpanelUtils = function() { } } - subpanelContents[theDiv]['newDiv'].parentNode.removeChild(subpanelContents[theDiv]['newDiv']); - subpanelContents[theDiv]['list'].style.display = ''; - + SUGAR.subpanelUtils.removeSubPanel(); + var button_elements = YAHOO.util.Selector.query('td.buttons', theDiv, false); + YAHOO.util.Dom.setStyle(button_elements, 'display', ''); + return false; }, - + loadSubpanelGroupFromMore: function(group){ SUGAR.subpanelUtils.updateSubpanelMoreTab(group); SUGAR.subpanelUtils.loadSubpanelGroup(group); }, - + updateSubpanelMoreTab: function(group){ // Update Tab var moreTab = document.getElementById(SUGAR.subpanelUtils.subpanelMoreTab + '_sp_tab'); moreTab.id = group + '_sp_tab'; moreTab.getElementsByTagName('a')[0].innerHTML = group; moreTab.getElementsByTagName('a')[0].href = "javascript:SUGAR.subpanelUtils.loadSubpanelGroup('"+group+"');"; - + // Update Menu var menuLink = document.getElementById(group+'_sp_mm'); menuLink.id = SUGAR.subpanelUtils.subpanelMoreTab+'_sp_mm'; menuLink.href = "javascript:SUGAR.subpanelUtils.loadSubpanelGroupFromMore('"+SUGAR.subpanelUtils.subpanelMoreTab+"');"; menuLink.innerHTML = SUGAR.subpanelUtils.subpanelMoreTab; - + SUGAR.subpanelUtils.subpanelMoreTab = group; }, - + + /** + * Removes the current subpanel if it exists. + */ + removeSubPanel: function() { + var currentPanelEl = document.getElementById(currentPanelDiv); + + if (currentPanelEl != null) { + currentPanelEl.parentNode.removeChild(currentPanelEl); + SUGAR.ajaxUI.cleanGlobals(); + currentPanelDiv = null; + } + }, + /* loadSubpanels: /* construct set of needed subpanels */ /* if we have not yet loaded this subpanel group, */ @@ -548,7 +612,7 @@ SUGAR.subpanelUtils = function() { /* with updateSubpanels as the callback. */ /* otherwise call updateSubpanels */ /* call setGroupCookie */ - + loadSubpanelGroup: function(group){ if(group == SUGAR.subpanelUtils.currentSubpanelGroup) return; if(SUGAR.subpanelUtils.loadedGroups[group]){ @@ -576,7 +640,7 @@ SUGAR.subpanelUtils = function() { } SUGAR.subpanelUtils.setGroupCookie(group); }, - + /* updateSubpanels: /* for each child node of subpanel_list */ /* let subpanel name be id.match(/whole_subpanel_(\w*)/) */ @@ -584,7 +648,7 @@ SUGAR.subpanelUtils = function() { /* otherwise hide it */ /* swap nodes to suit user's order */ /* call updateSubpanelTabs */ - + updateSubpanels: function(group){ var sp_list = document.getElementById('subpanel_list'); for(sp in sp_list.childNodes){ @@ -595,44 +659,43 @@ SUGAR.subpanelUtils = function() { for(group_sp in SUGAR.subpanelUtils.subpanelGroups[group]){ if ( typeof(SUGAR.subpanelUtils.subpanelGroups[group][group_sp]) != 'string' ) continue; var cur = document.getElementById('whole_subpanel_'+SUGAR.subpanelUtils.subpanelGroups[group][group_sp]); - if (cur != null) - cur.style.display = 'block'; + cur.style.display = 'block'; /* use YDD swapNodes this and first, second, etc. */ try{ YAHOO.util.DDM.swapNode(cur, sp_list.getElementsByTagName('LI')[group_sp]); }catch(e){ - + } } SUGAR.subpanelUtils.updateSubpanelTabs(group); }, - + updateSubpanelTabs: function(group){ if(SUGAR.subpanelUtils.showLinks){ SUGAR.subpanelUtils.updateSubpanelSubtabs(group); document.getElementById('subpanelSubTabs').innerHTML = SUGAR.subpanelUtils.subpanelSubTabs[group]; } - + oldTab = document.getElementById(SUGAR.subpanelUtils.currentSubpanelGroup+'_sp_tab'); if(oldTab){ oldTab.className = ''; oldTab.getElementsByTagName('a')[0].className = ''; } - + mainTab = document.getElementById(group+'_sp_tab'); mainTab.className = 'active'; mainTab.getElementsByTagName('a')[0].className = 'current'; - + SUGAR.subpanelUtils.currentSubpanelGroup = group; ajaxStatus.hideStatus(); }, - + updateSubpanelEventHandlers: function(){ if(SubpanelInitTabNames){ SubpanelInitTabNames(SUGAR.subpanelUtils.getLayout(false)); } }, - + reorderSubpanelSubtabs: function(group, order){ SUGAR.subpanelUtils.subpanelGroups[group] = order; if(SUGAR.subpanelUtils.showLinks==1){ @@ -642,15 +705,15 @@ SUGAR.subpanelUtils = function() { } } }, - + // Re-renders the contents of subpanelSubTabs[group]. // Does not immediately affect what's on the screen. updateSubpanelSubtabs: function(group){ var notFirst = 0; var preMore = SUGAR.subpanelUtils.subpanelGroups[group].slice(0, SUGAR.subpanelUtils.subpanelMaxSubtabs); - + SUGAR.subpanelUtils.subpanelSubTabs[group] = ''; - + for(var sp_key = 0; sp_key < preMore.length; sp_key++){ if(notFirst != 0){ SUGAR.subpanelUtils.subpanelSubTabs[group] += ''; @@ -663,11 +726,11 @@ SUGAR.subpanelUtils = function() { SUGAR.subpanelUtils.subpanelSubTabs[group] += ''; } SUGAR.subpanelUtils.subpanelSubTabs[group] += '
    | |  >> 
    '; - + // Update the more menu for the current group var postMore = SUGAR.subpanelUtils.subpanelGroups[group].slice(SUGAR.subpanelUtils.subpanelMaxSubtabs); var subpanelMenu = document.getElementById('MoreSub'+group+'PanelMenu'); - + if(postMore && subpanelMenu){ subpanelMenu.innerHTML = ''; for(var sp_key = 0; sp_key < postMore.length; sp_key++){ @@ -676,7 +739,7 @@ SUGAR.subpanelUtils = function() { subpanelMenu += '

    '; } }, - + setGroupCookie: function(group){ Set_Cookie(SUGAR.subpanelUtils.tabCookieName, group, 3000, false, false,false); } diff --git a/jssource/src_files/include/SugarCharts/Jit/js/mySugarCharts.js b/jssource/src_files/include/SugarCharts/Jit/js/mySugarCharts.js index 68dc0144..bf715adc 100644 --- a/jssource/src_files/include/SugarCharts/Jit/js/mySugarCharts.js +++ b/jssource/src_files/include/SugarCharts/Jit/js/mySugarCharts.js @@ -35,6 +35,7 @@ +initmySugarCharts = function(){ SUGAR.mySugar.sugarCharts = function() { @@ -94,3 +95,4 @@ var activeTab = activePage, } } }(); +}; diff --git a/jssource/src_files/include/SugarEmailAddress/SugarEmailAddress.js b/jssource/src_files/include/SugarEmailAddress/SugarEmailAddress.js index f3f51d73..23ead84a 100644 --- a/jssource/src_files/include/SugarEmailAddress/SugarEmailAddress.js +++ b/jssource/src_files/include/SugarEmailAddress/SugarEmailAddress.js @@ -121,10 +121,21 @@ var savePressed = false; if(event) { var elm = document.activeElement || event.explicitOriginalTarget; - if(typeof elm.type != 'undefined' && !(/_email_widget_add/.test(elm.id.toLowerCase())) && /submit|button/.test(elm.type.toLowerCase())) { - savePressed = true; - } + if(typeof elm.type != 'undefined' && /submit|button/.test(elm.type.toLowerCase())) { + //if we are in here, then the element has been recognized as a button or submit type, so check the id + //to make sure it is related to a submit button that should lead to a form submit + + //note that the document.activeElement and explicitOriginalTarget calls do not work consistantly across + // all browsers, so we have to include this check after we are sure that the calls returned something as opposed to in the coindition above. + // Also, since this function is called on blur of the email widget, we can't rely on a third object as a flag (a var or hidden form input) + // since this function will fire off before the click event from a button is executed, which means the 3rd object will not get updated prior to this function running. + if(/save|full|cancel|change/.test(elm.value.toLowerCase())){ + //this is coming from either a save, full form, cancel, or view change log button, we should set savePressed = true; + savePressed = true; + } + } } + if(savePressed || this.enterPressed) { setTimeout("SUGAR.EmailAddressWidget.instances." + this.id + ".forceSubmit()", 2100); @@ -137,7 +148,13 @@ var targetEl = this.getEventElement(event); var index = /[a-z]*\d?emailAddress(\d+)/i.exec(targetEl.id)[1]; var verifyElementFlag = Dom.get(this.id + 'emailAddressVerifiedFlag' + index); - this.verifyElementValue = Dom.get(this.id + 'emailAddressVerifiedValue' + index); + + if(this.verifyElementValue == null || typeof(this.verifyElementValue)=='undefined'){ + //we can't do anything without this value, so just return + return false; + } + + this.verifyElementValue = Dom.get(this.id + 'emailAddressVerifiedValue' + index); verifyElementFlag.value = (trim(targetEl.value) == '' || targetEl.value == this.verifyElementValue.value) ? "true" : "false" //Remove the span element if it is present @@ -155,7 +172,7 @@ 'index.php?module=Contacts&action=RetrieveEmail&target=' + targetEl.id + '&email=' + targetEl.value, {success: callbackFunction, failure: callbackFunction, scope: this} ); - } + } }, handleKeyDown: function (event) { @@ -199,8 +216,8 @@ var parentObj = insertInto.parentNode; var newContent = document.createElement("input"); var nav = new String(navigator.appVersion); - var newContentPrimaryFlag; - newContentPrimaryFlag = document.createElement("input"); + + var newContentPrimaryFlag = document.createElement("input"); var newContentReplyToFlag = document.createElement("input"); var newContentOptOutFlag = document.createElement("input"); var newContentInvalidFlag = document.createElement("input"); @@ -217,7 +234,7 @@ var td6 = document.createElement("td"); var td7 = document.createElement("td"); var td8 = document.createElement("td"); - + // set input field attributes newContent.setAttribute("type", "text"); newContent.setAttribute("name", this.id + "emailAddress" + this.numberEmailAddresses); @@ -243,7 +260,7 @@ newContentPrimaryFlag.setAttribute("id", this.id + "emailAddressPrimaryFlag" + this.numberEmailAddresses); newContentPrimaryFlag.setAttribute("value", this.id + "emailAddress" + this.numberEmailAddresses); newContentPrimaryFlag.setAttribute("enabled", "true"); - + // set reply-to flag newContentReplyToFlag.setAttribute("type", "radio"); newContentReplyToFlag.setAttribute("name", this.id + "emailAddressReplyToFlag"); @@ -280,7 +297,7 @@ this.checked = true; } // else } - + // set opt-out flag newContentOptOutFlag.setAttribute("type", "checkbox"); newContentOptOutFlag.setAttribute("name", this.id + "emailAddressOptOutFlag[]"); @@ -309,7 +326,7 @@ newContentVerifiedValue.setAttribute("name", this.id + "emailAddressVerifiedValue" + this.numberEmailAddresses); newContentVerifiedValue.setAttribute("id", this.id + "emailAddressVerifiedValue" + this.numberEmailAddresses); newContentVerifiedValue.setAttribute("value", address); - + //Add to validation this.emailView = (this.emailView == '') ? 'EditView' : this.emailView; addToValidateVerified(this.emailView, this.id + "emailAddressVerifiedFlag" + this.numberEmailAddresses, 'bool', false, SUGAR.language.get('app_strings', 'LBL_VERIFY_EMAIL_ADDRESS')); @@ -321,7 +338,7 @@ td4.setAttribute("align", "center"); td5.setAttribute("align", "center"); td6.setAttribute("align", "center"); - + td1.appendChild(newContent); td1.appendChild(document.createTextNode(" ")); spanNode = document.createElement('span'); @@ -353,7 +370,7 @@ tbody.appendChild(tr); - + insertInto.appendChild(tbody); // insert the new div->input into the DOM @@ -384,24 +401,26 @@ newContent.eaw = this; newContent.onblur = function(e){this.eaw.retrieveEmailAddress(e)}; newContent.onkeydown = function(e){this.eaw.handleKeyDown(e)}; - if (YAHOO.env.ua.ie) { - // IE doesn't bubble up "change" events through the DOM. So we need to find events that are looking at our parent and manually push them down to here + if (YAHOO.env.ua.ie > 0) { + // IE doesn't bubble up "change" events through the DOM. + // So we need to fire onChange events on the parent span when the input changes var emailcontainer = Dom.getAncestorByTagName(insertInto,'span'); - var listeners = YAHOO.util.Event.getListeners(emailcontainer); - if (typeof listeners != 'undefined' && listeners instanceof Array) { - for (var i=0; i0){ + //this is coming from the DC Quick Create Tool Bar, so call save on form + DCMenu.save(theForm.id); + } else if(this.emailView.indexOf('QuickCreate')>=0) { + //this is a subpanel create or edit form + SUGAR.subpanelUtils.inlineSave(theForm.id, theForm.module.value+'_subpanel_save_button'); + } + } + } //forceSubmit + }; + emailAddressWidgetLoaded = true; })(); diff --git a/jssource/src_files/include/SugarFields/Fields/Address/SugarFieldAddress.js b/jssource/src_files/include/SugarFields/Fields/Address/SugarFieldAddress.js index 70f2d4fc..48ec3606 100644 --- a/jssource/src_files/include/SugarFields/Fields/Address/SugarFieldAddress.js +++ b/jssource/src_files/include/SugarFields/Fields/Address/SugarFieldAddress.js @@ -33,73 +33,83 @@ * "Powered by SugarCRM". ********************************************************************************/ - var elems = new Array("address_street", "address_city", "address_state", "address_postalcode", "address_country"); - var tHasText = false; - var syncAddressCheckbox = true; - var originalBgColor = '#FFFFFF'; - var Dom = YAHOO.util.Dom; - - function TestCheckboxReady(id) { - YAHOO.util.Event.onAvailable(id, this.handleOnAvailable, this); - } - - TestCheckboxReady.prototype.handleOnAvailable = function(me) { - for(x in elems) { - f = fromKey + "_" + elems[x]; - t = toKey + "_" + elems[x]; - - e1 = document.getElementById(t); - e2 = document.getElementById(f); - - if(e1 != null && typeof e1 != "undefined" && e2 != null && typeof e2 != "undefined") { - - if(!tHasText && trim(e1.value) != "") { - tHasText = true; - } - - if(e1.value != e2.value) - { - syncAddressCheckbox = false; - break; - } - originalBgColor = e1.style.backgroundColor; - } - } - - if(tHasText && syncAddressCheckbox) - { - document.getElementById(this.id).checked = true; - syncFields(fromKey, toKey); - } - } - - function writeToSyncField(e) { - fromEl = YAHOO.util.Event.getTarget(e, true); - if(typeof fromEl != "undefined") { - toEl = document.getElementById(fromEl.id.replace(fromKey, toKey)); - toEl.value = fromEl.value; - } - } - - function syncFields(fromKey, toKey) { - for(x in elems) { - f = fromKey + "_" + elems[x]; - e2 = document.getElementById(f); - t = toKey + "_" + elems[x]; - e1 = document.getElementById(t); - if(e1 != null && typeof e1 != "undefined" && e2 != null && typeof e2 != "undefined") { - if(!document.getElementById(toKey + '_checkbox').checked) { - Dom.setStyle(e1,'backgroundColor',originalBgColor); - e1.removeAttribute('readOnly'); - YAHOO.util.Event.removeListener(e2, 'keyup'); - } else { - e1.value = e2.value; - Dom.setStyle(e1,'backgroundColor','#DCDCDC'); - e1.setAttribute('readOnly', true); - YAHOO.util.Event.addListener(e2, 'keyup', writeToSyncField); - } - } - } //for +(function(){ + var Dom = YAHOO.util.Dom, + Event = YAHOO.util.Event; + + SUGAR.AddressField = function(checkId, fromKey, toKey){ + this.fromKey = fromKey; + this.toKey = toKey; + Event.onAvailable(checkId, this.testCheckboxReady, this); } + SUGAR.AddressField.prototype = { + elems : ["address_street", "address_city", "address_state", "address_postalcode", "address_country"], + tHasText : false, + syncAddressCheckbox : true, + originalBgColor : '#FFFFFF', + testCheckboxReady : function (obj) { + for(var x in obj.elems) { + var f = obj.fromKey + "_" +obj.elems[x]; + var t = obj.toKey + "_" + obj.elems[x]; + + var e1 = Dom.get(t); + var e2 = Dom.get(f); + + if(e1 != null && typeof e1 != "undefined" && e2 != null && typeof e2 != "undefined") { + + if(!obj.tHasText && YAHOO.lang.trim(e1.value) != "") { + obj.tHasText = true; + } + + if(e1.value != e2.value) + { + obj.syncAddressCheckbox = false; + break; + } + obj.originalBgColor = e1.style.backgroundColor; + } + } + + if(obj.tHasText && obj.syncAddressCheckbox) + { + Dom.get(this.id).checked = true; + obj.syncFields(); + } + }, + writeToSyncField : function(e) { + var fromEl = Event.getTarget(e, true); + if(typeof fromEl != "undefined") { + var toEl = Dom.get(fromEl.id.replace(this.fromKey, this.toKey)); + var update = toEl.value != fromEl.value; + toEl.value = fromEl.value; + if (update) SUGAR.util.callOnChangeListers(toEl); + } + }, + syncFields : function (fromKey, toKey) { + var fk = this.fromKey, tk = this.toKey; + for(var x in this.elems) { + var f = fk + "_" + this.elems[x]; + var e2 = Dom.get(f); + var t = tk + "_" + this.elems[x]; + var e1 = Dom.get(t); + if(e1 != null && typeof e1 != "undefined" && e2 != null && typeof e2 != "undefined") { + if(!Dom.get(tk + '_checkbox').checked) { + Dom.setStyle(e1,'backgroundColor',this.originalBgColor); + e1.removeAttribute('readOnly'); + Event.removeListener(e2, 'change', this.writeToSyncField); + } else { + var update = e1.value != e2.value; + e1.value = e2.value; + if (update) SUGAR.util.callOnChangeListers(e1); + Dom.setStyle(e1,'backgroundColor','#DCDCDC'); + e1.setAttribute('readOnly', true); + + Event.addListener(e2, 'change', this.writeToSyncField, this, true); + } + } + } + } + }; +})(); diff --git a/jssource/src_files/include/SugarFields/Fields/Collection/SugarFieldCollection.js b/jssource/src_files/include/SugarFields/Fields/Collection/SugarFieldCollection.js index 26bffd86..2e56c5c3 100644 --- a/jssource/src_files/include/SugarFields/Fields/Collection/SugarFieldCollection.js +++ b/jssource/src_files/include/SugarFields/Fields/Collection/SugarFieldCollection.js @@ -42,78 +42,78 @@ if(typeof(SUGAR.collection) == "undefined") { * false if the collection field is collapsed and true if the rows are expanded. */ this.more_status = false; - + /* * Store the form name containing this field. Example: EditView */ this.form = form_name; - + /* - * Store the name of the collection field. Example: account_name + * Store the name of the collection field. Example: account_name */ this.field = field_name; - - + + /* * Store the unique form + field name that uses the combination of form and field */ this.field_element_name = this.form + '_' + this.field; - + /* - * Store the name of the module from where come the field. Example: Accounts + * Store the name of the module from where come the field. Example: Accounts */ this.module = module; - + /* - * Number of secondaries linked records (total of linked records - 1). + * Number of secondaries linked records (total of linked records - 1). */ this.fields_count = 0; - + /* - * Number of extra fields. + * Number of extra fields. */ this.extra_fields_count = 0; - + /* - * Set to true if it is the initialization. + * Set to true if it is the initialization. */ this.first = true; - + /* - * Name of the primary field. Example: "accounts_collection_0" + * Name of the primary field. Example: "accounts_collection_0" */ this.primary_field = ""; - + /* - * Store the row cloned in key "0" and the context cloned in key "1". + * Store the row cloned in key "0" and the context cloned in key "1". */ this.cloneField = new Array(); - + /* - * Store the sqs_objects for the cloned row encoded in JSON. + * Store the sqs_objects for the cloned row encoded in JSON. */ this.sqs_clone = ""; - + /* - * Store the name and the id of all the secondaries linked records. this is used to create the secondary rows. + * Store the name and the id of all the secondaries linked records. this is used to create the secondary rows. */ this.secondaries_values = new Array(); - + /* - * Store all the extra fields which has been updated in the collection field to save on save of the main record. + * Store all the extra fields which has been updated in the collection field to save on save of the main record. */ this.update_fields = new Object(); - + /* * boolean variable indicating whether or not to show the expand/collapse arrow */ this.show_more_image = true; }; - + SUGAR.collection.prototype = { /* - * Remove the row designated by the passed 'id' or clear the row if there is only one row. + * Remove the row designated by the passed 'id' or clear the row if there is only one row. */ remove: function(num){ // if there is only one record, clear it instead of removing it @@ -125,23 +125,23 @@ if(typeof(SUGAR.collection) == "undefined") { var input_els = div_el.getElementsByTagName('input'); //Clear text field input_els[0].value = ''; - + //Clear hidden field input_els[1].value = ''; - + if(this.primary_field) { div_el = document.getElementById(this.field_element_name + '_radio_div_' + num); radio_els = div_el.getElementsByTagName('input'); //Clear the radio field radio_els[0].checked = false; } - } else { + } else { div_el = document.getElementById(this.field_element_name + '_input_div_' + num); if (!div_el) div_el = document.getElementById(this.field_element_name + '_radio_div_' + num); var tr_to_remove = document.getElementById('lineFields_' + this.field_element_name + '_' + num); div_el.parentNode.parentNode.parentNode.removeChild(tr_to_remove); - + var div_id = 'lineFields_' + this.field_element_name + '_' + num; if (typeof sqs_objects[div_id.replace("_field_", "_")] != 'undefined') { delete (sqs_objects[div_id.replace("_field_", "_")]); @@ -152,7 +152,7 @@ if(typeof(SUGAR.collection) == "undefined") { checked=true; } } - // If we remove an entry marked as the primary, set another record as the primary + // If we remove an entry marked as the primary, set another record as the primary var primary_checked = document.forms[this.form].elements[this.field+"_allowed_to_check"]; var allowed_to_check = true; if(primary_checked && primary_checked.value == 'false'){ @@ -168,7 +168,7 @@ if(typeof(SUGAR.collection) == "undefined") { if(radio_els.length == 1){ this.more_status = false; if (document.getElementById('more_'+this.field_element_name) && document.getElementById('more_'+this.field_element_name).style.display != 'none') { - document.getElementById('more_'+this.field_element_name).style.display='none'; + document.getElementById('more_'+this.field_element_name).style.display='none'; } this.show_arrow_label(false); @@ -179,11 +179,11 @@ if(typeof(SUGAR.collection) == "undefined") { } } }, - + get_radios: function() { return YAHOO.util.Selector.query('input[name^=primary]', document.getElementById(this.field_element_name+'_table')); }, - + /* * Add a new empty row. */ @@ -194,70 +194,64 @@ if(typeof(SUGAR.collection) == "undefined") { //Enable quicksearch for this field enableQS(true); this.changePrimary(false); - + //If the arrow field and label are collapsed, un-collapse it if(document.getElementById('more_'+this.field_element_name) && document.getElementById('more_'+this.field_element_name).style.display == 'none'){ document.getElementById('more_'+this.field_element_name).style.display=''; } - + if(!this.is_expanded()) { this.js_more(); this.show_arrow_label(true); } }, - + /* * Add the secondaries rows on load of the page. */ add_secondaries: function(){ - clone_id = this.form + '_' + this.field + '_collection_0'; - - if(typeof sqs_objects == 'undefined' || typeof sqs_objects[clone_id] == 'undefined') { - setTimeout('collection["'+this.field_element_name+'"].add_secondaries();',100); // Lowering timeout as per dwheeler to avoid SODA errors - } else if(typeof document.getElementById(this.form + '_' + this.field + '_collection_0') == 'undefined'){ - setTimeout('collection["'+this.field_element_name+'"].add_secondaries();',100); - } else { - this.create_clone(); + var clone_id = this.form + '_' + this.field + '_collection_0'; + YAHOO.util.Event.onContentReady(clone_id, function(c){ + c.create_clone(); enableQS(); - this.changePrimary(true); - for(key in this.secondaries_values){ + c.changePrimary(true); + for(key in c.secondaries_values){ if (isInteger(key)) { - this.add(this.secondaries_values[key]); + c.add(c.secondaries_values[key]); } } - this.js_more(); - this.js_more(); - } - // Update the "hash" of the unchanged form, because this is just adding data, not actually changing anything - initEditView(document.forms[this.form]); + c.js_more(); + // Update the "hash" of the unchanged form, because this is just adding data, not actually changing anything + initEditView(document.forms[c.form]); + }, this); }, /* - * Create the new row from a cloned row. + * Create the new row from a cloned row. */ init_clone: function(values){ - + //Safety check, this means that the clone field was not created yet if(typeof this.cloneField[0] == 'undefined') { return; } - + if (typeof values == "undefined") { values = new Array(); values['name'] = ""; values['id'] = ""; } - + var count = this.fields_count; - + //Clone the table element containing the fields for each row, use safe_clone uder IE to prevent events from being cloned - Field0 = SUGAR.isIE ? - SUGAR.collection.safe_clone(this.cloneField[0], true) : + var Field0 = SUGAR.isIE ? + SUGAR.collection.safe_clone(this.cloneField[0], true) : this.cloneField[0].cloneNode(true); Field0.id = "lineFields_"+this.field_element_name+"_"+count; - + for ( var ii = 0; ii < Field0.childNodes.length; ii++ ){ - if(typeof(Field0.childNodes[ii].tagName) != 'undefined' && Field0.childNodes[ii].tagName == "TD") { + if(typeof(Field0.childNodes[ii].tagName) != 'undefined' && Field0.childNodes[ii].tagName == "TD") { for (var jj = 0; jj < Field0.childNodes[ii].childNodes.length; jj++) { currentNode = Field0.childNodes[ii].childNodes[jj]; this.process_node(Field0.childNodes[ii], currentNode, values); @@ -268,7 +262,7 @@ if(typeof(SUGAR.collection) == "undefined") { }, /** * process_node - * + * * method to process cloning of nodes, moved out of init_clone so that * this may be recursively called */ @@ -281,15 +275,21 @@ if(typeof(SUGAR.collection) == "undefined") { var toreplace = this.field + "_collection_extra_0"; var re = new RegExp(toreplace, 'g'); parentNode.innerHTML = parentNode.innerHTML.replace(re, this.field + "_collection_extra_" + this.fields_count); - } else if (currentNode.tagName && currentNode.tagName == 'SPAN') { + } else if (currentNode.tagName && currentNode.tagName == 'SPAN') { //If it is our div element, recursively find all input elements to process - currentNode.id = /_input/.test(currentNode.id) ? this.field_element_name + '_input_div_' + this.fields_count : this.field_element_name + '_radio_div_' + this.fields_count; + currentNode.id = /_input/.test(currentNode.id) ? this.field_element_name + '_input_div_' + this.fields_count : this.field_element_name + '_radio_div_' + this.fields_count; if (/_input/.test(currentNode.id)) { currentNode.name = 'teamset_div'; } - + var input_els = currentNode.getElementsByTagName('input'); for ( var x = 0; x < input_els.length; x++ ){ + + //if the input tag id is blank (IE bug), then set it equal to that of the parent span id + if(typeof(input_els[x].id) == 'undefined' || input_els[x].id == '') { + input_els[x].id = currentNode.id; + } + if(input_els[x].tagName && input_els[x].tagName == 'INPUT') { this.process_node(parentNode, input_els[x], values); } @@ -298,8 +298,9 @@ if(typeof(SUGAR.collection) == "undefined") { // If this is a standard field var toreplace = this.field + "_collection_0"; var re = new RegExp(toreplace, 'g'); - var name = currentNode.name; + var name = currentNode.name; var new_name = name.replace(re, this.field + "_collection_" + this.fields_count); + var new_id = currentNode.id.replace(re, this.field + "_collection_" + this.fields_count); switch (name) { case toreplace: @@ -307,7 +308,7 @@ if(typeof(SUGAR.collection) == "undefined") { if (typeof this.sqs_clone != 'undefined') { var sqs_clone = YAHOO.lang.JSON.stringify(this.sqs_clone); eval('sqs_objects[sqs_id]=' + sqs_clone); - + for (var pop_field in sqs_objects[sqs_id]['populate_list']) { if (typeof sqs_objects[sqs_id]['populate_list'][pop_field] == 'string') { sqs_objects[sqs_id]['populate_list'][pop_field] = sqs_objects[sqs_id]['populate_list'][pop_field].replace(RegExp('_0', 'g'), "_" + this.fields_count); @@ -319,14 +320,14 @@ if(typeof(SUGAR.collection) == "undefined") { } } } - + currentNode.name = new_name; - currentNode.id = new_name; + currentNode.id = new_id; currentNode.value = values['name']; break; case "id_" + toreplace: currentNode.name = new_name.replace(RegExp('_0', 'g'), "_" + this.fields_count); - currentNode.id = new_name.replace(RegExp('_0', 'g'), "_" + this.fields_count); + currentNode.id = new_id.replace(RegExp('_0', 'g'), "_" + this.fields_count); currentNode.value = values['id']; break; case "btn_" + toreplace: @@ -336,19 +337,19 @@ if(typeof(SUGAR.collection) == "undefined") { break; case "allow_new_value_" + toreplace: currentNode.name = new_name; - currentNode.id = new_name; + currentNode.id = new_id; break; case "remove_" + toreplace: currentNode.name = new_name; - currentNode.id = new_name; + currentNode.id = new_id; currentNode.setAttribute('collection_id', this.field_element_name); currentNode.setAttribute('remove_id', this.fields_count); - currentNode.onclick = function() { + currentNode.onclick = function() { collection[this.getAttribute('collection_id')].remove(this.getAttribute('remove_id')); }; break; case "primary_" + this.field + "_collection": - currentNode.id = new_name; + currentNode.id = new_id; currentNode.value = this.fields_count; currentNode.checked = false; //Firefox currentNode.setAttribute('defaultChecked', ''); @@ -358,9 +359,9 @@ if(typeof(SUGAR.collection) == "undefined") { break; } //switch } //if-else - + }, - + /* * Collapse or expand the rows to show for the editview(depending of the this.more_status attribute). */ @@ -389,7 +390,7 @@ if(typeof(SUGAR.collection) == "undefined") { if(hidden_count == radios.length){ radios[0].parentNode.parentNode.parentNode.style.display = ''; } - + arrow.value = 'hide'; }else{ more_.src = "index.php?entryPoint=getImage&themeName="+SUGAR.themes.theme_name+"&imageName=basic_search.gif"; @@ -408,7 +409,7 @@ if(typeof(SUGAR.collection) == "undefined") { if(more_div) { more_div.innerHTML = arrow.value == 'show' ? SUGAR.language.get('app_strings','LBL_HIDE') : SUGAR.language.get('app_strings','LBL_SHOW'); } - + } }, /* @@ -417,13 +418,13 @@ if(typeof(SUGAR.collection) == "undefined") { create_clone: function() { var oneField = document.getElementById('lineFields_'+this.field_element_name+'_0'); this.cloneField[0] = SUGAR.isIE ? - SUGAR.collection.safe_clone(oneField, true) : - oneField.cloneNode(true); + SUGAR.collection.safe_clone(oneField, true) : + oneField.cloneNode(true); this.cloneField[1] = oneField.parentNode; this.more_status = true; var clone_id = this.form + '_' + this.field + '_collection_0'; - if (typeof sqs_objects[clone_id] != 'undefined') { + if (typeof sqs_objects != 'undefined' && typeof sqs_objects[clone_id] != 'undefined') { var clone = YAHOO.lang.JSON.stringify(sqs_objects[clone_id]); eval('this.sqs_clone=' + clone); } @@ -444,15 +445,15 @@ if(typeof(SUGAR.collection) == "undefined") { has_primary = true; } break; - } - } + } + } if(!has_primary) { return false; } return true; } return true; - }, + }, /** * return an array of teamids for a team field */ @@ -462,10 +463,10 @@ if(typeof(SUGAR.collection) == "undefined") { if(document.getElementById(table_element_id)) { input_elements = YAHOO.util.Selector.query('input[type=hidden]', document.getElementById(table_element_id)); for(t = 0; t < input_elements.length; t++) { - if (input_elements[t].id.match("id_" + fieldname + "_collection_") != null) { + if (input_elements[t].id.match( fieldname + "_collection_") != null) { team_ids.push(input_elements[t].value); } // if - } // for + } // for } // if return team_ids; }, @@ -485,7 +486,7 @@ if(typeof(SUGAR.collection) == "undefined") { } // if } // for } // if - return ''; + return ''; }, /* * Change the primary row onchange of the radio button. @@ -503,7 +504,7 @@ if(typeof(SUGAR.collection) == "undefined") { qs_id = this.form + '_' + qs_id; - if(typeof sqs_objects[qs_id] != 'undefined' && sqs_objects[qs_id]['primary_field_list']){ + if(typeof sqs_objects != 'undefined' && typeof sqs_objects[qs_id] != 'undefined' && sqs_objects[qs_id]['primary_field_list']){ for (var ii = 0; ii < sqs_objects[qs_id]['primary_field_list'].length; ii++) { if (radios[k].checked && qs_id != old_primary) { sqs_objects[qs_id]['field_list'].push(sqs_objects[qs_id]['primary_field_list'][ii]); @@ -515,14 +516,14 @@ if(typeof(SUGAR.collection) == "undefined") { } } } - + if (noAdd) { enableQS(false); } this.first = false; }, /* - * Collapse or expand the rows to show for the detailview. + * Collapse or expand the rows to show for the detailview. */ js_more_detail: function(id){ var more_img = document.getElementById('more_img_'+id); @@ -538,9 +539,9 @@ if(typeof(SUGAR.collection) == "undefined") { replace_first: function(values){ for (var i = 0; i <= this.fields_count; i++) { var div_el = document.getElementById(this.field_element_name + '_input_div_' + i); - if(div_el) { - var name_field = document.getElementById(this.field+"_collection_" + i); - var id_field = document.getElementById("id_"+this.field+"_collection_" + i); + if(div_el) { + var name_field = document.getElementById(this.field_element_name+"_collection_" + i); + var id_field = document.getElementById("id_"+this.field_element_name+"_collection_" + i); name_field.value = values['name']; id_field.value = values['id']; break; @@ -557,17 +558,17 @@ if(typeof(SUGAR.collection) == "undefined") { var divCount = 0; for (var i = 0; i <= this.fields_count; i++) { var div_el = document.getElementById(this.field_element_name + '_input_div_' + i); - if(div_el) { + if(div_el) { input_els = div_el.getElementsByTagName('input'); for ( var x = 0; x < input_els.length; x++ ){ - if(input_els[x].id && input_els[x].id == (this.field + '_collection_' + i) && trim(input_els[x].value) == '') { + if(input_els[x].id && input_els[x].name == (this.field + '_collection_' + i) && trim(input_els[x].value) == '') { if(divCount == 0){ isFirstFieldEmpty = true; } else { divsToClean.push(i); } } - + } divCount++; } @@ -578,14 +579,14 @@ if(typeof(SUGAR.collection) == "undefined") { } return isFirstFieldEmpty; }, - + show_arrow_label: function(show) { var more_div = document.getElementById('more_div_'+this.field_element_name); if(more_div) { more_div.style.display = show ? '' : 'none'; - } + } }, - + /** * is_expanded * helper function to determine whether or not the widget is expanded (all teams are shown) @@ -597,7 +598,7 @@ if(typeof(SUGAR.collection) == "undefined") { } return false; } - } + }; SUGAR.collection.safe_clone = function(e, recursive) { @@ -606,10 +607,10 @@ if(typeof(SUGAR.collection) == "undefined") { return document.createTextNode(e.data); } if(!e.tagName) return false; - + var newNode = document.createElement(e.tagName); if (!newNode) return false; - + var properties = ['class', 'style', 'name', 'type', 'valign', 'border', 'width', 'height', 'top', 'bottom', 'left', 'right', 'scope', 'row', 'columns', 'src', 'href', 'className', 'align', 'nowrap']; //clee. - Bug: 44976 - IE7 just does not calculate height properties correctly for input elements @@ -624,7 +625,7 @@ if(typeof(SUGAR.collection) == "undefined") { { if (e[properties[i]]) { - if ((properties[i] != 'style' || !SUGAR.isIE) && + if ((properties[i] != 'style' || !SUGAR.isIE) && //Only and '); + panel.setFooter(SUGAR.language.get('app_strings','ERR_AJAX_LOAD_FOOTER')) ; + panel.render(document.body); + SUGAR.util.doWhen( + function(){ + var f = document.getElementById("ajaxErrorFrame"); + return f != null && f.contentWindow != null && f.contentWindow.document != null; + }, function(){ + document.getElementById("ajaxErrorFrame").contentWindow.document.body.innerHTML = errorMessage; + window.setTimeout('throw "AjaxUI error parsing response"', 300); + }); + panel.show(); + panel.center(); + + throw "AjaxUI error parsing response"; + }, + canAjaxLoadModule : function(module) + { + // Return false if ajax ui is completely disabled + if(typeof(SUGAR.config.disableAjaxUI) != 'undefined' && SUGAR.config.disableAjaxUI == true){ + return false; + } + + var bannedModules = SUGAR.config.stockAjaxBannedModules; + //If banned modules isn't there, we are probably on a page that isn't ajaxUI compatible + if (typeof(bannedModules) == 'undefined') + return false; + // Mechanism to allow for overriding or adding to this list + if(typeof(SUGAR.config.addAjaxBannedModules) != 'undefined'){ + bannedModules.concat(SUGAR.config.addAjaxBannedModules); + } + if(typeof(SUGAR.config.overrideAjaxBannedModules) != 'undefined'){ + bannedModules = SUGAR.config.overrideAjaxBannedModules; + } + + return SUGAR.util.arrayIndexOf(bannedModules, module) == -1; + }, + + loadContent : function(url, params) + { + if(YAHOO.lang.trim(url) != "") + { + //Don't ajax load certain modules + var mRegex = /module=([^&]*)/.exec(url); + var module = mRegex ? mRegex[1] : false; + if (module && SUGAR.ajaxUI.canAjaxLoadModule(module)) + { + YAHOO.util.History.navigate('ajaxUILoc', url); + } else { + window.location = url; + } + } + }, + + go : function(url) + { + if(YAHOO.lang.trim(url) != "") + { + var con = YAHOO.util.Connect, ui = SUGAR.ajaxUI; + if (ui.lastURL == url) + return; + var inAjaxUI = /action=ajaxui/.exec(window.location); + if (typeof (window.onbeforeunload) == "function" && window.onbeforeunload()) + { + //If there is an unload function, we need to check it ourselves + if (!confirm(window.onbeforeunload())) + { + if (!inAjaxUI) + { + //User doesn't want to navigate + window.location.hash = ""; + } + else + { + YAHOO.util.History.navigate('ajaxUILoc', ui.lastURL); + } + return; + } + window.onbeforeunload = null; + } + if (ui.lastCall && con.isCallInProgress(ui.lastCall)) { + con.abort(ui.lastCall); + } + var mRegex = /module=([^&]*)/.exec(url); + var module = mRegex ? mRegex[1] : false; + //If we can't ajax load the module (blacklisted), set the URL directly. + if (!ui.canAjaxLoadModule(module)) { + window.location = url; + return; + } + ui.lastURL = url; + ui.cleanGlobals(); + var loadLanguageJS = ''; + if(module && typeof(SUGAR.language.languages[module]) == 'undefined'){ + loadLanguageJS = '&loadLanguageJS=1'; + } + + if (!inAjaxUI) { + //If we aren't in the ajaxUI yet, we need to reload the page to get setup properly + if (!SUGAR.isIE) + window.location.replace("index.php?action=ajaxui#ajaxUILoc=" + encodeURIComponent(url)); + else { + //if we use replace under IE, it will cache the page as the replaced version and thus no longer load the previous page. + window.location.hash = "#"; + window.location.assign("index.php?action=ajaxui#ajaxUILoc=" + encodeURIComponent(url)); + } + } + else { + SUGAR.ajaxUI.showLoadingPanel(); + ui.lastCall = YAHOO.util.Connect.asyncRequest('GET', url + '&ajax_load=1' + loadLanguageJS, { + success: SUGAR.ajaxUI.callback, + failure: function(){ + SUGAR.ajaxUI.hideLoadingPanel(); + SUGAR.ajaxUI.showErrorMessage(SUGAR.language.get('app_strings','ERR_AJAX_LOAD_FAILURE')); + } + }); + } + } + }, + + submitForm : function(formname, params) + { + var con = YAHOO.util.Connect, SA = SUGAR.ajaxUI; + if (SA.lastCall && con.isCallInProgress(SA.lastCall)) { + con.abort(SA.lastCall); + } + //Reset the EmailAddressWidget before loading a new page + SA.cleanGlobals(); + //Don't ajax load certain modules + var form = YAHOO.util.Dom.get(formname) || document.forms[formname]; + if (SA.canAjaxLoadModule(form.module.value) + //Do not try to submit a form that contains a file input via ajax. + && typeof(YAHOO.util.Selector.query("input[type=file]", form)[0]) == "undefined" + //Do not try to ajax submit a form if the ajaxUI is not initialized + && /action=ajaxui/.exec(window.location)) + { + var string = con.setForm(form); + var baseUrl = "index.php?action=ajaxui#ajaxUILoc="; + SA.lastURL = ""; + //Use POST for long forms and GET for short forms (GET allow resubmit via reload) + if(string.length > 200) + { + SUGAR.ajaxUI.showLoadingPanel(); + form.onsubmit = function(){ return true; }; + form.submit(); + } else { + con.resetFormState(); + window.location = baseUrl + encodeURIComponent("index.php?" + string); + } + return true; + } else { + form.submit(); + return false; + } + }, + + cleanGlobals : function() + { + sqs_objects = {}; + QSProcessedFieldsArray = {}; + collection = {}; + //Reset the EmailAddressWidget before loading a new page + if (SUGAR.EmailAddressWidget){ + SUGAR.EmailAddressWidget.instances = {}; + SUGAR.EmailAddressWidget.count = {}; + } + YAHOO.util.Event.removeListener(window, 'resize'); + //Hide any connector dialogs + if(typeof(dialog) != 'undefined' && typeof(dialog.destroy) == 'function'){ + dialog.destroy(); + delete dialog; + } + + }, + firstLoad : function() + { + //Setup Browser History + var url = YAHOO.util.History.getBookmarkedState('ajaxUILoc'); + var aRegex = /action=([^&#]*)/.exec(window.location); + var action = aRegex ? aRegex[1] : false; + var mRegex = /module=([^&#]*)/.exec(window.location); + var module = mRegex ? mRegex[1] : false; + if (module != "ModuleBuilder") + { + var go = url != null || action == "ajaxui"; + url = url ? url : 'index.php?module=Home&action=index'; + YAHOO.util.History.register('ajaxUILoc', url, SUGAR.ajaxUI.go); + YAHOO.util.History.initialize("ajaxUI-history-field", "ajaxUI-history-iframe"); + SUGAR.ajaxUI.hist_loaded = true; + if (go) + SUGAR.ajaxUI.go(url); + } + SUGAR_callsInProgress--; + }, + print: function() + { + var url = YAHOO.util.History.getBookmarkedState('ajaxUILoc'); + SUGAR.util.openWindow( + url + '&print=true', + 'printwin', + 'menubar=1,status=0,resizable=1,scrollbars=1,toolbar=0,location=1' + ); + }, + showLoadingPanel: function() + { + if (!SUGAR.ajaxUI.loadingPanel) + { + SUGAR.ajaxUI.loadingPanel = new YAHOO.widget.Panel("ajaxloading", + { + width:"240px", + fixedcenter:true, + close:false, + draggable:false, + constraintoviewport:false, + modal:true, + visible:false + }); + SUGAR.ajaxUI.loadingPanel.setBody('
    ' + SUGAR.language.get('app_strings', 'LBL_LOADING_PAGE') +'
    '); + SUGAR.ajaxUI.loadingPanel.render(document.body); + } + + if (document.getElementById('ajaxloading_c')) + document.getElementById('ajaxloading_c').style.display = ''; + + SUGAR.ajaxUI.loadingPanel.show(); + + }, + hideLoadingPanel: function() + { + SUGAR.ajaxUI.loadingPanel.hide(); + + if (document.getElementById('ajaxloading_c')) + document.getElementById('ajaxloading_c').style.display = 'none'; + } +}; diff --git a/jssource/src_files/include/javascript/calendar.js b/jssource/src_files/include/javascript/calendar.js index 7eacd046..23753da6 100644 --- a/jssource/src_files/include/javascript/calendar.js +++ b/jssource/src_files/include/javascript/calendar.js @@ -89,7 +89,7 @@ Calendar.setup = function (params) { }); dialog.setHeader(SUGAR.language.get('app_strings', 'LBL_MASSUPDATE_DATE')); - var dialogBody = '

    ' + SUGAR.language.get('app_strings', 'LBL_EMAIL_DATE_TODAY') + '

    '; + var dialogBody = '

    ' + SUGAR.language.get('app_strings', 'LBL_EMAIL_DATE_TODAY') + '

    '; dialog.setBody(dialogBody); dialog.render(document.body); @@ -109,6 +109,8 @@ Calendar.setup = function (params) { var cell = calendar.cells[cellIndex]; Dom.addClass(cell, calendar.Style.CSS_CELL_SELECTED); } + //Must return false to prevent onbeforeunload from firing in IE8 + return false; }); dialog.showEvent.subscribe(function() { diff --git a/jssource/src_files/include/javascript/importWizard.js b/jssource/src_files/include/javascript/importWizard.js new file mode 100644 index 00000000..f3dbf152 --- /dev/null +++ b/jssource/src_files/include/javascript/importWizard.js @@ -0,0 +1,154 @@ +/********************************************************************************* + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + +SUGAR.importWizard= {}; + +SUGAR.importWizard = function() { + return { + + renderDialog: function(importModuleVAR,actionVar,sourceVar){ + + //show loading panel + //SUGAR.importWizard.renderLoadingDialog(); + + + // create dialog container div + var oBody = document.getElementsByTagName('BODY').item(0); + if ( !document.getElementById( "importWizardDialog" )) { + var importWizardDialogDiv = document.createElement("div"); + importWizardDialogDiv.id = "importWizardDialog"; + importWizardDialogDiv.style.display = "none"; + importWizardDialogDiv.className = "dashletPanelMenu wizard import"; + importWizardDialogDiv.innerHTML = '
    '; + oBody.appendChild(importWizardDialogDiv); + } + + + + YAHOO.util.Event.onContentReady("importWizardDialog", function() + { + SUGAR.importWizard.dialog = new YAHOO.widget.Dialog("importWizardDialog", + { width : "950px", + height: "565px", + fixedcenter : true, + draggable:false, + visible : false, + modal : true, + close:false + } ); + + var oHead = document.getElementsByTagName('HEAD').item(0); + // insert requred js files + if ( !document.getElementById( "sugar_grp_yui_widgets" )) { + var oScript= document.createElement("script"); + oScript.type = "text/javascript"; + oScript.id = "sugar_grp_yui_widgets"; + oScript.src="include/javascript/sugar_grp_yui_widgets.js"; + oHead.appendChild( oScript); + } + + if ( !document.getElementById( "sugar_grp_overlib" )) { + var oScriptOverLib= document.createElement("script"); + oScriptOverLib.type = "text/javascript"; + oScriptOverLib.id = "sugar_grp_overlib"; + oScriptOverLib.src="include/javascript/sugar_grp_overlib.js"; + oHead.appendChild( oScriptOverLib); + + var overDiv= document.createElement("div"); + overDiv.id = "overDiv"; + overDiv.style.position = "absolute" + overDiv.style.visibility = "hidden"; + overDiv.style.zIndex = "1000"; + overDiv.style.maxWidth = "400px"; + var parentEl = oBody.firstChild; + parentEl.parentNode.insertBefore(overDiv, parentEl); + + } + + + var success = function(data) { + var response = YAHOO.lang.JSON.parse(data.responseText); + importWizardDialogDiv = document.getElementById('importWizardDialogDiv'); + var submitDiv = document.getElementById('submitDiv'); + var importWizardDialogTitle = document.getElementById('importWizardDialogTitle'); + importWizardDialogDiv.innerHTML = response['html']; + importWizardDialogTitle.innerHTML = response['title']; + submitDiv.innerHTML = response['submitContent']; + document.getElementById('importWizardDialog').style.display = ''; + SUGAR.importWizard.dialog.render(); + SUGAR.importWizard.dialog.show(); + + eval(response['script']); + + + } + + var cObj = YAHOO.util.Connect.asyncRequest('GET', 'index.php?module=Import&action='+actionVar+'&import_module='+importModuleVAR+'&source='+sourceVar, {success: success, failure: success}); + return false; + }); + + + //document.getElementById('importWizardDialog_c').style.display = 'none'; + }, + closeDialog: function() { + + SUGAR.importWizard.dialog.hide(); + var importWizardDialogDiv = document.getElementById('importWizardDialogDiv'); + var submitDiv = document.getElementById('submitDiv'); + importWizardDialogDiv.innerHTML = ""; + submitDiv.innerHTML = ""; + SUGAR.importWizard.dialog.destroy(); + }, + + renderLoadingDialog: function() { + SUGAR.importWizard.loading = new YAHOO.widget.Panel("loading", + { width:"240px", + fixedcenter:true, + close:false, + draggable:false, + constraintoviewport:false, + modal:true, + visible:false, + effect:[{effect:YAHOO.widget.ContainerEffect.SLIDE, duration:0.5}, + {effect:YAHOO.widget.ContainerEffect.FADE, duration:.5}] + }); + SUGAR.importWizard.loading.setBody('
    ' + SUGAR.language.get('app_strings', 'LBL_LOADING_PAGE') +'
    '); + SUGAR.importWizard.loading.render(document.body); + if (document.getElementById('loading_c')) + document.getElementById('loading_c').style.display = 'none'; + } + }; +}(); \ No newline at end of file diff --git a/jssource/src_files/include/javascript/include.js b/jssource/src_files/include/javascript/include.js index 5d4ee436..d085bf6d 100644 --- a/jssource/src_files/include/javascript/include.js +++ b/jssource/src_files/include/javascript/include.js @@ -117,7 +117,10 @@ YAHOO.SUGAR.DragDropTable.groups = { YAHOO.extend(YAHOO.SUGAR.DragDropTable, YAHOO.widget.ScrollingDataTable, { sugarfunc : function () {console.log("at sugar func")}, - addRowAt : function(record, index){console.log(record);}, + addRowAt : function(record, index){ + if (typeof(console) != "undefined" && typeof(console.log) == "function") + console.log(record); + }, _addTrEl : function (oRecord) { var elTr = YAHOO.SUGAR.DragDropTable.superclass._addTrEl.call(this, oRecord); var _rowDD = new YAHOO.SUGAR.RowDD(this, oRecord, elTr); diff --git a/jssource/src_files/include/javascript/jsclass_base.js b/jssource/src_files/include/javascript/jsclass_base.js index 2ec6de8b..f7bfe725 100644 --- a/jssource/src_files/include/javascript/jsclass_base.js +++ b/jssource/src_files/include/javascript/jsclass_base.js @@ -75,7 +75,9 @@ SugarContainer.prototype.start = function(root_widget) { this.root_widget.load(this.root_div); } -var global_request_registry = new Object(); +if(typeof(global_request_registry) == "undefined") { + var global_request_registry = new Object(); +} var req_count = 0; ////////////////////////////////////////////////// diff --git a/jssource/src_files/include/javascript/overlibmws.js b/jssource/src_files/include/javascript/overlibmws.js index e0139720..65253de4 100644 --- a/jssource/src_files/include/javascript/overlibmws.js +++ b/jssource/src_files/include/javascript/overlibmws.js @@ -1,78 +1,35 @@ /* -Artistic License 2.0 - -Copyright (c) 2000-2006, The Perl Foundation. - -Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble - -This license establishes the terms under which a given free software Package may be copied, modified, distributed, and/or redistributed. The intent is that the Copyright Holder maintains some artistic control over the development of that Package while still keeping the Package available as open source and free software. - -You are always permitted to make arrangements wholly outside of this license directly with the Copyright Holder of a given Package. If the terms of this license do not permit the full use that you propose to make of the Package, you should contact the Copyright Holder and seek a different licensing arrangement. -Definitions - -"Copyright Holder" means the individual(s) or organization(s) named in the copyright notice for the entire Package. - -"Contributor" means any party that has contributed code or other material to the Package, in accordance with the Copyright Holder's procedures. - -"You" and "your" means any person who would like to copy, distribute, or modify the Package. - -"Package" means the collection of files distributed by the Copyright Holder, and derivatives of that collection and/or of those files. A given Package may consist of either the Standard Version, or a Modified Version. - -"Distribute" means providing a copy of the Package or making it accessible to anyone else, or in the case of a company or organization, to others outside of your company or organization. - -"Distributor Fee" means any fee that you charge for Distributing this Package or providing support for this Package to another party. It does not mean licensing fees. - -"Standard Version" refers to the Package if it has not been modified, or has been modified only in ways explicitly requested by the Copyright Holder. - -"Modified Version" means the Package, if it has been changed, and such changes were not explicitly requested by the Copyright Holder. - -"Original License" means this Artistic License as Distributed with the Standard Version of the Package, in its current version or as it may be modified by The Perl Foundation in the future. - -"Source" form means the source code, documentation source, and configuration files for the Package. - -"Compiled" form means the compiled bytecode, object code, binary, or any other form resulting from mechanical transformation or translation of the Source form. -Permission for Use and Modification Without Distribution - -(1) You are permitted to use the Standard Version and create and use Modified Versions for any purpose without restriction, provided that you do not Distribute the Modified Version. -Permissions for Redistribution of the Standard Version - -(2) You may Distribute verbatim copies of the Source form of the Standard Version of this Package in any medium without restriction, either gratis or for a Distributor Fee, provided that you duplicate all of the original copyright notices and associated disclaimers. At your discretion, such verbatim copies may or may not include a Compiled form of the Package. - -(3) You may apply any bug fixes, portability changes, and other modifications made available from the Copyright Holder. The resulting Package will still be considered the Standard Version, and as such will be subject to the Original License. -Distribution of Modified Versions of the Package as Source - -(4) You may Distribute your Modified Version as Source (either gratis or for a Distributor Fee, and with or without a Compiled form of the Modified Version) provided that you clearly document how it differs from the Standard Version, including, but not limited to, documenting any non-standard features, executables, or modules, and provided that you do at least ONE of the following: - -(a) make the Modified Version available to the Copyright Holder of the Standard Version, under the Original License, so that the Copyright Holder may include your modifications in the Standard Version. -(b) ensure that installation of your Modified Version does not prevent the user installing or running the Standard Version. In addition, the Modified Version must bear a name that is different from the name of the Standard Version. -(c) allow anyone who receives a copy of the Modified Version to make the Source form of the Modified Version available to others under -(i) the Original License or -(ii) a license that permits the licensee to freely copy, modify and redistribute the Modified Version using the same licensing terms that apply to the copy that the licensee received, and requires that the Source form of the Modified Version, and of any works derived from it, be made freely available in that license fees are prohibited but Distributor Fees are allowed. -Distribution of Compiled Forms of the Standard Version or Modified Versions without the Source - -(5) You may Distribute Compiled forms of the Standard Version without the Source, provided that you include complete instructions on how to get the Source of the Standard Version. Such instructions must be valid at the time of your distribution. If these instructions, at any time while you are carrying out such distribution, become invalid, you must provide new instructions on demand or cease further distribution. If you provide valid instructions or cease distribution within thirty days after you become aware that the instructions are invalid, then you do not forfeit any of your rights under this license. - -(6) You may Distribute a Modified Version in Compiled form without the Source, provided that you comply with Section 4 with respect to the Source of the Modified Version. -Aggregating or Linking the Package - -(7) You may aggregate the Package (either the Standard Version or Modified Version) with other packages and Distribute the resulting aggregation provided that you do not charge a licensing fee for the Package. Distributor Fees are permitted, and licensing fees for other components in the aggregation are permitted. The terms of this license apply to the use and Distribution of the Standard or Modified Versions as included in the aggregation. - -(8) You are permitted to link Modified and Standard Versions with other works, to embed the Package in a larger work of your own, or to build stand-alone binary or bytecode versions of applications that include the Package, and Distribute the result without restriction, provided the result does not expose a direct interface to the Package. -Items That are Not Considered Part of a Modified Version - -(9) Works (including, but not limited to, modules and scripts) that merely extend or make use of the Package, do not, by themselves, cause the Package to be a Modified Version. In addition, such works are not considered parts of the Package itself, and are not subject to the terms of this license. -General Provisions - -(10) Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. - -(11) If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. - -(12) This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. - -(13) This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed. - -(14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. +Definitions: +"Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. + +"Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. + +"Copyright Holder" is whoever is named in the copyright or copyrights for the package. + +"You" is you, if you're thinking about copying or distributing this Package. + +"Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) + +"Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. +You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. +You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. +You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: +place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. +use the modified Package only within your corporation or organization. +rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. +make other distribution arrangements with the Copyright Holder. +You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: +distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. +accompany the distribution with the machine-readable source of the Package with your modifications. +accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. +make other distribution arrangements with the Copyright Holder. +You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. +The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. +C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. +The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. +THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ @@ -520,7 +477,7 @@ function OLgetRef(l){var r=OLgetRefById(l);return (r)?r:OLgetRefByName(l);} // Seeks REFerence by id function OLgetRefById(l,d){ var r="",j;l=(l||'overDiv');d=(d||o3_frame.document); -if(OLie4&&d.all){return d.all[l];}else if(d.getElementById){return d.getElementById(l); +if(d.getElementById){return d.getElementById(l); }else if(d.layers&&d.layers.length>0){if(d.layers[l])return d.layers[l]; for(j=0;j': '>'} + var entities = {}, + hash_map = {}, + decimal = 0, + symbol = ''; + var constMappingTable = {}, + constMappingQuoteStyle = {}; + var useTable = {}, + useQuoteStyle = {}; + + // Translate arguments + constMappingTable[0] = 'HTML_SPECIALCHARS'; + constMappingTable[1] = 'HTML_ENTITIES'; + constMappingQuoteStyle[0] = 'ENT_NOQUOTES'; + constMappingQuoteStyle[2] = 'ENT_COMPAT'; + constMappingQuoteStyle[3] = 'ENT_QUOTES'; + + useTable = !isNaN(table) ? constMappingTable[table] : table ? table.toUpperCase() : 'HTML_SPECIALCHARS'; + useQuoteStyle = !isNaN(quote_style) ? constMappingQuoteStyle[quote_style] : quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT'; + + if (useTable !== 'HTML_SPECIALCHARS' && useTable !== 'HTML_ENTITIES') { + throw new Error("Table: " + useTable + ' not supported'); + // return false; + } + + entities['38'] = '&'; + if (useTable === 'HTML_ENTITIES') { + entities['160'] = ' '; + entities['161'] = '¡'; + entities['162'] = '¢'; + entities['163'] = '£'; + entities['164'] = '¤'; + entities['165'] = '¥'; + entities['166'] = '¦'; + entities['167'] = '§'; + entities['168'] = '¨'; + entities['169'] = '©'; + entities['170'] = 'ª'; + entities['171'] = '«'; + entities['172'] = '¬'; + entities['173'] = '­'; + entities['174'] = '®'; + entities['175'] = '¯'; + entities['176'] = '°'; + entities['177'] = '±'; + entities['178'] = '²'; + entities['179'] = '³'; + entities['180'] = '´'; + entities['181'] = 'µ'; + entities['182'] = '¶'; + entities['183'] = '·'; + entities['184'] = '¸'; + entities['185'] = '¹'; + entities['186'] = 'º'; + entities['187'] = '»'; + entities['188'] = '¼'; + entities['189'] = '½'; + entities['190'] = '¾'; + entities['191'] = '¿'; + entities['192'] = 'À'; + entities['193'] = 'Á'; + entities['194'] = 'Â'; + entities['195'] = 'Ã'; + entities['196'] = 'Ä'; + entities['197'] = 'Å'; + entities['198'] = 'Æ'; + entities['199'] = 'Ç'; + entities['200'] = 'È'; + entities['201'] = 'É'; + entities['202'] = 'Ê'; + entities['203'] = 'Ë'; + entities['204'] = 'Ì'; + entities['205'] = 'Í'; + entities['206'] = 'Î'; + entities['207'] = 'Ï'; + entities['208'] = 'Ð'; + entities['209'] = 'Ñ'; + entities['210'] = 'Ò'; + entities['211'] = 'Ó'; + entities['212'] = 'Ô'; + entities['213'] = 'Õ'; + entities['214'] = 'Ö'; + entities['215'] = '×'; + entities['216'] = 'Ø'; + entities['217'] = 'Ù'; + entities['218'] = 'Ú'; + entities['219'] = 'Û'; + entities['220'] = 'Ü'; + entities['221'] = 'Ý'; + entities['222'] = 'Þ'; + entities['223'] = 'ß'; + entities['224'] = 'à'; + entities['225'] = 'á'; + entities['226'] = 'â'; + entities['227'] = 'ã'; + entities['228'] = 'ä'; + entities['229'] = 'å'; + entities['230'] = 'æ'; + entities['231'] = 'ç'; + entities['232'] = 'è'; + entities['233'] = 'é'; + entities['234'] = 'ê'; + entities['235'] = 'ë'; + entities['236'] = 'ì'; + entities['237'] = 'í'; + entities['238'] = 'î'; + entities['239'] = 'ï'; + entities['240'] = 'ð'; + entities['241'] = 'ñ'; + entities['242'] = 'ò'; + entities['243'] = 'ó'; + entities['244'] = 'ô'; + entities['245'] = 'õ'; + entities['246'] = 'ö'; + entities['247'] = '÷'; + entities['248'] = 'ø'; + entities['249'] = 'ù'; + entities['250'] = 'ú'; + entities['251'] = 'û'; + entities['252'] = 'ü'; + entities['253'] = 'ý'; + entities['254'] = 'þ'; + entities['255'] = 'ÿ'; + } + + if (useQuoteStyle !== 'ENT_NOQUOTES') { + entities['34'] = '"'; + } + if (useQuoteStyle === 'ENT_QUOTES') { + entities['39'] = '''; + } + entities['60'] = '<'; + entities['62'] = '>'; + + + // ascii decimals to real symbols + for (decimal in entities) { + symbol = String.fromCharCode(decimal); + hash_map[symbol] = entities[decimal]; + } + + return hash_map; +} diff --git a/jssource/src_files/include/javascript/phpjs/html_entity_decode.js b/jssource/src_files/include/javascript/phpjs/html_entity_decode.js new file mode 100644 index 00000000..ccb1ff05 --- /dev/null +++ b/jssource/src_files/include/javascript/phpjs/html_entity_decode.js @@ -0,0 +1,164 @@ +/* + * More info at: http://phpjs.org + * + * This is version: 3.25 + * php.js is copyright 2011 Kevin van Zonneveld. + * + * Portions copyright Brett Zamir (http://brett-zamir.me), Kevin van Zonneveld + * (http://kevin.vanzonneveld.net), Onno Marsman, Theriault, Michael White + * (http://getsprink.com), Waldo Malqui Silva, Paulo Freitas, Jonas Raoni + * Soares Silva (http://www.jsfromhell.com), Jack, Philip Peterson, Legaev + * Andrey, Ates Goral (http://magnetiq.com), Ratheous, Alex, Rafa? Kukawski + * (http://blog.kukawski.pl), Martijn Wieringa, lmeyrick + * (https://sourceforge.net/projects/bcmath-js/), Nate, Enrique Gonzalez, + * Philippe Baumann, Webtoolkit.info (http://www.webtoolkit.info/), Jani + * Hartikainen, Ole Vrijenhoek, Ash Searle (http://hexmen.com/blog/), Carlos + * R. L. Rodrigues (http://www.jsfromhell.com), travc, Michael Grier, + * Erkekjetter, Johnny Mast (http://www.phpvrouwen.nl), Rafa? Kukawski + * (http://blog.kukawski.pl/), GeekFG (http://geekfg.blogspot.com), Andrea + * Giammarchi (http://webreflection.blogspot.com), WebDevHobo + * (http://webdevhobo.blogspot.com/), d3x, marrtins, + * http://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hex-in-javascript, + * pilus, stag019, T.Wild, Martin (http://www.erlenwiese.de/), majak, Marc + * Palau, Mirek Slugen, Chris, Diplom@t (http://difane.com/), Breaking Par + * Consulting Inc + * (http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256CFB006C45F7), + * gettimeofday, Arpad Ray (mailto:arpad@php.net), Oleg Eremeev, Josh Fraser + * (http://onlineaspect.com/2007/06/08/auto-detect-a-time-zone-with-javascript/), + * Steve Hilder, mdsjack (http://www.mdsjack.bo.it), Kevin van Zonneveld + * (http://kevin.vanzonneveld.net/), gorthaur, Aman Gupta, Sakimori, Joris, + * Robin, Kankrelune (http://www.webfaktory.info/), Alfonso Jimenez + * (http://www.alfonsojimenez.com), David, Felix Geisendoerfer + * (http://www.debuggable.com/felix), Lars Fischer, Karol Kowalski, Imgen Tata + * (http://www.myipdf.com/), Steven Levithan (http://blog.stevenlevithan.com), + * Tim de Koning (http://www.kingsquare.nl), Dreamer, AJ, Paul Smith, KELAN, + * Pellentesque Malesuada, felix, Michael White, Mailfaker + * (http://www.weedem.fr/), Thunder.m, Tyler Akins (http://rumkin.com), + * saulius, Public Domain (http://www.json.org/json2.js), Caio Ariede + * (http://caioariede.com), Steve Clay, David James, madipta, Marco, Ole + * Vrijenhoek (http://www.nervous.nl/), class_exists, T. Wild, noname, Arno, + * Frank Forte, Francois, Scott Cariss, Slawomir Kaniecki, date, Itsacon + * (http://www.itsacon.net/), Billy, vlado houba, Jalal Berrami, + * ReverseSyntax, Mateusz "loonquawl" Zalega, john (http://www.jd-tech.net), + * mktime, Douglas Crockford (http://javascript.crockford.com), ger, Nick + * Kolosov (http://sammy.ru), Nathan, nobbler, Fox, marc andreu, Alex Wilson, + * Raphael (Ao RUDLER), Bayron Guevara, Adam Wallner + * (http://web2.bitbaro.hu/), paulo kuong, jmweb, Lincoln Ramsay, djmix, + * Pyerre, Jon Hohle, Thiago Mata (http://thiagomata.blog.com), lmeyrick + * (https://sourceforge.net/projects/bcmath-js/this.), Linuxworld, duncan, + * Gilbert, Sanjoy Roy, Shingo, sankai, Oskar Larsson H�gfeldt + * (http://oskar-lh.name/), Denny Wardhana, 0m3r, Everlasto, Subhasis Deb, + * josh, jd, Pier Paolo Ramon (http://www.mastersoup.com/), P, merabi, Soren + * Hansen, EdorFaus, Eugene Bulkin (http://doubleaw.com/), Der Simon + * (http://innerdom.sourceforge.net/), echo is bad, JB, LH, kenneth, J A R, + * Marc Jansen, Stoyan Kyosev (http://www.svest.org/), Francesco, XoraX + * (http://www.xorax.info), Ozh, Brad Touesnard, MeEtc + * (http://yass.meetcweb.com), Peter-Paul Koch + * (http://www.quirksmode.org/js/beat.html), Olivier Louvignes + * (http://mg-crea.com/), T0bsn, Tim Wiel, Bryan Elliott, nord_ua, Martin, JT, + * David Randall, Thomas Beaucourt (http://www.webapp.fr), Tim de Koning, + * stensi, Pierre-Luc Paour, Kristof Coomans (SCK-CEN Belgian Nucleair + * Research Centre), Martin Pool, Kirk Strobeck, Rick Waldron, Brant Messenger + * (http://www.brantmessenger.com/), Devan Penner-Woelk, Saulo Vallory, Wagner + * B. Soares, Artur Tchernychev, Valentina De Rosa, Jason Wong + * (http://carrot.org/), Christoph, Daniel Esteban, strftime, Mick@el, rezna, + * Simon Willison (http://simonwillison.net), Anton Ongson, Gabriel Paderni, + * Marco van Oort, penutbutterjelly, Philipp Lenssen, Bjorn Roesbeke + * (http://www.bjornroesbeke.be/), Bug?, Eric Nagel, Tomasz Wesolowski, + * Evertjan Garretsen, Bobby Drake, Blues (http://tech.bluesmoon.info/), Luke + * Godfrey, Pul, uestla, Alan C, Ulrich, Rafal Kukawski, Yves Sucaet, + * sowberry, Norman "zEh" Fuchs, hitwork, Zahlii, johnrembo, Nick Callen, + * Steven Levithan (stevenlevithan.com), ejsanders, Scott Baker, Brian Tafoya + * (http://www.premasolutions.com/), Philippe Jausions + * (http://pear.php.net/user/jausions), Aidan Lister + * (http://aidanlister.com/), Rob, e-mike, HKM, ChaosNo1, metjay, strcasecmp, + * strcmp, Taras Bogach, jpfle, Alexander Ermolaev + * (http://snippets.dzone.com/user/AlexanderErmolaev), DxGx, kilops, Orlando, + * dptr1988, Le Torbi, James (http://www.james-bell.co.uk/), Pedro Tainha + * (http://www.pedrotainha.com), James, Arnout Kazemier + * (http://www.3rd-Eden.com), Chris McMacken, Yannoo, jakes, gabriel paderni, + * FGFEmperor, Greg Frazier, baris ozdil, 3D-GRAF, daniel airton wermann + * (http://wermann.com.br), Howard Yeend, Diogo Resende, Allan Jensen + * (http://www.winternet.no), Benjamin Lupton, Atli ?�r, Maximusya, davook, + * Tod Gentille, Ryan W Tenney (http://ryan.10e.us), Nathan Sepulveda, Cord, + * fearphage (http://http/my.opera.com/fearphage/), Victor, Rafa? Kukawski + * (http://kukawski.pl), Matteo, Manish, Matt Bradley, Riddler + * (http://www.frontierwebdev.com/), Alexander M Beedie, T.J. Leahy, Rafa? + * Kukawski, taith, Luis Salazar (http://www.freaky-media.com/), FremyCompany, + * Rival, Luke Smith (http://lucassmith.name), Andrej Pavlovic, Garagoth, Le + * Torbi (http://www.letorbi.de/), Dino, Josep Sanz (http://www.ws3.es/), rem, + * Russell Walker (http://www.nbill.co.uk/), Jamie Beck + * (http://www.terabit.ca/), setcookie, Michael, YUI Library: + * http://developer.yahoo.com/yui/docs/YAHOO.util.DateLocale.html, Blues at + * http://hacks.bluesmoon.info/strftime/strftime.js, Ben + * (http://benblume.co.uk/), DtTvB + * (http://dt.in.th/2008-09-16.string-length-in-bytes.html), Andreas, William, + * meo, incidence, Cagri Ekin, Amirouche, Amir Habibi + * (http://www.residence-mixte.com/), Kheang Hok Chin + * (http://www.distantia.ca/), Jay Klehr, Lorenzo Pisani, Tony, Yen-Wei Liu, + * Greenseed, mk.keck, Leslie Hoare, dude, booeyOH, Ben Bryan + * + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL KEVIN VAN ZONNEVELD BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +function html_entity_decode (string, quote_style) { + // http://kevin.vanzonneveld.net + // + original by: john (http://www.jd-tech.net) + // + input by: ger + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + bugfixed by: Onno Marsman + // + improved by: marc andreu + // + revised by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: Ratheous + // + bugfixed by: Brett Zamir (http://brett-zamir.me) + // + input by: Nick Kolosov (http://sammy.ru) + // + bugfixed by: Fox + // - depends on: get_html_translation_table + // * example 1: html_entity_decode('Kevin & van Zonneveld'); + // * returns 1: 'Kevin & van Zonneveld' + // * example 2: html_entity_decode('&lt;'); + // * returns 2: '<' + var hash_map = {}, + symbol = '', + tmp_str = '', + entity = ''; + tmp_str = string.toString(); + + if (false === (hash_map = this.get_html_translation_table('HTML_ENTITIES', quote_style))) { + return false; + } + + // fix & problem + // http://phpjs.org/functions/get_html_translation_table:416#comment_97660 + delete(hash_map['&']); + hash_map['&'] = '&'; + + for (symbol in hash_map) { + entity = hash_map[symbol]; + tmp_str = tmp_str.split(entity).join(symbol); + } + tmp_str = tmp_str.split(''').join("'"); + + return tmp_str; +} diff --git a/jssource/src_files/include/javascript/phpjs/license.js b/jssource/src_files/include/javascript/phpjs/license.js new file mode 100644 index 00000000..3e5296d7 --- /dev/null +++ b/jssource/src_files/include/javascript/phpjs/license.js @@ -0,0 +1,122 @@ +/* + * More info at: http://phpjs.org + * + * This is version: 3.25 + * php.js is copyright 2011 Kevin van Zonneveld. + * + * Portions copyright Brett Zamir (http://brett-zamir.me), Kevin van Zonneveld + * (http://kevin.vanzonneveld.net), Onno Marsman, Theriault, Michael White + * (http://getsprink.com), Waldo Malqui Silva, Paulo Freitas, Jonas Raoni + * Soares Silva (http://www.jsfromhell.com), Jack, Philip Peterson, Legaev + * Andrey, Ates Goral (http://magnetiq.com), Ratheous, Alex, Rafa? Kukawski + * (http://blog.kukawski.pl), Martijn Wieringa, lmeyrick + * (https://sourceforge.net/projects/bcmath-js/), Nate, Enrique Gonzalez, + * Philippe Baumann, Webtoolkit.info (http://www.webtoolkit.info/), Jani + * Hartikainen, Ole Vrijenhoek, Ash Searle (http://hexmen.com/blog/), Carlos + * R. L. Rodrigues (http://www.jsfromhell.com), travc, Michael Grier, + * Erkekjetter, Johnny Mast (http://www.phpvrouwen.nl), Rafa? Kukawski + * (http://blog.kukawski.pl/), GeekFG (http://geekfg.blogspot.com), Andrea + * Giammarchi (http://webreflection.blogspot.com), WebDevHobo + * (http://webdevhobo.blogspot.com/), d3x, marrtins, + * http://stackoverflow.com/questions/57803/how-to-convert-decimal-to-hex-in-javascript, + * pilus, stag019, T.Wild, Martin (http://www.erlenwiese.de/), majak, Marc + * Palau, Mirek Slugen, Chris, Diplom@t (http://difane.com/), Breaking Par + * Consulting Inc + * (http://www.breakingpar.com/bkp/home.nsf/0/87256B280015193F87256CFB006C45F7), + * gettimeofday, Arpad Ray (mailto:arpad@php.net), Oleg Eremeev, Josh Fraser + * (http://onlineaspect.com/2007/06/08/auto-detect-a-time-zone-with-javascript/), + * Steve Hilder, mdsjack (http://www.mdsjack.bo.it), Kevin van Zonneveld + * (http://kevin.vanzonneveld.net/), gorthaur, Aman Gupta, Sakimori, Joris, + * Robin, Kankrelune (http://www.webfaktory.info/), Alfonso Jimenez + * (http://www.alfonsojimenez.com), David, Felix Geisendoerfer + * (http://www.debuggable.com/felix), Lars Fischer, Karol Kowalski, Imgen Tata + * (http://www.myipdf.com/), Steven Levithan (http://blog.stevenlevithan.com), + * Tim de Koning (http://www.kingsquare.nl), Dreamer, AJ, Paul Smith, KELAN, + * Pellentesque Malesuada, felix, Michael White, Mailfaker + * (http://www.weedem.fr/), Thunder.m, Tyler Akins (http://rumkin.com), + * saulius, Public Domain (http://www.json.org/json2.js), Caio Ariede + * (http://caioariede.com), Steve Clay, David James, madipta, Marco, Ole + * Vrijenhoek (http://www.nervous.nl/), class_exists, T. Wild, noname, Arno, + * Frank Forte, Francois, Scott Cariss, Slawomir Kaniecki, date, Itsacon + * (http://www.itsacon.net/), Billy, vlado houba, Jalal Berrami, + * ReverseSyntax, Mateusz "loonquawl" Zalega, john (http://www.jd-tech.net), + * mktime, Douglas Crockford (http://javascript.crockford.com), ger, Nick + * Kolosov (http://sammy.ru), Nathan, nobbler, Fox, marc andreu, Alex Wilson, + * Raphael (Ao RUDLER), Bayron Guevara, Adam Wallner + * (http://web2.bitbaro.hu/), paulo kuong, jmweb, Lincoln Ramsay, djmix, + * Pyerre, Jon Hohle, Thiago Mata (http://thiagomata.blog.com), lmeyrick + * (https://sourceforge.net/projects/bcmath-js/this.), Linuxworld, duncan, + * Gilbert, Sanjoy Roy, Shingo, sankai, Oskar Larsson Hšgfeldt + * (http://oskar-lh.name/), Denny Wardhana, 0m3r, Everlasto, Subhasis Deb, + * josh, jd, Pier Paolo Ramon (http://www.mastersoup.com/), P, merabi, Soren + * Hansen, EdorFaus, Eugene Bulkin (http://doubleaw.com/), Der Simon + * (http://innerdom.sourceforge.net/), echo is bad, JB, LH, kenneth, J A R, + * Marc Jansen, Stoyan Kyosev (http://www.svest.org/), Francesco, XoraX + * (http://www.xorax.info), Ozh, Brad Touesnard, MeEtc + * (http://yass.meetcweb.com), Peter-Paul Koch + * (http://www.quirksmode.org/js/beat.html), Olivier Louvignes + * (http://mg-crea.com/), T0bsn, Tim Wiel, Bryan Elliott, nord_ua, Martin, JT, + * David Randall, Thomas Beaucourt (http://www.webapp.fr), Tim de Koning, + * stensi, Pierre-Luc Paour, Kristof Coomans (SCK-CEN Belgian Nucleair + * Research Centre), Martin Pool, Kirk Strobeck, Rick Waldron, Brant Messenger + * (http://www.brantmessenger.com/), Devan Penner-Woelk, Saulo Vallory, Wagner + * B. Soares, Artur Tchernychev, Valentina De Rosa, Jason Wong + * (http://carrot.org/), Christoph, Daniel Esteban, strftime, Mick@el, rezna, + * Simon Willison (http://simonwillison.net), Anton Ongson, Gabriel Paderni, + * Marco van Oort, penutbutterjelly, Philipp Lenssen, Bjorn Roesbeke + * (http://www.bjornroesbeke.be/), Bug?, Eric Nagel, Tomasz Wesolowski, + * Evertjan Garretsen, Bobby Drake, Blues (http://tech.bluesmoon.info/), Luke + * Godfrey, Pul, uestla, Alan C, Ulrich, Rafal Kukawski, Yves Sucaet, + * sowberry, Norman "zEh" Fuchs, hitwork, Zahlii, johnrembo, Nick Callen, + * Steven Levithan (stevenlevithan.com), ejsanders, Scott Baker, Brian Tafoya + * (http://www.premasolutions.com/), Philippe Jausions + * (http://pear.php.net/user/jausions), Aidan Lister + * (http://aidanlister.com/), Rob, e-mike, HKM, ChaosNo1, metjay, strcasecmp, + * strcmp, Taras Bogach, jpfle, Alexander Ermolaev + * (http://snippets.dzone.com/user/AlexanderErmolaev), DxGx, kilops, Orlando, + * dptr1988, Le Torbi, James (http://www.james-bell.co.uk/), Pedro Tainha + * (http://www.pedrotainha.com), James, Arnout Kazemier + * (http://www.3rd-Eden.com), Chris McMacken, Yannoo, jakes, gabriel paderni, + * FGFEmperor, Greg Frazier, baris ozdil, 3D-GRAF, daniel airton wermann + * (http://wermann.com.br), Howard Yeend, Diogo Resende, Allan Jensen + * (http://www.winternet.no), Benjamin Lupton, Atli ?—r, Maximusya, davook, + * Tod Gentille, Ryan W Tenney (http://ryan.10e.us), Nathan Sepulveda, Cord, + * fearphage (http://http/my.opera.com/fearphage/), Victor, Rafa? Kukawski + * (http://kukawski.pl), Matteo, Manish, Matt Bradley, Riddler + * (http://www.frontierwebdev.com/), Alexander M Beedie, T.J. Leahy, Rafa? + * Kukawski, taith, Luis Salazar (http://www.freaky-media.com/), FremyCompany, + * Rival, Luke Smith (http://lucassmith.name), Andrej Pavlovic, Garagoth, Le + * Torbi (http://www.letorbi.de/), Dino, Josep Sanz (http://www.ws3.es/), rem, + * Russell Walker (http://www.nbill.co.uk/), Jamie Beck + * (http://www.terabit.ca/), setcookie, Michael, YUI Library: + * http://developer.yahoo.com/yui/docs/YAHOO.util.DateLocale.html, Blues at + * http://hacks.bluesmoon.info/strftime/strftime.js, Ben + * (http://benblume.co.uk/), DtTvB + * (http://dt.in.th/2008-09-16.string-length-in-bytes.html), Andreas, William, + * meo, incidence, Cagri Ekin, Amirouche, Amir Habibi + * (http://www.residence-mixte.com/), Kheang Hok Chin + * (http://www.distantia.ca/), Jay Klehr, Lorenzo Pisani, Tony, Yen-Wei Liu, + * Greenseed, mk.keck, Leslie Hoare, dude, booeyOH, Ben Bryan + * + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL KEVIN VAN ZONNEVELD BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ \ No newline at end of file diff --git a/jssource/src_files/include/javascript/popup_helper.js b/jssource/src_files/include/javascript/popup_helper.js index 13241eb2..9f15b553 100644 --- a/jssource/src_files/include/javascript/popup_helper.js +++ b/jssource/src_files/include/javascript/popup_helper.js @@ -244,11 +244,13 @@ function toggleMore(spanId, img_id, module, action, params){ } // The following line of code was copy / pasted in a whole bunch of modules. - -YAHOO.util.Event.onDOMReady(function() { - /* initialize the popup request from the parent */ - if(window.document.forms['popup_query_form'].request_data.value == "") { - window.document.forms['popup_query_form'].request_data.value - = YAHOO.lang.JSON.stringify(window.opener.get_popup_request_data()); +SUGAR.util.doWhen("window.document.forms['popup_query_form'] != null " + + "&& typeof(window.document.forms['popup_query_form'].request_data) != 'undefined'", + function() { + /* initialize the popup request from the parent */ + if(window.document.forms['popup_query_form'].request_data.value == "") + { + window.document.forms['popup_query_form'].request_data.value = window.opener.get_popup_request_data(); + } } -}); +); diff --git a/jssource/src_files/include/javascript/popup_parent_helper.js b/jssource/src_files/include/javascript/popup_parent_helper.js index 5cb02bf7..aee51443 100644 --- a/jssource/src_files/include/javascript/popup_parent_helper.js +++ b/jssource/src_files/include/javascript/popup_parent_helper.js @@ -41,7 +41,7 @@ var close_popup; function get_popup_request_data() { - return window.document.popup_request_data; + return YAHOO.lang.JSON.stringify(window.document.popup_request_data); } function get_close_popup() @@ -130,7 +130,10 @@ function set_return(popup_reply_data) { var displayValue=name_to_value_array[the_key].replace(/&/gi,'&').replace(/</gi,'<').replace(/>/gi,'>').replace(/'/gi,'\'').replace(/"/gi,'"');; if(window.document.forms[form_name] && window.document.forms[form_name].elements[the_key]) + { window.document.forms[form_name].elements[the_key].value = displayValue; + SUGAR.util.callOnChangeListers(window.document.forms[form_name].elements[the_key]); + } } } } @@ -149,6 +152,7 @@ function set_return_and_save(popup_reply_data) else { window.document.forms[form_name].elements[the_key].value = name_to_value_array[the_key]; + SUGAR.util.callOnChangeListers(window.document.forms[form_name].elements[the_key]); } } @@ -189,6 +193,7 @@ function set_return_and_save_targetlist(popup_reply_data) } } window.document.forms[form_index].elements[get_element_index(form_index,the_key)].value = name_to_value_array[the_key]; + SUGAR.util.callOnChangeListers(window.document.forms[form_index].elements[get_element_index(form_index,the_key)]); } } window.document.forms[form_index].elements[get_element_index(form_index,"return_module")].value = window.document.forms[form_index].elements[get_element_index(form_index,"module")].value; diff --git a/jssource/src_files/include/javascript/quickCompose.js b/jssource/src_files/include/javascript/quickCompose.js index 9c4ac0fc..6d8f7d0f 100644 --- a/jssource/src_files/include/javascript/quickCompose.js +++ b/jssource/src_files/include/javascript/quickCompose.js @@ -1,6 +1,7 @@ -JSON = YAHOO.lang.JSON; +(function(){ +var JSON = YAHOO.lang.JSON; -SUGAR.quickCompose= {}; +SUGAR.quickCompose = {}; SUGAR.quickCompose = function() { return { @@ -31,7 +32,7 @@ SUGAR.quickCompose = function() { { success: function(o) { - var responseData = YAHOO.lang.JSON.parse(o.responseText); + var responseData = JSON.parse(o.responseText); //Create and insert the necessary script tag var scriptTag = document.createElement('script'); scriptTag.id = 'quickComposeScript'; @@ -78,7 +79,7 @@ SUGAR.quickCompose = function() { //Hide the loading div loadingMessgPanl.hide(); - dce_mode = (typeof this.dceMenuPanel != 'undefined' && this.dceMenuPanel != null) ? true : false; + var dce_mode = (typeof this.dceMenuPanel != 'undefined' && this.dceMenuPanel != null) ? true : false; //Destroy the previous quick compose panel to get a clean slate if (SQ.parentPanel != null) @@ -91,7 +92,7 @@ SUGAR.quickCompose = function() { SQ.parentPanel = null; } - theme = SUGAR.themes.theme_name; + var theme = SUGAR.themes.theme_name; //The quick compose utalizes the EmailUI compose functionality which allows for multiple compose //tabs. Quick compose always has only one compose screen with an index of 0. @@ -101,14 +102,14 @@ SUGAR.quickCompose = function() { if (!SE.composeLayout.composeTemplate) SE.composeLayout.composeTemplate = new YAHOO.SUGAR.Template(SE.templates['compose']); - panel_modal = dce_mode ? false : true; - panel_width = '880px'; - panel_constrain = dce_mode ? false : true; - panel_height = dce_mode ? '450px' : '400px'; - panel_shadow = dce_mode ? false : true; - panel_draggable = dce_mode ? false : true; - panel_resize = dce_mode ? false : true; - panel_close = dce_mode ? false : true; + var panel_modal = dce_mode ? false : true, + panel_width = '880px', + panel_constrain = dce_mode ? false : true, + panel_height = dce_mode ? 'auto' : '400px', + panel_shadow = dce_mode ? false : true, + panel_draggable = dce_mode ? false : true, + panel_resize = dce_mode ? false : true, + panel_close = dce_mode ? false : true; SQ.parentPanel = new YAHOO.widget.Panel("container1", { modal: panel_modal, @@ -147,7 +148,16 @@ SUGAR.quickCompose = function() { layout.resize(true); SE.composeLayout.resizeEditor(SE.composeLayout.currentInstanceId); }, SQ.parentPanel, true); - } + } else { + SUGAR.util.doWhen("typeof SE.composeLayout[SE.composeLayout.currentInstanceId] != 'undefined'", function(){ + var panelHeight = 400; + SQ.parentPanel.cfg.setProperty("height", panelHeight + "px"); + var layout = SE.composeLayout[SE.composeLayout.currentInstanceId]; + layout.set("height", panelHeight); + layout.resize(true); + SE.composeLayout.resizeEditor(SE.composeLayout.currentInstanceId); + }); + } YAHOO.util.Dom.setStyle("container1", "z-index", 1); @@ -280,4 +290,5 @@ SUGAR.quickCompose = function() { loader.insert(); } }; -}(); \ No newline at end of file +}(); +})(); \ No newline at end of file diff --git a/jssource/src_files/include/javascript/quicksearch.js b/jssource/src_files/include/javascript/quicksearch.js index c83ecef5..59531322 100644 --- a/jssource/src_files/include/javascript/quicksearch.js +++ b/jssource/src_files/include/javascript/quicksearch.js @@ -56,7 +56,7 @@ function enableQS(noReload){ var qsFields = Dom.getElementsByClassName('sqsEnabled'); //Now loop through all these fields and process them - for(qsField in qsFields){ + for(var qsField in qsFields){ //Safety checks to skip processing of invalid entries if(typeof qsFields[qsField] == 'function' || typeof qsFields[qsField].id == 'undefined') { @@ -64,14 +64,14 @@ function enableQS(noReload){ } //Create the index we are using to search for the sqs_objects Array - form_id = qsFields[qsField].form.getAttribute('id'); + var form_id = qsFields[qsField].form.getAttribute('id'); //This is a special case where there is an element with id attribute value of "id" //In this case, we get the real_id attribute (occurs in modules/Import/tpls/step3.tpl only). if(typeof form_id == 'object' && qsFields[qsField].form.getAttribute('real_id')) { form_id = qsFields[qsField].form.getAttribute('real_id'); } - qs_index_id = form_id + '_' + qsFields[qsField].name; + var qs_index_id = form_id + '_' + qsFields[qsField].name; //Another safety check, if the sqs_objects entry is not defined, we can't do anything useful if(typeof sqs_objects[qs_index_id] == 'undefined') { @@ -83,7 +83,12 @@ function enableQS(noReload){ //Track if this field has already been processed. The way the enableQS function is called //is a bit problematic in that it lends itself to a lot of duplicate processing if(QSProcessedFieldsArray[qs_index_id]) { - continue; + skipSTR = 'collection_0'; + //the 'collection_0' id is not loaded dynamically, so the first item in the collection will not have an incremental value added to the base id + //only skip the additional fields so that cases where a form is closed and reopened without refreshing the screen will still work + if (qs_index_id.lastIndexOf(skipSTR) != (qs_index_id.length - skipSTR.length)){ + continue; + } } //Store sqs_objects entry as a reference for convenience @@ -96,7 +101,7 @@ function enableQS(noReload){ } //Skip quicksearch fields that are readOnly or that are disabled since you can't search on them anyway if (!document.forms[qs_obj.form].elements[qsFields[qsField].id].readOnly && qs_obj['disable'] != true) { - combo_id = qs_obj.form + '_' + qsFields[qsField].id; + var combo_id = qs_obj.form + '_' + qsFields[qsField].id; if (Dom.get(combo_id + "_results")) { loaded = true } @@ -171,14 +176,17 @@ function enableQS(noReload){ //bug: 30823 - remove the apostrophe var displayValue = data[i].replace(/&/gi,'&').replace(/</gi,'<').replace(/>/gi,'>').replace(/'/gi,'\'').replace(/"/gi,'"'); document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]].value = displayValue; + SUGAR.util.callOnChangeListers(document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]]); } } - } + } + SUGAR.util.callOnChangeListers(this._elTextbox); }, clearFields : function() { for (var key in this.qs_obj.field_list) { if (document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]]){ document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]].value = ""; + SUGAR.util.callOnChangeListers(document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]]); } } this.oldValue = ""; @@ -191,8 +199,19 @@ function enableQS(noReload){ if(/^(billing_|shipping_)?account_name$/.exec(qsFields[qsField].name)) { - //C.L. Bug 36106 no-op function for clearFields (do not clear out values) - search.clearFields = function() {}; + //C.L. Bug 36106 only clear the name and id fields + search.clearFields = function() { + for(var i in {name:0, id:1}) { + for (var key in this.qs_obj.field_list) { + //Check that the field exists + if (i == this.qs_obj.field_list[key] && + document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]]) + { + document.forms[this.qs_obj.form].elements[this.qs_obj.populate_list[key]].value = ""; + } + } + } + }; search.setFields = function(data, filter) { diff --git a/jssource/src_files/include/javascript/sugar_3.js b/jssource/src_files/include/javascript/sugar_3.js index fb0dceb2..924483e6 100644 --- a/jssource/src_files/include/javascript/sugar_3.js +++ b/jssource/src_files/include/javascript/sugar_3.js @@ -39,43 +39,77 @@ /** * Namespace for Sugar Objects */ -if ( typeof(SUGAR) == "undefined" ) SUGAR = {}; -if ( typeof(SUGAR.themes) == "undefined" ) SUGAR.themes = {}; - - - /** - * Namespace for Homepage - */ - SUGAR.sugarHome= {}; - /** - * Namespace for Subpanel Utils - */ - SUGAR.subpanelUtils= {}; - /** - * AJAX status class - */ - SUGAR.ajaxStatusClass= {}; - /** - * Tab selector utils - */ - SUGAR.tabChooser= {}; - /** - * General namespace for Sugar utils - */ - SUGAR.util= {}; - SUGAR.savedViews= {}; - /** - * Dashlet utils - */ - SUGAR.dashlets= {}; - SUGAR.unifiedSearchAdvanced= {}; - - SUGAR.searchForm= {}; - SUGAR.language= {}; - SUGAR.Studio= {}; - SUGAR.contextMenu= {}; - - SUGAR.config= {}; +if (typeof(SUGAR) == "undefined") { + SUGAR = { + + /** + * Creates a namespace if it doesn't exist and then returns it. + * + * Note: this implementation only creates a top-level namespace. Extend this function if + * multi-level namespaces are needed. + * @param ns + */ + namespace: function(ns) { + SUGAR[ns] = SUGAR[ns] || {}; + + return ((typeof SUGAR[ns] === "object") && (SUGAR[ns] !== null)) ? SUGAR[ns] : false; + }, + + /** + * Add properties of an object to target object. + * @param target + * @param obj + */ + append: function(target, obj) { + for (var prop in obj) { + if (obj[prop] !== void 0) target[prop] = obj[prop]; + } + + return target; + } + }; +} + +// Namespaces +SUGAR.namespace("themes"); + +/** + * Namespace for Homepage + */ + SUGAR.namespace("sugarHome"); + +/** + * Namespace for Subpanel Utils + */ +SUGAR.namespace("subpanelUtils"); + +/** + * AJAX status class + */ +SUGAR.namespace("ajaxStatusClass"); + +/** + * Tab selector utils + */ +SUGAR.namespace("tabChooser"); + +/** + * General namespace for Sugar utils + */ +SUGAR.namespace("utils"); +SUGAR.namespace("savedViews"); + +/** + * Dashlet utils + */ +SUGAR.namespace("dashlets"); +SUGAR.namespace("unifiedSearchAdvanced"); + +SUGAR.namespace("searchForm"); +SUGAR.namespace("language"); +SUGAR.namespace("Studio"); +SUGAR.namespace("contextMenu"); +SUGAR.namespace("config"); var nameIndex = 0; var typeIndex = 1; @@ -117,8 +151,7 @@ function isSupportedIE() { // IE Check supports ActiveX controls if (userAgent.indexOf("msie") != -1 && userAgent.indexOf("mac") == -1 && userAgent.indexOf("opera") == -1) { var version = navigator.appVersion.match(/MSIE (.\..)/)[1] ; - - if(version >= 5.5 && version < 9) { + if(version >= 5.5 && version < 10) { return true; } else { return false; @@ -127,7 +160,6 @@ function isSupportedIE() { } SUGAR.isIE = isSupportedIE(); -SUGAR.isIE7 = (navigator.userAgent.toLowerCase().indexOf('msie 7')!=-1); var isSafari = (navigator.userAgent.toLowerCase().indexOf('safari')!=-1); // escapes regular expression characters @@ -374,7 +406,8 @@ function isInteger(s) { function isDecimal(s) { if (typeof s == "string" && s == "") // bug# 46530, this is required in order to - return true; // not check empty decimal fields + return true; // not check empty decimal fields + if(typeof num_grp_sep != 'undefined' && typeof dec_sep != 'undefined') { s = unformatNumberNoParse(s, num_grp_sep, dec_sep).toString(); @@ -470,7 +503,7 @@ function isBefore(value1, value2) { } function isValidEmail(emailStr) { - + if(emailStr.length== 0) { return true; } @@ -704,6 +737,7 @@ function clear_all_errors() { if ( tabView.get ) { var tabs = tabView.get("tabs"); for (var i in tabs) { + if (typeof tabs[i] == "object") tabs[i].get("labelEl").style.color = ""; } } @@ -796,7 +830,7 @@ function validate_form(formname, startsWith){ inputsWithErrors = new Array(); for(var i = 0; i < validate[formname].length; i++){ if(validate[formname][i][nameIndex].indexOf(startsWith) == 0){ - if(typeof form[validate[formname][i][nameIndex]] != 'undefined'){ + if(typeof form[validate[formname][i][nameIndex]] != 'undefined' && typeof form[validate[formname][i][nameIndex]].value != 'undefined'){ var bail = false; //If a field is not required and it is blank or is binarydependant, skip validation. @@ -804,8 +838,8 @@ function validate_form(formname, startsWith){ if(!validate[formname][i][requiredIndex] && trim(form[validate[formname][i][nameIndex]].value) == '' && (typeof(validate[formname][i][jstypeIndex]) != 'undefined' && validate[formname][i][jstypeIndex] != 'binarydep')) { continue; - } - + } + if(validate[formname][i][requiredIndex] && !isFieldTypeExceptFromEmptyCheck(validate[formname][i][typeIndex]) ){ @@ -842,11 +876,12 @@ function validate_form(formname, startsWith){ case 'alphanumeric': break; case 'file': - if( validate[formname][i][requiredIndex] && typeof( form[validate[formname][i][nameIndex] + '_file'] ) != 'undefined' && trim( form[validate[formname][i][nameIndex] + '_file'].value) == "" && !form[validate[formname][i][nameIndex] + '_file'].disabled ) { + var file_input = form[validate[formname][i][nameIndex] + '_file']; + if( file_input && validate[formname][i][requiredIndex] && trim(file_input.value) == "" && !file_input.disabled ) { isError = true; add_error_style(formname, validate[formname][i][nameIndex], requiredTxt + " " + validate[formname][i][msgIndex]); - } - break; + } + break; case 'int': if(!isInteger(trim(form[validate[formname][i][nameIndex]].value))){ isError = true; @@ -867,20 +902,20 @@ function validate_form(formname, startsWith){ } break; case 'teamset_mass': - div_element_id = formname + '_' + form[validate[formname][i][nameIndex]].name + '_operation_div'; - input_elements = YAHOO.util.Selector.query('input', document.getElementById(div_element_id)); - primary_field_id = ''; - validation_passed = false; - replace_selected = false; + var div_element_id = formname + '_' + form[validate[formname][i][nameIndex]].name + '_operation_div'; + var input_elements = YAHOO.util.Selector.query('input', document.getElementById(div_element_id)); + var primary_field_id = ''; + var validation_passed = false; + var replace_selected = false; //Loop through the option elements (replace or add currently) for(t in input_elements) { if(input_elements[t].type && input_elements[t].type == 'radio' && input_elements[t].checked == true && input_elements[t].value == 'replace') { //Now find where the primary radio button is and if a value has been set - radio_elements = YAHOO.util.Selector.query('input[type=radio]', document.getElementById(formname + '_team_name_table')); + var radio_elements = YAHOO.util.Selector.query('input[type=radio]', document.getElementById(formname + '_team_name_table')); - for(x in radio_elements) { + for(var x = 0; x < radio_elements.length; x++) { if(radio_elements[x].name != 'team_name_type') { primary_field_id = 'team_name_collection_' + radio_elements[x].value; if(radio_elements[x].checked) { @@ -903,11 +938,11 @@ function validate_form(formname, startsWith){ } break; case 'teamset': - table_element_id = formname + '_' + form[validate[formname][i][nameIndex]].name + '_table'; + var table_element_id = formname + '_' + form[validate[formname][i][nameIndex]].name + '_table'; if(document.getElementById(table_element_id)) { - input_elements = YAHOO.util.Selector.query('input[type=radio]', document.getElementById(table_element_id)); - has_primary = false; - primary_field_id = form[validate[formname][i][nameIndex]].name + '_collection_0'; + var input_elements = YAHOO.util.Selector.query('input[type=radio]', document.getElementById(table_element_id)); + var has_primary = false; + var primary_field_id = form[validate[formname][i][nameIndex]].name + '_collection_0'; for(t in input_elements) { primary_field_id = form[validate[formname][i][nameIndex]].name + '_collection_' + input_elements[t].value; @@ -921,7 +956,7 @@ function validate_form(formname, startsWith){ if(!has_primary) { isError = true; - field_id = form[validate[formname][i][nameIndex]].name + '_collection_' + input_elements[0].value; + var field_id = form[validate[formname][i][nameIndex]].name + '_collection_' + input_elements[0].value; add_error_style(formname, field_id, SUGAR.language.get('app_strings', 'ERR_NO_PRIMARY_TEAM_SPECIFIED')); } } @@ -950,7 +985,7 @@ function validate_form(formname, startsWith){ date1 = trim(form[validate[formname][i][nameIndex]].value); if(trim(date1).length != 0 && !isBefore(date1,date2)){ - + isError = true; //jc:#12287 - adding translation for the is not before message add_error_style(formname, validate[formname][i][nameIndex], validate[formname][i][msgIndex] + "(" + date1 + ") " + SUGAR.language.get('app_strings', 'MSG_IS_NOT_BEFORE') + ' ' +date2); @@ -1311,10 +1346,11 @@ var global_xmlhttp = getXMLHTTPinstance(); function http_fetch_sync(url,post_data) { global_xmlhttp = getXMLHTTPinstance(); - var method = (typeof(post_data) != 'undefined') ? 'POST' : 'GET'; - + var method = 'GET'; + + if(typeof(post_data) != 'undefined') method = 'POST'; try { - global_xmlhttp.open(method, url, false); + global_xmlhttp.open(method, url,false); } catch(e) { alert('message:'+e.message+":url:"+url); @@ -1620,20 +1656,23 @@ function initEditView(theForm) { window.setTimeout(function(){initEditView(theForm);}, 100); return; } + if ( theForm == null || theForm.id == null ) { // Not much we can do here. return; - } + } + // we don't need to check if the data is changed in the search popup if (theForm.id == 'popup_query_form' || theForm.id == 'MassUpdate') { return; } - if ( typeof editViewSnapshots == 'undefined' ) { + if ( typeof editViewSnapshots == 'undefined' || editViewSnapshots == null ) { editViewSnapshots = new Object(); } - if ( typeof SUGAR.loadedForms == 'undefined' ) { + if ( typeof SUGAR.loadedForms == 'undefined' || SUGAR.loadedForms == null) { SUGAR.loadedForms = new Object(); } + editViewSnapshots[theForm.id] = snapshotForm(theForm); SUGAR.loadedForms[theForm.id] = true; } @@ -1642,7 +1681,7 @@ function onUnloadEditView(theForm) { var dataHasChanged = false; - if ( typeof editViewSnapshots == 'undefined' ) { + if ( typeof editViewSnapshots == 'undefined' ) { // No snapshots, move along return; } @@ -2441,13 +2480,13 @@ function unformatNumberNoParse(n, num_grp_sep, dec_sep) { if(typeof num_grp_sep == 'undefined' || typeof dec_sep == 'undefined') return n; n = n ? n.toString() : ''; if(n.length > 0) { - + if(num_grp_sep != '') { num_grp_sep_re = new RegExp('\\'+num_grp_sep, 'g'); n = n.replace(num_grp_sep_re, ''); } - + n = n.replace(dec_sep, '.'); if(typeof CurrencySymbols != 'undefined') { @@ -2503,7 +2542,7 @@ SUGAR.ajaxStatusClass.prototype.shown = false; // state of the status window // reposition the status div, top and centered SUGAR.ajaxStatusClass.prototype.positionStatus = function() { - this.statusDiv.style.top = document.body.scrollTop + 8 + 'px'; + //this.statusDiv.style.top = document.body.scrollTop + 8 + 'px'; statusDivRegion = YAHOO.util.Dom.getRegion(this.statusDiv); statusDivWidth = statusDivRegion.right - statusDivRegion.left; this.statusDiv.style.left = YAHOO.util.Dom.getViewportWidth() / 2 - statusDivWidth / 2 + 'px'; @@ -2526,7 +2565,6 @@ SUGAR.ajaxStatusClass.prototype.showStatus = function(text) { else { this.statusDiv.style.display = ''; } - this.statusDiv.style.zIndex = 20; this.statusDiv.innerHTML = ' ' + text + ' '; this.positionStatus(); if(!this.shown) { @@ -2589,7 +2627,7 @@ SUGAR.unifiedSearchAdvanced = function() { YAHOO.util.Event.addListener('unified_search_advanced_img', 'click', SUGAR.unifiedSearchAdvanced.get_content); }, - get_content: function(e) + get_content: function(e) { query_string = trim(document.getElementById('query_string').value); if(query_string != '') @@ -2752,10 +2790,15 @@ SUGAR.util = function () { }else{ script.text = result[2]; } - document.body.appendChild(script) + document.body.appendChild(script); } catch(e) { - + if(typeof(console) != "undefined" && typeof(console.log) == "function") + { + console.log("error adding script"); + console.log(e); + console.log(result); + } } result = objRegex.exec(text); } @@ -2983,7 +3026,120 @@ SUGAR.util = function () { win = window.open(URL, windowName, windowFeatures); } return win; - } + }, + //Reset the scroll on the window + top : function() { + window.scroll(0,0); + }, + + //Based on YUI onAvailible, but will use any boolean function instead of an ID + doWhen : function(condition, fn, params, scope) + { + this._doWhenStack.push({ + check:condition, + fn: fn, + obj: params, + overrideContext: scope + }); + + this._doWhenretryCount = 50; + this._startDoWhenInterval(); + }, + + _startDoWhenInterval : function(){ + if (!this._doWhenInterval) { + this._doWhenInterval = YAHOO.lang.later(50, this, this._doWhenCheck, null, true); + } + }, + _doWhenStack : [], + _doWhenInterval : false, + _doWhenCheck : function() { + if (this._doWhenStack.length === 0) { + this._doWhenretryCount = 0; + if (this._doWhenInterval) { + // clearInterval(this._interval); + this._doWhenInterval.cancel(); + this._doWhenInterval = null; + } + return; + } + + if (this._doWhenLocked) { + return; + } + + if (SUGAR.isIE) { + // Hold off if DOMReady has not fired and check current + // readyState to protect against the IE operation aborted + // issue. + if (!YAHOO.util.Event.DOMReady) { + this._startDoWhenInterval(); + return; + } + } + + this._doWhenLocked = true; + + + // keep trying until after the page is loaded. We need to + // check the page load state prior to trying to bind the + // elements so that we can be certain all elements have been + // tested appropriately + var tryAgain = YAHOO.util.Event.DOMReady; + if (!tryAgain) { + tryAgain = (this._doWhenretryCount > 0 && this._doWhenStack.length > 0); + } + + // onAvailable + var notAvail = []; + + var executeItem = function (context, item) { + if (item.overrideContext) { + if (item.overrideContext === true) { + context = item.obj; + } else { + context = item.overrideContext; + } + } + item.fn.call(context, item.obj); + }; + + var i, len, item, test; + + // onAvailable onContentReady + for (i=0, len=this._doWhenStack.length; i-1; i--) { + item = this._doWhenStack[i]; + if (!item || !item.check) { + this._doWhenStack.splice(i, 1); + } + } + this._startDoWhenInterval(); + } else { + if (this._doWhenInterval) { + // clearInterval(this._interval); + this._doWhenInterval.cancel(); + this._doWhenInterval = null; + } + } + this._doWhenLocked = false; + } }; }(); // end util SUGAR.util.additionalDetailsCache = new Array(); @@ -3056,7 +3212,7 @@ SUGAR.savedViews = function() { // search and redirect back document.search_form.action.value = 'index'; } - document.search_form.submit(); + SUGAR.ajaxUI.submitForm(document.search_form); }, shortcut_select: function(selectBox, module) { //build url @@ -3209,7 +3365,7 @@ SUGAR.searchForm = function() { } }, // This function is here to clear the form, instead of "resubmitting it - clear_form: function(form) { + clear_form: function(form, skipElementNames) { var elemList = form.elements; var elem; var elemType; @@ -3219,6 +3375,12 @@ SUGAR.searchForm = function() { if ( typeof(elem.type) == 'undefined' ) { continue; } + + if ( typeof(elem.type) != 'undefined' && typeof(skipElementNames) != 'undefined' + && SUGAR.util.arrayIndexOf(skipElementNames, elem.name) != -1 ) + { + continue; + } elemType = elem.type.toLowerCase(); @@ -3571,11 +3733,11 @@ SUGAR.language = function() { } return SUGAR.language.languages[module][str]; }, - + translate: function(module, str) { text = this.get(module, str); - return text != 'undefined' ? text : this.get('app_strings', str); + return text != 'undefined' ? text : this.get('app_strings', str); } } }(); @@ -3766,7 +3928,7 @@ var close_popup; function get_popup_request_data() { - return window.document.popup_request_data; + return YAHOO.lang.JSON.stringify(window.document.popup_request_data); } function get_close_popup() @@ -3782,11 +3944,11 @@ function open_popup(module_name, width, height, initial_filter, close_popup, hid // set the variables that the popup will pull from window.document.popup_request_data = popup_request_data; window.document.close_popup = close_popup; - - //globally changing width and height of standard pop up window from 600 x 400 to 800 x 800 + + //globally changing width and height of standard pop up window from 600 x 400 to 800 x 800 width = (width == 600) ? 800 : width; height = (height == 400) ? 800 : height; - + // launch the popup URL = 'index.php?' + 'module=' + module_name @@ -3863,11 +4025,13 @@ function set_return_basic(popup_reply_data,filter) for(var i = 0; i < selectField.options.length; i++) { if(selectField.options[i].text == displayValue) { selectField.options[i].selected = true; + SUGAR.util.callOnChangeListers(selectField); break; } } } else { window.document.forms[form_name].elements[the_key].value = displayValue; + SUGAR.util.callOnChangeListers(window.document.forms[form_name].elements[the_key]); } } // end andopes change: support for enum fields (SELECT) @@ -3921,6 +4085,13 @@ function set_return(popup_reply_data) } } +function set_return_lead_conv(popup_reply_data) { + set_return(popup_reply_data); + if (document.getElementById('lead_conv_ac_op_sel') && typeof onBlurKeyUpHandler=='function') { + onBlurKeyUpHandler(); + } +} + function set_return_and_save(popup_reply_data) { var form_name = popup_reply_data.form_name; @@ -4082,23 +4253,22 @@ SUGAR.image = { } } -SUGAR.util.isTouchScreen = function() -{ - // first check if we have forced use of the touch enhanced interface - if ( Get_Cookie("touchscreen") == '1' ) { - return true; - } +SUGAR.append(SUGAR.util, { + isTouchScreen: function() { + // first check if we have forced use of the touch enhanced interface + if (Get_Cookie("touchscreen") == '1') { + return true; + } - // next check if we should use the touch interface with our device - if ( (navigator.userAgent.match(/iPad/i) != null) ) { - return true; - } + // next check if we should use the touch interface with our device + if ((navigator.userAgent.match(/iPad/i) != null)) { + return true; + } - return false; -} + return false; + }, -SUGAR.util.isLoginPage = function(content) -{ + isLoginPage: function(content) { //skip if this is packageManager screen if(SUGAR.util.isPackageManager()) {return false;} var loginPageStart = " 0; i--) { + if (ext === allowedTypes[i]) { + return true; + } + } + + return false; + }, + + arrayIndexOf: function(arr, val, start) { + if (typeof arr.indexOf == "function") + return arr.indexOf(val, start); + for (var i = (start || 0), j = arr.length; i < j; i++) { + if (arr[i] === val) { + return i; + } + } + return -1; + } +}); + +SUGAR.clearRelateField = function(form, name, id) +{ + if (typeof form[name] == "object"){ + form[name].value = ''; + SUGAR.util.callOnChangeListers(form[name]); + } + + if (typeof form[id] == "object"){ + form[id].value = ''; + SUGAR.util.callOnChangeListers(form[id]); + } +}; +if(typeof(SUGAR.AutoComplete) == 'undefined') SUGAR.AutoComplete = {}; + +SUGAR.AutoComplete.getOptionsArray = function(options_index){ + var return_arr = []; + + var opts = SUGAR.language.get('app_list_strings', options_index); + if(typeof(opts) != 'undefined'){ + for(key in opts){ + // Since we are using auto complete, we excluse blank dropdown entries since they can just leave it blank + if(key != '' && opts[key] != ''){ + var item = []; + item['key'] = key; + item['text'] = opts[key]; + return_arr.push(item); + } + } + } + return return_arr; } -/** - * Compares a filename with a supplied array of allowed file extensions. - * @param fileName string - * @param allowedTypes array of allowed file extensions - * @return bool - */ -SUGAR.util.validateFileExt = function(fileName, allowedTypes) { - var ext = fileName.split('.').pop(); - for (var i = allowedTypes.length; i >= 0; i--) { - if (ext === allowedTypes[i]) { - return true; +if(typeof(SUGAR.MultiEnumAutoComplete) == 'undefined') SUGAR.MultiEnumAutoComplete = {}; + +SUGAR.MultiEnumAutoComplete.getMultiSelectKeysFromValues = function(options_index, val_string){ + var opts = SUGAR.language.get('app_list_strings', options_index); + var selected_values = val_string.split(", "); + // YUI AutoComplete adds a blank. We remove it automatically here + if(selected_values.length > 0 && selected_values.indexOf('') == selected_values.length - 1){ + selected_values.pop(); + } + var final_arr = new Array(); + for(idx in selected_values){ + for(o_idx in opts){ + if(selected_values[idx] == opts[o_idx]){ + final_arr.push(o_idx); + } } } + return final_arr; +} - return false; +SUGAR.MultiEnumAutoComplete.getMultiSelectValuesFromKeys = function(options_index, val_string){ + var opts = SUGAR.language.get('app_list_strings', options_index); + val_string=val_string.replace(/^\^/,'').replace(/\^$/,'') //fixes bug where string starts or ends with ^ + var selected_values = val_string.split("^,^"); + + // YUI AutoComplete adds a blank. We remove it automatically here + if(selected_values.length > 0 && selected_values.indexOf('') == selected_values.length - 1){ + selected_values.pop(); + } + + var final_arr = new Array(); + for(idx in selected_values){ + for(o_idx in opts){ + if(selected_values[idx] == o_idx){ + final_arr.push(opts[o_idx]); + } + } + } + return final_arr; } diff --git a/jssource/src_files/include/javascript/sugar_connection_event_listener.js b/jssource/src_files/include/javascript/sugar_connection_event_listener.js index 037c7cd0..6cc92821 100644 --- a/jssource/src_files/include/javascript/sugar_connection_event_listener.js +++ b/jssource/src_files/include/javascript/sugar_connection_event_listener.js @@ -39,7 +39,7 @@ SUGAR_callsInProgress = 0; YAHOO.util.Connect.completeEvent.subscribe(function(event, data){ SUGAR_callsInProgress--; - if (SUGAR.util.isLoginPage(data[0].conn.responseText)) + if (data[0].conn && data[0].conn.responseText && SUGAR.util.isLoginPage(data[0].conn.responseText)) return false; }); diff --git a/jssource/src_files/include/javascript/sugarwidgets/SugarYUIWidgets.js b/jssource/src_files/include/javascript/sugarwidgets/SugarYUIWidgets.js index b0e530ac..de5fca77 100644 --- a/jssource/src_files/include/javascript/sugarwidgets/SugarYUIWidgets.js +++ b/jssource/src_files/include/javascript/sugarwidgets/SugarYUIWidgets.js @@ -169,7 +169,8 @@ sw.Template.prototype = { append: function (target, args) { var tEl = Dom.get(target); if (tEl) tEl.innerHTML += this.exec(args); - else if (!SUGAR.isIE) console.log("Warning, unable to find target:" + target); + else if (typeof(console) != "undefined" && typeof(console.log) == "function") + console.log("Warning, unable to find target:" + target); }, exec : function (args) { var out = this.content; @@ -381,12 +382,20 @@ YAHOO.extend(sw.RowDD, YAHOO.util.DDProxy, { this.getEl().style.display = "none"; this.table.appendChild(this.getEl()); this.newTable.addRow(this.row.getData(), this.newIndex); - this.ddtable.deleteRow(this.row); + try{ + //This method works, but throws an error under IE8 + this.ddtable.deleteRow(this.row); + }catch(e){ + if(typeof(console) != "undefined" && console.log) + { + console.log(e); + } + } this.ddtable.render(); } this.newTable = this.newIndex = null - - var clickEl = this.getEl(); + + var clickEl = this.getEl(); Dom.setStyle(clickEl, "opacity", ""); } }); @@ -711,4 +720,4 @@ YAHOO.widget.TVSlideOut.prototype = { }; YAHOO.widget.Record._nCount = 0; YAHOO.widget.Record.prototype = temp; -})(); \ No newline at end of file +})(); diff --git a/jssource/src_files/modules/InboundEmail/InboundEmail.js b/jssource/src_files/modules/InboundEmail/InboundEmail.js index 43397751..4bc6d7b6 100644 --- a/jssource/src_files/modules/InboundEmail/InboundEmail.js +++ b/jssource/src_files/modules/InboundEmail/InboundEmail.js @@ -121,7 +121,8 @@ function ie_test_open_popup_with_submit(module_name, action, pageTarget, width, return; } - ie_id = (typeof document.getElementById(formName).ie_id != 'undefined') ? document.getElementById(formName).ie_id : ''; + if(typeof(ie_id) == 'undefined' || ie_id == '') + ie_id = (typeof document.getElementById(formName).ie_id != 'undefined') ? document.getElementById(formName).ie_id.value : ''; // launch the popup URL = 'index.php?' diff --git a/jssource/src_files/modules/Meetings/jsclass_scheduler.js b/jssource/src_files/modules/Meetings/jsclass_scheduler.js index 03a4ed51..8588f037 100644 --- a/jssource/src_files/modules/Meetings/jsclass_scheduler.js +++ b/jssource/src_files/modules/Meetings/jsclass_scheduler.js @@ -470,52 +470,59 @@ SugarWidgetScheduleRow.prototype.load = function (thetableid) { } SugarWidgetScheduleRow.prototype.display = function() { - var self = this; - var tr; - this.thetable = document.getElementById(this.thetableid); - - if(typeof (this.element) != 'undefined') { - if (this.element.parentNode != null) - this.thetable.deleteRow(this.element.rowIndex); - - tr = document.createElement('tr'); - this.thetable.appendChild(tr); - } else { - tr = this.thetable.insertRow(this.thetable.rows.length); - } - tr.className = "schedulerAttendeeRow"; - - td = document.createElement('td'); - tr.appendChild(td); - //insertCell(tr.cells.length); - - // icon + full name - td.scope = 'row'; - var img = ' '; - td.innerHTML = img; - - td.innerHTML = td.innerHTML; - - if (self.focus_bean.fields.full_name) - td.innerHTML += ' ' + self.focus_bean.fields.full_name; - else - td.innerHTML += ' ' + self.focus_bean.fields.name; - - // add freebusy tds here: - this.add_freebusy_nodes(tr); - - // delete button - var td = document.createElement('td'); - tr.appendChild(td); - //var td = tr.insertCell(tr.cells.length); - td.className = 'schedulerAttendeeDeleteCell'; - td.noWrap = true; - //CCL - Remove check to disallow removal of assigned user or current user - //if ( GLOBAL_REGISTRY.focus.fields.assigned_user_id != self.focus_bean.fields.id && GLOBAL_REGISTRY.current_user.fields.id != self.focus_bean.fields.id) { - td.innerHTML = ' '+ GLOBAL_REGISTRY['meeting_strings']['LBL_REMOVE'] +' '+ GLOBAL_REGISTRY['meeting_strings']['LBL_REMOVE'] +''; - //} - this.element = tr; - this.element_index = this.thetable.rows.length - 1; + SUGAR.util.doWhen("document.getElementById('" + this.thetableid + "') != null", function(){ + var tr; + this.thetable = document.getElementById(this.thetableid); + + if(typeof (this.element) != 'undefined') { + if (this.element.parentNode != null) + this.thetable.deleteRow(this.element.rowIndex); + + tr = document.createElement('tr'); + this.thetable.appendChild(tr); + } else { + tr = this.thetable.insertRow(this.thetable.rows.length); + } + tr.className = "schedulerAttendeeRow"; + + td = document.createElement('td'); + tr.appendChild(td); + //insertCell(tr.cells.length); + + // icon + full name + td.scope = 'row'; + var img = ' '; + td.innerHTML = img; + + td.innerHTML = td.innerHTML; + + if (this.focus_bean.fields.full_name) + td.innerHTML += ' ' + this.focus_bean.fields.full_name; + else + td.innerHTML += ' ' + this.focus_bean.fields.name; + + // add freebusy tds here: + this.add_freebusy_nodes(tr); + + // delete button + var td = document.createElement('td'); + tr.appendChild(td); + //var td = tr.insertCell(tr.cells.length); + td.className = 'schedulerAttendeeDeleteCell'; + td.noWrap = true; + //CCL - Remove check to disallow removal of assigned user or current user + //if ( GLOBAL_REGISTRY.focus.fields.assigned_user_id != this.focus_bean.fields.id && GLOBAL_REGISTRY.current_user.fields.id != this.focus_bean.fields.id) { + td.innerHTML = ' ' + + ''+ GLOBAL_REGISTRY['meeting_strings']['LBL_REMOVE'] +' ' + + GLOBAL_REGISTRY['meeting_strings']['LBL_REMOVE'] +''; + //} + this.element = tr; + this.element_index = this.thetable.rows.length - 1; + }, null, this); } SugarWidgetScheduleRow.deleteRow = function(bean_id) { diff --git a/jssource/src_files/modules/Studio/studio.js b/jssource/src_files/modules/Studio/studio.js index 8f2fe3ae..fcd9d5c6 100644 --- a/jssource/src_files/modules/Studio/studio.js +++ b/jssource/src_files/modules/Studio/studio.js @@ -479,7 +479,7 @@ function dropdownChanged(value){ select.length = 0; var count = 0; - for(var key in app_list_strings[value]){ + for(var key in app_list_strings[value]){ select[count] = new Option(app_list_strings[value][key], key); count++; } diff --git a/jssource/src_files/themes/Sugar5/js/style.js b/jssource/src_files/themes/Sugar5/js/style.js index e87223d7..13717b86 100644 --- a/jssource/src_files/themes/Sugar5/js/style.js +++ b/jssource/src_files/themes/Sugar5/js/style.js @@ -67,10 +67,7 @@ YAHOO.util.Event.onAvailable('sitemapLinkSpan',function() } }); -/** - * Handles changing the sub menu items when using grouptabs - */ -YAHOO.util.Event.onAvailable('subModuleList',IKEADEBUG); + function IKEADEBUG() { var moduleLinks = document.getElementById('moduleList').getElementsByTagName("a"); @@ -216,3 +213,71 @@ YAHOO.util.Event.onDOMReady(function() } //////////////////////////////////////////////////////////////////////////////////////// }); + +/** + * For the module list menu + */ +SUGAR.themes = SUGAR.namespace("themes"); + +SUGAR.append(SUGAR.themes, { + allMenuBars: {}, + setModuleTabs: function(html) { + var el = document.getElementById('ajaxHeader'); + + if (el) { + try { + //This can fail hard if multiple events fired at the same time + YAHOO.util.Event.purgeElement(el, true); + for (var i in this.allMenuBars) { + if (this.allMenuBars[i].destroy) + this.allMenuBars[i].destroy(); + } + } catch (e) { + //If the menu fails to load, we can get leave the user stranded, reload the page instead. + window.location.reload(); + } + + if (el.hasChildNodes()) { + while (el.childNodes.length >= 1) { + el.removeChild(el.firstChild); + } + } + + el.innerHTML += html; + this.loadModuleList(); + } + }, + + loadModuleList: function() { + var nodes = YAHOO.util.Selector.query('#moduleList>div'), + currMenuBar; + this.allMenuBars = {}; + + for (var i = 0 ; i < nodes.length ; i++) { + currMenuBar = SUGAR.themes.currMenuBar = new YAHOO.widget.MenuBar(nodes[i].id, { + autosubmenudisplay: true, + visible: false, + hidedelay: 750, + lazyload: true + }); + + /* + Call the "render" method with no arguments since the + markup for this MenuBar already exists in the page. + */ + currMenuBar.render(); + this.allMenuBars[nodes[i].id.substr(nodes[i].id.indexOf('_')+1)] = currMenuBar; + + if (typeof YAHOO.util.Dom.getChildren(nodes[i]) == 'object' && YAHOO.util.Dom.getChildren(nodes[i]).shift().style.display != 'none') { + // This is the currently displayed menu bar + oMenuBar = currMenuBar; + } + } + /** + * Handles changing the sub menu items when using grouptabs + */ + YAHOO.util.Event.onAvailable('subModuleList',IKEADEBUG); + } +}); + +YAHOO.util.Event.onDOMReady(SUGAR.themes.loadModuleList, SUGAR.themes, true); diff --git a/metadata/calls_usersMetaData.php b/metadata/calls_usersMetaData.php index e971de79..13c04878 100644 --- a/metadata/calls_usersMetaData.php +++ b/metadata/calls_usersMetaData.php @@ -1,5 +1,5 @@ 'calls_users' - , 'fields' => array ( - array('name' =>'id', 'type' =>'varchar', 'len'=>'36') - , array('name' =>'call_id', 'type' =>'varchar', 'len'=>'36') - , array('name' =>'user_id', 'type' =>'varchar', 'len'=>'36') - , array('name' =>'required', 'type' =>'varchar', 'len'=>'1', 'default'=>'1') - , array('name' =>'accept_status', 'type' =>'varchar', 'len'=>'25', 'default'=>'none') - , array ('name' => 'date_modified','type' => 'datetime') - , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0', 'required'=>false) - ) , 'indices' => array ( - array('name' =>'calls_userspk', 'type' =>'primary', 'fields'=>array('id')) - , array('name' =>'idx_usr_call_call', 'type' =>'index', 'fields'=>array('call_id')) - , array('name' =>'idx_usr_call_usr', 'type' =>'index', 'fields'=>array('user_id')) - , array('name' => 'idx_call_users', 'type'=>'alternate_key', 'fields'=>array('call_id','user_id')) - ) - , 'relationships' => array ('calls_users' => array('lhs_module'=> 'Calls', 'lhs_table'=> 'calls', 'lhs_key' => 'id', - 'rhs_module'=> 'Users', 'rhs_table'=> 'users', 'rhs_key' => 'id', - 'relationship_type'=>'many-to-many', - 'join_table'=> 'calls_users', 'join_key_lhs'=>'call_id', 'join_key_rhs'=>'user_id')) - -) +$dictionary['calls_users'] = array( + 'table' => 'calls_users', + 'fields' => array( + array('name' => 'id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'call_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'user_id', 'type' => 'varchar', 'len' => '36'), + array('name' => 'required', 'type' => 'varchar', 'len' => '1', 'default' => '1'), + array('name' => 'accept_status', 'type' => 'varchar', 'len' => '25', 'default' => 'none'), + array('name' => 'date_modified', 'type' => 'datetime'), + array('name' => 'deleted', 'type' => 'bool', 'len' => '1', 'default' => '0', 'required' => false) + ), + 'indices' => array( + array('name' => 'calls_userspk', 'type' => 'primary', 'fields' => array('id')), + array('name' => 'idx_usr_call_call', 'type' => 'index', 'fields' => array('call_id')), + array('name' => 'idx_usr_call_usr', 'type' => 'index', 'fields' => array('user_id')), + array('name' => 'idx_call_users', 'type' => 'alternate_key', 'fields' => array('call_id', 'user_id')) + ), + 'relationships' => array( + 'calls_users' => array( + 'lhs_module' => 'Calls', + 'lhs_table' => 'calls', + 'lhs_key' => 'id', + 'rhs_module' => 'Users', + 'rhs_table' => 'users', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'calls_users', + 'join_key_lhs' => 'call_id', + 'join_key_rhs' => 'user_id', + ), + ), +); ?> diff --git a/metadata/contacts_bugsMetaData.php b/metadata/contacts_bugsMetaData.php index ee8acf7b..541d4218 100644 --- a/metadata/contacts_bugsMetaData.php +++ b/metadata/contacts_bugsMetaData.php @@ -1,5 +1,5 @@ 'contacts_bugs' - , 'fields' => array ( - array('name' =>'id', 'type' =>'varchar', 'len'=>'36') - , array('name' =>'contact_id', 'type' =>'varchar', 'len'=>'36', ) - , array('name' =>'bug_id', 'type' =>'varchar', 'len'=>'36', ) - , array('name' =>'contact_role', 'type' =>'varchar', 'len'=>'50', ) - , array ('name' => 'date_modified','type' => 'datetime') - , array('name' =>'deleted', 'type' =>'bool', 'len'=>'1', 'default'=>'0','required'=>false) - ) , 'indices' => array ( - array('name' =>'contacts_bugspk', 'type' =>'primary', 'fields'=>array('id')) - , array('name' =>'idx_con_bug_con', 'type' =>'index', 'fields'=>array('contact_id')) - , array('name' =>'idx_con_bug_bug', 'type' =>'index', 'fields'=>array('bug_id')) - , array('name' => 'idx_contact_bug', 'type'=>'alternate_key', 'fields'=>array('contact_id','bug_id')) - - ) - , 'relationships' => array ('contacts_bugs' => array('lhs_module'=> 'Contacts', 'lhs_table'=> 'contacts', 'lhs_key' => 'id', - 'rhs_module'=> 'Bugs', 'rhs_table'=> 'bugs', 'rhs_key' => 'id', - 'relationship_type'=>'many-to-many', - 'join_table'=> 'contacts_bugs', 'join_key_lhs'=>'contact_id', 'join_key_rhs'=>'bug_id')) - - - ) +$dictionary['contacts_bugs'] = array('table' => 'contacts_bugs' +, 'fields' => array( + array('name' => 'id', 'type' => 'varchar', 'len' => '36') + , array('name' => 'contact_id', 'type' => 'varchar', 'len' => '36',) + , array('name' => 'bug_id', 'type' => 'varchar', 'len' => '36',) + , array('name' => 'contact_role', 'type' => 'varchar', 'len' => '50',) + , array('name' => 'date_modified', 'type' => 'datetime') + , array('name' => 'deleted', 'type' => 'bool', 'len' => '1', 'default' => '0', 'required' => false) + ), 'indices' => array( + array('name' => 'contacts_bugspk', 'type' => 'primary', 'fields' => array('id')) + , array('name' => 'idx_con_bug_con', 'type' => 'index', 'fields' => array('contact_id')) + , array('name' => 'idx_con_bug_bug', 'type' => 'index', 'fields' => array('bug_id')) + , array('name' => 'idx_contact_bug', 'type' => 'alternate_key', 'fields' => array('contact_id', 'bug_id')) + + ) +, 'relationships' => array( + 'contacts_bugs' => array( + 'lhs_module' => 'Contacts', + 'lhs_table' => 'contacts', + 'lhs_key' => 'id', + 'rhs_module' => 'Bugs', + 'rhs_table' => 'bugs', + 'rhs_key' => 'id', + 'relationship_type' => 'many-to-many', + 'join_table' => 'contacts_bugs', + 'join_key_lhs' => 'contact_id', 'join_key_rhs' => 'bug_id')) + + +) ?> diff --git a/metadata/foldersMetaData.php b/metadata/foldersMetaData.php index 90797232..42b75352 100644 --- a/metadata/foldersMetaData.php +++ b/metadata/foldersMetaData.php @@ -173,7 +173,7 @@ $dictionary['folders_rel'] = array( 'type' => 'varchar', 'len' => 25, 'required' => true, - ), + ), array( 'name' => 'polymorphic_id', 'type' => 'id', @@ -197,9 +197,9 @@ $dictionary['folders_rel'] = array( 'fields' => array('polymorphic_module', 'polymorphic_id'), ), array( - 'name' => 'idx_folders_rel_folder_id', - 'type' => 'index', - 'fields' => array('folder_id'), + 'name' => 'idx_fr_id_deleted_poly', + 'type' => 'index', + 'fields' => array('folder_id','deleted','polymorphic_id'), ), ), ); diff --git a/metadata/oauth_nonce.php b/metadata/oauth_nonce.php new file mode 100644 index 00000000..accca146 --- /dev/null +++ b/metadata/oauth_nonce.php @@ -0,0 +1,76 @@ + 'oauth_nonce', + 'fields' => array( + 'conskey' => array( + 'name' => 'conskey', + 'type' => 'varchar', + 'len' => 32, + 'required' => true, + 'isnull' => false, + ), + 'nonce' => array( + 'name' => 'nonce', + 'type' => 'varchar', + 'len' => 32, + 'required' => true, + 'isnull' => false, + ), + 'nonce_ts' => array( + 'name' => 'nonce_ts', + 'type' => 'long', + 'required' => true, + ), + ), + 'indices' => array( + array( + 'name' => 'oauth_nonce_pk', + 'type' => 'primary', + 'fields' => array('conskey', 'nonce') + ), + array( + 'name' => 'oauth_nonce_keyts', + 'type' => 'index', + 'fields' => array('conskey', 'nonce_ts') + ), + ), +); diff --git a/modules/ACLActions/actiondefs.php b/modules/ACLActions/actiondefs.php index de1068f3..a13768be 100644 --- a/modules/ACLActions/actiondefs.php +++ b/modules/ACLActions/actiondefs.php @@ -116,7 +116,12 @@ $GLOBALS['ACLActions'] = array( 'label'=>'LBL_ACTION_EXPORT', 'default'=>ACL_ALLOW_ALL, ), - + 'massupdate'=> + array( + 'aclaccess'=>array(ACL_ALLOW_ALL,ACL_ALLOW_DEFAULT, ACL_ALLOW_NONE), + 'label'=>'LBL_ACTION_MASSUPDATE', + 'default'=>ACL_ALLOW_ALL, + ), ),), diff --git a/modules/ACLActions/language/en_us.lang.php b/modules/ACLActions/language/en_us.lang.php index df088cd3..13013f98 100644 --- a/modules/ACLActions/language/en_us.lang.php +++ b/modules/ACLActions/language/en_us.lang.php @@ -58,6 +58,7 @@ $mod_strings = array ( 'LBL_ACTION_IMPORT'=>'Import', 'LBL_ACTION_EXPORT'=>'Export', 'LBL_ACTION_LIST'=>'List', +'LBL_ACTION_MASSUPDATE' => 'Mass Update', 'LBL_ACTION_ACCESS'=>'Access', 'LBL_ACTION_ADMIN'=>'Access Type', 'LBL_ACCESS_DEFAULT'=>'Not Set', diff --git a/modules/Accounts/AccountFormBase.php b/modules/Accounts/AccountFormBase.php index cd896920..a4c49910 100644 --- a/modules/Accounts/AccountFormBase.php +++ b/modules/Accounts/AccountFormBase.php @@ -169,12 +169,12 @@ function buildTableForm($rows, $mod='Accounts'){ $form .= ""; if ($action != 'ShowDuplicates') { - $form .= "[${app_strings['LBL_SELECT_BUTTON_LABEL']}]  \n"; + $form .= "[${app_strings['LBL_SELECT_BUTTON_LABEL']}]  \n"; } foreach ($row as $key=>$value){ if($key != 'id'){ if(isset($_POST['popup']) && $_POST['popup']==true){ - $form .= "$value\n"; + $form .= "$value\n"; } else $form .= "$value\n"; @@ -475,16 +475,21 @@ function handleSave($prefix,$redirect=true, $useRequired=false){ if(!empty($_POST['popup'])) $get .= '&popup='.$_POST['popup']; if(!empty($_POST['create'])) $get .= '&create='.$_POST['create']; + $_SESSION['SHOW_DUPLICATES'] = $get; //now redirect the post to modules/Accounts/ShowDuplicates.php if (!empty($_POST['is_ajax_call']) && $_POST['is_ajax_call'] == '1') { ob_clean(); $json = getJSONobj(); - $_SESSION['SHOW_DUPLICATES'] = $get; echo $json->encode(array('status' => 'dupe', 'get' => $location)); - } else { - if(!empty($_POST['to_pdf'])) $location .= '&to_pdf='.$_POST['to_pdf']; - $_SESSION['SHOW_DUPLICATES'] = $get; + } + else if(!empty($_REQUEST['ajax_load'])) + { + echo ""; + } + else { + if(!empty($_POST['to_pdf'])) + $location .= '&to_pdf='.$_POST['to_pdf']; header("Location: index.php?$location"); } return null; diff --git a/modules/Accounts/Popup_picker.html b/modules/Accounts/Popup_picker.html index 2d088b68..af4e8681 100644 --- a/modules/Accounts/Popup_picker.html +++ b/modules/Accounts/Popup_picker.html @@ -116,7 +116,7 @@ {PREROW} -<{TAG_TYPE} href="#" onclick="send_back('Accounts','{ACCOUNT.ID}');" >{ACCOUNT.NAME} +<{TAG_TYPE} href="javascript:void(0)" onclick="send_back('Accounts','{ACCOUNT.ID}');" >{ACCOUNT.NAME} {ACCOUNT.CITY} {ACCOUNT.PHONE_OFFICE} diff --git a/modules/Accounts/ShowDuplicates.php b/modules/Accounts/ShowDuplicates.php index af09883c..d446ec7f 100644 --- a/modules/Accounts/ShowDuplicates.php +++ b/modules/Accounts/ShowDuplicates.php @@ -52,7 +52,8 @@ $error_msg = ''; global $current_language; $mod_strings = return_module_language($current_language, 'Accounts'); -echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_MODULE_NAME'],$mod_strings['LBL_SAVE_ACCOUNT']), true); +$moduleName = $GLOBALS['app_list_strings']['moduleList']['Accounts']; +echo getClassicModuleTitle('Accounts', array($moduleName, $mod_strings['LBL_SAVE_ACCOUNT']), true); $xtpl=new XTemplate ('modules/Accounts/ShowDuplicates.html'); $xtpl->assign("MOD", $mod_strings); $xtpl->assign("APP", $app_strings); diff --git a/modules/Accounts/language/en_us.lang.php b/modules/Accounts/language/en_us.lang.php index 6d37e3ac..748b8700 100644 --- a/modules/Accounts/language/en_us.lang.php +++ b/modules/Accounts/language/en_us.lang.php @@ -59,7 +59,7 @@ $mod_strings = array ( 'ACCOUNT_REMOVE_PROJECT_CONFIRM' => 'Are you sure you want to remove this account from the project?', 'ERR_DELETE_RECORD' => 'You must specify a record number in order to delete the account.', - 'LBL_ACCOUNT_INFORMATION' => 'Account Overview', + 'LBL_ACCOUNT_INFORMATION' => 'Overview', 'LBL_ACCOUNT_NAME' => 'Account Name:', 'LBL_ACCOUNT' => 'Account:', 'LBL_ACTIVITIES_SUBPANEL_TITLE'=>'Activities', @@ -81,7 +81,7 @@ $mod_strings = array ( 'LBL_BILLING_ADDRESS' => 'Billing Address:', 'LBL_BUG_FORM_TITLE' => 'Accounts', 'LBL_BUGS_SUBPANEL_TITLE' => 'Bugs', - 'LBL_CALLS_SUBPANEL_TITLE' => 'Calls', + 'LBL_CALLS_SUBPANEL_TITLE' => 'Calls', 'LBL_CAMPAIGN_ID' => 'Campaign ID', 'LBL_CASES_SUBPANEL_TITLE' => 'Cases', 'LBL_CITY' => 'City:', @@ -96,7 +96,7 @@ $mod_strings = array ( 'LBL_DUPLICATE' => 'Possible Duplicate Account', 'LBL_EMAIL' => 'Email Address:', 'LBL_EMAIL_OPT_OUT' => 'Email Opt Out:', - //'LBL_EMAIL_ADDRESSES' => 'Email Addresses', + 'LBL_EMAIL_ADDRESSES' => 'Email Addresses', 'LBL_EMPLOYEES' => 'Employees:', 'LBL_FAX' => 'Fax:', 'LBL_HISTORY_SUBPANEL_TITLE'=>'History', @@ -105,7 +105,7 @@ $mod_strings = array ( 'LBL_INVALID_EMAIL'=>'Invalid Email:', 'LBL_INVITEE' => 'Contacts', 'LBL_LEADS_SUBPANEL_TITLE' => 'Leads', - 'LBL_LIST_ACCOUNT_NAME' => 'Account Name', + 'LBL_LIST_ACCOUNT_NAME' => 'Name', 'LBL_LIST_CITY' => 'City', 'LBL_LIST_CONTACT_NAME' => 'Contact Name', 'LBL_LIST_EMAIL_ADDRESS' => 'Email Address', @@ -179,5 +179,13 @@ $mod_strings = array ( 'LBL_PROSPECT_LIST' => 'Prospect List', 'LBL_ACCOUNTS_SUBPANEL_TITLE'=>'Accounts', 'LBL_PROJECT_SUBPANEL_TITLE' => 'Projects', + //For export labels + 'LBL_ACCOUNT_TYPE' => 'Account Type', + 'LBL_CAMPAIGN_ID' => 'Campaign ID', + 'LBL_PARENT_ID' => 'Parent ID', + 'LBL_PHONE_ALTERNATE' => 'Phone Alternate', + 'LBL_EXPORT_ASSIGNED_USER_NAME' => 'Assigned User Name', + // SNIP + 'LBL_CONTACT_HISTORY_SUBPANEL_TITLE' => 'Related Contacts\' Emails', ); -?> \ No newline at end of file +?> diff --git a/modules/Accounts/metadata/subpaneldefs.php b/modules/Accounts/metadata/subpaneldefs.php index ac8767d8..02eda2be 100644 --- a/modules/Accounts/metadata/subpaneldefs.php +++ b/modules/Accounts/metadata/subpaneldefs.php @@ -38,7 +38,7 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); $layout_defs['Accounts'] = array( - // list of what Subpanels to show in the DetailView + // list of what Subpanels to show in the DetailView 'subpanel_setup' => array( 'activities' => array( @@ -50,15 +50,15 @@ $layout_defs['Accounts'] = array( 'subpanel_name' => 'activities', //this values is not associated with a physical file. 'header_definition_from_subpanel'=> 'meetings', 'module'=>'Activities', - + 'top_buttons' => array( array('widget_class' => 'SubPanelTopCreateTaskButton'), array('widget_class' => 'SubPanelTopScheduleMeetingButton'), array('widget_class' => 'SubPanelTopScheduleCallButton'), array('widget_class' => 'SubPanelTopComposeEmailButton'), - ), - - 'collection_list' => array( + ), + + 'collection_list' => array( 'tasks' => array( 'module' => 'Tasks', 'subpanel_name' => 'ForActivities', @@ -74,7 +74,7 @@ $layout_defs['Accounts'] = array( 'subpanel_name' => 'ForActivities', 'get_subpanel_data' => 'calls', ), - ) + ) ), 'history' => array( 'order' => 20, @@ -85,14 +85,14 @@ $layout_defs['Accounts'] = array( 'subpanel_name' => 'history', //this values is not associated with a physical file. 'header_definition_from_subpanel'=> 'meetings', 'module'=>'History', - + 'top_buttons' => array( array('widget_class' => 'SubPanelTopCreateNoteButton'), array('widget_class' => 'SubPanelTopArchiveEmailButton'), array('widget_class' => 'SubPanelTopSummaryButton'), - ), - - 'collection_list' => array( + ), + + 'collection_list' => array( 'tasks' => array( 'module' => 'Tasks', 'subpanel_name' => 'ForHistory', @@ -112,20 +112,20 @@ $layout_defs['Accounts'] = array( 'module' => 'Notes', 'subpanel_name' => 'ForHistory', 'get_subpanel_data' => 'notes', - ), + ), 'emails' => array( 'module' => 'Emails', 'subpanel_name' => 'ForHistory', 'get_subpanel_data' => 'emails', - ), + ), 'linkedemails' => array( 'module' => 'Emails', 'subpanel_name' => 'ForUnlinkedEmailHistory', 'get_subpanel_data' => 'function:get_unlinked_email_query', 'generate_select'=>true, 'function_parameters' => array('return_as_array'=>'true'), - ), - ) + ), + ) ), 'documents' => array( 'order' => 25, @@ -135,13 +135,13 @@ $layout_defs['Accounts'] = array( 'sort_by' => 'id', 'title_key' => 'LBL_DOCUMENTS_SUBPANEL_TITLE', 'get_subpanel_data' => 'documents', - 'top_buttons' => + 'top_buttons' => array ( - 0 => + 0 => array ( 'widget_class' => 'SubPanelTopButtonQuickCreate', ), - 1 => + 1 => array ( 'widget_class' => 'SubPanelTopSelectButton', 'mode' => 'MultiSelect', @@ -162,7 +162,7 @@ $layout_defs['Accounts'] = array( array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') ), - ), + ), 'opportunities' => array( 'order' => 40, 'module' => 'Opportunities', @@ -189,10 +189,10 @@ $layout_defs['Accounts'] = array( array('widget_class' => 'SubPanelTopCreateLeadNameButton'), array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Opportunities', - 'mode' => 'MultiSelect', + 'mode' => 'MultiSelect', ), ), - + ), 'cases' => array( 'order' => 100, @@ -257,8 +257,8 @@ $layout_defs['Accounts'] = array( 'sort_by' => 'activity_date', 'get_subpanel_data'=>'campaigns', 'subpanel_name' => 'ForTargets', - 'title_key' => 'LBL_CAMPAIGNS', - ), + 'title_key' => 'LBL_CAMPAIGNS', + ), ), ); ?> diff --git a/modules/Accounts/metadata/subpanels/ForEmails.php b/modules/Accounts/metadata/subpanels/ForEmails.php index 2dac7e85..f08d4ce0 100644 --- a/modules/Accounts/metadata/subpanels/ForEmails.php +++ b/modules/Accounts/metadata/subpanels/ForEmails.php @@ -37,6 +37,7 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); + $subpanel_layout = array( 'top_buttons' => array( array('widget_class' => 'SubPanelTopCreateButton'), @@ -45,7 +46,6 @@ $subpanel_layout = array( 'where' => '', - 'list_fields' => array( 'name' => array( 'vname' => 'LBL_LIST_ACCOUNT_NAME', diff --git a/modules/Administration/RebuildJSLang.php b/modules/Administration/RebuildJSLang.php index eec47bc5..25001402 100644 --- a/modules/Administration/RebuildJSLang.php +++ b/modules/Administration/RebuildJSLang.php @@ -39,20 +39,11 @@ if(is_admin($current_user)){ global $mod_strings, $sugar_config; echo $mod_strings['LBL_REBUILD_JAVASCRIPT_LANG_DESC']; - - $jsFiles = array(); - getFiles($jsFiles, $sugar_config['cache_dir'] . 'jsLanguage'); - foreach($jsFiles as $file) { - unlink($file); - } - - if(empty($sugar_config['js_lang_version'])) $sugar_config['js_lang_version'] = 1; - else $sugar_config['js_lang_version'] += 1; - - write_array_to_file( "sugar_config", $sugar_config, "config.php"); + + //remove the js language files + LanguageManager::removeJSLanguageFiles(); //remove lanugage cache files - LanguageManager::clearLanguageCache(); } else{ diff --git a/modules/Administration/RebuildRelationship.php b/modules/Administration/RebuildRelationship.php index 9520531d..5ba453de 100644 --- a/modules/Administration/RebuildRelationship.php +++ b/modules/Administration/RebuildRelationship.php @@ -106,7 +106,7 @@ foreach ( $GLOBALS['beanFiles'] as $bean => $file ) $rel_dictionary = $dictionary ; foreach ( $rel_dictionary as $rel_name => $rel_data ) { - $table = $rel_data [ 'table' ] ; + $table = isset($rel_data [ 'table' ]) ? $rel_data [ 'table' ] : "" ; if (empty ( $_REQUEST [ 'silent' ] )) echo $mod_strings [ 'LBL_REBUILD_REL_PROC_C_META' ] . $rel_name . "..." ; @@ -140,6 +140,10 @@ $query = 'INSERT INTO versions (id, deleted, date_entered, date_modified, modifi $log->info ( $query ) ; $db->query ( $query ) ; +$rel = new Relationship(); +Relationship::delete_cache(); +$rel->build_relationship_cache(); + // unset the session variable so it is not picked up in DisplayWarnings.php if (isset ( $_SESSION [ 'rebuild_relationships' ] )) { diff --git a/modules/Administration/SupportPortal.php b/modules/Administration/SupportPortal.php index 757a6a3c..503ee98c 100644 --- a/modules/Administration/SupportPortal.php +++ b/modules/Administration/SupportPortal.php @@ -222,4 +222,5 @@ switch ($_REQUEST['view']) { //$sugar_smarty->assign('iframeURL', $iframe_url); } break; -} \ No newline at end of file + +} diff --git a/modules/Administration/action_view_map.php b/modules/Administration/action_view_map.php index f22d196d..673786ac 100644 --- a/modules/Administration/action_view_map.php +++ b/modules/Administration/action_view_map.php @@ -38,6 +38,7 @@ $action_view_map['themesettings'] = 'themesettings'; $action_view_map['repair'] = 'repair'; $action_view_map['configuretabs'] = 'configuretabs'; +$action_view_map['configureajaxui'] = 'configureajaxui'; $action_view_map['enablewirelessmodules'] = 'enablewirelessmodules'; $action_view_map['configureshortcutbar'] = 'configureshortcutbar'; $action_view_map['viewofflineclients'] = 'viewofflineclients'; diff --git a/modules/Administration/controller.php b/modules/Administration/controller.php index 4316d6c0..d5b7a58b 100644 --- a/modules/Administration/controller.php +++ b/modules/Administration/controller.php @@ -90,10 +90,7 @@ class AdministrationController extends SugarController { require_once('modules/Administration/Forms.php'); - global $mod_strings; - global $app_list_strings; - global $app_strings; - global $current_user; + global $app_strings, $current_user, $moduleList; if (!is_admin($current_user)) sugar_die($app_strings['ERR_NOT_ADMIN']); @@ -130,7 +127,12 @@ class AdministrationController extends SugarController mkdir_recursive ( dirname ( $filename ) ) ; write_array_to_file ( 'wireless_module_registry', $updated_enabled_modules, $filename ); - + foreach($moduleList as $mod){ + sugar_cache_clear("CONTROLLER_wireless_module_registry_$mod"); + } + //Users doesn't appear in the normal module list, but its value is cached on login. + sugar_cache_clear("CONTROLLER_wireless_module_registry_Users"); + sugar_cache_reset(); } echo "true"; @@ -163,4 +165,14 @@ class AdministrationController extends SugarController echo "false"; } } + + public function action_UpdateAjaxUI() + { + require_once('modules/Configurator/Configurator.php'); + $cfg = new Configurator(); + $disabled = json_decode(html_entity_decode ($_REQUEST['disabled_modules'], ENT_QUOTES)); + $cfg->config['addAjaxBannedModules'] = empty($disabled) ? FALSE : $disabled; + $cfg->handleOverride(); + $this->view = "configureajaxui"; + } } diff --git a/modules/Administration/index.php b/modules/Administration/index.php index f5eb8ce0..710c7fd6 100644 --- a/modules/Administration/index.php +++ b/modules/Administration/index.php @@ -65,6 +65,7 @@ global $admin_group_header; ///variable defined in the file above. $tab = array(); $header_image = array(); $url = array(); +$onclick = array(); $label_tab = array(); $id_tab = array(); $description = array(); @@ -117,6 +118,9 @@ foreach ($admin_group_header as $key=>$values) { $colnum+=1; $header_image[$j][$i]= SugarThemeRegistry::current()->getImage($admin_option[0],'alt="' . translate($admin_option[1],'Administration') .'" border="0" align="absmiddle"'); $url[$j][$i] = $admin_option[3]; + if(!empty($admin_option[5])) { + $onclick[$j][$i] = $admin_option[5]; + } $label = translate($admin_option[1],'Administration'); if(!empty($admin_option['additional_label']))$label.= ' '. $admin_option['additional_label']; if(!empty($admin_option[4])){ @@ -152,6 +156,7 @@ $sugar_smarty->assign("ADMIN_GROUP_HEADER", $admin_group_header_tab); $sugar_smarty->assign("GROUP_HEADER", $group); $sugar_smarty->assign("ITEM_HEADER_IMAGE", $header_image); $sugar_smarty->assign("ITEM_URL", $url); +$sugar_smarty->assign("ITEM_ONCLICK", $onclick); $sugar_smarty->assign("ITEM_HEADER_LABEL",$label_tab); $sugar_smarty->assign("ITEM_DESCRIPTION", $description); $sugar_smarty->assign("COLNUM", $tab); diff --git a/modules/Administration/index.tpl b/modules/Administration/index.tpl index 0710d1f9..63bee282 100644 --- a/modules/Administration/index.tpl +++ b/modules/Administration/index.tpl @@ -38,11 +38,11 @@ *} -
    -
    + + +
    -
    -
    +
    {$MY_FRAME} @@ -67,10 +67,9 @@ {$ITEM_DESCRIPTION[$j][$i]} {assign var='i' value=$i+1} - {if $COLNUM[$j][$i] == '0'} + {if $COLNUM[$j][$i] == '0'} {$ITEM_HEADER_IMAGE[$j][$i]} {$ITEM_HEADER_LABEL[$j][$i]} {$ITEM_DESCRIPTION[$j][$i]} - {else}     @@ -86,7 +85,7 @@
    -
    +
    -
    -
    \ No newline at end of file + + diff --git a/modules/Administration/language/en_us.lang.php b/modules/Administration/language/en_us.lang.php index 7d8b0ece..e8884774 100644 --- a/modules/Administration/language/en_us.lang.php +++ b/modules/Administration/language/en_us.lang.php @@ -125,18 +125,18 @@ $mod_strings = array ( 'ERR_UW_UPLOAD_ERROR' => "There was an error uploading the file, please try again!
    \n", 'ERROR_FLAVOR_INCOMPATIBLE' => 'The uploaded file is not compatible with this flavor (Community Edition, Professional, or Enterprise) of Sugar: ', 'ERROR_LICENSE_EXPIRED'=> "Error: Your license expired ", - 'ERROR_LICENSE_EXPIRED2' => " day(s) ago. Please go to the '\"License Management\" in the Admin screen to enter your new license key. If you do not enter a new license key within 30 days of your license key expiration, you will no longer be able to log into this application.", + 'ERROR_LICENSE_EXPIRED2' => " day(s) ago. Please go to the '\"License Management\" in the Admin screen to enter your new license key. If you do not enter a new license key within 7 days of your license key expiration, you will no longer be able to log into this application.", 'ERROR_MANIFEST_TYPE' => 'Manifest file must specify the package type.', 'ERROR_PACKAGE_TYPE' => 'Manifest file specifies an unrecognized package type', 'ERROR_VALIDATION_EXPIRED'=> "Error: Your validation key expired ", - 'ERROR_VALIDATION_EXPIRED2' => " day(s) ago. Please go to the '\"License Management\" in the Admin screen to enter your new validation key. If you do not enter a new validation key within 30 days of your validation key expiration, you will no longer be able to log into this application.", + 'ERROR_VALIDATION_EXPIRED2' => " day(s) ago. Please go to the '\"License Management\" in the Admin screen to enter your new validation key. If you do not enter a new validation key within 7 days of your validation key expiration, you will no longer be able to log into this application.", 'ERROR_VERSION_INCOMPATIBLE' => 'The uploaded file is not compatible with this version of Sugar: ', 'FATAL_LICENSE_ALTERED' => "Your license has been altered since the last time you validated it.
    Please go to the '\"License Management\" in the Admin screen.", - 'FATAL_LICENSE_EXPIRED'=> "Fatal: Your license expired more than 30 days ago", + 'FATAL_LICENSE_EXPIRED'=> "Fatal: Your license expired more than 7 days ago", 'FATAL_LICENSE_EXPIRED2'=> "Please go to the '\"License Management\" on the Admin page to update your license information and restore full functionality.", 'FATAL_LICENSE_REQUIRED' => "Fatal: Your license key information is required .
    Please go to the '\"License Management\" in the Admin screen to update your license information and restore full functionality.", - 'FATAL_VALIDATION_EXPIRED'=> "Fatal: Your validation key expired more than 30 days ago", + 'FATAL_VALIDATION_EXPIRED'=> "Fatal: Your validation key expired more than 7 days ago", 'FATAL_VALIDATION_EXPIRED2'=> "Please go to the '\"License Management\" in the Admin screen to update your license information and restore full functionality.", 'FATAL_VALIDATION_REQUIRED' => "Fatal: Your validation key information is required .
    Please go to the '\"License Management\" in the Admin screen to update your license information and restore full functionality.
    Either re-save your license information to have it authenticated or export the key and import the validation key. " , 'HDR_LOGIN_PANEL' => 'Please enter your sugarcrm.com credentials.', @@ -180,7 +180,7 @@ $mod_strings = array ( 'LBL_BUG_DESC' => 'Maintain a list of releases for your product. Active releases are displayed in the Releases drop-down menus in bug records created within the Bug Tracker module.', 'LBL_CANCEL_BUTTON_TITLE' => 'Cancel', 'LBL_CAT_VIEW' => 'Categories', - 'LBL_CHANGE_NAME_TABS'=>'Change the names of the navigation tabs', + 'LBL_CHANGE_NAME_MODULES'=>'Change the names of the modules appearing within the application', 'LBL_CHECK_FOR_UPDATES' => 'Check for Updates', 'LBL_CHECK_NOW_LABEL' =>'Check Now', 'LBL_CHECK_NOW_TITLE' =>'Check Now', @@ -201,6 +201,9 @@ $mod_strings = array ( 'LBL_CLEAR_PDF_FONT_CACHE_TITLE'=>'Clear PDF Font File Cache', 'LBL_CLEAR_PDF_FONT_CACHE_DESC'=>'Removes cached file used to store PDF fonts data', 'LBL_CONFIG_CHECK' =>'Config Check', + 'LBL_CONFIG_AJAX' => 'Configure AJAX User Interface', + 'LBL_CONFIG_AJAX_DESC' => 'Performance and page-rendering times are improved in AJAX UI-enabled modules because full page refreshes are not required in those modules. If you are experiencing display issues with modules that are not compatible with AJAX, the AJAX UI for those modules can be disabled.', + 'LBL_CONFIG_AJAX_HELP' => 'Drag and drop the names of the modules below to enable or disable the use of the AJAX UI in those modules.', 'LBL_CONFIG_TABS'=>'Display Module Tabs and Subpanels', 'LBL_CONFIG_TABS_DESC'=>'Drag and Drop the names of the modules below to set tabs or subpanels to be displayed or to be hidden.', 'LBL_CONFIG_LANGS_DESC'=>'Drag and Drop the names of the languages below to enable and disable them.', @@ -338,6 +341,8 @@ $mod_strings = array ( 'LBL_IMPORT_CUSTOM_FIELDS_TITLE' => 'Import Custom Fields Structure', 'LBL_IMPORT_CUSTOM_FIELDS'=> 'Import custom field definitions from a .sugar file', 'LBL_IMPORT_VALIDATION_KEY' =>'Import Validation Key', + 'LBL_IMPORT_WIZARD' => 'Import Wizard', + 'LBL_IMPORT_WIZARD_DESC' => 'Use the import wizard to easily import records into the system', 'LBL_INBOUND_EMAIL_TITLE' => 'Inbound Email', 'LBL_LANGUAGES' => 'Manage which languages are available for users', 'LBL_LAYOUT' => 'Add, remove, change fields, and layout fields and panels across the application', @@ -440,7 +445,7 @@ $mod_strings = array ( 'LBL_MANUAL_VALIDATION_TXT' => 'Manual Validation', 'LBL_MANUAL_VALIDATION'=>' If you experience persistent problems with automatic validation, please check your Proxy configuration in the System Settings admin panel. - If your system environment prohibits your system from communicating to the license validation server through the internet, you should proceed with the Manual Validation steps. ', + If your system environment prohibits your system from communicating to the license validation server through the internet, you should proceed with the Manual Validation steps. ', 'LBL_MANUAL_VALIDATION1'=> 'Step 1: Generate a license key information file by clicking the following button. ', 'LBL_MANUAL_VALIDATION2'=> 'Then save the file (sugarkey.lic) on your local file system.', 'LBL_MANUAL_VALIDATION3'=> 'Step 2: Transfer the sugarkey.lic file to a system where you can access the internet with a web browser. Go to http://updates.sugarcrm.com/license and submit the sugarkey.lic file.

    The license validation web site will perform the validation immediately and return you the validation key file (sugarvalidationkey.lic) if the validation is successful. Your browser should prompt you to save the file. ', @@ -461,7 +466,9 @@ $mod_strings = array ( //ModuleInstaller 'LBL_MI_REBUILDING' => 'Rebuilding', 'LBL_MI_SECTION' => 'Section...', - 'LBL_MI_UN_CUSTOMFIELD' => 'Uninstalling Custom Fields...', + 'LBL_MI_IN_EXT' => 'Installing %s extension', + 'LBL_MI_UN_EXT' => 'Uninstalling %s extension', + 'LBL_MI_UN_CUSTOMFIELD' => 'Uninstalling Custom Fields...', 'LBL_MI_IN_CUSTOMFIELD' => 'Installing Custom Fields...', 'LBL_MI_COMPLETE' => 'Complete', 'LBL_MI_UN_BEAN' => 'Uninstalling Bean :', @@ -487,7 +494,10 @@ $mod_strings = array ( 'LBL_MI_REPAIR_INDICES' => 'Repairing indexes', 'LBL_MI_IN_CONNECTORS' => 'Installing Connectors', 'LBL_MI_UN_CONNECTORS' => 'UnInstalling Connectors', - + 'LBL_MI_IN_HOOKS' => 'Installing Logic Hooks', + 'LBL_MI_UN_HOOKS' => 'Uninstalling Logic Hooks', + 'LBL_MI_IN_SCHEDULEDTASKS' => 'Installing Scheduled Tasks', + 'LBL_MI_UN_SCHEDULEDTASKS' => 'Uninstalling Scheduled Tasks', 'LBL_ML_ACTION' => 'Action', 'LBL_ML_CANCEL' => 'Cancel', 'LBL_ML_COMMIT'=>'Commit', @@ -656,7 +666,7 @@ $mod_strings = array ( 'LBL_REGEX_HELP_TEXT' =>'Regular Expressions provide a concise and flexible means for identifying strings of the password, such as particular characters or patterns of characters. You can create custom password rules by providing a regex that will be used in a NOT MATCH condition; the password must not contain a match to any expressions in the regex.', 'LBL_REGEX_DESC_HELP_TEXT' =>'This description should explain the Regex Requirement and will be displayed in the list of requirements for users when they provide new passwords.', 'LBL_RELEASE' => 'Manage releases and versions', - 'LBL_RENAME_TABS'=>'Rename Tabs', + 'LBL_RENAME_TABS'=>'Rename Modules', 'LBL_REPAIR_ACTION' => 'What action would you like to take?', 'LBL_REPAIR_DATABASE_DESC' => 'Repairs database based on values defined in vardefs', 'LBL_REPAIR_DATABASE_PROCESSING' => 'Processing database and vardef comparison...', @@ -1089,5 +1099,16 @@ $mod_strings = array ( 'LBL_SELECT_MODULES_TITLE' => 'Drag and drop to select modules and to change the display order. Perform a search to apply the changes.', 'LBL_EAPM_SETTINGS' => 'External Accounts', 'LBL_EAPM_SETTINGS_DESC' => 'Select external applications for which users can provide their account information in order to access from within Sugar.', + 'LBL_MI_IN_ACTIONVIEWMAP' => 'Installing Action View Map', + 'LBL_MI_UN_ACTIONVIEWMAP' => 'Unninstalling Action View Map', +// OAuth + 'LBL_OAUTH_TITLE' => "OAuth Keys", + 'LBL_OAUTH' => "OAuth key management", + 'LBL_SAML_LOGIN_URL_DESC' => 'Enter Login URL', + // SNIP / Sugar Ease / Email Archiving + 'LBL_SNIP_TITLE' => 'Email Archiving', + 'LBL_SNIP_DESC' => 'Configure offline archiving (Email Archiving)', + 'LBL_CONFIGURE_SNIP' => 'Email Archiving', + 'LBL_CONFIGURE_SNIP_DESC' => 'Enable/disable the Sugar Email Archiving Service', ); diff --git a/modules/Administration/metadata/adminpaneldefs.php b/modules/Administration/metadata/adminpaneldefs.php index 5022c6f1..eec9391e 100644 --- a/modules/Administration/metadata/adminpaneldefs.php +++ b/modules/Administration/metadata/adminpaneldefs.php @@ -35,6 +35,7 @@ ********************************************************************************/ global $current_user,$admin_group_header; + //users and security. $admin_option_defs=array(); $admin_option_defs['Users']['user_management']= array('Users','LBL_MANAGE_USERS_TITLE','LBL_MANAGE_USERS','./index.php?module=Users&action=index'); @@ -79,36 +80,46 @@ $admin_group_header[]= array('LBL_SUGAR_NETWORK_TITLE','',false,$admin_option_de //system. $admin_option_defs=array(); $admin_option_defs['Administration']['configphp_settings']= array('Administration','LBL_CONFIGURE_SETTINGS_TITLE','LBL_CONFIGURE_SETTINGS','./index.php?module=Configurator&action=EditView'); +$admin_option_defs['Administration']['import']= array('Import','LBL_IMPORT_WIZARD','LBL_IMPORT_WIZARD_DESC','./index.php?module=Import&action=step1&import_module=Administration'); +$admin_option_defs['Administration']['locale']= array('Currencies','LBL_MANAGE_LOCALE','LBL_LOCALE','./index.php?module=Administration&action=Locale&view=default'); + if(!defined('TEMPLATE_URL')){ $admin_option_defs['Administration']['upgrade_wizard']= array('Upgrade','LBL_UPGRADE_WIZARD_TITLE','LBL_UPGRADE_WIZARD','./index.php?module=UpgradeWizard&action=index'); } -$admin_option_defs['Administration']['locale']= array('Currencies','LBL_MANAGE_LOCALE','LBL_LOCALE','./index.php?module=Administration&action=Locale&view=default'); +$admin_option_defs['Administration']['currencies_management']= array('Currencies','LBL_MANAGE_CURRENCIES','LBL_CURRENCY','./index.php?module=Currencies&action=index'); + $admin_option_defs['Administration']['backup_management']= array('Backups','LBL_BACKUPS_TITLE','LBL_BACKUPS','./index.php?module=Administration&action=Backups'); +$admin_option_defs['Administration']['scheduler'] = array('Schedulers','LBL_SUGAR_SCHEDULER_TITLE','LBL_SUGAR_SCHEDULER','./index.php?module=Schedulers&action=index'); -$admin_option_defs['Administration']['currencies_management']= array('Currencies','LBL_MANAGE_CURRENCIES','LBL_CURRENCY','./index.php?module=Currencies&action=index'); $admin_option_defs['Administration']['repair']= array('Repair','LBL_UPGRADE_TITLE','LBL_UPGRADE','./index.php?module=Administration&action=Upgrade'); -$admin_option_defs['Administration']['scheduler'] = array('Schedulers','LBL_SUGAR_SCHEDULER_TITLE','LBL_SUGAR_SCHEDULER','./index.php?module=Schedulers&action=index'); -$admin_option_defs['Administration']['diagnostic']= array('Diagnostic','LBL_DIAGNOSTIC_TITLE','LBL_DIAGNOSTIC_DESC','./index.php?module=Administration&action=Diagnostic'); - // Theme Enable/Disable $admin_option_defs['Administration']['theme_settings']=array('icon_AdminThemes','LBL_THEME_SETTINGS','LBL_THEME_SETTINGS_DESC','./index.php?module=Administration&action=ThemeSettings'); +$admin_option_defs['Administration']['diagnostic']= array('Diagnostic','LBL_DIAGNOSTIC_TITLE','LBL_DIAGNOSTIC_DESC','./index.php?module=Administration&action=Diagnostic'); + $admin_option_defs['Administration']['feed_settings']=array('icon_SugarFeed','LBL_SUGARFEED_SETTINGS','LBL_SUGARFEED_SETTINGS_DESC','./index.php?module=SugarFeed&action=AdminSettings'); + + // Connector Integration $admin_option_defs['Administration']['connector_settings']=array('icon_Connectors','LBL_CONNECTOR_SETTINGS','LBL_CONNECTOR_SETTINGS_DESC','./index.php?module=Connectors&action=ConnectorSettings'); -//$admin_option_defs['module_loader'] = array('ModuleLoader','LBL_MODULE_LOADER_TITLE','LBL_MODULE_LOADER','./index.php?module=Administration&action=UpgradeWizard&view=module'); - -$admin_option_defs['Administration']['global_search']=array('icon_SearchForm','LBL_GLOBAL_SEARCH_SETTINGS','LBL_GLOBAL_SEARCH_SETTINGS_DESC','./index.php?module=Administration&action=GlobalSearchSettings'); $admin_option_defs['Administration']['languages']= array('Currencies','LBL_MANAGE_LANGUAGES','LBL_LANGUAGES','./index.php?module=Administration&action=Languages&view=default'); +$admin_option_defs['Administration']['global_search']=array('icon_SearchForm','LBL_GLOBAL_SEARCH_SETTINGS','LBL_GLOBAL_SEARCH_SETTINGS_DESC','./index.php?module=Administration&action=GlobalSearchSettings'); +require_once 'include/SugarOAuthServer.php'; +if(SugarOAuthServer::enabled()) { + $admin_option_defs['Administration']['oauth']= array('Password','LBL_OAUTH_TITLE','LBL_OAUTH','./index.php?module=OAuthKeys&action=index'); +} + + + $admin_group_header[]= array('LBL_ADMINISTRATION_HOME_TITLE','',false,$admin_option_defs, 'LBL_ADMINISTRATION_HOME_DESC'); @@ -116,22 +127,30 @@ $admin_group_header[]= array('LBL_ADMINISTRATION_HOME_TITLE','',false,$admin_opt //email manager. $admin_option_defs=array(); $admin_option_defs['Emails']['mass_Email_config']= array('EmailMan','LBL_MASS_EMAIL_CONFIG_TITLE','LBL_MASS_EMAIL_CONFIG_DESC','./index.php?module=EmailMan&action=config'); + $admin_option_defs['Campaigns']['campaignconfig']= array('Campaigns','LBL_CAMPAIGN_CONFIG_TITLE','LBL_CAMPAIGN_CONFIG_DESC','./index.php?module=EmailMan&action=campaignconfig'); + $admin_option_defs['Emails']['mailboxes']= array('InboundEmail','LBL_MANAGE_MAILBOX','LBL_MAILBOX_DESC','./index.php?module=InboundEmail&action=index'); $admin_option_defs['Campaigns']['mass_Email']= array('EmailMan','LBL_MASS_EMAIL_MANAGER_TITLE','LBL_MASS_EMAIL_MANAGER_DESC','./index.php?module=EmailMan&action=index'); + + $admin_group_header[]= array('LBL_EMAIL_TITLE','',false,$admin_option_defs, 'LBL_EMAIL_DESC'); + + + //studio. $admin_option_defs=array(); $admin_option_defs['studio']['studio']= array('Studio','LBL_STUDIO','LBL_STUDIO_DESC','./index.php?module=ModuleBuilder&action=index&type=studio'); if(isset($GLOBALS['beanFiles']['iFrame'])) { $admin_option_defs['Administration']['portal']= array('iFrames','LBL_IFRAME','DESC_IFRAME','./index.php?module=iFrames&action=index'); } -$admin_option_defs['Administration']['rename_tabs']= array('RenameTabs','LBL_RENAME_TABS','LBL_CHANGE_NAME_TABS',"./index.php?action=wizard&module=Studio&wizard=StudioWizard&option=RenameTabs"); +$admin_option_defs['Administration']['rename_tabs']= array('RenameTabs','LBL_RENAME_TABS','LBL_CHANGE_NAME_MODULES',"./index.php?action=wizard&module=Studio&wizard=StudioWizard&option=RenameTabs"); $admin_option_defs['Administration']['moduleBuilder']= array('ModuleBuilder','LBL_MODULEBUILDER','LBL_MODULEBUILDER_DESC','./index.php?module=ModuleBuilder&action=index&type=mb'); $admin_option_defs['Administration']['configure_tabs']= array('ConfigureTabs','LBL_CONFIGURE_TABS_AND_SUBPANELS','LBL_CONFIGURE_TABS_AND_SUBPANELS_DESC','./index.php?module=Administration&action=ConfigureTabs'); - $admin_option_defs['Administration']['module_loader'] = array('ModuleLoader','LBL_MODULE_LOADER_TITLE','LBL_MODULE_LOADER','./index.php?module=Administration&action=UpgradeWizard&view=module'); + + $admin_option_defs['any']['configure_group_tabs']= array('ConfigureTabs','LBL_CONFIGURE_GROUP_TABS','LBL_CONFIGURE_GROUP_TABS_DESC','./index.php?action=wizard&module=Studio&wizard=StudioWizard&option=ConfigureGroupTabs'); $admin_option_defs['any']['dropdowneditor']= array('Dropdown','LBL_DROPDOWN_EDITOR','DESC_DROPDOWN_EDITOR','./index.php?module=ModuleBuilder&action=index&type=dropdowns'); @@ -142,14 +161,17 @@ $admin_option_defs['any']['dropdowneditor']= array('Dropdown','LBL_DROPDOWN_EDIT $admin_group_header[]= array('LBL_STUDIO_TITLE','',false,$admin_option_defs, 'LBL_TOOLS_DESC'); + //bug tracker. $admin_option_defs=array(); $admin_option_defs['Bugs']['bug_tracker']= array('Releases','LBL_MANAGE_RELEASES','LBL_RELEASE','./index.php?module=Releases&action=index'); $admin_group_header[]= array('LBL_BUG_TITLE','',false,$admin_option_defs, 'LBL_BUG_DESC'); + + if(file_exists('custom/modules/Administration/Ext/Administration/administration.ext.php')){ - require_once('custom/modules/Administration/Ext/Administration/administration.ext.php'); + include('custom/modules/Administration/Ext/Administration/administration.ext.php'); } //For users with MLA access we need to find which entries need to be shown. diff --git a/modules/Administration/repairDatabase.php b/modules/Administration/repairDatabase.php index cbf80975..4841423e 100644 --- a/modules/Administration/repairDatabase.php +++ b/modules/Administration/repairDatabase.php @@ -133,9 +133,11 @@ if (is_admin($current_user) || isset ($from_sync_client) || is_admin_for_any_mod include ('modules/TableDictionary.php'); foreach ($dictionary as $meta) { - $tablename = $meta['table']; - if (isset($repairedTables[$tablename])) continue; + if ( !isset($meta['table']) || isset($repairedTables[$meta['table']])) + continue; + + $tablename = $meta['table']; $fielddefs = $meta['fields']; $indices = $meta['indices']; $engine = isset($meta['engine'])?$meta['engine']:null; diff --git a/modules/Administration/templates/ConfigureAjaxUI.tpl b/modules/Administration/templates/ConfigureAjaxUI.tpl new file mode 100644 index 00000000..63181808 --- /dev/null +++ b/modules/Administration/templates/ConfigureAjaxUI.tpl @@ -0,0 +1,128 @@ +{* +/********************************************************************************* + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + +
    + + + + + + + + {$title}
    +

    {sugar_translate label="LBL_CONFIG_AJAX_DESC"}


    +

    {sugar_translate label="LBL_CONFIG_AJAX_HELP"}


    + + +
    + + + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/modules/Administration/vardefs.php b/modules/Administration/vardefs.php index 777dde33..f5b3bd94 100644 --- a/modules/Administration/vardefs.php +++ b/modules/Administration/vardefs.php @@ -101,7 +101,7 @@ $dictionary['UpgradeHistory'] = array( 'version' => array ( 'name' => 'version', 'type' => 'varchar', - 'len' => '10', + 'len' => '64', 'comment' => 'Version as contained in manifest file' ), 'name' => array ( diff --git a/modules/Administration/views/view.configureajaxui.php b/modules/Administration/views/view.configureajaxui.php new file mode 100644 index 00000000..28a32f13 --- /dev/null +++ b/modules/Administration/views/view.configureajaxui.php @@ -0,0 +1,106 @@ +" . translate('LBL_MODULE_NAME') . "", + translate('LBL_CONFIG_AJAX') + ); + } + + /** + * @see SugarView::preDisplay() + */ + public function preDisplay() + { + global $current_user; + + if (!is_admin($current_user)) + { + sugar_die("Unauthorized access to administration."); + } + } + + /** + * @see SugarView::display() + */ + public function display() + { + global $sugar_config, $moduleList; + //create array of subpanels to show, used to create Drag and Drop widget + $enabled = array(); + $disabled = array(); + $banned = ajaxBannedModules(); + + foreach($moduleList as $module) + { + if (!in_array($module, $banned)) + { + $enabled[] = array("module" => $module, 'label' => translate($module)); + } + } + if (!empty($sugar_config['addAjaxBannedModules'])) + { + foreach( $sugar_config['addAjaxBannedModules'] as $module) + { + $disabled[] = array("module" => $module, 'label' => translate($module)); + } + } + + $this->ss->assign('enabled_mods', json_encode($enabled)); + $this->ss->assign('disabled_mods', json_encode($disabled)); + $this->ss->assign('title',$this->getModuleTitle(false)); + + echo $this->ss->fetch('modules/Administration/templates/ConfigureAjaxUI.tpl'); + } +} diff --git a/modules/Bugs/language/en_us.lang.php b/modules/Bugs/language/en_us.lang.php index a2fa302b..71a17e25 100644 --- a/modules/Bugs/language/en_us.lang.php +++ b/modules/Bugs/language/en_us.lang.php @@ -110,6 +110,17 @@ $mod_strings = array ( 'LBL_LIST_ASSIGNED_TO_NAME' => 'Assigned User', 'LBL_ASSIGNED_TO_NAME' => 'Assigned to', - 'LBL_BUG_INFORMATION' => 'Bug Overview', + 'LBL_BUG_INFORMATION' => 'Overview', + + //For export labels + 'LBL_FOUND_IN_RELEASE_NAME' => 'Found In Release Name', + 'LBL_PORTAL_VIEWABLE' => 'Portal Viewable', + 'LBL_EXPORT_ASSIGNED_USER_NAME' => 'Assigned User Name', + 'LBL_EXPORT_ASSIGNED_USER_ID' => 'Assigned User ID', + 'LBL_EXPORT_FIXED_IN_RELEASE_NAMR' => 'Fixed in Release Name', + 'LBL_EXPORT_MODIFIED_USER_ID' => 'Modified By ID', + 'LBL_EXPORT_CREATED_BY' => 'Created By ID', + + ); ?> diff --git a/modules/Bugs/vardefs.php b/modules/Bugs/vardefs.php index 76db6f52..1b453a5f 100644 --- a/modules/Bugs/vardefs.php +++ b/modules/Bugs/vardefs.php @@ -255,7 +255,10 @@ $dictionary['Bug'] = array('table' => 'bugs', 'audited'=>true, 'comment' => ' , 'indices' => array ( array('name' =>'bug_number', 'type' =>'index', 'fields'=>array('bug_number')), - array('name' =>'idx_bug_name', 'type' =>'index', 'fields'=>array('name')) + array('name' =>'idx_bug_name', 'type' =>'index', 'fields'=>array('name')), + + array('name' => 'idx_bugs_assigned_user', 'type' => 'index', 'fields'=> array('assigned_user_id')), + ) , 'relationships' => array ( diff --git a/modules/Calendar/Calendar.php b/modules/Calendar/Calendar.php index 2f03e2b3..670af40a 100644 --- a/modules/Calendar/Calendar.php +++ b/modules/Calendar/Calendar.php @@ -501,11 +501,11 @@ class CalendarActivity break; } - $field_date = $GLOBALS['db']->convert($table_name.'.'.$field_name,'datetime'); - $start_day = $start->asDb(); - $end_day = $end->asDb(); + $field_date = $table_name.'.'.$field_name; + $start_day = $GLOBALS['db']->convert("'{$start->asDb()}'",'datetime'); + $end_day = $GLOBALS['db']->convert("'{$end->asDb()}'",'datetime'); - $where = "($field_date >= '{$start_day}' AND $field_date < '{$end_day}'"; + $where = "($field_date >= $start_day AND $field_date < $end_day"; if($rel_table != '') { $where .= " AND $rel_table.accept_status != 'decline'"; } diff --git a/modules/Calls/Call.php b/modules/Calls/Call.php index e3b2b6da..f9c080c8 100644 --- a/modules/Calls/Call.php +++ b/modules/Calls/Call.php @@ -135,7 +135,6 @@ class Call extends SugarBean // this is for calendar function save($check_notify = FALSE) { global $timedate,$current_user; - global $disable_date_format; if(isset($this->date_start) && isset($this->duration_hours) && isset($this->duration_minutes)) { @@ -287,7 +286,7 @@ class Call extends SugarBean $contact_required = stristr($where, "contacts"); if($contact_required) { - $query = "SELECT calls.*, contacts.first_name, contacts.last_name"; + $query = "SELECT calls.*, contacts.first_name, contacts.last_name, users.user_name as assigned_user_name "; if($custom_join){ $query .= $custom_join['select']; } @@ -296,7 +295,7 @@ class Call extends SugarBean } else { - $query = 'SELECT calls.*'; + $query = 'SELECT calls.*, users.user_name as assigned_user_name '; if($custom_join){ $query .= $custom_join['select']; } @@ -305,6 +304,8 @@ class Call extends SugarBean } + $query .= " LEFT JOIN users ON calls.assigned_user_id=users.id "; + if($custom_join){ $query .= $custom_join['join']; } @@ -655,11 +656,11 @@ class Call extends SugarBean function save_relationship_changes($is_update) { $exclude = array(); if(empty($this->in_workflow)) { - //if the global soap_server_object variable is not empty (as in from a soap/OPI call), then process the assigned_user_id relationship, otherwise + //if the global soap_server_object variable is not empty (as in from a soap/OPI call), then process the assigned_user_id relationship, otherwise //add assigned_user_id to exclude list and let the logic from MeetingFormBase determine whether assigned user id gets added to the relationship if(!empty($GLOBALS['soap_server_object'])){ $exclude = array('lead_id', 'contact_id', 'user_id'); - }else{ + }else{ $exclude = array('lead_id', 'contact_id', 'user_id', 'assigned_user_id'); } } diff --git a/modules/Calls/CallFormBase.php b/modules/Calls/CallFormBase.php index d20b7d77..9e1daa4c 100644 --- a/modules/Calls/CallFormBase.php +++ b/modules/Calls/CallFormBase.php @@ -267,7 +267,9 @@ function handleSave($prefix,$redirect=true,$useRequired=false) { $_POST['user_invitees'] = str_replace(',,', ',', $_POST['user_invitees']); } - if(isset($_POST['isSaveFromDetailView']) && $_POST['isSaveFromDetailView'] == 'true'){ + if( (isset($_POST['isSaveFromDetailView']) && $_POST['isSaveFromDetailView'] == 'true') || + (isset($_POST['is_ajax_call']) && !empty($_POST['is_ajax_call']) && !empty($focus->id)) + ){ $focus->save(true); $return_id = $focus->id; }else{ @@ -476,7 +478,8 @@ function handleSave($prefix,$redirect=true,$useRequired=false) { } } if (isset($_REQUEST['return_module']) && $_REQUEST['return_module'] == 'Home'){ - header("Location: index.php?module=Home&action=index"); + $_REQUEST['return_action'] = 'index'; + handleRedirect('', 'Home'); } else if($redirect) { handleRedirect($return_id, 'Calls'); diff --git a/modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.php b/modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.php index a862a9c0..902b75e1 100644 --- a/modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.php +++ b/modules/Calls/Dashlets/MyCallsDashlet/MyCallsDashlet.php @@ -153,9 +153,11 @@ class MyCallsDashlet extends DashletGeneric { 'myItems' => translate('LBL_DASHLET_CONFIGURE_MY_ITEMS_ONLY', 'Calls'), 'displayRows' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_DISPLAY_ROWS'], 'title' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_TITLE'], + 'clear' => $GLOBALS['app_strings']['LBL_CLEAR_BUTTON_LABEL'], 'save' => $GLOBALS['app_strings']['LBL_SAVE_BUTTON_LABEL'], 'autoRefresh' => $GLOBALS['app_strings']['LBL_DASHLET_CONFIGURE_AUTOREFRESH'], )); + return $this->configureSS->fetch($this->configureTpl); } } diff --git a/modules/Calls/language/en_us.lang.php b/modules/Calls/language/en_us.lang.php index 2e3bef2b..2409c535 100644 --- a/modules/Calls/language/en_us.lang.php +++ b/modules/Calls/language/en_us.lang.php @@ -122,8 +122,18 @@ $mod_strings = array ( 'LBL_ASSIGNED_TO_NAME' => 'Assigned to', 'LBL_ASSIGNED_TO_ID' => 'Assigned User', 'NOTICE_DURATION_TIME' => 'Duration time must be greater than 0', - 'LBL_CALL_INFORMATION' => 'Call Overview', + 'LBL_CALL_INFORMATION' => 'Overview', 'LBL_REMOVE' => 'rem', + 'LBL_ACCEPT_STATUS' => 'Accept Status', + 'LBL_ACCEPT_LINK' => 'Accept Link', + //For export labels + 'LBL_PARENT_ID' => 'Parent ID', + 'LBL_EXPORT_MODIFIED_USER_ID' => 'Modified By ID', + 'LBL_EXPORT_CREATED_BY' => 'Created By ID', + 'LBL_EXPORT_ASSIGNED_USER_ID' => 'Assigned User ID', + 'LBL_EXPORT_DATE_START' => 'Start Date and Time', + 'LBL_EXPORT_PARENT_TYPE' => 'Related To Module', + 'LBL_EXPORT_REMINDER_TIME' =>'Reminder Time (in minutes)', ); diff --git a/modules/Calls/metadata/editviewdefs.php b/modules/Calls/metadata/editviewdefs.php index 30f7e674..cb7d11c9 100644 --- a/modules/Calls/metadata/editviewdefs.php +++ b/modules/Calls/metadata/editviewdefs.php @@ -55,16 +55,16 @@ array ( array ( 0 => array ( - 'customCode' => '', + 'customCode' => '', ), 1 => 'CANCEL', 2 => array ( - 'customCode' => '', + 'customCode' => '', ), 3 => array ( - 'customCode' => '{if $fields.status.value != "Held"}{/if}', + 'customCode' => '{if $fields.status.value != "Held"}{/if}', ), ), 'footerTpl' => 'modules/Calls/tpls/footer.tpl', @@ -82,12 +82,10 @@ array ( 'field' => '30', ), ), - 'javascript' => ' - - - -', + 'javascript' => ' + +', 'useTabs' => false, ), 'panels' => diff --git a/modules/Calls/metadata/quickcreatedefs.php b/modules/Calls/metadata/quickcreatedefs.php index 15e90b4e..a0ec512c 100644 --- a/modules/Calls/metadata/quickcreatedefs.php +++ b/modules/Calls/metadata/quickcreatedefs.php @@ -55,16 +55,16 @@ array ( array ( 0 => array ( - 'customCode' => '', + 'customCode' => '', ), 1 => 'CANCEL', 2 => array ( - 'customCode' => '', + 'customCode' => '', ), 3 => array ( - 'customCode' => '{if $fields.status.value != "Held"}{/if}', + 'customCode' => '{if $fields.status.value != "Held"}{/if}', ), ), 'footerTpl' => 'modules/Calls/tpls/footer.tpl', @@ -83,9 +83,7 @@ array ( ), ), 'javascript' => ' - - - + ', 'useTabs' => false, diff --git a/modules/Calls/tpls/footer.tpl b/modules/Calls/tpls/footer.tpl index b27f0d13..d8882e2c 100644 --- a/modules/Calls/tpls/footer.tpl +++ b/modules/Calls/tpls/footer.tpl @@ -51,24 +51,35 @@ require_once("'".$externalJSFile."'"); diff --git a/modules/Calls/vardefs.php b/modules/Calls/vardefs.php index 9f01388f..302c0494 100644 --- a/modules/Calls/vardefs.php +++ b/modules/Calls/vardefs.php @@ -185,7 +185,7 @@ $dictionary['Call'] = array('table' => 'calls', 'comment' => 'A Call is an activ ), 'accept_status' => array ( 'name' => 'accept_status', - 'vname' => 'LBL_SUBJECT', + 'vname' => 'LBL_ACCEPT_STATUS', 'dbType' => 'varchar', 'type' => 'varchar', 'len' => '20', @@ -194,7 +194,7 @@ $dictionary['Call'] = array('table' => 'calls', 'comment' => 'A Call is an activ //bug 39559 'set_accept_links' => array ( 'name' => 'accept_status', - 'vname' => 'LBL_SUBJECT', + 'vname' => 'LBL_ACCEPT_LINK', 'dbType' => 'varchar', 'type' => 'varchar', 'len' => '20', @@ -220,15 +220,6 @@ $dictionary['Call'] = array('table' => 'calls', 'comment' => 'A Call is an activ 'importable' => 'false', 'studio' => array('required' => false, 'listview'=>true, 'visible' => false), ), - 'account' => - array ( - 'name' => 'account', - 'type' => 'link', - 'relationship' => 'account_calls', - 'link_type'=>'one', - 'source'=>'non-db', - 'vname'=>'LBL_OLD_ACCOUNT_LINK', - ), 'opportunity' => array ( 'name' => 'opportunity', @@ -351,7 +342,11 @@ $dictionary['Call'] = array('table' => 'calls', 'comment' => 'A Call is an activ 'name' => 'idx_calls_par_del', 'type' => 'index', 'fields' => array('parent_id','parent_type','deleted') - ) + ), + array( + 'name' =>'idx_calls_assigned_del', + 'type' =>'index', + 'fields'=>array( 'deleted', 'assigned_user_id')), ), 'relationships' => array ( 'calls_assigned_user' => array( diff --git a/modules/CampaignLog/Popup_picker.html b/modules/CampaignLog/Popup_picker.html index c0ea60ac..9a4b0d46 100644 --- a/modules/CampaignLog/Popup_picker.html +++ b/modules/CampaignLog/Popup_picker.html @@ -77,7 +77,7 @@ {PREROW} - <{TAG_TYPE} href="#" onclick="send_back('CampaignLog','{CAMPAIGNLOG.ID}');">{CAMPAIGNLOG.ID} + <{TAG_TYPE} href="javascript:void(0)" onclick="send_back('CampaignLog','{CAMPAIGNLOG.ID}');">{CAMPAIGNLOG.ID} {CAMPAIGNLOG.ACTIVITY_DATE} {CAMPAIGNLOG.CAMPAIGN_NAME1} diff --git a/modules/CampaignLog/vardefs.php b/modules/CampaignLog/vardefs.php index bf9790b3..7a5f525c 100644 --- a/modules/CampaignLog/vardefs.php +++ b/modules/CampaignLog/vardefs.php @@ -265,6 +265,14 @@ $dictionary['CampaignLog'] = array ('audited'=>false, 'type' =>'index', 'fields'=>array('target_id') ), + array ( + 'name' =>'idx_target_id_deleted', + + 'type' =>'index', + 'fields'=>array('target_id','deleted') + ), + + ), 'relationships' => array ( 'campaignlog_contact' => array( 'lhs_module'=> 'CampaignLog', diff --git a/modules/Campaigns/Delete.php b/modules/Campaigns/Delete.php index dff31225..21e320e1 100644 --- a/modules/Campaigns/Delete.php +++ b/modules/Campaigns/Delete.php @@ -112,5 +112,5 @@ if (isset($_REQUEST['mode']) and $_REQUEST['mode']=='Test') { $focus->mark_deleted($_REQUEST['record']); } $return_id=!empty($_REQUEST['return_id'])?$_REQUEST['return_id']:$focus->id; -header("Location: index.php?module=".$_REQUEST['return_module']."&action=".$_REQUEST['return_action']."&record=".$return_id); -?> +require_once ('include/formbase.php'); +handleRedirect($return_id, $_REQUEST['return_module']); \ No newline at end of file diff --git a/modules/Campaigns/ProspectLink.php b/modules/Campaigns/ProspectLink.php index e4260f60..42b58acf 100644 --- a/modules/Campaigns/ProspectLink.php +++ b/modules/Campaigns/ProspectLink.php @@ -43,12 +43,12 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); * Contributor(s): ______________________________________.. ********************************************************************************/ -require_once('data/Link.php'); +require_once('data/Link2.php'); /** * @brief Bug #40166. Campaign Log Report will not display Contact/Account Names */ -class ProspectLink extends Link +class ProspectLink extends Link2 { /** diff --git a/modules/Campaigns/RoiDetailView.tpl b/modules/Campaigns/RoiDetailView.tpl index 7bfde3e9..1305237e 100644 --- a/modules/Campaigns/RoiDetailView.tpl +++ b/modules/Campaigns/RoiDetailView.tpl @@ -38,6 +38,7 @@ {$chartResources} + diff --git a/modules/Campaigns/TrackDetailView.tpl b/modules/Campaigns/TrackDetailView.tpl index 74a7b3a9..f9daec91 100644 --- a/modules/Campaigns/TrackDetailView.tpl +++ b/modules/Campaigns/TrackDetailView.tpl @@ -40,7 +40,7 @@ *} {$chartResources} - +
    diff --git a/modules/Campaigns/WizardNewsletterSave.php b/modules/Campaigns/WizardNewsletterSave.php index ea4fb289..92e0356f 100644 --- a/modules/Campaigns/WizardNewsletterSave.php +++ b/modules/Campaigns/WizardNewsletterSave.php @@ -195,6 +195,8 @@ global $mod_strings; //load relationship and add to the list $campaign_focus->load_relationship('tracked_urls'); $campaign_focus->tracked_urls->add($ct_focus->id); + // save campaign_trkrs after populating campaign id + $ct_focus->save(); } } } diff --git a/modules/Campaigns/language/en_us.lang.php b/modules/Campaigns/language/en_us.lang.php index 44c2944b..7f437436 100644 --- a/modules/Campaigns/language/en_us.lang.php +++ b/modules/Campaigns/language/en_us.lang.php @@ -419,7 +419,7 @@ $mod_strings = array ( 'LBL_IMPORT_PROSPECTS'=>'Import Targets', 'LBL_LEAD_FORM_WIZARD' => 'Lead Form Wizard', - 'LBL_CAMPAIGN_INFORMATION' => 'Campaign Overview', + 'LBL_CAMPAIGN_INFORMATION' => 'Overview', 'LBL_MONTH' => "Month", 'LBL_YEAR' => "Year", diff --git a/modules/Campaigns/views/view.detail.php b/modules/Campaigns/views/view.detail.php index 4ddeab39..24da2e3f 100644 --- a/modules/Campaigns/views/view.detail.php +++ b/modules/Campaigns/views/view.detail.php @@ -66,6 +66,7 @@ class CampaignsViewDetail extends ViewDetail { $mod_strings['LBL_MODULE_NAME'] = $mod_strings['LBL_NEWSLETTERS']; } parent::preDisplay(); + $this->options['show_subpanels'] = false; } diff --git a/modules/Cases/Menu.php b/modules/Cases/Menu.php index 58e78e1c..985d3435 100644 --- a/modules/Cases/Menu.php +++ b/modules/Cases/Menu.php @@ -48,7 +48,7 @@ if(ACLController::checkAccess('Cases', 'edit', true)) $module_menu [] = Array("index.php?module=Cases&action=EditView&return_module=Cases&return_action=DetailView", $mod_strings['LNK_NEW_CASE'],"CreateCases"); if(ACLController::checkAccess('Cases', 'list', true)) $module_menu [] = Array("index.php?module=Cases&action=index&return_module=Cases&return_action=DetailView", $mod_strings['LNK_CASE_LIST'],"Cases"); -if(ACLController::checkAccess('Cases', 'import', true))$module_menu[] =Array("index.php?module=Import&action=Step1&import_module=Cases&return_module=Cases&return_action=index", $mod_strings['LNK_IMPORT_CASES'],"Import", 'Contacts'); +if(ACLController::checkAccess('Cases', 'import', true))$module_menu[] =Array("index.php?module=Import&action=Step1&import_module=Cases&return_module=Cases&return_action=index", $mod_strings['LNK_IMPORT_CASES'],"Import", 'Cases'); ?> \ No newline at end of file diff --git a/modules/Cases/language/en_us.lang.php b/modules/Cases/language/en_us.lang.php index 8c1d65fc..893360bd 100644 --- a/modules/Cases/language/en_us.lang.php +++ b/modules/Cases/language/en_us.lang.php @@ -103,8 +103,34 @@ $mod_strings = array ( 'LBL_CREATED_USER' => 'Created User', 'LBL_MODIFIED_USER' => 'Modified User', 'LBL_PROJECT_SUBPANEL_TITLE' => 'Projects', - 'LBL_CASE_INFORMATION' => 'Case Overview', -); + 'LBL_CASE_INFORMATION' => 'Overview', + + //For export labels + 'LBL_MODIFIED_BY_NAME_OWNER' => 'Modified By Name Owner', + 'LBL_MODIFIED_BY_NAME_MOD' => 'Modified By Name Mod', + 'LBL_CREATED_BY_NAME_OWNER' => 'Created By Name Owner', + 'LBL_CREATED_BY_NAME_MOD' => 'Created By Name Mod', + 'LBL_ASSIGNED_USER_NAME_OWNER' => 'Assigned User Name Owner', + 'LBL_ASSIGNED_USER_NAME_MOD' => 'Assigned User Name Mod', + 'LBL_TEAM_COUNT_OWNER' => 'Team Count Owner', + 'LBL_TEAM_COUNT_MOD' => 'Team Count Mod', + 'LBL_TEAM_NAME_OWNER' => 'Team Name Owner', + 'LBL_TEAM_NAME_MOD' => 'Team Name Mod', + 'LBL_ACCOUNT_NAME_OWNER' => 'Account Name Owner', + 'LBL_ACCOUNT_NAME_MOD' => 'Account Name Mod', + 'LBL_MODIFIED_USER_NAME' => 'Modified User Name', + 'LBL_MODIFIED_USER_NAME_OWNER' => 'Modified User Name Owner', + 'LBL_MODIFIED_USER_NAME_MOD' => 'Modified User Name Mod', + 'LBL_PORTAL_VIEWABLE' => 'Portal Viewable', + 'LBL_EXPORT_ASSIGNED_USER_ID' => 'Assigned User ID', + 'LBL_EXPORT_MODIFIED_USER_ID' => 'Modified By ID', + 'LBL_EXPORT_CREATED_BY' => 'Created By ID', + 'LBL_EXPORT_CREATED_BY_NAME' => 'Created By User Name', + 'LBL_EXPORT_ASSIGNED_USER_NAME' => 'Assigned User Name', + 'LBL_EXPORT_TEAM_COUNT' => 'Team Count', + // SNIP + 'LBL_CONTACT_HISTORY_SUBPANEL_TITLE' => 'Related Contacts\' Emails', +); -?> \ No newline at end of file +?> diff --git a/modules/Cases/metadata/subpaneldefs.php b/modules/Cases/metadata/subpaneldefs.php index eea581e1..20f7dced 100644 --- a/modules/Cases/metadata/subpaneldefs.php +++ b/modules/Cases/metadata/subpaneldefs.php @@ -55,7 +55,7 @@ $layout_defs['Cases'] = array( array( 'widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Cases', - 'mode' => 'MultiSelect', + 'mode' => 'MultiSelect', 'initial_filter_fields' => array('account_id' => 'account_id', 'account_name' => 'account_name'), ), ), @@ -76,7 +76,7 @@ $layout_defs['Cases'] = array( array('widget_class' => 'SubPanelTopComposeEmailButton'), ), - 'collection_list' => array( + 'collection_list' => array( 'meetings' => array( 'module' => 'Meetings', 'subpanel_name' => 'ForActivities', @@ -91,8 +91,8 @@ $layout_defs['Cases'] = array( 'module' => 'Calls', 'subpanel_name' => 'ForActivities', 'get_subpanel_data' => 'calls', - ), - ) + ), + ) ), 'history' => array( 'order' => 20, @@ -109,7 +109,7 @@ $layout_defs['Cases'] = array( array('widget_class' => 'SubPanelTopSummaryButton'), ), - 'collection_list' => array( + 'collection_list' => array( 'meetings' => array( 'module' => 'Meetings', 'subpanel_name' => 'ForHistory', @@ -124,18 +124,18 @@ $layout_defs['Cases'] = array( 'module' => 'Calls', 'subpanel_name' => 'ForHistory', 'get_subpanel_data' => 'calls', - ), + ), 'notes' => array( 'module' => 'Notes', 'subpanel_name' => 'ForHistory', 'get_subpanel_data' => 'notes', - ), + ), 'emails' => array( 'module' => 'Emails', 'subpanel_name' => 'ForHistory', 'get_subpanel_data' => 'emails', - ), - ) + ), + ) ), 'documents' => array( 'order' => 25, @@ -145,13 +145,13 @@ $layout_defs['Cases'] = array( 'sort_by' => 'id', 'title_key' => 'LBL_DOCUMENTS_SUBPANEL_TITLE', 'get_subpanel_data' => 'documents', - 'top_buttons' => + 'top_buttons' => array ( - 0 => + 0 => array ( 'widget_class' => 'SubPanelTopButtonQuickCreate', ), - 1 => + 1 => array ( 'widget_class' => 'SubPanelTopSelectButton', 'mode' => 'MultiSelect', @@ -172,10 +172,10 @@ $layout_defs['Cases'] = array( array( 'widget_class' => 'SubPanelTopSelectButton', 'popup_module' => 'Bugs', - 'mode' => 'MultiSelect', - ), - ), - ), + 'mode' => 'MultiSelect', + ), + ), + ), 'project' => array( 'order' => 110, 'sort_order' => 'asc', @@ -188,7 +188,7 @@ $layout_defs['Cases'] = array( 'top_buttons' => array( array('widget_class' => 'SubPanelTopButtonQuickCreate'), array('widget_class' => 'SubPanelTopSelectButton'), - ), + ), ), ), ); diff --git a/modules/Charts/Dashlets/PredefinedChartDashletScript.tpl b/modules/Charts/Dashlets/PredefinedChartDashletScript.tpl index 66e064c3..868a4452 100644 --- a/modules/Charts/Dashlets/PredefinedChartDashletScript.tpl +++ b/modules/Charts/Dashlets/PredefinedChartDashletScript.tpl @@ -41,5 +41,10 @@ *} diff --git a/modules/Configurator/controller.php b/modules/Configurator/controller.php index fd7c2fa3..d53091cd 100644 --- a/modules/Configurator/controller.php +++ b/modules/Configurator/controller.php @@ -43,7 +43,7 @@ class ConfiguratorController extends SugarController * Go to the font manager view */ function action_FontManager(){ - global $current_user; + global $current_user; if(!is_admin($current_user)){ sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); } @@ -71,17 +71,17 @@ class ConfiguratorController extends SugarController } function action_listview(){ - global $current_user; + global $current_user; if(!is_admin($current_user)){ sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); } - $this->view = 'edit'; + $this->view = 'edit'; } /** * Show the addFont view */ function action_addFontView(){ - global $current_user; + global $current_user; if(!is_admin($current_user)){ sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); } @@ -134,7 +134,7 @@ class ConfiguratorController extends SugarController } function action_saveadminwizard() { - global $current_user; + global $current_user; if(!is_admin($current_user)){ sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); } @@ -145,7 +145,7 @@ class ConfiguratorController extends SugarController $configurator = new Configurator(); $configurator->populateFromPost(); $configurator->handleOverride(); - $configurator->parseLoggerSettings(); + $configurator->parseLoggerSettings(); $configurator->saveConfig(); // Bug 37310 - Delete any existing currency that matches the one we've just set the default to during the admin wizard @@ -163,7 +163,7 @@ class ConfiguratorController extends SugarController function action_saveconfig() { - global $current_user; + global $current_user; if(!is_admin($current_user)){ sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); } @@ -178,14 +178,14 @@ class ConfiguratorController extends SugarController unlink($GLOBALS['sugar_config']['cache_dir'].'modules/Contacts/EditView.tpl'); SugarApplication::redirect('index.php?module=Administration&action=index'); - } - - function action_detail() + } + + function action_detail() { - global $current_user; + global $current_user; if(!is_admin($current_user)){ sugar_die($GLOBALS['app_strings']['ERR_NOT_ADMIN']); } $this->view = 'edit'; } -} +} \ No newline at end of file diff --git a/modules/Configurator/language/en_us.lang.php b/modules/Configurator/language/en_us.lang.php index 28627114..bc3c676f 100644 --- a/modules/Configurator/language/en_us.lang.php +++ b/modules/Configurator/language/en_us.lang.php @@ -198,9 +198,15 @@ $mod_strings = array ( 'LBL_LOGGER_MAX_LOG_SIZE'=>'Maximum log size', 'LBL_LOGGER_DEFAULT_DATE_FORMAT'=>'Default date format', 'LBL_LOGGER_LOG_LEVEL'=>'Log Level', + 'LBL_LEAD_CONV_OPTION' => 'Lead Conversion Options', + 'LEAD_CONV_OPT_HELP' => "Copy - Creates and relates copies of all of the Lead's activities to new records that are selected by the user during conversion. Copies are created for each of the selected records.

    Move - Moves all of the Lead's activities to a new record that is selected by the user during conversion.

    Do Nothing - Does nothing with the Lead's activities during conversion. The activities remain related to the Lead only.", + 'LBL_CONFIG_AJAX' => 'Configure AJAX User Interface', + 'LBL_CONFIG_AJAX_DESC' => 'Enable or disable the use of the AJAX UI for specific modules.', 'LBL_LOGGER_MAX_LOGS'=>'Maximum number of logs (before rolling)', 'LBL_LOGGER_FILENAME_SUFFIX' =>'Append after filename', 'LBL_VCAL_PERIOD' => 'vCal Updates Time Period:', + 'LBL_IMPORT_MAX_RECORDS' => 'Import - Maximum Number of Rows:', + 'LBL_IMPORT_MAX_RECORDS_HELP' => 'Specify how many rows are allowed within import files. If the number of rows
    in an import file exceeds this number, the user will be alerted. If no number
    is entered, an unlimited number of rows are allowed.', 'vCAL_HELP' => 'Use this setting to determine the number of months in advance of the current date that Free/Busy information for calls and meetings is published.
    To turn Free/Busy publishing off, enter "0". The minimum is 1 month; the maximum is 12 months.', 'LBL_PDFMODULE_NAME' => 'PDF Settings', 'SUGARPDF_BASIC_SETTINGS' => 'Document Properties', diff --git a/modules/Configurator/tpls/EditView.tpl b/modules/Configurator/tpls/EditView.tpl index 61adf9f1..a085d332 100644 --- a/modules/Configurator/tpls/EditView.tpl +++ b/modules/Configurator/tpls/EditView.tpl @@ -154,6 +154,11 @@ + + + + +
    {$MOD.LBL_LEAD_CONV_OPTION}: {sugar_help text=$MOD.LEAD_CONV_OPT_HELP} {$MOD.LBL_CONFIG_AJAX} {sugar_help text=$MOD.LBL_CONFIG_AJAX_DESC}
    @@ -303,6 +308,11 @@ + + + diff --git a/modules/Configurator/tpls/adminwizard.tpl b/modules/Configurator/tpls/adminwizard.tpl index 99c53253..79b22a28 100644 --- a/modules/Configurator/tpls/adminwizard.tpl +++ b/modules/Configurator/tpls/adminwizard.tpl @@ -58,7 +58,7 @@ function disableReturnSubmission(e) {
    {$MOD.LBL_IMPORT_MAX_RECORDS} {sugar_help text=$MOD.LBL_IMPORT_MAX_RECORDS_HELP} + +
    - - - - - - + + + + + + @@ -347,7 +346,7 @@ function disableReturnSubmission(e) {
    - +
    @@ -68,11 +68,10 @@ function disableReturnSubmission(e) { -
    -
    +
    +
    -
    -
    +
    @@ -85,7 +84,7 @@ function disableReturnSubmission(e) {

    {$MOD.LBL_WIZARD_WELCOME}

    -
    +
    @@ -317,27 +316,27 @@ function disableReturnSubmission(e) {
       
    - - {$MOD.LBL_ALLOW_DEFAULT_SELECTION}  - - - - - - - -   
    + + {$MOD.LBL_ALLOW_DEFAULT_SELECTION}  + + + + + + + +   
    -   +    
    - +
    @@ -360,10 +359,9 @@ function disableReturnSubmission(e) { onclick="if(adjustEmailSettings())this.form.submit();" type="button" name="continue" value="{$MOD.LBL_WIZARD_CONTINUE_BUTTON}" id="next_tab_continue" /> 
    -
    -
    +
    -
    +
    diff --git a/modules/Connectors/controller.php b/modules/Connectors/controller.php index a9929410..9fed8795 100644 --- a/modules/Connectors/controller.php +++ b/modules/Connectors/controller.php @@ -366,7 +366,8 @@ class ConnectorsController extends SugarController { $display_values = explode(',', $_REQUEST['display_values']); foreach($display_values as $value) { $entry = explode(':', $value); - $new_modules_sources[$entry[1]][$entry[0]] = $entry[0]; + $mod = get_module_from_singular($entry[1]); // get the internal module name + $new_modules_sources[$mod][$entry[0]] = $entry[0]; } } diff --git a/modules/Connectors/tpls/display_properties.tpl b/modules/Connectors/tpls/display_properties.tpl index 69fbaba0..46faa664 100644 --- a/modules/Connectors/tpls/display_properties.tpl +++ b/modules/Connectors/tpls/display_properties.tpl @@ -88,12 +88,12 @@ init: function() { new YAHOO.util.DDTarget("{$source_id}:enabled_ul"); new YAHOO.util.DDTarget("{$source_id}:disabled_ul"); - {foreach from=$enabled_modules item=module} - new YAHOO.example.DDList("{$source_id}:{$module}"); + {foreach from=$enabled_modules item=module key=moduleKey} + new YAHOO.example.DDList("{$source_id}:{$moduleKey}"); {/foreach} - {foreach from=$disabled_modules item=module} - new YAHOO.example.DDList("{$source_id}:{$module}"); + {foreach from=$disabled_modules item=module key=moduleKey} + new YAHOO.example.DDList("{$source_id}:{$moduleKey}"); {/foreach} {literal} } diff --git a/modules/Connectors/views/view.displayproperties.php b/modules/Connectors/views/view.displayproperties.php index a97c19f7..cbcba450 100644 --- a/modules/Connectors/views/view.displayproperties.php +++ b/modules/Connectors/views/view.displayproperties.php @@ -63,7 +63,6 @@ class ViewDisplayProperties extends ViewList $source = $_REQUEST['source_id']; $sources = ConnectorUtils::getConnectors(); $modules_sources = ConnectorUtils::getDisplayConfig(); - //$json = getJSONobj(); $enabled_modules = array(); $disabled_modules = array(); @@ -72,7 +71,7 @@ class ViewDisplayProperties extends ViewList foreach($modules_sources as $module=>$mapping) { foreach($modules_sources[$module] as $entry) { if($entry == $source) { - $enabled_modules[$module] = $module; + $enabled_modules[$module] = isset($GLOBALS['app_list_strings']['moduleList'][$module]) ? $GLOBALS['app_list_strings']['moduleList'][$module] : $module; } } } @@ -88,7 +87,7 @@ class ViewDisplayProperties extends ViewList if(substr($e, 0, 1) == '.' || !is_dir('modules/' . $e))continue; if(empty($enabled_modules[$e]) && file_exists('modules/' . $e . '/metadata/studio.php') && file_exists('modules/' . $e . '/metadata/detailviewdefs.php') && isset($GLOBALS [ 'beanList' ][$e]) && (in_array($e, $access) || is_admin($current_user))) // installed modules must also exist in the beanList { - $disabled_modules[$e] = $e; + $disabled_modules[$e] = isset($GLOBALS['app_list_strings']['moduleList'][$e]) ? $GLOBALS['app_list_strings']['moduleList'][$e] : $e; } } diff --git a/modules/Connectors/views/view.mappingproperties.php b/modules/Connectors/views/view.mappingproperties.php index f8076da0..831b6d4d 100644 --- a/modules/Connectors/views/view.mappingproperties.php +++ b/modules/Connectors/views/view.mappingproperties.php @@ -139,7 +139,9 @@ class ViewMappingProperties extends ViewList $display_data[$module] = array('field_keys' => $field_keys, 'field_values' => $field_values, 'available_fields' => $available_fields, - 'field_mapping' => $field_mapping); + 'field_mapping' => $field_mapping, + 'module_name' => isset($GLOBALS['app_list_strings']['moduleList'][$module]) ? $GLOBALS['app_list_strings']['moduleList'][$module] : $module + ); } } diff --git a/modules/Connectors/views/view.searchproperties.php b/modules/Connectors/views/view.searchproperties.php index cf653792..5f023fd3 100644 --- a/modules/Connectors/views/view.searchproperties.php +++ b/modules/Connectors/views/view.searchproperties.php @@ -99,8 +99,10 @@ class ViewSearchProperties extends ViewList } $modules_sources[$module] = array_merge($enabled, $disabled); + asort($disabled); - $display_data[$module] = array('enabled' => $enabled, 'disabled' => $disabled); + $display_data[$module] = array('enabled' => $enabled, 'disabled' => $disabled, + 'module_name' => isset($GLOBALS['app_list_strings']['moduleList'][$module]) ? $GLOBALS['app_list_strings']['moduleList'][$module] : $module); } } diff --git a/modules/Contacts/Contact.php b/modules/Contacts/Contact.php index b6c7a0dd..dec27d7d 100644 --- a/modules/Contacts/Contact.php +++ b/modules/Contacts/Contact.php @@ -203,7 +203,7 @@ class Contact extends Person { //if this is from "contact address popup" action, then process popup list query if(isset($_REQUEST['action']) && $_REQUEST['action'] == 'ContactAddressPopup'){ return $this->address_popup_create_new_list_query($order_by, $where, $filter, $params, $show_deleted, $join_type, $return_array, $parentbean, $singleSelect); - + }else{ //any other action goes to parent function in sugarbean if(strpos($order_by,'sync_contact') !== false){ @@ -212,7 +212,7 @@ class Contact extends Person { $order_by = ''; } return parent::create_new_list_query($order_by, $where, $filter, $params, $show_deleted, $join_type, $return_array, $parentbean, $singleSelect); - } + } } @@ -256,7 +256,7 @@ class Contact extends Person { $from_query .= $custom_join['join']; } $ret_array['from'] = $from_query; - $ret_array['from_min'] = 'from contacts'; + $ret_array['from_min'] = 'from contacts'; $where_auto = '1=1'; if($show_deleted == 0){ @@ -273,26 +273,26 @@ class Contact extends Person { $where_query = "where ".$where_auto; } - + $ret_array['where'] = $where_query; - $orderby_query = ''; + $orderby_query = ''; if(!empty($order_by)){ $orderby_query = " ORDER BY ". $this->process_order_by($order_by, null); } $ret_array['order_by'] = $orderby_query ; - + if($return_array) { return $ret_array; - } - + } + return $ret_array['select'] . $ret_array['from'] . $ret_array['where']. $ret_array['order_by']; } - - + + function create_export_query(&$order_by, &$where, $relate_link_join='') { $custom_join = $this->custom_fields->getJOIN(true, true,$where); @@ -312,11 +312,11 @@ class Contact extends Person { ON ( contacts.id=accounts_contacts.contact_id and (accounts_contacts.deleted is null or accounts_contacts.deleted = 0)) LEFT JOIN accounts ON accounts_contacts.account_id=accounts.id "; - + //join email address table too. $query .= ' LEFT JOIN email_addr_bean_rel on contacts.id = email_addr_bean_rel.bean_id and email_addr_bean_rel.bean_module=\'Contacts\' and email_addr_bean_rel.deleted=0 and email_addr_bean_rel.primary_address=1 '; $query .= ' LEFT JOIN email_addresses on email_addresses.id = email_addr_bean_rel.email_address_id ' ; - + if($custom_join){ $query .= $custom_join['join']; } @@ -335,13 +335,13 @@ class Contact extends Person { return $query; } - function fill_in_additional_list_fields() { + function fill_in_additional_list_fields() { parent::fill_in_additional_list_fields(); $this->_create_proper_name_field(); // cn: bug 8586 - l10n names for Contacts in Email TO: field $this->email_and_name1 = "{$this->full_name} <".$this->email1.">"; $this->email_and_name2 = "{$this->full_name} <".$this->email2.">"; - + if($this->force_load_details == true) { $this->fill_in_additional_detail_fields(); } @@ -369,6 +369,8 @@ class Contact extends Person { $query .= " and acc.id = '{$this->account_id}'"; } + $query .= " ORDER BY a_c.date_modified DESC"; + $result = $this->db->query($query,true," Error filling in additional detail fields: "); // Get the id and the name. @@ -401,11 +403,11 @@ class Contact extends Person { } // Set campaign name if there is a campaign id if( !empty($this->campaign_id)){ - + $camp = new Campaign(); $where = "campaigns.id='{$this->campaign_id}'"; $campaign_list = $camp->get_full_list("campaigns.name", $where, true); - $this->campaign_name = $campaign_list[0]->name; + $this->campaign_name = $campaign_list[0]->name; } } @@ -418,20 +420,11 @@ class Contact extends Person { global $current_user; $this->load_relationship("user_sync"); - $query_array=$this->user_sync->getQuery(true); - - $query_array['where'] .= " AND users.id = '$current_user->id'"; - - $query=''; - foreach ($query_array as $qstring) { - $query.=' '.$qstring; - } - - $list = $this->build_related_list($query, new User()); - if(!empty($list)){ - //this should only return one possible value so set it - $this->contacts_users_id = $list[0]->id; - } + $beans = $this->user_sync->getBeans(); + if (!empty($beans[$current_user->id])) + { + $this->contacts_users_id = $current_user->id; + } } function get_list_view_data($filter_fields = array()) { @@ -504,7 +497,7 @@ class Contact extends Person { function set_notification_body($xtpl, $contact) { global $locale; - + $xtpl->assign("CONTACT_NAME", trim($locale->getLocaleFormattedName($contact->first_name, $contact->last_name))); $xtpl->assign("CONTACT_DESCRIPTION", $contact->description); @@ -557,10 +550,10 @@ class Contact extends Person { return false; } function get_unlinked_email_query($type=array()) { - + return get_unlinked_email_query($type, $this); } - + /** * used by import to add a list of users * @@ -570,27 +563,27 @@ class Contact extends Person { * * @param string $list_of_user */ - + function process_sync_to_outlook( $list_of_users - ) + ) { static $focus_user; - + // cache this object since we'll be reusing it a bunch if ( !($focus_user instanceof User) ) { - + $focus_user = new User(); } - - + + if ( empty($list_of_users) ) { return; } if ( !isset($this->users) ) { $this->load_relationship('user_sync'); } - + if ( strtolower($list_of_users) == 'all' ) { // add all non-deleted users $sql = "SELECT id FROM users WHERE deleted=0 AND is_group=0 AND portal_only=0"; @@ -598,7 +591,7 @@ class Contact extends Person { while ( $hash = $this->db->fetchByAssoc($result) ) { $this->user_sync->add($hash['id']); } - } + } else { $theList = explode(",",$list_of_users); foreach ($theList as $eachItem) { diff --git a/modules/Contacts/ContactFormBase.php b/modules/Contacts/ContactFormBase.php index 3bbbc4a5..186e49c2 100644 --- a/modules/Contacts/ContactFormBase.php +++ b/modules/Contacts/ContactFormBase.php @@ -677,16 +677,21 @@ function handleSave($prefix, $redirect=true, $useRequired=false){ // for InboundEmail flow if(!empty($_POST['start'])) $get .= '&start='.$_POST['start']; - //now redirect the post to modules/Contacts/ShowDuplicates.php + + $_SESSION['SHOW_DUPLICATES'] = $get; + //now redirect the post to modules/Contacts/ShowDuplicates.php if (!empty($_POST['is_ajax_call']) && $_POST['is_ajax_call'] == '1') { ob_clean(); $json = getJSONobj(); - $_SESSION['SHOW_DUPLICATES'] = $get; echo $json->encode(array('status' => 'dupe', 'get' => $location)); - } else { + } + else if(!empty($_REQUEST['ajax_load'])) + { + echo ""; + } + else { if(!empty($_POST['to_pdf'])) $location .= '&to_pdf='.$_POST['to_pdf']; - $_SESSION['SHOW_DUPLICATES'] = $get; header("Location: index.php?$location"); } return null; @@ -805,12 +810,17 @@ function handleRedirect($return_id){ } //eggsurplus Bug 23816: maintain VCR after an edit/save. If it is a duplicate then don't worry about it. The offset is now worthless. - $redirect_url = "Location: index.php?action=$return_action&module=$return_module&record=$return_id"; + $redirect_url = "index.php?action=$return_action&module=$return_module&record=$return_id"; if(isset($_REQUEST['offset']) && empty($_REQUEST['duplicateSave'])) { $redirect_url .= "&offset=".$_REQUEST['offset']; } - - header($redirect_url); + + if(!empty($_REQUEST['ajax_load'])){ + echo "\n"; + } + else { + header("Location: ". $redirect_url); + } } } diff --git a/modules/Contacts/ShowDuplicates.php b/modules/Contacts/ShowDuplicates.php index d7ddb895..e1d4eff5 100644 --- a/modules/Contacts/ShowDuplicates.php +++ b/modules/Contacts/ShowDuplicates.php @@ -50,8 +50,8 @@ global $theme; $error_msg = ''; global $current_language; $mod_strings = return_module_language($current_language, 'Contacts'); - -echo getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array($mod_strings['LBL_MODULE_NAME'],$mod_strings['LBL_SAVE_CONTACT']), true); +$moduleName = $GLOBALS['app_list_strings']['moduleList']['Contacts']; +echo getClassicModuleTitle('Contacts', array($moduleName,$mod_strings['LBL_SAVE_CONTACT']), true); $xtpl=new XTemplate ('modules/Contacts/ShowDuplicates.html'); $xtpl->assign("MOD", $mod_strings); $xtpl->assign("APP", $app_strings); diff --git a/modules/Contacts/language/en_us.lang.php b/modules/Contacts/language/en_us.lang.php index e3ab8c12..d4da1db6 100644 --- a/modules/Contacts/language/en_us.lang.php +++ b/modules/Contacts/language/en_us.lang.php @@ -79,7 +79,7 @@ $mod_strings = array ( 'LBL_BUSINESSCARD' => 'Business Card', 'LBL_CITY' => 'City:', 'LBL_CAMPAIGN_ID' => 'Campaign ID', - 'LBL_CONTACT_INFORMATION' => 'Contact Overview', + 'LBL_CONTACT_INFORMATION' => 'Overview', 'LBL_CONTACT_NAME' => 'Contact Name:', 'LBL_CONTACT_OPP_FORM_TITLE' => 'Contact-Opportunity:', 'LBL_CONTACT_ROLE' => 'Role:', @@ -206,7 +206,7 @@ $mod_strings = array ( 'LBL_CASES_SUBPANEL_TITLE' => 'Cases', 'LBL_BUGS_SUBPANEL_TITLE' => 'Bugs', - 'LBL_PROJECTS_SUBPANEL_TITLE' => 'Projects', + 'LBL_PROJECTS_SUBPANEL_TITLE' => 'Projects', 'LBL_TARGET_OF_CAMPAIGNS' => 'Campaigns (Target of) :', 'LBL_CAMPAIGNS' => 'Campaigns', 'LBL_CAMPAIGN_LIST_SUBPANEL_TITLE'=>'Campaigns', @@ -220,5 +220,21 @@ $mod_strings = array ( 'LBL_PROJECT_SUBPANEL_TITLE' => 'Projects', 'LBL_CAMPAIGNS_SUBPANEL_TITLE' => 'Campaigns', 'LNK_IMPORT_CONTACTS' => 'Import Contacts', + + //For export labels + 'LBL_PHONE_HOME' => 'Phone Home', + 'LBL_PHONE_MOBILE' => 'Phone Mobile', + 'LBL_PHONE_WORK' => 'Phone Work', + 'LBL_PHONE_OTHER' => 'Phone Other', + 'LBL_PHONE_FAX' => 'Phone Fax', + 'LBL_CAMPAIGN_ID' => 'Campaign ID', + + 'LBL_EXPORT_ASSIGNED_USER_NAME' => 'Assigned User Name', + 'LBL_EXPORT_ASSIGNED_USER_ID' => 'Assigned User ID', + 'LBL_EXPORT_MODIFIED_USER_ID' => 'Modified By ID', + 'LBL_EXPORT_CREATED_BY' => 'Created By ID', + // SNIP + 'LBL_CONTACT_HISTORY_SUBPANEL_TITLE' => 'Related Contacts\' Emails', + 'LBL_USER_SYNC' => 'User Sync' ) -?> \ No newline at end of file +?> diff --git a/modules/Contacts/metadata/subpaneldefs.php b/modules/Contacts/metadata/subpaneldefs.php index e5053462..9e393e39 100644 --- a/modules/Contacts/metadata/subpaneldefs.php +++ b/modules/Contacts/metadata/subpaneldefs.php @@ -136,7 +136,7 @@ $layout_defs['Contacts'] = array( ), ) ), - 'documents' => array( + 'documents' => array( 'order' => 25, 'module' => 'Documents', 'subpanel_name' => 'default', @@ -144,13 +144,13 @@ $layout_defs['Contacts'] = array( 'sort_by' => 'id', 'title_key' => 'LBL_DOCUMENTS_SUBPANEL_TITLE', 'get_subpanel_data' => 'documents', - 'top_buttons' => + 'top_buttons' => array ( - 0 => + 0 => array ( 'widget_class' => 'SubPanelTopButtonQuickCreate', ), - 1 => + 1 => array ( 'widget_class' => 'SubPanelTopSelectButton', 'mode' => 'MultiSelect', diff --git a/modules/Contacts/tpls/QuickCreate.tpl b/modules/Contacts/tpls/QuickCreate.tpl index 5585b395..f79ef1cb 100644 --- a/modules/Contacts/tpls/QuickCreate.tpl +++ b/modules/Contacts/tpls/QuickCreate.tpl @@ -63,12 +63,13 @@ {{/if}} {* -- Begin QuickCreate Specific -- *} +{if $smarty.request.action != 'SubpanelEdits'} - +{/if} {* -- End QuickCreate Specific -- *} diff --git a/modules/Contacts/vardefs.php b/modules/Contacts/vardefs.php index abd23c8b..a7740f09 100644 --- a/modules/Contacts/vardefs.php +++ b/modules/Contacts/vardefs.php @@ -305,6 +305,16 @@ array ( 'source' => 'non-db', 'vname' => 'LBL_PROJECTS', ), + 'project_resource'=> + array ( + 'name' => 'project_resource', + 'type' => 'link', + 'relationship' => 'projects_contacts_resources', + 'source' => 'non-db', + 'vname' => 'LBL_PROJECTS', + ), + + 'tasks'=> array ( @@ -324,7 +334,7 @@ array ( ), 'user_sync'=> array ( - 'name' => 'users', + 'name' => 'user_sync', 'type' => 'link', 'relationship' => 'contacts_users', 'source' => 'non-db', diff --git a/modules/Contacts/views/view.edit.php b/modules/Contacts/views/view.edit.php index 333ef290..38d15a57 100644 --- a/modules/Contacts/views/view.edit.php +++ b/modules/Contacts/views/view.edit.php @@ -70,8 +70,7 @@ class ContactsViewEdit extends ViewEdit echo ''; } diff --git a/modules/Currencies/Currency.php b/modules/Currencies/Currency.php index 9d2e6937..b45ec872 100644 --- a/modules/Currencies/Currency.php +++ b/modules/Currencies/Currency.php @@ -488,8 +488,9 @@ function get_number_seperators($reset_sep = false) if ($dec_sep == null) { $dec_sep = $sugar_config['default_decimal_seperator']; - if (!empty($current_user->id)) { - $user_dec_sep = $current_user->getPreference('dec_sep'); + if (!empty($current_user->id)) + { + $user_dec_sep = $current_user->getPreference('dec_sep'); $dec_sep = (empty($user_dec_sep) ? $sugar_config['default_decimal_seperator'] : $user_dec_sep); } } @@ -497,8 +498,9 @@ function get_number_seperators($reset_sep = false) if ($num_grp_sep == null) { $num_grp_sep = $sugar_config['default_number_grouping_seperator']; - if (!empty($current_user->id)) { - $user_num_grp_sep = $current_user->getPreference('num_grp_sep'); + if (!empty($current_user->id)) + { + $user_num_grp_sep = $current_user->getPreference('num_grp_sep'); $num_grp_sep = (empty($user_num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $user_num_grp_sep); } } diff --git a/modules/DocumentRevisions/metadata/editviewdefs.php b/modules/DocumentRevisions/metadata/editviewdefs.php index dbda0d88..af57df00 100644 --- a/modules/DocumentRevisions/metadata/editviewdefs.php +++ b/modules/DocumentRevisions/metadata/editviewdefs.php @@ -44,8 +44,7 @@ $viewdefs['DocumentRevisions']['EditView'] = array( array('label' => '10', 'field' => '30') ), 'javascript' => ' - - +', ), 'panels' =>array ( diff --git a/modules/Documents/language/en_us.lang.php b/modules/Documents/language/en_us.lang.php index fa3aac68..9cb265b9 100644 --- a/modules/Documents/language/en_us.lang.php +++ b/modules/Documents/language/en_us.lang.php @@ -166,7 +166,7 @@ $mod_strings = array ( 'LBL_CONTRACTS' => 'Contracts', 'LBL_CREATED_USER' => 'Created User', 'LBL_THEREVISIONS_SUBPANEL_TITLE' => 'Reversions', - 'LBL_DOCUMENT_INFORMATION' => 'Document Overview', + 'LBL_DOCUMENT_INFORMATION' => 'Overview', 'LBL_DOC_ID' => 'Document Source ID', 'LBL_DOC_TYPE' => 'Source', 'LBL_LIST_DOC_TYPE' => 'Source', diff --git a/modules/Documents/metadata/editviewdefs.php b/modules/Documents/metadata/editviewdefs.php index 95e52d5e..4f946c43 100644 --- a/modules/Documents/metadata/editviewdefs.php +++ b/modules/Documents/metadata/editviewdefs.php @@ -45,8 +45,7 @@ $viewdefs['Documents']['EditView'] = array( array('label' => '10', 'field' => '30') ), 'javascript' => ' - - +', ), 'panels' =>array ( diff --git a/modules/Documents/metadata/quickcreatedefs.php b/modules/Documents/metadata/quickcreatedefs.php index 7daaf982..f57e62ff 100644 --- a/modules/Documents/metadata/quickcreatedefs.php +++ b/modules/Documents/metadata/quickcreatedefs.php @@ -48,8 +48,7 @@ $viewdefs['Documents']['QuickCreate'] = array( 'includes' => array ( array('file' => 'include/javascript/popup_parent_helper.js'), - array('file' => 'include/javascript/jsclass_base.js'), - array('file' => 'include/javascript/jsclass_async.js'), + array('file' => 'include/javascript/sugar_grp_jsolait.js'), array('file' => 'modules/Documents/documents.js'), ), ), @@ -68,7 +67,9 @@ $viewdefs['Documents']['QuickCreate'] = array( array ( 'document_name', - 'revision' + array('name'=>'revision', + 'customCode' => '' + ), ), array ( diff --git a/modules/Documents/tpls/view.extdoc.tpl b/modules/Documents/tpls/view.extdoc.tpl index de9d8eb9..f1f90331 100644 --- a/modules/Documents/tpls/view.extdoc.tpl +++ b/modules/Documents/tpls/view.extdoc.tpl @@ -81,8 +81,8 @@ YAHOO.util.Connect.asyncRequest('POST', 'index.php', callback, "module=Documents {counter start=0 name="colCounter" print=false assign="colCounter"} {foreach from=$displayColumns key=colHeader item=params} - diff --git a/modules/Documents/views/view.edit.php b/modules/Documents/views/view.edit.php index 62dc0f0f..ea43a8ea 100644 --- a/modules/Documents/views/view.edit.php +++ b/modules/Documents/views/view.edit.php @@ -39,6 +39,15 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); class DocumentsViewEdit extends ViewEdit { + + /** + * @see SugarView::ViewEdit() + */ + function DocumentsViewEdit(){ + parent::ViewEdit(); + $this->useForSubpanel = true; + } + /** * @see SugarView::display() */ @@ -72,7 +81,9 @@ class DocumentsViewEdit extends ViewEdit $this->bean->is_template=0; } //if - if (!empty($this->bean->id)) { + if (!empty($this->bean->id) || + (empty($this->bean->id) && !empty($_REQUEST['record']) && !empty($_REQUEST['action']) && strtolower($_REQUEST['action'])=='quickedit') + ) { $this->ss->assign("FILE_OR_HIDDEN", "hidden"); if (!$this->ev->isDuplicate) { $this->ss->assign("DISABLED", "disabled"); @@ -162,4 +173,5 @@ class DocumentsViewEdit extends ViewEdit return $params; } + } diff --git a/modules/DynamicFields/DynamicField.php b/modules/DynamicFields/DynamicField.php index 09617c13..0d1b798f 100644 --- a/modules/DynamicFields/DynamicField.php +++ b/modules/DynamicFields/DynamicField.php @@ -183,11 +183,7 @@ class DynamicField { global $beanList; if (! empty ( $beanList [$module] )) { - $object = $beanList [$module]; - - if ($object == 'aCase') { - $object = 'Case'; - } + $object = BeanFactory::getObjectName($module); if(empty($GLOBALS['dictionary'][$object]['fields'])){ //if the vardef isn't loaded let's try loading it. @@ -453,8 +449,10 @@ class DynamicField { } $object_name = $beanList[$this->module]; - if ($object_name == 'aCase') { - $object_name = 'Case'; + //Some modules like cases have a bean name that doesn't match the object name + if (empty($GLOBALS['dictionary'][$object_name])) { + $newName = BeanFactory::getObjectName($this->module); + $object_name = $newName != false ? $newName : $object_name; } $GLOBALS['db']->query("DELETE FROM fields_meta_data WHERE id='" . $this->module . $widget->name . "'"); @@ -550,7 +548,16 @@ class DynamicField { //We do this so that the existing entries in the custom table don't have the default value set $field->default = ''; $field->default_value = ''; + // resetting default and default_value does not work for multienum and causes trouble for mssql + // so using a temporary variable here to indicate that we don't want default for this query + if ($GLOBALS['db']->dbType == 'mssql') { + $field->no_default = 1; + } $query = $field->get_db_add_alter_table($this->bean->table_name . '_cstm'); + // unsetting temporary member variable + if ($GLOBALS['db']->dbType == 'mssql') { + unset($field->no_default); + } if(!empty($query)){ $GLOBALS['db']->query($query); $field->default = $fmd->default_value; @@ -558,13 +565,13 @@ class DynamicField { $query = $field->get_db_modify_alter_table($this->bean->table_name . '_cstm'); if(!empty($query)){ $GLOBALS['db']->query($query); - } + } } }else{ $query = $field->get_db_modify_alter_table($this->bean->table_name . '_cstm'); if(!empty($query)){ $GLOBALS['db']->query($query); - } + } } $this->saveExtendedAttributes($field, array_keys($fmd->field_defs)); } @@ -728,7 +735,7 @@ class DynamicField { $GLOBALS['db']->query($query); $out .= $this->add_existing_custom_fields($execute); } - + return $out; } @@ -780,7 +787,7 @@ class DynamicField { * @bug 43471 * @issue 43471 * @itr 23441 - * + * * force the name to be lower as it needs to be lower since that is how it's put into the key * in the get_columns() call above. */ @@ -898,7 +905,7 @@ class DynamicField { } - function populateXTPL(&$xtpl, $view) { + function populateXTPL($xtpl, $view) { if($this->bean->hasCustomFields()){ $results = $this->getAllFieldsView($view, 'xtpl'); @@ -917,23 +924,23 @@ class DynamicField { } - function populateAllXTPL(&$xtpl, $view){ + function populateAllXTPL($xtpl, $view){ $this->populateXTPL($xtpl, $view); } function getAllFieldsView($view, $type){ - $results = array(); + require_once ('modules/DynamicFields/FieldCases.php'); + $results = array(); foreach($this->bean->field_defs as $name=>$data){ if(empty($data['source']) || $data['source'] != 'custom_fields') { continue; } - require_once ('modules/DynamicFields/FieldCases.php'); $field = get_widget ( $data ['type'] ); $field->populateFromRow($data); $field->view = $view; - $field->bean =& $this->bean; + $field->bean = $this->bean; switch(strtolower($type)) { case 'xtpl': diff --git a/modules/DynamicFields/templates/Fields/TemplateEnum.php b/modules/DynamicFields/templates/Fields/TemplateEnum.php index 0b299097..e7d24c1e 100644 --- a/modules/DynamicFields/templates/Fields/TemplateEnum.php +++ b/modules/DynamicFields/templates/Fields/TemplateEnum.php @@ -193,9 +193,6 @@ class TemplateEnum extends TemplateText{ if (!empty($this->default) && is_array($this->default)) { $this->default = $this->default[0]; } - - if ( get_class( $this ) == 'TemplateEnum' && isset ( $this->dependency ) ) - $this->ext4 = serialize ( $this->dependency ) ; parent::save($df); } } diff --git a/modules/DynamicFields/templates/Fields/TemplateMultiEnum.php b/modules/DynamicFields/templates/Fields/TemplateMultiEnum.php index b410e5cd..c80a9171 100644 --- a/modules/DynamicFields/templates/Fields/TemplateMultiEnum.php +++ b/modules/DynamicFields/templates/Fields/TemplateMultiEnum.php @@ -134,13 +134,13 @@ class TemplateMultiEnum extends TemplateEnum{ // if we have a new error, then unserialize must have failed => we don't have a packed ext4 // safe to assume that false means the unpack failed, as ext4 will either contain an imploded string of default values, or an array, not a boolean false value - if ( $unpacked === false ) { + if ( $unpacked === false && !isset($this->no_default) ) { $def [ 'default' ] = $this->ext4 ; } else { // we have a packed representation containing one or both of default and dependency - if ( isset ( $unpacked [ 'default' ] ) ) + if ( isset ( $unpacked [ 'default' ] ) && !isset($this->no_default)) $def [ 'default' ] = $unpacked [ 'default' ] ; if ( isset ( $unpacked [ 'dependency' ] ) ) $def [ 'dependency' ] = $unpacked [ 'dependency' ] ; diff --git a/modules/EAPM/controller.php b/modules/EAPM/controller.php index da9cfbb4..09dd9dac 100644 --- a/modules/EAPM/controller.php +++ b/modules/EAPM/controller.php @@ -59,6 +59,10 @@ class EAPMController extends SugarController SugarApplication::appendErrorMessage($error); $GLOBALS['log']->error("Login error: $error"); $url = 'index.php?module=EAPM&action=EditView&record='.$this->bean->id; + + if($this->return_module == 'Import'){ + $url .= "&application={$this->bean->application}&return_module={$this->return_module}&return_action={$this->return_action}"; + } return $this->set_redirect($url); } @@ -100,6 +104,10 @@ class EAPMController extends SugarController $this->return_action = 'EditView'; } parent::post_save(); + + if($this->return_module == 'Import'){ + $this->set_redirect("index.php?module=Import&action=Step1&import_module=". $this->return_action . "&application=" . $this->bean->application); + } // Override the redirect location to add the hash $this->redirect_url = $this->redirect_url.'#tab5'; if ( $this->api->authMethod == 'oauth' && !$this->bean->deleted ) { diff --git a/modules/EAPM/metadata/editviewdefs.php b/modules/EAPM/metadata/editviewdefs.php index 7c6980dc..78f91b77 100644 --- a/modules/EAPM/metadata/editviewdefs.php +++ b/modules/EAPM/metadata/editviewdefs.php @@ -49,10 +49,10 @@ $viewdefs[$module_name]['EditView'] = array( 'customCode' => '{if $bean->aclAccess("save")}{/if} ' ), array ( - 'customCode' => '', + 'customCode' => '', ), array ( - 'customCode' => '{if $bean->aclAccess("delete")}{/if} ', + 'customCode' => '{if $bean->aclAccess("delete") && !empty($smarty.request.record)}{/if} ', ), ), 'headerTpl'=>'modules/EAPM/tpls/EditViewHeader.tpl', diff --git a/modules/EAPM/vardefs.php b/modules/EAPM/vardefs.php index 9800a4a9..fe47b129 100644 --- a/modules/EAPM/vardefs.php +++ b/modules/EAPM/vardefs.php @@ -44,7 +44,6 @@ $dictionary['EAPM'] = array( 'name' => 'password', 'vname' => 'LBL_PASSWORD', 'type' => 'encrypt', - 'dbtype' => 'varchar', 'massupdate' => 0, 'comments' => '', 'help' => '', @@ -101,7 +100,6 @@ $dictionary['EAPM'] = array( 'dbType' => 'varchar', 'len' => '255', 'unified_search' => true, -// 'required' => true, 'importable' => 'required', 'massupdate' => 0, 'comments' => '', @@ -152,7 +150,6 @@ $dictionary['EAPM'] = array( 'audited' => false, 'reportable' => false, 'required' => false, - 'dbtype' => 'varchar', 'studio' => 'hidden', ), 'oauth_secret' => array( @@ -164,7 +161,6 @@ $dictionary['EAPM'] = array( 'audited' => false, 'reportable' => false, 'required' => false, - 'dbtype' => 'varchar', 'studio' => 'hidden', ), 'validated' => array( diff --git a/modules/EAPM/views/view.detail.php b/modules/EAPM/views/view.detail.php index 87532c22..f7b7deab 100644 --- a/modules/EAPM/views/view.detail.php +++ b/modules/EAPM/views/view.detail.php @@ -43,6 +43,22 @@ class EAPMViewDetail extends ViewDetail { private $_returnId; + public function __construct() + { + $this->setReturnId(); + parent::__construct(); + } + + protected function setReturnId() + { + $returnId = $GLOBALS['current_user']->id; + if(!empty($_REQUEST['user_id']) && !empty($_REQUEST['return_module']) && 'Users' == $_REQUEST['return_module']){ + $returnId = $_REQUEST['user_id']; + } + $this->_returnId = $returnId; + } + + protected function _getModuleTab() { return 'Users'; diff --git a/modules/EAPM/views/view.edit.php b/modules/EAPM/views/view.edit.php index d01b0c5c..68c4468f 100644 --- a/modules/EAPM/views/view.edit.php +++ b/modules/EAPM/views/view.edit.php @@ -41,6 +41,21 @@ class EAPMViewEdit extends ViewEdit { private $_returnId; + public function __construct() + { + $this->setReturnId(); + parent::__construct(); + } + + protected function setReturnId() + { + $returnId = $GLOBALS['current_user']->id; + if(!empty($_REQUEST['user_id']) && !empty($_REQUEST['return_module']) && 'Users' == $_REQUEST['return_module']){ + $returnId = $_REQUEST['user_id']; + } + $this->_returnId = $returnId; + } + protected function _getModuleTab() { return 'Users'; @@ -97,6 +112,13 @@ class EAPMViewEdit extends ViewEdit { function display() { $this->ss->assign('return_id', $this->_returnId); + $cancelUrl = "index.php?action=EditView&module=Users&record={$this->_returnId}#tab5"; + + if(isset($_REQUEST['return_module']) && $_REQUEST['return_module'] == 'Import') { + $cancelUrl = "index.php?module=Import&action=Step1&import_module=". $_REQUEST['return_action'] . "&application=" . $_REQUEST['application']; + } + $this->ss->assign('cancelUrl', $cancelUrl); + if($GLOBALS['current_user']->is_admin || empty($this->bean) || empty($this->bean->id) || $this->bean->isOwner($GLOBALS['current_user']->id)){ if(!empty($this->bean) && empty($this->bean->id) && $this->_returnId != $GLOBALS['current_user']->id){ $this->bean->assigned_user_id = $this->_returnId; @@ -107,5 +129,4 @@ class EAPMViewEdit extends ViewEdit { ACLController::displayNoAccess(); } } -} -?> \ No newline at end of file +} \ No newline at end of file diff --git a/modules/EmailMan/EmailMan.php b/modules/EmailMan/EmailMan.php index d679106d..bbeeb472 100644 --- a/modules/EmailMan/EmailMan.php +++ b/modules/EmailMan/EmailMan.php @@ -122,7 +122,7 @@ class EmailMan extends SugarBean{ LEFT JOIN campaigns ON campaigns.id = $this->table_name.campaign_id LEFT JOIN email_marketing ON email_marketing.id = $this->table_name.marketing_id "; - $where_auto = " $this->table_name.deleted=0"; + $where_auto = " $this->table_name.deleted=0"; if($where != "") $query['where'] = "WHERE $where AND ".$where_auto; @@ -199,7 +199,7 @@ class EmailMan extends SugarBean{ on {$this->table_name}.id = secondary.id "; } - $where_auto = " $this->table_name.deleted=0"; + $where_auto = " $this->table_name.deleted=0"; if($where != "") $query .= "WHERE $where AND ".$where_auto; @@ -257,7 +257,7 @@ class EmailMan extends SugarBean{ LEFT JOIN campaigns ON campaigns.id = $this->table_name.campaign_id LEFT JOIN email_marketing ON email_marketing.id = $this->table_name.marketing_id "; - $where_auto = " $this->table_name.deleted=0"; + $where_auto = " $this->table_name.deleted=0"; if($where != "") $query .= "where $where AND ".$where_auto; diff --git a/modules/EmailMan/EmailManDelivery.php b/modules/EmailMan/EmailManDelivery.php index 61131146..bcf25682 100644 --- a/modules/EmailMan/EmailManDelivery.php +++ b/modules/EmailMan/EmailManDelivery.php @@ -92,7 +92,7 @@ $emailman = new EmailMan(); $select_query.=" join prospect_lists pl on pl.id = plc.prospect_list_id "; $select_query.=" WHERE em.list_id = pl.id and pl.list_type = 'test'"; $select_query.=" AND em.send_date_time <= ". db_convert("'".$timedate->nowDb()."'" ,"datetime"); - $select_query.=" AND (em.in_queue ='0' OR ( em.in_queue ='1' AND em.in_queue_date <= " .db_convert("'". $timedate->fromString("-1 day")->asDb() ."'" ,"datetime")."))"; + $select_query.=" AND (em.in_queue ='0' OR em.in_queue IS NULL OR ( em.in_queue ='1' AND em.in_queue_date <= " .db_convert("'". $timedate->fromString("-1 day")->asDb() ."'" ,"datetime")."))"; $select_query.=" AND em.campaign_id='{$campaign_id}'"; $select_query.=" ORDER BY em.send_date_time ASC, em.user_id, em.list_id"; }else{ @@ -103,7 +103,7 @@ $emailman = new EmailMan(); $select_query =" SELECT *"; $select_query.=" FROM $emailman->table_name"; $select_query.=" WHERE send_date_time <= ". db_convert("'".TimeDate::getInstance()->nowDb()."'" ,"datetime"); - $select_query.=" AND (in_queue ='0' OR ( in_queue ='1' AND in_queue_date <= " .db_convert("'". $timedate->fromString("-1 day")->asDb() ."'" ,"datetime")."))"; + $select_query.=" AND (in_queue ='0' OR in_queue IS NULL OR ( in_queue ='1' AND in_queue_date <= " .db_convert("'". $timedate->fromString("-1 day")->asDb() ."'" ,"datetime")."))"; if (!empty($campaign_id)) { $select_query.=" AND campaign_id='{$campaign_id}'"; @@ -175,7 +175,7 @@ do { //the criteria in the original query, and we care most about the in_queue_date and process_date_time, //if they are null or in past(older than 24 horus) then we are okay. $lock_query="UPDATE emailman SET in_queue=1, in_queue_date='". $timedate->nowDb() ."' WHERE id = '${row['id']}'"; - $lock_query.=" AND (in_queue ='0' OR ( in_queue ='1' AND in_queue_date <= " .db_convert("'". $timedate->fromString("-1 day")->asDb() ."'" ,"datetime")."))"; + $lock_query.=" AND (in_queue ='0' OR in_queue IS NULL OR ( in_queue ='1' AND in_queue_date <= " .db_convert("'". $timedate->fromString("-1 day")->asDb() ."'" ,"datetime")."))"; //if the query fails to execute.. terminate campaign email process. $lock_result=$db->query($lock_query,true,'Error acquiring a lock for emailman entry.'); diff --git a/modules/EmailMan/tpls/config.tpl b/modules/EmailMan/tpls/config.tpl index 05094578..ce5c7488 100644 --- a/modules/EmailMan/tpls/config.tpl +++ b/modules/EmailMan/tpls/config.tpl @@ -530,7 +530,6 @@ function sendTestEmail() var mail_sendtype = document.getElementById('mail_sendtype').value; var from_name = document.getElementById('notify_fromname').value; - var postDataString = 'mail_name=system&mail_sendtype=' + mail_sendtype + '&mail_smtpserver=' + smtpServer + "&mail_smtpport=" + smtpPort + "&mail_smtpssl=" + smtpssl + "&mail_smtpauth_req=" + mailsmtpauthreq.checked + "&mail_smtpuser=" + trim(document.getElementById('mail_smtpuser').value) + "&mail_smtppass=" + trim(document.getElementById('mail_smtppass').value) + "&outboundtest_to_address=" + encodeURIComponent(toAddress) + diff --git a/modules/EmailMan/vardefs.php b/modules/EmailMan/vardefs.php index 8104681f..bcc439ee 100644 --- a/modules/EmailMan/vardefs.php +++ b/modules/EmailMan/vardefs.php @@ -104,6 +104,7 @@ array( 'table' => 'emailman', 'comment' => 'Email campaign queue', 'fields' => a 'name' => 'in_queue', 'vname' => 'LBL_IN_QUEUE', 'type' => 'bool', + 'default' => '0', 'comment' => 'Flag indicating if item still in queue', ), 'in_queue_date' => array( @@ -125,6 +126,7 @@ array( 'table' => 'emailman', 'comment' => 'Email campaign queue', 'fields' => a 'type' => 'bool', 'reportable' =>false, 'comment' => 'Record deletion indicator', + 'default' => '0', ), 'related_id' => array( 'name' => 'related_id', diff --git a/modules/EmailTemplates/EditView.html b/modules/EmailTemplates/EditView.html index 4a02d2b1..91a326ba 100644 --- a/modules/EmailTemplates/EditView.html +++ b/modules/EmailTemplates/EditView.html @@ -225,10 +225,11 @@ + + + + +{MESSAGE} + + + + + + + + + + + + + + + + + + + +
    -
    +
    +
    {sugar_translate label=$params.label module='Documents'}
    + + + + + +
    + + + + + + {ADMIN_EDIT} +
    + + + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + + + + + +   + + + + + +  {CHANGE_PARENT_BUTTON} + +
    + + {APP.LBL_ASSIGNED_TO}  + + + + + + + + + + + + + + + + +
    +   +
    +   + + {MOD.LBL_NOTE_SEMICOLON} + +   +
    + + {MOD.LBL_TO} + + + + + + + + +
    + + + + + + {CHANGE_TO_ADDRS_BUTTON} +
    +
    +
    + + {MOD.LBL_CC} + + + + + + + + +
    + + + + + + {CHANGE_CC_ADDRS_BUTTON} +
    +
    +
    + + {MOD.LBL_BCC} + + + + + + + +
    + + + + + + {CHANGE_BCC_ADDRS_BUTTON} +
    +
    + + {MOD.LBL_FROM} + + + + + + + +
    + {FROM_ADDR_GROUP} + + +
    +
    +
    +   +
    + + {MOD.LBL_SUBJECT} + + + + + +
    + {MOD.LBL_BODY} + + +
    + + {MOD.LBL_EMAIL_EDITOR_OPTION} +
    +
    +
    + + {MOD.LBL_USE_TEMPLATE}  + + + + + +
    +   + + {TINY} + +
    + +
    +
    + + {MOD.LBL_EDIT_ALT_TEXT} +
    + +
    +
    + {MOD.LBL_ATTACHMENTS} + + {ATTACHMENTS_JAVASCRIPT} {ATTACHMENTS} +
    +
    +
    + + + + + + + + + + + + + + + + + + + + +
    + + +
    +
    + +{JAVASCRIPT} + + \ No newline at end of file diff --git a/modules/Emails/EditView.php b/modules/Emails/EditView.php index 13c89e92..15e27839 100644 --- a/modules/Emails/EditView.php +++ b/modules/Emails/EditView.php @@ -405,18 +405,22 @@ $xtpl->assign('PRINT_URL', 'index.php?'.$GLOBALS['request_string']); $quicksearch_js = <<sqs_objects = $sqs_objects_encoded; var dialog_loaded; function parent_typechangeQS() { - //new_module = document.getElementById('parent_type').value; - new_module = document.EditView.parent_type.value; + var new_module = document.EditView.parent_type.value; + var sqsId = 'EditView_parent_name'; if(new_module == 'Contacts' || new_module == 'Leads' || typeof(disabledModules[new_module]) != 'undefined') { - sqs_objects['EditView_parent_name']['disable'] = true; + sqs_objects[sqsId]['disable'] = true; document.getElementById('parent_name').readOnly = true; } else { - sqs_objects['EditView_parent_name']['disable'] = false; + sqs_objects[sqsId]['disable'] = false; document.getElementById('parent_name').readOnly = false; } - sqs_objects['EditView_parent_name']['modules'] = new Array(new_module); + sqs_objects[sqsId]['modules'] = new Array(new_module); + if (typeof(QSFieldsArray[sqsId]) != 'undefined') + { + QSFieldsArray[sqsId].sqs.modules = new Array(new_module); + } enableQS(false); } parent_typechangeQS(); diff --git a/modules/Emails/EditViewArchive.html b/modules/Emails/EditViewArchive.html index ee4d41e6..2d57f2b9 100644 --- a/modules/Emails/EditViewArchive.html +++ b/modules/Emails/EditViewArchive.html @@ -121,7 +121,7 @@ -   +    {CHANGE_PARENT_BUTTON} diff --git a/modules/Emails/Email.php b/modules/Emails/Email.php index 27cb6cf3..6c432ece 100644 --- a/modules/Emails/Email.php +++ b/modules/Emails/Email.php @@ -111,6 +111,7 @@ class Email extends SugarBean { var $new_schema = true; var $table_name = 'emails'; var $module_dir = 'Emails'; + var $module_name = 'Emails'; var $object_name = 'Email'; var $db; @@ -1047,9 +1048,6 @@ class Email extends SugarBean { if($this->load_relationship($rel) ) { $this->$rel->delete($this->id, $this->fetched_row['parent_id']); } - } else { - // we already have this relationship, don't add it - return; } } $mod = strtolower($this->parent_type); @@ -1059,6 +1057,7 @@ class Email extends SugarBean { } } } + $GLOBALS['log']->debug('-------------------------------> Email save() done'); } /** diff --git a/modules/Emails/javascript/Email.js b/modules/Emails/javascript/Email.js index b401df7d..16feb2a8 100644 --- a/modules/Emails/javascript/Email.js +++ b/modules/Emails/javascript/Email.js @@ -462,7 +462,7 @@ function docUpload() { eai.setAttribute('value', lbl_remove); eai.onclick=function(){ var filename = this.parentNode.childNodes[4].value; - if(filename != null){ + if(filename){ var tiny = tinyMCE.getInstanceById('body_text'); var currValTiny = tiny.getContent(); while(currValTiny.indexOf(unescape(filename)) != -1){ diff --git a/modules/Emails/javascript/EmailUI.js b/modules/Emails/javascript/EmailUI.js index 599d38d6..1b92ac74 100644 --- a/modules/Emails/javascript/EmailUI.js +++ b/modules/Emails/javascript/EmailUI.js @@ -67,7 +67,7 @@ SE.accounts = { if(obi.match(/^(add|line|sendmail)+/)) { alert('Invalid Operation'); } else { - overlay(app_strings.LBL_EMAIL_DELETING_OUTBOUND, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_DELETING_OUTBOUND, app_strings.LBL_EMAIL_ONE_MOMENT); AjaxObject.startRequest(AjaxObject.accounts.callbackDeleteOutbound, urlStandard + "&emailUIAction=deleteOutbound&outbound_email=" + obi); } }, @@ -752,7 +752,7 @@ SE.accounts = { deleteIeAccount : function(IeAccountID,IeGroupID) { if(confirm(app_strings.LBL_EMAIL_IE_DELETE_CONFIRM)) { - overlay(app_strings.LBL_EMAIL_IE_DELETE, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_IE_DELETE, app_strings.LBL_EMAIL_ONE_MOMENT); AjaxObject.target = 'frameFlex'; AjaxObject.startRequest(callbackAccountDelete, urlStandard + '&emailUIAction=deleteIeAccount&ie_id='+IeAccountID+'&group_id='+IeGroupID); @@ -790,7 +790,7 @@ SE.accounts = { } } if(isError) { - overlay(mod_strings.ERR_MISSING_REQUIRED_FIELDS, errorMessage, 'alert'); + SUGAR.showMessageBox(mod_strings.ERR_MISSING_REQUIRED_FIELDS, errorMessage, 'alert'); return false; } else { return true; @@ -803,19 +803,19 @@ SE.accounts = { var fromAddress = document.getElementById("outboundtest_from_address").value; if (trim(fromAddress) == "") { errorMessage += app_strings.LBL_EMAIL_SETTINGS_FROM_TO_EMAIL_ADDR + "
    "; - overlay(mod_strings.ERR_MISSING_REQUIRED_FIELDS, errorMessage, 'alert'); + SUGAR.showMessageBox(mod_strings.ERR_MISSING_REQUIRED_FIELDS, errorMessage, 'alert'); return false; } else if (!isValidEmail(fromAddress)) { errorMessage += app_strings.LBL_EMAIL_SETTINGS_FROM_TO_EMAIL_ADDR + "
    "; - overlay(mod_strings.ERR_INVALID_REQUIRED_FIELDS, errorMessage, 'alert'); + SUGAR.showMessageBox(mod_strings.ERR_INVALID_REQUIRED_FIELDS, errorMessage, 'alert'); return false; } //Hide the dialogue and show an in progress indicator. SE.accounts.testOutboundDialog.hide(); - overlay(app_strings.LBL_EMAIL_PERFORMING_TASK, app_strings.LBL_EMAIL_ONE_MOMENT, 'plain'); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_PERFORMING_TASK, app_strings.LBL_EMAIL_ONE_MOMENT, 'plain'); //If the outbound mail type is a system override we need to re-enable the post fields otherwise //nothing is sent in the request. @@ -877,7 +877,7 @@ SE.accounts = { { document.getElementById('saveButton').disabled = true; - overlay(app_strings.LBL_EMAIL_IE_SAVE, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_IE_SAVE, app_strings.LBL_EMAIL_ONE_MOMENT); var formObject = document.getElementById('ieAccount'); YAHOO.util.Connect.setForm(formObject); @@ -1014,7 +1014,7 @@ SE.accounts = { if(ieId == '') return; - overlay(app_strings.LBL_EMAIL_SETTINGS_RETRIEVING_ACCOUNT, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_SETTINGS_RETRIEVING_ACCOUNT, app_strings.LBL_EMAIL_ONE_MOMENT); var query = "&emailUIAction=getIeAccount&ieId=" + ieId; AjaxObject.startRequest(callbackIeAccountRetrieve, urlStandard + query); @@ -1071,7 +1071,7 @@ SE.accounts = { * Async call to rebuild the folder list. After a folder delete or account delete */ rebuildFolderList : function() { - overlay(app_strings.LBL_EMAIL_REBUILDING_FOLDERS, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_REBUILDING_FOLDERS, app_strings.LBL_EMAIL_ONE_MOMENT); AjaxObject.startRequest(callbackFolders, urlStandard + '&emailUIAction=rebuildFolders'); }, @@ -1276,7 +1276,7 @@ SE.contextMenus = { } // for } - overlay(app_strings.LBL_EMAIL_PERFORMING_TASK, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_PERFORMING_TASK, app_strings.LBL_EMAIL_ONE_MOMENT); AjaxObject.startRequest(callbackContextmenus.markUnread, urlStandard + '&emailUIAction=markEmail&type=' + type + '&uids=' + ser + "&ieId=" + ieId + "&folder=" + folder); }, @@ -1285,7 +1285,7 @@ SE.contextMenus = { */ markEmailCleanup : function() { SE.accounts.renderTree(); - hideOverlay(); + SUGAR.hideMessageBox(); SE.listView.refreshGrid(); }, @@ -1338,7 +1338,7 @@ SE.contextMenus = { * */ showEmailDetailViewInPopup : function(ieId,uid, folder) { - overlay(app_strings.LBL_EMAIL_RETRIEVING_RECORD, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_RETRIEVING_RECORD, app_strings.LBL_EMAIL_ONE_MOMENT); AjaxObject.startRequest(callbackEmailDetailView, urlStandard + '&emailUIAction=getEmail2DetailView&uid=' + uid + "&ieId=" + ieId + "&mbox=" + folder + "&record=" + uid); }, @@ -1595,7 +1595,7 @@ SE.detailView = { * @param */ emailDelete : function(ieId, uid, mbox) { - overlay(app_strings.LBL_EMAIL_DELETING_MESSAGE, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_DELETING_MESSAGE, app_strings.LBL_EMAIL_ONE_MOMENT); AjaxObject.startRequest(callbackContextmenus.markUnread, urlStandard + '&emailUIAction=markEmail&type=deleted&uids=' + uid + "&ieId=" + ieId + "&folder=" + mbox); }, @@ -1619,7 +1619,7 @@ SE.detailView = { importEmail : function(ieId, uid, mbox) { SE.util.clearHiddenFieldValues('emailUIForm'); - overlay(app_strings.LBL_EMAIL_IMPORTING_EMAIL, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_IMPORTING_EMAIL, app_strings.LBL_EMAIL_ONE_MOMENT); var vars = "&ieId=" + ieId + "&uid=" + uid + "&mbox=" + mbox; AjaxObject.target = ''; @@ -1711,7 +1711,7 @@ SE.detailView = { * Retrieves multiple emails for DetailView */ populateDetailViewMultiple : function(uids, mbox, ieId, setRead) { - overlay(app_strings.LBL_EMAIL_RETRIEVING_MESSAGE, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_RETRIEVING_MESSAGE, app_strings.LBL_EMAIL_ONE_MOMENT); SE.util.clearHiddenFieldValues('emailUIForm'); var mboxStr = new String(mbox); @@ -1777,7 +1777,7 @@ SE.detailView = { } formObject.action.value = 'EmailUIAjax'; YAHOO.util.Connect.setForm(formObject); - overlay('Saving', app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox('Saving', app_strings.LBL_EMAIL_ONE_MOMENT); AjaxObject.startRequest(theCallback, "to_pdf=true&emailUIAction=saveQuickCreate&qcmodule=" + qcd.qcmodule + '&uid=' + qcd.uid + accountType + '&mbox=' + qcd.mbox); } @@ -2017,7 +2017,7 @@ SE.folders = { // don't stomp an on-going request if(AjaxObject.currentRequestObject.conn == null) { if(showOverlay) { - overlay(app_strings.LBL_EMAIL_CHECKING_NEW, + SUGAR.showMessageBox(app_strings.LBL_EMAIL_CHECKING_NEW, app_strings.LBL_EMAIL_ONE_MOMENT + "
     
    " + app_strings.LBL_EMAIL_CHECKING_DESC + ""); } AjaxObject.startRequest(AjaxObject.folders.callback.checkMail, urlStandard + '&emailUIAction=checkEmail&all=true'); @@ -2033,13 +2033,13 @@ SE.folders = { startEmailAccountCheck : function() { // don't do two checks at the same time if(!AjaxObject.requestInProgress()) { - overlay(app_strings.LBL_EMAIL_ONE_MOMENT, app_strings.LBL_EMAIL_CHECKING_NEW, 'progress'); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_ONE_MOMENT, app_strings.LBL_EMAIL_CHECKING_NEW, 'progress'); SE.accounts.ieIds = SE.folders.getIeIds(); if (SE.accounts.ieIds.length > 0) { AjaxObject.startRequest(AjaxObject.accounts.callbackCheckMailProgress, urlStandard + '&emailUIAction=checkEmailProgress&ieId=' + SE.accounts.ieIds[0] + "¤tCount=0"); } else { - hideOverlay(); + SUGAR.hideMessageBox(); } } else { // wait 5 secs before trying again. @@ -2061,7 +2061,7 @@ SE.folders = { if (node && !synch) { mbox = node.data.mbox; } // if - overlay(app_strings.LBL_EMAIL_CHECKING_NEW, app_strings.LBL_EMAIL_CHECKING_DESC, 'progress'); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_CHECKING_NEW, app_strings.LBL_EMAIL_CHECKING_DESC, 'progress'); SE.accounts.ieIds = [ieId]; AjaxObject.startRequest(AjaxObject.accounts.callbackCheckMailProgress, urlStandard + '&emailUIAction=checkEmailProgress&mbox=' + mbox + '&ieId=' + ieId + "¤tCount=0&synch=" + synch); @@ -2073,7 +2073,7 @@ SE.folders = { */ emptyTrash : function() { SE.contextMenus.frameFoldersContextMenu.hide(); - overlay(app_strings.LBL_EMAIL_EMPTYING_TRASH, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_EMPTYING_TRASH, app_strings.LBL_EMAIL_ONE_MOMENT); AjaxObject.startRequest(callbackEmptyTrash, urlStandard + '&emailUIAction=emptyTrash'); }, @@ -2082,7 +2082,7 @@ SE.folders = { */ clearCacheFiles : function(ieId) { SE.contextMenus.frameFoldersContextMenu.hide(); - overlay(app_strings.LBL_EMAIL_CLEARING_CACHE_FILES, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_CLEARING_CACHE_FILES, app_strings.LBL_EMAIL_ONE_MOMENT); AjaxObject.startRequest(callbackClearCacheFiles, urlStandard + '&ieId=' + ieId + '&emailUIAction=clearInboundAccountCache'); }, @@ -2136,7 +2136,7 @@ SE.folders = { }, rebuildFolders : function(silent) { - if (!silent) overlay(app_strings.LBL_EMAIL_REBUILDING_FOLDERS, app_strings.LBL_EMAIL_ONE_MOMENT); + if (!silent) SUGAR.showMessageBox(app_strings.LBL_EMAIL_REBUILDING_FOLDERS, app_strings.LBL_EMAIL_ONE_MOMENT); AjaxObject.startRequest(callbackFolders, urlStandard + '&emailUIAction=getAllFoldersTree'); }, @@ -2186,7 +2186,7 @@ SE.folders = { * @param object SELECT list object */ setFolderSelection : function() { - overlay(app_strings.LBL_EMAIL_REBUILDING_FOLDERS, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_REBUILDING_FOLDERS, app_strings.LBL_EMAIL_ONE_MOMENT); var a_rs = SE.accounts.inboundAccountsSettingsTable.getRecordSet().getRecords(); var a_active_accnts = ""; @@ -2390,7 +2390,7 @@ SE.folders = { var node = SE.clickedFolderNode; if(node != null && node.data) { - overlay(app_strings.LBL_EMAIL_FOLDERS_ADD_DIALOG_TITLE, + SUGAR.showMessageBox(app_strings.LBL_EMAIL_FOLDERS_ADD_DIALOG_TITLE, app_strings.LBL_EMAIL_SETTINGS_NAME, 'prompt', {fn:SE.folders.folderAddXmlCall, beforeShow: SE.folders.folderAddRegisterEnter, beforeHide: SE.folders.folderRemoveRegisterEnter}); } else { @@ -2462,7 +2462,7 @@ SE.folders = { if(parentNode != null && parentNode.data) { if(parentNode.data.mbox == 'INBOX' || parentNode.data.id == 'Home') { - overlay(app_strings.LBL_EMAIL_ERROR_GENERAL_TITLE, app_strings.LBL_EMAIL_FOLDERS_CHANGE_HOME, 'alert'); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_ERROR_GENERAL_TITLE, app_strings.LBL_EMAIL_FOLDERS_CHANGE_HOME, 'alert'); return; } @@ -2475,7 +2475,7 @@ SE.folders = { // delete a sugar folder post = "&folderType=sugar&folder_id=" + parentNode.data.id; } - overlay("Deleting folder", app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox("Deleting folder", app_strings.LBL_EMAIL_ONE_MOMENT); AjaxObject.startRequest(callbackFolderDelete, urlStandard + '&emailUIAction=deleteFolder' + post); } else { alert(app_strings.LBL_EMAIL_ERROR_CANNOT_FIND_NODE); @@ -2493,11 +2493,11 @@ SE.folders = { if(node != null) { if(node.id == 'Home' || !node.data || node.data.mbox == 'INBOX') { - overlay(app_strings.LBL_EMAIL_ERROR_GENERAL_TITLE, app_strings.LBL_EMAIL_FOLDERS_CHANGE_HOME, 'alert'); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_ERROR_GENERAL_TITLE, app_strings.LBL_EMAIL_FOLDERS_CHANGE_HOME, 'alert'); return; } - overlay(app_strings.LBL_EMAIL_FOLDERS_RENAME_DIALOG_TITLE + " - " + node.data.text, + SUGAR.showMessageBox(app_strings.LBL_EMAIL_FOLDERS_RENAME_DIALOG_TITLE + " - " + node.data.text, app_strings.LBL_EMAIL_SETTINGS_NAME, 'prompt', {fn:SE.folders.submitFolderRename, beforeShow: SE.folders.folderAddRegisterEnter, beforeHide: SE.folders.folderRemoveRegisterEnter}); @@ -2733,7 +2733,7 @@ SE.folders = { return true; } if(SE.folders.isUniqueFolderName(newName)) { - overlay(app_strings.LBL_EMAIL_MENU_RENAMING_FOLDER, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_MENU_RENAMING_FOLDER, app_strings.LBL_EMAIL_ONE_MOMENT); if (node.data.ieId == "folder") { //Sugar Folder AjaxObject.startRequest(callbackFolderRename, urlStandard + "&emailUIAction=renameFolder&folderId=" + node.data.id + "&newFolderName=" + newName); @@ -2764,7 +2764,7 @@ SE.folders = { */ synchronizeAccounts : function() { if(confirm(app_strings.LBL_EMAIL_SETTINGS_FULL_SYNC_WARN)) { - overlayModal(app_strings.LBL_EMAIL_SETTINGS_FULL_SYNC, app_strings.LBL_EMAIL_ONE_MOMENT + "
     
    " + app_strings.LBL_EMAIL_COFFEE_BREAK); + SUGAR.showMessageBoxModal(app_strings.LBL_EMAIL_SETTINGS_FULL_SYNC, app_strings.LBL_EMAIL_ONE_MOMENT + "
     
    " + app_strings.LBL_EMAIL_COFFEE_BREAK); AjaxObject.startRequest(callbackFullSync, urlStandard + '&emailUIAction=synchronizeEmail'); } }, @@ -2775,7 +2775,7 @@ SE.folders = { * @param string type of Folder selection */ updateSubscriptions : function() { - overlay(app_strings.LBL_EMAIL_REBUILDING_FOLDERS, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_REBUILDING_FOLDERS, app_strings.LBL_EMAIL_ONE_MOMENT); var active = ""; @@ -2954,9 +2954,6 @@ SE.listView = { var total = (typeof(ds.totalLength) != "undefined") ? " (" + ds.totalLength +" " + app_strings.LBL_EMAIL_MESSAGES +") " : ""; SE.listViewLayout.setTitle(acctMbox + total);// + toggleRead + manualFit); - - // 4/20/2007 added to hide overlay after search - //hideOverlay(); if (ds.reader.xmlData.getElementsByTagName('UnreadCount').length > 0){ var unread = ds.reader.xmlData.getElementsByTagName('UnreadCount')[0].childNodes[0].data; var node = SE.folders.getNodeFromIeIdAndMailbox(ds.baseParams.ieId, ds.baseParams.mbox); @@ -3028,9 +3025,9 @@ SE.listView = { */ moveEmails : function(sourceIeId, sourceFolder, destinationIeId, destinationFolder, emailUids, selectedRows) { if(destinationIeId != 'folder' && sourceIeId != destinationIeId) { - overlay(app_strings.LBL_EMAIL_ERROR_MOVE_TITLE, app_strings.LBL_EMAIL_ERROR_MOVE); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_ERROR_MOVE_TITLE, app_strings.LBL_EMAIL_ERROR_MOVE); } else { - overlay("Moving Email(s)", app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox("Moving Email(s)", app_strings.LBL_EMAIL_ONE_MOMENT); // remove rows from visibility for(row in selectedRows) { //SE.grid.getStore().remove(row); @@ -3122,7 +3119,7 @@ SE.listView = { } // event wrapped call - need FQ - overlay(app_strings.LBL_EMAIL_PERFORMING_TASK, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_PERFORMING_TASK, app_strings.LBL_EMAIL_ONE_MOMENT); SE.listView.moveEmails(sourceIeId, sourceFolder, destinationIeId, destinationFolder, emailUids, e.selModel.selectedRows); break; } @@ -3240,7 +3237,6 @@ SE.search = { var safeCriteria = escape(searchCriteria); var accountListSearch = document.getElementById('accountListSearch'); - //overlay(app_strings.LBL_EMAIL_SEARCHING,app_strings.LBL_EMAIL_ONE_MOMENT); SE.grid.getStore().baseParams['emailUIAction'] = 'search'; SE.grid.getStore().baseParams['mbox'] = app_strings.LBL_EMAIL_SEARCH_RESULTS_TITLE; @@ -3374,7 +3370,7 @@ SE.settings = { deleteSignature : function() { if(confirm(app_strings.LBL_EMAIL_CONFIRM_DELETE_SIGNATURE)) { - overlay(app_strings.LBL_EMAIL_IE_DELETE_SIGNATURE, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_IE_DELETE_SIGNATURE, app_strings.LBL_EMAIL_ONE_MOMENT); var singature_id = document.getElementById('signature_id').value; AjaxObject.startRequest(callbackDeleteSignature, urlStandard + '&emailUIAction=deleteSignature&id=' + singature_id); } // if diff --git a/modules/Emails/javascript/EmailUICompose.js b/modules/Emails/javascript/EmailUICompose.js index 2a3e6478..a92108c8 100644 --- a/modules/Emails/javascript/EmailUICompose.js +++ b/modules/Emails/javascript/EmailUICompose.js @@ -966,7 +966,6 @@ SE.composeLayout = { SE.composeLayout.composeTemplate.exec({ 'app_strings':app_strings, 'mod_strings':mod_strings, - 'theme': theme, 'linkbeans_options' : linkBeans, 'idx' : SE.composeLayout.currentInstanceId }) @@ -1119,7 +1118,7 @@ SE.composeLayout = { var instance = SE.util.getTiny(SE.tinyInstances.currentHtmleditor); if(typeof(instance) == 'undefined' || (typeof(SE.composeLayout.loadedTinyInstances[idx]) != 'undefined' && SE.composeLayout.loadedTinyInstances[idx] == false)) { - setTimeout("SE.composeLayout.resizeEditorSetSignature(" + idx + ",'"+isReplyForward+"');",500); + setTimeout("SE.composeLayout.resizeEditorSetSignature(" + idx + ",'"+setSignature+"');",500); return; } @@ -1759,7 +1758,7 @@ SE.composeLayout = { if( typeof(SUGAR.email2.composeLayout.outboundAccountErrors[obAccountID]) != 'undefined' ) { - overlay(app_strings.LBL_EMAIL_ERROR_DESC, SUGAR.email2.composeLayout.outboundAccountErrors[obAccountID], 'alert'); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_ERROR_DESC, SUGAR.email2.composeLayout.outboundAccountErrors[obAccountID], 'alert'); return false; } @@ -1827,7 +1826,7 @@ SE.composeLayout = { SE.util.clearHiddenFieldValues('emailCompose' + idx); document.getElementById('data_parent_id' + idx).value = parentIdValue; var title = (isDraft) ? app_strings.LBL_EMAIL_SAVE_DRAFT : app_strings.LBL_EMAIL_SENDING_EMAIL; - overlay(title, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(title, app_strings.LBL_EMAIL_ONE_MOMENT); html = html.replace(/</ig, "sugarLessThan"); html = html.replace(/>/ig, "sugarGreaterThan"); @@ -2211,7 +2210,7 @@ SE.composeLayout = { */ replyForwardEmailStage2 : function() { SE.util.clearHiddenFieldValues('emailUIForm'); - overlay(app_strings.LBL_EMAIL_RETRIEVING_MESSAGE, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_RETRIEVING_MESSAGE, app_strings.LBL_EMAIL_ONE_MOMENT); var ieId = SE.composeLayout.replyForwardObj.ieId; var uid = SE.composeLayout.replyForwardObj.uid; diff --git a/modules/Emails/javascript/EmailUIShared.js b/modules/Emails/javascript/EmailUIShared.js index 47685d45..843209af 100644 --- a/modules/Emails/javascript/EmailUIShared.js +++ b/modules/Emails/javascript/EmailUIShared.js @@ -68,13 +68,18 @@ SUGAR.email2 = { } }; + /** * Shows overlay progress message */ -function overlayModal(title, body) { - overlay(title, body); + +//overlayModal +SUGAR.showMessageBoxModal = function(title, body) { + SUGAR.showMessageBox(title, body); } -function overlay(reqtitle, body, type, additconfig) { + +//overlay +SUGAR.showMessageBox = function(reqtitle, body, type, additconfig) { var config = { }; if (typeof(additconfig) == "object") { var config = additconfig; @@ -83,8 +88,9 @@ function overlay(reqtitle, body, type, additconfig) { config.title = reqtitle; config.msg = body; YAHOO.SUGAR.MessageBox.show(config); -}; +} -function hideOverlay() { +//hideOverlay +SUGAR.hideMessageBox = function() { YAHOO.SUGAR.MessageBox.hide(); }; diff --git a/modules/Emails/javascript/ajax.js b/modules/Emails/javascript/ajax.js index 5da10881..8802fc4e 100644 --- a/modules/Emails/javascript/ajax.js +++ b/modules/Emails/javascript/ajax.js @@ -83,11 +83,11 @@ var AjaxObject = { if (typeof(ret.errorArray)=='object' && ret.errorArray instanceof Array && ret.errorArray.length > 0){ //add error messages for display for(i in ret.errorArray) - overlay(app_strings.LBL_EMAIL_ERROR_DESC, ret.errorArray[i], 'alert'); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_ERROR_DESC, ret.errorArray[i], 'alert'); }else if (typeof(ret.errorArray)=='object' && ret.errorArray!=null && ret.errorArray!='' ) { //if error element is returning an object, and the object value is not empty or null, then display error message for(i in ret.errorArray) - overlay(app_strings.LBL_EMAIL_ERROR_DESC, ret.errorArray[i], 'alert'); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_ERROR_DESC, ret.errorArray[i], 'alert'); } //YUI bug with IE6 - Wont restore visibility property for nested select elements. @@ -101,8 +101,8 @@ var AjaxObject = { handleDeleteSignature : function(o) { - hideOverlay(); - var ret = YAHOO.lang.JSON.parse(o.responseText); + SUGAR.hideMessageBox(); + var ret = YAHOO.lang.JSON.parse(o.responseText); SUGAR.email2.composeLayout.signatures = ret.signatures; var field = document.getElementById('signature_id'); SUGAR.email2.util.emptySelectOptions(field); @@ -118,7 +118,7 @@ var AjaxObject = { */ handleDeleteReturn : function(o) { // force refresh ListView - hideOverlay(); + SUGAR.hideMessageBox(); if(document.getElementById('focusEmailMbox')) { YAHOO.namespace('frameFolders').selectednode = SUGAR.email2.folders.getNodeFromMboxPath(document.getElementById('focusEmailMbox').innerHTML); } @@ -131,7 +131,7 @@ var AjaxObject = { */ handleFailure : function(o) { // Failure handler - overlay('Exception occurred...', o.statusText, 'alert'); + SUGAR.showMessageBox('Exception occurred...', o.statusText, 'alert'); if(document.getElementById('saveButton')) { document.getElementById('saveButton').disabled = false; } @@ -196,14 +196,13 @@ var AjaxObject = { */ handleSuccess : function(o) { document.getElementById(this.target).innerHTML = o.responseText; - hideOverlay(); + SUGAR.hideMessageBox(); }, /** */ ieDeleteSuccess : function(o) { - hideOverlay(); - + SUGAR.hideMessageBox(); SUGAR.email2.accounts.refreshInboundAccountTable(); alert(app_strings.LBL_EMAIL_IE_DELETE_SUCCESSFUL); SUGAR.email2.accounts.rebuildFolderList(); @@ -216,7 +215,7 @@ var AjaxObject = { var a = YAHOO.lang.JSON.parse(o.responseText); if (a) { if(a.error) { - overlay(app_strings.LBL_EMAIL_ERROR_DESC, app_strings.LBL_EMAIL_ERROR_CHECK_IE_SETTINGS, 'alert'); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_ERROR_DESC, app_strings.LBL_EMAIL_ERROR_CHECK_IE_SETTINGS, 'alert'); SUGAR.email2.accounts.ieAccountError(SUGAR.email2.accounts.errorStyle); } else { resp = YAHOO.lang.JSON.parse(o.responseText); @@ -226,8 +225,8 @@ var AjaxObject = { SUGAR.email2.accounts.inboundAccountEditDialog.hide(); } } else { - hideOverlay(); - overlay(app_strings.LBL_EMAIL_ERROR_DESC, app_strings.LBL_EMAIL_ERROR_SAVE_ACCOUNT, 'alert'); + SUGAR.hideMessageBox(); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_ERROR_DESC, app_strings.LBL_EMAIL_ERROR_SAVE_ACCOUNT, 'alert'); } }, @@ -254,8 +253,8 @@ var AjaxObject = { markEmailCleanup : function(o) { var ret = YAHOO.lang.JSON.parse(o.responseText); if (!ret['status']) { - hideOverlay(); - overlay(app_strings.LBL_EMAIL_ERROR_DESC, ret['message'], 'alert'); + SUGAR.hideMessageBox(); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_ERROR_DESC, ret['message'], 'alert'); } else { SUGAR.email2.contextMenus.markEmailCleanup(); } // else @@ -301,7 +300,7 @@ var AjaxObject = { */ sendEmailCleanUp : function(o) { var ret; - hideOverlay(); + SUGAR.hideMessageBox(); try { ret = YAHOO.lang.JSON.parse(o.responseText); @@ -309,11 +308,11 @@ var AjaxObject = { //SUGAR.email2.addressBook.showContactMatches(ret.possibleMatches); } catch(err) { if (o.responseText) { - overlay(mod_strings.LBL_SEND_EMAIL_FAIL_TITLE, o.responseText, 'alert'); + SUGAR.showMessageBox(mod_strings.LBL_SEND_EMAIL_FAIL_TITLE, o.responseText, 'alert'); } // Else we have an error here. - } - + } + if (typeof(SE.grid) != 'undefined') SE.listView.refreshGrid(); //Disabled while address book is disabled @@ -332,8 +331,8 @@ var AjaxObject = { }, ieSendSuccess : function(o) { - hideOverlay(); - overlay(app_strings.LBL_EMAIL_TEST_OUTBOUND_SETTINGS_SENT, app_strings.LBL_EMAIL_TEST_NOTIFICATION_SENT, 'plain'); + SUGAR.hideMessageBox(); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_TEST_OUTBOUND_SETTINGS_SENT, app_strings.LBL_EMAIL_TEST_NOTIFICATION_SENT, 'plain'); }, /** @@ -376,7 +375,7 @@ var AjaxObject = { updateFolderSubscriptions : function() { SUGAR.email2.folders.lazyLoadSettings(); // refresh view in Settings overlay SUGAR.email2.folders.setSugarFolders(1000);// refresh view in TreeView - hideOverlay(); + SUGAR.hideMessageBox(); }, /** @@ -484,15 +483,15 @@ AjaxObject.accounts = { { if(confirm(ret.error_message)) { - overlay(app_strings.LBL_EMAIL_IE_DELETE, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_IE_DELETE, app_strings.LBL_EMAIL_ONE_MOMENT); AjaxObject.startRequest(AjaxObject.accounts.callbackDeleteOutbound, urlStandard + "&emailUIAction=deleteOutbound&confirm=true&outbound_email=" + ret.outbound_email); } else - hideOverlay(); + SUGAR.hideMessageBox(); } else { - hideOverlay(); + SUGAR.hideMessageBox(); SUGAR.email2.accounts.refreshOuboundAccountTable(); } }, @@ -513,8 +512,8 @@ AjaxObject.accounts = { var done = false; if (typeof(o.responseText) == 'undefined' || o.responseText == "" || ret == false) { - hideOverlay(); - overlay(app_strings.LBL_EMAIL_ERROR_DESC, app_strings.LBL_EMAIL_ERROR_TIMEOUT, 'alert'); + SUGAR.hideMessageBox(); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_ERROR_DESC, app_strings.LBL_EMAIL_ERROR_TIMEOUT, 'alert'); SUGAR.email2.accounts.totalMsgCount = -1; //SUGAR.email2.folders.rebuildFolders(); done = true; @@ -548,15 +547,15 @@ AjaxObject.accounts = { } else if (SUGAR.email2.accounts.totalMsgCount < 0 && ret.totalcount) { SUGAR.email2.accounts.totalMsgCount = ret.totalcount; } else { - hideOverlay(); - overlay(app_strings.LBL_EMAIL_ERROR_DESC, app_strings.LBL_EMAIL_ERROR_TIMEOUT, 'alert'); + SUGAR.hideMessageBox(); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_ERROR_DESC, app_strings.LBL_EMAIL_ERROR_TIMEOUT, 'alert'); SUGAR.email2.accounts.totalMsgCount = -1; done = true; } if (done) { SUGAR.email2.accounts.totalMsgCount = -1; - hideOverlay(); + SUGAR.hideMessageBox(); SUGAR.email2.folders.rebuildFolders(); SE.listView.refreshGrid(); } else if (SUGAR.email2.accounts.totalMsgCount < 0) { @@ -580,19 +579,19 @@ AjaxObject.accounts = { /////////////////////////////////////////////////////////////////////////////// //// COMPOSE LAYOUT AjaxObject.composeLayout = { - /** - * Populates the record id - */ + /** + * Populates the record id + */ saveDraftCleanup : function(o) { var ret; - hideOverlay(); + SUGAR.hideMessageBox(); try { ret = YAHOO.lang.JSON.parse(o.responseText); SUGAR.email2.composeLayout.forceCloseCompose(ret.composeLayoutId); } catch(err) { if (o.responseText) { - overlay(mod_strings.LBL_ERROR_SAVING_DRAFT, o.responseText, 'alert'); + SUGAR.showMessageBox(mod_strings.LBL_ERROR_SAVING_DRAFT, o.responseText, 'alert'); } } } @@ -743,14 +742,14 @@ AjaxObject.detailView = { }, saveQuickCreateForm : function(o) { - hideOverlay(); + SUGAR.hideMessageBox(); SUGAR.email2.detailView.quickCreateDialog.hide(); validate['EditView'] = [ ]; }, saveQuickCreateFormAndReply : function(o) { - hideOverlay(); - var ret = YAHOO.lang.JSON.parse(o.responseText); + SUGAR.hideMessageBox(); + var ret = YAHOO.lang.JSON.parse(o.responseText); SUGAR.email2.detailView.quickCreateDialog.hide(); var qcd = SUGAR.email2.detailView.quickCreateDialog; var type = (qcd.qcmodule == 'Cases') ? 'replyCase' : 'reply'; @@ -765,7 +764,7 @@ AjaxObject.detailView = { }, saveQuickCreateFormAndAddToAddressBook : function(o) { - hideOverlay(); + SUGAR.hideMessageBox(); SUGAR.email2.detailView.quickCreateDialog.hide(); SUGAR.email2.complexLayout.findPanel('contactsTab').show(); validate['EditView'] = [ ]; @@ -803,7 +802,7 @@ AjaxObject.detailView = { var mbox = data.mbox; AjaxObject.startRequest(callbackAssignmentAction, urlStandard + '&emailUIAction=' + "doAssignmentAssign&uids=" + uids + "&ieId=" + ieid + "&folder=" + mbox + "&distribute_method=" + dist + "&users=" +assign_user_id + get); SUGAR.email2.contextMenus.assignToDialogue.hide(); - overlay('Assignment', app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox('Assignment', app_strings.LBL_EMAIL_ONE_MOMENT); }, @@ -815,14 +814,14 @@ AjaxObject.detailView = { var mbox = row.data.mbox; AjaxObject.startRequest(callbackAssignmentAction, urlStandard + '&emailUIAction=' + "doAssignmentDelete&uids=" + uids + "&ieId=" + ieId + "&folder=" + mbox); SUGAR.email2.contextMenus.assignmentDialog.hide(); - overlay(app_strings.LBL_EMAIL_PERFORMING_TASK, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_PERFORMING_TASK, app_strings.LBL_EMAIL_ONE_MOMENT); // AJAX Call }, showEmailDetailView : function(o) { - hideOverlay(); + SUGAR.hideMessageBox(); var SED = SUGAR.email2.detailView; var ret = YAHOO.lang.JSON.parse(o.responseText); @@ -858,7 +857,7 @@ AjaxObject.detailView = { showAssignmentDialogWithData : function(o) { var SEC = SUGAR.email2.contextMenus; - hideOverlay(); + SUGAR.hideMessageBox(); var ret = YAHOO.lang.JSON.parse(o.responseText); if (!SEC.assignmentDialog) { SEC.assignmentDialog = new YAHOO.widget.Dialog("assignmentDialog", { @@ -889,7 +888,7 @@ AjaxObject.detailView = { var ret = YAHOO.lang.JSON.parse(o.responseText); document.getElementById('quickCreateContent').innerHTML = ""; - hideOverlay(); + SUGAR.hideMessageBox(); if (!ret) { return false; } @@ -975,9 +974,9 @@ AjaxObject.detailView = { action = action + '&emailUids='; } if (action.search(/importEmail/) != -1) { - overlay(app_strings.LBL_EMAIL_IMPORTING_EMAIL, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_IMPORTING_EMAIL, app_strings.LBL_EMAIL_ONE_MOMENT); } else { - overlay("Moving Email(s)", app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox("Moving Email(s)", app_strings.LBL_EMAIL_ONE_MOMENT); } AjaxObject.startRequest(callbackStatusForImport, urlStandard + '&emailUIAction=' + action + uids + "&ieId=" + ieId + "&mbox=" + mbox + @@ -990,7 +989,7 @@ AjaxObject.detailView = { var SED = SUGAR.email2.detailView; var ret = YAHOO.lang.JSON.parse(o.responseText); document.getElementById('quickCreateContent').innerHTML = ""; - hideOverlay(); + SUGAR.hideMessageBox(); if (!ret) { return false; } @@ -1022,7 +1021,7 @@ AjaxObject.detailView = { } uids += emailUids[i]; } - overlay(app_strings.LBL_EMAIL_PERFORMING_TASK, app_strings.LBL_EMAIL_ONE_MOMENT); + SUGAR.showMessageBox(app_strings.LBL_EMAIL_PERFORMING_TASK, app_strings.LBL_EMAIL_ONE_MOMENT); AjaxObject.startRequest(callbackStatusForImport, urlStandard + '&emailUIAction=relateEmails&uid=' + uids + "&ieId=" + ieId + "&mbox=" + mbox + "&parent_id=" + parent_id + "&parent_type=" + parent_type); SED.relateDialog.hide(); @@ -1106,7 +1105,7 @@ AjaxObject.folders = { * check-mail post actions */ checkMailCleanup : function(o) { - hideOverlay(); + SUGAR.hideMessageBox(); AjaxObject.folders.rebuildFolders(o); // rebuild TreeView // refresh focus ListView @@ -1117,7 +1116,7 @@ AjaxObject.folders = { /** */ rebuildFolders : function(o) { - hideOverlay(); + SUGAR.hideMessageBox(); var data = YAHOO.lang.JSON.parse(o.responseText); @@ -1186,14 +1185,14 @@ scope : AjaxObject var callbackStatusForImport = { success : function (o) { - hideOverlay(); + SUGAR.hideMessageBox(); if (o.responseText != "") { var statusString = ""; var data = YAHOO.lang.JSON.parse(o.responseText); for(i=0; i'; } - overlay(SUGAR.language.get('Emails','LBL_IMPORT_STATUS_TITLE'), statusString, 'alert'); + SUGAR.showMessageBox(SUGAR.language.get('Emails','LBL_IMPORT_STATUS_TITLE'), statusString, 'alert'); } SE.listView.refreshGrid(); @@ -1217,8 +1216,8 @@ var callbackDelete = { }; var callbackEmailDetailMultiple = { success : function(o) { - hideOverlay(); - var retMulti = YAHOO.lang.JSON.parse(o.responseText); + SUGAR.hideMessageBox(); + var retMulti = YAHOO.lang.JSON.parse(o.responseText); var ret = new Object(); for(var i=0; i 'My Inbox', 'LBL_LIST_TITLE_MY_SENT' => 'My Sent Email', 'LBL_LIST_TITLE_MY_ARCHIVES'=> 'My Archived Emails', - 'LBL_ACTIVITIES_REPORTS' => 'Activities Report', + 'LBL_ACTIVITIES_REPORTS' => 'Activities Report', 'LNK_CHECK_MY_INBOX' => 'Check My Mail', 'LNK_DATE_SENT' => 'Date Sent', @@ -309,7 +309,7 @@ $mod_strings = array ( 'LBL_EMAILTEMPLATE_MESSAGE_WARNING_TITLE' => 'Warning', 'LBL_EMAILTEMPLATE_MESSAGE_MULTIPLE_RECIPIENTS' => 'Using an email template containing contact variables, such as the contact name, to send emails to multiple recipients may have unexpected results. It is recommended that you use an email campaign for mass mailings.', 'LBL_CHECK_ATTACHMENTS'=>'Please Check Attachments!', - 'LBL_HAS_ATTACHMENTS' => 'This email already has attachment(s). Would you like to keep the attachment(s)?', + 'LBL_HAS_ATTACHMENTS' => 'This email already has attachment(s). Would you like to keep the attachment(s)?', 'ERR_MISSING_REQUIRED_FIELDS' => 'Missing required field', 'ERR_INVALID_REQUIRED_FIELDS' => 'Invalid required field', 'LBL_FILTER_BY_RELATED_BEAN' => 'Only show recipients related to', @@ -345,7 +345,7 @@ $mod_strings = array ( 'LBL_CHECKING_ACCOUNT' => 'Checking Account', 'LBL_OF' => 'of', 'LBL_TEST_EMAIL_BODY' => 'This email was sent in order to test the outgoing mail server information provided in the Sugar application. A successful receipt of this email indicates that the outgoing mail server information provided is valid.', - + // for outbound email dialog 'LBL_MAIL_SMTPUSER' => 'Username', 'LBL_MAIL_SMTPPASS' => 'Password', @@ -368,4 +368,10 @@ $mod_strings = array ( 'LBL_EXCHANGE_SMTPUSER' => 'Exchange Username:', 'LBL_EXCHANGE_SMTPPORT' => 'Exchange Server Port:', 'LBL_EXCHANGE_SMTPSERVER' => 'Exchange Server:', -); + + // SNIP + 'LBL_CONTACTS_SUBPANEL_TITLE_SNIP' => 'Email Contacts', + 'LBL_EMAILS_MEETINGS_REL' => 'Emails:Meetings', + 'LBL_DATE_CREATED' => 'Date Created', + 'LBL_DATE_MODIFIED' => 'Date Modified', +); \ No newline at end of file diff --git a/modules/Emails/metadata/subpaneldefs.php b/modules/Emails/metadata/subpaneldefs.php index 6b4453d9..d9159dbb 100644 --- a/modules/Emails/metadata/subpaneldefs.php +++ b/modules/Emails/metadata/subpaneldefs.php @@ -41,11 +41,11 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. All Rights * Reserved. Contributor(s): ______________________________________.. *********************************************************************************/ - + $layout_defs['Emails'] = array( - // list of what Subpanels to show in the DetailView + // list of what Subpanels to show in the DetailView 'subpanel_setup' => array( 'notes' => array( 'order' => 5, @@ -56,7 +56,7 @@ $layout_defs['Emails'] = array( 'title_key' => 'LBL_NOTES_SUBPANEL_TITLE', 'module' => 'Notes', 'top_buttons' => array(), - ), + ), 'accounts' => array( 'order' => 10, 'module' => 'Accounts', @@ -126,7 +126,7 @@ $layout_defs['Emails'] = array( array('widget_class' => 'SubPanelTopCreateButton'), array('widget_class' => 'SubPanelTopSelectButton', 'mode'=>'MultiSelect') ), - ), + ), 'users' => array( 'order' => 50, 'module' => 'Users', @@ -171,5 +171,16 @@ $layout_defs['Emails'] = array( ), ), + 'meetings' => array( + 'order' => 1, + 'sort_order' => 'desc', + 'sort_by' => 'date_start', + 'title_key' => 'LBL_ACTIVITIES_SUBPANEL_TITLE', + 'module' => 'Meetings', + 'subpanel_name' => 'ForActivities', + 'get_subpanel_data' => 'meetings', + 'top_buttons' => array(), + ), + ), ); diff --git a/modules/Emails/templates/importRelate.tpl b/modules/Emails/templates/importRelate.tpl index f10ffb66..a10dcac3 100644 --- a/modules/Emails/templates/importRelate.tpl +++ b/modules/Emails/templates/importRelate.tpl @@ -92,7 +92,7 @@ function parent_typechangeQS() { - + diff --git a/modules/Emails/vardefs.php b/modules/Emails/vardefs.php index 26f0f8e7..cf690fc8 100644 --- a/modules/Emails/vardefs.php +++ b/modules/Emails/vardefs.php @@ -427,6 +427,16 @@ $dictionary['Email'] = array( 'bean_name' => 'Note', 'source' => 'non-db', ), + // SNIP + 'meetings' => array( + 'name' => 'meetings', + 'vname' => 'LBL_EMAILS_MEETINGS_REL', + 'type' => 'link', + 'relationship' => 'emails_meetings_rel', + 'module' => 'Meetings', + 'bean_name' => 'Meeting', + 'source' => 'non-db', + ), /* end relationship collections */ ), /* end fields() array */ @@ -467,6 +477,17 @@ $dictionary['Email'] = array( 'rhs_key' => 'parent_id', 'relationship_type' => 'one-to-many', ), + + // SNIP + 'emails_meetings_rel' => array( + 'lhs_module' => 'Emails', + 'lhs_table' => 'emails', + 'lhs_key' => 'id', + 'rhs_module' => 'Meetings', + 'rhs_table' => 'meetings', + 'rhs_key' => 'parent_id', + 'relationship_type' => 'one-to-many', + ), ), // end relationships 'indices' => array ( array( diff --git a/modules/Employees/views/view.list.php b/modules/Employees/views/view.list.php index e59402b3..7ba7f80b 100644 --- a/modules/Employees/views/view.list.php +++ b/modules/Employees/views/view.list.php @@ -49,7 +49,7 @@ class EmployeesViewList extends ViewList $this->lv->multiSelect = false; } } - + /** * Return the "breadcrumbs" to display at the top of the page * @@ -99,22 +99,26 @@ EOHTML; $theTitle .= "
    \n"; return $theTitle; - } - + } + public function listViewProcess() { $this->processSearchForm(); $this->lv->searchColumns = $this->searchForm->searchColumns; - + if(!$this->headers) return; if(empty($_REQUEST['search_form_only']) || $_REQUEST['search_form_only'] == false){ $this->lv->ss->assign("SEARCH",true); - + $tplFile = 'include/ListView/ListViewGeneric.tpl'; if (!$GLOBALS['current_user']->isAdminForModule('Users')){ $tplFile = 'include/ListView/ListViewNoMassUpdate.tpl'; } + if(!empty($this->where)){ + $this->where .= " AND "; + } + $this->where .= "(users.status != 'Reserved' or users.status is null) "; $this->lv->setup($this->seed, $tplFile, $this->where, $this->params); $savedSearchName = empty($_REQUEST['saved_search_select_name']) ? '' : (' - ' . $_REQUEST['saved_search_select_name']); echo $this->lv->display(); diff --git a/modules/Groups/Group.php b/modules/Groups/Group.php index e95d7a90..aff984be 100644 --- a/modules/Groups/Group.php +++ b/modules/Groups/Group.php @@ -43,7 +43,9 @@ class Group extends User { var $status = 'Group'; var $password = ''; // to disallow logins var $default_team; - + var $importable = false; + + function Group() { parent::User(); } diff --git a/modules/Home/About.php b/modules/Home/About.php index dd729dd8..39007277 100644 --- a/modules/Home/About.php +++ b/modules/Home/About.php @@ -180,7 +180,9 @@ echo $theProductName."™ ".$mod_strings['LBL_AND']." Sugar™ ".$mod_st
  • (http://cubiq.org/iscroll)
  • (http://thejit.org/)
  • (http://flashcanvas.net/)
  • - +
  • (http://framework.zend.com/)
  • +
  • (http://code.google.com/p/parsecsv-for-php/)
  • +
  • (http://phpjs.org/)
diff --git a/modules/Home/Dashlets/ChartsDashlet/ChartsDashletScript.tpl b/modules/Home/Dashlets/ChartsDashlet/ChartsDashletScript.tpl index 0aa436ac..d483c231 100644 --- a/modules/Home/Dashlets/ChartsDashlet/ChartsDashletScript.tpl +++ b/modules/Home/Dashlets/ChartsDashlet/ChartsDashletScript.tpl @@ -41,5 +41,10 @@ *} diff --git a/modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.php b/modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.php index 69529e0e..63a0c192 100644 --- a/modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.php +++ b/modules/Home/Dashlets/InvadersDashlet/InvadersDashlet.php @@ -107,6 +107,7 @@ class InvadersDashlet extends Dashlet { $ss->assign('titleLbl', $this->dashletStrings['LBL_CONFIGURE_TITLE']); $ss->assign('heightLbl', $this->dashletStrings['LBL_CONFIGURE_HEIGHT']); $ss->assign('saveLbl', $app_strings['LBL_SAVE_BUTTON_LABEL']); + $ss->assign('clearLbl', $app_strings['LBL_CLEAR_BUTTON_LABEL']); $ss->assign('title', $this->title); $ss->assign('height', $this->height); $ss->assign('id', $this->id); diff --git a/modules/Home/Dashlets/InvadersDashlet/InvadersOptions.tpl b/modules/Home/Dashlets/InvadersDashlet/InvadersOptions.tpl index edd8314e..f3694c81 100644 --- a/modules/Home/Dashlets/InvadersDashlet/InvadersOptions.tpl +++ b/modules/Home/Dashlets/InvadersDashlet/InvadersOptions.tpl @@ -64,6 +64,7 @@ + diff --git a/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.php b/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.php index 3b300f07..e7f4ce2b 100644 --- a/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.php +++ b/modules/Home/Dashlets/JotPadDashlet/JotPadDashlet.php @@ -119,6 +119,7 @@ class JotPadDashlet extends Dashlet { $ss->assign('titleLbl', $this->dashletStrings['LBL_CONFIGURE_TITLE']); $ss->assign('heightLbl', $this->dashletStrings['LBL_CONFIGURE_HEIGHT']); $ss->assign('saveLbl', $app_strings['LBL_SAVE_BUTTON_LABEL']); + $ss->assign('clearLbl', $app_strings['LBL_CLEAR_BUTTON_LABEL']); $ss->assign('title', $this->title); $ss->assign('height', $this->height); $ss->assign('id', $this->id); diff --git a/modules/Home/Dashlets/RSSDashlet/RSSDashlet.php b/modules/Home/Dashlets/RSSDashlet/RSSDashlet.php index eaa6308c..9a1121bc 100644 --- a/modules/Home/Dashlets/RSSDashlet/RSSDashlet.php +++ b/modules/Home/Dashlets/RSSDashlet/RSSDashlet.php @@ -105,6 +105,7 @@ class RSSDashlet extends Dashlet $ss->assign('heightLbl', $this->dashletStrings['LBL_CONFIGURE_HEIGHT']); $ss->assign('rssUrlLbl', $this->dashletStrings['LBL_CONFIGURE_RSSURL']); $ss->assign('saveLbl', $app_strings['LBL_SAVE_BUTTON_LABEL']); + $ss->assign('clearLbl', $app_strings['LBL_CLEAR_BUTTON_LABEL']); $ss->assign('title', $this->title); $ss->assign('height', $this->height); $ss->assign('url', $this->url); @@ -168,10 +169,14 @@ EOHTML; } else { foreach ( $rssdoc->entry as $entry ) { + $link = trim($entry->link); + if ( empty($link) ) { + $link = $entry->link[0]['href']; + } $output .= << -

{$entry->title}

+

{$entry->title}

{$entry->summary} diff --git a/modules/Home/Dashlets/RSSDashlet/RSSDashletOptions.tpl b/modules/Home/Dashlets/RSSDashlet/RSSDashletOptions.tpl index 1cad01de..c94734b0 100644 --- a/modules/Home/Dashlets/RSSDashlet/RSSDashletOptions.tpl +++ b/modules/Home/Dashlets/RSSDashlet/RSSDashletOptions.tpl @@ -81,6 +81,7 @@ + diff --git a/modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.php b/modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.php index 207f55e8..2e59e08b 100644 --- a/modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.php +++ b/modules/Home/Dashlets/SugarNewsDashlet/SugarNewsDashlet.php @@ -80,6 +80,7 @@ class SugarNewsDashlet extends Dashlet { $ss->assign('id', $this->id); $ss->assign('height', $this->height); $ss->assign('saveLBL', $app_strings['LBL_SAVE_BUTTON_LABEL']); + $ss->assign('clearLBL', $app_strings['LBL_CLEAR_BUTTON_LABEL']); if($this->isAutoRefreshable()) { $ss->assign('isRefreshable', true); $ss->assign('autoRefresh', $GLOBALS['app_strings']['LBL_DASHLET_CONFIGURE_AUTOREFRESH']); diff --git a/modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.php b/modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.php index 1ccb84b0..5287eb60 100644 --- a/modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.php +++ b/modules/Home/Dashlets/iFrameDashlet/iFrameDashlet.php @@ -93,6 +93,7 @@ class iFrameDashlet extends Dashlet { $ss->assign('id', $this->id); $ss->assign('height', $this->height); $ss->assign('saveLBL', $app_strings['LBL_SAVE_BUTTON_LABEL']); + $ss->assign('clearLBL', $app_strings['LBL_CLEAR_BUTTON_LABEL']); if($this->isAutoRefreshable()) { $ss->assign('isRefreshable', true); $ss->assign('autoRefresh', $GLOBALS['app_strings']['LBL_DASHLET_CONFIGURE_AUTOREFRESH']); diff --git a/modules/Home/Home.tpl b/modules/Home/Home.tpl index 24535502..aa61d3ab 100644 --- a/modules/Home/Home.tpl +++ b/modules/Home/Home.tpl @@ -201,9 +201,13 @@ SUGAR.mySugar.init = function () { SUGAR.mySugar.homepage_dd[j].afterEndDrag = SUGAR.mySugar.onDrop; j++; } - for(var wp = 0; wp <= {/literal}{$hiddenCounter}{literal}; wp++) { + {/literal} + {if $hiddenCounter > 0} + for(var wp = 0; wp <= {$hiddenCounter}; wp++) {ldelim} SUGAR.mySugar.homepage_dd[j++] = new ygDDListBoundary('page_'+activePage+'_hidden' + wp); - } + {rdelim} + {/if} + {literal} YAHOO.util.DDM.mode = 1; @@ -212,7 +216,7 @@ SUGAR.mySugar.init = function () { SUGAR.mySugar.renderChangeLayoutDialog(); } -YAHOO.util.Event.addListener(window, 'load', SUGAR.mySugar.init); +YAHOO.util.Event.addListener(window, 'load', SUGAR.mySugar.init); {/literal} diff --git a/modules/Home/SubpanelEdits.php b/modules/Home/SubpanelEdits.php new file mode 100644 index 00000000..ea7ec495 --- /dev/null +++ b/modules/Home/SubpanelEdits.php @@ -0,0 +1,76 @@ +viaAJAX = true; + } + else { // else use base class + require_once('include/EditView/EditViewQuickCreate.php'); + $editview = new EditViewQuickCreate($target_module, 'modules/' . $target_module . '/tpls/' . $tpl); + } + $editview->process(); + echo $editview->display(); +} else{ + + $subpanelView = 'modules/'. $target_module . '/views/view.subpanelquickedit.php'; + $view = (!empty($_REQUEST['target_view'])) ? $_REQUEST['target_view'] : 'QuickEdit'; + //Check if there is a custom override, then check for module override, finally use default (SubpanelQuickCreate) + if(file_exists('custom/' . $subpanelView)) { + require_once($subpanelView); + $subpanelClass = $target_module . 'SubpanelQuickEdit'; + $sqc = new $subpanelClass($target_module, $view); + } else if(file_exists($subpanelView)) { + require_once($subpanelView); + $subpanelClass = $target_module . 'SubpanelQuickEdit'; + $sqc = new $subpanelClass($target_module, $view); + } else { + require_once('include/EditView/SubpanelQuickEdit.php'); + $sqc = new SubpanelQuickEdit($target_module, $view); + } +} + +?> diff --git a/modules/Home/UnifiedSearchAdvanced.php b/modules/Home/UnifiedSearchAdvanced.php index 02e88243..ac14243b 100644 --- a/modules/Home/UnifiedSearchAdvanced.php +++ b/modules/Home/UnifiedSearchAdvanced.php @@ -374,7 +374,7 @@ class UnifiedSearchAdvanced { if (!isset($beanFiles[$beanName])) continue; - if($beanName == 'aCase') $beanName = 'Case'; + $beanName = BeanFactory::getObjectName($moduleName); $manager = new VardefManager ( ); $manager->loadVardef( $moduleName , $beanName ) ; diff --git a/modules/Home/UnifiedSearchAdvancedResults.tpl b/modules/Home/UnifiedSearchAdvancedResults.tpl index e30a1a7e..4ec7613d 100644 --- a/modules/Home/UnifiedSearchAdvancedResults.tpl +++ b/modules/Home/UnifiedSearchAdvancedResults.tpl @@ -63,19 +63,19 @@ {literal} var GlobalSearchOnDrag = function() { -console.log('dragging'); +//console.log('dragging'); } var GlobalSearchOnDrop = function() { -console.log('dropping'); +//console.log('dropping'); } {/literal} var GlobalSearchInit = function() {ldelim} -console.log('loading...'); +//console.log('loading...'); subpanel_dd = new Array(); {foreach from=$MODULE_RESULTS name=m key=module item=info} diff --git a/modules/Home/index.php b/modules/Home/index.php index 8c6c8097..d4e6762b 100644 --- a/modules/Home/index.php +++ b/modules/Home/index.php @@ -303,5 +303,6 @@ $mySugarResources = $sugarChart->getMySugarChartResources(); $sugar_smarty->assign('chartResources', $resources); $sugar_smarty->assign('mySugarChartResources', $mySugarResources); echo $sugar_smarty->fetch('include/MySugar/tpls/MySugar.tpl'); - +//init the quickEdit listeners after the dashlets have loaded on home page the first time +echo""; ?> \ No newline at end of file diff --git a/modules/Home/language/en_us.lang.php b/modules/Home/language/en_us.lang.php index 020cf0c8..e3334bec 100644 --- a/modules/Home/language/en_us.lang.php +++ b/modules/Home/language/en_us.lang.php @@ -229,7 +229,9 @@ $mod_strings = array ( 'LBL_SOURCE_ISCROLL' => 'iScroll - The overflow:scroll for mobile webkit. Native scrolling inside a fixed width/height element.', 'LBL_SOURCE_FLASHCANVAS' => 'FlashCanvas - FlashCanvas is a JavaScript library which adds the HTML5 Canvas support to Internet Explorer. It renders shapes and images via Flash drawing API. It supports almost all Canvas APIs and, in many cases, runs faster than other similar libraries which use VML or Silverlight.', 'LBL_SOURCE_JIT' => 'JavaScript InfoVis Toolkit - The JavaScript InfoVis Toolkit provides tools for creating Interactive Data Visualizations for the Web.', - + 'LBL_SOURCE_ZEND' => 'Zend Framework - An open source, object oriented web application framework for PHP5.', + 'LBL_SOURCE_PARSECSV' => 'parseCSV - CSV data parser for PHP', + 'LBL_SOURCE_PHPJS' => 'php.js - Use PHP functions in JavaScript', 'LBL_DASHLET_TITLE' => 'My Sites', 'LBL_DASHLET_OPT_TITLE' => 'Title', diff --git a/modules/Import/CsvAutoDetect.php b/modules/Import/CsvAutoDetect.php new file mode 100644 index 00000000..218d82fc --- /dev/null +++ b/modules/Import/CsvAutoDetect.php @@ -0,0 +1,373 @@ +getCsvSettings($delimiter, $enclosure); + if ($ret) { + echo "found delimiter = ".$delimiter."
"; + echo "found enclosure = ".$enclosure."
"; + } else { + echo "couldn't find settings
"; + } + + $ret = $auto->hasHeader($heading); + if ($ret) { + $header = $heading?'true':'false'; + echo "found heading = ".$header."
"; + } else { + echo "couldn't determine header info
"; + } + + $date_format = $auto->getDateFormat(); + if ($date_format) { + echo "found date format=".$date_format."
"; + } else { + echo "couldn't find date format
"; + } + + $time_format = $auto->getTimeFormat(); + if ($time_format) { + echo "found time format=".$time_format."
"; + } else { + echo "couldn't find time format
"; + } + +*/ + +require_once('include/parsecsv.lib.php'); + +class CsvAutoDetect { + + protected $_parser = null; + + protected $_csv_file = null; + + protected $_max_depth = 15; + + protected $_parsed = false; + + static protected $_date_formats = array( + 'm/d/Y' => "/^(0?[1-9]|1[012])\/(0?[1-9]|[12][0-9]|3[01])\/\d\d\d\d/", // 12/23/2010 or 3/23/2010 + 'd/m/Y' => "/^(0?[1-9]|[12][0-9]|3[01])\/(0?[1-9]|1[012])\/\d\d\d\d/", // 23/12/2010 or 23/3/2010 + 'Y/m/d' => "/^\d\d\d\d\/(0?[1-9]|1[012])\/(0?[1-9]|[12][0-9]|3[01])/", // 2010/12/23 or 2010/3/23 + 'm-d-Y' => "/^(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])-\d\d\d\d/", // 12-23-2010 or 3-23-2010 + 'd-m-Y' => "/^(0?[1-9]|[12][0-9]|3[01])-(0?[1-9]|1[012])-\d\d\d\d/", // 23-12-2010 or 23-3-2010 + 'Y-m-d' => "/^\d\d\d\d-(0?[1-9]|1[012])-(0?[1-9]|[12][0-9]|3[01])/", // 2010-12-23 or 2010-3-23 + 'm.d.Y' => "/^(0?[1-9]|1[012])\.(0?[1-9]|[12][0-9]|3[01])\.\d\d\d\d/", // 12.23.2010 or 3.23.2010 + 'd.m.Y' => "/^(0?[1-9]|[12][0-9]|3[01])\.(0?[1-9]|1[012])\.\d\d\d\d/", // 23.12.2010 or 23.3.2010 + 'Y.m.d' => "/^\d\d\d\d\.(0?[1-9]|1[012])\.(0?[1-9]|[12][0-9]|3[01])/", // 2010.12.23 or 2010.3.23 + ); + + static protected $_time_formats = array( + 'h:ia' => "/(^| )(0?[0-9]|1[0-2]):(0?[0-9]|[1-5][0-9])(:0?[0-9]|[1-5][0-9])?[am|pm]/", // 11:00pm or 11:00:00pm or 9:3pm + 'h:iA' => "/(^| )(0?[0-9]|1[0-2]):(0?[0-9]|[1-5][0-9])(:0?[0-9]|[1-5][0-9])?[AM|PM]/", // 11:00PM or 11:00:00PM or 9:3PM + 'h:i a' => "/(^| )(0?[0-9]|1[0-2]):(0?[0-9]|[1-5][0-9])(:0?[0-9]|[1-5][0-9])? [am|pm]/", // 11:00 pm or 11:00:00 pm or 9:3 pm + 'h:i A' => "/(^| )(0?[0-9]|1[0-2]):(0?[0-9]|[1-5][0-9])(:0?[0-9]|[1-5][0-9])? [AM|PM]/", // 11:00 PM or 11:00:00 PM or 9:3 PM + 'H:i' => "/(^| )(0?[0-9]|1[0-9]|2[0-4]):(0?[0-9]|[1-5][0-9])(:0?[0-9]|[1-5][0-9])?/", // 23:00 or 23:00:00 or 9:3 + 'h.ia' => "/(^| )(0?[0-9]|1[0-2])\.(0?[0-9]|[1-5][0-9])(\.0?[0-9]|[1-5][0-9])?[am|pm]/", // 11.00pm or 11.00.00pm or 9.3pm + 'h.iA' => "/(^| )(0?[0-9]|1[0-2])\.(0?[0-9]|[1-5][0-9])(\.0?[0-9]|[1-5][0-9])?[AM|PM]/", // 11.00PM or 11.00.00PM or 9.3PM + 'h.i a' => "/(^| )(0?[0-9]|1[0-2])\.(0?[0-9]|[1-5][0-9])(\.0?[0-9]|[1-5][0-9])? [am|pm]/", // 11.00 pm or 11.00.00 pm or 9.3 pm + 'h.i A' => "/(^| )(0?[0-9]|1[0-2])\.(0?[0-9]|[1-5][0-9])(\.0?[0-9]|[1-5][0-9])? [AM|PM]/", // 11.00 PM or 11.00.00 PM or 9.3 PM + 'H.i' => "/(^| )(0?[0-9]|1[0-9]|2[0-4])\.(0?[0-9]|[1-5][0-9])(\.0?[0-9]|[1-5][0-9])?/", // 23.00 or 23.00.00 or 9.3 + ); + + + /** + * Constructor + * + * @param string $csv_filename + * @param int $max_depth + */ + public function __construct($csv_filename, $max_depth = 2) { + $this->_csv_file = $csv_filename; + + $this->_parser = new parseCSV(); + + $this->_parser->auto_depth = $max_depth; + + $this->_max_depth = $max_depth; + } + + + + /** + * To get the possible csv settings (delimiter, enclosure). + * This function causes CSV to be parsed. + * So call this function before calling others. + * + * @param string $delimiter + * @param string $enclosure + * @return bool true if settings are found, false otherwise + */ + public function getCsvSettings(&$delimiter, &$enclosure) { + // try parsing the file to find possible delimiter and enclosure + $this->_parser->heading = false; + + $found_setting = false; + + $singleQuoteParsedOK = $doubleQuoteParsedOK = false; + $beginEndWithSingle = $beginEndWithDouble = false; + + // check double quotes first + $depth = 1; + $enclosure = "\""; + $delimiter1 = $this->_parser->auto($this->_csv_file, true, null, null, $enclosure); + if (strlen($delimiter1) == 1) { // this means parsing ok + $doubleQuoteParsedOK = true; + // sometimes it parses ok with either single quote or double quote as enclosure + // so we need to make sure the data do not begin and end with the other enclosure + foreach ($this->_parser->data as &$row) { + foreach ($row as &$data) { + $len = strlen($data); + // check if it begins and ends with single quotes + // if it does, then it double quotes may not be the enclosure + if ($len>=2 && $data[0] == "'" && $data[$len-1] == "'") { + $beginEndWithSingle = true; + break; + } + } + if ($beginEndWithSingle) { + break; + } + $depth++; + if ($depth > $this->_max_depth) { + break; + } + } + if (!$beginEndWithSingle) { + $delimiter = $delimiter1; + $found_setting = true; + } + } + + // check single quotes + if (!$found_setting) { + $depth = 1; + $enclosure = "'"; + $delimiter2 = $this->_parser->auto($this->_csv_file, true, null, null, $enclosure); + if (strlen($delimiter2) == 1) { // this means parsing ok + $singleQuoteParsedOK = true; + foreach ($this->_parser->data as &$row) { + foreach ($row as &$data) { + $len = strlen($data); + // check if it begins and ends with double quotes + // if it does, then it single quotes may not be the enclosure + if ($len>=2 && $data[0] == "\"" && $data[$len-1] == "\"") { + $beginEndWithDouble = true; + break; + } + } + if ($beginEndWithDouble) { + break; + } + $depth++; + if ($depth > $this->_max_depth) { + break; + } + } + if (!$beginEndWithDouble) { + $delimiter = $delimiter2; + $found_setting = true; + } + } + } + + if (!$found_setting) { + // we don't seem to have a perfect enclosure candidate + // let's pick one of the possible candidates + if ($doubleQuoteParsedOK) { + // if double quotes parsed ok, let's take that + $delimiter = $delimiter1; + $enclosure = "\""; + $found_setting = true; + } else if ($singleQuoteParsedOK) { + // otherwise, if single quote parsed ok, let's use it + $delimiter = $delimiter2; + $enclosure = "'"; + $found_setting = true; + } + } + + if (!$found_setting) { + return false; + } + + $this->_parsed = true; + + return true; + } + + /** + * To check CSV heading + * + * @param bool $heading true of it has header, false if not + * @return bool true if header is found, false if error + */ + public function hasHeader(&$heading, $module) { + + if (!$this->_parsed) { + return false; + } + + $total_count = count($this->_parser->data[0]); + if ($total_count == 0) { + return false; + } + + if (!isset($GLOBALS['beanList'][$module])) { + return false; + } + + $bean = new $GLOBALS['beanList'][$module](); + + $match_count = 0; + + $mod_strings = return_module_language($GLOBALS['current_language'], $module); + + // process only the first row + foreach ($this->_parser->data[0] as $val) { + foreach ($bean->field_defs as $field_name=>$defs) { + + // check if the CSV item matches field name + if (!strcasecmp($val, $field_name)) { + $match_count++; + break; + } + // check if the CSV item is part of the label or vice versa + else if (isset($defs['vname']) && isset($mod_strings[$defs['vname']])) { + if (stripos(trim($mod_strings[$defs['vname']],':'), $val) !== false || stripos($val, trim($mod_strings[$defs['vname']],':')) !== false) { + $match_count++; + break; + } + } + else if (isset($defs['vname']) && isset($GLOBALS['app_strings'][$defs['vname']])) { + if (stripos(trim($GLOBALS['app_strings'][$defs['vname']],':'), $val) !== false || stripos($val, trim($GLOBALS['app_strings'][$defs['vname']],':')) !== false) { + $match_count++; + break; + } + } + } + } + + // if more than 50% matched, consider it a header + if ($match_count/$total_count >= 0.5) { + $heading = true; + } else { + $heading = false; + } + + return true; + } + + + /** + * To get the possible format (for date or time) + * + * @param array $formats + * @return mixed possible format if found, false otherwise + */ + protected function getFormat(&$formats) { + + if (!$this->_parsed) { + return false; + } + + $depth = 1; + + foreach ($this->_parser->data as $row) { + + foreach ($row as $val) { + + foreach ($formats as $format=>$regex) { + + $ret = preg_match($regex, $val); + if ($ret) { + return $format; + } + } + } + + // give up if reaching max depth + $depth++; + if ($depth > $this->_max_depth) { + break; + } + } + + return false; + } + + + /** + * To get the possible date format used in the csv file + * + * @return mixed possible date format if found, false otherwise + */ + public function getDateFormat() { + + $format = $this->getFormat(self::$_date_formats); + + return $format; + } + + + /** + * To get the possible time format used in the csv file + * + * @return mixed possible time format if found, false otherwise + */ + public function getTimeFormat() { + + $format = $this->getFormat(self::$_time_formats); + + return $format; + } + +} +?> diff --git a/modules/Import/Forms.php b/modules/Import/Forms.php index 5e0f46ac..931a14cf 100644 --- a/modules/Import/Forms.php +++ b/modules/Import/Forms.php @@ -67,8 +67,8 @@ function getControl( // set the filename for this control $file = create_cache_directory('modules/Import/') . $module . $fieldname . '.tpl'; - if ( !is_file($file) - || !empty($GLOBALS['sugar_config']['developerMode']) + if ( !is_file($file) + || !empty($GLOBALS['sugar_config']['developerMode']) || !empty($_SESSION['developerMode']) ) { if ( !isset($vardef) ) { @@ -113,7 +113,7 @@ function getControl( && ( $vardef['function'] == 'getCurrencyDropDown' || $vardef['function']['name'] == 'getCurrencyDropDown' ) ) $contents .= "{literal}{/literal}"; - + // Save it to the cache file if($fh = @sugar_fopen($file, 'w')) { fputs($fh, $contents); @@ -166,8 +166,11 @@ function getControl( $fieldlist[$name]['options'][''] = ''; } // fill in function return values - if ( !in_array($fieldname,array('email1','email2')) ) { - if (!empty($fieldlist[$fieldname]['function']['returns']) && $fieldlist[$fieldname]['function']['returns'] == 'html'){ + if ( !in_array($fieldname,array('email1','email2')) ) + { + if (!empty($fieldlist[$fieldname]['function']['returns']) && $fieldlist[$fieldname]['function']['returns'] == 'html') + { + $function = $fieldlist[$fieldname]['function']['name']; // include various functions required in the various vardefs if ( isset($fieldlist[$fieldname]['function']['include']) && is_file($fieldlist[$fieldname]['function']['include'])) @@ -177,6 +180,15 @@ function getControl( if ( preg_match('/getCurrency.*DropDown/s',$function) ) $value = str_ireplace('','',$value); } + elseif($fieldname == 'assigned_user_name' && empty($value)) + { + $fieldlist['assigned_user_id']['value'] = $GLOBALS['current_user']->id; + $value = get_assigned_user_name($GLOBALS['current_user']->id); + } + elseif($fieldname == 'team_name' && empty($value)) + { + $value = json_encode(array()); + } } $fieldlist[$fieldname]['value'] = $value; $ss->assign("fields",$fieldlist); diff --git a/modules/Import/ImportCacheFiles.php b/modules/Import/ImportCacheFiles.php index 4db4707f..bd7e81c6 100644 --- a/modules/Import/ImportCacheFiles.php +++ b/modules/Import/ImportCacheFiles.php @@ -52,9 +52,7 @@ class ImportCacheFiles * @param string $type string to prepend to the filename, typically to indicate the file's use * @return string filename */ - private static function _createFileName( - $type = 'misc' - ) + private static function _createFileName($type = 'misc') { global $sugar_config, $current_user; @@ -68,7 +66,7 @@ class ImportCacheFiles } /** - * Returns the duplicates filename + * Returns the duplicates filename (the ones used to download to csv file * * @return string filename */ @@ -76,7 +74,17 @@ class ImportCacheFiles { return self::_createFileName("dupes"); } - + + /** + * Returns the duplicates display filename (the one used for display in html) + * + * @return string filename + */ + public static function getDuplicateFileDisplayName() + { + return self::_createFileName("dupesdisplay"); + } + /** * Returns the error filename * @@ -96,7 +104,17 @@ class ImportCacheFiles { return self::_createFileName("errorrecords"); } - + + /** + * Returns the error records filename + * + * @return string filename + */ + public static function getErrorRecordsWithoutErrorFileName() + { + return self::_createFileName("errorrecordsonly"); + } + /** * Returns the status filename * diff --git a/modules/Import/ImportDuplicateCheck.php b/modules/Import/ImportDuplicateCheck.php index 27eb1ab3..a7938576 100644 --- a/modules/Import/ImportDuplicateCheck.php +++ b/modules/Import/ImportDuplicateCheck.php @@ -49,6 +49,11 @@ class ImportDuplicateCheck * Private reference to the bean we're dealing with */ private $_focus; + + /* + * holds current field when a duplicate has been found + */ + public $_dupedFields =array(); /** * Constructor @@ -70,7 +75,13 @@ class ImportDuplicateCheck private function _getIndexVardefs() { $indexes = $this->_focus->getIndices(); - + + //grab any custom indexes if they exist + if($this->_focus->hasCustomFields()){ + $custmIndexes = $this->_focus->db->helper->get_indices($this->_focus->table_name.'_cstm'); + $indexes = array_merge($custmIndexes,$indexes); + } + if ( $this->_focus->getFieldDefinition('email1') ) $indexes[] = array( 'name' => 'special_idx_email1', @@ -117,23 +128,103 @@ class ImportDuplicateCheck return $index_array; } - + + /** + * Checks to see if the given bean is a duplicate based off the given fields + * + * @param array $indexlist + * @return bool true if this bean is a duplicate or false if it isn't + */ + public function isADuplicateRecordByFields($fieldList) + { + foreach($fieldList as $field) + { + if ( $field == 'email1' || $field == 'email2' ) + { + $emailAddress = new SugarEmailAddress(); + $email = $field; + if ( $emailAddress->getCountEmailAddressByBean($this->_focus->$email,$this->_focus,($field == 'email1')) > 0 ) + return true; + } + else + { + $index_fields = array('deleted' => '0'); + if( is_array($field) ) + { + foreach($field as $tmpField) + { + if ($tmpField == 'deleted') + continue; + if (strlen($this->_focus->$tmpField) > 0) + $index_fields[$tmpField] = $this->_focus->$tmpField; + } + } + elseif($field != 'deleted' && strlen($this->_focus->$field) > 0) + $index_fields[$field] = $this->_focus->$field; + + if ( count($index_fields) <= 1 ) + continue; + + $newfocus = loadBean($this->_focus->module_dir); + $result = $newfocus->retrieve_by_string_fields($index_fields,true); + + if ( !is_null($result) ) + return true; + } + } + + return false; + } + /** * Checks to see if the given bean is a duplicate based off the given indexes * * @param array $indexlist * @return bool true if this bean is a duplicate or false if it isn't */ - public function isADuplicateRecord( - $indexlist - ) + public function isADuplicateRecord( $indexlist ) { + + //lets strip the indexes of the name field in the value and leave only the index name + $origIndexList = $indexlist; + $indexlist=array(); + $fieldlist=array(); + $customIndexlist=array(); + foreach($origIndexList as $iv){ + if(empty($iv)) continue; + $field_index_array = explode('::',$iv); + if($field_index_array[0] == 'customfield'){ + //this is a custom field, so place in custom array + $customIndexlist[] = $field_index_array[1]; + + }else{ + //this is not a custom field, so place in index list + $indexlist[] = $field_index_array[0]; + $fieldlist[] = $field_index_array[1]; + } + } + + //if full_name is set, then manually search on the first and last name fields before iterating through rest of fields + //this is a special handling of the name fields on people objects, the rest of the fields are checked individually + if(in_array('full_name',$indexlist)){ + $newfocus = loadBean($this->_focus->module_dir); + $result = $newfocus->retrieve_by_string_fields(array('deleted' =>'0', 'first_name'=>$this->_focus->first_name, 'last_name'=>$this->_focus->last_name),true); + + if ( !is_null($result) ){ + //set dupe field to full_name and name fields + $this->_dupedFields[] = 'full_name'; + $this->_dupedFields[] = 'first_name'; + $this->_dupedFields[] = 'last_name'; + + } + } + // loop through var def indexes and compare with selected indexes - foreach ( $this->_getIndexVardefs() as $index ) { + foreach ($this->_getIndexVardefs() as $index){ // if we get an index not in the indexlist, loop if ( !in_array($index['name'],$indexlist) ) continue; - + // This handles the special case of duplicate email checking if ( $index['name'] == 'special_idx_email1' || $index['name'] == 'special_idx_email2' ) { $emailAddress = new SugarEmailAddress(); @@ -142,8 +233,11 @@ class ImportDuplicateCheck $this->_focus->$email, $this->_focus, ($index['name'] == 'special_idx_email1') - ) > 0 ) - return true; + ) > 0 ){ foreach($index['fields'] as $field){ + if($field !='deleted') + $this->_dupedFields[] = $field; + } + } } // Adds a hook so you can define a method in the bean to handle dupe checking elseif ( isset($index['dupeCheckFunction']) ) { @@ -153,27 +247,91 @@ class ImportDuplicateCheck } else { $index_fields = array('deleted' => '0'); + //search only for the field we have selected foreach($index['fields'] as $field){ - if ($field == 'deleted') + if ($field == 'deleted' || !in_array($field,$fieldlist)) continue; if (!in_array($field,$index_fields)) - if (strlen($this->_focus->$field) > 0) + if (isset($this->_focus->$field) && strlen($this->_focus->$field) > 0) $index_fields[$field] = $this->_focus->$field; } - + // if there are no valid fields in the index field list, loop if ( count($index_fields) <= 1 ) continue; - + $newfocus = loadBean($this->_focus->module_dir); $result = $newfocus->retrieve_by_string_fields($index_fields,true); - - if ( !is_null($result) ) - return true; + + if ( !is_null($result) ){ + //remove deleted as a duped field + unset($index_fields['deleted']); + + //create string based on array of dupe fields + $this->_dupedFields = array_merge(array_keys($index_fields),$this->_dupedFields); + } } } + + //return true if any dupes were found + if(!empty($this->_dupedFields)){ + return true; + } + return false; } + + + public function getDuplicateCheckIndexedFiles() + { + require_once('include/export_utils.php'); + $import_fields = $this->_focus->get_importable_fields(); + $importable_keys = array_keys($import_fields);// + + $index_array = array(); + $fields_used = array(); + $mstr_exclude_array = array('all'=>array('team_set_id','id','deleted'),'contacts'=>array('email2'), array('leads'=>'reports_to_id'), array('prospects'=>'tracker_key')); + + //create exclude array from subset of applicable mstr_exclude_array elements + $exclude_array = isset($mstr_exclude_array[strtolower($this->_focus->module_dir)])?array_merge($mstr_exclude_array[strtolower($this->_focus->module_dir)], $mstr_exclude_array['all']) : $mstr_exclude_array['all']; + + + + //process all fields belonging to indexes + foreach ($this->_getIndexVardefs() as $index){ + if ($index['type'] == "index"){ + + foreach ($index['fields'] as $field){ + $fieldName=''; + + //skip this field if it is the deleted field, not in the importable keys array, or a field in the exclude array + if (!in_array($field, $importable_keys) || in_array($field, $exclude_array)) continue; + $fieldDef = $this->_focus->getFieldDefinition($field); + + //skip if this field is already defined (from another index) + if (in_array($fieldDef['name'],$fields_used)) continue; + + //get the proper export label + $fieldName = translateForExport($fieldDef['name'],$this->_focus); + + + $index_array[$index['name'].'::'.$fieldDef['name']] = $fieldName; + $fields_used[] = $fieldDef['name']; + } + + } + } + + //special handling for beans with first_name and last_name + if(in_array('first_name', $fields_used) && in_array('last_name', $fields_used)){ + //since both full name and last name fields have been mapped, add full name index + $index_array['full_name::full_name'] = translateForExport('full_name',$this->_focus); + $fields_used[] = 'full_name'; + } + + asort($index_array); + return $index_array; + } } - -?> + +?> \ No newline at end of file diff --git a/modules/Import/ImportFieldSanitize.php b/modules/Import/ImportFieldSanitize.php index d3b6d608..e94b3ab4 100644 --- a/modules/Import/ImportFieldSanitize.php +++ b/modules/Import/ImportFieldSanitize.php @@ -42,7 +42,7 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. * All Rights Reserved. ********************************************************************************/ -require_once('modules/Import/ImportFile.php'); +require_once('modules/Import/sources/ImportFile.php'); class ImportFieldSanitize { diff --git a/modules/Import/ImportFile.php b/modules/Import/ImportFile.php deleted file mode 100644 index ef9feaa7..00000000 --- a/modules/Import/ImportFile.php +++ /dev/null @@ -1,329 +0,0 @@ -_fp = sugar_fopen($filename,'r'); - $this->_filename = $filename; - $this->_deleteFile = $deleteFile; - $this->_delimiter = ( empty($delimiter) ? ',' : $delimiter ); - $this->_enclosure = ( empty($enclosure) ? '' : trim($enclosure) ); - - // Bug 39494 - Remove the BOM (Byte Order Mark) from the beginning of the import row if it exists - $bomCheck = fread($this->_fp, 3); - if($bomCheck != pack("CCC",0xef,0xbb,0xbf)) { - rewind($this->_fp); - } - } - - /** - * Destructor - * - * Deletes $_importFile if $_deleteFile is true - */ - public function __destruct() - { - if ( $this->_deleteFile && $this->fileExists() ) { - fclose($this->_fp); - //Make sure the file exists before unlinking - if(file_exists($this->_filename)) { - unlink($this->_filename); - } - } - - ini_restore('auto_detect_line_endings'); - } - - /** - * Returns true if the filename given exists and is readable - * - * @return bool - */ - public function fileExists() - { - return !$this->_fp ? false : true; - } - - /** - * Gets the next row from $_importFile - * - * @return array current row of file - */ - public function getNextRow() - { - if (!$this->fileExists()) - return false; - - // explode on delimiter instead if enclosure is an empty string - if ( empty($this->_enclosure) ) { - $row = explode($this->_delimiter,rtrim(fgets($this->_fp, 8192),"\r\n")); - if ($row !== false && !( count($row) == 1 && trim($row[0]) == '') ) - $this->_currentRow = $row; - else - return false; - } - else { - $row = fgetcsv($this->_fp, 8192, $this->_delimiter, $this->_enclosure); - if ($row !== false && $row != array(null)) - $this->_currentRow = $row; - else - return false; - } - - // Bug 26219 - Convert all line endings to the same style as PHP_EOL - foreach ( $this->_currentRow as $key => $value ) { - // use preg_replace instead of str_replace as str_replace may cause extra lines on Windows - $this->_currentRow[$key] = preg_replace("[\r\n|\n|\r]", PHP_EOL, $value); - } - - $this->_rowsCount++; - $this->_rowCountedForErrors = false; - - return $this->_currentRow; - } - - /** - * Returns the number of fields in the current row - * - * @return int count of fiels in the current row - */ - public function getFieldCount() - { - return count($this->_currentRow); - } - - /** - * Writes the row out to the ImportCacheFiles::getDuplicateFileName() file - */ - public function markRowAsDuplicate() - { - $fp = sugar_fopen(ImportCacheFiles::getDuplicateFileName(),'a'); - if ( empty($this->_enclosure) ) - fputs($fp,implode($this->_delimiter,$this->_currentRow).PHP_EOL); - else - fputcsv($fp,$this->_currentRow, $this->_delimiter, $this->_enclosure); - fclose($fp); - - $this->_dupeCount++; - } - - /** - * Writes the row out to the ImportCacheFiles::getErrorFileName() file - * - * @param $error string - * @param $fieldName string - * @param $fieldValue mixed - */ - public function writeError( - $error, - $fieldName, - $fieldValue - ) - { - $fp = sugar_fopen(ImportCacheFiles::getErrorFileName(),'a'); - fputcsv($fp,array($error,$fieldName,$fieldValue,$this->_rowsCount)); - fclose($fp); - - if ( !$this->_rowCountedForErrors ) { - $this->_errorCount++; - $this->_rowCountedForErrors = true; - $this->writeErrorRecord(); - } - } - - /** - * Writes the row out to the ImportCacheFiles::getErrorRecordsFileName() file - */ - public function writeErrorRecord() - { - $fp = sugar_fopen(ImportCacheFiles::getErrorRecordsFileName(),'a'); - if ( empty($this->_enclosure) ) - fputs($fp,implode($this->_delimiter,$this->_currentRow).PHP_EOL); - else - fputcsv($fp,$this->_currentRow, $this->_delimiter, $this->_enclosure); - fclose($fp); - } - - /** - * Writes the totals and filename out to the ImportCacheFiles::getStatusFileName() file - */ - public function writeStatus() - { - $fp = sugar_fopen(ImportCacheFiles::getStatusFileName(),'a'); - fputcsv($fp,array($this->_rowsCount,$this->_errorCount,$this->_dupeCount, - $this->_createdCount,$this->_updatedCount,$this->_filename)); - fclose($fp); - } - - /** - * Add this row to the UsersLastImport table - * - * @param string $import_module name of the module we are doing the import into - * @param string $module name of the bean we are creating for this import - * @param string $id id of the recorded created in the $module - */ - public static function writeRowToLastImport( - $import_module, - $module, - $id - ) - { - // cache $last_import instance - static $last_import; - - if ( !($last_import instanceof UsersLastImport) ) - $last_import = new UsersLastImport(); - - $last_import->id = null; - $last_import->deleted = null; - $last_import->assigned_user_id = $GLOBALS['current_user']->id; - $last_import->import_module = $import_module; - if ( $module == 'Case' ) { - $module = 'aCase'; - } - $last_import->bean_type = $module; - $last_import->bean_id = $id; - return $last_import->save(); - } - - /** - * Marks whether this row created a new record or not - * - * @param $createdRecord bool true if record is created, false if it is just updated - */ - public function markRowAsImported( - $createdRecord = true - ) - { - if ( $createdRecord ) - ++$this->_createdCount; - else - ++$this->_updatedCount; - } -} diff --git a/modules/Import/Importer.php b/modules/Import/Importer.php new file mode 100644 index 00000000..df205f1e --- /dev/null +++ b/modules/Import/Importer.php @@ -0,0 +1,833 @@ +importSource = $importSource; + + //Vanilla copy of the bean object. + $this->bean = $bean; + + // use our own error handler + set_error_handler(array('Importer','handleImportErrors'),E_ALL); + + // Increase the max_execution_time since this step can take awhile + ini_set("max_execution_time", max($sugar_config['import_max_execution_time'],3600)); + + // stop the tracker + TrackerManager::getInstance()->pause(); + + // set the default locale settings + $this->ifs = $this->getFieldSanitizer(); + + //Get the default user currency + $this->defaultUserCurrency = new Currency(); + $this->defaultUserCurrency->retrieve('-99'); + + //Get our import column definitions + $this->importColumns = $this->getImportColumns(); + $this->isUpdateOnly = ( isset($_REQUEST['import_type']) && $_REQUEST['import_type'] == 'update' ); + } + + public function import() + { + foreach($this->importSource as $row) + { + $this->importRow($row); + } + + // save mapping if requested + if ( isset($_REQUEST['save_map_as']) && $_REQUEST['save_map_as'] != '' ) + { + $this->saveMappingFile(); + } + + $this->importSource->writeStatus(); + + //All done, remove file. + } + + + protected function importRow($row) + { + global $sugar_config, $mod_strings; + + $focus = clone $this->bean; + $focus->unPopulateDefaultValues(); + $focus->save_from_post = false; + $focus->team_id = null; + $this->ifs->createdBeans = array(); + $this->importSource->resetRowErrorCounter(); + $do_save = true; + + for ( $fieldNum = 0; $fieldNum < $_REQUEST['columncount']; $fieldNum++ ) + { + // loop if this column isn't set + if ( !isset($this->importColumns[$fieldNum]) ) + continue; + + // get this field's properties + $field = $this->importColumns[$fieldNum]; + $fieldDef = $focus->getFieldDefinition($field); + $fieldTranslated = translate((isset($fieldDef['vname'])?$fieldDef['vname']:$fieldDef['name']), $focus->module_dir)." (".$fieldDef['name'].")"; + $defaultRowValue = ''; + // Bug 37241 - Don't re-import over a field we already set during the importing of another field + if ( !empty($focus->$field) ) + continue; + + // translate strings + global $locale; + if(empty($locale)) + { + $locale = new Localization(); + } + if ( isset($row[$fieldNum]) ) + { + $rowValue = $locale->translateCharset(strip_tags(trim($row[$fieldNum])),$this->importSource->importlocale_charset,$sugar_config['default_charset']); + } + else if( isset($this->sugarToExternalSourceFieldMap[$field]) && isset($row[$this->sugarToExternalSourceFieldMap[$field]]) ) + { + $rowValue = $locale->translateCharset(strip_tags(trim($row[$this->sugarToExternalSourceFieldMap[$field]])),$this->importSource->importlocale_charset,$sugar_config['default_charset']); + } + else + { + $rowValue = ''; + } + + // If there is an default value then use it instead + if ( !empty($_REQUEST[$field]) ) + { + $defaultRowValue = $this->populateDefaultMapValue($field, $_REQUEST[$field], $fieldDef); + + + if( empty($rowValue)) + { + $rowValue = $defaultRowValue; + //reset the default value to empty + $defaultRowValue=''; + } + } + + // Bug 22705 - Don't update the First Name or Last Name value if Full Name is set + if ( in_array($field, array('first_name','last_name')) && !empty($focus->full_name) ) + continue; + + // loop if this value has not been set + if ( !isset($rowValue) ) + continue; + + // If the field is required and blank then error out + if ( array_key_exists($field,$focus->get_import_required_fields()) && empty($rowValue) && $rowValue!='0') + { + $this->importSource->writeError( $mod_strings['LBL_REQUIRED_VALUE'],$fieldTranslated,'NULL'); + $do_save = false; + } + + // Handle the special case "Sync to Outlook" + if ( $focus->object_name == "Contacts" && $field == 'sync_contact' ) + { + $bad_names = array(); + $returnValue = $this->ifs->synctooutlook($rowValue,$fieldDef,$bad_names); + // try the default value on fail + if ( !$returnValue && !empty($defaultRowValue) ) + $returnValue = $this->ifs->synctooutlook($defaultRowValue, $fieldDef, $bad_names); + if ( !$returnValue ) + { + $this->importSource->writeError($mod_strings['LBL_ERROR_SYNC_USERS'], $fieldTranslated, explode(",",$bad_names)); + $do_save = 0; + } + } + + // Handle email1 and email2 fields ( these don't have the type of email ) + if ( $field == 'email1' || $field == 'email2' ) + { + $returnValue = $this->ifs->email($rowValue, $fieldDef, $focus); + // try the default value on fail + if ( !$returnValue && !empty($defaultRowValue) ) + $returnValue = $this->ifs->email( $defaultRowValue, $fieldDef); + if ( $returnValue === FALSE ) + { + $do_save=0; + $this->importSource->writeError( $mod_strings['LBL_ERROR_INVALID_EMAIL'], $fieldTranslated, $rowValue); + } + else + { + $rowValue = $returnValue; + // check for current opt_out and invalid email settings for this email address + // if we find any, set them now + $emailres = $focus->db->query( "SELECT opt_out, invalid_email FROM email_addresses WHERE email_address = '".$focus->db->quote($rowValue)."'"); + if ( $emailrow = $focus->db->fetchByAssoc($emailres) ) + { + $focus->email_opt_out = $emailrow['opt_out']; + $focus->invalid_email = $emailrow['invalid_email']; + } + } + } + + // Handle splitting Full Name into First and Last Name parts + if ( $field == 'full_name' && !empty($rowValue) ) + { + $this->ifs->fullname($rowValue,$fieldDef,$focus); + } + + // to maintain 451 compatiblity + if(!isset($fieldDef['module']) && $fieldDef['type']=='relate') + $fieldDef['module'] = ucfirst($fieldDef['table']); + + if(isset($fieldDef['custom_type']) && !empty($fieldDef['custom_type'])) + $fieldDef['type'] = $fieldDef['custom_type']; + + // If the field is empty then there is no need to check the data + if( !empty($rowValue) ) + { + //Start + $rowValue = $this->sanitizeFieldValueByType($rowValue, $fieldDef, $defaultRowValue, $focus, $fieldTranslated); + if($rowValue === FALSE) + continue; + + } + + // if the parent type is in singular form, get the real module name for parent_type + if (isset($fieldDef['type']) && $fieldDef['type']=='parent_type') { + $rowValue = get_module_from_singular($rowValue); + } + + $focus->$field = $rowValue; + unset($defaultRowValue); + } + + // Now try to validate flex relate fields + if ( isset($focus->field_defs['parent_name']) && isset($focus->parent_name) && ($focus->field_defs['parent_name']['type'] == 'parent') ) + { + // populate values from the picker widget if the import file doesn't have them + $parent_idField = $focus->field_defs['parent_name']['id_name']; + if ( empty($focus->$parent_idField) && !empty($_REQUEST[$parent_idField]) ) + $focus->$parent_idField = $_REQUEST[$parent_idField]; + + $parent_typeField = $focus->field_defs['parent_name']['type_name']; + + if ( empty($focus->$parent_typeField) && !empty($_REQUEST[$parent_typeField]) ) + $focus->$parent_typeField = $_REQUEST[$parent_typeField]; + // now validate it + $returnValue = $this->ifs->parent($focus->parent_name,$focus->field_defs['parent_name'],$focus, empty($_REQUEST['parent_name'])); + if ( !$returnValue && !empty($_REQUEST['parent_name']) ) + $returnValue = $this->ifs->parent( $_REQUEST['parent_name'],$focus->field_defs['parent_name'], $focus); + } + + // check to see that the indexes being entered are unique. + if (isset($_REQUEST['enabled_dupes']) && $_REQUEST['enabled_dupes'] != "") + { + $toDecode = html_entity_decode ($_REQUEST['enabled_dupes'], ENT_QUOTES); + $enabled_dupes = json_decode($toDecode); + $idc = new ImportDuplicateCheck($focus); + + if ( $idc->isADuplicateRecord($enabled_dupes) ) + { + $this->importSource->markRowAsDuplicate($idc->_dupedFields); + $this->_undoCreatedBeans($this->ifs->createdBeans); + return; + } + } + //Allow fields to be passed in for dup check as well (used by external adapters) + else if( !empty($_REQUEST['enabled_dup_fields']) ) + { + $toDecode = html_entity_decode ($_REQUEST['enabled_dup_fields'], ENT_QUOTES); + $enabled_dup_fields = json_decode($toDecode); + $idc = new ImportDuplicateCheck($focus); + if ( $idc->isADuplicateRecordByFields($enabled_dup_fields) ) + { + $this->importSource->markRowAsDuplicate($idc->_dupedFields); + $this->_undoCreatedBeans($this->ifs->createdBeans); + return; + } + } + + // if the id was specified + $newRecord = true; + if ( !empty($focus->id) ) + { + $focus->id = $this->_convertId($focus->id); + + // check if it already exists + $query = "SELECT * FROM {$focus->table_name} WHERE id='".$focus->db->quote($focus->id)."'"; + $result = $focus->db->query($query) + or sugar_die("Error selecting sugarbean: "); + + $dbrow = $focus->db->fetchByAssoc($result); + + if (isset ($dbrow['id']) && $dbrow['id'] != -1) + { + // if it exists but was deleted, just remove it + if (isset ($dbrow['deleted']) && $dbrow['deleted'] == 1 && $this->isUpdateOnly ==false) + { + $this->removeDeletedBean($focus); + $focus->new_with_id = true; + } + else + { + if( ! $this->isUpdateOnly ) + { + $this->importSource->writeError($mod_strings['LBL_ID_EXISTS_ALREADY'],'ID',$focus->id); + $this->_undoCreatedBeans($this->ifs->createdBeans); + return; + } + + $clonedBean = $this->cloneExistingBean($focus); + if($clonedBean === FALSE) + { + $this->importSource->writeError($mod_strings['LBL_RECORD_CANNOT_BE_UPDATED'],'ID',$focus->id); + $this->_undoCreatedBeans($this->ifs->createdBeans); + return; + } + else + { + $focus = $clonedBean; + $newRecord = FALSE; + } + } + } + else + { + $focus->new_with_id = true; + } + } + + if ($do_save) + { + $this->saveImportBean($focus, $newRecord); + // Update the created/updated counter + $this->importSource->markRowAsImported($newRecord); + } + else + $this->_undoCreatedBeans($this->ifs->createdBeans); + + unset($defaultRowValue); + + } + + + protected function sanitizeFieldValueByType($rowValue, $fieldDef, $defaultRowValue, $focus, $fieldTranslated) + { + global $mod_strings, $app_list_strings; + switch ($fieldDef['type']) + { + case 'enum': + case 'multienum': + if ( isset($fieldDef['type']) && $fieldDef['type'] == "multienum" ) + $returnValue = $this->ifs->multienum($rowValue,$fieldDef); + else + $returnValue = $this->ifs->enum($rowValue,$fieldDef); + // try the default value on fail + if ( !$returnValue && !empty($defaultRowValue) ) + { + if ( isset($fieldDef['type']) && $fieldDef['type'] == "multienum" ) + $returnValue = $this->ifs->multienum($defaultRowValue,$fieldDef); + else + $returnValue = $this->ifs->enum($defaultRowValue,$fieldDef); + } + if ( $returnValue === FALSE ) + { + $this->importSource->writeError($mod_strings['LBL_ERROR_NOT_IN_ENUM'] . implode(",",$app_list_strings[$fieldDef['options']]), $fieldTranslated,$rowValue); + return FALSE; + } + else + return $returnValue; + + break; + case 'relate': + case 'parent': + $returnValue = $this->ifs->relate($rowValue, $fieldDef, $focus, empty($defaultRowValue)); + if (!$returnValue && !empty($defaultRowValue)) + $returnValue = $this->ifs->relate($defaultRowValue,$fieldDef, $focus); + // Bug 33623 - Set the id value found from the above method call as an importColumn + if ($returnValue !== false) + $this->importColumns[] = $fieldDef['id_name']; + return $rowValue; + break; + case 'teamset': + $this->ifs->teamset($rowValue,$fieldDef,$focus); + $this->importColumns[] = 'team_set_id'; + $this->importColumns[] = 'team_id'; + return $rowValue; + break; + case 'fullname': + return $rowValue; + break; + default: + $fieldtype = $fieldDef['type']; + $returnValue = $this->ifs->$fieldtype($rowValue, $fieldDef, $focus); + // try the default value on fail + if ( !$returnValue && !empty($defaultRowValue) ) + $returnValue = $this->ifs->$fieldtype($defaultRowValue,$fieldDef, $focus); + if ( !$returnValue ) + { + $this->importSource->writeError($mod_strings['LBL_ERROR_INVALID_'.strtoupper($fieldDef['type'])],$fieldTranslated,$rowValue,$focus); + return FALSE; + } + return $returnValue; + } + } + + protected function cloneExistingBean($focus) + { + $existing_focus = clone $this->bean; + if ( !( $existing_focus->retrieve($focus->id) instanceOf SugarBean ) ) + { + return FALSE; + } + else + { + $newData = $focus->toArray(); + foreach ( $newData as $focus_key => $focus_value ) + if ( in_array($focus_key,$this->importColumns) ) + $existing_focus->$focus_key = $focus_value; + + return $existing_focus; + } + } + + protected function removeDeletedBean($focus) + { + global $mod_strings; + + $query2 = "DELETE FROM {$focus->table_name} WHERE id='".$focus->db->quote($focus->id)."'"; + $result2 = $focus->db->query($query2) or sugar_die($mod_strings['LBL_ERROR_DELETING_RECORD']." ".$focus->id); + if ($focus->hasCustomFields()) + { + $query3 = "DELETE FROM {$focus->table_name}_cstm WHERE id_c='".$focus->db->quote($focus->id)."'"; + $result2 = $focus->db->query($query3); + } + } + + protected function saveImportBean($focus, $newRecord) + { + global $timedate, $current_user; + + // Populate in any default values to the bean + $focus->populateDefaultValues(); + + if ( !isset($focus->assigned_user_id) || $focus->assigned_user_id == '' && $newRecord ) + { + $focus->assigned_user_id = $current_user->id; + } + /* + * Bug 34854: Added all conditions besides the empty check on date modified. + */ + if ( ( !empty($focus->new_with_id) && !empty($focus->date_modified) ) || + ( empty($focus->new_with_id) && $timedate->to_db($focus->date_modified) != $timedate->to_db($timedate->to_display_date_time($focus->fetched_row['date_modified'])) ) + ) + $focus->update_date_modified = false; + + $focus->optimistic_lock = false; + if ( $focus->object_name == "Contacts" && isset($focus->sync_contact) ) + { + //copy the potential sync list to another varible + $list_of_users=$focus->sync_contact; + //and set it to false for the save + $focus->sync_contact=false; + } + else if($focus->object_name == "User" && !empty($current_user) && $focus->is_admin && !is_admin($current_user) && is_admin_for_module($current_user, 'Users')) { + sugar_die($GLOBALS['mod_strings']['ERR_IMPORT_SYSTEM_ADMININSTRATOR']); + } + //bug# 40260 setting it true as the module in focus is involved in an import + $focus->in_import=true; + // call any logic needed for the module preSave + $focus->beforeImportSave(); + + $focus->save(false); + + // call any logic needed for the module postSave + $focus->afterImportSave(); + + if ( $focus->object_name == "Contacts" && isset($list_of_users) ) + $focus->process_sync_to_outlook($list_of_users); + + // Add ID to User's Last Import records + if ( $newRecord ) + $this->importSource->writeRowToLastImport( $_REQUEST['import_module'],($focus->object_name == 'Case' ? 'aCase' : $focus->object_name),$focus->id); + + } + + protected function saveMappingFile() + { + global $current_user; + + $firstrow = unserialize(base64_decode($_REQUEST['firstrow'])); + $mappingValsArr = $this->importColumns; + $mapping_file = new ImportMap(); + if ( isset($_REQUEST['has_header']) && $_REQUEST['has_header'] == 'on') + { + $header_to_field = array (); + foreach ($this->importColumns as $pos => $field_name) + { + if (isset($firstrow[$pos]) && isset($field_name)) + { + $header_to_field[$firstrow[$pos]] = $field_name; + } + } + + $mappingValsArr = $header_to_field; + } + //get array of values to save for duplicate and locale settings + $advMapping = $this->retrieveAdvancedMapping(); + + //merge with mappingVals array + if(!empty($advMapping) && is_array($advMapping)) + { + $mappingValsArr = array_merge($mappingValsArr,$advMapping); + } + + //set mapping + $mapping_file->setMapping($mappingValsArr); + + // save default fields + $defaultValues = array(); + for ( $i = 0; $i < $_REQUEST['columncount']; $i++ ) + { + if (isset($this->importColumns[$i]) && !empty($_REQUEST[$this->importColumns[$i]])) + { + $field = $this->importColumns[$i]; + $fieldDef = $this->bean->getFieldDefinition($field); + if(!empty($fieldDef['custom_type']) && $fieldDef['custom_type'] == 'teamset') + { + require_once('include/SugarFields/Fields/Teamset/SugarFieldTeamset.php'); + $sugar_field = new SugarFieldTeamset('Teamset'); + $teams = $sugar_field->getTeamsFromRequest($field); + if(isset($_REQUEST['primary_team_name_collection'])) + { + $primary_index = $_REQUEST['primary_team_name_collection']; + } + + //If primary_index was selected, ensure that the first Array entry is the primary team + if(isset($primary_index)) + { + $count = 0; + $new_teams = array(); + foreach($teams as $id=>$name) + { + if($primary_index == $count++) + { + $new_teams[$id] = $name; + unset($teams[$id]); + break; + } + } + + foreach($teams as $id=>$name) + { + $new_teams[$id] = $name; + } + $teams = $new_teams; + } //if + + $json = getJSONobj(); + $defaultValues[$field] = $json->encode($teams); + } + else + { + $defaultValues[$field] = $_REQUEST[$this->importColumns[$i]]; + } + } + } + $mapping_file->setDefaultValues($defaultValues); + $result = $mapping_file->save( $current_user->id, $_REQUEST['save_map_as'], $_REQUEST['import_module'], $_REQUEST['source'], + ( isset($_REQUEST['has_header']) && $_REQUEST['has_header'] == 'on'), $_REQUEST['custom_delimiter'], html_entity_decode($_REQUEST['custom_enclosure'],ENT_QUOTES) + ); + } + + + protected function populateDefaultMapValue($field, $fieldValue, $fieldDef) + { + global $timedate, $current_user; + + if ( is_array($fieldValue) ) + $defaultRowValue = encodeMultienumValue($fieldValue); + else + $defaultRowValue = $_REQUEST[$field]; + // translate default values to the date/time format for the import file + if( $fieldDef['type'] == 'date' && $this->ifs->dateformat != $timedate->get_date_format() ) + $defaultRowValue = $timedate->swap_formats($defaultRowValue, $this->ifs->dateformat, $timedate->get_date_format()); + + if( $fieldDef['type'] == 'time' && $this->ifs->timeformat != $timedate->get_time_format() ) + $defaultRowValue = $timedate->swap_formats($defaultRowValue, $this->ifs->timeformat, $timedate->get_time_format()); + + if( ($fieldDef['type'] == 'datetime' || $fieldDef['type'] == 'datetimecombo') && $this->ifs->dateformat.' '.$this->ifs->timeformat != $timedate->get_date_time_format() ) + $defaultRowValue = $timedate->swap_formats($defaultRowValue, $this->ifs->dateformat.' '.$this->ifs->timeformat,$timedate->get_date_time_format()); + + if ( in_array($fieldDef['type'],array('currency','float','int','num')) && $this->ifs->num_grp_sep != $current_user->getPreference('num_grp_sep') ) + $defaultRowValue = str_replace($current_user->getPreference('num_grp_sep'), $this->ifs->num_grp_sep,$defaultRowValue); + + if ( in_array($fieldDef['type'],array('currency','float')) && $this->ifs->dec_sep != $current_user->getPreference('dec_sep') ) + $defaultRowValue = str_replace($current_user->getPreference('dec_sep'), $this->ifs->dec_sep,$defaultRowValue); + + $user_currency_symbol = $this->defaultUserCurrency->symbol; + if ( $fieldDef['type'] == 'currency' && $this->ifs->currency_symbol != $user_currency_symbol ) + $defaultRowValue = str_replace($user_currency_symbol, $this->ifs->currency_symbol,$defaultRowValue); + + return $defaultRowValue; + } + + protected function getImportColumns() + { + $importable_fields = $this->bean->get_importable_fields(); + $importColumns = array(); + foreach ($_REQUEST as $name => $value) + { + // only look for var names that start with "fieldNum" + if (strncasecmp($name, "colnum_", 7) != 0) + continue; + + // pull out the column position for this field name + $pos = substr($name, 7); + + if ( isset($importable_fields[$value]) ) + { + // now mark that we've seen this field + $importColumns[$pos] = $value; + } + } + + return $importColumns; + } + + protected function getFieldSanitizer() + { + $ifs = new ImportFieldSanitize(); + $copyFields = array('dateformat','timeformat','timezone','default_currency_significant_digits','num_grp_sep','dec_sep','default_locale_name_format'); + foreach($copyFields as $field) + { + $fieldKey = "importlocale_$field"; + $ifs->$field = $this->importSource->$fieldKey; + } + + $currency = new Currency(); + $currency->retrieve($this->importSource->importlocale_currency); + $ifs->currency_symbol = $currency->symbol; + + return $ifs; + } + + /** + * Sets a translation map from sugar field key to external source key used while importing a row. This allows external sources + * to return a data set that is an associative array rather than numerically indexed. + * + * @param $translator + * @return void + */ + public function setFieldKeyTranslator($translator) + { + $this->sugarToExternalSourceFieldMap = $translator; + } + + /** + * If a bean save is not done for some reason, this method will undo any of the beans that were created + * + * @param array $ids ids of user_last_import records created + */ + protected function _undoCreatedBeans( array $ids ) + { + $focus = new UsersLastImport(); + foreach ($ids as $id) + $focus->undoById($id); + } + + /** + * clean id's when being imported + * + * @param string $string + * @return string + */ + protected function _convertId($string) + { + return preg_replace_callback( + '|[^A-Za-z0-9\-\_]|', + create_function( + // single quotes are essential here, + // or alternative escape all $ as \$ + '$matches', + 'return ord($matches[0]);' + ) , + $string); + } + + public function retrieveAdvancedMapping() + { + $advancedMappingSettings = array(); + + //harvest the dupe index settings + if( isset($_REQUEST['enabled_dupes']) ) + { + $toDecode = html_entity_decode ($_REQUEST['enabled_dupes'], ENT_QUOTES); + $dupe_ind = json_decode($toDecode); + + foreach($dupe_ind as $dupe) + { + $advancedMappingSettings['dupe_'.$dupe] = $dupe; + } + } + + foreach($_REQUEST as $rk=>$rv) + { + //harvest the import locale settings + if(strpos($rk,'portlocale_')>0) + { + $advancedMappingSettings[$rk] = $rv; + } + + } + return $advancedMappingSettings; + } + + public static function getImportableModules() + { + global $beanList; + $importableModules = array(); + foreach ($beanList as $moduleName => $beanName) + { + if( class_exists($beanName) ) + { + $tmp = new $beanName(); + if( isset($tmp->importable) && $tmp->importable ) + { + $label = isset($GLOBALS['app_list_strings']['moduleList'][$moduleName]) ? $GLOBALS['app_list_strings']['moduleList'][$moduleName] : $moduleName; + $importableModules[$moduleName] = $label; + } + } + } + + asort($importableModules); + return $importableModules; + } + + + /** + * Replaces PHP error handler in Step4 + * + * @param int $errno + * @param string $errstr + * @param string $errfile + * @param string $errline + */ + public static function handleImportErrors($errno, $errstr, $errfile, $errline) + { + $GLOBALS['log']->fatal("Caught error: $errstr"); + + if ( !defined('E_DEPRECATED') ) + define('E_DEPRECATED','8192'); + if ( !defined('E_USER_DEPRECATED') ) + define('E_USER_DEPRECATED','16384'); + + // check to see if current reporting level should be included based upon error_reporting() setting, if not + // then just return + if ( !(error_reporting() & $errno) ) + return true; + + switch ($errno) + { + case E_USER_ERROR: + echo "ERROR: [$errno] $errstr on line $errline in file $errfile
\n"; + exit(1); + break; + case E_USER_WARNING: + case E_WARNING: + echo "WARNING: [$errno] $errstr on line $errline in file $errfile
\n"; + break; + case E_USER_NOTICE: + case E_NOTICE: + echo "NOTICE: [$errno] $errstr on line $errline in file $errfile
\n"; + break; + case E_STRICT: + case E_DEPRECATED: + case E_USER_DEPRECATED: + // don't worry about these + //echo "STRICT ERROR: [$errno] $errstr on line $errline in file $errfile
\n"; + break; + default: + echo "Unknown error type: [$errno] $errstr on line $errline in file $errfile
\n"; + break; + } + + return true; + } +} \ No newline at end of file diff --git a/modules/Import/UsersLastImport.php b/modules/Import/UsersLastImport.php index 31079479..05aaaeb6 100644 --- a/modules/Import/UsersLastImport.php +++ b/modules/Import/UsersLastImport.php @@ -106,12 +106,9 @@ class UsersLastImport extends SugarBean * * @param string $user_id user id of the user doing the import */ - public function mark_deleted_by_user_id( - $user_id - ) + public function mark_deleted_by_user_id($user_id) { - $query = "DELETE FROM $this->table_name - WHERE assigned_user_id = '$user_id'"; + $query = "DELETE FROM $this->table_name WHERE assigned_user_id = '$user_id'"; $this->db->query($query,true,"Error marking last imported records deleted: "); } @@ -120,17 +117,12 @@ class UsersLastImport extends SugarBean * * @param string $id specific users_last_import id to undo */ - public function undoById( - $id - ) + public function undoById($id) { global $current_user; - $query1 = "SELECT bean_id, bean_type - FROM users_last_import - WHERE assigned_user_id = '$current_user->id' - AND id = '$id' - AND deleted=0"; + $query1 = "SELECT bean_id, bean_type FROM users_last_import WHERE assigned_user_id = '$current_user->id' + AND id = '$id' AND deleted=0"; $result1 = $this->db->query($query1); if ( !$result1 ) @@ -147,17 +139,12 @@ class UsersLastImport extends SugarBean * * @param string $module module being imported into */ - public function undo( - $module - ) + public function undo($module) { global $current_user; - $query1 = "SELECT bean_id, bean_type - FROM users_last_import - WHERE assigned_user_id = '$current_user->id' - AND import_module = '$module' - AND deleted=0"; + $query1 = "SELECT bean_id, bean_type FROM users_last_import WHERE assigned_user_id = '$current_user->id' + AND import_module = '$module' AND deleted=0"; $result1 = $this->db->query($query1); if ( !$result1 ) @@ -175,10 +162,7 @@ class UsersLastImport extends SugarBean * @param $bean_id * @param $module */ - protected function _deleteRecord( - $bean_id, - $module - ) + protected function _deleteRecord($bean_id,$module) { static $focus; @@ -227,17 +211,12 @@ class UsersLastImport extends SugarBean * * @param string $module module being imported into */ - public static function getBeansByImport( - $module - ) + public static function getBeansByImport($module) { global $current_user; - $query1 = "SELECT DISTINCT bean_type - FROM users_last_import - WHERE assigned_user_id = '$current_user->id' - AND import_module = '$module' - AND deleted=0"; + $query1 = "SELECT DISTINCT bean_type FROM users_last_import WHERE assigned_user_id = '$current_user->id' + AND import_module = '$module' AND deleted=0"; $result1 = $GLOBALS['db']->query($query1); if ( !$result1 ) diff --git a/modules/Import/controller.php b/modules/Import/controller.php index 6be136ba..8a7a3e39 100644 --- a/modules/Import/controller.php +++ b/modules/Import/controller.php @@ -45,6 +45,8 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); require_once("modules/Import/Forms.php"); require_once("include/MVC/Controller/SugarController.php"); +require_once('modules/Import/sources/ImportFile.php'); +require_once('modules/Import/views/ImportListView.php'); class ImportController extends SugarController { @@ -54,8 +56,10 @@ class ImportController extends SugarController public function loadBean() { global $mod_strings; - - $this->bean = loadBean($_REQUEST['import_module']); + + $this->importModule = isset($_REQUEST['import_module']) ? $_REQUEST['import_module'] : ''; + + $this->bean = loadBean($this->importModule); if ( $this->bean ) { if ( !$this->bean->importable ) $this->bean = false; @@ -81,22 +85,121 @@ class ImportController extends SugarController { $this->action_Step1(); } + + function action_mapping() + { + global $mod_strings, $current_user; + $results = array('message' => ''); + // handle publishing and deleting import maps + if(isset($_REQUEST['delete_map_id'])) + { + $import_map = new ImportMap(); + $import_map->mark_deleted($_REQUEST['delete_map_id']); + } + + if(isset($_REQUEST['publish']) ) + { + $import_map = new ImportMap(); + + $import_map = $import_map->retrieve($_REQUEST['import_map_id'], false); + + if($_REQUEST['publish'] == 'yes') + { + $result = $import_map->mark_published($current_user->id,true); + if (!$result) + $results['message'] = $mod_strings['LBL_ERROR_UNABLE_TO_PUBLISH']; + } + elseif( $_REQUEST['publish'] == 'no') + { + // if you don't own this importmap, you do now, unless you have a map by the same name + $result = $import_map->mark_published($current_user->id,false); + if (!$result) + $results['message'] = $mod_strings['LBL_ERROR_UNABLE_TO_UNPUBLISH']; + } + } + + echo json_encode($results); + sugar_cleanup(TRUE); + } + function action_RefreshMapping() + { + global $mod_strings; + require_once('modules/Import/sources/ImportFile.php'); + require_once('modules/Import/views/view.confirm.php'); + $v = new ImportViewConfirm(); + $fileName = $_REQUEST['importFile']; + $delim = $_REQUEST['delim']; + if ($delim == '\t') { + $delim = "\t"; + } + $enclosure = $_REQUEST['qualif']; + $enclosure = html_entity_decode($enclosure, ENT_QUOTES); + $hasHeader = isset($_REQUEST['header']) && !empty($_REQUEST['header']) ? TRUE : FALSE; + + $importFile = new ImportFile( $fileName, $delim, $enclosure, FALSE); + $importFile->setHeaderRow($hasHeader); + $rows = $v->getSampleSet($importFile); + + $ss = new Sugar_Smarty(); + $ss->assign("SAMPLE_ROWS",$rows); + $ss->assign("HAS_HEADER",$hasHeader); + $ss->assign("column_count",$v->getMaxColumnsInSampleSet($rows)); + $ss->assign("MOD",$mod_strings); + $ss->display('modules/Import/tpls/confirm_table.tpl'); + sugar_cleanup(TRUE); + + } + + function action_RefreshTable() + { + $offset = isset($_REQUEST['offset']) ? $_REQUEST['offset'] : 0; + $tableID = isset($_REQUEST['tableID']) ? $_REQUEST['tableID'] : 'errors'; + $has_header = $_REQUEST['has_header'] == 'on' ? TRUE : FALSE; + if($tableID == 'dup') + $tableFilename = ImportCacheFiles::getDuplicateFileName(); + else + $tableFilename = ImportCacheFiles::getErrorRecordsFileName(); + + $if = new ImportFile($tableFilename, ",", '"', FALSE, FALSE); + $if->setHeaderRow($has_header); + $lv = new ImportListView($if,array('offset'=> $offset), $tableID); + $lv->display(FALSE); + + sugar_cleanup(TRUE); + } function action_Step1() { - $this->view = 'step1'; + $fromAdminView = isset($_REQUEST['from_admin_wizard']) ? $_REQUEST['from_admin_wizard'] : FALSE; + if( $this->importModule == 'Administration' || $fromAdminView + ) + { + $this->view = 'step1'; + } + else + $this->view = 'step2'; } function action_Step2() { $this->view = 'step2'; } - + + function action_Confirm() + { + $this->view = 'confirm'; + } + function action_Step3() { $this->view = 'step3'; } - + + function action_DupCheck() + { + $this->view = 'dupcheck'; + } + function action_Step4() { $this->view = 'step4'; @@ -116,6 +219,21 @@ class ImportController extends SugarController { $this->view = 'error'; } + + function action_ExtStep1() + { + $this->view = 'extStep1'; + } + + function action_Extdupcheck() + { + $this->view = 'extdupcheck'; + } + + function action_Extimport() + { + $this->view = 'extimport'; + } function action_GetControl() { diff --git a/modules/Import/language/en_us.lang.php b/modules/Import/language/en_us.lang.php index 7e7de4f1..e12c8a7d 100644 --- a/modules/Import/language/en_us.lang.php +++ b/modules/Import/language/en_us.lang.php @@ -45,18 +45,20 @@ global $timedate; $mod_strings = array ( 'LBL_GOOD_FILE' => 'Import File Read Successfully', - 'LBL_RECORDS_SKIPPED_DUE_TO_ERROR' => 'records were not imported due to error.', + 'LBL_RECORDS_SKIPPED_DUE_TO_ERROR' => 'rows were not imported due to error', 'LBL_UPDATE_SUCCESSFULLY' => 'records updated successfully', - 'LBL_SUCCESSFULLY_IMPORTED' => 'records created successfully', - 'LBL_STEP_4_TITLE' => 'Step 4: Import File', - 'LBL_STEP_5_TITLE' => 'Step 5: View Results', + 'LBL_SUCCESSFULLY_IMPORTED' => 'records were created', + 'LBL_STEP_4_TITLE' => 'Step {0}: Import File', + 'LBL_STEP_5_TITLE' => 'Step {0}: View Import Results', 'LBL_CUSTOM_ENCLOSURE' => 'Fields Qualified By:', 'LBL_ERROR_UNABLE_TO_PUBLISH' => 'Unable to publish. There is another published Import map by the same name.', 'LBL_ERROR_UNABLE_TO_UNPUBLISH' => 'Unable to un-publish a map owned by another user. You own an Import map by the same name.', 'LBL_ERROR_IMPORTS_NOT_SET_UP' => 'Imports aren\'t set up for this module type', - 'LBL_IMPORT_TYPE' => 'Import Action', - 'LBL_IMPORT_BUTTON' => 'Create Records', - 'LBL_UPDATE_BUTTON' => 'Create and Update Records', + 'LBL_IMPORT_TYPE' => 'What would you like to do with the imported data?', + 'LBL_IMPORT_BUTTON' => 'Create new records only', + 'LBL_UPDATE_BUTTON' => 'Create new records and update existing records', + 'LBL_CREATE_BUTTON_HELP' => 'Use this option to create new records. Note: Rows in the import file containing values that match the IDs of existing records will not be imported if the values are mapped to the ID field.', + 'LBL_UPDATE_BUTTON_HELP' => 'Use this option to update existing records. The data in the import file will be matched to existing records based on the record ID in the import file.', 'LBL_ERROR_INVALID_BOOL'=>'Invalid boolean value', 'LBL_NO_ID' => 'ID Required', 'LBL_PRE_CHECK_SKIPPED' => 'Pre-Check skipped', @@ -119,8 +121,10 @@ $mod_strings = array ( 'LBL_IMPORT_MODULE_ERROR_LARGE_FILE_END' => 'Bytes. Change $sugar_config[\'upload_maxsize\'] in config.php', 'LBL_MODULE_NAME' => 'Import', 'LBL_TRY_AGAIN' => 'Try Again', + 'LBL_START_OVER' => 'Start Over', 'LBL_ERROR' => 'Error:', - 'ERR_IMPORT_SYSTEM_ADMININSTRATOR' => 'You cannot import a system administrator user', + 'LBL_IMPORT_ERROR_MAX_REC_LIMIT_REACHED' => 'The import file contains {0} rows. The optimal number of rows is {1}. More rows may slow the import process. Click OK to continue importing. Click Cancel to revise and re-upload the import file.', + 'ERR_IMPORT_SYSTEM_ADMININSTRATOR' => 'You cannot import a system administrator user', 'ERR_MULTIPLE' => 'Multiple columns have been defined with the same field name.', 'ERR_MISSING_REQUIRED_FIELDS' => 'Missing required fields:', 'ERR_MISSING_MAP_NAME' => 'Missing custom mapping name', @@ -129,27 +133,32 @@ $mod_strings = array ( 'LBL_SELECT_FILE' => 'Select file:', 'LBL_CUSTOM' => 'Custom', 'LBL_CUSTOM_CSV' => 'Custom comma delimited file', - 'LBL_CSV' => 'Comma delimited file', + 'LBL_CSV' => 'a file on my computer', + 'LBL_EXTERNAL_SOURCE' => 'an external application or service', 'LBL_TAB' => 'Tab delimited file', 'LBL_CUSTOM_DELIMITED' => 'Custom delimited file', 'LBL_CUSTOM_DELIMITER' => 'Fields Delimited By:', 'LBL_FILE_OPTIONS' => 'File options', 'LBL_CUSTOM_TAB' => 'Custom tab delimited file', 'LBL_DONT_MAP' => '-- Do not map this field --', - 'LBL_STEP_1_TITLE' => 'Step 1: Select Data Source and Import Action', - 'LBL_WHAT_IS' => 'What is the Data Source?', + 'LBL_STEP_MODULE' => 'Which module do you want to import data into?', + 'LBL_STEP_1_TITLE' => 'Step 1: Select Data Source', + 'LBL_CONFIRM_TITLE' => 'Step {0}: Confirm Import File Properties', + 'LBL_CONFIRM_EXT_TITLE' => 'Step {0}: Confirm External Source Properties', + 'LBL_WHAT_IS' => 'My data is in:', 'LBL_MICROSOFT_OUTLOOK' => 'Microsoft Outlook', + 'LBL_MICROSOFT_OUTLOOK_HELP' => 'The custom mappings for Microsoft Outlook rely on the import file being comma-delimited (.csv). If your import file is tab-delimited, the mappings will not be applied as expected.', 'LBL_ACT' => 'Act!', 'LBL_SALESFORCE' => 'Salesforce.com', - 'LBL_MY_SAVED' => 'My Saved Mappings:', + 'LBL_MY_SAVED' => 'To use your saved import settings, select from below:', 'LBL_PUBLISH' => 'Publish', 'LBL_DELETE' => 'Delete', - 'LBL_PUBLISHED_SOURCES' => 'Published Mappings:', + 'LBL_PUBLISHED_SOURCES' => 'To use pre-set import settings, select from below:', 'LBL_UNPUBLISH' => 'Un-Publish', 'LBL_NEXT' => 'Next >', 'LBL_BACK' => '< Back', - 'LBL_STEP_2_TITLE' => 'Step 2: Upload Import File', - 'LBL_HAS_HEADER' => 'Has Header:', + 'LBL_STEP_2_TITLE' => 'Step {0}: Upload Import File', + 'LBL_HAS_HEADER' => 'Header Row:', 'LBL_NUM_1' => '1.', 'LBL_NUM_2' => '2.', 'LBL_NUM_3' => '3.', @@ -203,10 +212,12 @@ $mod_strings = array ( 'LBL_TAB_NUM_1' => 'Launch the application and open the data file', 'LBL_TAB_NUM_2' => 'Select the Save As... or Export... menu option', 'LBL_TAB_NUM_3' => 'Save the file in a TSV or Tab Separated Values format', - 'LBL_STEP_3_TITLE' => 'Step 3: Confirm Fields and Import', - 'LBL_SELECT_FIELDS_TO_MAP' => 'In the list below, select the fields in the import file that should be imported into each field in the system. When you are finished, click Import Now:', - 'LBL_DATABASE_FIELD' => 'Database Field', + 'LBL_STEP_3_TITLE' => 'Step {0}: Confirm Field Mappings', + 'LBL_STEP_DUP_TITLE' => 'Step {0}: Check for Possible Duplicates', + 'LBL_SELECT_FIELDS_TO_MAP' => 'In the list below, select the fields in the import file that should be imported into each field in the system. When you are finished, click Next:', + 'LBL_DATABASE_FIELD' => 'Module Field', 'LBL_HEADER_ROW' => 'Header Row', + 'LBL_HEADER_ROW_OPTION_HELP' => 'Select if the top row of the import file is a Header Row containing field labels.', 'LBL_ROW' => 'Row', 'LBL_SAVE_AS_CUSTOM' => 'Save as Custom Mapping:', 'LBL_SAVE_AS_CUSTOM_NAME' => 'Custom Mapping Name:', @@ -220,30 +231,33 @@ $mod_strings = array ( 'LBL_' => '', 'LBL_CANNOT_OPEN' => 'Cannot open the imported file for reading', 'LBL_NOT_SAME_NUMBER' => 'There were not the same number of fields per line in your file', - 'LBL_NO_LINES' => 'There were no lines in your import file', + 'LBL_NO_LINES' => 'There were no lines detected in your import file. Please make sure there are no empty lines in your file and try again.', 'LBL_FILE_ALREADY_BEEN_OR' => 'The import file has already been processed or does not exist', 'LBL_SUCCESS' => 'Success:', 'LBL_FAILURE' => 'Import Failed:', 'LBL_SUCCESSFULLY' => 'Successfully imported', - 'LBL_LAST_IMPORT_UNDONE' => 'Your last import was undone', + 'LBL_LAST_IMPORT_UNDONE' => 'The import was undone.', 'LBL_NO_IMPORT_TO_UNDO' => 'There was no import to undo.', 'LBL_FAIL' => 'Fail:', 'LBL_RECORDS_SKIPPED' => 'Records skipped because they were missing one or more required fields', 'LBL_IDS_EXISTED_OR_LONGER' => 'Records skipped because the id\'s either existed or were longer than 36 characters', 'LBL_RESULTS' => 'Results', - 'LBL_IMPORT_MORE' => 'Import More', - 'LBL_FINISHED' => 'Return to ', - 'LBL_UNDO_LAST_IMPORT' => 'Undo Last Import', - 'LBL_LAST_IMPORTED'=>'Last Created', + 'LBL_CREATED_TAB' => 'Created Records', + 'LBL_DUPLICATE_TAB' => 'Duplicates', + 'LBL_ERROR_TAB' => 'Errors', + 'LBL_IMPORT_MORE' => 'Import Again', + 'LBL_FINISHED' => 'Finished', + 'LBL_UNDO_LAST_IMPORT' => 'Undo Import', + 'LBL_LAST_IMPORTED'=>'Created', 'ERR_MULTIPLE_PARENTS' => 'You can only have one Parent ID defined', 'LBL_DUPLICATES' => 'Duplicates Found', 'LNK_DUPLICATE_LIST' => 'Download list of duplicates', 'LNK_ERROR_LIST' => 'Download list of errors', - 'LNK_RECORDS_SKIPPED_DUE_TO_ERROR' => 'Download list of records that were not imported', + 'LNK_RECORDS_SKIPPED_DUE_TO_ERROR' => 'Download list of rows that were not imported', 'LBL_UNIQUE_INDEX' => 'Choose index for duplicate comparison', - 'LBL_VERIFY_DUPS' => 'Verify duplicate entries against selected indexes.', - 'LBL_INDEX_USED' => 'Index(es) used:', - 'LBL_INDEX_NOT_USED' => 'Index(es) not used:', + 'LBL_VERIFY_DUPS' => 'To check for existing records matching data in the import file, select the fields to check.', + 'LBL_INDEX_USED' => 'Fields to Check:', + 'LBL_INDEX_NOT_USED' => 'Available Fields:', 'LBL_IMPORT_MODULE_ERROR_NO_MOVE' => 'File was not successfully uploaded. Check the file permissions in your Sugar installation cache directory.', 'LBL_IMPORT_FIELDDEF_ID' => 'Unique ID number', 'LBL_IMPORT_FIELDDEF_RELATE' => 'Name or ID', @@ -270,46 +284,88 @@ $mod_strings = array ( 'LBL_ADD_ROW' => 'Add Field', 'LBL_REMOVE_ROW' => 'Remove Field', 'LBL_DEFAULT_VALUE' => 'Default Value', - 'LBL_SHOW_ADVANCED_OPTIONS' => 'Show Advanced Options', - 'LBL_HIDE_ADVANCED_OPTIONS' => 'Hide Advanced Options', + 'LBL_SHOW_ADVANCED_OPTIONS' => 'View Import File Properties', + 'LBL_HIDE_ADVANCED_OPTIONS' => 'Hide Import File Properties', + 'LBL_SHOW_NOTES' => 'View Notes', + 'LBL_HIDE_NOTES' => 'Hide Notes', 'LBL_SHOW_PREVIEW_COLUMNS' => 'Show Preview Columns', 'LBL_HIDE_PREVIEW_COLUMNS' => 'Hide Preview Columns', - 'LBL_SAVE_MAPPING_AS' => 'Save Mapping As', + 'LBL_SAVE_MAPPING_AS' => 'To save the import settings, provide a name for the saved settings:', 'LBL_OPTION_ENCLOSURE_QUOTE' => 'Single Quote (\')', 'LBL_OPTION_ENCLOSURE_DOUBLEQUOTE' => 'Double Quote (")', 'LBL_OPTION_ENCLOSURE_NONE' => 'None', 'LBL_OPTION_ENCLOSURE_OTHER' => 'Other:', - 'LBL_IMPORT_COMPLETE' => 'Import Complete', + 'LBL_IMPORT_COMPLETE' => 'Exit', + 'LBL_IMPORT_COMPLETED' => 'Import Completed', 'LBL_IMPORT_ERROR' => 'Import Errors Occurred', 'LBL_IMPORT_RECORDS' => 'Importing Records', 'LBL_IMPORT_RECORDS_OF' => 'of', 'LBL_IMPORT_RECORDS_TO' => 'to', - 'LBL_CURRENCY' => 'Currency', + 'LBL_CURRENCY' => 'Currency:', 'LBL_CURRENCY_SIG_DIGITS' => 'Currency Significant Digits', 'LBL_LOCALE_EXAMPLE_NAME_FORMAT' => 'Example', - 'LBL_NUMBER_GROUPING_SEP' => '1000s separator', - 'LBL_DECIMAL_SEP' => 'Decimal symbol', + 'LBL_NUMBER_GROUPING_SEP' => '1000s separator:', + 'LBL_DECIMAL_SEP' => 'Decimal symbol:', 'LBL_LOCALE_DEFAULT_NAME_FORMAT' => 'Name Display Format', 'LBL_LOCALE_EXAMPLE_NAME_FORMAT' => 'Example', 'LBL_LOCALE_NAME_FORMAT_DESC' => '"s" Salutation, "f" First Name, "l" Last Name', - 'LBL_CHARSET' => 'File Encoding', - 'LBL_MY_SAVED_HELP' => 'A saved mapping specifies a previously used combination of a specific data source and a set of database fields to map to the fields in the import file.
Click Publish to make the mapping available to other users.
Click Un-Publish to make the mapping unavailable to other users.', - 'LBL_MY_PUBLISHED_HELP' => 'A published mapping specifies a previously used combination of a specific data source and a set of database fields to map to the fields in the import file.', + 'LBL_CHARSET' => 'File Encoding:', + 'LBL_MY_SAVED_HELP' => 'Use this option to apply your pre-set import settings, including import properties, mappings, and any duplicate check settings, to this import.

Click Delete to delete a mapping for all users.', + 'LBL_MY_SAVED_ADMIN_HELP' => 'Use this option to apply your pre-set import settings, including import properties, mappings, and any duplicate check settings, to this import.

Click Publish to make the mapping available to other users.
Click Un-Publish to make the mapping unavailable to other users.
Click Delete to delete a mapping for all users.', + 'LBL_MY_PUBLISHED_HELP' => 'Use this option to apply pre-set import settings, including import properties, mappings, and any duplicate check settings, to this import.', 'LBL_ENCLOSURE_HELP' => '

The qualifier character is used to enclose the intended field content, including any characters that are used as delimiters.

Example: If the delimiter is a comma (,) and the qualifier is a quotation mark ("),
"Cupertino, California" is imported into one field in the application and appears as Cupertino, California.
If there are no qualifier characters, or if a different character is the qualifier,
"Cupertino, California" is imported into two adjacent fields as "Cupertino and "California".

Note: The import file might not contain any qualifier characters.
The default qualifier character for comma- and tab- delimited files created in Excel is a quotation mark.

', - 'LBL_DELIMITER_COMMA_HELP' => 'Select this option if the character that separates the fields in the import file is a comma, or if the file extension is .csv.', + 'LBL_DELIMITER_COMMA_HELP' => 'Use this option to select and upload a spreadsheet file containing the data that you would like to import. Examples: comma-delimited .csv file or export file from Microsoft Outlook.', 'LBL_DELIMITER_TAB_HELP' => 'Select this option if the character that separates the fields in the import file is a TAB, and the file extension is .txt.', 'LBL_DELIMITER_CUSTOM_HELP' => 'Select this option if the character that separates the fields in the import file is neither a comma or a TAB, and type the character in the adjacent field.', - 'LBL_DATABASE_FIELD_HELP' => 'Select a field from list of all fields existing in the database for the module.', - 'LBL_HEADER_ROW_HELP' => 'These are the field titles in the header row of the import file.', + 'LBL_DATABASE_FIELD_HELP' => 'This column displays all of the fields in the module. Select a field to map to the data in the import file rows.', + 'LBL_HEADER_ROW_HELP' => 'This column displays the labels in the header row of the import file.', 'LBL_DEFAULT_VALUE_HELP' => 'Indicate a value to use for the field in the created or updated record if the field in the import file contains no data.', - 'LBL_ROW_HELP' => 'This is the data in the first non-header row of the import file.', - 'LBL_SAVE_MAPPING_HELP' => 'Enter a name for the set of database fields used above for mapping to the fields in the import file fields.
The set of fields, including the order of the fields and the data souce selected in Import Step 1, will be saved during the import attempt.
The saved mapping can then be selected in Import Step 1 to for another import.', - 'LBL_IMPORT_FILE_SETTINGS_HELP' => 'Specify the settings in the import file to ensure that the data is imported
correctly. These settings will not override your preferences. The records
created or updated will contain the settings specified in your My Account page.', + 'LBL_ROW_HELP' => 'This column displays the data in the first non-header row of the import file. If the header row labels are appearing in this column, click Back to specify the header row in the Import File Properties.', + 'LBL_SAVE_MAPPING_HELP' => 'Enter a name to save the import settings, including the field mappings and indexes used for the duplicate check. Saved import settings can be used for future imports.', + 'LBL_IMPORT_FILE_SETTINGS_HELP' => 'During the upload of your import file, some file properties might have been automatically detected. View and manage these properties, as
necessary. Note: The settings provided here pertain to this import
and will not override your overall User Settings.', 'LBL_IMPORT_FILE_SETTINGS' => 'Import File Settings', - 'LBL_VERIFY_DUPLCATES_HELP' => 'Select the fields in the import file to be used for the duplicate check.
If data in the selected fields matches data in fields in existing records, new records will not be created for the rows containing the duplicate field data.
The rows containing duplicate field data will be identified in the Import Results.', + 'LBL_VERIFY_DUPLCATES_HELP' => 'Find existing records in the system that could be considered duplicates of the records about to be imported by performing a duplicate check for matching data. Fields dragged into the "Check Data" column will be used for the duplicate check. The rows in your import file containing matching data will be listed within the next page, and you will be able to select which rows to import', 'LBL_IMPORT_STARTED' => 'Import Started:', 'LBL_IMPORT_FILE_SETTINGS' => 'Import File Settings', 'LBL_RECORD_CANNOT_BE_UPDATED' => 'The record could not be updated due to a permissions issue', - 'LBL_DELETE_MAP_CONFIRMATION' => 'Are you sure you want to delete this mapping?', + 'LBL_DELETE_MAP_CONFIRMATION' => 'Are you sure you want to delete this saved set of import settings?', + 'LBL_THIRD_PARTY_CSV_SOURCES' => 'If the import file data was exported from any of the following sources, select which one.', + 'LBL_THIRD_PARTY_CSV_SOURCES_HELP' => 'Select the source to automatically apply custom mappings in order to simplify the mapping process (next step).', + 'LBL_EXTERNAL_SOURCE_HELP' => 'Use this option to import data directly from an external application or service, such as Gmail.', + 'LBL_EXAMPLE_FILE' => 'Download Import File Template', + 'LBL_CONFIRM_IMPORT' => 'You have selected to update records during the import process. Updates made to existing records cannot be undone. However, records created during the import process can be undone (deleted), if desired. Click Cancel to select to create new records only, or click OK to continue.', + 'LBL_CONFIRM_MAP_OVERRIDE' => 'Warning: You have already selected a custom mapping for this import, do you want to continue?', + 'LBL_EXTERNAL_FIELD' => 'External Field', + 'LBL_SAMPLE_URL_HELP' => 'Download a sample import file containing a header row of the module fields. The file can be used as a template to create an import file containing the data that you would like to import.', + 'LBL_AUTO_DETECT_ERROR' => 'The field delimiter and qualifier in the import file could not be detected. Please verify the settings in the Import File Properties.', + 'LBL_MIME_TYPE_ERROR_1' => 'The selected file does not appear to contain a delimited list. Please check the file type. We recommend comma-delimited files (.csv).', + 'LBL_MIME_TYPE_ERROR_2' => 'To proceed with importing the selected file, click OK. To upload a new file, click Try Again', + 'LBL_FIELD_DELIMETED_HELP' => 'The field delimiter specifies the character used to separate the field columns.', + 'LBL_FILE_UPLOAD_WIDGET_HELP' => 'Select a file containing data that is separated by a delimiter, such as a comma- or tab- delimited file. Files of the type .csv are recommended.', + 'LBL_EXTERNAL_ERROR_NO_SOURCE' => 'Unable to retrieve source adapter, please try again later.', + 'LBL_EXTERNAL_ERROR_FEED_CORRUPTED' => 'Unable to retrieve external feed, please try again later.', + 'LBL_ADD_FIELD_HELP' => 'Use this option to add a value to a field in all records created and/or updated. Select the field and then enter or select a value for that field in the Default Value column.', + 'LBL_MISSING_HEADER_ROW' => 'No Header Row Found', + 'LBL_CANCEL' => 'Cancel', + 'LBL_SELECT_DS_INSTRUCTION' => 'Ready to start importing? Select the source of the data that you would like to import.', + 'LBL_SELECT_UPLOAD_INSTRUCTION' => 'Select a file on your computer that contains the data that you would like to import, or download the template to get a head start on creating the import file.', + 'LBL_SELECT_PROPERTY_INSTRUCTION' => 'Here is how the the first several rows of the import file appear with the detected file properties. If a header row was detected, it is displayed in the top row of the table. View the import file properties to make changes to the detected properties and to set additional properties. Updating the settings will update the data appearing in the table.', + 'LBL_SELECT_MAPPING_INSTRUCTION' => 'The table below contains all of the fields in the module that can be mapped to the data in the import file. If the file contains a header row, the columns in the file have been mapped to matching fields. Check the mappings to make sure that they are what you expect, and make changes, as necessary. To help you check the mappings, Row 1 displays the data in the file. Be sure to map to all of the required fields (noted by an asterisk).', + 'LBL_SELECT_DUPLICATE_INSTRUCTION' => 'To avoid creating duplicate records, select which of the mapped fields you would like to use to perform a duplicate check while data is being imported. Values within existing records in the selected fields will be checked against the data in the import file. If matching data is found, the rows in the import file containing the data will be displayed along with the import results (next page). You will then be able to select which of these rows to continue importing.', + 'LBL_EXT_SOURCE_SIGN_IN' => 'Sign In', + 'LBL_DUP_HELP' => 'Here are the rows in the import file that were not imported because they contain data that matches values in existing records based on the duplicate check. The data that matches is highlighted. To re-import these rows, download the list, make changes and click Import Again.', + 'LBL_DESELECT' => 'deselect', + 'LBL_SUMMARY' => 'Summary', + 'LBL_OK' => 'OK', + 'LBL_ERROR_HELP' => 'Here are the rows in the import file that were not imported due to errors. To re-import these rows, download the list, make changes and click Import Again', + 'LBL_EXTERNAL_MAP_HELP' => 'The table below contains the fields in the external source and the module fields to which they are mapped. Check the mappings to make sure that they are what you expect, and make changes, as necessary. Be sure to map to all of the required fields (noted by an asterisk).', + 'LBL_EXTERNAL_MAP_NOTE' => 'The import will be attempted for contacts within all Google Contacts groups.', + 'LBL_EXTERNAL_MAP_NOTE_SUB' => 'The User Names of the newly created users will be the Full Names of the Google Contact by default. The User Names can be changed after the user records are created.', + 'LBL_EXTERNAL_MAP_SUB_HELP' => 'Click Import Now to begin the import. Records will only be created for entries that include last names. Records will not be created for data identified as duplicate based on names and/or email addresses matching existing records.', + 'LBL_EXTERNAL_FIELD_TOOLTIP' => 'This column displays the fields in the external source containing data that will be used to create new records.', + 'LBL_EXTERNAL_DEFAULT_TOOPLTIP' => 'Indicate a value to use for the field in the created record if the field in the external source contains no data.', + 'LBL_EXTERNAL_ASSIGNED_TOOLTIP' => 'To assign the new records to a user other than yourself, use the Default Value column to select a different user.', + 'LBL_EXTERNAL_TEAM_TOOLTIP' => 'To assign the new records to teams other than your default team(s), use the Default Value column to select different teams.', + 'LBL_SIGN_IN_HELP' => 'To enable this service, please sign in under the External Accounts tab within your user settings page.' ); ?> diff --git a/modules/Import/ImportMap.php b/modules/Import/maps/ImportMap.php similarity index 80% rename from modules/Import/ImportMap.php rename to modules/Import/maps/ImportMap.php index fe2f3cfb..44250e0b 100644 --- a/modules/Import/ImportMap.php +++ b/modules/Import/maps/ImportMap.php @@ -352,6 +352,60 @@ class ImportMap extends SugarBean return $obj_arr; } + /** + * set and get field elements in request field to and from user preferences + * + * @param array $fields_array + * @return array $obj_arr + */ + public function set_get_import_wizard_fields($ForceValsArr = '') + { + global $current_user; + $set = false; + //list of field values we track during import wizard + $import_step_fields = array( + //step1 + // 'import_module', 'source', 'custom_enclosure', 'custom_enclosure_other', 'custom_delimiter', 'type', + //step2 + // 'custom_delimiter', 'custom_enclosure', 'type', 'source', 'source_id', 'import_module', 'has_header', + //step3 + 'display_tabs_def','custom_delimiter', 'custom_enclosure', 'import_type', 'source', 'source_id', 'import_module', 'has_header', 'importlocale_charset', + 'importlocale_dateformat', 'importlocale_timeformat', 'importlocale_timezone', 'importlocale_currency', + 'importlocale_default_currency_significant_digits', 'importlocale_num_grp_sep', 'importlocale_dec_sep', + ' importlocale_default_locale_name_format'); + + //retrieve user preferences and populate preference array + $preference_values_str = $current_user->getPreference('field_values', 'import'); + $preference_values = json_decode($preference_values_str,true); + + foreach ($import_step_fields as $val){ + //overwrite preference array with new values from request if the value is different or new + if((isset($_REQUEST[$val]) && !isset($preference_values[$val])) || (isset($_REQUEST[$val]) && $preference_values[$val] != $_REQUEST[$val])){ + $preference_values[$val] = $_REQUEST[$val]; + $set = true; + } + } + + //force the values to passed in array if array is set + if(!empty($ForceValsArr) && is_array($ForceValsArr)){ + foreach ($ForceValsArr as $forceKey=>$forceVal){ + $preference_values[$forceKey] = $forceVal; + $set = true; + } + } + + //set preferences if any changes were made and return the new array + if($set){ + $preference_values_str = json_encode($preference_values); + $current_user->setPreference('field_values', $preference_values_str, 0, 'import'); + } + if(empty($preference_values)){ + return array(); + } + + return $preference_values; + } + } diff --git a/modules/Import/ImportMapAct.php b/modules/Import/maps/ImportMapAct.php similarity index 98% rename from modules/Import/ImportMapAct.php rename to modules/Import/maps/ImportMapAct.php index 3a5f4a27..f12b0303 100644 --- a/modules/Import/ImportMapAct.php +++ b/modules/Import/maps/ImportMapAct.php @@ -42,7 +42,7 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); * All Rights Reserved. ********************************************************************************/ -require_once('modules/Import/ImportMapOther.php'); +require_once('modules/Import/maps/ImportMapOther.php'); class ImportMapAct extends ImportMapOther { diff --git a/modules/Import/ImportMapCsv.php b/modules/Import/maps/ImportMapCsv.php similarity index 97% rename from modules/Import/ImportMapCsv.php rename to modules/Import/maps/ImportMapCsv.php index 306f297e..b0c0ab05 100644 --- a/modules/Import/ImportMapCsv.php +++ b/modules/Import/maps/ImportMapCsv.php @@ -42,7 +42,7 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); * All Rights Reserved. ********************************************************************************/ -require_once('modules/Import/ImportMapOther.php'); +require_once('modules/Import/maps/ImportMapOther.php'); class ImportMapCsv extends ImportMapOther { diff --git a/modules/Import/maps/ImportMapGoogle.php b/modules/Import/maps/ImportMapGoogle.php new file mode 100644 index 00000000..a1023cd1 --- /dev/null +++ b/modules/Import/maps/ImportMapGoogle.php @@ -0,0 +1,99 @@ + array('sugar_key' => 'first_name', 'sugar_label' => '', 'default_label' => 'Given Name'), + 'last_name' => array('sugar_key' => 'last_name', 'sugar_label' => '', 'default_label' => 'Family Name'), + 'birthday' => array('sugar_key' => 'birthdate', 'sugar_label' => '', 'default_label' => 'Birthday'), + 'title' => array('sugar_key' => 'title', 'sugar_label' => '', 'default_label' => 'Title'), + 'notes' => array('sugar_key' => 'description', 'sugar_label' => '', 'default_label' => 'Notes'), + + 'alt_address_street' => array('sugar_key' => 'alt_address_street', 'sugar_label' => '', 'default_label' => 'Home Street'), + 'alt_address_postcode' => array('sugar_key' => 'alt_address_postalcode', 'sugar_label' => '', 'default_label' => 'Home Postcode'), + 'alt_address_city' => array('sugar_key' => 'alt_address_city', 'sugar_label' => '', 'default_label' => 'Home City'), + 'alt_address_state' => array('sugar_key' => 'alt_address_state', 'sugar_label' => '', 'default_label' => 'Home State'), + 'alt_address_country' => array('sugar_key' => 'alt_address_country', 'sugar_label' => '', 'default_label' => 'Home Country'), + + 'primary_address_street' => array('sugar_key' => 'primary_address_street', 'sugar_label' => '', 'default_label' => 'Work Street'), + 'primary_address_postcode' => array('sugar_key' => 'primary_address_postalcode', 'sugar_label' => '', 'default_label' => 'Work Postcode'), + 'primary_address_city' => array('sugar_key' => 'primary_address_city', 'sugar_label' => '', 'default_label' => 'Work City'), + 'primary_address_state' => array('sugar_key' => 'primary_address_state', 'sugar_label' => '', 'default_label' => 'Work State'), + 'primary_address_country' => array('sugar_key' => 'primary_address_country', 'sugar_label' => '', 'default_label' => 'Work Country'), + + 'phone_main' => array('sugar_key' => 'phone_other', 'sugar_label' => '', 'default_label' => 'Main Phone'), + 'phone_mobile' => array('sugar_key' => 'phone_mobile', 'sugar_label' => '', 'default_label' => 'Mobile Phone'), + 'phone_home' => array('sugar_key' => 'phone_home', 'sugar_label' => '', 'default_label' => 'Home phone'), + 'phone_work' => array('sugar_key' => 'phone_work', 'sugar_label' => '', 'default_label' => 'Work phone'), + 'phone_fax' => array('sugar_key' => 'phone_fax', 'sugar_label' => '', 'default_label' => 'Fax phone'), + + 'email1' => array('sugar_key' => 'email1', 'sugar_label' => 'LBL_EMAIL_ADDRESS', 'default_label' => 'Email Address'), + 'email2' => array('sugar_key' => 'email2', 'sugar_label' => 'LBL_OTHER_EMAIL_ADDRESS', 'default_label' => 'Other Email'), + + 'assigned_user_name' => array('sugar_key' => 'assigned_user_name', 'sugar_help_key' => 'LBL_EXTERNAL_ASSIGNED_TOOLTIP', 'sugar_label' => 'LBL_ASSIGNED_TO_NAME', 'default_label' => 'Assigned To'), + 'team_name' => array('sugar_key' => 'team_name', 'sugar_help_key' => 'LBL_EXTERNAL_TEAM_TOOLTIP','sugar_label' => 'LBL_TEAMS', 'default_label' => 'Teams'), + ); + + if($module == 'Users') + { + $return_array['status'] = array('sugar_key' => 'status', 'sugar_label' => '', 'default_label' => 'Status'); + $return_array['full_name'] = array('sugar_key' => 'user_name', 'sugar_label' => '', 'default_label' => 'Full Name'); + } + return $return_array; + } +} + + +?> diff --git a/modules/Import/ImportMapOther.php b/modules/Import/maps/ImportMapOther.php similarity index 100% rename from modules/Import/ImportMapOther.php rename to modules/Import/maps/ImportMapOther.php diff --git a/modules/Import/ImportMapOutlook.php b/modules/Import/maps/ImportMapOutlook.php similarity index 98% rename from modules/Import/ImportMapOutlook.php rename to modules/Import/maps/ImportMapOutlook.php index 14a2f1a9..8b01ab24 100644 --- a/modules/Import/ImportMapOutlook.php +++ b/modules/Import/maps/ImportMapOutlook.php @@ -42,7 +42,7 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); * All Rights Reserved. ********************************************************************************/ -require_once('modules/Import/ImportMapOther.php'); +require_once('modules/Import/maps/ImportMapOther.php'); class ImportMapOutlook extends ImportMapOther { diff --git a/modules/Import/ImportMapSalesforce.php b/modules/Import/maps/ImportMapSalesforce.php similarity index 97% rename from modules/Import/ImportMapSalesforce.php rename to modules/Import/maps/ImportMapSalesforce.php index 49528cbd..c8f18afc 100644 --- a/modules/Import/ImportMapSalesforce.php +++ b/modules/Import/maps/ImportMapSalesforce.php @@ -42,7 +42,7 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); * All Rights Reserved. ********************************************************************************/ -require_once('modules/Import/ImportMapOther.php'); +require_once('modules/Import/maps/ImportMapOther.php'); class ImportMapSalesforce extends ImportMapOther { @@ -127,6 +127,7 @@ class ImportMapSalesforce extends ImportMapOther "Billing Address Line2"=>"billing_address_street_3", "Billing City"=>"billing_address_city", "Billing State"=>"billing_address_state", + "Billing State/Province"=>"billing_address_state", "Billing Zip/Postal Code"=>"billing_address_postalcode", "Billing Country"=>"billing_address_country", "Shipping Street"=>"shipping_address_street", @@ -139,6 +140,7 @@ class ImportMapSalesforce extends ImportMapOther "Phone"=>"phone_office", "Fax"=>"phone_fax", "Website"=>"website", + "Created Date"=>"date_entered", ); break; default: diff --git a/modules/Import/ImportMapTab.php b/modules/Import/maps/ImportMapTab.php similarity index 97% rename from modules/Import/ImportMapTab.php rename to modules/Import/maps/ImportMapTab.php index 63fabb13..b7a222fe 100644 --- a/modules/Import/ImportMapTab.php +++ b/modules/Import/maps/ImportMapTab.php @@ -42,7 +42,7 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); * All Rights Reserved. ********************************************************************************/ -require_once('modules/Import/ImportMapOther.php'); +require_once('modules/Import/maps/ImportMapOther.php'); class ImportMapTab extends ImportMapOther { diff --git a/modules/Import/sources/ExternalSourceEAPMAdapter.php b/modules/Import/sources/ExternalSourceEAPMAdapter.php new file mode 100644 index 00000000..12ed6191 --- /dev/null +++ b/modules/Import/sources/ExternalSourceEAPMAdapter.php @@ -0,0 +1,157 @@ + 'UTF-8', + 'importlocale_dateformat' => 'Y-m-d', + 'importlocale_timeformat' => 'H:i', + 'importlocale_timezone' => '', + 'importlocale_currency' => '', + 'importlocale_default_currency_significant_digits' => '', + 'importlocale_num_grp_sep' => '', + 'importlocale_dec_sep' => '', + 'importlocale_default_locale_name_format' => ''); + + + public function __construct() + { + global $current_user, $locale; + + $this->_localeSettings['importlocale_num_grp_sep'] = $current_user->getPreference('num_grp_sep'); + $this->_localeSettings['importlocale_dec_sep'] = $current_user->getPreference('dec_sep'); + $this->_localeSettings['importlocale_default_currency_significant_digits'] = $locale->getPrecedentPreference('default_currency_significant_digits', $current_user); + $this->_localeSettings['importlocale_default_locale_name_format'] = $locale->getLocaleFormatMacro($current_user); + $this->_localeSettings['importlocale_currency'] = $locale->getPrecedentPreference('currency', $current_user); + $this->_localeSettings['importlocale_timezone'] = $current_user->getPreference('timezone'); + + $this->setSourceName(); + } + /** + * Return a feed of google contacts using the EAPM and Connectors farmework. + * + * @throws Exception + * @param $maxResults + * @return array + */ + public function loadDataSet($maxResults = 0) + { + if ( !$eapmBean = EAPM::getLoginInfo($this->_eapmName,true) ) + { + throw new Exception('Authentication error with Google Contacts EAPM.'); + } + + $api = ExternalAPIFactory::loadAPI($this->_eapmName); + $api->loadEAPM($eapmBean); + $conn = $api->getConnector(); + + $feed = $conn->getList(array('maxResults' => $maxResults, 'startIndex' => $this->_offset)); + if($feed !== FALSE) + { + $this->_totalRecordCount = $feed['totalResults']; + $this->_recordSet = $feed['records']; + } + else + { + throw new Exception("Unable to retrieve {$this->_eapmName} feed."); + } + } + + public function getHeaderColumns() + { + return ''; + } + + public function getTotalRecordCount() + { + return $this->_totalRecordCount; + } + + public function setSourceName($sourceName = '') + { + $this->_sourcename = $this->_eapmName; + } + + //Begin Implementation for SPL's Iterator interface + public function current() + { + $this->_currentRow = current($this->_recordSet); + return $this->_currentRow; + } + + public function key() + { + return key($this->_recordSet); + } + + public function rewind() + { + reset($this->_recordSet); + } + + public function next() + { + $this->_rowsCount++; + next($this->_recordSet); + } + + public function valid() + { + return (current($this->_recordSet) !== FALSE); + } +} + diff --git a/modules/Import/sources/ImportDataSource.php b/modules/Import/sources/ImportDataSource.php new file mode 100644 index 00000000..5227b1ee --- /dev/null +++ b/modules/Import/sources/ImportDataSource.php @@ -0,0 +1,345 @@ +_sourcename = $sourceName; + } + + + /** + * Set the current offset. + * + * @param $offset + * @return void + */ + public function setCurrentOffset($offset) + { + $this->_offset = $offset; + } + + /** + * Return the current offset + * + * @return int + */ + public function getCurrentOffset() + { + return $this->_offset; + } + + /** + * Return the current data set loaded. + * + * @return array + */ + public function getDataSet() + { + return $this->_dataSet; + } + + /** + * Add this row to the UsersLastImport table + * + * @param string $import_module name of the module we are doing the import into + * @param string $module name of the bean we are creating for this import + * @param string $id id of the recorded created in the $module + */ + public static function writeRowToLastImport($import_module, $module, $id) + { + // cache $last_import instance + static $last_import; + + if ( !($last_import instanceof UsersLastImport) ) + $last_import = new UsersLastImport(); + + $last_import->id = null; + $last_import->deleted = null; + $last_import->assigned_user_id = $GLOBALS['current_user']->id; + $last_import->import_module = $import_module; + if ( $module == 'Case' ) + $module = 'aCase'; + + $last_import->bean_type = $module; + $last_import->bean_id = $id; + return $last_import->save(); + } + + + /** + * Writes the row out to the ImportCacheFiles::getErrorFileName() file + * + * @param $error string + * @param $fieldName string + * @param $fieldValue mixed + */ + public function writeError($error, $fieldName, $fieldValue) + { + $fp = sugar_fopen(ImportCacheFiles::getErrorFileName(),'a'); + fputcsv($fp,array($error,$fieldName,$fieldValue,$this->_rowsCount)); + fclose($fp); + + if ( !$this->_rowCountedForErrors ) + { + $this->_errorCount++; + $this->_rowCountedForErrors = true; + $this->writeErrorRecord($this->formatErrorMessage($error, $fieldName, $fieldValue)); + } + } + + protected function formatErrorMessage($error, $fieldName, $fieldValue) + { + global $current_language; + $mod_strings = return_module_language($current_language, 'Import'); + return "{$mod_strings['LBL_ERROR']} $error
". + "{$mod_strings['LBL_FIELD_NAME']} $fieldName
" . + "{$mod_strings['LBL_VALUE']} $fieldValue
"; + } + public function resetRowErrorCounter() + { + $this->_rowCountedForErrors = false; + } + + /** + * Writes the totals and filename out to the ImportCacheFiles::getStatusFileName() file + */ + public function writeStatus() + { + $fp = sugar_fopen(ImportCacheFiles::getStatusFileName(),'a'); + $statusData = array($this->_rowsCount,$this->_errorCount,$this->_dupeCount, + $this->_createdCount,$this->_updatedCount,$this->_sourcename); + fputcsv($fp, $statusData); + fclose($fp); + } + + /** + * Writes the row out to the ImportCacheFiles::getDuplicateFileName() file + */ + public function markRowAsDuplicate($field_names=array()) + { + $fp = sugar_fopen(ImportCacheFiles::getDuplicateFileName(),'a'); + fputcsv($fp, $this->_currentRow); + fclose($fp); + + //if available, grab the column number based on passed in field_name + if(!empty($field_names)) + { + $colkey = ''; + $colnums = array(); + + //REQUEST should have the field names in order as they appear in the row to be written, get the key values + //of passed in fields into an array + foreach($field_names as $fv) + { + $fv = trim($fv); + if(empty($fv) || $fv == 'delete') + continue; + $new_keys = array_keys($_REQUEST, $fv); + $colnums = array_merge($colnums,$new_keys); + } + + + //if values were found, process for number position + if(!empty($colnums)) + { + //foreach column, strip the 'colnum_' prefix to the get the column key value + foreach($colnums as $column_key) + { + if(strpos($column_key,'colnum_') == 0) + { + $colkey = substr($column_key,7); + } + + //if we have the column key, then lets add a span tag with styling reference to the original value + if(!empty($colkey)) + { + $hilited_val = $this->_currentRow[$colkey]; + $this->_currentRow[$colkey]= ''.$hilited_val.''; + } + } + } + } + + //add the row (with or without stylings) to the list view, this will get displayed to the user as a list of duplicates + $fdp = sugar_fopen(ImportCacheFiles::getDuplicateFileDisplayName(),'a'); + fputcsv($fdp, $this->_currentRow); + fclose($fdp); + + //increment dupecount + $this->_dupeCount++; + } + + /** + * Marks whether this row created a new record or not + * + * @param $createdRecord bool true if record is created, false if it is just updated + */ + public function markRowAsImported($createdRecord = true) + { + if ( $createdRecord ) + ++$this->_createdCount; + else + ++$this->_updatedCount; + } + + /** + * Writes the row out to the ImportCacheFiles::getErrorRecordsFileName() file + */ + public function writeErrorRecord($errorMessage = '') + { + $rowData = !$this->_currentRow ? array() : $this->_currentRow; + $fp = sugar_fopen(ImportCacheFiles::getErrorRecordsFileName(),'a'); + $fpNoErrors = sugar_fopen(ImportCacheFiles::getErrorRecordsWithoutErrorFileName(),'a'); + + //Write records only for download without error message. + fputcsv($fpNoErrors, $rowData); + + //Add the error message to the first column + array_unshift($rowData, $errorMessage); + fputcsv($fp, $rowData); + + fclose($fp); + fclose($fpNoErrors); + } + + public function __get($var) + { + if( isset($_REQUEST[$var]) ) + return $_REQUEST[$var]; + else if( isset($this->_localeSettings[$var]) ) + return $this->_localeSettings[$var]; + else + return $this->$var; + } + +} + diff --git a/modules/Import/sources/ImportFile.php b/modules/Import/sources/ImportFile.php new file mode 100644 index 00000000..aa45f994 --- /dev/null +++ b/modules/Import/sources/ImportFile.php @@ -0,0 +1,448 @@ +fatal("ImportFile detected attempt to access to the following file not within the sugar upload dir: $filename"); + return null; + } + + // turn on auto-detection of line endings to fix bug #10770 + ini_set('auto_detect_line_endings', '1'); + + $this->_fp = sugar_fopen($filename,'r'); + $this->_sourcename = $filename; + $this->_deleteFile = $deleteFile; + $this->_delimiter = ( empty($delimiter) ? ',' : $delimiter ); + if ($this->_delimiter == '\t') { + $this->_delimiter = "\t"; + } + $this->_enclosure = ( empty($enclosure) ? '' : trim($enclosure) ); + $this->setFpAfterBOM(); + } + + /** + * Remove the BOM (Byte Order Mark) from the beginning of the import row if it exists + * @return void + */ + private function setFpAfterBOM() + { + if($this->_fp === FALSE) + return; + + rewind($this->_fp); + $bomCheck = fread($this->_fp, 3); + if($bomCheck != pack("CCC",0xef,0xbb,0xbf)) { + rewind($this->_fp); + } + } + /** + * Destructor + * + * Deletes $_importFile if $_deleteFile is true + */ + public function __destruct() + { + if ( $this->_deleteFile && $this->fileExists() ) { + fclose($this->_fp); + //Make sure the file exists before unlinking + if(file_exists($this->_sourcename)) { + unlink($this->_sourcename); + } + } + + ini_restore('auto_detect_line_endings'); + } + + /** + * Returns true if the filename given exists and is readable + * + * @return bool + */ + public function fileExists() + { + return !$this->_fp ? false : true; + } + + /** + * Gets the next row from $_importFile + * + * @return array current row of file + */ + public function getNextRow() + { + $this->_currentRow = FALSE; + + if (!$this->fileExists()) + return false; + + // explode on delimiter instead if enclosure is an empty string + if ( empty($this->_enclosure) ) { + $row = explode($this->_delimiter,rtrim(fgets($this->_fp, 8192),"\r\n")); + if ($row !== false && !( count($row) == 1 && trim($row[0]) == '') ) + $this->_currentRow = $row; + else + return false; + } + else { + $row = fgetcsv($this->_fp, 8192, $this->_delimiter, $this->_enclosure); + if ($row !== false && $row != array(null)) + $this->_currentRow = $row; + else + return false; + } + + // Bug 26219 - Convert all line endings to the same style as PHP_EOL + foreach ( $this->_currentRow as $key => $value ) { + // use preg_replace instead of str_replace as str_replace may cause extra lines on Windows + $this->_currentRow[$key] = preg_replace("[\r\n|\n|\r]", PHP_EOL, $value); + } + + $this->_rowsCount++; + + return $this->_currentRow; + } + + /** + * Returns the number of fields in the current row + * + * @return int count of fiels in the current row + */ + public function getFieldCount() + { + return count($this->_currentRow); + } + + /** + * Determine the number of lines in this file. + * + * @return int + */ + public function getNumberOfLinesInfile() + { + $lineCount = 0; + + if ($this->_fp ) + { + rewind($this->_fp); + while( !feof($this->_fp) ) + { + if( fgets($this->_fp) !== FALSE) + $lineCount++; + } + //Reset the fp to after the bom if applicable. + $this->setFpAfterBOM(); + } + + return $lineCount; + } + + //TODO: Add auto detection for field delim and qualifier properteis. + public function autoDetectCSVProperties() + { + // defaults + $this->_delimiter = ","; + $this->_enclosure = '"'; + + $this->_detector = new CsvAutoDetect($this->_sourcename); + + $delimiter = $enclosure = false; + + $ret = $this->_detector->getCsvSettings($delimiter, $enclosure); + if ($ret) + { + $this->_delimiter = $delimiter; + $this->_enclosure = $enclosure; + return TRUE; + } + else + { + return FALSE; + } + } + + public function getFieldDelimeter() + { + return $this->_delimiter; + } + + public function getFieldEnclosure() + { + return $this->_enclosure; + } + + public function autoDetectCharacterSet() + { + global $locale; + + $this->setFpAfterBOM(); + + //Retrieve a sample set of data + $rows = array(); + + $user_charset = $locale->getExportCharset(); + $system_charset = $locale->default_export_charset; + $other_charsets = 'UTF-8, UTF-7, ASCII, CP1252, EUC-JP, SJIS, eucJP-win, SJIS-win, JIS, ISO-2022-JP'; + $detectable_charsets = "UTF-8, {$user_charset}, {$system_charset}, {$other_charsets}"; + // Bug 26824 - mb_detect_encoding() thinks CP1252 is IS0-8859-1, so use that instead in the encoding list passed to the function + $detectable_charsets = str_replace('CP1252','ISO-8859-1',$detectable_charsets); + $charset_for_import = $user_charset; //We will set the default import charset option by user's preference. + $able_to_detect = function_exists('mb_detect_encoding'); + for ( $i = 0; $i < 3; $i++ ) + { + $rows[$i] = $this->getNextRow(); + if(!empty($rows[$i]) && $able_to_detect) + { + foreach($rows[$i] as & $temp_value) + { + $current_charset = mb_detect_encoding($temp_value, $detectable_charsets); + if(!empty($current_charset) && $current_charset != "UTF-8") + { + $temp_value = $locale->translateCharset($temp_value, $current_charset);// we will use utf-8 for displaying the data on the page. + $charset_for_import = $current_charset; + //set the default import charset option according to the current_charset. + //If it is not utf-8, tt may be overwritten by the later one. So the uploaded file should not contain two types of charset($user_charset, $system_charset), and I think this situation will not occur. + } + } + } + } + + //Reset the fp to after the bom if applicable. + $this->setFpAfterBOM(); + + return $charset_for_import; + + } + + public function getDateFormat() + { + if ($this->_detector) { + $this->_date_format = $this->_detector->getDateFormat(); + } + + return $this->_date_format; + } + + public function getTimeFormat() + { + if ($this->_detector) { + $this->_time_format = $this->_detector->getTimeFormat(); + } + + return $this->_time_format; + } + + public function setHeaderRow($hasHeader) + { + $this->_hasHeader = $hasHeader; + } + + public function hasHeaderRow($autoDetect = TRUE) + { + if($autoDetect) + { + if (!isset($_REQUEST['import_module'])) + return FALSE; + + $module = $_REQUEST['import_module']; + + $ret = FALSE; + $heading = FALSE; + + if ($this->_detector) + $ret = $this->_detector->hasHeader($heading, $module); + + if ($ret) + $this->_hasHeader = $heading; + } + return $this->_hasHeader; + } + + public function setImportFileMap($map) + { + $this->_importFile = $map; + $importMapProperties = array('_delimiter' => 'delimiter','_enclosure' => 'enclosure', '_hasHeader' => 'has_header'); + //Inject properties from the import map + foreach($importMapProperties as $k => $v) + { + $this->$k = $map->$v; + } + } + + //Begin Implementation for SPL's Iterator interface + public function key() + { + return $this->_rowsCount; + } + + public function current() + { + return $this->_currentRow; + } + + public function next() + { + $this->getNextRow(); + } + + public function valid() + { + return $this->_currentRow !== FALSE; + } + + public function rewind() + { + $this->setFpAfterBOM(); + //Load our first row + $this->getNextRow(); + } + + public function getTotalRecordCount() + { + $totalCount = $this->getNumberOfLinesInfile(); + if($this->hasHeaderRow(FALSE) && $totalCount > 0) + { + $totalCount--; + } + return $totalCount; + } + + public function loadDataSet($totalItems = 0) + { + $currentLine = 0; + $this->_dataSet = array(); + $this->rewind(); + //If there's a header don't include it. + if( $this->hasHeaderRow(FALSE) ) + $this->next(); + + while( $this->valid() && $totalItems > count($this->_dataSet) ) + { + if($currentLine >= $this->_offset) + { + $this->_dataSet[] = $this->_currentRow; + } + $this->next(); + $currentLine++; + } + + return $this; + } + + public function getHeaderColumns() + { + $this->rewind(); + if($this->hasHeaderRow(FALSE)) + return $this->_currentRow; + else + return FALSE; + } + +} diff --git a/modules/Import/tpls/confirm.tpl b/modules/Import/tpls/confirm.tpl new file mode 100644 index 00000000..e438a537 --- /dev/null +++ b/modules/Import/tpls/confirm.tpl @@ -0,0 +1,199 @@ +{* + +/********************************************************************************* + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + +{$INSTRUCTION} + +
+ +
+ + + + + + + + + + + +{if $AUTO_DETECT_ERROR != ''} +
+ {$AUTO_DETECT_ERROR} +
+{/if} + +
+{include file='modules/Import/tpls/confirm_table.tpl'} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {sugar_help text=$MOD.LBL_IMPORT_FILE_SETTINGS_HELP} +
 
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

{$MOD.LBL_THIRD_PARTY_CSV_SOURCES} {sugar_help text=$MOD.LBL_THIRD_PARTY_CSV_SOURCES_HELP}

 {$MOD.LBL_NONE}
 {$MOD.LBL_SALESFORCE}
 {$MOD.LBL_MICROSOFT_OUTLOOK} {sugar_help text=$MOD.LBL_MICROSOFT_OUTLOOK_HELP}
 
+ + + + + +
+   + +
+
\ No newline at end of file diff --git a/modules/Import/tpls/confirm_table.tpl b/modules/Import/tpls/confirm_table.tpl new file mode 100644 index 00000000..5f7bdff9 --- /dev/null +++ b/modules/Import/tpls/confirm_table.tpl @@ -0,0 +1,56 @@ +{* +/********************************************************************************* + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + {foreach from=$SAMPLE_ROWS item=row name=row} + + {foreach from=$row item=value} + {if $smarty.foreach.row.first} + {if $HAS_HEADER} + + {else} + + {/if} + {else} + + {/if} + {/foreach} + + {/foreach} + +
{$value}{$MOD.LBL_MISSING_HEADER_ROW}{$value}
diff --git a/modules/Import/tpls/dupcheck.tpl b/modules/Import/tpls/dupcheck.tpl new file mode 100644 index 00000000..523e6250 --- /dev/null +++ b/modules/Import/tpls/dupcheck.tpl @@ -0,0 +1,126 @@ +{* + +/********************************************************************************* + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} +{literal} + +{/literal} + +{$INSTRUCTION} +
+ +{foreach from=$smarty.request key=k item=v} + {if $k neq 'current_step'} + {if is_array($v)} + {foreach from=$v key=k1 item=v1} + + {/foreach} + {else} + + {/if} + {/if} +{/foreach} + + + + + + + + + + + + +
+
+ + + + +
+ + + + + +
+
+
+
+
+
+
+
+
+ {$MOD.LBL_SAVE_MAPPING_AS} {sugar_help text=$MOD.LBL_SAVE_MAPPING_HELP} + + + +
+
+ + + + + +
+   + +
+
+ + diff --git a/modules/Import/tpls/error.tpl b/modules/Import/tpls/error.tpl index 85826428..2bd4faf3 100644 --- a/modules/Import/tpls/error.tpl +++ b/modules/Import/tpls/error.tpl @@ -39,21 +39,61 @@ *} + + \ No newline at end of file diff --git a/modules/Import/tpls/last.tpl b/modules/Import/tpls/last.tpl index c72c9bc7..e128e1c1 100644 --- a/modules/Import/tpls/last.tpl +++ b/modules/Import/tpls/last.tpl @@ -35,17 +35,28 @@ * "Powered by SugarCRM". ********************************************************************************/ +*} +{literal} + +{/literal} - -*} -{$MODULE_TITLE} - -{if $noSuccess} -

{$MOD.LBL_FAILURE}

-{else} -

{$MOD.LBL_SUCCESS}

-{/if} +

+

{$MOD.LBL_SUMMARY}

+

+
+ {if $createdCount > 0} {$createdCount} {$MOD.LBL_SUCCESSFULLY_IMPORTED}
{/if} @@ -54,40 +65,122 @@ {/if} {if $errorCount > 0} {$errorCount} {$MOD.LBL_RECORDS_SKIPPED_DUE_TO_ERROR}
-{$MOD.LNK_ERROR_LIST}
-{$MOD.LNK_RECORDS_SKIPPED_DUE_TO_ERROR}
{/if} {if $dupeCount > 0} {$dupeCount} {$MOD.LBL_DUPLICATES}
-{$MOD.LNK_DUPLICATE_LIST}
{/if} - +
+
+ - - - + + +
-{if !$noSuccess} - -{/if} - - - {$PROSPECTLISTBUTTON} -
+ {if $showUndoButton} + + {/if} + + + {$PROSPECTLISTBUTTON} +
+ +
+ + + + + + +
+ + + +
+
+ +
+
{$RESULTS_TABLE}
+ + +
+ {if $PROSPECTLISTBUTTON != ''}
{/if} -{$JAVASCRIPT} diff --git a/modules/Import/tpls/listview.tpl b/modules/Import/tpls/listview.tpl new file mode 100644 index 00000000..a5d3f9f7 --- /dev/null +++ b/modules/Import/tpls/listview.tpl @@ -0,0 +1,95 @@ +{* + +/********************************************************************************* + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + +
+ + {include file='modules/Import/tpls/listviewpaginator.tpl'} + + {counter start=0 name="colCounter" print=false assign="colCounter"} + {if $displayColumns eq false} + + {else} + {foreach from=$displayColumns key=colHeader item=label} + + {counter name="colCounter"} + {/foreach} + {/if} + + {counter start=$pageData.offsets.current print=false assign="offset" name="offset"} + {foreach name=rowIteration from=$data key=id item=rowData} + {counter name="offset" print=false} + + {if $smarty.foreach.rowIteration.iteration is odd} + {assign var='_rowColor' value=$rowColor[0]} + {else} + {assign var='_rowColor' value=$rowColor[1]} + {/if} + + {counter start=0 name="colCounter" print=false assign="colCounter"} + {foreach from=$rowData key=col item=params} + {strip} + + {/strip} + {counter name="colCounter"} + {/foreach} + + {foreachelse} + + + + {/foreach} + {include file='modules/Import/tpls/listviewpaginator.tpl'} +
{$MOD.LBL_MISSING_HEADER_ROW} +
+ {$label} +
+
+ {$params} +
+ {$APP.LBL_NO_DATA} +
+
\ No newline at end of file diff --git a/modules/Import/tpls/listviewpaginator.tpl b/modules/Import/tpls/listviewpaginator.tpl new file mode 100644 index 00000000..56843d8e --- /dev/null +++ b/modules/Import/tpls/listviewpaginator.tpl @@ -0,0 +1,86 @@ +{* +/********************************************************************************* + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + + + + + + +
+ {if $pageData.offsets.current != 0} + + {else} + + {/if} + {if $pageData.offsets.current != 0 } + + {else} + + {/if} + ({if $pageData.offsets.lastOffsetOnPage == 0}0{else}{$pageData.offsets.current+1}{/if} - {$pageData.offsets.lastOffsetOnPage} {$navStrings.of} {$pageData.offsets.total}) + {if $pageData.offsets.next > 0} + + {else} + + {/if} + {if $pageData.offsets.next > 0} + + {else} + + {/if} +
+ + \ No newline at end of file diff --git a/modules/Import/tpls/step1.tpl b/modules/Import/tpls/step1.tpl index 5ed92cde..8694b264 100644 --- a/modules/Import/tpls/step1.tpl +++ b/modules/Import/tpls/step1.tpl @@ -35,162 +35,66 @@ * "Powered by SugarCRM". ********************************************************************************/ - - - - *} -{overlib_includes} -{$MODULE_TITLE} + +{literal} + {if $ERROR != ''} {$ERROR} {/if} +{$INSTRUCTION}
+ + + +

- - - + + +
- - - - -
- - - - - - - - - - - - - - - - - - - - - {if $show_salesforce} - - - - {/if} - {if $show_outlook} - - - - {/if} - {if $show_act} - - - - {/if} - {foreach from=$custom_mappings item=item name=custommappings} - {capture assign=mapping_label}{$MOD.LBL_CUSTOM_MAPPING_}{$item|upper}{/capture} - - - - {/foreach} - {foreach from=$custom_imports key=key item=item name=saved} - {if $smarty.foreach.saved.first} - - - - {/if} - - - +

{$MOD.LBL_WHAT_IS} *

source == 'csv'}checked="checked"{/if} /> -  {$MOD.LBL_CSV} {sugar_help text=$MOD.LBL_DELIMITER_COMMA_HELP}
  {$MOD.LBL_CUSTOM_ENCLOSURE} - - - {sugar_help text=$MOD.LBL_ENCLOSURE_HELP} -
source == 'tab'}checked="checked"{/if} /> -  {$MOD.LBL_TAB} {sugar_help text=$MOD.LBL_DELIMITER_TAB_HELP}
source == 'other'}checked="checked"{/if}/> -  {$MOD.LBL_CUSTOM_DELIMITED} {sugar_help text=$MOD.LBL_DELIMITER_CUSTOM_HELP}
source == 'salesforce'}checked="checked"{/if}/> -  {$MOD.LBL_SALESFORCE}
source == 'outlook'}checked="checked"{/if}/> -  {$MOD.LBL_MICROSOFT_OUTLOOK}
source == 'act'}checked="checked"{/if}/> -  {$MOD.LBL_ACT}
-  {$mapping_label}
-
{$MOD.LBL_MY_SAVED} {sugar_help text=$MOD.LBL_MY_SAVED_HELP}
- -  {$item.IMPORT_NAME} + + + - - - {/foreach} - {foreach from=$published_imports key=key item=item name=published} - {if $smarty.foreach.published.first} - - - - {/if} - - - - - {/foreach} - - - - - - - - - -
+ + + + +
+ + {if $showModuleSelection} + + + + + + + + + + {/if} + + + +

{$MOD.LBL_STEP_MODULE} 

 
+ +
+
- {if $is_admin} - - {/if} - -
-
{$MOD.LBL_PUBLISHED_SOURCES} {sugar_help text=$MOD.LBL_MY_PUBLISHED_HELP}
- -  {$item.IMPORT_NAME} - - {if $is_admin} - - - {/if} -
-

{$MOD.LBL_IMPORT_TYPE} *

- type == 'import' or !$selectedData->type}checked="checked"{/if} /> -  {$MOD.LBL_IMPORT_BUTTON} -
- type == 'update'}checked="checked"{/if} /> -  {$MOD.LBL_UPDATE_BUTTON} -
-
-

-
- - - -
- +

-{$JAVASCRIPT} diff --git a/modules/Import/tpls/step2.tpl b/modules/Import/tpls/step2.tpl index 6442f6e2..04b5a27a 100644 --- a/modules/Import/tpls/step2.tpl +++ b/modules/Import/tpls/step2.tpl @@ -39,74 +39,146 @@ *} -{$MODULE_TITLE} +{literal} + + +{/literal} + + +{$INSTRUCTION} + +
+
- - + + -{foreach from=$instructions key=key item=item name=instructions} -{if $smarty.foreach.instructions.first} - - - - - - - -

{$INSTRUCTIONS_TITLE}

- -{/if} - - - - -{if $smarty.foreach.instructions.last} -
{$item.STEP_NUM}{$item.INSTRUCTION_STEP}
-
-{/if} -{/foreach} - -
- - + +
- - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + +
{$MOD.LBL_SELECT_FILE}
- - -
- {$MOD.LBL_HAS_HEADER}  -
{$SAMPLE_URL}  {sugar_help text=$MOD.LBL_SAMPLE_URL_HELP}
 
 
{$MOD.LBL_SELECT_FILE}  {sugar_help text=$MOD.LBL_FILE_UPLOAD_WIDGET_HELP}
 
 
+

{$MOD.LBL_IMPORT_TYPE} 

+ +  {$MOD.LBL_IMPORT_BUTTON}  {sugar_help text=$MOD.LBL_CREATE_BUTTON_HELP} +
+ +  {$MOD.LBL_UPDATE_BUTTON}  {sugar_help text=$MOD.LBL_UPDATE_BUTTON_HELP} +
+
+ + {foreach from=$custom_mappings item=item name=custommappings} + {capture assign=mapping_label}{$MOD.LBL_CUSTOM_MAPPING_}{$item|upper}{/capture} + + + + {/foreach} + + {if !empty($custom_imports) || !empty($published_imports)} + + + + + + + + {/if} + {foreach from=$custom_imports key=key item=item name=saved} + + + + + {/foreach} + {foreach from=$published_imports key=key item=item name=published} + + + + + {/foreach} +
+  {$mapping_label}
+

{$MOD.LBL_PUBLISHED_SOURCES} {sugar_help text=$savedMappingHelpText}

+ +  {$MOD.LBL_NONE} +
+ +  {$item.IMPORT_NAME} + + {if $is_admin} + + {/if} + +
+ +  {$item.IMPORT_NAME} + + {if $is_admin} + + + {/if} +

+ -
-   - + + {if $displayBackBttn} +   + {/if} +
- -
+ + diff --git a/modules/Import/tpls/step3.tpl b/modules/Import/tpls/step3.tpl index 54230ede..694a6bef 100644 --- a/modules/Import/tpls/step3.tpl +++ b/modules/Import/tpls/step3.tpl @@ -39,49 +39,59 @@ *} -{literal} - -{/literal} - -{overlib_includes} -{$MODULE_TITLE} + +{$CSS} + +{$INSTRUCTION} + +
+ - - + + - - + + + + + + + + + + + + +
+{if $NOTETEXT != ''} +

+ +

+

+{/if} -
- {$APP.LBL_REQUIRED_SYMBOL} {$APP.NTC_REQUIRED} -
+
-

-{$MOD.LBL_SELECT_FIELDS_TO_MAP} -

-
- + +
{foreach from=$rows key=key item=item name=rows} {if $smarty.foreach.rows.first} - {if $HAS_HEADER == 'on'} {/if} {if $HAS_HEADER != 'on'} - + {/if} + {/if} + {if $HAS_HEADER == 'on'} + + {/if} - {if $HAS_HEADER == 'on'} - - {/if} - {if $item.show_remove} {/if} - + {/if} + {/foreach} - - - -
- {$MOD.LBL_DATABASE_FIELD}  - {sugar_help text=$MOD.LBL_DATABASE_FIELD_HELP} - {$MOD.LBL_HEADER_ROW}  @@ -89,31 +99,33 @@ textarea { width: 20em } - {$MOD.LBL_DEFAULT_VALUE}  - {sugar_help text=$MOD.LBL_DEFAULT_VALUE_HELP} + {$MOD.LBL_DATABASE_FIELD}  + {sugar_help text=$MOD.LBL_DATABASE_FIELD_HELP} {$MOD.LBL_ROW} 1  {sugar_help text=$MOD.LBL_ROW_HELP} {$MOD.LBL_ROW} 2{$MOD.LBL_ROW} 2 +  {$MOD.LBL_DEFAULT_VALUE}  + {sugar_help text=$MOD.LBL_DEFAULT_VALUE_HELP} +   +
{$item.cell1} {$item.cell1} - {$item.default_field} - {$item.cell1}{$item.cell2}{$item.cell2} + {$item.default_field} +
+ - + name="button" value=" {$MOD.LBL_ADD_ROW} "> {sugar_help text=$MOD.LBL_ADD_FIELD_HELP}        - {$MOD.LBL_SAVE_MAPPING_AS} - - -  {sugar_help text=$MOD.LBL_SAVE_MAPPING_HELP} - -
-{$JAVASCRIPT_CHOOSER} - -{if $NOTETEXT != '' || $required_fields != ''} -

-{$MOD.LBL_NOTES} -

    -
  • {$MOD.LBL_REQUIRED_NOTE}{$required_fields}
  • -{$NOTETEXT} -
-

-{/if}
+
  - +
-
-{literal} - -{/literal} -{$JAVASCRIPT} -{literal} - -{/literal} +{$QS_JS} \ No newline at end of file diff --git a/modules/Import/tpls/undo.tpl b/modules/Import/tpls/undo.tpl index a45304ff..c0ceccfb 100644 --- a/modules/Import/tpls/undo.tpl +++ b/modules/Import/tpls/undo.tpl @@ -39,27 +39,28 @@ *} +
{if $UNDO_SUCCESS} -

{$MOD.LBL_SUCCESS} {$MOD.LBL_LAST_IMPORT_UNDONE}

+

{$MOD.LBL_LAST_IMPORT_UNDONE}

{else} -

{$MOD.LBL_FAIL} {$MOD.LBL_NO_IMPORT_TO_UNDO}

+

{$MOD.LBL_NO_IMPORT_TO_UNDO}

{/if} +
- -
- - + + +
+
-{$JAVASCRIPT} + diff --git a/modules/Import/tpls/wizardWrapper.tpl b/modules/Import/tpls/wizardWrapper.tpl new file mode 100644 index 00000000..ffa9e65f --- /dev/null +++ b/modules/Import/tpls/wizardWrapper.tpl @@ -0,0 +1,76 @@ +{* +/********************************************************************************* + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} + + + +{overlib_includes} +
+
+
+
+
+
+
+
+
+
+ {$MODULE_TITLE} +
+ {$CONTENT} +
+
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/modules/Import/views/ImportListView.php b/modules/Import/views/ImportListView.php new file mode 100644 index 00000000..7bd9d672 --- /dev/null +++ b/modules/Import/views/ImportListView.php @@ -0,0 +1,177 @@ +ss = new Sugar_Smarty(); + $this->tableID = $tableIdentifier; + + $this->dataSource = $dataSource; + $this->headerColumns = $this->dataSource->getHeaderColumns(); + + if( !isset($params['offset']) ) + throw new Exception("Missing required parameter offset for ImportListView"); + else + $this->dataSource->setCurrentOffset($params['offset']); + + $this->recordsPerPage = isset($params['totalRecords']) ? $params['totalRecords'] : ($sugar_config['list_max_entries_per_page'] + 0); + $this->data = $this->dataSource->loadDataSet($this->recordsPerPage)->getDataSet(); + $this->maxColumns = $this->getMaxColumnsForDataSet(); + } + + /** + * Display the list view like table. + * + * @param bool $return True if we should return the content rather than echoing. + * @return + */ + public function display($return = FALSE) + { + global $app_strings,$mod_strings; + + $navStrings = array('next' => $app_strings['LNK_LIST_NEXT'],'previous' => $app_strings['LNK_LIST_PREVIOUS'],'end' => $app_strings['LNK_LIST_END'], + 'start' => $app_strings['LNK_LIST_START'],'of' => $app_strings['LBL_LIST_OF']); + $this->ss->assign('navStrings', $navStrings); + $this->ss->assign('pageData', $this->generatePaginationData() ); + $this->ss->assign('tableID', $this->tableID); + $this->ss->assign('colCount', count($this->headerColumns)); + $this->ss->assign('APP',$app_strings); + $this->ss->assign('rowColor', array('oddListRow', 'evenListRow')); + $this->ss->assign('displayColumns',$this->headerColumns); + $this->ss->assign('data', $this->data); + $this->ss->assign('maxColumns', $this->maxColumns); + $this->ss->assign('MOD', $mod_strings); + $contents = $this->ss->fetch('modules/Import/tpls/listview.tpl'); + if($return) + return $contents; + else + echo $contents; + } + + /** + * For the data set that was loaded, find the max count of entries per row. + * + * @return int + */ + protected function getMaxColumnsForDataSet() + { + $maxColumns = 0; + foreach($this->data as $data) + { + if(count($data) > $maxColumns) + $maxColumns = count($data); + } + return $maxColumns; + } + + /** + * Generate the pagination data. + * + * @return array + */ + protected function generatePaginationData() + { + $currentOffset = $this->dataSource->getCurrentOffset(); + $totalRecordsCount = $this->dataSource->getTotalRecordCount(); + $nextOffset = $currentOffset+ $this->recordsPerPage; + $nextOffset = $nextOffset > $totalRecordsCount ? 0 : $nextOffset; + $lastOffset = floor($totalRecordsCount / $this->recordsPerPage) * $this->recordsPerPage; + $previousOffset = $currentOffset - $this->recordsPerPage; + $offsets = array('totalCounted'=> true, 'total' => $totalRecordsCount, 'next' => $nextOffset, + 'last' => $lastOffset, 'previous' => $previousOffset, + 'current' => $currentOffset, 'lastOffsetOnPage' => count($this->data) + $this->dataSource->getCurrentOffset() ); + + $pageData = array('offsets' => $offsets); + return $pageData; + + } + + + +} diff --git a/modules/Import/views/ImportView.php b/modules/Import/views/ImportView.php new file mode 100644 index 00000000..d3646342 --- /dev/null +++ b/modules/Import/views/ImportView.php @@ -0,0 +1,170 @@ +currentStep = isset($_REQUEST['current_step']) ? ($_REQUEST['current_step'] - 1) : 1; + } else { + $this->currentStep = isset($_REQUEST['current_step']) ? ($_REQUEST['current_step'] + 1) : 1; + } + $this->importModule = isset($_REQUEST['import_module']) ? $_REQUEST['import_module'] : ''; + + } + + /** + * @see SugarView::getMenu() + */ + public function getMenu($module = null) + { + global $mod_strings, $current_language; + + if ( empty($module) ) + $module = $this->importModule; + + $old_mod_strings = $mod_strings; + $mod_strings = return_module_language($current_language, $module); + $returnMenu = parent::getMenu($module); + $mod_strings = $old_mod_strings; + + return $returnMenu; + } + + /** + * @see SugarView::_getModuleTab() + */ + protected function _getModuleTab() + { + global $app_list_strings, $moduleTabMap; + + // Need to figure out what tab this module belongs to, most modules have their own tabs, but there are exceptions. + if ( !empty($_REQUEST['module_tab']) ) + return $_REQUEST['module_tab']; + elseif ( isset($moduleTabMap[$this->importModule]) ) + return $moduleTabMap[$this->importModule]; + // Default anonymous pages to be under Home + elseif ( !isset($app_list_strings['moduleList'][$this->importModule]) ) + return 'Home'; + else + return $this->importModule; + } + + /** + * Send our output to the importer controller. + * + * @param string $html + * @param string $submitContent + * @param string $script + * @param bool $encode + * @return void + */ + protected function sendJsonOutput($html = "", $submitContent = "", $script = "", $encode = FALSE) + { + $title = $this->getModuleTitle(false); + $out = array( + 'html' => $html, + 'submitContent' => $submitContent, + 'title' => $title, + 'script' => $script); + + if($encode){ + array_walk($out, create_function('&$val', '$val = htmlspecialchars($val,ENT_NOQUOTES);')); + } + echo json_encode($out); + } + + /** + * @see SugarView::_getModuleTitleParams() + */ + protected function _getModuleTitleParams($browserTitle = false) + { + global $mod_strings, $app_list_strings; + $returnArray = array(string_format($mod_strings[$this->pageTitleKey], array($this->currentStep))); + + return $returnArray; + } + + protected function getInstruction() + { + global $mod_strings; + + $ins = ''; + + if ($this->instruction) { + $ins_string = $mod_strings[$this->instruction]; + $ins = '
' . $ins_string . '
'; + } + + return $ins; + } + + /** + * Displays the Smarty template for an error + * + * @param string $message error message to show + * @param string $module what module we were importing into + * @param string $action what page we should go back to + */ + protected function _showImportError($message,$module,$action = 'Step1') + { + $ss = new Sugar_Smarty(); + + $ss->assign("MESSAGE",$message); + $ss->assign("ACTION",$action); + $ss->assign("IMPORT_MODULE",$module); + $ss->assign("MOD", $GLOBALS['mod_strings']); + $ss->assign("SOURCE",""); + if ( isset($_REQUEST['source']) ) + $ss->assign("SOURCE", $_REQUEST['source']); + + echo $ss->fetch('modules/Import/tpls/error.tpl'); + } +} \ No newline at end of file diff --git a/modules/Import/views/view.confirm.php b/modules/Import/views/view.confirm.php new file mode 100644 index 00000000..1eebd836 --- /dev/null +++ b/modules/Import/views/view.confirm.php @@ -0,0 +1,652 @@ +ss->assign("IMPORT_MODULE", $_REQUEST['import_module']); + $this->ss->assign("TYPE",( !empty($_REQUEST['type']) ? $_REQUEST['type'] : "import" )); + $this->ss->assign("SOURCE_ID", $_REQUEST['source_id']); + + $this->instruction = 'LBL_SELECT_PROPERTY_INSTRUCTION'; + $this->ss->assign('INSTRUCTION', $this->getInstruction()); + + $this->ss->assign("MODULE_TITLE", $this->getModuleTitle(false), ENT_NOQUOTES); + $this->ss->assign("CURRENT_STEP", $this->currentStep); + $sugar_config['import_max_records_per_file'] = ( empty($sugar_config['import_max_records_per_file']) ? 1000 : $sugar_config['import_max_records_per_file'] ); + $importSource = isset($_REQUEST['source']) ? $_REQUEST['source'] : 'csv' ; + + // Clear out this user's last import + $seedUsersLastImport = new UsersLastImport(); + $seedUsersLastImport->mark_deleted_by_user_id($current_user->id); + ImportCacheFiles::clearCacheFiles(); + + // handle uploaded file + $uploadFile = new UploadFile('userfile'); + if (isset($_FILES['userfile']) && $uploadFile->confirm_upload()) + { + $uploadFile->final_move('IMPORT_'.$this->bean->object_name.'_'.$current_user->id); + $uploadFileName = $uploadFile->get_upload_path('IMPORT_'.$this->bean->object_name.'_'.$current_user->id); + } + elseif( !empty($_REQUEST['tmp_file']) ) + { + $uploadFileName = $_REQUEST['tmp_file']; + } + else + { + $this->_showImportError($mod_strings['LBL_IMPORT_MODULE_ERROR_NO_UPLOAD'],$_REQUEST['import_module'],'Step2', true, null, true); + return; + } + + //check the file size, we dont want to process an empty file + if(isset($_FILES['userfile']['size']) && $_FILES['userfile']['size'] == 0){ + //this file is empty, throw error message + $this->_showImportError($mod_strings['LBL_NO_LINES'],$_REQUEST['import_module'],'Step2', false, null, true); + return; + } + + $mimeTypeOk = true; + + //check to see if the file mime type is not a form of text or application octed streramand fire error if not + if(isset($_FILES['userfile']['type']) && strpos($_FILES['userfile']['type'],'octet-stream') === false && strpos($_FILES['userfile']['type'],'text') === false + && strpos($_FILES['userfile']['type'],'application/vnd.ms-excel') === false) { + //this file does not have a known text or application type of mime type, issue the warning + $error_msgs[] = $mod_strings['LBL_MIME_TYPE_ERROR_1']; + $error_msgs[] = $mod_strings['LBL_MIME_TYPE_ERROR_2']; + $this->_showImportError($error_msgs,$_REQUEST['import_module'],'Step2', true, $mod_strings['LBL_OK']); + $mimeTypeOk = false; + } + + $this->ss->assign("FILE_NAME", $uploadFileName); + + // Now parse the file and look for errors + $importFile = new ImportFile( $uploadFileName, $_REQUEST['custom_delimiter'], html_entity_decode($_REQUEST['custom_enclosure'],ENT_QUOTES), FALSE); + + if( $this->shouldAutoDetectProperties($importSource) ) + { + $GLOBALS['log']->debug("Auto detecing csv properties..."); + $autoDetectOk = $importFile->autoDetectCSVProperties(); + $importFileMap = array(); + $this->ss->assign("SOURCE", 'csv'); + if($autoDetectOk === FALSE) + { + //show error only if previous mime type check has passed + if($mimeTypeOk){ + $this->ss->assign("AUTO_DETECT_ERROR", $mod_strings['LBL_AUTO_DETECT_ERROR']); + } + } + else + { + $dateFormat = $importFile->getDateFormat(); + $timeFormat = $importFile->getTimeFormat(); + if ($dateFormat) { + $importFileMap['importlocale_dateformat'] = $dateFormat; + } + if ($timeFormat) { + $importFileMap['importlocale_timeformat'] = $timeFormat; + } + } + } + else + { + $impotMapSeed = $this->getImportMap($importSource); + $importFile->setImportFileMap($impotMapSeed); + $importFileMap = $impotMapSeed->getMapping($_REQUEST['import_module']); + } + + $delimeter = $importFile->getFieldDelimeter(); + $enclosure = $importFile->getFieldEnclosure(); + $hasHeader = $importFile->hasHeaderRow(); + + $encodeOutput = TRUE; + //Handle users navigating back through the wizard. + if( !empty($_REQUEST['previous_action']) && $_REQUEST['previous_action'] == 'Confirm') + { + $encodeOutput = FALSE; + $importFileMap = $this->overloadImportFileMapFromRequest($importFileMap); + $delimeter = !empty($_REQUEST['custom_delimiter']) ? $_REQUEST['custom_delimiter'] : $delimeter; + $enclosure = isset($_REQUEST['custom_enclosure']) ? $_REQUEST['custom_enclosure'] : $enclosure; + $enclosure = html_entity_decode($enclosure, ENT_QUOTES); + $hasHeader = !empty($_REQUEST['has_header']) ? $_REQUEST['has_header'] : $hasHeader; + if ($hasHeader == 'on') { + $hasHeader = true; + } else if ($hasHeader == 'off') { + $hasHeader = false; + } + } + + $this->ss->assign("IMPORT_ENCLOSURE_OPTIONS", $this->getEnclosureOptions($enclosure)); + $this->ss->assign("IMPORT_DELIMETER_OPTIONS", $this->getDelimeterOptions($delimeter)); + $this->ss->assign("CUSTOM_DELIMITER", $delimeter); + $this->ss->assign("CUSTOM_ENCLOSURE", htmlentities($enclosure, ENT_QUOTES)); + $hasHeaderFlag = $hasHeader ? " CHECKED" : ""; + $this->ss->assign("HAS_HEADER_CHECKED", $hasHeaderFlag); + + if ( !$importFile->fileExists() ) { + $this->_showImportError($mod_strings['LBL_CANNOT_OPEN'],$_REQUEST['import_module'],'Step2', false, null, true); + return; + } + + //Check if we will exceed the maximum number of records allowed per import. + $maxRecordsExceeded = FALSE; + $maxRecordsWarningMessg = ""; + $lineCount = $importFile->getNumberOfLinesInfile(); + $maxLineCount = isset($sugar_config['import_max_records_total_limit'] ) ? $sugar_config['import_max_records_total_limit'] : 5000; + if( !empty($maxLineCount) && ($lineCount > $maxLineCount) ) + { + $maxRecordsExceeded = TRUE; + $maxRecordsWarningMessg = string_format($mod_strings['LBL_IMPORT_ERROR_MAX_REC_LIMIT_REACHED'], array($lineCount, $maxLineCount) ); + } + + //Retrieve a sample set of data + $rows = $this->getSampleSet($importFile); + $this->ss->assign('column_count', $this->getMaxColumnsInSampleSet($rows) ); + $this->ss->assign('HAS_HEADER', $importFile->hasHeaderRow(FALSE) ); + $this->ss->assign('getNumberJs', $locale->getNumberJs()); + $this->setImportFileCharacterSet($importFile, $importFileMap); + $this->setDateTimeProperties($importFileMap); + $this->setCurrencyOptions($importFileMap); + $this->setNumberFormatOptions($importFileMap); + $this->setNameFormatProperties($importFileMap); + + $importMappingJS = $this->getImportMappingJS(); + + $this->ss->assign("SAMPLE_ROWS",$rows); + $JS = $this->_getJS($maxRecordsExceeded, $maxRecordsWarningMessg, $importMappingJS, $importFileMap ); + $this->ss->assign("JAVASCRIPT", $JS); + $content = $this->ss->fetch('modules/Import/tpls/confirm.tpl'); + $this->ss->assign("CONTENT",$content); + $this->ss->display('modules/Import/tpls/wizardWrapper.tpl'); + + } + + private function getDelimeterOptions($selctedDelim) + { + $selctedDelim = $selctedDelim == "\t" ? '\t' : $selctedDelim; + return get_select_options_with_id($GLOBALS['app_list_strings']['import_delimeter_options'], $selctedDelim); + } + + private function getEnclosureOptions($enclosure) + { + $results = array(); + foreach ($GLOBALS['app_list_strings']['import_enclosure_options'] as $k => $v) + { + $results[htmlentities($k, ENT_QUOTES)] = $v; + } + + return get_select_options_with_id($results, htmlentities($enclosure, ENT_QUOTES)); + } + + private function overloadImportFileMapFromRequest($importFileMap) + { + $overideKeys = array( + 'importlocale_dateformat','importlocale_timeformat','importlocale_timezone','importlocale_charset', + 'importlocale_currency','importlocale_default_currency_significant_digits','importlocale_num_grp_sep', + 'importlocale_dec_sep','importlocale_default_locale_name_format','custom_delimiter', 'custom_enclosure' + ); + + foreach($overideKeys as $key) + { + if( !empty( $_REQUEST[$key]) ) + $importFileMap[$key] = $_REQUEST[$key]; + } + return $importFileMap; + } + + private function shouldAutoDetectProperties($importSource) + { + if(empty($importSource) || $importSource == 'csv' ) + return TRUE; + else + return FALSE; + } + + private function getImportMap($importSource) + { + if ( strncasecmp("custom:",$importSource,7) == 0) + { + $id = substr($importSource,7); + $import_map_seed = new ImportMap(); + $import_map_seed->retrieve($id, false); + + $this->ss->assign("SOURCE_ID", $import_map_seed->id); + $this->ss->assign("SOURCE_NAME", $import_map_seed->name); + $this->ss->assign("SOURCE", $import_map_seed->source); + } + else + { + $classname = 'ImportMap' . ucfirst($importSource); + if ( file_exists("modules/Import/maps/{$classname}.php") ) + require_once("modules/Import/maps/{$classname}.php"); + elseif ( file_exists("custom/modules/Import/maps/{$classname}.php") ) + require_once("custom/modules/Import/maps/{$classname}.php"); + else + { + require_once("custom/modules/Import/maps/ImportMapOther.php"); + $classname = 'ImportMapOther'; + $importSource = 'other'; + } + if ( class_exists($classname) ) + { + $import_map_seed = new $classname; + $this->ss->assign("SOURCE", $importSource); + } + } + + return $import_map_seed; + } + + private function setNameFormatProperties($field_map = array()) + { + global $locale, $current_user; + + $localized_name_format = isset($field_map['importlocale_default_locale_name_format'])? $field_map['importlocale_default_locale_name_format'] : $locale->getLocaleFormatMacro($current_user); + $this->ss->assign('default_locale_name_format', $localized_name_format); + $this->ss->assign('getNameJs', $locale->getNameJs()); + + } + + private function setNumberFormatOptions($field_map = array()) + { + global $locale, $current_user, $sugar_config; + + $num_grp_sep = isset($field_map['importlocale_num_grp_sep'])? $field_map['importlocale_num_grp_sep'] : $current_user->getPreference('num_grp_sep'); + $dec_sep = isset($field_map['importlocale_dec_sep'])? $field_map['importlocale_dec_sep'] : $current_user->getPreference('dec_sep'); + + $this->ss->assign("NUM_GRP_SEP",( empty($num_grp_sep) ? $sugar_config['default_number_grouping_seperator'] : $num_grp_sep )); + $this->ss->assign("DEC_SEP",( empty($dec_sep)? $sugar_config['default_decimal_seperator'] : $dec_sep )); + + + $significantDigits = isset($field_map['importlocale_default_currency_significant_digits']) ? $field_map['importlocale_default_currency_significant_digits'] + : $locale->getPrecedentPreference('default_currency_significant_digits', $current_user); + + $sigDigits = ''; + for($i=0; $i<=6; $i++) + { + if($significantDigits == $i) + { + $sigDigits .= ''; + } else + { + $sigDigits .= ''; + } + } + + $this->ss->assign('sigDigits', $sigDigits); + } + + + private function setCurrencyOptions($field_map = array() ) + { + global $locale, $current_user; + $cur_id = isset($field_map['importlocale_currency'])? $field_map['importlocale_currency'] : $locale->getPrecedentPreference('currency', $current_user); + // get currency preference + require_once('modules/Currencies/ListCurrency.php'); + $currency = new ListCurrency(); + if($cur_id) + $selectCurrency = $currency->getSelectOptions($cur_id); + else + $selectCurrency = $currency->getSelectOptions(); + + $this->ss->assign("CURRENCY", $selectCurrency); + + $currenciesVars = ""; + $i=0; + foreach($locale->currencies as $id => $arrVal) + { + $currenciesVars .= "currencies[{$i}] = '{$arrVal['symbol']}';\n"; + $i++; + } + $currencySymbolsJs = <<getUserDateTimePreferences(); + $defaultTimeOption = isset($field_map['importlocale_timeformat'])? $field_map['importlocale_timeformat'] : $timeFormat['time']; + $defaultDateOption = isset($field_map['importlocale_dateformat'])? $field_map['importlocale_dateformat'] : $timeFormat['date']; + + $timeOptions = get_select_options_with_id($sugar_config['time_formats'], $defaultTimeOption); + $dateOptions = get_select_options_with_id($sugar_config['date_formats'], $defaultDateOption); + + // get list of valid timezones + $userTZ = isset($field_map['importlocale_timezone'])? $field_map['importlocale_timezone'] : $current_user->getPreference('timezone'); + if(empty($userTZ)) + $userTZ = TimeDate::userTimezone(); + + $this->ss->assign('TIMEZONE_CURRENT', $userTZ); + $this->ss->assign('TIMEOPTIONS', $timeOptions); + $this->ss->assign('DATEOPTIONS', $dateOptions); + $this->ss->assign('TIMEZONEOPTIONS', TimeDate::getTimezoneList()); + } + + private function setImportFileCharacterSet($importFile, $field_map = array()) + { + global $locale; + $charset_for_import = isset($field_map['importlocale_charset']) ? $field_map['importlocale_charset'] : $importFile->autoDetectCharacterSet(); + $charsetOptions = get_select_options_with_id( $locale->getCharsetSelect(), $charset_for_import);//wdong, bug 25927, here we should use the charset testing results from above. + $this->ss->assign('CHARSETOPTIONS', $charsetOptions); + } + + protected function getImportMappingJS() + { + $results = array(); + $importMappings = array('ImportMapSalesforce', 'ImportMapOutlook'); + foreach($importMappings as $importMap) + { + $tmpFile = "modules/Import/maps/$importMap.php"; + if( file_exists($tmpFile) ) + { + require_once($tmpFile); + $t = new $importMap(); + $results[$t->name] = array('delim' => $t->delimiter, 'enclos' => $t->enclosure, 'has_header' => $t->has_header); + } + } + return $results; + } + + public function getMaxColumnsInSampleSet($sampleSet) + { + $maxColumns = 0; + foreach($sampleSet as $v) + { + if(count($v) > $maxColumns) + $maxColumns = count($v); + else + continue; + } + + return $maxColumns; + } + + public function getSampleSet($importFile) + { + $rows = array(); + for($i=0; $i < self::SAMPLE_ROW_SIZE; $i++) + { + $rows[] = $importFile->getNextRow(); + } + + if( ! $importFile->hasHeaderRow(FALSE) ) + { + array_unshift($rows, array_fill(0,1,'') ); + } + + // to be displayed in UTF-8 format + global $locale; + $encoding = $importFile->autoDetectCharacterSet(); + if (!empty($encoding) && $encoding != 'UTF-8') { + foreach ($rows as &$row) { + if (is_array($row)) { + foreach ($row as &$val) { + $val = $locale->translateCharset($val, $encoding); + } + } + } + } + + return $rows; + } + + /** + * Returns JS used in this view + */ + private function _getJS($maxRecordsExceeded, $maxRecordsWarningMessg, $importMappingJS, $importFileMap) + { + global $mod_strings, $locale; + $maxRecordsExceededJS = $maxRecordsExceeded?"true":"false"; + $importMappingJS = json_encode($importMappingJS); + + $currencySymbolJs = $this->setCurrencyOptions($importFileMap); + $getNumberJs = $locale->getNumberJs(); + $getNameJs = $locale->getNameJs(); + + return <<
'; + } + global $mod_strings; + + $ss->assign("MESSAGE",$display_msg); + $ss->assign("ACTION",$action); + $ss->assign("IMPORT_MODULE",$module); + $ss->assign("MOD", $GLOBALS['mod_strings']); + $ss->assign("SOURCE",""); + $ss->assign("SHOWCANCEL",$showCancel); + if ( isset($_REQUEST['source']) ) + $ss->assign("SOURCE", $_REQUEST['source']); + + if ($cancelLabel) { + $ss->assign('CANCELLABEL', $cancelLabel); + } + + $content = $ss->fetch('modules/Import/tpls/error.tpl'); + + echo $ss->fetch('modules/Import/tpls/error.tpl'); + } + +} + +?> diff --git a/modules/Import/views/view.dupcheck.php b/modules/Import/views/view.dupcheck.php new file mode 100644 index 00000000..0535ffbb --- /dev/null +++ b/modules/Import/views/view.dupcheck.php @@ -0,0 +1,371 @@ +instruction = 'LBL_SELECT_DUPLICATE_INSTRUCTION'; + $this->ss->assign('INSTRUCTION', $this->getInstruction()); + + $this->ss->assign("MODULE_TITLE", $this->getModuleTitle(false)); + $this->ss->assign("DELETE_INLINE_PNG", SugarThemeRegistry::current()->getImage('delete_inline','align="absmiddle" alt="'.$app_strings['LNK_DELETE'].'" border="0"')); + $this->ss->assign("PUBLISH_INLINE_PNG", SugarThemeRegistry::current()->getImage('publish_inline','align="absmiddle" alt="'.$mod_strings['LBL_PUBLISH'].'" border="0"')); + $this->ss->assign("UNPUBLISH_INLINE_PNG", SugarThemeRegistry::current()->getImage('unpublish_inline','align="absmiddle" alt="'.$mod_strings['LBL_UNPUBLISH'].'" border="0"')); + $this->ss->assign("IMPORT_MODULE", $_REQUEST['import_module']); + $this->ss->assign("CURRENT_STEP", $this->currentStep); + $this->ss->assign("JAVASCRIPT", $this->_getJS()); + + $content = $this->ss->fetch('modules/Import/tpls/dupcheck.tpl'); + $this->ss->assign("CONTENT", $content); + $this->ss->display('modules/Import/tpls/wizardWrapper.tpl'); + } + + private function getImportMap() + { + if( !empty($_REQUEST['source_id']) ) + { + $import_map_seed = new ImportMap(); + $import_map_seed->retrieve($_REQUEST['source_id'], false); + + return $import_map_seed->getMapping(); + } + else + { + return array(); + } + } + + /** + * Returns JS used in this view + */ + private function _getJS() + { + global $mod_strings, $sugar_config; + + $has_header = $_REQUEST['has_header'] == 'on' ? TRUE : FALSE; + $uploadFileName = $_REQUEST['tmp_file']; + $splitter = new ImportFileSplitter($uploadFileName, $sugar_config['import_max_records_per_file']); + $splitter->splitSourceFile( $_REQUEST['custom_delimiter'], html_entity_decode($_REQUEST['custom_enclosure'],ENT_QUOTES), $has_header); + $count = $splitter->getFileCount()-1; + $recCount = $splitter->getRecordCount(); + + //BEGIN DRAG DROP WIDGET + $idc = new ImportDuplicateCheck($this->bean); + $dupe_indexes = $idc->getDuplicateCheckIndexes(); + + //grab all the import enabled fields and the field map + $field_map = $this->getImportMap(); + $import_fields = $idc->getDuplicateCheckIndexedFiles(); + + //check for saved entries from mapping + $dupe_disabled = array(); + $dupe_enabled = array(); + $mapped_fields = array('full_name'); + + //grab the list of user mapped fields + foreach($_REQUEST as $req_k => $req_v){ + if(strpos($req_k,'olnum')>0){ + if(empty($req_v) || $req_v != '-1'){ + $mapped_fields[] = $req_v; + } + } + } + + foreach($import_fields as $ik=>$iv){ + + //grab the field value from the key + $ik_field = explode('::', $ik); + + //field is not a custom field and was not included in the key, or was not in mapped fields, so skip + if(strpos($ik_field[0],'ustomfield::')>0 && (empty($ik_field[1]) || !in_array($ik_field[1], $mapped_fields))){ + //skip indexed fields that are not defined in user mapping or + continue; + } + + if(isset($field_map['dupe_'.$ik])){ + //index is defined in mapping, so set this index as enabled if not already defined + $dupe_enabled[] = array("dupeVal" => $ik, "label" => $iv); + }else{ + //index is not defined in mapping, so display as disabled if not already defined + $dupe_disabled[] = array("dupeVal" => $ik, "label" => $iv); + } + } + + $enabled_dupes = json_encode($dupe_enabled); + $disabled_dupes = json_encode($dupe_disabled); + + $stepTitle4 = $mod_strings['LBL_IMPORT_RECORDS']; + + $dateTimeFormat = $GLOBALS['timedate']->get_cal_date_time_format(); + $type = (isset($_REQUEST['type'])) ? $_REQUEST['type'] : ''; + $lblUsed = str_replace(":","",$mod_strings['LBL_INDEX_USED']); + $lblNotUsed = str_replace(":","",$mod_strings['LBL_INDEX_NOT_USED']); + return <<= ProcessImport.fileTotal ) { + YAHOO.SUGAR.MessageBox.updateProgress(1,'{$mod_strings['LBL_IMPORT_COMPLETED']}'); + SUGAR.util.hrefURL(locationStr); + } + else { + document.getElementById("importstepdup").save_map_as.value = ''; + ProcessImport.fileCount++; + ProcessImport.submit(); + } + } + }, + failure: function(o) { + YAHOO.SUGAR.MessageBox.minWidth = 500; + YAHOO.SUGAR.MessageBox.show({ + type: "alert", + title: '{$mod_strings['LBL_IMPORT_ERROR']}', + msg: o.responseText, + fn: function() { window.location.reload(true); } + }); + } + } + ); + var move = 0; + if ( this.fileTotal > 0 ) { + move = this.fileCount/this.fileTotal; + } + YAHOO.SUGAR.MessageBox.updateProgress( move, + "{$mod_strings['LBL_IMPORT_RECORDS']} " + ((this.fileCount * this.recordThreshold) + 1) + + " {$mod_strings['LBL_IMPORT_RECORDS_TO']} " + Math.min(((this.fileCount+1) * this.recordThreshold),this.recordCount) + + " {$mod_strings['LBL_IMPORT_RECORDS_OF']} " + this.recordCount ); + } + + /* + * begins the form submission process + */ + this.begin = function() + { + datestarted = '{$mod_strings['LBL_IMPORT_STARTED']} ' + + YAHOO.util.Date.format('{$dateTimeFormat}'); + YAHOO.SUGAR.MessageBox.show({ + title: '{$stepTitle4}', + msg: datestarted, + width: 500, + type: "progress", + closable:false, + animEl: 'importnow' + }); + SUGAR.saveConfigureDupes(); + this.submit(); + } +} + +//begin dragdrop code + var enabled_dupes = {$enabled_dupes}; + var disabled_dupes = {$disabled_dupes}; + var lblEnabled = '{$lblUsed}'; + var lblDisabled = '{$lblNotUsed}'; + + + SUGAR.enabledDupesTable = new YAHOO.SUGAR.DragDropTable( + "enabled_div", + [{key:"label", label: lblEnabled, width: 225, sortable: false}, + {key:"module", label: lblEnabled, hidden:true}], + new YAHOO.util.LocalDataSource(enabled_dupes, { + responseSchema: { + resultsList : "dupeVal", + fields : [{key : "dupeVal"}, {key : "label"}] + } + }), + { + height: "300px", + group: ["enabled_div", "disabled_div"] + } + ); + SUGAR.disabledDupesTable = new YAHOO.SUGAR.DragDropTable( + "disabled_div", + [{key:"label", label: lblDisabled, width: 225, sortable: false}, + {key:"module", label: lblDisabled, hidden:true}], + new YAHOO.util.LocalDataSource(disabled_dupes, { + responseSchema: { + resultsList : "dupeVal", + fields : [{key : "dupeVal"}, {key : "label"}] + } + }), + { + height: "300px", + group: ["enabled_div", "disabled_div"] + } + ); + SUGAR.enabledDupesTable.disableEmptyRows = true; + SUGAR.disabledDupesTable.disableEmptyRows = true; + SUGAR.enabledDupesTable.addRow({module: "", label: ""}); + SUGAR.disabledDupesTable.addRow({module: "", label: ""}); + SUGAR.enabledDupesTable.render(); + SUGAR.disabledDupesTable.render(); + + + SUGAR.saveConfigureDupes = function() + { + var enabledTable = SUGAR.enabledDupesTable; + var dupeVal = []; + for(var i=0; i < enabledTable.getRecordSet().getLength(); i++){ + var data = enabledTable.getRecord(i).getData(); + if (data.dupeVal && data.dupeVal != '') + dupeVal[i] = data.dupeVal; + } + YAHOO.util.Dom.get('enabled_dupes').value = YAHOO.lang.JSON.stringify(dupeVal); + + var disabledTable = SUGAR.disabledDupesTable; + var dupeVal = []; + for(var i=0; i < disabledTable.getRecordSet().getLength(); i++){ + var data = disabledTable.getRecord(i).getData(); + if (data.dupeVal && data.dupeVal != '') + dupeVal[i] = data.dupeVal; + } + YAHOO.util.Dom.get('disabled_dupes').value = YAHOO.lang.JSON.stringify(dupeVal); + } + + + + +document.getElementById('goback').onclick = function(){ + document.getElementById('importstepdup').action.value = 'step3'; + document.getElementById('importstepdup').to_pdf.value = '0'; + var success = function(data) { + var response = YAHOO.lang.JSON.parse(data.responseText); + importWizardDialogDiv = document.getElementById('importWizardDialogDiv'); + importWizardDialogTitle = document.getElementById('importWizardDialogTitle'); + submitDiv = document.getElementById('submitDiv'); + importWizardDialogDiv.innerHTML = response['html']; + importWizardDialogTitle.innerHTML = response['title']; + SUGAR.util.evalScript(response['html']); + submitDiv.innerHTML = response['submitContent']; + eval(response['script']); + + } + + var formObject = document.getElementById('importstepdup'); + YAHOO.util.Connect.setForm(formObject); + var cObj = YAHOO.util.Connect.asyncRequest('POST', "index.php", {success: success, failure: success}); +} + +document.getElementById('importnow').onclick = function(){ + SUGAR.saveConfigureDupes(); + + var form = document.getElementById('importstepdup'); + // Move on to next step + document.getElementById('importstepdup').action.value = 'Step4'; + ProcessImport.begin(); +} + + +enableQS(false); + +EOJAVASCRIPT; + } +} + +?> diff --git a/modules/Import/views/view.extdupcheck.php b/modules/Import/views/view.extdupcheck.php new file mode 100644 index 00000000..c08cc3b6 --- /dev/null +++ b/modules/Import/views/view.extdupcheck.php @@ -0,0 +1,117 @@ +ss->assign("MODULE_TITLE", $this->getModuleTitle(false)); + $this->ss->assign("DELETE_INLINE_PNG", SugarThemeRegistry::current()->getImage('delete_inline','align="absmiddle" alt="'.$app_strings['LNK_DELETE'].'" border="0"')); + $this->ss->assign("PUBLISH_INLINE_PNG", SugarThemeRegistry::current()->getImage('publish_inline','align="absmiddle" alt="'.$mod_strings['LBL_PUBLISH'].'" border="0"')); + $this->ss->assign("UNPUBLISH_INLINE_PNG", SugarThemeRegistry::current()->getImage('unpublish_inline','align="absmiddle" alt="'.$mod_strings['LBL_UNPUBLISH'].'" border="0"')); + $this->ss->assign("IMPORT_MODULE", $_REQUEST['import_module']); + $this->ss->assign("JAVASCRIPT", $this->_getJS()); + $this->ss->assign("CURRENT_STEP", $this->currentStep); + + //BEGIN DRAG DROP WIDGET + $idc = new ImportDuplicateCheck($this->bean); + $dupe_indexes = $idc->getDuplicateCheckIndexes(); + + $dupe_disabled = array(); + + foreach($dupe_indexes as $dk=>$dv){ + $dupe_disabled[] = array("dupeVal" => $dk, "label" => $dv); + } + + + //set dragdrop value + $this->ss->assign('enabled_dupes', json_encode(array())); + $this->ss->assign('disabled_dupes', json_encode($dupe_disabled)); + //END DRAG DROP WIDGET + + $this->ss->assign("RECORDTHRESHOLD", $sugar_config['import_max_records_per_file']); + + $content = $this->ss->fetch('modules/Import/tpls/extdupcheck.tpl'); + $this->ss->assign("CONTENT",$content); + $this->ss->display('modules/Import/tpls/wizardWrapper.tpl'); + } + + /** + * Returns JS used in this view + */ + private function _getJS() + { + global $mod_strings; + + return << + +document.getElementById('goback').onclick = function(){ + document.getElementById('importstepdup').action.value = 'extstep1'; + document.getElementById('importstepdup').to_pdf.value = '0'; + return true; +} + + + + + + +EOJAVASCRIPT; + } +} + +?> diff --git a/modules/Import/views/view.last.php b/modules/Import/views/view.last.php index 0b532325..127fdddf 100644 --- a/modules/Import/views/view.last.php +++ b/modules/Import/views/view.last.php @@ -41,72 +41,16 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. * All Rights Reserved. ********************************************************************************/ -require_once('include/MVC/View/SugarView.php'); - +require_once('modules/Import/views/ImportView.php'); require_once('modules/Import/ImportCacheFiles.php'); +require_once('modules/Import/sources/ImportFile.php'); +require_once('modules/Import/views/ImportListView.php'); +require_once('include/ListView/ListViewFacade.php'); - -class ImportViewLast extends SugarView -{ - /** - * @see SugarView::getMenu() - */ - public function getMenu( - $module = null - ) - { - global $mod_strings, $current_language; - - if ( empty($module) ) - $module = $_REQUEST['import_module']; - - $old_mod_strings = $mod_strings; - $mod_strings = return_module_language($current_language, $module); - $returnMenu = parent::getMenu($module); - $mod_strings = $old_mod_strings; - - return $returnMenu; - } - - /** - * @see SugarView::_getModuleTab() - */ - protected function _getModuleTab() - { - global $app_list_strings, $moduleTabMap; - - // Need to figure out what tab this module belongs to, most modules have their own tabs, but there are exceptions. - if ( !empty($_REQUEST['module_tab']) ) - return $_REQUEST['module_tab']; - elseif ( isset($moduleTabMap[$_REQUEST['import_module']]) ) - return $moduleTabMap[$_REQUEST['import_module']]; - // Default anonymous pages to be under Home - elseif ( !isset($app_list_strings['moduleList'][$_REQUEST['import_module']]) ) - return 'Home'; - else - return $_REQUEST['import_module']; - } - - /** - * @see SugarView::_getModuleTitleParams() - */ - protected function _getModuleTitleParams($browserTitle = false) - { - global $mod_strings, $app_list_strings; - - $iconPath = $this->getModuleTitleIconPath($this->module); - $returnArray = array(); - if (!empty($iconPath) && !$browserTitle) { - $returnArray[] = "{$app_list_strings["; - } - else { - $returnArray[] = $app_list_strings['moduleList'][$_REQUEST['import_module']]; - } - $returnArray[] = "".$mod_strings['LBL_MODULE_NAME'].""; - $returnArray[] = $mod_strings['LBL_RESULTS']; - - return $returnArray; - } + +class ImportViewLast extends ImportView +{ + protected $pageTitleKey = 'LBL_STEP_5_TITLE'; /** * @see SugarView::display() @@ -115,17 +59,17 @@ class ImportViewLast extends SugarView { global $mod_strings, $app_strings, $current_user, $sugar_config, $current_language; + + $this->ss->assign("IMPORT_MODULE", $_REQUEST['import_module']); $this->ss->assign("TYPE", $_REQUEST['type']); $this->ss->assign("HEADER", $app_strings['LBL_IMPORT']." ". $mod_strings['LBL_MODULE_NAME']); - $this->ss->assign("MODULE_TITLE", $this->getModuleTitle()); + $this->ss->assign("MODULE_TITLE", $this->getModuleTitle(false)); // lookup this module's $mod_strings to get the correct module name $module_mod_strings = return_module_language($current_language, $_REQUEST['import_module']); $this->ss->assign("MODULENAME",$module_mod_strings['LBL_MODULE_NAME']); - $this->ss->assign("JAVASCRIPT", $this->_getJS()); - // read status file to get totals for records imported, errors, and duplicates $count = 0; $errorCount = 0; @@ -133,7 +77,8 @@ class ImportViewLast extends SugarView $createdCount = 0; $updatedCount = 0; $fp = sugar_fopen(ImportCacheFiles::getStatusFileName(),'r'); - while (( $row = fgetcsv($fp, 8192) ) !== FALSE) { + while (( $row = fgetcsv($fp, 8192) ) !== FALSE) + { $count += (int) $row[0]; $errorCount += (int) $row[1]; $dupeCount += (int) $row[2]; @@ -142,79 +87,115 @@ class ImportViewLast extends SugarView } fclose($fp); - $this->ss->assign("noSuccess",FALSE); - if(($count == $errorCount) || ($dupeCount == $count)){ - $this->ss->assign("noSuccess",TRUE); + $this->ss->assign("showUndoButton",FALSE); + if($createdCount > 0) + { + $this->ss->assign("showUndoButton",TRUE); } - + + if ($errorCount > 0 && ($createdCount <= 0 && $updatedCount <= 0)) + $activeTab = 2; + else if($dupeCount > 0 && ($createdCount <= 0 && $updatedCount <= 0)) + $activeTab = 1; + else + $activeTab = 0; + + $this->ss->assign("JAVASCRIPT", $this->_getJS($activeTab)); $this->ss->assign("errorCount",$errorCount); $this->ss->assign("dupeCount",$dupeCount); $this->ss->assign("createdCount",$createdCount); $this->ss->assign("updatedCount",$updatedCount); $this->ss->assign("errorFile",ImportCacheFiles::getErrorFileName()); - $this->ss->assign("errorrecordsFile",ImportCacheFiles::getErrorRecordsFileName()); + $this->ss->assign("errorrecordsFile",ImportCacheFiles::getErrorRecordsWithoutErrorFileName()); $this->ss->assign("dupeFile",ImportCacheFiles::getDuplicateFileName()); - if ( $this->bean->object_name == "Prospect" ) { - $this->ss->assign("PROSPECTLISTBUTTON", - $this->_addToProspectListButton()); + if ( $this->bean->object_name == "Prospect" ) + { + $this->ss->assign("PROSPECTLISTBUTTON", $this->_addToProspectListButton()); } else { $this->ss->assign("PROSPECTLISTBUTTON",""); } - - $this->ss->display('modules/Import/tpls/last.tpl'); - - foreach ( UsersLastImport::getBeansByImport($_REQUEST['import_module']) as $beanname ) { + + $resultsTable = ""; + foreach ( UsersLastImport::getBeansByImport($_REQUEST['import_module']) as $beanname ) + { // load bean - if ( !( $this->bean instanceof $beanname ) ) { + if ( !( $this->bean instanceof $beanname ) ) + { $this->bean = new $beanname; } - // build listview to show imported records - require_once('include/ListView/ListViewFacade.php'); - $lvf = new ListViewFacade($this->bean, $this->bean->module_dir, 0); - - $params = array(); - if(!empty($_REQUEST['orderBy'])) { - $params['orderBy'] = $_REQUEST['orderBy']; - $params['overrideOrder'] = true; - if(!empty($_REQUEST['sortOrder'])) $params['sortOrder'] = $_REQUEST['sortOrder']; - } - $beanname = ($this->bean->object_name == 'Case' ? 'aCase' : $this->bean->object_name); - // add users_last_import joins so we only show records done in this import - $params['custom_from'] = ', users_last_import'; - $params['custom_where'] = " AND users_last_import.assigned_user_id = '{$GLOBALS['current_user']->id}' - AND users_last_import.bean_type = '{$beanname}' - AND users_last_import.bean_id = {$this->bean->table_name}.id - AND users_last_import.deleted = 0 + $resultsTable .= $this->getListViewResults(); + } + if(empty($resultsTable)) + { + $resultsTable = $this->getListViewResults(); + } + + $this->ss->assign("RESULTS_TABLE", $resultsTable); + $this->ss->assign("ERROR_TABLE", $this->getListViewTableFromFile(ImportCacheFiles::getErrorRecordsFileName(), 'errors') ); + $this->ss->assign("DUP_TABLE", $this->getListViewTableFromFile(ImportCacheFiles::getDuplicateFileDisplayName(), 'dup')); + $content = $this->ss->fetch('modules/Import/tpls/last.tpl'); + $this->ss->assign("CONTENT",$content); + $this->ss->display('modules/Import/tpls/wizardWrapper.tpl'); + } + + protected function getListViewResults() + { + global $mod_strings, $current_language; + // build listview to show imported records + $lvf = new ListViewFacade($this->bean, $this->bean->module_dir, 0); + + $params = array(); + if(!empty($_REQUEST['orderBy'])) + { + $params['orderBy'] = $_REQUEST['orderBy']; + $params['overrideOrder'] = true; + if(!empty($_REQUEST['sortOrder'])) $params['sortOrder'] = $_REQUEST['sortOrder']; + } + $beanname = ($this->bean->object_name == 'Case' ? 'aCase' : $this->bean->object_name); + // add users_last_import joins so we only show records done in this import + $params['custom_from'] = ', users_last_import'; + $params['custom_where'] = " AND users_last_import.assigned_user_id = '{$GLOBALS['current_user']->id}' + AND users_last_import.bean_type = '{$beanname}' + AND users_last_import.bean_id = {$this->bean->table_name}.id + AND users_last_import.deleted = 0 AND {$this->bean->table_name}.deleted = 0"; - $where = " {$this->bean->table_name}.id IN ( + $where = " {$this->bean->table_name}.id IN ( SELECT users_last_import.bean_id FROM users_last_import - WHERE users_last_import.assigned_user_id = '{$GLOBALS['current_user']->id}' - AND users_last_import.bean_type = '{$beanname}' + WHERE users_last_import.assigned_user_id = '{$GLOBALS['current_user']->id}' + AND users_last_import.bean_type = '{$beanname}' AND users_last_import.deleted = 0 )"; - - $lbl_last_imported = $mod_strings['LBL_LAST_IMPORTED']; - $lvf->lv->mergeduplicates = false; - $lvf->lv->showMassupdateFields = false; - if ( $lvf->type == 2 ) { - $lvf->template = 'include/ListView/ListViewNoMassUpdate.tpl'; - } - $module_mod_strings = return_module_language($current_language, $this->bean->module_dir); - $lvf->setup('', $where, $params, $module_mod_strings, 0, -1, '', strtoupper($beanname), array(), 'id'); - $lvf->display($lbl_last_imported.": ".$module_mod_strings['LBL_MODULE_NAME']); - } + + $lvf->lv->mergeduplicates = false; + $lvf->lv->showMassupdateFields = false; + if ( $lvf->type == 2 ) + $lvf->template = 'include/ListView/ListViewNoMassUpdate.tpl'; + + $module_mod_strings = return_module_language($current_language, $this->bean->module_dir); + $lvf->setup('', $where, $params, $module_mod_strings, 0, -1, '', strtoupper($beanname), array(), 'id'); + global $app_list_strings; + return $lvf->display($app_list_strings['moduleList'][$this->bean->module_dir], 'main', TRUE); + + } + + protected function getListViewTableFromFile($fileName, $tableName) + { + $has_header = $_REQUEST['has_header'] == 'on' ? TRUE : FALSE; + $if = new ImportFile($fileName, ",", '"', FALSE, FALSE); + $if->setHeaderRow($has_header); + $lv = new ImportListView($if,array('offset'=> 0), $tableName); + return $lv->display(TRUE); } /** * Returns JS used in this view */ - private function _getJS() + private function _getJS($activeTab) { return << - - + +if ( typeof(SUGAR) == 'undefined' ) + SUGAR = {}; +if ( typeof(SUGAR.IV) == 'undefined' ) + SUGAR.IV = {}; + +SUGAR.IV = { + + getTable : function(tableID, offset) { + var callback = { + success: function(o) + { + var tableKey = tableID + '_table'; + document.getElementById(tableKey).innerHTML = o.responseText; + }, + failure: function(o) {}, + }; + var has_header = document.getElementById('importlast').has_header.value + var url = 'index.php?action=RefreshTable&module=Import&offset=' + offset + '&tableID=' + tableID + '&has_header=' + has_header; + YAHOO.util.Connect.asyncRequest('GET', url, callback); + }, + togglePages : function(activePage) + { + var num_tabs = 3; + var pageId = 'pageNumIW_' + activePage; + activeDashboardPage = activePage; + activeTab = activePage; + + //hide all pages first for display purposes + for(var i=0; i < num_tabs; i++) + { + var pageDivId = 'pageNumIW_'+i+'_div'; + var pageDivElem = document.getElementById(pageDivId); + pageDivElem.style.display = 'none'; + } + + for(var i=0; i < num_tabs; i++) + { + var tabId = 'pageNumIW_'+i; + var anchorId = 'pageNumIW_'+i+'_anchor'; + var pageDivId = 'pageNumIW_'+i+'_div'; + + var tabElem = document.getElementById(tabId); + var anchorElem = document.getElementById(anchorId); + var pageDivElem = document.getElementById(pageDivId); + + if(tabId == pageId) + { + tabElem.className = 'active'; + anchorElem.className = 'current'; + pageDivElem.style.display = ''; + } + else + { + tabElem.className = ''; + anchorElem.className = ''; + } + } + } +} + +SUGAR.IV.togglePages('$activeTab'); + EOJAVASCRIPT; } @@ -239,29 +282,14 @@ EOJAVASCRIPT; { global $app_strings, $sugar_version, $sugar_config, $current_user; - $query = "SELECT distinct - prospects.id, - prospects.assigned_user_id, - prospects.first_name, - prospects.last_name, - prospects.phone_work, - prospects.title, - email_addresses.email_address email1, - users.user_name as assigned_user_name + $query = "SELECT distinct prospects.id, prospects.assigned_user_id, prospects.first_name, prospects.last_name, prospects.phone_work, prospects.title, + email_addresses.email_address email1, users.user_name as assigned_user_name FROM users_last_import,prospects - LEFT JOIN users - ON prospects.assigned_user_id=users.id + LEFT JOIN users ON prospects.assigned_user_id=users.id LEFT JOIN email_addr_bean_rel on prospects.id = email_addr_bean_rel.bean_id and email_addr_bean_rel.bean_module='Prospect' and email_addr_bean_rel.primary_address=1 and email_addr_bean_rel.deleted=0 - LEFT JOIN email_addresses on email_addresses.id = email_addr_bean_rel.email_address_id - - WHERE - users_last_import.assigned_user_id= - '{$current_user->id}' - AND users_last_import.bean_type='Prospect' - AND users_last_import.bean_id=prospects.id - AND users_last_import.deleted=0 - AND prospects.deleted=0 - "; + LEFT JOIN email_addresses on email_addresses.id = email_addr_bean_rel.email_address_id + WHERE users_last_import.assigned_user_id = '{$current_user->id}' AND users_last_import.bean_type='Prospect' AND users_last_import.bean_id=prospects.id + AND users_last_import.deleted=0 AND prospects.deleted=0"; $popup_request_data = array( 'call_back_function' => 'set_return_and_save_background', diff --git a/modules/Import/views/view.step1.php b/modules/Import/views/view.step1.php index ba1df780..6028a3a7 100644 --- a/modules/Import/views/view.step1.php +++ b/modules/Import/views/view.step1.php @@ -41,86 +41,25 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. * All Rights Reserved. ********************************************************************************/ -require_once('include/MVC/View/SugarView.php'); +require_once('modules/Import/views/ImportView.php'); +require_once('include/externalAPI/ExternalAPIFactory.php'); +require_once('modules/Import/Importer.php'); - -class ImportViewStep1 extends SugarView -{ - /** - * @see SugarView::getMenu() - */ - public function getMenu( - $module = null - ) - { - global $mod_strings, $current_language; - - if ( empty($module) ) - $module = $_REQUEST['import_module']; - - $old_mod_strings = $mod_strings; - $mod_strings = return_module_language($current_language, $module); - $returnMenu = parent::getMenu($module); - $mod_strings = $old_mod_strings; - - return $returnMenu; - } - - /** - * @see SugarView::_getModuleTab() - */ - protected function _getModuleTab() + +class ImportViewStep1 extends ImportView +{ + + protected $pageTitleKey = 'LBL_STEP_1_TITLE'; + + public function __construct($bean = null, $view_object_map = array()) { - global $app_list_strings, $moduleTabMap; - - // Need to figure out what tab this module belongs to, most modules have their own tabs, but there are exceptions. - if ( !empty($_REQUEST['module_tab']) ) - return $_REQUEST['module_tab']; - elseif ( isset($moduleTabMap[$_REQUEST['import_module']]) ) - return $moduleTabMap[$_REQUEST['import_module']]; - // Default anonymous pages to be under Home - elseif ( !isset($app_list_strings['moduleList'][$_REQUEST['import_module']]) ) - return 'Home'; - else - return $_REQUEST['import_module']; - } - - /** - * @see SugarView::_getModuleTitleParams() - */ - protected function _getModuleTitleParams($browserTitle = false) - { - global $mod_strings, $app_list_strings; - - $iconPath = $this->getModuleTitleIconPath($this->module); - $returnArray = array(); - if (!empty($iconPath) && !$browserTitle) { - $returnArray[] = "{$app_list_strings["; - } - else { - $returnArray[] = $app_list_strings['moduleList'][$_REQUEST['import_module']]; - } - $returnArray[] = "".$mod_strings['LBL_MODULE_NAME'].""; - $returnArray[] = $mod_strings['LBL_STEP_1_TITLE']; - - return $returnArray; + parent::__construct($bean, $view_object_map); + $this->currentStep = isset($_REQUEST['current_step']) ? ($_REQUEST['current_step'] + 1) : 1; + $this->importModule = isset($_REQUEST['import_module']) ? $_REQUEST['import_module'] : ''; + if( isset($_REQUEST['from_admin_wizard']) && $_REQUEST['from_admin_wizard'] ) + $this->importModule = 'Administration'; } - - private function _retrieveParams() { - $selectedData = new stdClass(); - foreach ($_POST as $key => &$value) { - trim(strip_tags($value)); - $selectedData->$key = $value; - } - if (isset($selectedData->custom_enclosure)) { - if ($selectedData->custom_enclosure != '"' and $selectedData->custom_enclosure != ''' and $selectedData->custom_enclosure != '') { - $selectedData->custom_other = true; - } - } - $this->ss->assign('selectedData', $selectedData); - return $selectedData; - } - + /** * @see SugarView::display() */ @@ -128,221 +67,237 @@ class ImportViewStep1 extends SugarView { global $mod_strings, $app_strings, $current_user; global $sugar_config; - - $selectedData = $this->_retrieveParams(); - - $this->ss->assign("MODULE_TITLE", $this->getModuleTitle()); + + $this->ss->assign("MODULE_TITLE", $this->getModuleTitle(false) ); $this->ss->assign("DELETE_INLINE_PNG", SugarThemeRegistry::current()->getImage('delete_inline','align="absmiddle" alt="'.$app_strings['LNK_DELETE'].'" border="0"')); $this->ss->assign("PUBLISH_INLINE_PNG", SugarThemeRegistry::current()->getImage('publish_inline','align="absmiddle" alt="'.$mod_strings['LBL_PUBLISH'].'" border="0"')); $this->ss->assign("UNPUBLISH_INLINE_PNG", SugarThemeRegistry::current()->getImage('unpublish_inline','align="absmiddle" alt="'.$mod_strings['LBL_UNPUBLISH'].'" border="0"')); $this->ss->assign("IMPORT_MODULE", $_REQUEST['import_module']); - $this->ss->assign("JAVASCRIPT", $this->_getJS(isset($selectedData->source) ? $selectedData->source : false)); - - - // handle publishing and deleting import maps - if (isset($_REQUEST['delete_map_id'])) { - $import_map = new ImportMap(); - $import_map->mark_deleted($_REQUEST['delete_map_id']); - } - - if (isset($_REQUEST['publish']) ) { - $import_map = new ImportMap(); - $result = 0; - - $import_map = $import_map->retrieve($_REQUEST['import_map_id'], false); - - if ($_REQUEST['publish'] == 'yes') { - $result = $import_map->mark_published($current_user->id,true); - if (!$result) { - $this->ss->assign("ERROR",$mod_strings['LBL_ERROR_UNABLE_TO_PUBLISH']); - } - } - elseif ( $_REQUEST['publish'] == 'no') { - // if you don't own this importmap, you do now! - // unless you have a map by the same name - $result = $import_map->mark_published($current_user->id,false); - if (!$result) { - $this->ss->assign("ERROR",$mod_strings['LBL_ERROR_UNABLE_TO_UNPUBLISH']); - } - } - + + $showModuleSelection = ($this->importModule == 'Administration'); + $importableModulesOptions = array(); + $importablePersonModules = array(); + //If we are coming from the admin link, get the module list. + if($showModuleSelection) + { + $tmpImportable = Importer::getImportableModules(); + $importableModulesOptions = get_select_options_with_id($tmpImportable, ''); + $importablePersonModules = $this->getImportablePersonModulesJS(); + $this->ss->assign("IMPORT_MODULE", key($tmpImportable)); } - - // trigger showing other software packages - $this->ss->assign("show_salesforce",false); - $this->ss->assign("show_outlook",false); - $this->ss->assign("show_act",false); - switch ($_REQUEST['import_module']) { - case "Prospects": - break; - case "Accounts": - $this->ss->assign("show_salesforce",true); - $this->ss->assign("show_act",true); - break; - case "Contacts": - $this->ss->assign("show_salesforce",true); - $this->ss->assign("show_outlook",true); - $this->ss->assign("show_act",true); - break; - default: - $this->ss->assign("show_salesforce",true); - break; + else + { + $this->instruction = 'LBL_SELECT_DS_INSTRUCTION'; + $this->ss->assign('INSTRUCTION', $this->getInstruction()); } + $this->ss->assign("FROM_ADMIN", $showModuleSelection); + $this->ss->assign("PERSON_MODULE_LIST", json_encode($importablePersonModules)); + $this->ss->assign("showModuleSelection", $showModuleSelection); + $this->ss->assign("IMPORTABLE_MODULES_OPTIONS", $importableModulesOptions); + + $this->ss->assign("EXTERNAL_SOURCES", $this->getAllImportableExternalEAPMs()); + $this->ss->assign("EXTERNAL_AUTHENTICATED_SOURCES", json_encode($this->getAuthenticatedImportableExternalEAPMs()) ); + $selectExternal = !empty($_REQUEST['application']) ? $_REQUEST['application'] : ''; + $this->ss->assign("selectExternalSource", $selectExternal); + + $content = $this->ss->fetch('modules/Import/tpls/step1.tpl'); - // show any custom mappings - if (sugar_is_dir('custom/modules/Import') && $dir = opendir('custom/modules/Import')) + $submitContent = "
"; + $submitContent .= ""; + $submitContent .= "
"; + + $this->ss->assign("JAVASCRIPT",$this->_getJS() ); + $this->ss->assign("CONTENT",$content); + $this->ss->display('modules/Import/tpls/wizardWrapper.tpl'); + + } + + private function getImportablePersonModulesJS() + { + global $beanList; + $results = array(); + foreach ($beanList as $moduleName => $beanName) { - while (($file = readdir($dir)) !== false) + if( class_exists($beanName) ) { - if (sugar_is_file("custom/modules/Import/{$file}") && strpos($file,".php") !== false) - { - require_once("custom/modules/Import/{$file}"); - $classname = str_replace('.php','',$file); - $mappingClass = new $classname; - $custom_mappings[] = $mappingClass->name; - } - } - } - - - // get user defined import maps - $this->ss->assign('is_admin',is_admin($current_user)); - $import_map_seed = new ImportMap(); - $custom_imports_arr = $import_map_seed->retrieve_all_by_string_fields( - array( - 'assigned_user_id' => $current_user->id, - 'is_published' => 'no', - 'module' => $_REQUEST['import_module'], - ) - ); - - if ( count($custom_imports_arr) ) { - $custom = array(); - foreach ( $custom_imports_arr as $import) { - $custom[] = array( - "IMPORT_NAME" => $import->name, - "IMPORT_ID" => $import->id, - ); + $tmp = new $beanName(); + if( isset($tmp->importable) && $tmp->importable && ($tmp instanceof Person)) + $results[$moduleName] = $moduleName; } - $this->ss->assign('custom_imports',$custom); } - - // get globally defined import maps - $published_imports_arr = $import_map_seed->retrieve_all_by_string_fields( - array( - 'is_published' => 'yes', - 'module' => $_REQUEST['import_module'], - ) - ); - - if ( count($published_imports_arr) ) { - $published = array(); - foreach ( $published_imports_arr as $import) { - $published[] = array( - "IMPORT_NAME" => $import->name, - "IMPORT_ID" => $import->id, - ); - } - $this->ss->assign('published_imports',$published); - } - - $this->ss->display('modules/Import/tpls/step1.tpl'); + + return $results; + } + + private function getAllImportableExternalEAPMs() + { + ExternalAPIFactory::clearCache(); + return ExternalAPIFactory::getModuleDropDown('Import', TRUE, FALSE); + } + + private function getAuthenticatedImportableExternalEAPMs() + { + return ExternalAPIFactory::getModuleDropDown('Import', FALSE, FALSE); } - /** * Returns JS used in this view */ private function _getJS($sourceType = false) { global $mod_strings; - - if (!$sourceType) { - $sourceType = 'csv'; - } - $getElementById = "document.getElementById('source_{$sourceType}')"; - $sourceType = "defineEnclosureSelectPosition('{$sourceType}', {$getElementById});"; + $EXTERNAL_AUTHENTICATED_SOURCES = json_encode($this->getAuthenticatedImportableExternalEAPMs()); + $selectExternalSource = !empty($_REQUEST['application']) ? $_REQUEST['application'] : ''; + + $showModuleSelection = ($this->importModule == 'Administration'); + $importableModulesOptions = array(); + $importablePersonModules = array(); + //If we are coming from the admin link, get the module list. + if($showModuleSelection) + { + $importablePersonModules = $this->getImportablePersonModulesJS(); + } + + + $PERSON_MODULE_LIST = json_encode($importablePersonModules); return << - - + + +var auth_sources = {$EXTERNAL_AUTHENTICATED_SOURCES} +var selectedExternalSource = '{$selectExternalSource}'; +var personModules = {$PERSON_MODULE_LIST}; EOJAVASCRIPT; } diff --git a/modules/Import/views/view.step2.php b/modules/Import/views/view.step2.php index 2f8e6329..b0d54af9 100644 --- a/modules/Import/views/view.step2.php +++ b/modules/Import/views/view.step2.php @@ -42,84 +42,30 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); * All Rights Reserved. ********************************************************************************/ -require_once('include/MVC/View/SugarView.php'); +require_once('modules/Import/views/ImportView.php'); -class ImportViewStep2 extends SugarView -{ - /** - * @see SugarView::getMenu() - */ - public function getMenu( - $module = null - ) - { - global $mod_strings, $current_language; - - if ( empty($module) ) - $module = $_REQUEST['import_module']; - - $old_mod_strings = $mod_strings; - $mod_strings = return_module_language($current_language, $module); - $returnMenu = parent::getMenu($module); - $mod_strings = $old_mod_strings; - - return $returnMenu; - } - - /** - * @see SugarView::_getModuleTab() - */ - protected function _getModuleTab() - { - global $app_list_strings, $moduleTabMap; - - // Need to figure out what tab this module belongs to, most modules have their own tabs, but there are exceptions. - if ( !empty($_REQUEST['module_tab']) ) - return $_REQUEST['module_tab']; - elseif ( isset($moduleTabMap[$_REQUEST['import_module']]) ) - return $moduleTabMap[$_REQUEST['import_module']]; - // Default anonymous pages to be under Home - elseif ( !isset($app_list_strings['moduleList'][$_REQUEST['import_module']]) ) - return 'Home'; - else - return $_REQUEST['import_module']; - } - - /** - * @see SugarView::_getModuleTitleParams() - */ - protected function _getModuleTitleParams() - { - global $mod_strings, $app_list_strings; - - $iconPath = $this->getModuleTitleIconPath($this->module); - $returnArray = array(); - if (!empty($iconPath) && !$browserTitle) { - $returnArray[] = "{$app_list_strings["; - } - else { - $returnArray[] = $app_list_strings['moduleList'][$_REQUEST['import_module']]; - } - $returnArray[] = "".$mod_strings['LBL_MODULE_NAME'].""; - $returnArray[] = $mod_strings['LBL_STEP_2_TITLE']; - - return $returnArray; - } +class ImportViewStep2 extends ImportView +{ + protected $pageTitleKey = 'LBL_STEP_2_TITLE'; + /** * @see SugarView::display() */ public function display() { global $mod_strings, $app_list_strings, $app_strings, $current_user, $import_bean_map; - global $import_mod_strings; + global $import_mod_strings; - $this->ss->assign("MODULE_TITLE", $this->getModuleTitle()); + $this->instruction = 'LBL_SELECT_UPLOAD_INSTRUCTION'; + $this->ss->assign('INSTRUCTION', $this->getInstruction()); + + $this->ss->assign("MODULE_TITLE", $this->getModuleTitle(false)); $this->ss->assign("IMP", $import_mod_strings); + $this->ss->assign("CURRENT_STEP", $this->currentStep); $this->ss->assign("TYPE",( !empty($_REQUEST['type']) ? $_REQUEST['type'] : "import" )); - $this->ss->assign("CUSTOM_DELIMITER", - ( !empty($_REQUEST['custom_delimiter']) ? $_REQUEST['custom_delimiter'] : "," )); + $this->ss->assign("CUSTOM_DELIMITER", ( !empty($_REQUEST['custom_delimiter']) ? $_REQUEST['custom_delimiter'] : "," )); $this->ss->assign("CUSTOM_ENCLOSURE",htmlentities( ( !empty($_REQUEST['custom_enclosure']) && $_REQUEST['custom_enclosure'] != 'other' ? $_REQUEST['custom_enclosure'] : @@ -129,97 +75,80 @@ class ImportViewStep2 extends SugarView $this->ss->assign("IMPORT_MODULE", $_REQUEST['import_module']); $this->ss->assign("HEADER", $app_strings['LBL_IMPORT']." ". $mod_strings['LBL_MODULE_NAME']); $this->ss->assign("JAVASCRIPT", $this->_getJS()); + $this->ss->assign("SAMPLE_URL", "".$mod_strings['LBL_EXAMPLE_FILE'].""); + + $displayBackBttn = isset($_REQUEST['return_action']) && $_REQUEST['return_action'] != 'index'? TRUE : FALSE; + $this->ss->assign("displayBackBttn", $displayBackBttn); - // special for importing from Outlook - if ($_REQUEST['source'] == "outlook") { - $this->ss->assign("SOURCE", $_REQUEST['source']); - $this->ss->assign("SOURCE_NAME","Outlook "); - $this->ss->assign("HAS_HEADER_CHECKED"," CHECKED"); - } - // see if the source starts with 'custom' - // if so, pull off the id, load that map, and get the name - elseif ( strncasecmp("custom:",$_REQUEST['source'],7) == 0) { - $id = substr($_REQUEST['source'],7); - $import_map_seed = new ImportMap(); - $import_map_seed->retrieve($id, false); - - $this->ss->assign("SOURCE_ID", $import_map_seed->id); - $this->ss->assign("SOURCE_NAME", $import_map_seed->name); - $this->ss->assign("SOURCE", $import_map_seed->source); - if (isset($import_map_seed->delimiter)) - $this->ss->assign("CUSTOM_DELIMITER", $import_map_seed->delimiter); - if (isset($import_map_seed->enclosure)) - $this->ss->assign("CUSTOM_ENCLOSURE", htmlentities($import_map_seed->enclosure)); - if ($import_map_seed->has_header) - $this->ss->assign("HAS_HEADER_CHECKED"," CHECKED"); - } - else { - $classname = 'ImportMap' . ucfirst($_REQUEST['source']); - if ( file_exists("modules/Import/{$classname}.php") ) - require_once("modules/Import/{$classname}.php"); - elseif ( file_exists("custom/modules/Import/{$classname}.php") ) - require_once("custom/modules/Import/{$classname}.php"); - else { - require_once("custom/modules/Import/ImportMapOther.php"); - $classname = 'ImportMapOther'; - $_REQUEST['source'] = 'other'; + $importSource = isset($_REQUEST['source']) ? $_REQUEST['source'] : 'csv' ; + //Start custom mapping + // show any custom mappings + if (sugar_is_dir('custom/modules/Import') && $dir = opendir('custom/modules/Import')) + { + while (($file = readdir($dir)) !== false) + { + if (sugar_is_file("custom/modules/Import/{$file}") && strpos($file,".php") !== false) + { + require_once("custom/modules/Import/{$file}"); + $classname = str_replace('.php','',$file); + $mappingClass = new $classname; + $custom_mappings[] = $mappingClass->name; + } } - if ( class_exists($classname) ) { - $import_map_seed = new $classname; - if (isset($import_map_seed->delimiter)) - $this->ss->assign("CUSTOM_DELIMITER", $import_map_seed->delimiter); - if (isset($import_map_seed->enclosure)) - $this->ss->assign("CUSTOM_ENCLOSURE", htmlentities($import_map_seed->enclosure)); - if ($import_map_seed->has_header) - $this->ss->assign("HAS_HEADER_CHECKED"," CHECKED"); - $this->ss->assign("SOURCE", $_REQUEST['source']); + } + // get user defined import maps + $is_admin = is_admin($current_user); + if($is_admin) + $savedMappingHelpText = $mod_strings['LBL_MY_SAVED_ADMIN_HELP']; + else + $savedMappingHelpText = $mod_strings['LBL_MY_SAVED_HELP']; + + $this->ss->assign('savedMappingHelpText',$savedMappingHelpText); + $this->ss->assign('is_admin',$is_admin); + + $import_map_seed = new ImportMap(); + $custom_imports_arr = $import_map_seed->retrieve_all_by_string_fields( array('assigned_user_id' => $current_user->id, 'is_published' => 'no','module' => $_REQUEST['import_module'])); + + if( count($custom_imports_arr) ) + { + $custom = array(); + foreach ( $custom_imports_arr as $import) + { + $custom[] = array( "IMPORT_NAME" => $import->name,"IMPORT_ID" => $import->id); } + $this->ss->assign('custom_imports',$custom); } - // add instructions for anything other than custom_delimited - if ($_REQUEST['source'] != 'other') + // get globally defined import maps + $published_imports_arr = $import_map_seed->retrieve_all_by_string_fields(array('is_published' => 'yes', 'module' => $_REQUEST['import_module'],) ); + if ( count($published_imports_arr) ) { - $instructions = array(); - $lang_key = ''; - switch($_REQUEST['source']) { - case "act": - $lang_key = "ACT"; - break; - case "outlook": - $lang_key = "OUTLOOK"; - break; - case "salesforce": - $lang_key = "SF"; - break; - case "tab": - $lang_key = "TAB"; - break; - case "csv": - $lang_key = "CUSTOM"; - break; - case "other": - break; - default: - $lang_key = "CUSTOM_MAPPING_".strtoupper($import_map_seed->name); - break; + $published = array(); + foreach ( $published_imports_arr as $import) + { + $published[] = array("IMPORT_NAME" => $import->name, "IMPORT_ID" => $import->id); } - if ( $lang_key != '' ) { - for ($i = 1; isset($mod_strings["LBL_{$lang_key}_NUM_$i"]);$i++) { - $instructions[] = array( - "STEP_NUM" => $mod_strings["LBL_NUM_$i"], - "INSTRUCTION_STEP" => $mod_strings["LBL_{$lang_key}_NUM_$i"], - ); - } - if(!isset($mod_strings["LBL_IMPORT_{$lang_key}_TITLE"])){ - $lang_key = 'CUSTOM'; - } + $this->ss->assign('published_imports',$published); + } + //End custom mapping - $this->ss->assign("INSTRUCTIONS_TITLE",$mod_strings["LBL_IMPORT_{$lang_key}_TITLE"]); - $this->ss->assign("instructions",$instructions); - } + // add instructions for anything other than custom_delimited + $instructions = array(); + $lang_key = "CUSTOM"; + + for ($i = 1; isset($mod_strings["LBL_{$lang_key}_NUM_$i"]);$i++) + { + $instructions[] = array( + "STEP_NUM" => $mod_strings["LBL_NUM_$i"], + "INSTRUCTION_STEP" => $mod_strings["LBL_{$lang_key}_NUM_$i"], + ); } - - $this->ss->display('modules/Import/tpls/step2.tpl'); + $this->ss->assign("INSTRUCTIONS_TITLE",$mod_strings["LBL_IMPORT_{$lang_key}_TITLE"]); + $this->ss->assign("instructions",$instructions); + + $content = $this->ss->fetch('modules/Import/tpls/step2.tpl'); + $this->ss->assign("CONTENT",$content); + $this->ss->display('modules/Import/tpls/wizardWrapper.tpl'); } /** @@ -230,15 +159,25 @@ class ImportViewStep2 extends SugarView global $mod_strings; return << - - EOJAVASCRIPT; } diff --git a/modules/Import/views/view.step3.php b/modules/Import/views/view.step3.php index 758af840..635d38d4 100644 --- a/modules/Import/views/view.step3.php +++ b/modules/Import/views/view.step3.php @@ -41,76 +41,22 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); * Portions created by SugarCRM are Copyright (C) SugarCRM, Inc. * All Rights Reserved. ********************************************************************************/ -require_once('include/MVC/View/SugarView.php'); -require_once('modules/Import/ImportFile.php'); +require_once('modules/Import/views/ImportView.php'); +require_once('modules/Import/sources/ImportFile.php'); require_once('modules/Import/ImportFileSplitter.php'); require_once('modules/Import/ImportCacheFiles.php'); require_once('modules/Import/ImportDuplicateCheck.php'); require_once('include/upload_file.php'); -class ImportViewStep3 extends SugarView +class ImportViewStep3 extends ImportView { - /** - * @see SugarView::getMenu() - */ - public function getMenu( - $module = null - ) - { - global $mod_strings, $current_language; - - if ( empty($module) ) - $module = $_REQUEST['import_module']; - - $old_mod_strings = $mod_strings; - $mod_strings = return_module_language($current_language, $module); - $returnMenu = parent::getMenu($module); - $mod_strings = $old_mod_strings; - - return $returnMenu; - } - - /** - * @see SugarView::_getModuleTab() - */ - protected function _getModuleTab() - { - global $app_list_strings, $moduleTabMap; - - // Need to figure out what tab this module belongs to, most modules have their own tabs, but there are exceptions. - if ( !empty($_REQUEST['module_tab']) ) - return $_REQUEST['module_tab']; - elseif ( isset($moduleTabMap[$_REQUEST['import_module']]) ) - return $moduleTabMap[$_REQUEST['import_module']]; - // Default anonymous pages to be under Home - elseif ( !isset($app_list_strings['moduleList'][$_REQUEST['import_module']]) ) - return 'Home'; - else - return $_REQUEST['import_module']; - } - - /** - * @see SugarView::_getModuleTitleParams() - */ - protected function _getModuleTitleParams($browserTitle = false) - { - global $mod_strings, $app_list_strings; - - $iconPath = $this->getModuleTitleIconPath($this->module); - $returnArray = array(); - if (!empty($iconPath) && !$browserTitle) { - $returnArray[] = "{$app_list_strings["; - } - else { - $returnArray[] = $app_list_strings['moduleList'][$_REQUEST['import_module']]; - } - $returnArray[] = "".$mod_strings['LBL_MODULE_NAME'].""; - $returnArray[] = $mod_strings['LBL_STEP_3_TITLE']; - - return $returnArray; - } + protected $pageTitleKey = 'LBL_STEP_3_TITLE'; + protected $currentFormID = 'importstep3'; + protected $previousAction = 'Confirm'; + protected $nextAction = 'dupcheck'; + /** * @see SugarView::display() */ @@ -120,21 +66,18 @@ class ImportViewStep3 extends SugarView $this->ss->assign("IMPORT_MODULE", $_REQUEST['import_module']); $has_header = ( isset( $_REQUEST['has_header']) ? 1 : 0 ); - $sugar_config['import_max_records_per_file'] = - ( empty($sugar_config['import_max_records_per_file']) - ? 1000 : $sugar_config['import_max_records_per_file'] ); - - // Clear out this user's last import - $seedUsersLastImport = new UsersLastImport(); - $seedUsersLastImport->mark_deleted_by_user_id($current_user->id); - ImportCacheFiles::clearCacheFiles(); - + $sugar_config['import_max_records_per_file'] = ( empty($sugar_config['import_max_records_per_file']) ? 1000 : $sugar_config['import_max_records_per_file'] ); + $this->ss->assign("CURRENT_STEP", $this->currentStep); // attempt to lookup a preexisting field map // use the custom one if specfied to do so in step 1 - $field_map = array(); + $mapping_file = new ImportMap(); + $field_map = $mapping_file->set_get_import_wizard_fields(); $default_values = array(); $ignored_fields = array(); - if ( !empty( $_REQUEST['source_id'])) { + + if ( !empty( $_REQUEST['source_id'])) + { + $GLOBALS['log']->fatal("Loading import map properties."); $mapping_file = new ImportMap(); $mapping_file->retrieve( $_REQUEST['source_id'],false); $_REQUEST['source'] = $mapping_file->source; @@ -144,99 +87,66 @@ class ImportViewStep3 extends SugarView if (isset($mapping_file->enclosure)) $_REQUEST['custom_enclosure'] = htmlentities($mapping_file->enclosure); $field_map = $mapping_file->getMapping(); + //print_r($field_map);die(); $default_values = $mapping_file->getDefaultValues(); $this->ss->assign("MAPNAME",$mapping_file->name); $this->ss->assign("CHECKMAP",'checked="checked" value="on"'); } - else { + else + { // Try to see if we have a custom mapping we can use // based upon the where the records are coming from // and what module we are importing into $classname = 'ImportMap' . ucfirst($_REQUEST['source']); - if ( file_exists("modules/Import/{$classname}.php") ) - require_once("modules/Import/{$classname}.php"); - elseif ( file_exists("custom/modules/Import/{$classname}.php") ) - require_once("custom/modules/Import/{$classname}.php"); + if ( file_exists("modules/Import/maps/{$classname}.php") ) + require_once("modules/Import/maps/{$classname}.php"); + elseif ( file_exists("custom/modules/Import/maps/{$classname}.php") ) + require_once("custom/modules/Import/maps/{$classname}.php"); else { - require_once("custom/modules/Import/ImportMapOther.php"); + require_once("custom/modules/Import/maps/ImportMapOther.php"); $classname = 'ImportMapOther'; $_REQUEST['source'] = 'other'; } - if ( class_exists($classname) ) { + + if ( class_exists($classname) ) + { $mapping_file = new $classname; - if (isset($mapping_file->delimiter)) - $_REQUEST['custom_delimiter'] = $mapping_file->delimiter; - if (isset($mapping_file->enclosure)) - $_REQUEST['custom_enclosure'] = htmlentities($mapping_file->enclosure); $ignored_fields = $mapping_file->getIgnoredFields($_REQUEST['import_module']); - $field_map = $mapping_file->getMapping($_REQUEST['import_module']); + $field_map2 = $mapping_file->getMapping($_REQUEST['import_module']); + $field_map = array_merge($field_map,$field_map2); } } - $this->ss->assign("CUSTOM_DELIMITER", - ( !empty($_REQUEST['custom_delimiter']) ? $_REQUEST['custom_delimiter'] : "," )); - $this->ss->assign("CUSTOM_ENCLOSURE", - ( !empty($_REQUEST['custom_enclosure']) ? $_REQUEST['custom_enclosure'] : "" )); - - // handle uploaded file - $uploadFile = new UploadFile('userfile'); - if (isset($_FILES['userfile']) && $uploadFile->confirm_upload()) - { - $uploadFile->final_move('IMPORT_'.$this->bean->object_name.'_'.$current_user->id); - $uploadFileName = $uploadFile->get_upload_path('IMPORT_'.$this->bean->object_name.'_'.$current_user->id); - } - else { - $this->_showImportError($mod_strings['LBL_IMPORT_MODULE_ERROR_NO_UPLOAD'],$_REQUEST['import_module'],'Step2'); - return; - } + $delimeter = $this->getRequestDelimiter(); + + $this->ss->assign("CUSTOM_DELIMITER", $delimeter); + $this->ss->assign("CUSTOM_ENCLOSURE", ( !empty($_REQUEST['custom_enclosure']) ? $_REQUEST['custom_enclosure'] : "" )); - // split file into parts - $splitter = new ImportFileSplitter( - $uploadFileName, - $sugar_config['import_max_records_per_file']); - $splitter->splitSourceFile( - $_REQUEST['custom_delimiter'], - html_entity_decode($_REQUEST['custom_enclosure'],ENT_QUOTES), - $has_header - ); + //populate import locale values from import mapping if available, these values will be used througout the rest of the code path + + $uploadFileName = $_REQUEST['file_name']; // Now parse the file and look for errors - $importFile = new ImportFile( - $uploadFileName, - $_REQUEST['custom_delimiter'], - html_entity_decode($_REQUEST['custom_enclosure'],ENT_QUOTES) - ); + $importFile = new ImportFile( $uploadFileName, $delimeter, html_entity_decode($_REQUEST['custom_enclosure'],ENT_QUOTES), FALSE); if ( !$importFile->fileExists() ) { $this->_showImportError($mod_strings['LBL_CANNOT_OPEN'],$_REQUEST['import_module'],'Step2'); return; } + $charset = $importFile->autoDetectCharacterSet(); + // retrieve first 3 rows $rows = array(); - $system_charset = $locale->default_export_charset; - $user_charset = $locale->getExportCharset(); - $other_charsets = 'UTF-8, UTF-7, ASCII, CP1252, EUC-JP, SJIS, eucJP-win, SJIS-win, JIS, ISO-2022-JP'; - $detectable_charsets = "UTF-8, {$user_charset}, {$system_charset}, {$other_charsets}"; - // Bug 26824 - mb_detect_encoding() thinks CP1252 is IS0-8859-1, so use that instead in the encoding list passed to the function - $detectable_charsets = str_replace('CP1252','ISO-8859-1',$detectable_charsets); - $charset_for_import = $user_charset; //We will set the default import charset option by user's preference. - $able_to_detect = function_exists('mb_detect_encoding'); - for ( $i = 0; $i < 3; $i++ ) { - $rows[$i] = $importFile->getNextRow(); - if(!empty($rows[$i]) && $able_to_detect) { - foreach($rows[$i] as & $temp_value) { - $current_charset = mb_detect_encoding($temp_value, $detectable_charsets); - if(!empty($current_charset) && $current_charset != "UTF-8") { - $temp_value = $locale->translateCharset($temp_value, $current_charset);// we will use utf-8 for displaying the data on the page. - $charset_for_import = $current_charset; - //set the default import charset option according to the current_charset. - //If it is not utf-8, tt may be overwritten by the later one. So the uploaded file should not contain two types of charset($user_charset, $system_charset), and I think this situation will not occur. - } - } - } + + //Keep track of the largest row count found. + $maxFieldCount = 0; + for ( $i = 0; $i < 3; $i++ ) + { + $rows[] = $importFile->getNextRow(); + $maxFieldCount = $importFile->getFieldCount() > $maxFieldCount ? $importFile->getFieldCount() : $maxFieldCount; } - $ret_field_count = $importFile->getFieldCount(); + $ret_field_count = $maxFieldCount; // Bug 14689 - Parse the first data row to make sure it has non-empty data in it $isempty = true; @@ -259,14 +169,15 @@ class ImportViewStep3 extends SugarView // Now build template $this->ss->assign("TMP_FILE", $uploadFileName ); - $this->ss->assign("FILECOUNT", $splitter->getFileCount() ); - $this->ss->assign("RECORDCOUNT", $splitter->getRecordCount() ); - $this->ss->assign("RECORDTHRESHOLD", $sugar_config['import_max_records_per_file']); $this->ss->assign("SOURCE", $_REQUEST['source'] ); $this->ss->assign("TYPE", $_REQUEST['type'] ); $this->ss->assign("DELETE_INLINE_PNG", SugarThemeRegistry::current()->getImage('basic_search','align="absmiddle" alt="'.$app_strings['LNK_DELETE'].'" border="0"')); $this->ss->assign("PUBLISH_INLINE_PNG", SugarThemeRegistry::current()->getImage('advanced_search','align="absmiddle" alt="'.$mod_strings['LBL_PUBLISH'].'" border="0"')); - $this->ss->assign("MODULE_TITLE", $this->getModuleTitle()); + + $this->instruction = 'LBL_SELECT_MAPPING_INSTRUCTION'; + $this->ss->assign('INSTRUCTION', $this->getInstruction()); + + $this->ss->assign("MODULE_TITLE", $this->getModuleTitle(false)); $this->ss->assign("STEP4_TITLE", strip_tags(str_replace("\n","",getClassicModuleTitle( $mod_strings['LBL_MODULE_NAME'], @@ -283,6 +194,13 @@ class ImportViewStep3 extends SugarView $columns = array(); $mappedFields = array(); + // this should be populated if the request comes from a 'Back' button click + $importColumns = $this->getImportColumns(); + $column_sel_from_req = false; + if (!empty($importColumns)) { + $column_sel_from_req = true; + } + for($field_count = 0; $field_count < $ret_field_count; $field_count++) { // See if we have any field map matches $defaultValue = ""; @@ -305,12 +223,21 @@ class ImportViewStep3 extends SugarView $fields = $this->bean->get_importable_fields(); $options = array(); $defaultField = ''; + global $current_language; + $moduleStrings = return_module_language($current_language, $this->bean->module_dir); + foreach ( $fields as $fieldname => $properties ) { // get field name - if (!empty ($properties['vname'])) - $displayname = str_replace(":","",translate($properties['vname'] ,$this->bean->module_dir)); + if (!empty($moduleStrings['LBL_EXPORT_'.strtoupper($fieldname)]) ) + { + $displayname = str_replace(":","", $moduleStrings['LBL_EXPORT_'.strtoupper($fieldname)] ); + } + else if (!empty ($properties['vname'])) + { + $displayname = str_replace(":","",translate($properties['vname'] ,$this->bean->module_dir)); + } else - $displayname = str_replace(":","",translate($properties['name'] ,$this->bean->module_dir)); + $displayname = str_replace(":","",translate($properties['name'] ,$this->bean->module_dir)); // see if this is required $req_mark = ""; $req_class = ""; @@ -320,16 +247,26 @@ class ImportViewStep3 extends SugarView } // see if we have a match $selected = ''; - if ( !empty($defaultValue) && !in_array($fieldname,$mappedFields) - && !in_array($fieldname,$ignored_fields) ) { - if ( strtolower($fieldname) == strtolower($defaultValue) - || strtolower($fieldname) == str_replace(" ","_",strtolower($defaultValue)) - || strtolower($displayname) == strtolower($defaultValue) - || strtolower($displayname) == str_replace(" ","_",strtolower($defaultValue)) ) { + if ($column_sel_from_req && isset($importColumns[$field_count])) { + if ($fieldname == $importColumns[$field_count]) { $selected = ' selected="selected" '; $defaultField = $fieldname; $mappedFields[] = $fieldname; } + } else { + if ( !empty($defaultValue) && !in_array($fieldname,$mappedFields) + && !in_array($fieldname,$ignored_fields) ) + { + if ( strtolower($fieldname) == strtolower($defaultValue) + || strtolower($fieldname) == str_replace(" ","_",strtolower($defaultValue)) + || strtolower($displayname) == strtolower($defaultValue) + || strtolower($displayname) == str_replace(" ","_",strtolower($defaultValue)) ) + { + $selected = ' selected="selected" '; + $defaultField = $fieldname; + $mappedFields[] = $fieldname; + } + } } // get field type information $fieldtype = ''; @@ -359,12 +296,22 @@ class ImportViewStep3 extends SugarView // Bug 27046 - Sort the column name picker alphabetically ksort($options); + // to be displayed in UTF-8 format + if (!empty($charset) && $charset != 'UTF-8') { + if (isset($rows[1][$field_count])) { + $rows[1][$field_count] = $locale->translateCharset($rows[1][$field_count], $charset); + } + } + + $cellOneData = isset($rows[0][$field_count]) ? $rows[0][$field_count] : ''; + $cellTwoData = isset($rows[1][$field_count]) ? $rows[1][$field_count] : ''; + $cellThreeData = isset($rows[2][$field_count]) ? $rows[2][$field_count] : ''; $columns[] = array( 'field_choices' => implode('',$options), 'default_field' => $defaultFieldHTML, - 'cell1' => str_replace(""",'',htmlspecialchars($rows[0][$field_count])), - 'cell2' => str_replace(""",'',htmlspecialchars($rows[1][$field_count])), - 'cell3' => str_replace(""",'',htmlspecialchars($rows[2][$field_count])), + 'cell1' => str_replace(""",'', htmlspecialchars($cellOneData)), + 'cell2' => str_replace(""",'', htmlspecialchars($cellTwoData)), + 'cell3' => str_replace(""",'', htmlspecialchars($cellThreeData)), 'show_remove' => false, ); } @@ -436,101 +383,11 @@ class ImportViewStep3 extends SugarView $this->ss->assign("COLUMNCOUNT",$ret_field_count); $this->ss->assign("rows",$columns); - // get list of valid date/time formats - $timeFormat = $current_user->getUserDateTimePreferences(); - $timeOptions = get_select_options_with_id($sugar_config['time_formats'], $timeFormat['time']); - $dateOptions = get_select_options_with_id($sugar_config['date_formats'], $timeFormat['date']); - $this->ss->assign('TIMEOPTIONS', $timeOptions); - $this->ss->assign('DATEOPTIONS', $dateOptions); $this->ss->assign('datetimeformat', $GLOBALS['timedate']->get_cal_date_time_format()); - // get list of valid timezones - $userTZ = $current_user->getPreference('timezone'); - if(empty($userTZ)) - $userTZ = TimeDate::userTimezone(); - - $this->ss->assign('TIMEZONE_CURRENT', $userTZ); - $this->ss->assign('TIMEZONEOPTIONS', TimeDate::getTimezoneList()); - - // get currency preference - require_once('modules/Currencies/ListCurrency.php'); - $currency = new ListCurrency(); - $cur_id = $locale->getPrecedentPreference('currency', $current_user); - if($cur_id) { - $selectCurrency = $currency->getSelectOptions($cur_id); - $this->ss->assign("CURRENCY", $selectCurrency); - } else { - $selectCurrency = $currency->getSelectOptions(); - $this->ss->assign("CURRENCY", $selectCurrency); - } - - $currenciesVars = ""; - $i=0; - foreach($locale->currencies as $id => $arrVal) { - $currenciesVars .= "currencies[{$i}] = '{$arrVal['symbol']}';\n"; - $i++; - } - $currencySymbolsJs = <<ss->assign('currencySymbolJs', $currencySymbolsJs); - - - // fill significant digits dropdown - $significantDigits = $locale->getPrecedentPreference('default_currency_significant_digits', $current_user); - $sigDigits = ''; - for($i=0; $i<=6; $i++) { - if($significantDigits == $i) { - $sigDigits .= ''; - } else { - $sigDigits .= ''; - } - } - - $this->ss->assign('sigDigits', $sigDigits); - - $num_grp_sep = $current_user->getPreference('num_grp_sep'); - $dec_sep = $current_user->getPreference('dec_sep'); - $this->ss->assign("NUM_GRP_SEP", - ( empty($num_grp_sep) - ? $sugar_config['default_number_grouping_seperator'] : $num_grp_sep )); - $this->ss->assign("DEC_SEP", - ( empty($dec_sep) - ? $sugar_config['default_decimal_seperator'] : $dec_sep )); - $this->ss->assign('getNumberJs', $locale->getNumberJs()); - - // Name display format - $this->ss->assign('default_locale_name_format', $locale->getLocaleFormatMacro($current_user)); - $this->ss->assign('getNameJs', $locale->getNameJs()); - - // Charset - $charsetOptions = get_select_options_with_id( - $locale->getCharsetSelect(), $charset_for_import);//wdong, bug 25927, here we should use the charset testing results from above. - $this->ss->assign('CHARSETOPTIONS', $charsetOptions); - // handle building index selector global $dictionary, $current_language; - require_once("include/templates/TemplateGroupChooser.php"); - - $chooser_array = array(); - $chooser_array[0] = array(); - $idc = new ImportDuplicateCheck($this->bean); - $chooser_array[1] = $idc->getDuplicateCheckIndexes(); - - $chooser = new TemplateGroupChooser(); - $chooser->args['id'] = 'selected_indices'; - $chooser->args['values_array'] = $chooser_array; - $chooser->args['left_name'] = 'choose_index'; - $chooser->args['right_name'] = 'ignore_index'; - $chooser->args['left_label'] = $mod_strings['LBL_INDEX_USED']; - $chooser->args['right_label'] = $mod_strings['LBL_INDEX_NOT_USED']; - $this->ss->assign("TAB_CHOOSER", $chooser->display()); - // show notes if ( $this->bean instanceof Person ) $module_key = "LBL_CONTACTS_NOTE_"; @@ -557,38 +414,90 @@ eoq; // include anything needed for quicksearch to work require_once("include/TemplateHandler/TemplateHandler.php"); $quicksearch_js = TemplateHandler::createQuickSearchCode($fields,$fields,'importstep3'); - $this->ss->assign("JAVASCRIPT", $quicksearch_js . "\n" . $this->_getJS($required)); + + $this->ss->assign("QS_JS", $quicksearch_js); + $this->ss->assign("JAVASCRIPT", $this->_getJS($required)); $this->ss->assign('required_fields',implode(', ',$required)); - $this->ss->display('modules/Import/tpls/step3.tpl'); + $this->ss->assign('CSS', $this->_getCSS()); + + $content = $this->ss->fetch('modules/Import/tpls/step3.tpl'); + $this->ss->assign("CONTENT",$content); + $this->ss->display('modules/Import/tpls/wizardWrapper.tpl'); + } - /** - * Displays the Smarty template for an error - * - * @param string $message error message to show - * @param string $module what module we were importing into - * @param string $action what page we should go back to - */ - protected function _showImportError( - $message, - $module, - $action = 'Step1' - ) + protected function getRequestDelimiter() { - $ss = new Sugar_Smarty(); - - $ss->assign("MESSAGE",$message); - $ss->assign("ACTION",$action); - $ss->assign("IMPORT_MODULE",$module); - $ss->assign("MOD", $GLOBALS['mod_strings']); - $ss->assign("SOURCE",""); - if ( isset($_REQUEST['source']) ) - $ss->assign("SOURCE", $_REQUEST['source']); - - echo $ss->fetch('modules/Import/tpls/error.tpl'); + $delimiter = !empty($_REQUEST['custom_delimiter']) ? $_REQUEST['custom_delimiter'] : ","; + + switch ($delimiter) + { + case "other": + $delimiter = $_REQUEST['custom_delimiter_other']; + break; + case '\t': + $delimiter = "\t"; + break; + } + return $delimiter; + } + + protected function getImportColumns() + { + $importColumns = array(); + foreach ($_REQUEST as $name => $value) + { + // only look for var names that start with "fieldNum" + if (strncasecmp($name, "colnum_", 7) != 0) + continue; + + // pull out the column position for this field name + $pos = substr($name, 7); + + // now mark that we've seen this field + $importColumns[$pos] = $value; + } + + return $importColumns; + } + + protected function _getCSS() + { + return << + textarea { width: 20em } + .detail tr td[scope="row"] { + text-align:left + } + span.collapse{ + background: transparent url('index.php?entryPoint=getImage&themeName=Sugar&themeName=Sugar&imageName=sugar-yui-sprites.png') no-repeat 0 -90px; + padding-left: 10px; + cursor: pointer; + } + + span.expand{ + background: transparent url('index.php?entryPoint=getImage&themeName=Sugar&themeName=Sugar&imageName=sugar-yui-sprites.png') no-repeat -0 -110px; + padding-left: 10px; + cursor: pointer; + } + .removeButton{ + border: none !important; + background-image: none !important; + background-color: transparent; + padding: 0px; + } + + #importNotes ul{ + margin: 0px; + margin-top: 10px; + padding-left: 20px; + } + + +EOCSS; + } - /** * Returns JS used in this view * @@ -603,77 +512,85 @@ eoq; foreach ($required as $name=>$display) { $print_required_array .= "required['$name'] = '". $display . "';\n"; } - $sqsWaitImage = SugarThemeRegistry::current()->getImageURL('sqsWait.gif'); return << - - EOJAVASCRIPT; } diff --git a/modules/Import/views/view.step4.php b/modules/Import/views/view.step4.php index 0083d603..488f3d76 100644 --- a/modules/Import/views/view.step4.php +++ b/modules/Import/views/view.step4.php @@ -44,644 +44,37 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); ********************************************************************************/ require_once('include/MVC/View/SugarView.php'); -require_once('modules/Import/ImportFile.php'); -require_once('modules/Import/ImportFileSplitter.php'); -require_once('modules/Import/ImportCacheFiles.php'); -require_once('modules/Import/ImportFieldSanitize.php'); -require_once('modules/Import/ImportDuplicateCheck.php'); +require_once('modules/Import/Importer.php'); class ImportViewStep4 extends SugarView -{ +{ + private $currentStep; + + public function __construct($bean = null, $view_object_map = array()) + { + parent::__construct($bean, $view_object_map); + $this->currentStep = isset($_REQUEST['current_step']) ? ($_REQUEST['current_step'] + 1) : 1; + } + /** * @see SugarView::display() */ public function display() { - global $sugar_config; - - // Increase the max_execution_time since this step can take awhile - ini_set("max_execution_time", max($sugar_config['import_max_execution_time'],3600)); - - // stop the tracker - TrackerManager::getInstance()->pause(); - - // use our own error handler - set_error_handler(array('ImportViewStep4','handleImportErrors'),E_ALL); - - global $mod_strings, $app_strings, $current_user, $import_bean_map; - global $app_list_strings, $timedate; - - $update_only = ( isset($_REQUEST['import_type']) && $_REQUEST['import_type'] == 'update' ); - $firstrow = unserialize(base64_decode($_REQUEST['firstrow'])); - - // All the Look Up Caches are initialized here - $enum_lookup_cache=array(); - - // setup the importable fields array. - $importable_fields = $this->bean->get_importable_fields(); - - // loop through all request variables - $importColumns = array(); - foreach ($_REQUEST as $name => $value) { - // only look for var names that start with "fieldNum" - if (strncasecmp($name, "colnum_", 7) != 0) { - continue; - } - - // pull out the column position for this field name - $pos = substr($name, 7); - - if ( isset($importable_fields[$value]) ) { - // now mark that we've seen this field - $importColumns[$pos] = $value; - } - } - - - // set the default locale settings - $ifs = new ImportFieldSanitize(); - $ifs->dateformat = $_REQUEST['importlocale_dateformat']; - $ifs->timeformat = $_REQUEST['importlocale_timeformat']; - $ifs->timezone = $_REQUEST['importlocale_timezone']; - $currency = new Currency(); - $currency->retrieve($_REQUEST['importlocale_currency']); - $ifs->currency_symbol = $currency->symbol; - $ifs->default_currency_significant_digits - = $_REQUEST['importlocale_default_currency_significant_digits']; - $ifs->num_grp_sep - = $_REQUEST['importlocale_num_grp_sep']; - $ifs->dec_sep = $_REQUEST['importlocale_dec_sep']; - $ifs->default_locale_name_format - = $_REQUEST['importlocale_default_locale_name_format']; - + global $mod_strings, $sugar_config; + // Check to be sure we are getting an import file that is in the right place if ( realpath(dirname($_REQUEST['tmp_file']).'/') != realpath($sugar_config['upload_dir']) ) trigger_error($mod_strings['LBL_CANNOT_OPEN'],E_USER_ERROR); - + // Open the import file - $importFile = new ImportFile( - $_REQUEST['tmp_file'], - $_REQUEST['custom_delimiter'], - html_entity_decode($_REQUEST['custom_enclosure'],ENT_QUOTES) - ); - - if ( !$importFile->fileExists() ) { + $importSource = new ImportFile($_REQUEST['tmp_file'],$_REQUEST['custom_delimiter'],html_entity_decode($_REQUEST['custom_enclosure'],ENT_QUOTES)); + + //Ensure we have a valid file. + if ( !$importSource->fileExists() ) trigger_error($mod_strings['LBL_CANNOT_OPEN'],E_USER_ERROR); - } - - $fieldDefs = $this->bean->getFieldDefinitions(); - - while ( $row = $importFile->getNextRow() ) { - $focus = clone $this->bean; - $focus->unPopulateDefaultValues(); - $focus->save_from_post = false; - $focus->team_id = null; - $ifs->createdBeans = array(); - - $do_save = true; - - for ( $fieldNum = 0; $fieldNum < $_REQUEST['columncount']; $fieldNum++ ) { - // loop if this column isn't set - if ( !isset($importColumns[$fieldNum]) ) { - continue; - } - - // get this field's properties - $field = $importColumns[$fieldNum]; - $fieldDef = $focus->getFieldDefinition($field); - $fieldTranslated = translate((isset($fieldDef['vname'])?$fieldDef['vname']:$fieldDef['name']), - $_REQUEST['module'])." (".$fieldDef['name'].")"; - - // Bug 37241 - Don't re-import over a field we already set during the importing of another field - if ( !empty($focus->$field) ) { - continue; - } - - //DETERMINE WHETHER OR NOT $fieldDef['name'] IS DATE_MODIFIED AND SET A VAR, USE DOWN BELOW - - // translate strings - global $locale; - if(empty($locale)) { - $locale = new Localization(); - } - if ( isset($row[$fieldNum]) ) - $rowValue = $locale->translateCharset( - strip_tags(trim($row[$fieldNum])), - $_REQUEST['importlocale_charset'], - $sugar_config['default_charset'] - ); - else - $rowValue = ''; - - // If there is an default value then use it instead - if ( !empty($_REQUEST[$field]) ) { - if ( is_array($_REQUEST[$field]) ) - $defaultRowValue = encodeMultienumValue($_REQUEST[$field]); - else - $defaultRowValue = $_REQUEST[$field]; - // translate default values to the date/time format for the import file - if ( $fieldDef['type'] == 'date' - && $ifs->dateformat != $timedate->get_date_format() ) - $defaultRowValue = $timedate->swap_formats( - $defaultRowValue, $ifs->dateformat, $timedate->get_date_format()); - if ( $fieldDef['type'] == 'time' - && $ifs->timeformat != $timedate->get_time_format() ) - $defaultRowValue = $timedate->swap_formats( - $defaultRowValue, $ifs->timeformat, $timedate->get_time_format()); - if ( ($fieldDef['type'] == 'datetime' || $fieldDef['type'] == 'datetimecombo') - && $ifs->dateformat.' '.$ifs->timeformat != $timedate->get_date_time_format() ) - $defaultRowValue = $timedate->swap_formats( - $defaultRowValue, $ifs->dateformat.' '.$ifs->timeformat, - $timedate->get_date_time_format()); - if ( in_array($fieldDef['type'],array('currency','float','int','num')) - && $ifs->num_grp_sep != $current_user->getPreference('num_grp_sep') ) - $defaultRowValue = str_replace($current_user->getPreference('num_grp_sep'), - $ifs->num_grp_sep,$defaultRowValue); - if ( in_array($fieldDef['type'],array('currency','float')) - && $ifs->dec_sep != $current_user->getPreference('dec_sep') ) - $defaultRowValue = str_replace($current_user->getPreference('dec_sep'), - $ifs->dec_sep,$defaultRowValue); - $currency->retrieve('-99'); - $user_currency_symbol = $currency->symbol; - if ( $fieldDef['type'] == 'currency' - && $ifs->currency_symbol != $user_currency_symbol ) - $defaultRowValue = str_replace($user_currency_symbol, - $ifs->currency_symbol,$defaultRowValue); - - - if ( empty($rowValue) ) { - $rowValue = $defaultRowValue; - unset($defaultRowValue); - } - } - - // Bug 22705 - Don't update the First Name or Last Name value if Full Name is set - if ( in_array($field, array('first_name','last_name')) && !empty($focus->full_name) ) - continue; - - // loop if this value has not been set - if ( !isset($rowValue) ) - continue; - - // If the field is required and blank then error out - if ( array_key_exists($field,$focus->get_import_required_fields()) - && empty($rowValue) - && $rowValue!='0') { - $importFile->writeError( - $mod_strings['LBL_REQUIRED_VALUE'], - $fieldTranslated, - 'NULL' - ); - $do_save = false; - } - - // Handle the special case "Sync to Outlook" - if ( $focus->object_name == "Contacts" && $field == 'sync_contact' ) { - $bad_names = array(); - $returnValue = $ifs->synctooutlook( - $rowValue, - $fieldDef, - $bad_names); - // try the default value on fail - if ( !$returnValue && !empty($defaultRowValue) ) - $returnValue = $ifs->synctooutlook( - $defaultRowValue, - $fieldDef, - $bad_names); - if ( !$returnValue ) { - $importFile->writeError( - $mod_strings['LBL_ERROR_SYNC_USERS'], - $fieldTranslated, - explode(",",$bad_names)); - $do_save = 0; - } - } - - // Handle email1 and email2 fields ( these don't have the type of email ) - if ( $field == 'email1' || $field == 'email2' ) { - $returnValue = $ifs->email($rowValue, $fieldDef, $focus); - // try the default value on fail - if ( !$returnValue && !empty($defaultRowValue) ) - $returnValue = $ifs->email( - $defaultRowValue, - $fieldDef); - if ( $returnValue === FALSE ) { - $do_save=0; - $importFile->writeError( - $mod_strings['LBL_ERROR_INVALID_EMAIL'], - $fieldTranslated, - $rowValue); - } - else { - $rowValue = $returnValue; - // check for current opt_out and invalid email settings for this email address - // if we find any, set them now - $emailres = $focus->db->query( - "SELECT opt_out, invalid_email FROM email_addresses - WHERE email_address = '".$focus->db->quote($rowValue)."'"); - if ( $emailrow = $focus->db->fetchByAssoc($emailres) ) { - $focus->email_opt_out = $emailrow['opt_out']; - $focus->invalid_email = $emailrow['invalid_email']; - } - } - } - - // Handle splitting Full Name into First and Last Name parts - if ( $field == 'full_name' && !empty($rowValue) ) { - $ifs->fullname( - $rowValue, - $fieldDef, - $focus); - } - - // to maintain 451 compatiblity - if(!isset($fieldDef['module']) && $fieldDef['type']=='relate') - $fieldDef['module'] = ucfirst($fieldDef['table']); - - if(isset($fieldDef['custom_type']) && !empty($fieldDef['custom_type'])) - $fieldDef['type'] = $fieldDef['custom_type']; - - // If the field is empty then there is no need to check the data - if( !empty($rowValue) ) { - switch ($fieldDef['type']) { - case 'enum': - case 'multienum': - if ( isset($fieldDef['type']) && $fieldDef['type'] == "multienum" ) - $returnValue = $ifs->multienum($rowValue,$fieldDef); - else - $returnValue = $ifs->enum($rowValue,$fieldDef); - // try the default value on fail - if ( !$returnValue && !empty($defaultRowValue) ) - if ( isset($fieldDef['type']) && $fieldDef['type'] == "multienum" ) - $returnValue = $ifs->multienum($defaultRowValue,$fieldDef); - else - $returnValue = $ifs->enum($defaultRowValue,$fieldDef); - if ( $returnValue === FALSE ) { - $importFile->writeError( - $mod_strings['LBL_ERROR_NOT_IN_ENUM'] - . implode(",",$app_list_strings[$fieldDef['options']]), - $fieldTranslated, - $rowValue); - $do_save = 0; - } - else - $rowValue = $returnValue; - - break; - case 'relate': - case 'parent': - $returnValue = $ifs->relate( - $rowValue, - $fieldDef, - $focus, - empty($defaultRowValue)); - if ( !$returnValue && !empty($defaultRowValue) ) - $returnValue = $ifs->relate( - $defaultRowValue, - $fieldDef, - $focus); - // Bug 33623 - Set the id value found from the above method call as an importColumn - if ( $returnValue !== false ) - $importColumns[] = $fieldDef['id_name']; - break; - case 'teamset': - $returnValue = $ifs->teamset( - $rowValue, - $fieldDef, - $focus); - $importColumns[] = 'team_set_id'; - $importColumns[] = 'team_id'; - break; - case 'fullname': - break; - default: - $fieldtype = $fieldDef['type']; - $returnValue = $ifs->$fieldtype($rowValue, $fieldDef, $focus); - // try the default value on fail - if ( !$returnValue && !empty($defaultRowValue) ) - $returnValue = $ifs->$fieldtype( - $defaultRowValue, - $fieldDef, - $focus); - if ( !$returnValue ) { - $do_save=0; - $importFile->writeError( - $mod_strings['LBL_ERROR_INVALID_'.strtoupper($fieldDef['type'])], - $fieldTranslated, - $rowValue, - $focus); - } - else { - $rowValue = $returnValue; - } - } - } - $focus->$field = $rowValue; - unset($defaultRowValue); - } - - // Now try to validate flex relate fields - if ( isset($focus->field_defs['parent_name']) - && isset($focus->parent_name) - && ($focus->field_defs['parent_name']['type'] == 'parent') ) { - // populate values from the picker widget if the import file doesn't have them - $parent_idField = $focus->field_defs['parent_name']['id_name']; - if ( empty($focus->$parent_idField) && !empty($_REQUEST[$parent_idField]) ) - $focus->$parent_idField = $_REQUEST[$parent_idField]; - $parent_typeField = $focus->field_defs['parent_name']['type_name']; - if ( empty($focus->$parent_typeField) && !empty($_REQUEST[$parent_typeField]) ) - $focus->$parent_typeField = $_REQUEST[$parent_typeField]; - // now validate it - $returnValue = $ifs->parent( - $focus->parent_name, - $focus->field_defs['parent_name'], - $focus, - empty($_REQUEST['parent_name'])); - if ( !$returnValue && !empty($_REQUEST['parent_name']) ) - $returnValue = $ifs->parent( - $_REQUEST['parent_name'], - $focus->field_defs['parent_name'], - $focus); - } - - // check to see that the indexes being entered are unique. - if (isset($_REQUEST['display_tabs_def']) && $_REQUEST['display_tabs_def'] != ""){ - $idc = new ImportDuplicateCheck($focus); - if ( $idc->isADuplicateRecord(explode('&', $_REQUEST['display_tabs_def'])) ){ - $importFile->markRowAsDuplicate(); - $this->_undoCreatedBeans($ifs->createdBeans); - continue; - } - } - - // if the id was specified - $newRecord = true; - if ( !empty($focus->id) ) { - $focus->id = $this->_convertId($focus->id); - - // check if it already exists - $query = "SELECT * FROM {$focus->table_name} WHERE id='".$focus->db->quote($focus->id)."'"; - $result = $focus->db->query($query) - or sugar_die("Error selecting sugarbean: "); - - $dbrow = $focus->db->fetchByAssoc($result); - - if (isset ($dbrow['id']) && $dbrow['id'] != -1) { - // if it exists but was deleted, just remove it - if (isset ($dbrow['deleted']) && $dbrow['deleted'] == 1 && $update_only==false) { - $query2 = "DELETE FROM {$focus->table_name} WHERE id='".$focus->db->quote($focus->id)."'"; - $result2 = $focus->db->query($query2) or sugar_die($mod_strings['LBL_ERROR_DELETING_RECORD']." ".$focus->id); - if ($focus->hasCustomFields()) { - $query3 = "DELETE FROM {$focus->table_name}_cstm WHERE id_c='".$focus->db->quote($focus->id)."'"; - $result2 = $focus->db->query($query3); - } - $focus->new_with_id = true; - } - else { - if( !$update_only ) { - $do_save = 0; - $importFile->writeError($mod_strings['LBL_ID_EXISTS_ALREADY'],'ID',$focus->id); - $this->_undoCreatedBeans($ifs->createdBeans); - continue; - } - $existing_focus = clone $this->bean; - $newRecord = false; - if ( !( $existing_focus->retrieve($dbrow['id']) instanceOf SugarBean ) ) { - $do_save = 0; - $importFile->writeError($mod_strings['LBL_RECORD_CANNOT_BE_UPDATED'],'ID',$focus->id); - $this->_undoCreatedBeans($ifs->createdBeans); - continue; - } - else { - $newData = $focus->toArray(); - foreach ( $newData as $focus_key => $focus_value ) - if ( in_array($focus_key,$importColumns) ) - $existing_focus->$focus_key = $focus_value; - - $focus = $existing_focus; - $focus->update_date_entered = true; - } - unset($existing_focus); - } - } - else { - $focus->new_with_id = true; - } - } - - if ($do_save) { - // Populate in any default values to the bean - $focus->populateDefaultValues(); - - if ( !isset($focus->assigned_user_id) || $focus->assigned_user_id == '' && $newRecord ) { - $focus->assigned_user_id = $current_user->id; - } - /* - * Bug 34854: Added all conditions besides the empty check on date modified. Currently, if - * we do an update to a record, it doesn't update the date_modified value. - * Hack note: I'm doing a to_display and back to_db on the fetched row to make sure that any truncating that happens - * when $focus->date_modified goes to_display and back to_db also happens on the fetched db value. Otherwise, - * in some cases we truncate the seconds on one and not the other, and the comparison fails when it should pass - */ - if ( ( !empty($focus->new_with_id) && !empty($focus->date_modified) ) || - ( empty($focus->new_with_id) && $timedate->to_db($focus->date_modified) != $timedate->to_db($timedate->to_display_date_time($focus->fetched_row['date_modified'])) ) - ) - $focus->update_date_modified = false; - $focus->optimistic_lock = false; - if ( $focus->object_name == "Contacts" && isset($focus->sync_contact) ) { - //copy the potential sync list to another varible - $list_of_users=$focus->sync_contact; - //and set it to false for the save - $focus->sync_contact=false; - } else if($focus->object_name == "User" && (empty($current_user) || !$current_user->isAdminForModule( 'Users'))) { - sugar_die($GLOBALS['mod_strings']['ERR_IMPORT_SYSTEM_ADMININSTRATOR']); - } - //bug# 40260 setting it true as the module in focus is involved in an import - $focus->in_import=true; - // call any logic needed for the module preSave - $focus->beforeImportSave(); - - - $focus->save(false); - - // call any logic needed for the module postSave - $focus->afterImportSave(); - - if ( $focus->object_name == "Contacts" && isset($list_of_users) ) - $focus->process_sync_to_outlook($list_of_users); - - // Update the created/updated counter - $importFile->markRowAsImported($newRecord); - - // Add ID to User's Last Import records - if ( $newRecord ) - ImportFile::writeRowToLastImport( - $_REQUEST['import_module'], - ($focus->object_name == 'Case' ? 'aCase' : $focus->object_name), - $focus->id); - } - else - $this->_undoCreatedBeans($ifs->createdBeans); - - unset($defaultRowValue); - } - - // save mapping if requested - if ( isset($_REQUEST['save_map_as']) && $_REQUEST['save_map_as'] != '' ) { - $mapping_file = new ImportMap(); - if ( isset($_REQUEST['has_header']) && $_REQUEST['has_header'] == 'on') { - $header_to_field = array (); - foreach ($importColumns as $pos => $field_name) { - if (isset($firstrow[$pos]) && isset($field_name)) { - $header_to_field[$firstrow[$pos]] = $field_name; - } - } - $mapping_file->setMapping($header_to_field); - } - else { - $mapping_file->setMapping($importColumns); - } - - // save default fields - $defaultValues = array(); - for ( $i = 0; $i < $_REQUEST['columncount']; $i++ ) - - if (isset($importColumns[$i]) && !empty($_REQUEST[$importColumns[$i]])) { - $field = $importColumns[$i]; - $fieldDef = $focus->getFieldDefinition($field); - if(!empty($fieldDef['custom_type']) && $fieldDef['custom_type'] == 'teamset') { - require_once('include/SugarFields/Fields/Teamset/SugarFieldTeamset.php'); - $sugar_field = new SugarFieldTeamset('Teamset'); - $teams = $sugar_field->getTeamsFromRequest($field); - if(isset($_REQUEST['primary_team_name_collection'])) { - $primary_index = $_REQUEST['primary_team_name_collection']; - } - - //If primary_index was selected, ensure that the first Array entry is the primary team - if(isset($primary_index)) { - $count = 0; - $new_teams = array(); - foreach($teams as $id=>$name) { - if($primary_index == $count++) { - $new_teams[$id] = $name; - unset($teams[$id]); - break; - } - } - - foreach($teams as $id=>$name) { - $new_teams[$id] = $name; - } - $teams = $new_teams; - } //if - - $json = getJSONobj(); - $defaultValues[$field] = $json->encode($teams); - } else { - $defaultValues[$field] = $_REQUEST[$importColumns[$i]]; - } - } - - $mapping_file->setDefaultValues($defaultValues); - $result = $mapping_file->save( - $current_user->id, - $_REQUEST['save_map_as'], - $_REQUEST['import_module'], - $_REQUEST['source'], - ( isset($_REQUEST['has_header']) && $_REQUEST['has_header'] == 'on'), - $_REQUEST['custom_delimiter'], - html_entity_decode($_REQUEST['custom_enclosure'],ENT_QUOTES) - ); - } - - $importFile->writeStatus(); - } - - /** - * If a bean save is not done for some reason, this method will undo any of the beans that were created - * - * @param array $ids ids of user_last_import records created - */ - protected function _undoCreatedBeans( - array $ids - ) - { - $focus = new UsersLastImport(); - foreach ($ids as $id) - $focus->undoById($id); - } - - /** - * clean id's when being imported - * - * @param string $string - * @return string - */ - protected function _convertId( - $string - ) - { - return preg_replace_callback( - '|[^A-Za-z0-9\-\.]|', - create_function( - // single quotes are essential here, - // or alternative escape all $ as \$ - '$matches', - 'return ord($matches[0]);' - ) , - $string); - } - - /** - * Replaces PHP error handler in Step4 - * - * @param int $errno - * @param string $errstr - * @param string $errfile - * @param string $errline - */ - public static function handleImportErrors( - $errno, - $errstr, - $errfile, - $errline - ) - { - if ( !defined('E_DEPRECATED') ) - define('E_DEPRECATED','8192'); - if ( !defined('E_USER_DEPRECATED') ) - define('E_USER_DEPRECATED','16384'); - - // check to see if current reporting level should be included based upon error_reporting() setting, if not - // then just return - if ( !(error_reporting() & $errno) ) - return true; - - switch ($errno) { - case E_USER_ERROR: - echo "ERROR: [$errno] $errstr on line $errline in file $errfile
\n"; - exit(1); - break; - case E_USER_WARNING: - case E_WARNING: - echo "WARNING: [$errno] $errstr on line $errline in file $errfile
\n"; - break; - case E_USER_NOTICE: - case E_NOTICE: - echo "NOTICE: [$errno] $errstr on line $errline in file $errfile
\n"; - break; - case E_STRICT: - case E_DEPRECATED: - case E_USER_DEPRECATED: - // don't worry about these - //echo "STRICT ERROR: [$errno] $errstr on line $errline in file $errfile
\n"; - break; - default: - echo "Unknown error type: [$errno] $errstr on line $errline in file $errfile
\n"; - break; - } - - return true; + $importer = new Importer($importSource, $this->bean); + $importer->import(); } } diff --git a/modules/Import/views/view.undo.php b/modules/Import/views/view.undo.php index 39f68376..fca706c0 100644 --- a/modules/Import/views/view.undo.php +++ b/modules/Import/views/view.undo.php @@ -42,49 +42,13 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); * All Rights Reserved. ********************************************************************************/ -require_once('include/MVC/View/SugarView.php'); +require_once('modules/Import/views/ImportView.php'); -class ImportViewUndo extends SugarView +class ImportViewUndo extends ImportView { - /** - * @see SugarView::getMenu() - */ - public function getMenu( - $module = null - ) - { - global $mod_strings, $current_language; - - if ( empty($module) ) - $module = $_REQUEST['import_module']; - - $old_mod_strings = $mod_strings; - $mod_strings = return_module_language($current_language, $module); - $returnMenu = parent::getMenu($module); - $mod_strings = $old_mod_strings; - - return $returnMenu; - } + + protected $pageTitleKey = 'LBL_UNDO_LAST_IMPORT'; - /** - * @see SugarView::_getModuleTab() - */ - protected function _getModuleTab() - { - global $app_list_strings, $moduleTabMap; - - // Need to figure out what tab this module belongs to, most modules have their own tabs, but there are exceptions. - if ( !empty($_REQUEST['module_tab']) ) - return $_REQUEST['module_tab']; - elseif ( isset($moduleTabMap[$_REQUEST['import_module']]) ) - return $moduleTabMap[$_REQUEST['import_module']]; - // Default anonymous pages to be under Home - elseif ( !isset($app_list_strings['moduleList'][$_REQUEST['import_module']]) ) - return 'Home'; - else - return $_REQUEST['import_module']; - } - /** * @see SugarView::display() */ @@ -98,14 +62,16 @@ class ImportViewUndo extends SugarView $module_mod_strings = return_module_language($current_language, $_REQUEST['import_module']); $this->ss->assign("MODULENAME",$module_mod_strings['LBL_MODULE_NAME']); + $this->ss->assign("MODULE_TITLE", $this->getModuleTitle(false), ENT_NOQUOTES); // reset old ones afterwards $mod_strings = $old_mod_strings; $last_import = new UsersLastImport(); $this->ss->assign('UNDO_SUCCESS',$last_import->undo($_REQUEST['import_module'])); $this->ss->assign("JAVASCRIPT", $this->_getJS()); - - $this->ss->display('modules/Import/tpls/undo.tpl'); + $content = $this->ss->fetch('modules/Import/tpls/undo.tpl'); + $this->ss->assign("CONTENT",$content); + $this->ss->display('modules/Import/tpls/wizardWrapper.tpl'); } /** @@ -114,16 +80,11 @@ class ImportViewUndo extends SugarView private function _getJS() { return << - - - EOJAVASCRIPT; } } diff --git a/modules/InboundEmail/InboundEmail.js b/modules/InboundEmail/InboundEmail.js index fad64eb3..83a0d38c 100644 --- a/modules/InboundEmail/InboundEmail.js +++ b/modules/InboundEmail/InboundEmail.js @@ -43,7 +43,8 @@ if(word.indexOf('%')>0){fragment1=word.substr(0,word.indexOf('%'));fragment2=wor return words;} function ie_test_open_popup_with_submit(module_name,action,pageTarget,width,height,mail_server,protocol,port,login,password,mailbox,ssl,personal,formName,ie_id) {if(!formName)formName="testSettingsView";var words=getEncryptedPassword(login,password,mailbox);var isPersonal=(personal)?'true':'false';if(!isDataValid(formName,true)){return;} -ie_id=(typeof document.getElementById(formName).ie_id!='undefined')?document.getElementById(formName).ie_id:'';URL='index.php?' +if(typeof(ie_id)=='undefined'||ie_id=='') +ie_id=(typeof document.getElementById(formName).ie_id!='undefined')?document.getElementById(formName).ie_id.value:'';URL='index.php?' +'module='+module_name +'&to_pdf=1' +'&action='+action diff --git a/modules/InboundEmail/Save.php b/modules/InboundEmail/Save.php index 0c3d442e..f383a55b 100644 --- a/modules/InboundEmail/Save.php +++ b/modules/InboundEmail/Save.php @@ -68,6 +68,7 @@ foreach($focus->required_fields as $field) { $focus->$field = $value; } } + if(!empty($_REQUEST['email_password'])) { $focus->email_password = $_REQUEST['email_password']; } diff --git a/modules/Leads/Lead.php b/modules/Leads/Lead.php index b5dfaa35..01d780bd 100644 --- a/modules/Leads/Lead.php +++ b/modules/Leads/Lead.php @@ -563,7 +563,22 @@ class Lead extends Person { return $return_array; } - + + /** + * Returns array of lead conversion activity options + * + * @return string SQL statement + */ + public static function getActivitiesOptions() { + + if (isset($GLOBALS['app_list_strings']['lead_conv_activity_opt'])) { + return $GLOBALS['app_list_strings']['lead_conv_activity_opt']; + } + else { + return array(); + } + } + /** * Returns query to find the related meetings created pre-5.1 * diff --git a/modules/Leads/language/en_us.lang.php b/modules/Leads/language/en_us.lang.php index 3604f012..d8dc7265 100644 --- a/modules/Leads/language/en_us.lang.php +++ b/modules/Leads/language/en_us.lang.php @@ -78,7 +78,7 @@ $mod_strings = array ( 'LBL_BUSINESSCARD' => 'Convert Lead', 'LBL_CITY' => 'City:', 'LBL_CONTACT_ID' => 'Contact ID', - 'LBL_CONTACT_INFORMATION' => 'Lead Overview', + 'LBL_CONTACT_INFORMATION' => 'Overview', 'LBL_CONTACT_NAME' => 'Lead Name:', 'LBL_CONTACT_OPP_FORM_TITLE' => 'Lead-Opportunity:', 'LBL_CONTACT_ROLE' => 'Role:', @@ -248,6 +248,22 @@ $mod_strings = array ( 'LBL_SELECTION_TIP' => 'Modules with a relate field in Contacts can be selected rather than created during the convert lead process.', 'LBL_EDIT_TIP' => 'Modify the convert layout for this module.', 'LBL_DELETE_TIP' => 'Remove this module from the convert layout.', + 'LBL_ACTIVITIES_MOVE' => 'Move Activities to', + 'LBL_ACTIVITIES_COPY' => 'Copy Activities to', + 'LBL_ACTIVITIES_MOVE_HELP' => "Select the record to which to move the Lead's activities. Tasks, Calls, Meetings, Notes and Emails will be moved to the selected record(s).", + 'LBL_ACTIVITIES_COPY_HELP' => "Select the record(s) for which to create copies of the Lead's activities. New Tasks, Calls, Meetings and Notes will be created for each of the selected record(s). Emails will be related to the selected record(s).", + //For export labels + 'LBL_PHONE_HOME' => 'Phone Home', + 'LBL_PHONE_MOBILE' => 'Phone Mobile', + 'LBL_PHONE_WORK' => 'Phone Work', + 'LBL_PHONE_OTHER' => 'Phone Other', + 'LBL_PHONE_FAX' => 'Phone Fax', + 'LBL_CAMPAIGN_ID' => 'Campaign ID', + 'LBL_EXPORT_ASSIGNED_USER_NAME' => 'Assigned User Name', + 'LBL_EXPORT_ASSIGNED_USER_ID' => 'Assigned User ID', + 'LBL_EXPORT_MODIFIED_USER_ID' => 'Modified By ID', + 'LBL_EXPORT_CREATED_BY' => 'Created By ID', + 'LBL_EXPORT_EMAIL2'=>'Other Email Address', ); diff --git a/modules/Leads/metadata/subpaneldefs.php b/modules/Leads/metadata/subpaneldefs.php index 7bba77a6..488b0087 100644 --- a/modules/Leads/metadata/subpaneldefs.php +++ b/modules/Leads/metadata/subpaneldefs.php @@ -80,7 +80,7 @@ $layout_defs['Leads'] = array( 'subpanel_name' => 'ForActivities', 'get_subpanel_data' => 'calls', ), - 'oldcalls' => array( + 'oldcalls' => array( 'module' => 'Calls', 'subpanel_name' => 'ForActivities', 'get_subpanel_data' => 'function:get_old_related_calls', diff --git a/modules/Leads/tpls/ConvertLead.tpl b/modules/Leads/tpls/ConvertLead.tpl index 76af71ec..ef7400c0 100644 --- a/modules/Leads/tpls/ConvertLead.tpl +++ b/modules/Leads/tpls/ConvertLead.tpl @@ -55,7 +55,7 @@ {{/foreach}} {{/if}} {if !$def.required || !empty($def.select)} - + +{literal} + +{/literal} + +{if $lead_conv_activity_opt == 'move'} + + + + + +
+ {sugar_translate label='LBL_ACTIVITIES_MOVE' module='Leads'}: {sugar_help text=$MOD.LBL_ACTIVITIES_MOVE_HELP} + + +
+{elseif $lead_conv_activity_opt == 'copy' || $lead_conv_activity_opt == ''} + + + + + +
+ {sugar_translate label='LBL_ACTIVITIES_COPY' module='Leads'}: {sugar_help text=$MOD.LBL_ACTIVITIES_COPY_HELP} + + +
+{/if} +
diff --git a/modules/Leads/tpls/ConvertLeadHeader.tpl b/modules/Leads/tpls/ConvertLeadHeader.tpl index b07df00a..e6cf5615 100644 --- a/modules/Leads/tpls/ConvertLeadHeader.tpl +++ b/modules/Leads/tpls/ConvertLeadHeader.tpl @@ -35,6 +35,40 @@ ********************************************************************************/ *} +{literal} + +{/literal} +
diff --git a/modules/Leads/vardefs.php b/modules/Leads/vardefs.php index ef2905de..b6c0e615 100644 --- a/modules/Leads/vardefs.php +++ b/modules/Leads/vardefs.php @@ -128,16 +128,33 @@ $dictionary['Lead'] = array('table' => 'leads','audited'=>true, 'unified_search' 'reportable'=>false, 'massupdate' => false, ), - 'reports_to_link' => - array ( - 'name' => 'reports_to_link', - 'type' => 'link', - 'relationship' => 'lead_direct_reports', + 'reports_to_link' => array ( + 'name' => 'reports_to_link', + 'type' => 'link', + 'relationship' => 'lead_direct_reports', 'link_type'=>'one', 'side'=>'right', - 'source'=>'non-db', + 'source'=>'non-db', 'vname'=>'LBL_REPORTS_TO', ), + 'reportees' => array ( + 'name' => 'reportees', + 'type' => 'link', + 'relationship' => 'lead_direct_reports', + 'link_type'=>'many', + 'side'=>'left', + 'source'=>'non-db', + 'vname'=>'LBL_REPORTS_TO', + ), + 'contacts'=> + array ( + 'name' => 'contacts', + 'type' => 'link', + 'relationship' => 'contact_leads', + 'module' => "Contacts", + 'source' => 'non-db', + 'vname' => 'LBL_LEADS', + ), /*'acc_name_from_accounts' => array ( 'name' => 'acc_name_from_accounts', @@ -197,6 +214,14 @@ $dictionary['Lead'] = array('table' => 'leads','audited'=>true, 'unified_search' 'vname'=>'LBL_CONTACT_ID', 'comment' => 'If converted, Contact ID resulting from the conversion' ), + 'contact'=> array ( + 'name' => 'contact', + 'type' => 'link', + 'link_type' => 'one', + 'relationship' => 'contact_leads', + 'source' => 'non-db', + 'vname' => 'LBL_LEADS', + ), 'account_id' => array ( 'name' => 'account_id', @@ -213,6 +238,14 @@ $dictionary['Lead'] = array('table' => 'leads','audited'=>true, 'unified_search' 'vname'=>'LBL_OPPORTUNITY_ID', 'comment' => 'If converted, Opportunity ID resulting from the conversion' ), + 'opportunity' => array ( + 'name' => 'opportunity', + 'type' => 'link', + 'link_type' => 'one', + 'relationship' => 'opportunity_leads', + 'source'=>'non-db', + 'vname'=>'LBL_LEADS', + ), 'opportunity_name' => array ( 'name' => 'opportunity_name', @@ -435,7 +468,7 @@ $dictionary['Lead'] = array('table' => 'leads','audited'=>true, 'unified_search' array ( 'name' => 'calls', 'type' => 'link', - 'relationship' => 'lead_calls', + 'relationship' => 'calls_leads', 'source'=>'non-db', 'vname'=>'LBL_CALLS', ), @@ -514,6 +547,8 @@ $dictionary['Lead'] = array('table' => 'leads','audited'=>true, 'unified_search' array('name' =>'idx_lead_assigned', 'type'=>'index', 'fields'=>array('assigned_user_id')), array('name' =>'idx_lead_contact', 'type'=>'index', 'fields'=>array('contact_id')), array('name' =>'idx_reports_to', 'type'=>'index', 'fields'=>array('reports_to_id')), + array('name' =>'idx_lead_phone_work', 'type'=>'index', 'fields'=>array('phone_work')), + array('name' =>'idx_leads_id_del', 'type'=>'index', 'fields'=>array('id','deleted',)), ) , 'relationships' => array ( diff --git a/modules/Leads/views/view.convertlead.php b/modules/Leads/views/view.convertlead.php index 62948d83..2e63bf19 100644 --- a/modules/Leads/views/view.convertlead.php +++ b/modules/Leads/views/view.convertlead.php @@ -41,6 +41,7 @@ require_once("include/upload_file.php"); class ViewConvertLead extends SugarView { protected $fileName = "modules/Leads/metadata/convertdefs.php"; + protected $new_contact = false; public function __construct( $bean = null, @@ -120,10 +121,16 @@ class ViewConvertLead extends SugarView $smarty->assign("view", "convertlead"); $smarty->assign("bean", $this->focus); $smarty->assign("record_id", $this->focus->id); + global $mod_strings; + $smarty->assign('MOD', $mod_strings); $smarty->display("modules/Leads/tpls/ConvertLeadHeader.tpl"); echo "
"; + global $sugar_config, $app_list_strings; + $smarty->assign('lead_conv_activity_opt', $sugar_config['lead_conv_activity_opt']); + $smarty->assign('convertModuleListOptions', get_select_options_with_id(array('Contacts' => $app_list_strings["moduleListSingular"]['Contacts']), '')); + foreach($this->defs as $module => $vdef) { if(!isset($beanList[$module])) @@ -341,6 +348,7 @@ class ViewConvertLead extends SugarView echo $contactForm->buildTableForm($duplicateContacts, 'Contacts'); return; } + $this->new_contact = true; } if (!empty($_REQUEST['selectedAccount'])) { @@ -408,6 +416,7 @@ class ViewConvertLead extends SugarView //Handle non-contacts relationships foreach ($beans as $bean) { + if (!empty($lead)) { if (empty($bean->assigned_user_id)) @@ -493,7 +502,7 @@ class ViewConvertLead extends SugarView foreach($beans as $bean) { $beanName = $bean->object_name; - if ( $beanName == 'Contact' && !$bean->new_with_id ) { + if ( $beanName == 'Contact' && !$this->new_contact ) { echo "
  • " . translate("LBL_EXISTING_CONTACT") . " - {$bean->get_summary_text()} @@ -525,6 +534,7 @@ class ViewConvertLead extends SugarView ) { global $app_list_strings; + global $sugar_config; $parent_types = $app_list_strings['record_type_display']; $activities = $this->getActivitiesFromLead($lead); @@ -533,14 +543,81 @@ class ViewConvertLead extends SugarView { if (isset($parent_types[$module])) { + if (empty($bean->id)) + { + $bean->id = create_guid(); + $bean->new_with_id = true; + } foreach($activities as $activity) { - $this->copyActivityAndRelateToBean($activity, $bean); + if (!isset($sugar_config['lead_conv_activity_opt']) || $sugar_config['lead_conv_activity_opt'] == 'copy') { + if (isset($_POST['lead_conv_ac_op_sel'])) { + //if the copy to module(s) are defined, copy only to those module(s) + if (is_array($_POST['lead_conv_ac_op_sel'])) { + foreach ($_POST['lead_conv_ac_op_sel'] as $mod) { + if ($mod == $module) { + $this->copyActivityAndRelateToBean($activity, $bean); + break; + } + } + } + } + } + else if ($sugar_config['lead_conv_activity_opt'] == 'move') { + // if to move activities, should be only one module selected + if ($_POST['lead_conv_ac_op_sel'] == $module) { + $this->moveActivity($activity, $bean); + } + } } } } } + /** + * Change the parent id and parent type of an activity + * @param $activity Activity to be modified + * @param $bean New parent bean of the activity + */ + protected function moveActivity($activity, $bean) { + global $beanList; + + $lead = null; + if (!empty($_REQUEST['record'])) + { + $lead = new Lead(); + $lead->retrieve($_REQUEST['record']); + } + + // delete the old relationship to the old parent (lead) + if ($rel = $this->findRelationship($activity, $lead)) { + $activity->load_relationship ($rel) ; + + if ($activity->parent_id && $activity->id) { + $activity->$rel->delete($activity->id, $activity->parent_id); + } + } + + // add the new relationship to the new parent (contact, account, etc) + if ($rel = $this->findRelationship($activity, $bean)) { + $activity->load_relationship ($rel) ; + + $relObj = $activity->$rel->getRelationshipObject(); + if ( $relObj->relationship_type=='one-to-one' || $relObj->relationship_type == 'one-to-many' ) + { + $key = $relObj->rhs_key; + $activity->$key = $bean->id; + } + $activity->$rel->add($bean); + } + + // set the new parent id and type + $activity->parent_id = $bean->id; + $activity->parent_type = $bean->module_dir; + + $activity->save(); + } + /** * Gets the list of activities related to the lead * @param Lead $lead Lead to get activities from @@ -601,12 +678,12 @@ class ViewConvertLead extends SugarView $key = $relObj->rhs_key; $newActivity->$key = $bean->id; } - $newActivity->$rel->add($bean->id); $newActivity->parent_id = $bean->id; $newActivity->parent_type = $bean->module_dir; $newActivity->update_date_modified = false; //bug 41747 $newActivity->save(); - if ($newActivity->module_dir == "Notes" && $newActivity->filename) { + $newActivity->$rel->add($bean); + if ($newActivity->module_dir == "Notes" && $newActivity->filename) { UploadFile::duplicate_file($activity->id, $newActivity->id, $newActivity->filename); } } @@ -668,7 +745,7 @@ class ViewConvertLead extends SugarView $id_field = $relObject->rhs_key; $bean->$id_field = $contact->id; } else { - $contact->$contactRel->add($bean->id); + $contact->$contactRel->add($bean); } //Set the parent of activites to the new Contact if (isset($bean->field_defs['parent_id']) && isset($bean->field_defs['parent_type'])) diff --git a/modules/MailMerge/Step2.html b/modules/MailMerge/Step2.html index 8ce4046f..da1ff81a 100644 --- a/modules/MailMerge/Step2.html +++ b/modules/MailMerge/Step2.html @@ -356,17 +356,12 @@ function displayKeyCode(evt) function search(searchText) { var searchInput = document.getElementById("searchText"); - searchText = searchInput.value; - var where = ''; - if(searchText != '') - { - mTerm = searchText; - if(module == 'CampaignProspects'){ + mTerm = searchInput.value; + if(module == 'CampaignProspects'){ var prospectType = document.getElementById("campaign_prospect_type"); var lmodule = prospectType.value.toLowerCase(); relModule = lmodule; - } - } + } mOffset = 0; getObjects(); } @@ -374,13 +369,18 @@ function search(searchText) function getOrderBy() { var order = ''; - if(module == 'Contacts' || module == 'Leads') + var tmpModule = module.toLowerCase(); + if(module == 'CampaignProspects'){ + tmpModule = document.getElementById("campaign_prospect_type").value.toLowerCase(); + } + + if(tmpModule == 'contacts' || tmpModule == 'leads' || tmpModule == 'prospects') { - order = module+".last_name"; + order = tmpModule+".last_name"; } else { - order = module+".name"; + order = tmpModule+".name"; } orderBy = order.toLowerCase(); diff --git a/modules/MailMerge/controller.php b/modules/MailMerge/controller.php index 440b3d1a..6f738f34 100644 --- a/modules/MailMerge/controller.php +++ b/modules/MailMerge/controller.php @@ -68,30 +68,31 @@ class MailMergeController extends SugarController{ $where = $lmodule.".first_name like '%".$term."%' OR ".$lmodule.".last_name like '%".$term."%'"; $order_by = $lmodule.".last_name"; } - else if($module == 'CampaignProspects'){ + else + { + $where = $lmodule.".name like '".$term."%'"; + } + } + + if($module == 'CampaignProspects'){ $using_cp = true; + $module = 'Prospects'; $lmodule = strtolower($relModule); $campign_where = $_SESSION['MAILMERGE_WHERE']; $where = $lmodule.".first_name like '%".$term."%' OR ".$lmodule.".last_name like '%".$term."%'"; if($campign_where) $where .= " AND ".$campign_where ; $where .= " AND related_type = #".$lmodule."#"; - $module = 'Prospects'; - } - else - { - $where = $lmodule.".name like '".$term."%'"; - } } $seed = SugarModule::get($module)->loadBean(); - if($using_cp){ $fields = array('id', 'first_name', 'last_name'); - $dataList = $seed->retrieveTargetList($where, $fields, $offset,-1,$max,$deleted); + $dataList = $seed->retrieveTargetList($where, $fields, $offset,-1,$max,$deleted); + }else{ - $dataList = $seed->get_list($order_by, $where, $offset,-1,$max,$deleted); + $dataList = $seed->get_list($order_by, $where, $offset,-1,$max,$deleted); } $list = $dataList['list']; diff --git a/modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.php b/modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.php index 6cac248d..1760246a 100644 --- a/modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.php +++ b/modules/Meetings/Dashlets/MyMeetingsDashlet/MyMeetingsDashlet.php @@ -167,6 +167,7 @@ class MyMeetingsDashlet extends DashletGeneric { 'title' => $GLOBALS['mod_strings']['LBL_DASHLET_CONFIGURE_TITLE'], 'save' => $GLOBALS['app_strings']['LBL_SAVE_BUTTON_LABEL'], 'autoRefresh' => $GLOBALS['app_strings']['LBL_DASHLET_CONFIGURE_AUTOREFRESH'], + 'clear' => $GLOBALS['app_strings']['LBL_CLEAR_BUTTON_LABEL'], )); require_once('modules/Meetings/Meeting.php'); diff --git a/modules/Meetings/Meeting.php b/modules/Meetings/Meeting.php index 2913786f..9a7247e3 100644 --- a/modules/Meetings/Meeting.php +++ b/modules/Meetings/Meeting.php @@ -88,6 +88,7 @@ class Meeting extends SugarBean { var $case_id; var $assigned_user_name; var $outlook_id; + var $sequence; var $update_vcal = true; var $contacts_arr; @@ -140,6 +141,7 @@ class Meeting extends SugarBean { function save($check_notify = FALSE) { global $timedate; global $current_user; + global $disable_date_format; if(isset($this->date_start) && isset($this->duration_hours) && isset($this->duration_minutes)) @@ -152,7 +154,7 @@ class Meeting extends SugarBean { $this->date_end = $td->modify("+{$this->duration_hours} hours {$this->duration_minutes} mins")->asDb(); } } - } + } $check_notify =(!empty($_REQUEST['send_invites']) && $_REQUEST['send_invites'] == '1') ? true : false; if(empty($_REQUEST['send_invites'])) { @@ -197,7 +199,7 @@ class Meeting extends SugarBean { $this->type = 'Sugar'; } - if ( isset($api) && is_a($api,'WebMeeting') ) { + if ( isset($api) && is_a($api,'WebMeeting') && empty($this->in_relationship_update) ) { // Make sure the API initialized and it supports Web Meetings // Also make suer we have an ID, the external site needs something to reference if ( !isset($this->id) || empty($this->id) ) { @@ -257,20 +259,21 @@ class Meeting extends SugarBean { $contact_required = stristr($where, "contacts"); if($contact_required) { - $query = "SELECT meetings.*, contacts.first_name, contacts.last_name, contacts.assigned_user_id contact_name_owner "; + $query = "SELECT meetings.*, contacts.first_name, contacts.last_name, contacts.assigned_user_id contact_name_owner, users.user_name as assigned_user_name "; if($custom_join) { $query .= $custom_join['select']; } $query .= " FROM contacts, meetings, meetings_contacts "; $where_auto = " meetings_contacts.contact_id = contacts.id AND meetings_contacts.meeting_id = meetings.id AND meetings.deleted=0 AND contacts.deleted=0"; } else { - $query = 'SELECT meetings.*'; + $query = 'SELECT meetings.*, users.user_name as assigned_user_name '; if($custom_join) { $query .= $custom_join['select']; } $query .= ' FROM meetings '; $where_auto = "meetings.deleted=0"; } + $query .= " LEFT JOIN users ON meetings.assigned_user_id=users.id "; if($custom_join) { $query .= $custom_join['join']; @@ -424,7 +427,7 @@ class Meeting extends SugarBean { } global $timedate; $today = $timedate->nowDb(); - $nextday = $timedate->asDbDate($timedate->getNow()->get("+1 day")); + $nextday = $timedate->asDbDate($timedate->getNow()->get("+1 day")); $mergeTime = $meeting_fields['DATE_START']; //$timedate->merge_date_time($meeting_fields['DATE_START'], $meeting_fields['TIME_START']); $date_db = $timedate->to_db($mergeTime); if($date_db < $today ) { @@ -743,8 +746,11 @@ function getMeetingsExternalApiDropDown($focus = null, $name = null, $value = nu { $apiList[$value] = $value; } - //bug 46294: adding list of options to dropdown list - $apiList = array_merge(getMeetingTypeOptions($dictionary, $app_list_strings), $apiList); + //bug 46294: adding list of options to dropdown list (if it is not the default list) + if ($dictionary['Meeting']['fields']['type']['options'] != "eapm_list") + { + $apiList = array_merge(getMeetingTypeOptions($dictionary, $app_list_strings), $apiList); + } return $apiList; } diff --git a/modules/Meetings/MeetingFormBase.php b/modules/Meetings/MeetingFormBase.php index 18ed20f5..70f09968 100644 --- a/modules/Meetings/MeetingFormBase.php +++ b/modules/Meetings/MeetingFormBase.php @@ -236,7 +236,9 @@ function handleSave($prefix,$redirect=true, $useRequired=false) { } - if(isset($_POST['isSaveFromDetailView']) && $_POST['isSaveFromDetailView'] == 'true'){ + if( (isset($_POST['isSaveFromDetailView']) && $_POST['isSaveFromDetailView'] == 'true') || + (isset($_POST['is_ajax_call']) && !empty($_POST['is_ajax_call']) && !empty($focus->id) ) + ){ $focus->save(true); $return_id = $focus->id; }else{ diff --git a/modules/Meetings/Menu.php b/modules/Meetings/Menu.php index 938a2c3f..0c76c6ff 100644 --- a/modules/Meetings/Menu.php +++ b/modules/Meetings/Menu.php @@ -47,7 +47,7 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); global $mod_strings,$app_strings; if(ACLController::checkAccess('Meetings', 'edit', true))$module_menu[]=Array("index.php?module=Meetings&action=EditView&return_module=Meetings&return_action=DetailView", $mod_strings['LNK_NEW_MEETING'],"CreateMeetings"); if(ACLController::checkAccess('Meetings', 'list', true))$module_menu[]=Array("index.php?module=Meetings&action=index&return_module=Meetings&return_action=DetailView", $mod_strings['LNK_MEETING_LIST'],"Meetings"); -if(ACLController::checkAccess('Meetings', 'import', true))$module_menu[] =Array("index.php?module=Import&action=Step1&import_module=Meetings&return_module=Meetings&return_action=index", $mod_strings['LNK_IMPORT_MEETINGS'],"Import", 'Contacts'); +if(ACLController::checkAccess('Meetings', 'import', true))$module_menu[]=Array("index.php?module=Import&action=Step1&import_module=Meetings&return_module=Meetings&return_action=index", $mod_strings['LNK_IMPORT_MEETINGS'],"Import", 'Meetings'); diff --git a/modules/Meetings/jsclass_scheduler.js b/modules/Meetings/jsclass_scheduler.js index 21a860d2..469e04e9 100644 --- a/modules/Meetings/jsclass_scheduler.js +++ b/modules/Meetings/jsclass_scheduler.js @@ -90,11 +90,17 @@ GLOBAL_REGISTRY.scheduler_attendees_obj.display();} SugarClass.inherit("SugarWidgetScheduleRow","SugarClass");function SugarWidgetScheduleRow(timeslots){this.init(timeslots);} SugarWidgetScheduleRow.prototype.init=function(timeslots){this.timeslots=timeslots;} SugarWidgetScheduleRow.prototype.load=function(thetableid){this.thetableid=thetableid;var self=this;vcalClient=new SugarVCalClient();if(typeof(GLOBAL_REGISTRY['freebusy_adjusted'])=='undefined'||typeof(GLOBAL_REGISTRY['freebusy_adjusted'][this.focus_bean.fields.id])=='undefined'){global_request_registry[req_count]=[this,'display'];vcalClient.load(this.focus_bean.fields.id,req_count);req_count++;}else{this.display();}} -SugarWidgetScheduleRow.prototype.display=function(){var self=this;var tr;this.thetable=document.getElementById(this.thetableid);if(typeof(this.element)!='undefined'){if(this.element.parentNode!=null) +SugarWidgetScheduleRow.prototype.display=function(){SUGAR.util.doWhen("document.getElementById('"+this.thetableid+"') != null",function(){var tr;this.thetable=document.getElementById(this.thetableid);if(typeof(this.element)!='undefined'){if(this.element.parentNode!=null) this.thetable.deleteRow(this.element.rowIndex);tr=document.createElement('tr');this.thetable.appendChild(tr);}else{tr=this.thetable.insertRow(this.thetable.rows.length);} -tr.className="schedulerAttendeeRow";td=document.createElement('td');tr.appendChild(td);td.scope='row';var img=' ';td.innerHTML=img;td.innerHTML=td.innerHTML;if(self.focus_bean.fields.full_name) -td.innerHTML+=' '+self.focus_bean.fields.full_name;else -td.innerHTML+=' '+self.focus_bean.fields.name;this.add_freebusy_nodes(tr);var td=document.createElement('td');tr.appendChild(td);td.className='schedulerAttendeeDeleteCell';td.noWrap=true;td.innerHTML=' '+GLOBAL_REGISTRY['meeting_strings']['LBL_REMOVE']+' '+GLOBAL_REGISTRY['meeting_strings']['LBL_REMOVE']+'';this.element=tr;this.element_index=this.thetable.rows.length-1;} +tr.className="schedulerAttendeeRow";td=document.createElement('td');tr.appendChild(td);td.scope='row';var img=' ';td.innerHTML=img;td.innerHTML=td.innerHTML;if(this.focus_bean.fields.full_name) +td.innerHTML+=' '+this.focus_bean.fields.full_name;else +td.innerHTML+=' '+this.focus_bean.fields.name;this.add_freebusy_nodes(tr);var td=document.createElement('td');tr.appendChild(td);td.className='schedulerAttendeeDeleteCell';td.noWrap=true;td.innerHTML=' ' ++''+GLOBAL_REGISTRY['meeting_strings']['LBL_REMOVE']+' ' ++GLOBAL_REGISTRY['meeting_strings']['LBL_REMOVE']+'';this.element=tr;this.element_index=this.thetable.rows.length-1;},null,this);} SugarWidgetScheduleRow.deleteRow=function(bean_id){for(var i=0;i 'Name', 'LBL_NEW_FORM_TITLE' => 'Create Appointment', 'LBL_OUTLOOK_ID' => 'Outlook ID', + 'LBL_SEQUENCE' => 'Meeting update sequence', 'LBL_PHONE' => 'Phone Office:', 'LBL_REMINDER_TIME'=>'Reminder Time', 'LBL_REMINDER' => 'Reminder:', @@ -105,16 +106,19 @@ $mod_strings = array ( 'LBL_SEND_BUTTON_LABEL'=>'Send Invites', 'LBL_SEND_BUTTON_TITLE'=>'Send Invites [Alt+I]', 'LBL_STATUS' => 'Status:', - 'LBL_TYPE' => 'Meeting Type', - 'LBL_PASSWORD' => 'Meeting Password', - 'LBL_URL' => 'Start/Join Meeting', + 'LBL_TYPE' => 'Meeting Type', + 'LBL_PASSWORD' => 'Meeting Password', + 'LBL_URL' => 'Start/Join Meeting', + 'LBL_HOST_URL' => 'Host URL', + 'LBL_DISPLAYED_URL' => 'Display URL', 'LBL_CREATOR' => 'Meeting Creator', 'LBL_EXTERNALID' => 'External App ID', 'LBL_SUBJECT' => 'Subject:', 'LBL_TIME' => 'Start Time:', 'LBL_USERS_SUBPANEL_TITLE' => 'Users', 'LBL_ACTIVITIES_REPORTS' => 'Activities Report', - + 'LBL_PARENT_TYPE' => 'Parent Type', + 'LBL_PARENT_ID' => 'Parent ID', 'LNK_MEETING_LIST'=>'View Meetings', 'LNK_NEW_APPOINTMENT' => 'Create Appointment', 'LNK_NEW_MEETING'=>'Schedule Meeting', @@ -124,11 +128,12 @@ $mod_strings = array ( 'LBL_CREATED_USER' => 'Created User', 'LBL_MODIFIED_USER' => 'Modified User', 'NOTICE_DURATION_TIME' => 'Duration time must be greater than 0', - 'LBL_MEETING_INFORMATION' => 'Meeting Overview', + 'LBL_MEETING_INFORMATION' => 'Overview', 'LBL_LIST_JOIN_MEETING' => 'Join Meeting', 'LBL_JOIN_EXT_MEETING' => 'Join Meeting', 'LBL_HOST_EXT_MEETING' => 'Start Meeting', - + 'LBL_ACCEPT_STATUS' => 'Accept Status', + 'LBL_ACCEPT_LINK' => 'Accept Link', // You are not invited to the meeting messages 'LBL_EXTNOT_HEADER' => 'Error: Not Invited', 'LBL_EXTNOT_MAIN' => 'You are not able to join this meeting because you are not an Invitee.', @@ -139,5 +144,20 @@ $mod_strings = array ( 'LBL_EXTNOSTART_HEADER' => 'Error: Cannot Start Meeting', 'LBL_EXTNOSTART_MAIN' => 'You cannot start this meeting because you are not an Administrator or the owner of the meeting.', + //For export labels + 'LBL_EXPORT_JOIN_URL' => 'Join Url', + 'LBL_EXPORT_HOST_URL' => 'Host Url', + 'LBL_EXPORT_DISPLAYED_URL' => 'Displayed Url', + 'LBL_EXPORT_ASSIGNED_USER_ID' => 'Assigned User ID', + 'LBL_EXPORT_EXTERNAL_ID' => 'External ID', + 'LBL_EXPORT_ASSIGNED_USER_NAME' => 'Assigned User Name', + 'LBL_EXPORT_MODIFIED_USER_ID' => 'Modified By ID', + 'LBL_EXPORT_CREATED_BY' => 'Created By ID', + + 'LBL_EXPORT_DATE_START' => 'Start Date and Time', + 'LBL_EXPORT_DATE_END' => 'End Date and Time', + 'LBL_EXPORT_PARENT_TYPE' => 'Related Type', + 'LBL_EXPORT_PARENT_ID' => 'Parent ID', + 'LBL_EXPORT_REMINDER_TIME' =>'Reminder Time (in minutes)', ); ?> diff --git a/modules/Meetings/metadata/editviewdefs.php b/modules/Meetings/metadata/editviewdefs.php index 92c20ce9..a5587547 100644 --- a/modules/Meetings/metadata/editviewdefs.php +++ b/modules/Meetings/metadata/editviewdefs.php @@ -51,16 +51,16 @@ array ( array ( 0 => array ( - 'customCode' => '', + 'customCode' => '', ), 1 => 'CANCEL', 2 => array ( - 'customCode' => '', + 'customCode' => '', ), 3 => array ( - 'customCode' => '{if $fields.status.value != "Held"}{/if}', + 'customCode' => '{if $fields.status.value != "Held"}{/if}', ), ), 'headerTpl' => 'modules/Meetings/tpls/header.tpl', @@ -80,10 +80,8 @@ array ( ), ), 'javascript' => ' - - - - +', 'useTabs' => false, ), diff --git a/modules/Meetings/metadata/quickcreatedefs.php b/modules/Meetings/metadata/quickcreatedefs.php index d3f2a48c..f44bb87a 100644 --- a/modules/Meetings/metadata/quickcreatedefs.php +++ b/modules/Meetings/metadata/quickcreatedefs.php @@ -51,16 +51,16 @@ array ( array ( array ( - 'customCode' => '', + 'customCode' => '', ), 'CANCEL', array ( - 'customCode' => '', + 'customCode' => '', ), array ( - 'customCode' => '{if $fields.status.value != "Held"}{/if}', + 'customCode' => '{if $fields.status.value != "Held"}{/if}', ), ), 'headerTpl' => 'modules/Meetings/tpls/header.tpl', @@ -80,9 +80,7 @@ array ( ), ), 'javascript' => ' - - - + ', 'useTabs' => false, ), diff --git a/modules/Meetings/tpls/footer.tpl b/modules/Meetings/tpls/footer.tpl index 6c534999..e2af6fd5 100644 --- a/modules/Meetings/tpls/footer.tpl +++ b/modules/Meetings/tpls/footer.tpl @@ -54,24 +54,35 @@ diff --git a/modules/Meetings/vardefs.php b/modules/Meetings/vardefs.php index 78ff352f..d08f76c1 100644 --- a/modules/Meetings/vardefs.php +++ b/modules/Meetings/vardefs.php @@ -53,7 +53,7 @@ $dictionary['Meeting'] = array('table' => 'meetings', ), 'accept_status' => array ( 'name' => 'accept_status', - 'vname' => 'LBL_SUBJECT', + 'vname' => 'LBL_ACCEPT_STATUS', 'type' => 'varchar', 'dbType' => 'varchar', 'len' => '20', @@ -62,7 +62,7 @@ $dictionary['Meeting'] = array('table' => 'meetings', //bug 39559 'set_accept_links' => array ( 'name' => 'accept_status', - 'vname' => 'LBL_SUBJECT', + 'vname' => 'LBL_ACCEPT_LINK', 'type' => 'varchar', 'dbType' => 'varchar', 'len' => '20', @@ -98,7 +98,7 @@ $dictionary['Meeting'] = array('table' => 'meetings', 'host_url' => array ( 'name' => 'host_url', - 'vname' => 'LBL_URL', + 'vname' => 'LBL_HOST_URL', 'type' => 'varchar', 'len' => '400', 'comment' => 'Host URL', @@ -108,7 +108,7 @@ $dictionary['Meeting'] = array('table' => 'meetings', 'displayed_url' => array ( 'name' => 'displayed_url', - 'vname' => 'LBL_URL', + 'vname' => 'LBL_DISPLAYED_URL', 'type' => 'url', 'len' => '400', 'comment' => 'Meeting URL', @@ -178,7 +178,7 @@ $dictionary['Meeting'] = array('table' => 'meetings', 'parent_type' => array ( 'name' => 'parent_type', - 'vname'=>'LBL_LIST_RELATED_TO', + 'vname'=>'LBL_PARENT_TYPE', 'type' =>'parent_type', 'dbType' => 'varchar', 'group'=>'parent_name', @@ -227,7 +227,7 @@ $dictionary['Meeting'] = array('table' => 'meetings', 'parent_id' => array ( 'name' => 'parent_id', - 'vname'=>'LBL_LIST_RELATED_TO', + 'vname'=>'LBL_PARENT_ID', 'type' => 'id', 'group'=>'parent_name', 'reportable'=>false, @@ -262,6 +262,16 @@ $dictionary['Meeting'] = array('table' => 'meetings', 'reportable' => false, 'comment' => 'When the Sugar Plug-in for Microsoft Outlook syncs an Outlook appointment, this is the Outlook appointment item ID' ), + 'sequence' => + array ( + 'name' => 'sequence', + 'vname' => 'LBL_SEQUENCE', + 'type' => 'int', + 'len' => '11', + 'reportable' => false, + 'default'=>0, + 'comment' => 'Meeting update sequence for meetings as per iCalendar standards' + ), 'contact_name' => array ( @@ -385,6 +395,7 @@ $dictionary['Meeting'] = array('table' => 'meetings', array('name' =>'idx_mtg_name', 'type'=>'index', 'fields'=>array('name')), array('name' =>'idx_meet_par_del', 'type'=>'index', 'fields'=>array('parent_id','parent_type','deleted')), array('name' => 'idx_meet_stat_del', 'type' => 'index', 'fields'=> array('assigned_user_id', 'status', 'deleted')), + array('name' => 'idx_meet_date_start', 'type' => 'index', 'fields'=> array('date_start')), ) //This enables optimistic locking for Saves From EditView diff --git a/modules/ModuleBuilder/MB/MBLanguage.php b/modules/ModuleBuilder/MB/MBLanguage.php index 299c89d9..6cf96362 100644 --- a/modules/ModuleBuilder/MB/MBLanguage.php +++ b/modules/ModuleBuilder/MB/MBLanguage.php @@ -72,7 +72,7 @@ class MBLanguage{ } } - function loadAppListStrings($file){ + function loadAppListStrings($file){ if(!file_exists($file))return; //we may not need this when loading in the app strings, but there is no harm //in setting it. @@ -152,7 +152,7 @@ class MBLanguage{ mkdir_recursive($save_path); foreach($this->strings as $lang=>$values){ //Check if the module Label has changed. - $renameLang = $rename || empty($values) || $this->label != $values['LBL_MODULE_NAME']; + $renameLang = $rename || empty($values) || (isset($values['LBL_MODULE_NAME']) && $this->label != $values['LBL_MODULE_NAME']); $mod_strings = return_module_language(str_replace('.lang.php','',$lang), 'ModuleBuilder'); $required = array( 'LBL_LIST_FORM_TITLE'=>$this->label . " " . $mod_strings['LBL_LIST'], @@ -193,7 +193,7 @@ class MBLanguage{ unset($values['moduleList'][$this->key_name]); } - + $values = sugarArrayMerge($values, $app_list_strings); $values['moduleList'][$key_name]= $this->label; @@ -228,7 +228,7 @@ class MBLanguage{ **/ function getGlobalAppListStringsForMB(&$values){ //Ensure it comes from MB - if(!empty($_REQUEST['view_package']) && !empty($_REQUEST['type']) && $_REQUEST['type']='enum' && !empty($_REQUEST['options'])){ + if(!empty($_REQUEST['view_package']) && !empty($_REQUEST['type']) && $_REQUEST['type'] == 'enum' && !empty($_REQUEST['options'])){ if(!isset($values[$_REQUEST['options']])){ global $app_list_strings; if(!empty($app_list_strings[$_REQUEST['options']])){ diff --git a/modules/ModuleBuilder/MB/MBVardefs.php b/modules/ModuleBuilder/MB/MBVardefs.php index 04688ec4..64edf247 100644 --- a/modules/ModuleBuilder/MB/MBVardefs.php +++ b/modules/ModuleBuilder/MB/MBVardefs.php @@ -61,14 +61,17 @@ class MBVardefs{ if(file_exists($file)){ include($file); - if($by_group){ - $this->vardefs['fields'] [$template]= $vardefs['fields']; - }else{ - $this->vardefs['fields']= array_merge($this->vardefs['fields'], $vardefs['fields']); - if(!empty($vardefs['relationships'])){ - $this->vardefs['relationships']= array_merge($this->vardefs['relationships'], $vardefs['relationships']); - } - } + if (isset($vardefs)) + { + if($by_group){ + $this->vardefs['fields'] [$template]= $vardefs['fields']; + }else{ + $this->vardefs['fields']= array_merge($this->vardefs['fields'], $vardefs['fields']); + if(!empty($vardefs['relationships'])){ + $this->vardefs['relationships']= array_merge($this->vardefs['relationships'], $vardefs['relationships']); + } + } + } } //Bug40450 - Extra 'Name' field in a File type module in module builder if(array_key_exists('file', $this->templates)) diff --git a/modules/ModuleBuilder/Module/StudioModule.php b/modules/ModuleBuilder/Module/StudioModule.php index 3872dc56..65a9cfc7 100644 --- a/modules/ModuleBuilder/Module/StudioModule.php +++ b/modules/ModuleBuilder/Module/StudioModule.php @@ -35,6 +35,7 @@ ********************************************************************************/ +require_once 'data/BeanFactory.php'; require_once 'modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php' ; require_once 'modules/ModuleBuilder/parsers/constants.php' ; @@ -55,9 +56,7 @@ class StudioModule $moduleNames = array_change_key_case ( $GLOBALS [ 'app_list_strings' ] [ 'moduleList' ] ) ; $this->name = isset ( $moduleNames [ strtolower ( $module ) ] ) ? $moduleNames [ strtolower ( $module ) ] : strtolower ( $module ) ; $this->module = $module ; - $class = $GLOBALS [ 'beanList' ] [ $this->module ] ; - require_once $GLOBALS [ 'beanFiles' ] [ $class ] ; - $this->seed = new $class ( ) ; + $this->seed = BeanFactory::getBean($this->module); $this->fields = $this->seed->field_defs ; //$GLOBALS['log']->debug ( get_class($this)."->__construct($module): ".print_r($this->fields,true) ) ; } @@ -218,7 +217,7 @@ class StudioModule $nodes = $this->getSearch () ; if ( !empty ( $nodes ) ) { - $layouts [ translate('LBL_SEARCH') ] = array ( 'name' => translate('LBL_SEARCH') , 'type' => 'Folder' , 'children' => $nodes , 'action' => "module=ModuleBuilder&action=wizard&view=search&view_module={$this->module}" , 'imageTitle' => 'SearchForm' , 'help' => 'searchBtn' , 'size' => '48') ; + $layouts [ translate('LBL_SEARCH') ] = array ( 'name' => translate('LBL_SEARCH') , 'type' => 'Folder' , 'children' => $nodes , 'action' => "module=ModuleBuilder&action=wizard&view=search&view_module={$this->module}" , 'imageTitle' => 'BasicSearch' , 'help' => 'searchBtn' , 'size' => '48') ; } return $layouts ; diff --git a/modules/ModuleBuilder/controller.php b/modules/ModuleBuilder/controller.php index 52bf35b5..defbb31b 100644 --- a/modules/ModuleBuilder/controller.php +++ b/modules/ModuleBuilder/controller.php @@ -369,7 +369,7 @@ class ModuleBuilderController extends SugarController { $module = $_REQUEST [ 'view_module' ] ; - $bean = loadBean($module); + $bean = BeanFactory::getBean($module); if(!empty($bean)) { $field_defs = $bean->field_defs; @@ -391,9 +391,13 @@ class ModuleBuilderController extends SugarController include_once ('modules/Administration/QuickRepairAndRebuild.php') ; global $mod_strings; $mod_strings['LBL_ALL_MODULES'] = 'all_modules'; + require_once('ModuleInstall/ModuleInstaller.php'); + $mi = new ModuleInstaller(); + $mi->silent = true; + $mi->rebuild_extensions(); $repair = new RepairAndClear(); - $repair->repairAndClearAll(array('rebuildExtensions', 'clearVardefs', 'clearTpls'), array($class_name), true, false); - //#28707 ,clear all the js files in cache + $repair->repairAndClearAll(array('clearVardefs', 'clearTpls'), array($class_name), true, false); + //#28707 ,clear all the js files in cache $repair->module_list = array(); $repair->clearJsFiles(); } @@ -423,9 +427,8 @@ class ModuleBuilderController extends SugarController require_once ('modules/ModuleBuilder/parsers/StandardField.php') ; $module = $_REQUEST [ 'view_module' ] ; $df = new StandardField ( $module ) ; + $mod = BeanFactory::getBean($module); $class_name = $GLOBALS [ 'beanList' ] [ $module ] ; - require_once ($GLOBALS [ 'beanFiles' ] [ $class_name ]) ; - $mod = new $class_name ( ) ; $df->setup ( $mod ) ; $field->module = $mod; @@ -439,13 +442,17 @@ class ModuleBuilderController extends SugarController $GLOBALS [ 'mod_strings' ]['LBL_ALL_MODULES'] = 'all_modules'; $_REQUEST['execute_sql'] = true; + require_once('ModuleInstall/ModuleInstaller.php'); + $mi = new ModuleInstaller(); + $mi->silent = true; + $mi->rebuild_extensions(); + $repair = new RepairAndClear(); - $repair->repairAndClearAll(array('rebuildExtensions', 'clearVardefs', 'clearTpls'), array($class_name), true, false); + $repair->repairAndClearAll(array('clearVardefs', 'clearTpls'), array($class_name), true, false); //#28707 ,clear all the js files in cache $repair->module_list = array(); $repair->clearJsFiles(); - // now clear the cache so that the results are immediately visible include_once ('include/TemplateHandler/TemplateHandler.php') ; TemplateHandler::clearCache ( $module ) ; @@ -519,11 +526,9 @@ class ModuleBuilderController extends SugarController $GLOBALS['log']->debug("\n\nSTART BUILD"); if (empty($_REQUEST [ 'view_package' ])) { $relationships->build () ; - LanguageManager::clearLanguageCache($_REQUEST [ 'view_module' ]); } $GLOBALS['log']->debug("\n\nEND BUILD"); - $this->view = 'relationships' ; } @@ -547,6 +552,8 @@ class ModuleBuilderController extends SugarController $relationships->delete ( $_REQUEST [ 'relationship_name' ] ) ; $relationships->save () ; + require_once("data/Relationships/RelationshipFactory.php"); + SugarRelationshipFactory::deleteCache(); } $this->view = 'relationships' ; } @@ -761,11 +768,7 @@ class ModuleBuilderController extends SugarController $module_name = $_REQUEST [ 'view_module' ] ; global $beanList; if (isset($beanList[$module_name]) && $beanList[$module_name]!="") { - $objectName = $beanList[$module_name]; - if($objectName == 'aCase') // Bug 17614 - renamed aCase as Case in vardefs for backwards compatibililty with 451 modules - { - $objectName = 'Case'; - } + $objectName = BeanFactory::getObjectName($module_name); //Load the vardefs for the module to pass to TemplateRange VardefManager::loadVardef($module_name, $objectName, true); diff --git a/modules/ModuleBuilder/javascript/ModuleBuilder.js b/modules/ModuleBuilder/javascript/ModuleBuilder.js index e50f2f4d..fa094755 100644 --- a/modules/ModuleBuilder/javascript/ModuleBuilder.js +++ b/modules/ModuleBuilder/javascript/ModuleBuilder.js @@ -72,7 +72,13 @@ function addChildNodes(parentNode, parentData) { if (typeof(ModuleBuilder) == 'undefined') { ModuleBuilder = { init: function(){ - + //Check if we shoudln't be in studio and need to load the normal ajaxUI + var aRegex = /#.*ajaxUILoc=([^&]*)/.exec(window.location); + var ajaxLoc = aRegex ? aRegex[1] : false; + if (ajaxLoc) { + window.location = "index.php?action=ajaxui#ajaxUILoc=" + ajaxLoc; + return; + } //Setup the basic ajax request settings Connect.extraParams = { to_pdf: true @@ -159,10 +165,15 @@ if (typeof(ModuleBuilder) == 'undefined') { var w = (this.body.offsetWidth - 7) + "px"; this.body.style.width = w; this.header.style.width = w; + if (typeof Studio2 != "undefined") + Studio2.resizeDivs(); + if (typeof resizeDDLists == "function") + resizeDDLists(); }; mp.getUnitByPosition('right').on("resize", correctW); mp.getUnitByPosition('right').on("collapse", function(){ Ck.setSub("ModuleBuilder", "helpHidden", "true"); + mp.get("element").querySelector(".yui-layout-clip-right .collapse").id = "expand_help"; }); mp.getUnitByPosition('right').on("expand", function(){ Ck.setSub("ModuleBuilder", "helpHidden", "false"); @@ -170,6 +181,7 @@ if (typeof(ModuleBuilder) == 'undefined') { mp.getUnitByPosition('left').on("resize", correctW); mp.getUnitByPosition('left').on("collapse", function(){ Ck.setSub("ModuleBuilder", "treeHidden", "true"); + mp.get("element").querySelector(".yui-layout-clip-left .collapse").id = "expand_tree"; }); mp.getUnitByPosition('left').on("expand", function(){ Ck.setSub("ModuleBuilder", "treeHidden", "false"); @@ -208,7 +220,7 @@ if (typeof(ModuleBuilder) == 'undefined') { } YAHOO.util.History.register('mbContent', mbContent, ModuleBuilder.navigate); - YAHOO.util.History.initialize("yui-history-field", "yui-history-iframe"); + YAHOO.util.History.initialize("yui-history-field", "yui-history-iframe"); ModuleBuilder.getContent(mbContent); if (SUGAR.themes.tempHideLeftCol) SUGAR.themes.tempHideLeftCol(); @@ -223,6 +235,9 @@ if (typeof(ModuleBuilder) == 'undefined') { SUGAR.themes.tempHideLeftCol(); } } + //We need to add ID's to the collapse buttons for automated testing + Dom.getElementsByClassName("collapse", "div", mp.getUnitByPosition('left').header)[0].id = "collapse_tree"; + Dom.getElementsByClassName("collapse", "div", mp.getUnitByPosition('right').header)[0].id = "collapse_help"; }, //Empty layout manager diff --git a/modules/ModuleBuilder/javascript/SimpleList.js b/modules/ModuleBuilder/javascript/SimpleList.js index 5982163a..7429ec29 100644 --- a/modules/ModuleBuilder/javascript/SimpleList.js +++ b/modules/ModuleBuilder/javascript/SimpleList.js @@ -49,6 +49,11 @@ if(typeof(SimpleList) == 'undefined'){ SimpleList.editImage = editImage; SimpleList.deleteImage = deleteImage; new YAHOO.util.DDTarget("ul1"); + + Studio2.scrollZones = {} + for (var i = 0; Dom.get("ul" + i); i++){ + Studio2.scrollZones["ul" + i] = Studio2.getScrollZones("ul" + i); + } for (i=0;i box[0][0] && xy[0] < box[1][0] && xy[1] > box[0][1] && xy[1] < box[1][1]; + }, + + setScrollObj: function(o){ + Studio2.scrollObj = o; + Studio2.scrollCheck = setInterval(function(){ + var o = Studio2.scrollObj; + for(var i in Studio2.scrollZones) + { + var zone = Studio2.scrollZones[i]; + if (Studio2.isWithinBox([o.lastX, o.lastY], zone.up)) + { + document.getElementById(i).scrollTop -= 5; + YAHOO.util.DragDropMgr.refreshCache(); + return; + } + else if (Studio2.isWithinBox([o.lastX, o.lastY], zone.down)) + { + document.getElementById(i).scrollTop += 5; + YAHOO.util.DragDropMgr.refreshCache(); + return; + } + } + }, 25); + }, + + clearScrollObj: function() { + Studio2.scrollObj = false; + if (Studio2.scrollCheck) + clearInterval(Studio2.scrollCheck); + Studio2.scrollCheck = false; + }, + + onDrag: function(e) { + // Keep track of the direction of the drag for use during onDragOver + var y = e.pageY; + + if (y < this.lastY) { + this.goingUp = true; + } else if (y > this.lastY) { + this.goingUp = false; + } + + this.lastY = e.pageY || e.clientY; + this.lastX = e.pageX || e.clientX; + } }; diff --git a/modules/ModuleBuilder/javascript/studio2FieldDD.js b/modules/ModuleBuilder/javascript/studio2FieldDD.js index 82785907..1b33d990 100644 --- a/modules/ModuleBuilder/javascript/studio2FieldDD.js +++ b/modules/ModuleBuilder/javascript/studio2FieldDD.js @@ -58,9 +58,11 @@ YAHOO.extend(Studio2.FieldDD, YAHOO.util.DDProxy, { } else { YAHOO.util.Dom.setStyle(clickEl, "visibility", "hidden"); // want a empty space as we're dragging it away from this place } + Studio2.setScrollObj(this); }, endDrag: function(e) { + Studio2.clearScrollObj(); ModuleBuilder.state.isDirty=true; var srcEl = this.getEl(); var proxy = this.getDragEl(); @@ -85,12 +87,15 @@ YAHOO.extend(Studio2.FieldDD, YAHOO.util.DDProxy, { }, onInvalidDrop: function(e) { + Studio2.clearScrollObj(); var dragEl = this.getDragEl(); dragEl.innerHTML = ''; Studio2.removeCopy(); YAHOO.util.Dom.setStyle(this.getEl(), "display", "block"); }, + onDrag: Studio2.onDrag, + onDragDrop: function(e, id) { var srcEl = this.getEl(); var destEl = YAHOO.util.Dom.get(id); // where this element is being dropped diff --git a/modules/ModuleBuilder/javascript/studio2ListDD.js b/modules/ModuleBuilder/javascript/studio2ListDD.js index 291744f3..8cfe2ad4 100644 --- a/modules/ModuleBuilder/javascript/studio2ListDD.js +++ b/modules/ModuleBuilder/javascript/studio2ListDD.js @@ -88,6 +88,7 @@ YAHOO.extend(Studio2.ListDD, YAHOO.util.DDProxy, { Dom.setStyle(clickEl, "opacity", 0.5); Dom.setStyle(clickEl, "filter", "alpha(opacity=10)"); Dom.setStyle(clickEl, "border", '2px dashed #cccccc'); + Studio2.setScrollObj(this); }, updateTabs: function(){ @@ -110,6 +111,7 @@ YAHOO.extend(Studio2.ListDD, YAHOO.util.DDProxy, { }, endDrag: function(e){ + Studio2.clearScrollObj(); ModuleBuilder.state.isDirty=true; var clickEl = this.getEl(); var clickExEl = new YAHOO.util.Element(clickEl); @@ -147,7 +149,9 @@ YAHOO.extend(Studio2.ListDD, YAHOO.util.DDProxy, { dragEl.innerHTML = ""; }, - + + onDrag: Studio2.onDrag, + onDragOver: function(e, id){ var el; if (this.lastNode) { diff --git a/modules/ModuleBuilder/javascript/studio2PanelDD.js b/modules/ModuleBuilder/javascript/studio2PanelDD.js index bb4bc12c..618dc6f0 100644 --- a/modules/ModuleBuilder/javascript/studio2PanelDD.js +++ b/modules/ModuleBuilder/javascript/studio2PanelDD.js @@ -48,6 +48,7 @@ Studio2.PanelDD = function(id, sGroup) { YAHOO.extend(Studio2.PanelDD, YAHOO.util.DDProxy, { startDrag: function(x, y) { + var Dom = YAHOO.util.Dom; // make the proxy look like the source element var dragEl = this.getDragEl(); var clickEl = this.getEl(); @@ -63,15 +64,18 @@ YAHOO.extend(Studio2.PanelDD, YAHOO.util.DDProxy, { var copy = Studio2.newPanel(); Studio2.setCopy(copy); clickEl.parentNode.insertBefore(copy,clickEl.nextSibling); - YAHOO.util.Dom.setStyle(copy, 'display','block'); // must make it visible - the css sets rows outside of panel to invisible - YAHOO.util.Dom.setStyle(clickEl, "display","none"); - } + // must make it visible - the css sets rows outside of panel to invisible + Dom.setStyle(copy, 'display','block'); + Dom.setStyle(clickEl, "display","none"); + } - YAHOO.util.Dom.setStyle(clickEl, "visibility", "hidden"); + Dom.setStyle(clickEl, "visibility", "hidden"); + Studio2.setScrollObj(this); }, endDrag: function(e) { ModuleBuilder.state.isDirty=true; + Studio2.clearScrollObj(); // alert("endDrag"); var srcEl = this.getEl(); @@ -80,10 +84,17 @@ YAHOO.extend(Studio2.PanelDD, YAHOO.util.DDProxy, { var thisid = this.id; if (this.deletePanel) { - Studio2.removeElement(srcEl); + Studio2.removeElement(srcEl); // If we've just removed the last panel then we need to put an empty panel back in proxy.innerHTML = ''; Studio2.tidyPanels(); + //Check if this is the toolbox panel which must be re-activitated + if (Studio2.isSpecial(srcEl)) + { + Studio2.setSpecial(Studio2.copy()); + Studio2.activateCopy(); + YAHOO.util.Dom.setStyle(Studio2.copy(), "display", "block"); + } } else { // Show the proxy element and animate it to the src element's location @@ -144,6 +155,8 @@ YAHOO.extend(Studio2.PanelDD, YAHOO.util.DDProxy, { var srcEl = this.getEl(); var dragEl = this.getDragEl(); dragEl.innerHTML = ''; + Studio2.clearScrollObj(); + }, onDragDrop: function(e, id) { @@ -159,25 +172,14 @@ YAHOO.extend(Studio2.PanelDD, YAHOO.util.DDProxy, { } }, - onDrag: function(e) { - // Keep track of the direction of the drag for use during onDragOver - var y = e.pageY; - - if (y < this.lastY) { - this.goingUp = true; - } else if (y > this.lastY) { - this.goingUp = false; - } - - this.lastY = y; - }, + onDrag: Studio2.onDrag, onDragOver: function(e, id) { var srcEl = this.getEl(); var destEl = YAHOO.util.Dom.get(id); var dragEl = this.getDragEl(); - - if ((Studio2.establishLocation(destEl) == 'panels') && (destEl.className.indexOf('le_panel') != -1)) { + var loc = Studio2.establishLocation(destEl); + if ((loc == 'panels') && (destEl.className.indexOf('le_panel') != -1)) { YAHOO.util.Dom.setStyle(srcEl, 'visibility','hidden'); YAHOO.util.Dom.setStyle(srcEl, 'display','block'); var orig_p = srcEl.parentNode; diff --git a/modules/ModuleBuilder/javascript/studio2RowDD.js b/modules/ModuleBuilder/javascript/studio2RowDD.js index fb1e681a..05aa86ea 100644 --- a/modules/ModuleBuilder/javascript/studio2RowDD.js +++ b/modules/ModuleBuilder/javascript/studio2RowDD.js @@ -66,9 +66,11 @@ YAHOO.extend(Studio2.RowDD, YAHOO.util.DDProxy, { } YAHOO.util.Dom.setStyle(clickEl,'visibility','hidden'); + Studio2.setScrollObj(this); }, endDrag: function(e) { + Studio2.clearScrollObj(); ModuleBuilder.state.isDirty=true; // alert("endDrag"); @@ -80,6 +82,12 @@ YAHOO.extend(Studio2.RowDD, YAHOO.util.DDProxy, { if (this.deleteRow) { Studio2.removeElement(srcEl); proxy.innerHTML = ''; + //Check if this is the new row el, which must be re-activitated + if (Studio2.isSpecial(srcEl)) { + Studio2.setSpecial(Studio2.copy()); + Studio2.activateCopy(); + YAHOO.util.Dom.setStyle(Studio2.copy(), "display","block"); + } } else { // Show the proxy element and animate it to the src element's location YAHOO.util.Dom.setStyle(proxy, 'visibility',''); @@ -133,6 +141,7 @@ YAHOO.extend(Studio2.RowDD, YAHOO.util.DDProxy, { }, onInvalidDrop: function(e) { + Studio2.clearScrollObj(); this.getDragEl().innerHTML = ''; }, @@ -148,26 +157,15 @@ YAHOO.extend(Studio2.RowDD, YAHOO.util.DDProxy, { } }, - onDrag: function(e) { - // Keep track of the direction of the drag for use during onDragOver - var y = e.pageY; - - if (y < this.lastY) { - this.goingUp = true; - } else if (y > this.lastY) { - this.goingUp = false; - } - - this.lastY = y; - }, + onDrag: Studio2.onDrag, onDragOver: function(e, id) { var srcEl = this.getEl(); var destEl = document.getElementById(id); var srcLoc = Studio2.establishLocation(srcEl); var dstLoc = Studio2.establishLocation(destEl); - if ((Studio2.establishLocation(destEl) == 'panels') && (destEl.className.indexOf('le_row') != -1)) { - + + if ((Studio2.establishLocation(destEl) == 'panels') && (destEl.className.indexOf('le_row') != -1)) { YAHOO.util.Dom.setStyle(srcEl, "visibility","hidden"); YAHOO.util.Dom.setStyle(srcEl, "display" ,"block"); var orig_p = srcEl.parentNode; diff --git a/modules/ModuleBuilder/language/en_us.lang.php b/modules/ModuleBuilder/language/en_us.lang.php index e6d9348a..5a1aba54 100644 --- a/modules/ModuleBuilder/language/en_us.lang.php +++ b/modules/ModuleBuilder/language/en_us.lang.php @@ -538,6 +538,7 @@ $mod_strings = array( 'LBL_BTN_VIEW_FIELDS'=>'View Fields', 'LBL_BTN_VIEW_RELATIONSHIPS'=>'View Relationships', 'LBL_BTN_ADD_RELATIONSHIP'=>'Add Relationship', +'LBL_BTN_RENAME_MODULE' => 'Change Module Name', //TABS @@ -702,6 +703,7 @@ $mod_strings = array( "phone number, with allowance for the country code 1, and
    " . "to apply a U.S. format to the phone number when the record
    " . "is saved. The following format will be applied: (xxx) xxx-xxxx.", +'LBL_ALL_MODULES'=>'All Modules', ); diff --git a/modules/ModuleBuilder/parsers/parser.label.php b/modules/ModuleBuilder/parsers/parser.label.php index 49611c12..61fc6b3e 100644 --- a/modules/ModuleBuilder/parsers/parser.label.php +++ b/modules/ModuleBuilder/parsers/parser.label.php @@ -223,6 +223,7 @@ class ParserLabel extends ModuleBuilderParser // if we have a cache to worry about, then clear it now if ($deployedModule) { + SugarCache::cleanOpcodes(); $GLOBALS [ 'log' ]->debug ( "PaserLabel->addLabels: clearing language cache" ) ; $cache_key = "module_language." . $language . $moduleName ; sugar_cache_clear ( $cache_key ) ; diff --git a/modules/ModuleBuilder/parsers/relationships/AbstractRelationship.php b/modules/ModuleBuilder/parsers/relationships/AbstractRelationship.php index a7eed4e0..bfe61028 100644 --- a/modules/ModuleBuilder/parsers/relationships/AbstractRelationship.php +++ b/modules/ModuleBuilder/parsers/relationships/AbstractRelationship.php @@ -287,7 +287,8 @@ class AbstractRelationship ); return array ( $subpanelDefinition ); - } + } + /* @@ -296,7 +297,7 @@ class AbstractRelationship * @param string $sourceModule Name of the source module for this field * @param string $relationshipName Name of the relationship */ - protected function getLinkFieldDefinition ($sourceModule , $relationshipName, $right_side = false, $vname = "") + protected function getLinkFieldDefinition ($sourceModule , $relationshipName, $right_side = false, $vname = "", $id_name = false) { $vardef = array ( ) ; @@ -308,6 +309,8 @@ class AbstractRelationship $vardef [ 'side' ] = 'right' ; if (!empty($vname)) $vardef [ 'vname' ] = $vname; + if (!empty($id_name)) + $vardef['id_name'] = $id_name; return $vardef ; } @@ -436,9 +439,11 @@ class AbstractRelationship * 3. fields: fields within the join table * 4. indicies: indicies on the join table * @param string $relationshipType Cardinality of the relationship, for example, MB_ONETOONE or MB_ONETOMANY or MB_MANYTOMANY + * @param bool $checkExisting check if a realtionship with the given name is already depolyed in this instance. If so, we will clones its table and column names to preserve existing data. */ - function getRelationshipMetaData ($relationshipType) + function getRelationshipMetaData ($relationshipType, $checkExisting = true) { + global $dictionary; $relationshipName = $this->definition [ 'relationship_name' ] ; $lhs_module = $this->lhs_module ; $rhs_module = $this->rhs_module ; @@ -447,30 +452,39 @@ class AbstractRelationship $rhs_table = $this->getTablename ( $rhs_module ) ; $properties = array ( ) ; - - // first define section 1, the relationship element of the metadata entry - - $rel_properties = array ( ) ; - $rel_properties [ 'lhs_module' ] = $lhs_module ; - $rel_properties [ 'lhs_table' ] = $lhs_table ; - $rel_properties [ 'lhs_key' ] = 'id' ; - $rel_properties [ 'rhs_module' ] = $rhs_module ; - $rel_properties [ 'rhs_table' ] = $rhs_table ; - $rel_properties [ 'rhs_key' ] = 'id' ; - - // because the implementation of one-to-many relationships within SugarBean does not use a join table and so requires schema changes to add a foreign key for each new relationship, - // we currently implement all new relationships as many-to-many regardless of the real type and enforce cardinality through the relate fields and subpanels - $rel_properties [ 'relationship_type' ] = MB_MANYTOMANY ; - // but as we need to display the true cardinality in Studio and ModuleBuilder we also record the actual relationship type - // this property is only used by Studio/MB - $properties [ 'true_relationship_type' ] = $relationshipType ; - if ($this->from_studio) - $properties [ 'from_studio' ] = true; - - $rel_properties [ 'join_table' ] = $this->getValidDBName ( $relationshipName."_c" ) ; - // a and b are in case the module relates to itself - $rel_properties [ 'join_key_lhs' ] = $this->getJoinKeyLHS() ; - $rel_properties [ 'join_key_rhs' ] = $this->getJoinKeyRHS() ; + + if ($checkExisting && !empty($dictionary[$relationshipName]) + && !empty($dictionary[$relationshipName][ 'true_relationship_type' ]) + && $dictionary[$relationshipName][ 'true_relationship_type' ] == $relationshipType + && !empty($dictionary[$relationshipName]['relationships'][$relationshipName])) + { + $rel_properties = $dictionary[$relationshipName]['relationships'][$relationshipName]; + } else + { + // first define section 1, the relationship element of the metadata entry + + $rel_properties = array ( ) ; + $rel_properties [ 'lhs_module' ] = $lhs_module ; + $rel_properties [ 'lhs_table' ] = $lhs_table ; + $rel_properties [ 'lhs_key' ] = 'id' ; + $rel_properties [ 'rhs_module' ] = $rhs_module ; + $rel_properties [ 'rhs_table' ] = $rhs_table ; + $rel_properties [ 'rhs_key' ] = 'id' ; + + // because the implementation of one-to-many relationships within SugarBean does not use a join table and so requires schema changes to add a foreign key for each new relationship, + // we currently implement all new relationships as many-to-many regardless of the real type and enforce cardinality through the relate fields and subpanels + $rel_properties [ 'relationship_type' ] = MB_MANYTOMANY ; + // but as we need to display the true cardinality in Studio and ModuleBuilder we also record the actual relationship type + // this property is only used by Studio/MB + $properties [ 'true_relationship_type' ] = $relationshipType ; + if ($this->from_studio) + $properties [ 'from_studio' ] = true; + + $rel_properties [ 'join_table' ] = $this->getValidDBName ( $relationshipName."_c" ) ; + // a and b are in case the module relates to itself + $rel_properties [ 'join_key_lhs' ] = $this->getJoinKeyLHS() ; + $rel_properties [ 'join_key_rhs' ] = $this->getJoinKeyRHS() ; + } // set the extended properties if they exist = for now, many-to-many definitions do not have to contain a role_column even if role_column_value is set; we'll just create a likely name if missing if (isset ( $this->definition [ 'relationship_role_column_value' ] )) diff --git a/modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php b/modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php index fb4f1e49..ed063d58 100644 --- a/modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php +++ b/modules/ModuleBuilder/parsers/relationships/AbstractRelationships.php @@ -47,7 +47,13 @@ if (! defined ( 'sugarEntry' ) || ! sugarEntry) class AbstractRelationships { - static $methods = array ( 'Labels' => 'language' , 'RelationshipMetaData' => 'relationships' , 'SubpanelDefinitions' => 'layoutdefs' , 'Vardefs' => 'vardefs' , 'FieldsToLayouts' => 'layoutfields' ) ; + static $methods = array ( + 'Labels' => 'language' , + 'RelationshipMetaData' => 'relationships' , + 'SubpanelDefinitions' => 'layoutdefs' , + 'Vardefs' => 'vardefs' , + 'FieldsToLayouts' => 'layoutfields', + ) ; static $activities = array ( 'calls' => 'Calls' , 'meetings' => 'Meetings' , 'notes' => 'Notes' , 'tasks' => 'Tasks' , 'emails' => 'Emails' ) ; protected $relationships = array ( ) ; // array containing all the AbstractRelationship objects that are in this set of relationships @@ -435,22 +441,27 @@ class AbstractRelationships foreach ( $subpanelDefinitions as $moduleName => $definitions ) { $filename = "$basepath/layoutdefs/{$relationshipName}_{$moduleName}.php" ; - $out = "debug ( get_class ( $this ) . "->saveSubpanelDefinitions(): saving the following to {$filename}" . print_r ( $definition, true ) ) ; - if (empty($definition ['get_subpanel_data']) || $definition ['subpanel_name'] == 'history' || $definition ['subpanel_name'] == 'activities') { - $definition ['get_subpanel_data'] = $definition ['subpanel_name']; - } - $out .= '$layout_defs["' . $moduleName . '"]["subpanel_setup"]["' . $definition ['get_subpanel_data'] . '"] = ' - . var_export_helper($definition) . ";\n"; + if (empty($definition ['get_subpanel_data']) || $definition ['subpanel_name'] == 'history' || $definition ['subpanel_name'] == 'activities') { + $definition ['get_subpanel_data'] = $definition ['subpanel_name']; + } + $out .= override_value_to_string($subpanelVarname, strtolower ( $definition [ 'get_subpanel_data' ] ), $definition) . "\n"; } - file_put_contents($filename, $out); + if (!empty($out)) { + $out = " "{$installDefPrefix}/relationships/layoutdefs/{$relationshipName}_{$moduleName}.php" , 'to_module' => $moduleName ) ; } return $installDefs ; } + /* * Translate a set of linkFieldDefinitions into files for the Module Loader * Note that the Module Loader will only accept one entry in the vardef section of the Manifest for each module diff --git a/modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php b/modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php index 7595630c..2571c70e 100644 --- a/modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php +++ b/modules/ModuleBuilder/parsers/relationships/DeployedRelationships.php @@ -337,12 +337,14 @@ class DeployedRelationships extends AbstractRelationships implements Relationshi VardefManager::clearVardef () ; - + $mi->install_relationships () ; $mi->install_languages () ; $mi->install_vardefs () ; $mi->install_layoutdefs () ; - + $mi->install_extensions(); + + $mi->rebuild_relationships(); } // now clear all caches so that our changes are visible @@ -356,10 +358,7 @@ class DeployedRelationships extends AbstractRelationships implements Relationshi $this->save () ; $GLOBALS [ 'log' ]->info ( get_class ( $this ) . "->build(): finished relationship installation" ) ; - - - } /* diff --git a/modules/ModuleBuilder/parsers/relationships/ManyToManyRelationship.php b/modules/ModuleBuilder/parsers/relationships/ManyToManyRelationship.php index c3a195ef..8e6b9662 100644 --- a/modules/ModuleBuilder/parsers/relationships/ManyToManyRelationship.php +++ b/modules/ModuleBuilder/parsers/relationships/ManyToManyRelationship.php @@ -79,6 +79,7 @@ class ManyToManyRelationship extends AbstractRelationship return $subpanelDefinitions ; } + /* * @return array An array of field definitions, ready for the vardefs, keyed by module */ diff --git a/modules/ModuleBuilder/parsers/relationships/ManyToOneRelationship.php b/modules/ModuleBuilder/parsers/relationships/ManyToOneRelationship.php index 6e1ddf3b..bb466a92 100644 --- a/modules/ModuleBuilder/parsers/relationships/ManyToOneRelationship.php +++ b/modules/ModuleBuilder/parsers/relationships/ManyToOneRelationship.php @@ -95,6 +95,7 @@ class ManyToOneRelationship extends AbstractRelationship return $this->one_to_many->buildSubpanelDefinitions(); } + /* * @return array An array of field definitions, ready for the vardefs, keyed by module */ diff --git a/modules/ModuleBuilder/parsers/relationships/OneToManyRelationship.php b/modules/ModuleBuilder/parsers/relationships/OneToManyRelationship.php index c155ded7..202f6214 100644 --- a/modules/ModuleBuilder/parsers/relationships/OneToManyRelationship.php +++ b/modules/ModuleBuilder/parsers/relationships/OneToManyRelationship.php @@ -106,6 +106,7 @@ class OneToManyRelationship extends AbstractRelationship ); } + /* * @return array An array of field definitions, ready for the vardefs, keyed by module */ @@ -114,7 +115,9 @@ class OneToManyRelationship extends AbstractRelationship $vardefs = array ( ) ; $vardefs [ $this->rhs_module ] [] = $this->getLinkFieldDefinition ( $this->lhs_module, $this->relationship_name, false, - 'LBL_' . strtoupper ( $this->relationship_name . '_FROM_' . $this->getLeftModuleSystemLabel() ) . '_TITLE') ; + 'LBL_' . strtoupper ( $this->relationship_name . '_FROM_' . $this->getLeftModuleSystemLabel() ) . '_TITLE', + $this->relationship_only ? false : $this->getIDName( $this->lhs_module ) + ) ; if ($this->rhs_module != $this->lhs_module ) { $vardefs [ $this->lhs_module ] [] = $this->getLinkFieldDefinition ( $this->rhs_module, $this->relationship_name, true, diff --git a/modules/ModuleBuilder/parsers/relationships/OneToOneRelationship.php b/modules/ModuleBuilder/parsers/relationships/OneToOneRelationship.php index 4a734959..77272574 100644 --- a/modules/ModuleBuilder/parsers/relationships/OneToOneRelationship.php +++ b/modules/ModuleBuilder/parsers/relationships/OneToOneRelationship.php @@ -92,9 +92,13 @@ class OneToOneRelationship extends AbstractRelationship { $vardefs = array ( ) ; $vardefs [ $this->rhs_module ] [] = $this->getLinkFieldDefinition ( $this->lhs_module, $this->relationship_name , false, - 'LBL_' . strtoupper ( $this->relationship_name . '_FROM_' . $this->getLeftModuleSystemLabel() ) . '_TITLE' ) ; + 'LBL_' . strtoupper ( $this->relationship_name . '_FROM_' . $this->getLeftModuleSystemLabel() ) . '_TITLE' , + $this->relationship_only ? false : $this->getIDName( $this->lhs_module ) + ) ; $vardefs [ $this->lhs_module ] [] = $this->getLinkFieldDefinition ( $this->rhs_module, $this->relationship_name, false, - 'LBL_' . strtoupper ( $this->relationship_name . '_FROM_' . $this->getRightModuleSystemLabel() ) . '_TITLE' ) ; + 'LBL_' . strtoupper ( $this->relationship_name . '_FROM_' . $this->getRightModuleSystemLabel() ) . '_TITLE' , + $this->relationship_only ? false : $this->getIDName( $this->rhs_module ) + ) ; if (!$this->relationship_only) { diff --git a/modules/ModuleBuilder/parsers/relationships/UndeployedRelationships.php b/modules/ModuleBuilder/parsers/relationships/UndeployedRelationships.php index 14f89971..8b7560ba 100644 --- a/modules/ModuleBuilder/parsers/relationships/UndeployedRelationships.php +++ b/modules/ModuleBuilder/parsers/relationships/UndeployedRelationships.php @@ -283,36 +283,6 @@ class UndeployedRelationships extends AbstractRelationships implements Relations $this->installDefs = parent::build ( $basepath, "/SugarModules", $relationships ) ; } - /* - * Translate a set of subpanelDefinitions into files for the Module Loader - * @param string $basepath Basepath location for this module - * @param $installDefPrefix Pathname prefix for the installdefs, for example for ModuleBuilder use "/SugarModules" - * @param array $subpanelDefinitions Set of subpanel definitions in the form $subpanelDefinitions[$for_module][] - * @param string $relationshipName The name of the relationship for this subpanel definition - * @return array $installDefs Set of new installDefs - */ - protected function saveSubpanelDefinitions ($basepath , $installDefPrefix , $relationshipName , $subpanelDefinitions) - { - mkdir_recursive ( "$basepath/layoutdefs/" ) ; - - foreach ( $subpanelDefinitions as $moduleName => $definitions ) - { - $filename = "$basepath/layoutdefs/{$relationshipName}_{$moduleName}.php" ; - - foreach ( $definitions as $definition ) - { - $GLOBALS [ 'log' ]->debug ( get_class ( $this ) . "->saveSubpanelDefinitions(): saving the following to {$filename}" . print_r ( $definition, true ) ) ; - if (empty($definition ['get_subpanel_data']) || $definition ['subpanel_name'] == 'history' || $definition ['subpanel_name'] == 'activities') { - $definition ['get_subpanel_data'] = $definition ['subpanel_name']; - } - write_array_to_file ( 'layout_defs["' . $moduleName . '"]["subpanel_setup"]["' . strtolower ( $definition [ 'get_subpanel_data' ] ) . '"]', $definition, $filename, "a" ) ; - } - - $installDefs [ $moduleName ] = array ( 'from' => "{$installDefPrefix}/relationships/layoutdefs/{$relationshipName}_{$moduleName}.php" , 'to_module' => $moduleName ) ; - } - return $installDefs ; - } - /* * Add the installDefs for this relationship to the definitions in the parameter * Required by MBModule @@ -342,6 +312,27 @@ class UndeployedRelationships extends AbstractRelationships implements Relations return $this->updateUndeployedLayout ( $relationship, false ) ; } + /** + * @param AbstractRelationship $relationship + * @return void + */ + private function removeAppLangStrings($relationship) { + $def = $relationship->getDefinition(); + if (strtolower ( $def [ 'rhs_module' ] ) == 'activities' && !empty($_REQUEST [ 'view_package' ]) && !empty($_REQUEST [ 'view_module' ] )) + { + $mb = new ModuleBuilder ( ) ; + $module = $mb->getPackageModule ( $_REQUEST [ 'view_package' ], $_REQUEST [ 'view_module' ] ) ; + $appStrings = $module->getAppListStrings () ; + foreach(array('parent_type_display', 'record_type_display', 'record_type_display_notes') as $key) + { + if (isset($appStrings[$key][ $module->key_name ])) + unset($appStrings[$key][ $module->key_name ]); + } + $module->setAppListStrings ( 'en_us', $appStrings ) ; + $module->save () ; + } + } + /* * Add any relate fields to the DetailView and EditView of the appropriate module immediately (don't wait for a build) * @param AbstractRelationship $relationship The relationship whose fields we are to add or remove diff --git a/modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php b/modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php index edb3c17f..3300fb00 100644 --- a/modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php +++ b/modules/ModuleBuilder/parsers/views/GridLayoutMetaDataParser.php @@ -195,7 +195,8 @@ class GridLayoutMetaDataParser extends AbstractMetaDataParser implements MetaDat }else{ $availableFields [ $key ] = array ( 'name' => $key , 'label' => isset($def [ 'label' ]) ? $def [ 'label' ] : $def['vname'] ) ; // layouts use 'label' not 'vname' for the label entry } - $availableFields[$key]['translatedLabel'] = translate($availableFields[$key]['label'], $this->_moduleName); + + $availableFields[$key]['translatedLabel'] = translate( isset($def [ 'label' ]) ? $def [ 'label' ] : $def['vname'], $this->_moduleName); } } diff --git a/modules/ModuleBuilder/tpls/LayoutEditor.css b/modules/ModuleBuilder/tpls/LayoutEditor.css index ce0393e6..60cae5ed 100644 --- a/modules/ModuleBuilder/tpls/LayoutEditor.css +++ b/modules/ModuleBuilder/tpls/LayoutEditor.css @@ -48,7 +48,7 @@ #toolbox { float:left; width: 175px; padding:5px; margin:0; border: 1px dotted black;} #panels { float:right; - padding:5px 20px 10px 5px; + padding:5px 10px 5px 5px; margin-left:20px; border: 1px dotted black; } diff --git a/modules/ModuleBuilder/tpls/MBModule/vardef.tpl b/modules/ModuleBuilder/tpls/MBModule/vardef.tpl index 626d4fcf..92a3c22f 100644 --- a/modules/ModuleBuilder/tpls/MBModule/vardef.tpl +++ b/modules/ModuleBuilder/tpls/MBModule/vardef.tpl @@ -37,6 +37,9 @@ $dictionary['{{$class.name}}'] = array( 'table'=>'{{$class.table_name}}', 'audited'=>{{$class.audited}}, + {{if !($class.templates|strstr:"file")}} + 'duplicate_merge'=>true, + {{/if}} 'fields'=>{{$class.fields_string}}, 'relationships'=>{{$class.relationships}}, 'optimistic_locking'=>true, diff --git a/modules/ModuleBuilder/tpls/Preview/layoutView.tpl b/modules/ModuleBuilder/tpls/Preview/layoutView.tpl index a2bdee0b..58978177 100644 --- a/modules/ModuleBuilder/tpls/Preview/layoutView.tpl +++ b/modules/ModuleBuilder/tpls/Preview/layoutView.tpl @@ -44,7 +44,7 @@
  • -
    + + + {include file='modules/ModuleBuilder/tpls/assistantJavascript.tpl'} \ No newline at end of file diff --git a/modules/ModuleBuilder/tpls/labels.tpl b/modules/ModuleBuilder/tpls/labels.tpl index 403e419c..10afc247 100644 --- a/modules/ModuleBuilder/tpls/labels.tpl +++ b/modules/ModuleBuilder/tpls/labels.tpl @@ -48,6 +48,8 @@ {else} + {/if}
    {html_options name='labels' options=$labels_choice selected=$labels_current onchange='this.form.action.value="EditLabels";ModuleBuilder.handleSave("editlabels")'} diff --git a/modules/ModuleBuilder/tpls/listView.tpl b/modules/ModuleBuilder/tpls/listView.tpl index c942a43a..0d7542cd 100644 --- a/modules/ModuleBuilder/tpls/listView.tpl +++ b/modules/ModuleBuilder/tpls/listView.tpl @@ -48,6 +48,7 @@ studiotabs.reset(); + {if $fromPortal} @@ -179,6 +180,8 @@ function dragDropInit(){ resizeDDLists = function() { var Dom = YAHOO.util.Dom; + if (!Dom.get('ul0')) + return; var body = document.getElementById('mbtabs'); for(var msi = 0; msi < studiotabs.slotCount ; msi++){ var targetHeight = body.offsetHeight - (Dom.getY("ul" + msi) - Dom.getY(body)) - 20; @@ -189,6 +192,10 @@ resizeDDLists = function() { if (targetHeight > 0 ) Dom.setStyle("ul" + msi, "height", targetHeight + "px"); } + Studio2.scrollZones = {} + for (var i = 0; Dom.get("ul" + i); i++){ + Studio2.scrollZones["ul" + i] = Studio2.getScrollZones("ul" + i); + } }; function countListFields() { diff --git a/modules/ModuleBuilder/views/view.dashlet.php b/modules/ModuleBuilder/views/view.dashlet.php index c46b6df3..917aa99c 100644 --- a/modules/ModuleBuilder/views/view.dashlet.php +++ b/modules/ModuleBuilder/views/view.dashlet.php @@ -119,7 +119,7 @@ class ViewDashlet extends ViewListView $ViewLabel = ($this->editLayout == MB_DASHLET) ? 'LBL_DASHLETLISTVIEW' : 'LBL_DASHLETSEARCHVIEW'; $ajax->addCrumb ( translate ($ViewLabel, 'ModuleBuilder' ), '' ) ; }else{ - $ajax->addCrumb ( $this->editModule, 'ModuleBuilder.getContent("module=ModuleBuilder&action=module&view_module=' . $this->editModule . '")' ) ; + $ajax->addCrumb ( translate($this->editModule), 'ModuleBuilder.getContent("module=ModuleBuilder&action=module&view_module=' . $this->editModule . '")' ) ; $ajax->addCrumb ( translate('LBL_LAYOUTS', 'ModuleBuilder'), 'ModuleBuilder.getContent("module=ModuleBuilder&action=wizard&layouts=1&view_module=' . $this->editModule . '")'); $ajax->addCrumb ( translate('LBL_DASHLET', 'ModuleBuilder'), 'ModuleBuilder.getContent("module=ModuleBuilder&action=wizard&view=dashlet&view_module=' . $this->editModule . '")' ); $ViewLabel = ($this->editLayout == MB_DASHLET) ? 'LBL_DASHLETLISTVIEW' : 'LBL_DASHLETSEARCHVIEW'; diff --git a/modules/ModuleBuilder/views/view.dropdown.php b/modules/ModuleBuilder/views/view.dropdown.php index 48397b4f..fd66623f 100644 --- a/modules/ModuleBuilder/views/view.dropdown.php +++ b/modules/ModuleBuilder/views/view.dropdown.php @@ -104,6 +104,9 @@ class ViewDropdown extends SugarView $smarty->assign('module_name', $module->name); } + $module_name = !empty($module->name) ? $module->name : ''; + $module_name = (empty($module_name) && !empty($_REQUEST['view_module'])) ? $_REQUEST['view_module'] : $module_name; + foreach($my_list_strings as $key=>$value){ if(!is_array($value)){ unset($my_list_strings[$key]); @@ -150,6 +153,7 @@ class ViewDropdown extends SugarView $smarty->assign('prepopulated_name', $use_name); } + $smarty->assign('module_name', $module_name); $smarty->assign('APP', $GLOBALS['app_strings']); $smarty->assign('MOD', $GLOBALS['mod_strings']); $smarty->assign('selected_lang', $selected_lang); diff --git a/modules/ModuleBuilder/views/view.labels.php b/modules/ModuleBuilder/views/view.labels.php index 1e09d00f..5826d0a7 100644 --- a/modules/ModuleBuilder/views/view.labels.php +++ b/modules/ModuleBuilder/views/view.labels.php @@ -81,12 +81,7 @@ class ViewLabels extends ViewModulefields $smarty->assign('available_languages',get_languages()); - global $beanList; - $objectName = $beanList[$editModule]; - if($objectName == 'aCase') { - $objectName = 'Case'; - } - + $objectName = BeanFactory::getObjectName($editModule); VardefManager::loadVardef($editModule, $objectName); global $dictionary; $vnames = array(); diff --git a/modules/ModuleBuilder/views/view.listview.php b/modules/ModuleBuilder/views/view.listview.php index 99bd0513..384df6b5 100644 --- a/modules/ModuleBuilder/views/view.listview.php +++ b/modules/ModuleBuilder/views/view.listview.php @@ -181,6 +181,7 @@ class ViewListView extends ViewEdit if (!empty ( $this->subpanel ) ) { $smarty->assign ( 'subpanel', $this->subpanel ) ; + $smarty->assign ( 'subpanelLabel', $this->subpanelLabel ) ; if (!$this->fromModuleBuilder) { $subList = SubPanel::getModuleSubpanels ( $this->editModule); $subRef = $subList[strtolower($this->subpanel)]; diff --git a/modules/ModuleBuilder/views/view.main.php b/modules/ModuleBuilder/views/view.main.php index 51cfe076..14658338 100644 --- a/modules/ModuleBuilder/views/view.main.php +++ b/modules/ModuleBuilder/views/view.main.php @@ -38,7 +38,7 @@ class ViewMain extends SugarView { function ViewMain(){ - $this->options['show_footer'] = true; + $this->options['show_footer'] = false; parent::SugarView(); } diff --git a/modules/ModuleBuilder/views/view.modulefield.php b/modules/ModuleBuilder/views/view.modulefield.php index 81f3e0c0..e3794354 100644 --- a/modules/ModuleBuilder/views/view.modulefield.php +++ b/modules/ModuleBuilder/views/view.modulefield.php @@ -142,21 +142,14 @@ class ViewModulefield extends SugarView } if(! isset($_REQUEST['view_package']) || $_REQUEST['view_package'] == 'studio' || empty ( $_REQUEST [ 'view_package' ] ) ) { - $module = new stdClass; $moduleName = $_REQUEST['view_module']; + $objectName = BeanFactory::getObjectName($moduleName); + $module = BeanFactory::getBean($moduleName); - $objectName = $beanList[$moduleName]; - $className = $objectName; - if($objectName == 'aCase') // Bug 17614 - renamed aCase as Case in vardefs for backwards compatibililty with 451 modules - $objectName = 'Case'; - - $module = new $className(); - VardefManager::loadVardef($moduleName, $objectName,true); global $dictionary; $module->mbvardefs->vardefs = $dictionary[$objectName]; -// $GLOBALS['log']->debug('vardefs from dictionary = '.print_r($module->mbvardefs->vardefs,true)); $module->name = $moduleName; if(!$ac){ $ac = new AjaxCompose(); diff --git a/modules/ModuleBuilder/views/view.modulefields.php b/modules/ModuleBuilder/views/view.modulefields.php index 0eca18e8..46febb52 100644 --- a/modules/ModuleBuilder/views/view.modulefields.php +++ b/modules/ModuleBuilder/views/view.modulefields.php @@ -68,19 +68,11 @@ class ViewModulefields extends SugarView $studioClass = new stdClass; $studioClass->name = $module_name; - global $beanList; - $objectName = $beanList[$module_name]; - - if($objectName == 'aCase') // Bug 17614 - renamed aCase as Case in vardefs for backwards compatibililty with 451 modules - $objectName = 'Case'; - + $objectName = BeanFactory::getObjectName($module_name); VardefManager::loadVardef($module_name, $objectName, true); global $dictionary; $f = array($mod_strings['LBL_HCUSTOM']=>array(), $mod_strings['LBL_HDEFAULT']=>array()); - // TODO: replace this section to select fields to list with the algorithm in AbstractMetaDataImplmentation::validField() - $def = $this->cullFields($dictionary[$objectName]['fields']); - foreach($dictionary[$objectName]['fields'] as $def) { if ($this->isValidStudioField($def)) { diff --git a/modules/ModuleBuilder/views/view.popupview.php b/modules/ModuleBuilder/views/view.popupview.php index 5c33b1ad..f208f251 100644 --- a/modules/ModuleBuilder/views/view.popupview.php +++ b/modules/ModuleBuilder/views/view.popupview.php @@ -118,7 +118,7 @@ class ViewPopupview extends ViewListView $ViewLabel = ($this->editLayout == MB_POPUPLIST) ? 'LBL_POPUPLISTVIEW' : 'LBL_POPUPSEARCH'; $ajax->addCrumb ( translate ($ViewLabel, 'ModuleBuilder' ), '' ) ; }else{ - $ajax->addCrumb ( $this->editModule, 'ModuleBuilder.getContent("module=ModuleBuilder&action=module&view_module=' . $this->editModule . '")' ) ; + $ajax->addCrumb ( translate($this->editModule), 'ModuleBuilder.getContent("module=ModuleBuilder&action=module&view_module=' . $this->editModule . '")' ) ; $ajax->addCrumb ( translate('LBL_LAYOUTS', 'ModuleBuilder'), 'ModuleBuilder.getContent("module=ModuleBuilder&action=wizard&layouts=1&view_module=' . $this->editModule . '")'); $ajax->addCrumb ( translate('LBL_POPUP', 'ModuleBuilder'), 'ModuleBuilder.getContent("module=ModuleBuilder&action=wizard&view=popup&view_module=' . $this->editModule . '")' ); $ViewLabel = ($this->editLayout == MB_POPUPLIST) ? 'LBL_POPUPLISTVIEW' : 'LBL_POPUPSEARCH'; diff --git a/modules/MySettings/LoadTabSubpanels.php b/modules/MySettings/LoadTabSubpanels.php index 41f269ba..4839cf7c 100644 --- a/modules/MySettings/LoadTabSubpanels.php +++ b/modules/MySettings/LoadTabSubpanels.php @@ -63,7 +63,8 @@ if(!function_exists('get_form_header')) { // set up data for subpanels global $currentModule; -$currentModule = $_REQUEST['loadModule']; +if (!empty($_REQUEST['loadModule'])) + $currentModule = $_REQUEST['loadModule']; $_REQUEST['action'] = 'DetailView'; echo $subpanel->display(false); diff --git a/modules/Notes/Note.php b/modules/Notes/Note.php index f11072d5..3d616e8e 100644 --- a/modules/Notes/Note.php +++ b/modules/Notes/Note.php @@ -191,7 +191,7 @@ class Note extends SugarBean { $custom_join = $this->custom_fields->getJOIN(true, true,$where); if($custom_join) $custom_join['join'] .= $relate_link_join; - $query = "SELECT notes.*, contacts.first_name, contacts.last_name "; + $query = "SELECT notes.*, contacts.first_name, contacts.last_name, users.user_name as assigned_user_name "; if($custom_join) { $query .= $custom_join['select']; @@ -200,6 +200,7 @@ class Note extends SugarBean { $query .= " FROM notes "; $query .= " LEFT JOIN contacts ON notes.contact_id=contacts.id "; + $query .= " LEFT JOIN users ON notes.assigned_user_id=users.id "; if($custom_join) { $query .= $custom_join['join']; diff --git a/modules/Notes/language/en_us.lang.php b/modules/Notes/language/en_us.lang.php index 60e1b120..b68cc8aa 100644 --- a/modules/Notes/language/en_us.lang.php +++ b/modules/Notes/language/en_us.lang.php @@ -100,8 +100,13 @@ $mod_strings = array ( 'LBL_LIST_EDIT_BUTTON' => 'Edit', 'LBL_ACTIVITIES_REPORTS' => 'Activities Report', 'LBL_PANEL_DETAILS' => 'Details', - 'LBL_NOTE_INFORMATION' => 'Note Overview', + 'LBL_NOTE_INFORMATION' => 'Overview', 'LBL_MY_NOTES_DASHLETNAME' => 'My Notes', + //For export labels + 'LBL_FIRST_NAME' => 'First Name', + 'LBL_LAST_NAME' => 'Last Name', + 'LBL_EXPORT_PARENT_TYPE' => 'Related To Module', + 'LBL_EXPORT_PARENT_ID' => 'Related To ID', ); ?> \ No newline at end of file diff --git a/modules/Notes/vardefs.php b/modules/Notes/vardefs.php index 1aadf346..8242af8e 100644 --- a/modules/Notes/vardefs.php +++ b/modules/Notes/vardefs.php @@ -457,6 +457,7 @@ $dictionary['Note'] = array( array('name' =>'idx_note_name', 'type'=>'index', 'fields'=>array('name')), array('name' =>'idx_notes_parent', 'type'=>'index', 'fields'=>array('parent_id', 'parent_type')), array('name' =>'idx_note_contact', 'type'=>'index', 'fields'=>array('contact_id')), + array('name' =>'idx_notes_assigned_del', 'type' =>'index', 'fields'=>array( 'deleted', 'assigned_user_id')), ) diff --git a/modules/OAuthKeys/OAuthKey.php b/modules/OAuthKeys/OAuthKey.php new file mode 100644 index 00000000..eb1121d9 --- /dev/null +++ b/modules/OAuthKeys/OAuthKey.php @@ -0,0 +1,90 @@ +retrieve_by_string_fields(array("c_key" => $key)); + if(empty($this->id)) return false; + // need this to decrypt the key + $this->check_date_relationships_load(); + return $this; + } + + /** + * Fetch customer key by id + * @param string $key + */ + public static function fetchKey($key) + { + if(isset(self::$keys_cache[$key])) { + return self::$keys_cache[$key]; + } + $k = new self(); + if($k->getByKey($key)) { + self::$keys_cache[$key] = $k; + return $k; + } + return false; + } + + public function mark_deleted($id) + { + $this->db->query("DELETE from {$this->table_name} WHERE id='".$this->db->quote($id)."'"); + $this->db->query("DELETE from oauth_tokens WHERE consumer='".$this->db->quote($id)."'"); + } + +} diff --git a/modules/OAuthKeys/controller.php b/modules/OAuthKeys/controller.php new file mode 100644 index 00000000..9283d7ee --- /dev/null +++ b/modules/OAuthKeys/controller.php @@ -0,0 +1,46 @@ +hasAccess = false; + } + parent::process(); + } +} \ No newline at end of file diff --git a/modules/OAuthKeys/language/en_us.lang.php b/modules/OAuthKeys/language/en_us.lang.php new file mode 100644 index 00000000..11f21c0e --- /dev/null +++ b/modules/OAuthKeys/language/en_us.lang.php @@ -0,0 +1,64 @@ + 'Consumer Key', + 'LBL_CONSSECRET' => 'Consumer Secret', + 'LBL_ASSIGNED_TO_ID' => 'Assigned User Id', + 'LBL_ASSIGNED_TO_NAME' => 'User', + 'LBL_ID' => 'ID', + 'LBL_DATE_ENTERED' => 'Date Created', + 'LBL_DATE_MODIFIED' => 'Date Modified', + 'LBL_MODIFIED' => 'Modified By', + 'LBL_MODIFIED_ID' => 'Modified By Id', + 'LBL_MODIFIED_NAME' => 'Modified By Name', + 'LBL_CREATED' => 'Created By', + 'LBL_CREATED_ID' => 'Created By Id', + 'LBL_DESCRIPTION' => 'Description', + 'LBL_DELETED' => 'Deleted', + 'LBL_NAME' => 'Consumer Key Name', + 'LBL_CREATED_USER' => 'Created By User', + 'LBL_MODIFIED_USER' => 'Modified By User', + 'LBL_LIST_NAME' => 'Key Name', + 'LBL_LIST_FORM_TITLE' => 'OAuth Keys', + 'LBL_MODULE_NAME' => 'OAuth Keys', + 'LBL_MODULE_TITLE' => 'OAuth Keys', + 'LNK_NEW_RECORD' => 'Create OAuth Key', + 'LNK_LIST' => 'View OAuth Keys', + 'LBL_TOKENS' => 'Tokens', +); diff --git a/modules/OAuthKeys/metadata/SearchFields.php b/modules/OAuthKeys/metadata/SearchFields.php new file mode 100644 index 00000000..97513477 --- /dev/null +++ b/modules/OAuthKeys/metadata/SearchFields.php @@ -0,0 +1,55 @@ + array( 'query_type'=>'default'), + 'name' => array( 'query_type'=>'default'), + 'c_key' => array( 'query_type'=>'default'), + 'current_user_only'=> array('query_type'=>'default','db_field'=>array('assigned_user_id'),'my_items'=>true, 'vname' => 'LBL_CURRENT_USER_FILTER', 'type' => 'bool'), + 'assigned_user_id'=> array('query_type'=>'default'), + 'favorites_only' => array( + 'query_type'=>'format', + 'operator' => 'subquery', + 'subquery' => 'SELECT sugarfavorites.record_id FROM sugarfavorites + WHERE sugarfavorites.deleted=0 + and sugarfavorites.module = "'.$module_name.'" + and sugarfavorites.assigned_user_id = "{0}"', + 'db_field'=>array('id')), + ); +?> diff --git a/modules/OAuthKeys/metadata/detailviewdefs.php b/modules/OAuthKeys/metadata/detailviewdefs.php new file mode 100644 index 00000000..90ecefaf --- /dev/null +++ b/modules/OAuthKeys/metadata/detailviewdefs.php @@ -0,0 +1,65 @@ + array('maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + ), + +'panels' =>array ( + array('name', 'description'), + array('c_key'), + + array ( + array ( + 'name' => 'date_entered', + 'customCode' => '{$fields.date_entered.value} {$APP.LBL_BY} {$fields.created_by_name.value}', + 'label' => 'LBL_DATE_ENTERED', + ), + array ( + 'name' => 'date_modified', + 'customCode' => '{$fields.date_modified.value} {$APP.LBL_BY} {$fields.modified_by_name.value}', + 'label' => 'LBL_DATE_MODIFIED', + ), + ), + +) +); +?> diff --git a/modules/OAuthKeys/metadata/editviewdefs.php b/modules/OAuthKeys/metadata/editviewdefs.php new file mode 100644 index 00000000..cd95247c --- /dev/null +++ b/modules/OAuthKeys/metadata/editviewdefs.php @@ -0,0 +1,52 @@ + array('maxColumns' => '2', + 'widths' => array( + array('label' => '10', 'field' => '30'), + array('label' => '10', 'field' => '30') + ), + ), + 'panels' =>array ( + 'default' => + array ( + array('name'), + array ('c_key', 'c_secret'), + array('description'), + ), +), +); diff --git a/modules/OAuthKeys/metadata/listviewdefs.php b/modules/OAuthKeys/metadata/listviewdefs.php new file mode 100644 index 00000000..a411f229 --- /dev/null +++ b/modules/OAuthKeys/metadata/listviewdefs.php @@ -0,0 +1,53 @@ + array( + 'width' => '32', + 'label' => 'LBL_NAME', + 'default' => true, + 'link' => true, + ), + 'C_KEY' => array( + 'width' => '40', + 'label' => 'LBL_CONSKEY', + 'default' => true), +); diff --git a/modules/OAuthKeys/metadata/metafiles.php b/modules/OAuthKeys/metadata/metafiles.php new file mode 100644 index 00000000..3ab57eed --- /dev/null +++ b/modules/OAuthKeys/metadata/metafiles.php @@ -0,0 +1,46 @@ + 'modules/' . $module_name . '/metadata/detailviewdefs.php', + 'editviewdefs' => 'modules/' . $module_name . '/metadata/editviewdefs.php', + 'listviewdefs' => 'modules/' . $module_name . '/metadata/listviewdefs.php', + 'searchdefs' => 'modules/' . $module_name . '/metadata/searchdefs.php', + 'popupdefs' => 'modules/' . $module_name . '/metadata/popupdefs.php', + 'searchfields' => 'modules/' . $module_name . '/metadata/SearchFields.php', + ); +?> diff --git a/modules/OAuthKeys/metadata/searchdefs.php b/modules/OAuthKeys/metadata/searchdefs.php new file mode 100644 index 00000000..90a6de39 --- /dev/null +++ b/modules/OAuthKeys/metadata/searchdefs.php @@ -0,0 +1,56 @@ + array( + 'maxColumns' => '3', 'maxColumnsBasic' => '4', + 'widths' => array('label' => '10', 'field' => '30'), + ), + 'layout' => array( + 'basic_search' => array( + 'name', + array('name'=>'current_user_only', 'label'=>'LBL_CURRENT_USER_FILTER', 'type'=>'bool'), + array ('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',), + ), + 'advanced_search' => array( + 'name', 'type', 'validated', + array('name' => 'assigned_user_id', 'label' => 'LBL_ASSIGNED_TO', 'type' => 'enum', 'function' => array('name' => 'get_user_array', 'params' => array(false))), + array ('name' => 'favorites_only','label' => 'LBL_FAVORITES_FILTER','type' => 'bool',), + ), + ), + ); +?> diff --git a/modules/OAuthKeys/metadata/subpaneldefs.php b/modules/OAuthKeys/metadata/subpaneldefs.php new file mode 100644 index 00000000..519587ca --- /dev/null +++ b/modules/OAuthKeys/metadata/subpaneldefs.php @@ -0,0 +1,56 @@ + array( + 'tokens' => array( + 'order' => 30, + 'module' => 'OAuthTokens', + 'sort_order' => 'asc', + 'sort_by' => 'token_ts', + 'subpanel_name' => 'ForKeys', + 'get_subpanel_data' => 'tokens', + 'title_key' => 'LBL_TOKENS', + 'top_buttons' => array( + ), + + ), + ) +); diff --git a/modules/OAuthKeys/vardefs.php b/modules/OAuthKeys/vardefs.php new file mode 100644 index 00000000..c2c5eb12 --- /dev/null +++ b/modules/OAuthKeys/vardefs.php @@ -0,0 +1,86 @@ + 'oauth_consumer', + 'comment' => 'OAuth consumer keys', + 'audited'=>false, + 'fields' => array ( + 'c_key' => + array ( + 'name' => 'c_key', + 'vname' => 'LBL_CONSKEY', + 'type' => 'varchar', + 'required' => true, + 'comment' => 'Consumer public key', + 'importable' => 'required', + 'massupdate' => 0, + 'reportable'=>false, + 'studio' => 'hidden', + ), + 'c_secret' => + array ( + 'name' => 'c_secret', + 'vname' => 'LBL_CONSSECRET', + //'type' => 'encrypt', + 'type' => 'varchar', + 'required' => true, + 'comment' => 'Consumer secret key', + 'importable' => 'required', + 'massupdate' => 0, + 'reportable'=>false, + 'studio' => 'hidden', + ), + 'tokens' => + array ( + 'name' => 'tokens', + 'type' => 'link', + 'relationship' => 'consumer_tokens', + 'module'=>'OAuthTokens', + 'bean_name'=>'OAuthToken', + 'source'=>'non-db', + 'vname'=>'LBL_TOKENS', + ), + + ), + 'indices' => array ( + array('name' =>'ckey', 'type' =>'unique', 'fields'=>array('c_key')), + ) +); +if (!class_exists('VardefManager')){ + require_once('include/SugarObjects/VardefManager.php'); +} +VardefManager::createVardef('OAuthKeys','OAuthKey', array('basic','assignable')); diff --git a/modules/OAuthTokens/OAuthToken.php b/modules/OAuthTokens/OAuthToken.php new file mode 100644 index 00000000..70de03fb --- /dev/null +++ b/modules/OAuthTokens/OAuthToken.php @@ -0,0 +1,246 @@ +token = $token; + $this->secret = $secret; + $this->setState(self::REQUEST); + } + + /** + * Set token state + * @param int $s + * @return OAuthToken + */ + public function setState($s) + { + $this->tstate = $s; + return $this; + } + + /** + * Associate the token with the consumer key + * @param OAuthKey $consumer + */ + public function setConsumer($consumer) + { + $this->consumer = $consumer->id; + $this->consumer_obj = $consumer; + return $this; + } + + /** + * Generate random token + * @return string + */ + protected static function randomValue() + { + return bin2hex(Zend_Oauth_Provider::generateToken(6)); + } + + /** + * Generate random token/secret pair and create token + * @return OAuthToken + */ + static function generate() + { + $t = self::randomValue(); + $s = self::randomValue(); + return new self($t, $s); + } + + public function save() + { + $this->token_ts = time(); + if(!isset($this->id)) { + $this->new_with_id = true; + $this->id = $this->token; + } + parent::save(); + } + + /** + * Load token by ID + * @param string $token + * @return OAuthToken + */ + static function load($token) + { + $ltoken = new self(); + $ltoken->retrieve($token); + if(empty($ltoken->id)) return null; + $ltoken->token = $ltoken->id; + if(!empty($ltoken->consumer)) { + $ltoken->consumer_obj = new OAuthKey(); + $ltoken->consumer_obj->retrieve($ltoken->consumer); + if(empty($ltoken->consumer_obj->id)) { + return null; + } + } + return $ltoken; + } + + /** + * Invalidate token + */ + public function invalidate() + { + $this->setState(self::INVALID); + $this->verify = false; + return $this->save(); + } + + /** + * Authorize request token + * @param mixed $authdata + * @return string Validation token + */ + public function authorize($authdata) + { + if($this->tstate != self::REQUEST) { + return false; + } + $this->verify = self::randomValue(); + $this->authdata = $authdata; + if(isset($authdata['user'])) { + $this->assigned_user_id = $authdata['user']; + } + $this->save(); + return $this->verify; + } + + /** + * Copy auth data between tokens + * @param OAuthToken $token + * @return OAuthToken + */ + public function copyAuthData(OAuthToken $token) + { + $this->authdata = $token->authdata; + $this->assigned_user_id = $token->assigned_user_id; + return $this; + } + + /** + * Get query string for the token + */ + public function queryString() + { + return "oauth_token={$this->token}&oauth_token_secret={$this->secret}"; + } + + /** + * Clean up stale tokens + */ + static public function cleanup() + { + global $db; + // delete invalidated tokens older than 1 day + $db->query("DELETE FROM oauth_token WHERE status = ".self::INVALID." AND token_ts < ".time()-60*60*24); + // delete request tokens older than 1 day + $db->query("DELETE FROM oauth_token WHERE status = ".self::REQUEST." AND token_ts < ".time()-60*60*24); + } + + /** + * Check if the nonce is valid + * @param string $key + * @param string $nonce + * @param string $ts + */ + public static function checkNonce($key, $nonce, $ts) + { + global $db; + + $res = $db->query(sprintf("SELECT * FROM oauth_nonce WHERE conskey='%s' AND nonce_ts > %d", $db->quote($key), $ts)); + if($res && $db->fetchByAssoc($res)) { + // we have later ts + return Zend_Oauth_Provider::BAD_TIMESTAMP; + } + + $res = $db->query(sprintf("SELECT * FROM oauth_nonce WHERE conskey='%s' AND nonce='%s' AND nonce_ts = %d", $db->quote($key), $db->quote($nonce), $ts)); + if($res && $db->fetchByAssoc($res)) { + // Already seen this one + return Zend_Oauth_Provider::BAD_NONCE; + } + $db->query(sprintf("DELETE FROM oauth_nonce WHERE conskey='%s' AND nonce_ts < %d", $db->quote($key), $ts)); + $db->query(sprintf("INSERT INTO oauth_nonce(conskey, nonce, nonce_ts) VALUES('%s', '%s', %d)", $db->quote($key), $db->quote($nonce), $ts)); + return Zend_Oauth_Provider::OK; + } + + public function mark_deleted($id) + { + $this->db->query("DELETE from {$this->table_name} WHERE id='".$this->db->quote($id)."'"); + } +} + +function displayDateFromTs($focus, $field, $value, $view='ListView') +{ + $field = strtoupper($field); + if(!isset($focus[$field])) return ''; + global $timedate; + return $timedate->asUser($timedate->fromTimestamp($focus[$field])); +} diff --git a/modules/OAuthTokens/action_view_map.php b/modules/OAuthTokens/action_view_map.php new file mode 100644 index 00000000..b08fd81c --- /dev/null +++ b/modules/OAuthTokens/action_view_map.php @@ -0,0 +1,41 @@ +bean->assigned_user_id != $current_user->id) { + ACLController::displayNoAccess(true); + sugar_cleanup(true); + } + $this->bean->mark_deleted($_REQUEST['record']); + }else{ + sugar_die("A record number must be specified to delete"); + } + } + + protected function post_delete() + { + if(!empty($_REQUEST['return_url'])){ + $_REQUEST['return_url'] =urldecode($_REQUEST['return_url']); + $this->redirect_url = $_REQUEST['return_url']; + } else { + parent::post_delete(); + } + } +} \ No newline at end of file diff --git a/modules/OAuthTokens/language/en_us.lang.php b/modules/OAuthTokens/language/en_us.lang.php new file mode 100644 index 00000000..fd3b62c1 --- /dev/null +++ b/modules/OAuthTokens/language/en_us.lang.php @@ -0,0 +1,53 @@ + "Request Token", + 'LBL_OAUTH_AUTHORIZE' => "Authorize Token", + 'LBL_OAUTH_CONSUMERREQ' => "Authorize token from consumer %s?", + 'LBL_OAUTH_ROLE' => "Token role", + 'LBL_OAUTH_VALIDATION' => "Verification code", + 'LBL_ASSIGNED_TO_NAME' => 'User', + 'LBL_ID' => 'ID', + 'LBL_STATUS' => 'Status', + 'LBL_TS' => 'Timestamp', + 'LBL_LIST_DELETE' => 'Delete Token', + 'LBL_CONSUMER' => 'Consumer Name', + 'LBL_OAUTH_DISABLED' => 'OAuth support not enabled. PHP oauth extension may be missing. Please contact your administrator.', +); diff --git a/modules/OAuthTokens/metadata/subpanels/ForKeys.php b/modules/OAuthTokens/metadata/subpanels/ForKeys.php new file mode 100644 index 00000000..ea7585e6 --- /dev/null +++ b/modules/OAuthTokens/metadata/subpanels/ForKeys.php @@ -0,0 +1,79 @@ + array( + ), + + 'where' => '', + + 'list_fields' => array( + 'id'=>array( + 'name'=>'id', + 'width' => '10%', + 'vname' => 'LBL_ID', + ), + 'tstate'=>array( + 'name'=>'tstate', + 'width' => '10%', + 'vname' => 'LBL_STATUS', + ), + 'token_ts'=>array( + 'name'=>'token_ts', + 'width' => '10%', + 'vname' => 'LBL_TS', + 'function' => 'testfunc', + ), + 'assigned_user_name' => array( + 'name' => 'assigned_user_name', + 'module' => 'Users', + 'target_record_key' => 'assigned_user_id', + 'target_module' => 'Users', + 'widget_class' => 'SubPanelDetailViewLink', + 'width' => '10%', + 'vname' => 'LBL_ASSIGNED_TO_NAME', + ), + 'del_button'=>array( + 'widget_class' => 'SubPanelDeleteButton', + 'vname' => 'LBL_LIST_DELETE', + 'width' => '6%', + 'sortable'=>false, + ), + ) +); diff --git a/modules/OAuthTokens/metadata/subpanels/ForUser.php b/modules/OAuthTokens/metadata/subpanels/ForUser.php new file mode 100644 index 00000000..a9c76bd2 --- /dev/null +++ b/modules/OAuthTokens/metadata/subpanels/ForUser.php @@ -0,0 +1,79 @@ + array( + ), + + 'where' => '', + + 'list_fields' => array( + 'id'=>array( + 'name'=>'id', + 'width' => '10%', + 'vname' => 'LBL_ID', + ), + 'tstate'=>array( + 'name'=>'tstate', + 'width' => '10%', + 'vname' => 'LBL_STATUS', + ), + 'token_ts'=>array( + 'name'=>'token_ts', + 'width' => '10%', + 'vname' => 'LBL_TS', + 'function' => 'testfunc', + ), + 'consumer_name' => array( + 'name' => 'consumer_name', + 'module' => 'OAuthKeys', + 'target_record_key' => 'consumer', + 'target_module' => 'OAuthKeys', + 'width' => '10%', + 'vname' => 'LBL_CONSUMER', + ), + 'del_button'=>array( + 'widget_class' => 'SubPanelDeleteButton', + 'vname' => 'LBL_LIST_DELETE', + 'width' => '6%', + 'sortable'=>false, + ), + ) +); diff --git a/modules/OAuthTokens/tpl/authorize.tpl b/modules/OAuthTokens/tpl/authorize.tpl new file mode 100644 index 00000000..703978e8 --- /dev/null +++ b/modules/OAuthTokens/tpl/authorize.tpl @@ -0,0 +1,53 @@ +{* +/********************************************************************************* + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +
    + + + + + + +{$consumer}
    + + + + +
    {$MOD.LBL_OAUTH_REQUEST}:
    + +
    +
    diff --git a/modules/OAuthTokens/tpl/authorized.tpl b/modules/OAuthTokens/tpl/authorized.tpl new file mode 100644 index 00000000..37beb276 --- /dev/null +++ b/modules/OAuthTokens/tpl/authorized.tpl @@ -0,0 +1,39 @@ +{* +/********************************************************************************* + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + +*} +Token authorization code: +{$VERIFY} \ No newline at end of file diff --git a/modules/OAuthTokens/vardefs.php b/modules/OAuthTokens/vardefs.php new file mode 100644 index 00000000..004cc131 --- /dev/null +++ b/modules/OAuthTokens/vardefs.php @@ -0,0 +1,195 @@ + 'oauth_tokens', + 'comment' => 'OAuth tokens', + 'audited'=>false, + 'fields' => array ( + 'id' => + array ( + 'name' => 'id', + 'vname' => 'LBL_ID', + 'type' => 'id', + 'required'=>true, + 'reportable'=>true, + 'comment' => 'Unique identifier' + ), + 'secret' => + array ( + 'name' => 'secret', + 'type' => 'varchar', + 'len' => 32, + 'required' => true, + 'comment' => 'Secret key', + ), + 'tstate' => + array ( + 'name' => 'tstate', + 'type' => 'enum', + 'len' => 1, + 'options' => 'token_status', + 'required' => true, + 'comment' => 'Token state', + + ), + 'consumer' => + array ( + 'name' => 'consumer', + 'type' => 'id', + 'required' => true, + 'comment' => 'Token related to the consumer', + ), + 'token_ts' => + array ( + 'name' => 'token_ts', + 'type' => 'long', + 'required' => true, + 'comment' => 'Token timestamp', + 'function' => array('name' => 'displayDateFromTs', 'returns' => 'html', 'onListView' => true) + ), + 'verify' => + array ( + 'name' => 'verify', + 'type' => 'varchar', + 'len' => 32, + 'comment' => 'Token verification info', + ), +// 'authdata' => +// array ( +// 'name' => 'verify', +// 'type' => 'text', +// 'comment' => 'Token auth data', +// ), + 'deleted' => + array ( + 'name' => 'deleted', + 'vname' => 'LBL_DELETED', + 'type' => 'bool', + 'default' => '0', + 'reportable'=>false, + 'required' => true, + 'isnull' => false, + 'comment' => 'Record deletion indicator' + ), + 'consumer_link' => + array ( + 'name' => 'consumer_link', + 'type' => 'link', + 'relationship' => 'consumer_tokens', + 'vname' => 'LBL_CONSUMER', + 'link_type' => 'one', + 'module'=>'OAuthKeys', + 'bean_name'=>'OAuthKey', + 'source'=>'non-db', + ), + 'consumer_name' => + array ( + 'name' => 'consumer_name', + 'link'=>'consumer_link' , + 'vname' => 'LBL_CONSUMER', + 'rname' => 'name', + 'type' => 'relate', + 'reportable'=>false, + 'source'=>'non-db', + 'table' => 'oauth_consumer', + 'id_name' => 'consumer', + 'module'=>'OAuthKeys', + 'duplicate_merge'=>'disabled' + ), + 'assigned_user_id' => + array ( + 'name' => 'assigned_user_id', + 'rname' => 'user_name', + 'id_name' => 'assigned_user_id', + 'vname' => 'LBL_ASSIGNED_TO_ID', + 'group'=>'assigned_user_name', + 'type' => 'relate', + 'table' => 'users', + 'module' => 'Users', + 'reportable'=>true, + 'isnull' => 'false', + 'dbType' => 'id', + 'audited'=>true, + 'comment' => 'User ID assigned to record', + 'duplicate_merge'=>'disabled' + ), + 'assigned_user_name' => + array ( + 'name' => 'assigned_user_name', + 'link'=>'assigned_user_link' , + 'vname' => 'LBL_ASSIGNED_TO_NAME', + 'rname' => 'user_name', + 'type' => 'relate', + 'reportable'=>false, + 'source'=>'non-db', + 'table' => 'users', + 'id_name' => 'assigned_user_id', + 'module'=>'Users', + 'duplicate_merge'=>'disabled' + ), + 'assigned_user_link' => + array ( + 'name' => 'assigned_user_link', + 'type' => 'link', + 'relationship' => 'oauthtokens_assigned_user', + 'vname' => 'LBL_ASSIGNED_TO_USER', + 'link_type' => 'one', + 'module'=>'Users', + 'bean_name'=>'User', + 'source'=>'non-db', + 'duplicate_merge'=>'enabled', + 'rname' => 'user_name', + 'id_name' => 'assigned_user_id', + 'table' => 'users', + ), + ), + 'indices' => array ( + 'id'=>array('name' =>'oauthtokenpk', 'type' =>'primary', 'fields'=>array('id', 'deleted')), + 'state_ts'=>array('name' =>"oauth_state_ts", 'type' =>'index', 'fields'=>array('tstate','token_ts')), + 'consumer'=>array('name' =>"constoken_key", 'type' =>'index', 'fields'=>array('consumer')), + ), + 'relationships'=>array( + 'consumer_tokens' => + array('lhs_module'=> 'OAuthKeys', 'lhs_table'=> 'oauth_consumer', 'lhs_key' => 'id', + 'rhs_module'=> 'OAuthTokens', 'rhs_table'=> 'oauth_tokens', 'rhs_key' => 'consumer', + 'relationship_type'=>'one-to-many'), + 'oauthtokens_assigned_user' => + array('lhs_module'=> 'Users', 'lhs_table'=> 'users', 'lhs_key' => 'id', + 'rhs_module'=> 'OAuthTokens' , 'rhs_table'=> 'oauth_tokens', 'rhs_key' => 'assigned_user_id', + 'relationship_type'=>'one-to-many') + ) +); diff --git a/modules/OAuthTokens/views/view.authorize.php b/modules/OAuthTokens/views/view.authorize.php new file mode 100644 index 00000000..39342acb --- /dev/null +++ b/modules/OAuthTokens/views/view.authorize.php @@ -0,0 +1,86 @@ +assign('APP', $GLOBALS['app_strings']); + $sugar_smarty->assign('MOD', $GLOBALS['mod_strings']); + $sugar_smarty->assign('token', $_REQUEST['token']); + $sugar_smarty->assign('sid', session_id()); + + $token = OAuthToken::load($_REQUEST['token']); + if(empty($token) || empty($token->consumer) || $token->tstate != OAuthToken::REQUEST || empty($token->consumer_obj)) { + sugar_die('Invalid token'); + } + + if(empty($_REQUEST['confirm'])) { + $sugar_smarty->assign('consumer', sprintf($GLOBALS['mod_strings']['LBL_OAUTH_CONSUMERREQ'], $token->consumer_obj->name)); +// SM: roles disabled for now +// $roles = array('' => ''); +// $allroles = ACLRole::getAllRoles(); +// foreach($allroles as $role) { +// $roles[$role->id] = $role->name; +// } +// $sugar_smarty->assign('roles', $roles); + $hash = md5(rand()); + $_SESSION['oauth_hash'] = $hash; + $sugar_smarty->assign('hash', $hash); + echo $sugar_smarty->fetch('modules/OAuthTokens/tpl/authorize.tpl'); + } else { + if($_REQUEST['sid'] != session_id() || $_SESSION['oauth_hash'] != $_REQUEST['hash']) { + sugar_die('Invalid request'); + } + $verify = $token->authorize(array("user" => $current_user->id)); + $sugar_smarty->assign('VERIFY', $verify); + $sugar_smarty->assign('token', ''); + echo $sugar_smarty->fetch('modules/OAuthTokens/tpl/authorized.tpl'); + } + } + +} + diff --git a/modules/Opportunities/Menu.php b/modules/Opportunities/Menu.php index dc8f6a74..149b35c6 100644 --- a/modules/Opportunities/Menu.php +++ b/modules/Opportunities/Menu.php @@ -52,7 +52,7 @@ if(ACLController::checkAccess('Opportunities','list',true)){ $module_menu[]= Array("index.php?module=Opportunities&action=index&return_module=Opportunities&return_action=DetailView", $mod_strings['LNK_OPPORTUNITY_LIST'],"Opportunities"); } if(ACLController::checkAccess('Opportunities','import',true)){ - $module_menu[]= Array("index.php?module=Import&action=Step1&import_module=Opportunities&return_module=Opportunities&return_action=index", $mod_strings['LNK_IMPORT_OPPORTUNITIES'],"Import"); + $module_menu[]= Array("index.php?module=Import&action=Step1&import_module=Opportunities&return_module=Opportunities&return_action=index", $mod_strings['LNK_IMPORT_OPPORTUNITIES'],"Import"); } ?> \ No newline at end of file diff --git a/modules/Opportunities/language/en_us.lang.php b/modules/Opportunities/language/en_us.lang.php index 5cbb5337..50a34edf 100644 --- a/modules/Opportunities/language/en_us.lang.php +++ b/modules/Opportunities/language/en_us.lang.php @@ -141,6 +141,17 @@ $mod_strings = array ( 'LBL_PROJECT_SUBPANEL_TITLE' => 'Projects', 'LABEL_PANEL_ASSIGNMENT' => 'Assignment', 'LNK_IMPORT_OPPORTUNITIES' => 'Import Opportunities', + //For export labels + 'LBL_EXPORT_CAMPAIGN_ID' => 'Campaign ID', + 'LBL_OPPORTUNITY_TYPE' => 'Opportunity Type', + 'LBL_EXPORT_ASSIGNED_USER_NAME' => 'Assigned User Name', + 'LBL_EXPORT_ASSIGNED_USER_ID' => 'Assigned User ID', + 'LBL_EXPORT_MODIFIED_USER_ID' => 'Modified By ID', + 'LBL_EXPORT_CREATED_BY' => 'Created By ID', + 'LBL_EXPORT_NAME'=>'Name', + + // SNIP + 'LBL_CONTACT_HISTORY_SUBPANEL_TITLE' => 'Related Contacts\' Emails', ); -?> \ No newline at end of file +?> diff --git a/modules/Opportunities/metadata/subpaneldefs.php b/modules/Opportunities/metadata/subpaneldefs.php index dc3b79bc..367e36c9 100644 --- a/modules/Opportunities/metadata/subpaneldefs.php +++ b/modules/Opportunities/metadata/subpaneldefs.php @@ -127,13 +127,13 @@ $layout_defs['Opportunities'] = array( 'sort_by' => 'id', 'title_key' => 'LBL_DOCUMENTS_SUBPANEL_TITLE', 'get_subpanel_data' => 'documents', - 'top_buttons' => + 'top_buttons' => array ( - 0 => + 0 => array ( 'widget_class' => 'SubPanelTopButtonQuickCreate', ), - 1 => + 1 => array ( 'widget_class' => 'SubPanelTopSelectButton', 'mode' => 'MultiSelect', @@ -190,6 +190,7 @@ $layout_defs['Opportunities'] = array( ), ), + ), ); ?> \ No newline at end of file diff --git a/modules/Opportunities/vardefs.php b/modules/Opportunities/vardefs.php index f525cea4..2157733c 100644 --- a/modules/Opportunities/vardefs.php +++ b/modules/Opportunities/vardefs.php @@ -114,7 +114,7 @@ $dictionary['Opportunity'] = array('table' => 'opportunities','audited'=>true, ' 'id_name'=>'campaign_id', 'vname'=>'LBL_CAMPAIGN', 'type'=>'relate', - 'link' => 'campaign_opportunities', + 'link' => 'campaign_opportunities', 'isnull'=>'true', 'table' => 'campaigns', 'module'=>'Campaigns', @@ -248,7 +248,7 @@ $dictionary['Opportunity'] = array('table' => 'opportunities','audited'=>true, ' 'audited'=>true, 'comment' => 'The probability of closure', 'validation' => array('type' => 'range', 'min' => 0, 'max' => 100), - 'merge_filter' => 'enabled', + 'merge_filter' => 'enabled', ), 'accounts' => array ( @@ -337,7 +337,7 @@ $dictionary['Opportunity'] = array('table' => 'opportunities','audited'=>true, ' 'source'=>'non-db', 'vname'=>'LBL_LEADS', ), - + 'campaigns' => array ( 'name' => 'campaigns', @@ -380,6 +380,11 @@ $dictionary['Opportunity'] = array('table' => 'opportunities','audited'=>true, ' 'type' => 'index', 'fields' => array('assigned_user_id'), ), + array( + 'name' => 'idx_opp_id_deleted', + 'type' => 'index', + 'fields' => array('id','deleted'), + ), ), 'relationships' => array ( @@ -424,7 +429,7 @@ $dictionary['Opportunity'] = array('table' => 'opportunities','audited'=>true, ' 'rhs_module'=> 'Opportunities', 'rhs_table'=> 'opportunities', 'rhs_key' => 'created_by', 'relationship_type'=>'one-to-many'), 'opportunities_campaign' => - array('lhs_module'=> 'campaigns', 'lhs_table'=> 'campaigns', 'lhs_key' => 'id', + array('lhs_module'=> 'Campaigns', 'lhs_table'=> 'campaigns', 'lhs_key' => 'id', 'rhs_module'=> 'Opportunities', 'rhs_table'=> 'opportunities', 'rhs_key' => 'campaign_id', 'relationship_type'=>'one-to-many'), ) @@ -433,4 +438,4 @@ $dictionary['Opportunity'] = array('table' => 'opportunities','audited'=>true, ' ); VardefManager::createVardef('Opportunities','Opportunity', array('default', 'assignable', )); -?> \ No newline at end of file +?> diff --git a/modules/Project/language/en_us.lang.php b/modules/Project/language/en_us.lang.php index d17ebb3a..abe5dc7a 100644 --- a/modules/Project/language/en_us.lang.php +++ b/modules/Project/language/en_us.lang.php @@ -138,6 +138,6 @@ $mod_strings = array ( 'LBL_PROJECTRESOURCES_SUBPANEL_TITLE' => 'Project Resources', 'LBL_PROJECTTASK_SUBPANEL_TITLE' => 'Project Task', 'LBL_HOLIDAYS_SUBPANEL_TITLE' => 'Holidays', - 'LBL_PROJECT_INFORMATION' => 'Project Overview', + 'LBL_PROJECT_INFORMATION' => 'Overview', ); ?> \ No newline at end of file diff --git a/modules/ProjectTask/ProjectTask.php b/modules/ProjectTask/ProjectTask.php index 53a4d3f9..16d5522e 100644 --- a/modules/ProjectTask/ProjectTask.php +++ b/modules/ProjectTask/ProjectTask.php @@ -98,7 +98,7 @@ class ProjectTask extends SugarBean { if ($init) { // default value for a clean instantiation $this->utilization = 100; - + global $current_user; if(empty($current_user)) { @@ -112,16 +112,16 @@ class ProjectTask extends SugarBean { $this->assigned_user_id = $current_user->id; $this->assigned_user_name = $current_user->user_name; } - + } } - + function save($check_notify = FALSE){ $id = parent::save($check_notify); $this->updateParentProjectTaskPercentage(); return $id; } - + /** * overriding the base class function to do a join with users table */ @@ -245,13 +245,13 @@ class ProjectTask extends SugarBean { $today = $timedate->handle_offset(date($GLOBALS['timedate']->get_db_date_time_format(), time()), $timedate->dbDayFormat, true); $task_fields =$this->get_list_view_array(); //$date_due = $timedate->to_db_date($task_fields['DATE_DUE'],false); - if (isset($this->parent_type)) + if (isset($this->parent_type)) $task_fields['PARENT_MODULE'] = $this->parent_type; /* if ($this->status != "Completed" && $this->status != "Deferred" ) { $task_fields['SET_COMPLETE'] = "".SugarThemeRegistry::current()->getImage("close_inline","alt='Close' border='0'").""; } - + if( $date_due < $today){ $task_fields['DATE_DUE']= "".$task_fields['DATE_DUE'].""; }else if( $date_due == $today ){ @@ -273,7 +273,7 @@ class ProjectTask extends SugarBean { return $task_fields; } - + function bean_implements($interface){ switch($interface){ case 'ACL':return true; @@ -284,7 +284,7 @@ class ProjectTask extends SugarBean { $array_assign = parent::listviewACLHelper(); $is_owner = false; if(!empty($this->parent_name)){ - + if(!empty($this->parent_name_owner)){ global $current_user; $is_owner = $current_user->id == $this->parent_name_owner; @@ -297,7 +297,7 @@ class ProjectTask extends SugarBean { } $is_owner = false; if(!empty($this->depends_on_name)){ - + if(!empty($this->depends_on_name_owner)){ global $current_user; $is_owner = $current_user->id == $this->depends_on_name_owner; @@ -308,10 +308,10 @@ class ProjectTask extends SugarBean { }else{ $array_assign['PARENT_TASK'] = 'span'; } - + return $array_assign; } - + function create_export_query(&$order_by, &$where, $relate_link_join='') { $custom_join = $this->custom_fields->getJOIN(true, true,$where); @@ -323,8 +323,8 @@ class ProjectTask extends SugarBean { if($custom_join){ $query .= $custom_join['select']; } - $query .= " FROM project_task "; - + $query .= " FROM project_task LEFT JOIN project ON project_task.project_id=project.id AND project.deleted=0 "; + if($custom_join){ $query .= $custom_join['join']; } @@ -343,17 +343,18 @@ class ProjectTask extends SugarBean { $table_defined_already = strpos($order_by, "."); if($table_defined_already === false){ - //table not defined yet, define accounts to avoid "ambigous column" SQL error + //table not defined yet, define accounts to avoid "ambigous column" SQL error $query .= " ORDER BY $order_by"; }else{ //table already defined, just add it to end of query - $query .= " ORDER BY $order_by"; - } + $query .= " ORDER BY $order_by"; + } } return $query; } + public function updateParentProjectTaskPercentage() { if (empty($this->parent_task_id)) @@ -388,7 +389,7 @@ class ProjectTask extends SugarBean { } function getUtilizationDropdown($focus, $field, $value, $view) { - global $app_list_strings; + global $app_list_strings; if($view == 'EditView') { global $app_list_strings; @@ -397,7 +398,7 @@ function getUtilizationDropdown($focus, $field, $value, $view) { $html .= ''; return $html; } - - return translate('project_task_utilization_options', '', $focus->$field); -} + + return translate('project_task_utilization_options', '', $focus->$field); +} ?> \ No newline at end of file diff --git a/modules/ProspectLists/ProspectList.php b/modules/ProspectLists/ProspectList.php index dc8d87de..78cec665 100644 --- a/modules/ProspectLists/ProspectList.php +++ b/modules/ProspectLists/ProspectList.php @@ -174,11 +174,10 @@ class ProspectList extends SugarBean { l.do_not_call AS do_not_call, l.phone_fax AS phone_fax, l.phone_other AS phone_other, l.phone_home AS phone_home, l.phone_mobile AS phone_mobile, l.phone_work AS phone_work FROM prospect_lists_prospects plp INNER JOIN leads l ON plp.related_id=l.id - LEFT JOIN email_addr_bean_rel ear ON ear.bean_id=l.id + LEFT JOIN email_addr_bean_rel ear ON ear.bean_id=l.id AND ear.deleted=0 LEFT JOIN email_addresses ea ON ear.email_address_id=ea.id WHERE plp.prospect_list_id = $record_id AND plp.deleted=0 - AND l.deleted=0 - AND ear.deleted=0"; + AND l.deleted=0"; $users_query = "SELECT u.id AS id, 'Users' AS related_type, '' AS \"name\", u.first_name AS first_name, u.last_name AS last_name,u.title AS title, '' AS salutation, u.address_street AS primary_address_street,u.address_city AS primary_address_city, u.address_state AS primary_address_state, u.address_postalcode AS primary_address_postalcode, u.address_country AS primary_address_country, @@ -187,11 +186,10 @@ class ProspectList extends SugarBean { 0 AS do_not_call, u.phone_fax AS phone_fax, u.phone_other AS phone_other, u.phone_home AS phone_home, u.phone_mobile AS phone_mobile, u.phone_work AS phone_work FROM prospect_lists_prospects plp INNER JOIN users u ON plp.related_id=u.id - LEFT JOIN email_addr_bean_rel ear ON ear.bean_id=u.id + LEFT JOIN email_addr_bean_rel ear ON ear.bean_id=u.id AND ear.deleted=0 LEFT JOIN email_addresses ea ON ear.email_address_id=ea.id WHERE plp.prospect_list_id = $record_id AND plp.deleted=0 - AND u.deleted=0 - AND ear.deleted=0"; + AND u.deleted=0"; $contacts_query = "SELECT c.id AS id, 'Contacts' AS related_type, '' AS \"name\", c.first_name AS first_name, c.last_name AS last_name,c.title AS title, c.salutation AS salutation, c.primary_address_street AS primary_address_street,c.primary_address_city AS primary_address_city, c.primary_address_state AS primary_address_state, c.primary_address_postalcode AS primary_address_postalcode, c.primary_address_country AS primary_address_country, @@ -200,11 +198,10 @@ class ProspectList extends SugarBean { c.do_not_call AS do_not_call, c.phone_fax AS phone_fax, c.phone_other AS phone_other, c.phone_home AS phone_home, c.phone_mobile AS phone_mobile, c.phone_work AS phone_work FROM prospect_lists_prospects plp INNER JOIN contacts c ON plp.related_id=c.id LEFT JOIN accounts_contacts ac ON ac.contact_id=c.id LEFT JOIN accounts a ON ac.account_id=a.id - LEFT JOIN email_addr_bean_rel ear ON ear.bean_id=c.id + LEFT JOIN email_addr_bean_rel ear ON ear.bean_id=c.id AND ear.deleted=0 LEFT JOIN email_addresses ea ON ear.email_address_id=ea.id WHERE plp.prospect_list_id = $record_id AND plp.deleted=0 - AND c.deleted=0 - AND ear.deleted=0"; + AND c.deleted=0"; $prospects_query = "SELECT p.id AS id, 'Prospects' AS related_type, '' AS \"name\", p.first_name AS first_name, p.last_name AS last_name,p.title AS title, p.salutation AS salutation, p.primary_address_street AS primary_address_street,p.primary_address_city AS primary_address_city, p.primary_address_state AS primary_address_state, p.primary_address_postalcode AS primary_address_postalcode, p.primary_address_country AS primary_address_country, @@ -213,11 +210,10 @@ FROM prospect_lists_prospects plp p.do_not_call AS do_not_call, p.phone_fax AS phone_fax, p.phone_other AS phone_other, p.phone_home AS phone_home, p.phone_mobile AS phone_mobile, p.phone_work AS phone_work FROM prospect_lists_prospects plp INNER JOIN prospects p ON plp.related_id=p.id - LEFT JOIN email_addr_bean_rel ear ON ear.bean_id=p.id + LEFT JOIN email_addr_bean_rel ear ON ear.bean_id=p.id AND ear.deleted=0 LEFT JOIN email_addresses ea ON ear.email_address_id=ea.id WHERE plp.prospect_list_id = $record_id AND plp.deleted=0 - AND p.deleted=0 - AND ear.deleted=0"; + AND p.deleted=0"; $accounts_query = "SELECT a.id AS id, 'Accounts' AS related_type, a.name AS \"name\", '' AS first_name, '' AS last_name,'' AS title, '' AS salutation, a.billing_address_street AS primary_address_street,a.billing_address_city AS primary_address_city, a.billing_address_state AS primary_address_state, a.billing_address_postalcode AS primary_address_postalcode, a.billing_address_country AS primary_address_country, @@ -226,11 +222,10 @@ FROM prospect_lists_prospects plp 0 AS do_not_call, a.phone_fax as phone_fax, a.phone_alternate AS phone_other, '' AS phone_home, '' AS phone_mobile, a.phone_office AS phone_office FROM prospect_lists_prospects plp INNER JOIN accounts a ON plp.related_id=a.id - LEFT JOIN email_addr_bean_rel ear ON ear.bean_id=a.id + LEFT JOIN email_addr_bean_rel ear ON ear.bean_id=a.id AND ear.deleted=0 LEFT JOIN email_addresses ea ON ear.email_address_id=ea.id WHERE plp.prospect_list_id = $record_id AND plp.deleted=0 - AND a.deleted=0 - AND ear.deleted=0"; + AND a.deleted=0"; $order_by = "ORDER BY related_type, id, primary_address DESC"; $query = "$leads_query UNION ALL $users_query UNION ALL $contacts_query UNION ALL $prospects_query UNION ALL $accounts_query $order_by"; return $query; diff --git a/modules/ProspectLists/Save.php b/modules/ProspectLists/Save.php index db398dde..066a29ae 100644 --- a/modules/ProspectLists/Save.php +++ b/modules/ProspectLists/Save.php @@ -91,8 +91,7 @@ if(isset($_POST['return_id']) && $_POST['return_id'] != "") $return_id = $_POST[ if($return_action == "SaveCampaignProspectListRelationshipNew") { $prospect_list_id = $focus->id; - - header("Location: index.php?action=$return_action&module=$return_module&record=$return_id&prospect_list_id=$prospect_list_id"); + handleRedirect($return_id, $return_module, array("prospect_list_id" => $prospect_list_id)); } else { @@ -102,6 +101,7 @@ else $redirect_url .= "&offset=".$_REQUEST['offset']; } $GLOBALS['log']->debug("Saved record with id of ".$return_id); - header($redirect_url); + handleRedirect($return_id, $return_module); + } ?> \ No newline at end of file diff --git a/modules/ProspectLists/vardefs.php b/modules/ProspectLists/vardefs.php index 711f42d5..3619d4af 100644 --- a/modules/ProspectLists/vardefs.php +++ b/modules/ProspectLists/vardefs.php @@ -181,6 +181,12 @@ $dictionary['ProspectList'] = array ( 'relationship' => 'prospect_list_users', 'source'=>'non-db', ), + 'email_marketing'=> array ( + 'name' => 'email_marketing', + 'type' => 'link', + 'relationship' => 'email_marketing_prospect_lists', + 'source'=>'non-db', + ), 'marketing_id' => array ( 'name' => 'marketing_id', 'vname' => 'LBL_MARKETING_ID', diff --git a/modules/Prospects/Menu.php b/modules/Prospects/Menu.php index 0ea3cf23..67aae201 100644 --- a/modules/Prospects/Menu.php +++ b/modules/Prospects/Menu.php @@ -47,4 +47,4 @@ global $mod_strings, $app_strings; if(ACLController::checkAccess('Prospects', 'edit', true))$module_menu[]= Array("index.php?module=Prospects&action=EditView&return_module=Prospects&return_action=DetailView", $mod_strings['LNK_NEW_PROSPECT'],"CreateProspects"); if(ACLController::checkAccess('Prospects', 'list', true))$module_menu[]= Array("index.php?module=Prospects&action=index&return_module=Prospects&return_action=index", $mod_strings['LNK_PROSPECT_LIST'],"Prospects"); -if(ACLController::checkAccess('Prospects', 'import', true))$module_menu[]= Array("index.php?module=Import&action=Step1&import_module=Prospects&return_module=Prospects&return_action=index", $mod_strings['LNK_IMPORT_PROSPECT'],"Import"); \ No newline at end of file +if(ACLController::checkAccess('Prospects', 'import', true))$module_menu[]= Array("index.php?module=Import&action=Step1&import_module=Prospects&return_module=Prospects&return_action=index", $mod_strings['LNK_IMPORT_PROSPECT'],"Import"); \ No newline at end of file diff --git a/modules/Prospects/language/en_us.lang.php b/modules/Prospects/language/en_us.lang.php index b1972bd7..fc208751 100644 --- a/modules/Prospects/language/en_us.lang.php +++ b/modules/Prospects/language/en_us.lang.php @@ -83,7 +83,7 @@ $mod_strings = array ( 'LBL_NAME' => 'Name:', 'LBL_FULL_NAME' => 'Name', 'LBL_PROSPECT_NAME' => 'Target Name:', - 'LBL_PROSPECT_INFORMATION' => 'Target Overview', + 'LBL_PROSPECT_INFORMATION' => 'Overview', 'LBL_MORE_INFORMATION' => 'More Information', 'LBL_FIRST_NAME' => 'First Name:', 'LBL_OFFICE_PHONE' => 'Office Phone:', @@ -183,5 +183,17 @@ $mod_strings = array ( 'LBL_MODIFIED_USER' => 'Modified User', 'LBL_CAMPAIGNS_SUBPANEL_TITLE' => 'Campaigns', 'LBL_HISTORY_SUBPANEL_TITLE'=>'History', + //For export labels + 'LBL_PHONE_HOME' => 'Phone Home', + 'LBL_PHONE_MOBILE' => 'Phone Mobile', + 'LBL_PHONE_WORK' => 'Phone Work', + 'LBL_PHONE_OTHER' => 'Phone Other', + 'LBL_PHONE_FAX' => 'Phone Fax', + 'LBL_CAMPAIGN_ID' => 'Campaign ID', + 'LBL_EXPORT_ASSIGNED_USER_NAME' => 'Assigned User Name', + 'LBL_EXPORT_ASSIGNED_USER_ID' => 'Assigned User ID', + 'LBL_EXPORT_MODIFIED_USER_ID' => 'Modified By ID', + 'LBL_EXPORT_CREATED_BY' => 'Created By ID', + 'LBL_EXPORT_EMAIL2'=>'Other Email Address', ); ?> diff --git a/modules/Prospects/vardefs.php b/modules/Prospects/vardefs.php index b533b421..fca4ea90 100644 --- a/modules/Prospects/vardefs.php +++ b/modules/Prospects/vardefs.php @@ -197,6 +197,9 @@ $dictionary['Prospect'] = array( 'deleted' ) ), + array('name' =>'idx_prospects_id_del', 'type'=>'index', 'fields'=>array('id','deleted')), + array('name' =>'idx_prospects_assigned', 'type'=>'index', 'fields'=>array('assigned_user_id')), + ), 'relationships' => array ( diff --git a/modules/Relationships/Relationship.php b/modules/Relationships/Relationship.php index 8342d10e..10265f66 100644 --- a/modules/Relationships/Relationship.php +++ b/modules/Relationships/Relationship.php @@ -224,24 +224,28 @@ class Relationship extends SugarBean { $handle=sugar_fopen(Relationship::cache_file_dir().'/'.Relationship::cache_file_name_only(),'w'); fwrite($handle,$rel_string); fclose($handle); + require_once("data/Relationships/RelationshipFactory.php"); + SugarRelationshipFactory::deleteCache(); } - function cache_file_dir() { + public static function cache_file_dir() { $file_dir="{$GLOBALS['sugar_config']['cache_dir']}modules/Relationships"; return $file_dir; } - function cache_file_name_only() { + public static function cache_file_name_only() { return 'relationships.cache.php'; } - function delete_cache() { + public static function delete_cache() { $filename=Relationship::cache_file_dir().'/'.Relationship::cache_file_name_only(); if (file_exists($filename)) { unlink($filename); } + require_once("data/Relationships/RelationshipFactory.php"); + SugarRelationshipFactory::deleteCache(); } diff --git a/modules/Relationships/action_view_map.php b/modules/Relationships/action_view_map.php new file mode 100644 index 00000000..a1006722 --- /dev/null +++ b/modules/Relationships/action_view_map.php @@ -0,0 +1,38 @@ + +{{assign var='rowCount' value=0}} +{{foreach name=rowIteration from=$panel key=row item=rowData}} +{counter name="fieldsUsed" start=0 print=false assign="fieldsUsed"} +{capture name="tr" assign="tableRow"} + + + {{if isset($colData.field.customLabel)}} + {{$colData.field.customLabel}} + {{elseif isset($colData.field.label)}} + {capture name="label" assign="label"} + {sugar_translate label='{{$colData.field.label}}' module='{{$module}}'} + {/capture} + {$label|strip_semicolon}: + {{elseif isset($fields[$colData.field.name])}} + {capture name="label" assign="label"} + {sugar_translate label='{{$fields[$colData.field.name].vname}}' module='{{$module}}'} + {/capture} + {$label|strip_semicolon}: + {{/if}} + {{* Show the required symbol if field is required, but override not set. Or show if override is set *}} + {{if ($fields[$colData.field.name].required && (!isset($colData.field.displayParams.required) || $colData.field.displayParams.required)) || + (isset($colData.field.displayParams.required) && $colData.field.displayParams.required)}} + {{$APP.LBL_REQUIRED_SYMBOL}} + {{/if}} + + {{/if}} + {counter name="fieldsUsed"} + + {{if !empty($def.templateMeta.labelsOnTop)}} + {{if isset($colData.field.label)}} + {{if !empty($colData.field.label)}} + {sugar_translate label='{{$colData.field.label}}' module='{{$module}}'}: + {{/if}} + {{elseif isset($fields[$colData.field.name])}} + {sugar_translate label='{{$fields[$colData.field.name].vname}}' module='{{$module}}'}: + {{/if}} + + {{* Show the required symbol if field is required, but override not set. Or show if override is set *}} + {{if ($fields[$colData.field.name].required && (!isset($colData.field.displayParams.required) || $colData.field.displayParams.required)) || + (isset($colData.field.displayParams.required) && $colData.field.displayParams.required)}} + {{$APP.LBL_REQUIRED_SYMBOL}} + {{/if}} + {{if !isset($colData.field.label) || !empty($colData.field.label)}} +
    + {{/if}} + {{/if}} + + + {{if $fields[$colData.field.name] && !empty($colData.field.fields) }} + {{foreach from=$colData.field.fields item=subField}} + {{if $fields[$subField.name]}} + {counter name="panelFieldCount"} + {{sugar_field parentFieldArray='fields' tabindex=$colData.field.tabindex vardef=$fields[$subField.name] displayType='EditView' displayParams=$subField.displayParams formName=$form_name}}  + {{/if}} + {{/foreach}} + {{elseif !empty($colData.field.customCode)}} + {counter name="panelFieldCount"} + {{sugar_evalcolumn var=$colData.field.customCode colData=$colData tabindex=$colData.field.tabindex}} + {{elseif $fields[$colData.field.name]}} + {counter name="panelFieldCount"} + {{$colData.displayParams}} + {{sugar_field parentFieldArray='fields' tabindex=$colData.field.tabindex vardef=$fields[$colData.field.name] displayType='EditView' displayParams=$colData.field.displayParams typeOverride=$colData.field.type formName=$form_name}} + {{/if}} + {{if !empty($colData.field.hideIf)}} + {else} + + {/if} + {{/if}} + + {{/foreach}} + +{/capture} +{if $fieldsUsed > 0 } +{$tableRow} +{/if} +{{/foreach}} + \ No newline at end of file diff --git a/modules/Relationships/views/view.editfields.php b/modules/Relationships/views/view.editfields.php new file mode 100644 index 00000000..ca099979 --- /dev/null +++ b/modules/Relationships/views/view.editfields.php @@ -0,0 +1,84 @@ +rel = $_REQUEST['rel']; + $this->id = $_REQUEST['id']; + $moduleName = $this->module = $_REQUEST['rel_module']; + + global $beanList; + require_once("data/Link.php"); + + $beanName = $beanList [ $moduleName ]; + $link = new Link($this->rel, new $beanName(), array()); + $this->fields = $link->_get_link_table_definition($rel, 'fields'); + } + + function display(){ + + //echo "
    ".print_r($this->fields, true)."
    "; + echo "
    " . + '' . + '' . + '' . + '' . + '' . + '' . + '' . + ""; + $count = 0; + foreach($this->fields as $def) + { + if (!empty($def['relationship_field'])) { + $label = !empty($def['vname']) ? $def['vname'] : $def['name']; + echo "" + . ""; + $count++; + } + } + echo "
    " . translate($label, $this->module) . ":" ; + + if ($count%1) + echo "
    "; + } + +} diff --git a/modules/SavedSearch/SavedSearch.php b/modules/SavedSearch/SavedSearch.php index c9889384..f0298acb 100644 --- a/modules/SavedSearch/SavedSearch.php +++ b/modules/SavedSearch/SavedSearch.php @@ -341,8 +341,9 @@ class SavedSearch extends SugarBean { function handleRedirect($return_module, $search_query, $saved_search_id, $advanced = 'false') { $_SESSION['LastSavedView'][$return_module] = $saved_search_id; $return_action = 'index'; + $ajaxLoad = empty($_REQUEST['ajax_load']) ? "" : "&ajax_load=" . $_REQUEST['ajax_load']; //Reduce the params to avoid the problems caused by URL max length in IE ( the reduced params can be get from saved search according to saved_search_id). - header("Location: index.php?action=$return_action&module=$return_module&saved_search_select={$saved_search_id}{$search_query}&advanced={$advanced}"); + header("Location: index.php?action=$return_action&module=$return_module&saved_search_select={$saved_search_id}{$search_query}&advanced={$advanced}$ajaxLoad"); die(); } diff --git a/modules/SavedSearch/index.php b/modules/SavedSearch/index.php index ba26f06a..040e5126 100644 --- a/modules/SavedSearch/index.php +++ b/modules/SavedSearch/index.php @@ -71,7 +71,8 @@ elseif(!empty($_REQUEST['saved_search_select'])) { // requesting a search here. if($_REQUEST['saved_search_select'] == '_none') { // none selected $_SESSION['LastSavedView'][$_REQUEST['search_module']] = ''; $current_user->setPreference('ListViewDisplayColumns', array(), 0, $_REQUEST['search_module']); - header("Location: index.php?action=index&module={$_REQUEST['search_module']}&searchFormTab={$searchFormTab}&query=true&clear_query=true"); + $ajaxLoad = empty($_REQUEST['ajax_load']) ? "" : "&ajax_load=" . $_REQUEST['ajax_load']; + header("Location: index.php?action=index&module={$_REQUEST['search_module']}&searchFormTab={$searchFormTab}&query=true&clear_query=true$ajaxLoad"); die(); } else { diff --git a/modules/Schedulers/Scheduler.php b/modules/Schedulers/Scheduler.php index 414435bd..195df883 100644 --- a/modules/Schedulers/Scheduler.php +++ b/modules/Schedulers/Scheduler.php @@ -202,10 +202,13 @@ class Scheduler extends SugarBean { $r2 = $this->db->query($q2); if($r2 != null) { $a2 = $this->db->fetchByAssoc($r2); // we only care about the newest + $a2['execute_time'] = $this->db->fromConvert($a2['execute_time'],'datetime'); if($a2 != null) { $GLOBALS['log']->debug("-----> Scheduler found [ {$a['name']} ] 'In Progress' with most recent Execute Time at [ {$a2['execute_time']} GMT-0 ]"); $execTime = TimeDate::getInstance()->fromDB($a2['execute_time'])->ts; + + $GLOBALS['log']->debug("-----> Checking if Scheduler execTime ($execTime) is higher than lowerLimit ($lowerLimit)"); if($execTime > $lowerLimit) { if(($now - $execTime) >= (60 * $this->timeOutMins)) { diff --git a/modules/Schedulers/_AddJobsHere.php b/modules/Schedulers/_AddJobsHere.php index 367f74ae..11ac2279 100644 --- a/modules/Schedulers/_AddJobsHere.php +++ b/modules/Schedulers/_AddJobsHere.php @@ -312,18 +312,48 @@ function pruneDatabase() { if(empty($colName)) { $GLOBALS['log']->fatal('pruneDatabase() could not get the columns for table ('.$table.')'); } + + if(array_search($table.'_cstm', $tables) !== FALSE && array_search('id', $colName) !== FALSE && array_key_exists('id', $aDel)) { + // build custom column names + $rColsCstm = $db->query('SHOW COLUMNS FROM '.$table.'_cstm'); + $colNameCstm = array(); + + while($aColsCstm = $db->fetchByAssoc($rColsCstm)) { + $colNameCstm[] = $aColsCstm['Field']; + } + + $qDelCstm = 'SELECT * FROM '.$table.'_cstm WHERE id_c = "'.$db->quote($aDel['id']).'"'; + $rDelCstm = $db->query($qDelCstm);// OR continue; // continue if no 'deleted' column + + // make a backup INSERT query if we are deleting. + while($aDelCstm = $db->fetchByAssoc($rDelCstm)) { + + $query = 'INSERT INTO '.$table.'_cstm ('; + $values = ''; + + foreach($colNameCstm as $kC => $column) { + $query .= $column.', '; + $values .= '"'.$aDelCstm[$column].'", '; + } + + $query = substr($query, 0, (strlen($query) - 2)); + $values = substr($values, 0, (strlen($values) - 2)); + $query .= ') VALUES ('.str_replace("'", "'", $values).');'; + + $queryString[] = $query; + + if(empty($colNameCstm)) { + $GLOBALS['log']->fatal('pruneDatabase() could not get the columns for table ('.$table.'_cstm)'); + } + } // end aDel while() + + $db->query('DELETE FROM '.$table.'_cstm WHERE id_c = "'.$db->quote($aDel['id']).'"'); + } } // end aDel while() // now do the actual delete $db->query('DELETE FROM '.$table.' WHERE deleted = 1'); } // foreach() tables - // now output file with SQL - if(!function_exists('mkdir_recursive')) { - - } - if(!function_exists('write_array_to_file')) { - - } if(!file_exists($backupDir) || !file_exists($backupDir.'/'.$backupFile)) { // create directory if not existent mkdir_recursive($backupDir, false); @@ -429,4 +459,9 @@ function pollMonitoredInboxesForBouncedCampaignEmails() { if (file_exists('custom/modules/Schedulers/_AddJobsHere.php')) { require('custom/modules/Schedulers/_AddJobsHere.php'); } + +if (file_exists('custom/modules/Schedulers/Ext/ScheduledTasks/scheduledtasks.ext.php')) +{ + require('custom/modules/Schedulers/Ext/ScheduledTasks/scheduledtasks.ext.php'); +} ?> diff --git a/modules/SchedulersJobs/SchedulersJob.php b/modules/SchedulersJobs/SchedulersJob.php index 64083d5b..e238c934 100644 --- a/modules/SchedulersJobs/SchedulersJob.php +++ b/modules/SchedulersJobs/SchedulersJob.php @@ -76,7 +76,7 @@ class SchedulersJob extends SugarBean { if (false === $adminId) {//retrive other admin $adminId = $this->db->getOne( 'SELECT id FROM users WHERE is_admin=1 AND deleted=0 AND status=\'Active\'', - true, + true, 'Error retrieving Admin account info' ); if ($adminId) { @@ -204,13 +204,11 @@ class SchedulersJob extends SugarBean { $trackerManager->pause(); $GLOBALS['log']->debug('----->SchedulersJob updating Job Status and finishing Job execution.'); $this->scheduler->retrieve($this->scheduler->id); - $this->scheduler->last_run = gmdate($GLOBALS['timedate']->get_db_date_time_format()); if($this->scheduler->last_run == gmdate($GLOBALS['timedate']->get_db_date_time_format(), strtotime('Jan 01 2000 00:00:00'))) { $this->scheduler->last_run = $this->handleDateFormat('now'); $GLOBALS['log']->fatal('Scheduler applying bogus date for "Last Run": '.$this->scheduler->last_run); } - $this->scheduler->save(); $trackerManager->unPause(); } diff --git a/modules/SchedulersJobs/vardefs.php b/modules/SchedulersJobs/vardefs.php index 1fa66d18..18ba83e0 100644 --- a/modules/SchedulersJobs/vardefs.php +++ b/modules/SchedulersJobs/vardefs.php @@ -70,8 +70,6 @@ $dictionary['SchedulersJob'] = array('table' => 'schedulers_times', 'name' => 'scheduler_id', 'vname' => 'LBL_SCHEDULER_ID', 'type' => 'id', - 'db_type' => 'varchar', - 'len' => 36, 'required' => true, 'reportable' => false, ), diff --git a/modules/Studio/DropDowns/DropDownHelper.php b/modules/Studio/DropDowns/DropDownHelper.php index bc5dc8e2..28b770b5 100644 --- a/modules/Studio/DropDowns/DropDownHelper.php +++ b/modules/Studio/DropDowns/DropDownHelper.php @@ -112,8 +112,8 @@ class DropDownHelper{ while(isset($params['slot_' . $count])){ $index = $params['slot_' . $count]; - $key = (isset($params['key_' . $index]))?$params['key_' . $index]: 'BLANK'; - $value = (isset($params['value_' . $index]))?$params['value_' . $index]: ''; + $key = (isset($params['key_' . $index]))?to_html(remove_xss(from_html($params['key_' . $index]))): 'BLANK'; + $value = (isset($params['value_' . $index]))?to_html(remove_xss(from_html($params['value_' . $index]))): ''; if($key == 'BLANK'){ $key = ''; diff --git a/modules/Studio/TabGroups/TabGroupHelper.php b/modules/Studio/TabGroups/TabGroupHelper.php index fcc68b3a..de895da0 100644 --- a/modules/Studio/TabGroups/TabGroupHelper.php +++ b/modules/Studio/TabGroups/TabGroupHelper.php @@ -118,7 +118,10 @@ class TabGroupHelper{ $completedIndexes[$index] = true; } + // Force a rebuild of the app language + global $current_user; + include('modules/Administration/RebuildJSLang.php'); sugar_cache_clear('app_strings.'.$grouptab_lang); $newFile = create_custom_directory('include/tabConfig.php'); write_array_to_file("GLOBALS['tabStructure']", $tabGroups, $newFile); diff --git a/modules/Studio/language/en_us.lang.php b/modules/Studio/language/en_us.lang.php index d08e3d9d..43c079bb 100644 --- a/modules/Studio/language/en_us.lang.php +++ b/modules/Studio/language/en_us.lang.php @@ -133,6 +133,7 @@ $mod_strings = array ( //BUTTONS 'LBL_BTN_SAVE'=>'Save', +'LBL_BTN_CANCEL'=>'Cancel', 'LBL_BTN_SAVEPUBLISH'=>'Save & Deploy', 'LBL_BTN_HISTORY'=>'History', 'LBL_BTN_NEXT'=>'Next', @@ -158,7 +159,7 @@ $mod_strings = array ( 'LBL_TAB_GROUP_LANGUAGE_HELP' => 'Select an available language, edit the Group labels and click Save & Deploy to apply the labels in the selected language.', 'LBL_ADD_GROUP'=>'Add Group', 'LBL_NEW_GROUP'=>'New Group', -'LBL_RENAME_TABS'=>'Rename Tabs', +'LBL_RENAME_TABS'=>'Rename Modules', 'LBL_DISPLAY_OTHER_TAB' => 'Display \'Other\' Tab', //LIST VIEW EDITOR @@ -184,6 +185,9 @@ $mod_strings = array ( 'LBL_SP_UPLOADED'=> 'Uploaded', 'ERROR_SP_UPLOADED'=>'Please ensure that you are uploading a css style sheet.', 'LBL_SP_PREVIEW'=>'Here is a preview of what your style sheet will look like', - +'LBL_LANGUAGE_TOOLTIP' => 'Select the language to edit.', +'LBL_SINGULAR' => 'Singular Label', +'LBL_PLURAL' => 'Plural Label', +'LBL_RENAME_MOD_SAVE_HELP' => 'Click Save to apply the changes.' ); ?> diff --git a/modules/Studio/studio.js b/modules/Studio/studio.js index d41414e2..ce40730a 100644 --- a/modules/Studio/studio.js +++ b/modules/Studio/studio.js @@ -69,7 +69,7 @@ var typeIndex=o.responseText.indexOf('[TYPE]');var labelIndex=o.responseText.ind if(!check_form('popup_form'))return;if(isPopup){var callback={success:popupSave,failure:popupSave,argument:''} YAHOO.util.Connect.setForm('popup_form');var cObj=YAHOO.util.Connect.asyncRequest('POST','index.php',callback);studiopopup.destroy();}else{document.popup_form.submit();}} function deleteCustomFieldForm(isPopup){if(confirm("WARNING\nDeleting a custom field will delete all data related to that custom field. \nYou will still need to remove the field from any layouts you have added it to.")){document.popup_form.option.value='DeleteCustomField';document.popup_form.submit();}} -function dropdownChanged(value){if(typeof(app_list_strings[value])=='undefined')return;var select=document.getElementById('default_value').options;select.length=0;var count=0;for(var keyin app_list_strings[value]){select[count]=new Option(app_list_strings[value][key],key);count++;}} +function dropdownChanged(value){if(typeof(app_list_strings[value])=='undefined')return;var select=document.getElementById('default_value').options;select.length=0;var count=0;for(var key in app_list_strings[value]){select[count]=new Option(app_list_strings[value][key],key);count++;}} function customFieldChanged(){} var populateCustomField=function(response){var div=document.getElementById('customfieldbody');if(response.status=0){div.innerHTML='Server Connection Failed';}else{validate['popup_form']=new Array();inputsWithErrors=new Array();div.innerHTML=response.responseText;studiopopup.evalScript(response.responseText);if(studiojs.popupAvailable){var region=YAHOO.util.Dom.getRegion('custom_field_table');studiojs.popup.cfg.setProperty('width',region.right-region.left+30+'px');studiojs.popup.cfg.setProperty('height',region.bottom-region.top+30+'px');studiojs.popup.render(document.body);studiojs.popup.center();studiojs.popup.show();}}};var populateCustomFieldCallback={success:populateCustomField,failure:populateCustomField,argument:1};var COBJ=false;function changeTypeData(type){document.getElementById('customfieldbody').innerHTML='

    Loading...

    ';COBJ=YAHOO.util.Connect.asyncRequest('GET','index.php?module=Studio&popup=true&action=index&&ajax=editcustomfield&to_pdf=true&type='+type,populateCustomFieldCallback,null);} function typeChanged(obj) diff --git a/modules/Studio/wizards/RenameModules.php b/modules/Studio/wizards/RenameModules.php new file mode 100644 index 00000000..ccda237f --- /dev/null +++ b/modules/Studio/wizards/RenameModules.php @@ -0,0 +1,943 @@ + array( + array('name' => 'LBL_CAMPAIGNS', 'type' => 'plural', 'source' => 'Campaigns'), + array('name' => 'LBL_CAMPAIGN_ID', 'type' => 'singular', 'source' => 'Campaigns'), + array('name' => 'LBL_PARENT_ACCOUNT_ID', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_PROSPECT_LIST', 'type' => 'singular', 'source' => 'Prospects'), + ), + 'Bugs' => array( + array('name' => 'LBL_LIST_FORM_TITLE', 'type' => 'singular', 'source' => 'Bugs'), + array('name' => 'LBL_LIST_MY_BUGS', 'type' => 'plural', 'source' => 'Bugs'), + array('name' => 'LBL_SEARCH_FORM_TITLE', 'type' => 'singular', 'source' => 'Bugs'), + array('name' => 'LNK_BUG_LIST', 'type' => 'plural', 'source' => 'Bugs'), + array('name' => 'LNK_BUG_REPORTS', 'type' => 'singular', 'source' => 'Bugs'), + array('name' => 'LNK_IMPORT_BUGS', 'type' => 'plural', 'source' => 'Bugs'), + array('name' => 'LNK_NEW_BUG', 'type' => 'singular', 'source' => 'Bugs'), + ), + 'Calls' => array( + array('name' => 'LBL_LIST_CONTACT', 'type' => 'singular', 'source' => 'Contacts'), + ), + 'Campaigns' => array( + array('name' => 'LBL_ACCOUNTS', 'type' => 'plural', 'source' => 'Accounts'), + array('name' => 'LBL_CONTACTS', 'type' => 'plural', 'source' => 'Contacts'), + array('name' => 'LBL_LIST_CAMPAIGN_NAME', 'type' => 'singular', 'source' => 'Campaigns'), + array('name' => 'LBL_LOG_ENTRIES_CONTACT_TITLE', 'type' => 'plural', 'source' => 'Contacts'), + array('name' => 'LBL_LOG_ENTRIES_LEAD_TITLE', 'type' => 'plural', 'source' => 'Leads'), + array('name' => 'LBL_OPPORTUNITIES', 'type' => 'plural', 'source' => 'Opportunities'), + array('name' => 'LBL_PROSPECT_LIST_SUBPANEL_TITLE', 'type' => 'singular', 'source' => 'Targets'), + ), + 'Cases' => array( + array('name' => 'LBL_BUGS_SUBPANEL_TITLE', 'type' => 'plural', 'source' => 'Bugs'), + array('name' => 'LBL_LIST_ACCOUNT_NAME', 'type' => 'singular', 'source' => 'Accounts'), + ), + 'Contacts' => array( + array('name' => 'LBL_BUGS_SUBPANEL_TITLE', 'type' => 'plural', 'source' => 'Bugs'), + array('name' => 'LBL_CAMPAIGN_LIST_SUBPANEL_TITLE', 'type' => 'plural', 'source' => 'Campaigns'), + array('name' => 'LBL_CONTRACTS', 'type' => 'plural', 'source' => 'Contracts'), + array('name' => 'LBL_LIST_ACCOUNT_NAME', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_LEAD_SOURCE', 'type' => 'singular', 'source' => 'Leads'), + array('name' => 'LBL_OPPORTUNITIES', 'type' => 'singular', 'source' => 'Opportunities'), + array('name' => 'LBL_OPPORTUNITY_ROLE', 'type' => 'singular', 'source' => 'Opportunities'), + array('name' => 'LBL_OPPORTUNITY_ROLE_ID', 'type' => 'singular', 'source' => 'Opportunities'), + array('name' => 'LBL_PRODUCTS_TITLE', 'type' => 'plural', 'source' => 'Products'), + array('name' => 'LBL_PROSPECT_LIST', 'type' => 'singular', 'source' => 'Prospects'), + ), + 'Contracts' => array( + array('name' => 'LBL_CONTRACT_NAME', 'type' => 'singular', 'source' => 'Contracts'), + array('name' => 'LBL_CONTRACT_TERM', 'type' => 'singular', 'source' => 'Contracts'), + array('name' => 'LBL_DOCUMENTS', 'type' => 'plural', 'source' => 'Documents'), + array('name' => 'LBL_LIST_ACCOUNT_NAME', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_LIST_CONTRACT_NAME', 'type' => 'singular', 'source' => 'Contracts'), + array('name' => 'LBL_OPPORTUNITY', 'type' => 'singular', 'source' => 'Opportunities'), + array('name' => 'LBL_SEARCH_FORM_TITLE', 'type' => 'singular', 'source' => 'Contracts'), + array('name' => 'LBL_TOTAL_CONTRACT_VALUE', 'type' => 'singular', 'source' => 'Contracts'), + array('name' => 'LBL_TOTAL_CONTRACT_VALUE_USDOLLAR', 'type' => 'singular', 'source' => 'Contracts'), + array('name' => 'LNK_NEW_CONTRACT', 'type' => 'singular', 'source' => 'Contracts'), + ), + 'Documents' => array( + array('name' => 'LBL_BUGS_SUBPANEL_TITLE', 'type' => 'plural', 'source' => 'Bugs'), + array('name' => 'LBL_CONTRACTS', 'type' => 'plural', 'source' => 'Contracts'), + array('name' => 'LBL_CONTRACT_NAME', 'type' => 'singular', 'source' => 'Contracts'), + array('name' => 'LBL_CONTRACT_STATUS', 'type' => 'singular', 'source' => 'Contracts'), + array('name' => 'LBL_DET_RELATED_DOCUMENT_VERSION', 'type' => 'singular', 'source' => 'Documents'), + array('name' => 'LBL_DET_TEMPLATE_TYPE', 'type' => 'singular', 'source' => 'Documents'), + array('name' => 'LBL_DOC_ID', 'type' => 'singular', 'source' => 'Documents'), + array('name' => 'LBL_DOC_NAME', 'type' => 'singular', 'source' => 'Documents'), + array('name' => 'LBL_DOC_REV_HEADER', 'type' => 'singular', 'source' => 'Documents'), + array('name' => 'LBL_DOC_URL', 'type' => 'singular', 'source' => 'Documents'), + array('name' => 'LBL_NAME', 'type' => 'singular', 'source' => 'Documents'), + array('name' => 'LBL_TEMPLATE_TYPE', 'type' => 'singular', 'source' => 'Documents'), + ), + 'KBDocuments' => array( + array('name' => 'LBL_CASES', 'type' => 'plural', 'source' => 'Cases'), + array('name' => 'LBL_CONTRACTS', 'type' => 'plural', 'source' => 'Contracts'), + array('name' => 'LBL_CONTRACT_NAME', 'type' => 'plural', 'source' => 'Contracts'), + ), + 'Leads' => array( + array('name' => 'LNK_SELECT_###MODULE_PLURAL###', 'type' => 'singular', 'source' => 'Leads'), + array('name' => 'LNK_SELECT_###MODULE_SINGULAR###', 'type' => 'singular', 'source' => 'Leads'), + array('name' => 'LBL_ACCOUNT_DESCRIPTION', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_ACCOUNT_ID', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_ACCOUNT_NAME', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_CAMPAIGN_ID', 'type' => 'singular', 'source' => 'Campaigns'), + array('name' => 'LBL_CAMPAIGN_LEAD', 'type' => 'plural', 'source' => 'Campaigns'), + array('name' => 'LBL_CAMPAIGN_LIST_SUBPANEL_TITLE', 'type' => 'plural', 'source' => 'Campaigns'), + array('name' => 'LBL_CONTACT_ID', 'type' => 'singular', 'source' => 'Contacts'), + array('name' => 'LBL_LEAD_SOURCE', 'type' => 'singular', 'source' => 'Leads'), + array('name' => 'LBL_LEAD_SOURCE_DESCRIPTION', 'type' => 'singular', 'source' => 'Leads'), + array('name' => 'LBL_LIST_ACCOUNT_NAME', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_OPPORTUNITY_AMOUNT', 'type' => 'singular', 'source' => 'Opportunities'), + array('name' => 'LBL_OPPORTUNITY_ID', 'type' => 'singular', 'source' => 'Opportunities'), + array('name' => 'LBL_OPPORTUNITY_NAME', 'type' => 'singular', 'source' => 'Opportunities'), + array('name' => 'LBL_CONVERTED_ACCOUNT', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LNK_SELECT_ACCOUNTS', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LNK_NEW_ACCOUNT', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_CONVERTED_CONTACT', 'type' => 'singular', 'source' => 'Contacts'), + array('name' => 'LBL_CONVERTED_OPP', 'type' => 'singular', 'source' => 'Opportunities'), + + ), + 'Meetings' => array( + array('name' => 'LBL_LIST_CONTACT', 'type' => 'singular', 'source' => 'Contacts'), + array('name' => 'LBL_LIST_JOIN_MEETING', 'type' => 'singular', 'source' => 'Meetings'), + array('name' => 'LBL_PASSWORD', 'type' => 'singular', 'source' => 'Meetings'), + array('name' => 'LBL_TYPE', 'type' => 'singular', 'source' => 'Meetings'), + array('name' => 'LBL_URL', 'type' => 'singular', 'source' => 'Meetings'), + ), + 'Notes' => array( + array('name' => 'LBL_ACCOUNT_ID', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_CASE_ID', 'type' => 'singular', 'source' => 'Cases'), + array('name' => 'LBL_CONTACT_ID', 'type' => 'singular', 'source' => 'Contacts'), + array('name' => 'LBL_LIST_CONTACT', 'type' => 'singular', 'source' => 'Contacts'), + array('name' => 'LBL_LIST_CONTACT_NAME', 'type' => 'singular', 'source' => 'Contacts'), + array('name' => 'LBL_NOTE_STATUS', 'type' => 'singular', 'source' => 'Notes'), + array('name' => 'LBL_OPPORTUNITY_ID', 'type' => 'singular', 'source' => 'Opportunities'), + array('name' => 'LBL_PRODUCT_ID', 'type' => 'singular', 'source' => 'Products'), + array('name' => 'LBL_QUOTE_ID', 'type' => 'singular', 'source' => 'Quotes'), + ), + 'Opportunities' => array( + array('name' => 'LBL_ACCOUNT_ID', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_AMOUNT', 'type' => 'singular', 'source' => 'Opportunities'), + array('name' => 'LBL_CAMPAIGN_OPPORTUNITY', 'type' => 'plural', 'source' => 'Campaigns'), + array('name' => 'LBL_CONTRACTS', 'type' => 'plural', 'source' => 'Contracts'), + array('name' => 'LBL_LEAD_SOURCE', 'type' => 'singular', 'source' => 'Leads'), + array('name' => 'LBL_LIST_ACCOUNT_NAME', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_OPPORTUNITY_NAME', 'type' => 'singular', 'source' => 'Opportunities'), + ), + 'ProductTemplates' => array( + array('name' => 'LBL_PRODUCT_ID', 'type' => 'singular', 'source' => 'Products'), + ), + 'Products' => array( + array('name' => 'LBL_ACCOUNT_ID', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_CONTACT', 'type' => 'singular', 'source' => 'Contacts'), + array('name' => 'LBL_CONTACT_ID', 'type' => 'singular', 'source' => 'Contacts'), + array('name' => 'LBL_CONTRACTS', 'type' => 'plural', 'source' => 'Contacts'), + array('name' => 'LBL_LIST_ACCOUNT_NAME', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_LIST_NAME', 'type' => 'singular', 'source' => 'Products'), + array('name' => 'LBL_NAME', 'type' => 'singular', 'source' => 'Products'), + array('name' => 'LBL_QUOTE_ID', 'type' => 'singular', 'source' => 'Quotes'), + array('name' => 'LBL_RELATED_PRODUCTS', 'type' => 'plural', 'source' => 'Products'), + array('name' => 'LBL_URL', 'type' => 'singular', 'source' => 'Products'), + ), + 'ProjectTask' => array( + array('name' => 'LBL_PARENT_NAME', 'type' => 'singular', 'source' => 'Projects'), + array('name' => 'LBL_PROJECT_ID', 'type' => 'singular', 'source' => 'Projects'), + array('name' => 'LBL_PROJECT_NAME', 'type' => 'singular', 'source' => 'Projects'), + array('name' => 'LBL_PROJECT_TASK_ID', 'type' => 'singular', 'source' => 'Projects'), + ), + 'Project' => array( + array('name' => 'LBL_BUGS_SUBPANEL_TITLE', 'type' => 'plural', 'source' => 'Bugs'), + array('name' => 'LBL_CONTACTS_RESOURCE', 'type' => 'singular', 'source' => 'Contacts'), + array('name' => 'LBL_LIST_FORM_TITLE', 'type' => 'singular', 'source' => 'Projects'), + array('name' => 'LBL_OPPORTUNITIES', 'type' => 'plural', 'source' => 'Opportunities'), + array('name' => 'LBL_PROJECT_HOLIDAYS_TITLE', 'type' => 'singular', 'source' => 'Projects'), + array('name' => 'LBL_PROJECT_TASKS_SUBPANEL_TITLE', 'type' => 'singular', 'source' => 'Projects'), + array('name' => 'LBL_SEARCH_FORM_TITLE', 'type' => 'singular', 'source' => 'Projects'), + array('name' => 'LNK_NEW_PROJECT', 'type' => 'singular', 'source' => 'Projects'), + array('name' => 'LNK_PROJECT_LIST', 'type' => 'singular', 'source' => 'Projects'), + ), + 'Quotes' => array( + array('name' => 'LBL_ACCOUNT_ID', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_CONTRACTS', 'type' => 'plural', 'source' => 'Contracts'), + array('name' => 'LBL_LIST_ACCOUNT_NAME', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_QUOTE_NUM', 'type' => 'singular', 'source' => 'Quotes'), + ), + 'Targets' => array( + array('name' => 'LBL_ACCOUNT_NAME', 'type' => 'singular', 'source' => 'Accounts'), + array('name' => 'LBL_CAMPAIGN_ID', 'type' => 'plural', 'source' => 'Campaigns'), + array('name' => 'LBL_CAMPAIGN_LIST_SUBPANEL_TITLE', 'type' => 'singular', 'source' => 'Campaigns'), + array('name' => 'LBL_PROSPECT_LIST', 'type' => 'singular', 'source' => 'Prospects'), + ), + 'Tasks' => array( + array('name' => 'LBL_CONTACT', 'type' => 'singular', 'source' => 'Contacts'), + array('name' => 'LBL_CONTACT_ID', 'type' => 'singular', 'source' => 'Contacts'), + array('name' => 'LBL_CONTACT_PHONE', 'type' => 'singular', 'source' => 'Contacts'), + ), + ); + + + /** + * + * @param string $options + * @return void + */ + public function process($options = '') + { + if($options == 'SaveDropDown') + $this->save(); + + $this->display(); + + } + + /** + * Main display function. + * + * @return void + */ + protected function display() + { + global $app_list_strings, $mod_strings; + + + require_once('modules/Studio/parsers/StudioParser.php'); + $dh = new DropDownHelper(); + + $smarty = new Sugar_Smarty(); + $smarty->assign('MOD', $GLOBALS['mod_strings']); + $title=getClassicModuleTitle($mod_strings['LBL_MODULE_NAME'], array("".$mod_strings['LBL_MODULE_NAME']."", $mod_strings['LBL_RENAME_TABS']), false); + $smarty->assign('title', $title); + + $selected_lang = (!empty($_REQUEST['dropdown_lang'])?$_REQUEST['dropdown_lang']:$_SESSION['authenticated_user_language']); + if(empty($selected_lang)) + { + $selected_lang = $GLOBALS['sugar_config']['default_language']; + } + + if($selected_lang == $GLOBALS['current_language']) + { + $my_list_strings = $GLOBALS['app_list_strings']; + } + else + { + $my_list_strings = return_app_list_strings_language($selected_lang); + } + + $selected_dropdown = $my_list_strings['moduleList']; + $selected_dropdown_singular = $my_list_strings['moduleListSingular']; + + + foreach($selected_dropdown as $key=>$value) + { + $singularValue = isset($selected_dropdown_singular[$key]) ? $selected_dropdown_singular[$key] : $value; + if($selected_lang != $_SESSION['authenticated_user_language'] && !empty($app_list_strings['moduleList']) && isset($app_list_strings['moduleList'][$key])) + { + $selected_dropdown[$key]=array('lang'=>$value, 'user_lang'=> '['.$app_list_strings['moduleList'][$key] . ']', 'singular' => $singularValue); + } + else + { + $selected_dropdown[$key]=array('lang'=>$value, 'singular' => $singularValue); + } + } + + + $selected_dropdown = $dh->filterDropDown('moduleList', $selected_dropdown); + + $smarty->assign('dropdown', $selected_dropdown); + $smarty->assign('dropdown_languages', get_languages()); + + $buttons = array(); + $buttons[] = array('text'=>$mod_strings['LBL_BTN_UNDO'],'actionScript'=>"onclick='jstransaction.undo()'" ); + $buttons[] = array('text'=>$mod_strings['LBL_BTN_REDO'],'actionScript'=>"onclick='jstransaction.redo()'" ); + $buttons[] = array('text'=>$mod_strings['LBL_BTN_SAVE'],'actionScript'=>"onclick='if(check_form(\"editdropdown\")){document.editdropdown.submit();}'"); + $buttonTxt = StudioParser::buildImageButtons($buttons); + $smarty->assign('buttons', $buttonTxt); + $smarty->assign('dropdown_lang', $selected_lang); + + $editImage = SugarThemeRegistry::current()->getImage( 'edit_inline', ''); + $smarty->assign('editImage',$editImage); + $deleteImage = SugarThemeRegistry::current()->getImage( 'delete_inline', ''); + $smarty->assign('deleteImage',$deleteImage); + $smarty->display("modules/Studio/wizards/RenameModules.tpl"); + } + + /** + * Save function responsible executing all sub-save functions required to rename a module. + * + * @return void + */ + public function save($redirect = TRUE) + { + $this->selectedLanguage = (!empty($_REQUEST['dropdown_lang'])? $_REQUEST['dropdown_lang']:$_SESSION['authenticated_user_language']); + + //Clear all relevant language caches + $this->clearLanguageCaches(); + + //Retrieve changes the user is requesting and store previous values for future use. + $this->changedModules = $this->getChangedModules(); + + //Change module, appStrings, subpanels, and related links. + $this->changeAppStringEntries()->changeAllModuleModStrings()->renameAllRelatedLinks()->renameAllSubpanels()->renameAllDashlets(); + + foreach (self::$labelMap as $module=>$labelsArr) { + $this->renameCertainModuleModStrings($module, $labelsArr); + } + + //Refresh the page again so module tabs are changed as the save process happens after module tabs are already generated. + if($redirect) + SugarApplication::redirect('index.php?action=wizard&module=Studio&wizard=StudioWizard&option=RenameTabs'); + } + + /** + * Rename all subpanels within the application. + * + * + * @return RenameModules + */ + private function renameAllSubpanels() + { + global $beanList; + + foreach($beanList as $moduleName => $beanName) + { + if( class_exists($beanName) ) + { + $this->renameModuleSubpanel($moduleName, $beanName, $this->changedModules); + } + else + { + $GLOBALS['log']->error("Class $beanName does not exist, unable to rename."); + } + } + + return $this; + + } + + /** + * Rename subpanels for a particular module. + * + * @param string $moduleName The name of the module to be renamed + * @param string $beanName The name of the SugarBean to be renamed. + * @return void + */ + private function renameModuleSubpanel($moduleName, $beanName) + { + $GLOBALS['log']->info("About to rename subpanel for module: $moduleName"); + $bean = new $beanName(); + //Get the subpanel def + $subpanelDefs = $this->getSubpanelDefs($bean); + + if( count($subpanelDefs) <= 0) + { + $GLOBALS['log']->debug("Found empty subpanel defs for $moduleName"); + return; + } + + $mod_strings = return_module_language($this->selectedLanguage, $moduleName); + $replacementStrings = array(); + + //Iterate over all subpanel entries and see if we need to make a change. + foreach($subpanelDefs as $subpanelName => $subpanelMetaData) + { + $GLOBALS['log']->debug("Examining subpanel definition for potential rename: $subpanelName "); + //For each subpanel def, check if they are in our changed modules set. + foreach($this->changedModules as $changedModuleName => $renameFields) + { + if( !( isset($subpanelMetaData['type']) && $subpanelMetaData['type'] == 'collection') //Dont bother with collections + && $subpanelMetaData['module'] == $changedModuleName && isset($subpanelMetaData['title_key']) ) + { + $replaceKey = $subpanelMetaData['title_key']; + if( !isset($mod_strings[$replaceKey]) ) + { + $GLOBALS['log']->info("No module string entry defined for: {$mod_strings[$replaceKey]}"); + continue; + } + $oldStringValue = $mod_strings[$replaceKey]; + //At this point we don't know if we should replace the string with the plural or singular version of the new + //strings so we'll try both but with the plural version first since it should be longer than the singular. + // The saved old strings are html decoded, so we need to decode the new string first before str_replace. + $replacedString = str_replace(html_entity_decode_utf8($renameFields['prev_plural'], ENT_QUOTES), $renameFields['plural'], $oldStringValue); + if ($replacedString == $oldStringValue) { + // continue to replace singular only if nothing been replaced yet + $replacedString = str_replace(html_entity_decode_utf8($renameFields['prev_singular'], ENT_QUOTES), $renameFields['singular'], $replacedString); + } + $replacementStrings[$replaceKey] = $replacedString; + } + } + } + + //Now we can write out the replaced language strings for each module + if(count($replacementStrings) > 0) + { + $GLOBALS['log']->debug("Writing out labels for subpanel changes for module $moduleName, labels: " . var_export($replacementStrings,true)); + ParserLabel::addLabels($this->selectedLanguage, $replacementStrings, $moduleName); + $this->renamedModules[$moduleName] = true; + } + } + + /** + * Retrieve the subpanel definitions for a given SugarBean object. Unforunately we can't reuse + * any of the SubPanelDefinion.php functions. + * + * @param SugarBean $bean + * @return array The subpanel definitions. + */ + private function getSubpanelDefs($bean ) + { + + $layout_defs = array(); + + if ( file_exists( 'modules/' . $bean->module_dir . '/metadata/subpaneldefs.php') ) + require('modules/' . $bean->module_dir . '/metadata/subpaneldefs.php'); + + if ( file_exists( 'custom/modules/' . $bean->module_dir . '/Ext/Layoutdefs/layoutdefs.ext.php')) + require('custom/modules/' . $bean->module_dir . '/Ext/Layoutdefs/layoutdefs.ext.php'); + + return isset($layout_defs[$bean->module_dir]['subpanel_setup']) ? $layout_defs[$bean->module_dir]['subpanel_setup'] : $layout_defs; + } + + /** + * Rename all related linked within the application + * + * @return RenameModules + */ + private function renameAllRelatedLinks() + { + global $beanList; + + foreach($beanList as $moduleName => $beanName) + { + if( class_exists($beanName) ) + { + $this->renameModuleRelatedLinks($moduleName, $beanName); + } + else + { + $GLOBALS['log']->fatal("Class $beanName does not exist, unable to rename."); + } + } + + return $this; + } + + /** + * Rename the related links within a module. + * + * @param string $moduleName The module to be renamed + * @param string $moduleClass The class name of the module to be renamed + * @return void + */ + private function renameModuleRelatedLinks($moduleName, $moduleClass) + { + $GLOBALS['log']->info("Begining to renameModuleRelatedLinks for $moduleClass\n"); + $tmp = new $moduleClass; + if( ! method_exists($tmp, 'get_related_fields') ) + { + $GLOBALS['log']->info("Unable to resolve linked fields for module $moduleClass "); + return; + } + + $linkedFields = $tmp->get_related_fields(); + $mod_strings = return_module_language($this->selectedLanguage, $moduleName); + $replacementStrings = array(); + + foreach($linkedFields as $link => $linkEntry) + { + //For each linked field check if the module referenced to is in our changed module list. + foreach($this->changedModules as $changedModuleName => $renameFields) + { + if( isset($linkEntry['module']) && $linkEntry['module'] == $changedModuleName) + { + $GLOBALS['log']->debug("Begining to rename for link field {$link}"); + if( !isset($mod_strings[$linkEntry['vname']]) ) + { + $GLOBALS['log']->debug("No label attribute for link $link, continuing."); + continue; + } + + $replaceKey = $linkEntry['vname']; + $oldStringValue = $mod_strings[$replaceKey]; + //At this point we don't know if we should replace the string with the plural or singular version of the new + //strings so we'll try both but with the plural version first since it should be longer than the singular. + $replacedString = str_replace(html_entity_decode_utf8($renameFields['prev_plural'], ENT_QUOTES), $renameFields['plural'], $oldStringValue); + if ($replacedString == $oldStringValue) { + $replacedString = str_replace(html_entity_decode_utf8($renameFields['prev_singular'], ENT_QUOTES), $renameFields['singular'], $replacedString); + } + $replacementStrings[$replaceKey] = $replacedString; + } + } + } + + //Now we can write out the replaced language strings for each module + if(count($replacementStrings) > 0) + { + $GLOBALS['log']->debug("Writing out labels for link changes for module $moduleName, labels: " . var_export($replacementStrings,true)); + ParserLabel::addLabels($this->selectedLanguage, $replacementStrings, $moduleName); + $this->renamedModules[$moduleName] = true; + } + } + + /** + * Clear all related language cache files. + * + * @return void + */ + private function clearLanguageCaches() + { + //remove the js language files + LanguageManager::removeJSLanguageFiles(); + + //remove lanugage cache files + LanguageManager::clearLanguageCache(); + } + + /** + * Rename all module strings within the application for dashlets. + * + * @return RenameModules + */ + private function renameAllDashlets() + { + //Load the Dashlet metadata so we know what needs to be changed + if(!is_file($GLOBALS['sugar_config']['cache_dir'].'dashlets/dashlets.php')) + { + require_once('include/Dashlets/DashletCacheBuilder.php'); + $dc = new DashletCacheBuilder(); + $dc->buildCache(); + } + require_once($GLOBALS['sugar_config']['cache_dir'].'dashlets/dashlets.php'); + + foreach($this->changedModules as $moduleName => $replacementLabels) + { + $this->changeModuleDashletStrings($moduleName, $replacementLabels, $dashletsFiles); + } + + return $this; + + } + + /* + * Rename the title value for all dashlets associated with a particular module + * + */ + private function changeModuleDashletStrings($moduleName, $replacementLabels, $dashletsFiles) + { + $GLOBALS['log']->debug("Beginning to change module dashlet labels for: $moduleName "); + $replacementStrings = array(); + + foreach($dashletsFiles as $dashletName => $dashletData) + { + if( isset($dashletData['module']) && $dashletData['module'] == $moduleName && file_exists($dashletData['meta']) ) + { + require_once( $dashletData['meta'] ); + $dashletTitle = $dashletMeta[$dashletName]['title']; + $currentModuleStrings = return_module_language($this->selectedLanguage, $moduleName); + $modStringKey = array_search($dashletTitle,$currentModuleStrings); + if($modStringKey !== FALSE) + { + $replacedString = str_replace(html_entity_decode_utf8($replacementLabels['prev_plural'], ENT_QUOTES), $replacementLabels['plural'], $dashletTitle); + if ($replacedString == $dashletTitle) { + $replacedString = str_replace(html_entity_decode_utf8($replacementLabels['prev_singular'], ENT_QUOTES), $replacementLabels['singular'], $replacedString); + } + $replacementStrings[$modStringKey] = $replacedString; + } + } + } + + //Now we can write out the replaced language strings for each module + if(count($replacementStrings) > 0) + { + $GLOBALS['log']->debug("Writing out labels for dashlet changes for module $moduleName, labels: " . var_export($replacementStrings,true)); + ParserLabel::addLabels($this->selectedLanguage, $replacementStrings, $moduleName); + } + } + + + /** + * Rename all module strings within the application. + * + * @return RenameModules + */ + private function changeAllModuleModStrings() + { + foreach($this->changedModules as $moduleName => $replacementLabels) + { + $this->changeModuleModStrings($moduleName, $replacementLabels); + } + + return $this; + } + + /** + * Rename all module strings within the leads module. + * + * @param string $targetModule The name of the module that owns the labels to be changed. + * @param array $labelKeysToReplace The labels to be changed. + * @return RenameModules + */ + private function renameCertainModuleModStrings($targetModule, $labelKeysToReplace) + { + $GLOBALS['log']->debug("Beginning to rename labels for $targetModule module"); + foreach($this->changedModules as $moduleName => $replacementLabels) + { + $this->changeCertainModuleModStrings($moduleName, $replacementLabels, $targetModule, $labelKeysToReplace); + } + + return $this; + } + + /** + * For a particular module, rename any relevant module strings that need to be replaced. + * + * @param string $moduleName The name of the module to be renamed. + * @param $replacementLabels + * @param string $targetModule The name of the module that owns the labels to be changed. + * @param array $labelKeysToReplace The labels to be changed. + * @return void + */ + private function changeCertainModuleModStrings($moduleName, $replacementLabels, $targetModule, $labelKeysToReplace) + { + $GLOBALS['log']->debug("Beginning to change module labels for : $moduleName"); + $currentModuleStrings = return_module_language($this->selectedLanguage, $targetModule); + + $replacedLabels = array(); + foreach($labelKeysToReplace as $entry) + { + if (!isset($entry['source']) || $entry['source'] != $moduleName) { + // skip this entry if the source module does not match the module being renamed + continue; + } + + $formattedLanguageKey = $this->formatModuleLanguageKey($entry['name'], $replacementLabels); + + //If the static of dynamic key exists it should be replaced. + if( isset($currentModuleStrings[$formattedLanguageKey]) ) + { + $oldStringValue = $currentModuleStrings[$formattedLanguageKey]; + $newStringValue = $this->replaceSingleLabel($oldStringValue, $replacementLabels, $entry); + if ($oldStringValue != $newStringValue) { + $replacedLabels[$formattedLanguageKey] = $newStringValue; + } + } + } + + //Save all entries + ParserLabel::addLabels($this->selectedLanguage, $replacedLabels, $targetModule); + $this->renamedModules[$targetModule] = true; + } + + + /** + * For a particular module, rename any relevant module strings that need to be replaced. + * + * @param string $moduleName The name of the module to be renamed. + * @param $replacementLabels + * @return void + */ + private function changeModuleModStrings($moduleName, $replacementLabels) + { + $GLOBALS['log']->info("Begining to change module labels for: $moduleName"); + $currentModuleStrings = return_module_language($this->selectedLanguage, $moduleName); + $labelKeysToReplace = array( + array('name' => 'LNK_NEW_RECORD', 'type' => 'plural'), //Module built modules, Create + array('name' => 'LNK_LIST', 'type' => 'plural'), //Module built modules, View + array('name' => 'LNK_NEW_###MODULE_SINGULAR###', 'type' => 'singular'), + array('name' => 'LNK_###MODULE_SINGULAR###_LIST', 'type' => 'plural'), + array('name' => 'LNK_###MODULE_SINGULAR###_REPORTS', 'type' => 'singular'), + array('name' => 'LNK_IMPORT_VCARD', 'type' => 'singular'), + array('name' => 'LNK_IMPORT_###MODULE_PLURAL###', 'type' => 'plural'), + array('name' => 'MSG_SHOW_DUPLICATES', 'type' => 'singular', 'case' => 'both'), + array('name' => 'LBL_SAVE_###MODULE_SINGULAR###', 'type' => 'singular'), + array('name' => 'LBL_LIST_FORM_TITLE', 'type' => 'singular'), //Popup title + array('name' => 'LBL_SEARCH_FORM_TITLE', 'type' => 'singular'), //Popup title + ); + + $replacedLabels = array(); + foreach($labelKeysToReplace as $entry) + { + $formattedLanguageKey = $this->formatModuleLanguageKey($entry['name'], $replacementLabels); + + //If the static of dynamic key exists it should be replaced. + if( isset($currentModuleStrings[$formattedLanguageKey]) ) + { + $oldStringValue = $currentModuleStrings[$formattedLanguageKey]; + $replacedLabels[$formattedLanguageKey] = $this->replaceSingleLabel($oldStringValue, $replacementLabels, $entry); + if( isset($entry['case']) && $entry['case'] == 'both') + { + $replacedLabels[$formattedLanguageKey] = $this->replaceSingleLabel($replacedLabels[$formattedLanguageKey], $replacementLabels, $entry, 'strtolower'); + } + } + } + + //Save all entries + ParserLabel::addLabels($this->selectedLanguage, $replacedLabels, $moduleName); + $this->renamedModules[$moduleName] = true; + } + + /** + * Format our dynamic keys containing module strings to a valid key depending on the module. + * + * @param string $unformatedKey + * @param string $replacementStrings + * @return string + */ + private function formatModuleLanguageKey($unformatedKey, $replacementStrings) + { + $unformatedKey = str_replace('###MODULE_SINGULAR###', strtoupper($replacementStrings['key_singular']), $unformatedKey); + return str_replace('###MODULE_PLURAL###', strtoupper($replacementStrings['key_plural']), $unformatedKey); + + } + + /** + * Replace a label with a new value based on metadata which specifies the label as either singular or plural. + * + * @param string $oldStringValue + * @param string $replacementLabels + * @param array $replacementMetaData + * @return string + */ + private function replaceSingleLabel($oldStringValue, $replacementLabels, $replacementMetaData, $modifier = '') + { + $replaceKey = 'prev_' . $replacementMetaData['type']; + $search = html_entity_decode_utf8($replacementLabels[$replaceKey], ENT_QUOTES); + $replace = $replacementLabels[$replacementMetaData['type']]; + if( !empty($modifier) ) + { + $search = call_user_func($modifier, $search); + $replace = call_user_func($modifier, $replace); + } + + return str_replace($search, $replace, $oldStringValue); + } + + + /** + * Save changes to the module names to the app string entries for both the moduleList and moduleListSingular entries. + * + * @return RenameModules + */ + private function changeAppStringEntries() + { + $GLOBALS['log']->debug('Begining to save app string entries'); + //Save changes to the moduleList app string entry + DropDownHelper::saveDropDown($_REQUEST); + + //Save changes to the moduleListSingular app string entry + $newParams = array(); + $newParams['dropdown_name'] = 'moduleListSingular'; + $newParams['dropdown_lang'] = isset($_REQUEST['dropdown_lang']) ? $_REQUEST['dropdown_lang'] : ''; + $newParams['use_push'] = true; + DropDownHelper::saveDropDown($this->createModuleListSingularPackage($newParams, $this->changedModules)); + + //Save changes to the parent_type_display app_list_strings entry + global $app_list_strings; + $cur_app_list_strings = $app_list_strings; + foreach ($this->changedModules as $moduleName => $package) { + $found = false; + // only change if it exists + foreach ($cur_app_list_strings['parent_type_display'] as $moduleName2 => $parentDispName) { + if ($moduleName == $moduleName2) { + $found = true; + break; + } + } + if ($found) { + $newParams['dropdown_name'] = 'parent_type_display'; + DropDownHelper::saveDropDown($this->createModuleListSingularPackage($newParams, array($moduleName => $this->changedModules[$moduleName]))); + } + } + return $this; + } + + /** + * Create an array entry that can be passed to the DropDownHelper:saveDropDown function so we can re-utilize + * the save logic. + * + * @param array $params + * @param array $changedModules + * @return + */ + private function createModuleListSingularPackage($params, $changedModules) + { + $count = 0; + foreach($changedModules as $moduleName => $package) + { + $singularString = $package['singular']; + + $params['slot_' . $count] = $count; + $params['key_' . $count] = $moduleName; + $params['value_' . $count] = $singularString; + $params['delete_' . $count] = ''; + + $count++; + } + + return $params; + + } + + /** + * Determine which modules have been updated and return an array with the module name as the key + * and the singular/plural entries as the value. + * + * @return array + */ + private function getChangedModules() + { + $count = 0; + $allModuleEntries = array(); + $results = array(); + $params = $_REQUEST; + + $selected_lang = (!empty($params['dropdown_lang'])?$params['dropdown_lang']:$_SESSION['authenticated_user_language']); + $current_app_list_string = return_app_list_strings_language($selected_lang); + + while(isset($params['slot_' . $count])) + { + $index = $params['slot_' . $count]; + $key = (isset($params['key_' . $index]))?to_html(remove_xss(from_html($params['key_' . $index]))): 'BLANK'; + $value = (isset($params['value_' . $index]))?to_html(remove_xss(from_html($params['value_' . $index]))): ''; + $svalue = (isset($params['svalue_' . $index]))?to_html(remove_xss(from_html($params['svalue_' . $index]))): $value; + if($key == 'BLANK') + $key = ''; + + $key = trim($key); + $value = trim($value); + $svalue = trim($svalue); + + //If the module key dne then do not continue with this rename. + if( isset($current_app_list_string['moduleList'][$key]) ) + $allModuleEntries[$key] = array('s' => $svalue, 'p' => $value); + else + $_REQUEST['delete_' . $count] = TRUE; + + + $count++; + } + + + foreach($allModuleEntries as $k => $e) + { + $svalue = $e['s']; + $pvalue = $e['p']; + $prev_plural = $current_app_list_string['moduleList'][$k]; + $prev_singular = isset($current_app_list_string['moduleListSingular'][$k]) ? $current_app_list_string['moduleListSingular'][$k] : $prev_plural; + if( strcmp($prev_plural, $pvalue) != 0 || (strcmp($prev_singular, $svalue) != 0) ) + { + $results[$k] = array('singular' => $svalue, 'plural' => $pvalue, 'prev_singular' => $prev_singular, 'prev_plural' => $prev_plural, + 'key_plural' => $k, 'key_singular' => $this->getModuleSingularKey($k) + ); + } + + } + + return $results; + } + + + /** + * Return the 'singular' name of a module (Eg. Opportunity for Opportunities) given a moduleName which is a key + * in the app string moduleList array. If no entry is found, simply return the moduleName as this is consistant with modules + * built by moduleBuilder. + * + * @param string $moduleName + * @return string The 'singular' name of a module. + */ + private function getModuleSingularKey($moduleName) + { + $className = isset($GLOBALS['beanList'][$moduleName]) ? $GLOBALS['beanList'][$moduleName] : null; + if( is_null($className) || ! class_exists($className) ) + { + $GLOBALS['log']->error("Unable to get module singular key for class: $className"); + return $moduleName; + } + + $tmp = new $className(); + if( property_exists($tmp, 'object_name') ) + return $tmp->object_name; + else + return $moduleName; + } + + /** + * Return an array of the modules whos mod_strings have been modified. + * + * @return array + */ + public function getRenamedModules() + { + return $this->renamedModules; + } +} + + + diff --git a/modules/Studio/wizards/RenameModules.tpl b/modules/Studio/wizards/RenameModules.tpl new file mode 100644 index 00000000..994fa4d9 --- /dev/null +++ b/modules/Studio/wizards/RenameModules.tpl @@ -0,0 +1,258 @@ +{* + +/********************************************************************************* + * SugarCRM Community Edition is a customer relationship management program developed by + * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc. + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU Affero General Public License version 3 as published by the + * Free Software Foundation with the addition of the following permission added + * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK + * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY + * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License along with + * this program; if not, see http://www.gnu.org/licenses or write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, + * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU Affero General Public License version 3. + * + * In accordance with Section 7(b) of the GNU Affero General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * SugarCRM" logo. If the display of the logo is not reasonably feasible for + * technical reasons, the Appropriate Legal Notices must display the words + * "Powered by SugarCRM". + ********************************************************************************/ + + + + +*} + + +{literal} + +{/literal} + + + + +
    + {$title} + + + + + + + + +
    {$MOD.LBL_RENAME_MOD_SAVE_HELP}
     
    + + +
    +
     
    + + + + + +
    + {$error} + + + + +
    +
    + + + + + + {$MOD.LBL_TABGROUP_LANGUAGE}   + {html_options name='dropdown_lang' options=$dropdown_languages selected=$dropdown_lang onchange="document.dropdownsform.submit();"} + {sugar_help text=$MOD.LBL_LANGUAGE_TOOLTIP} +
    +
    +
    +
    + + + + + + + + + +{counter start=0 name="rowCounter" print=false assign="rowCounter"} +{foreach from=$dropdown item="value" key="key"} + + + +{counter name="rowCounter"} +{/foreach} + +
    + + {$editImage} +   + {$value.lang} + + +
    +
    + +{literal} + + + +{/literal} + + + + + + +
    \ No newline at end of file diff --git a/modules/Studio/wizards/StudioWizard.php b/modules/Studio/wizards/StudioWizard.php index 9a295923..2fefff60 100644 --- a/modules/Studio/wizards/StudioWizard.php +++ b/modules/Studio/wizards/StudioWizard.php @@ -80,10 +80,9 @@ class StudioWizard{ $newWiz->display(); break; case 'RenameTabs': - $_REQUEST['dropdown_name'] = 'moduleList'; - require_once('modules/Studio/wizards/EditDropDownWizard.php'); - $newWiz = new EditDropDownWizard(); - $newWiz->process('EditDropdown'); + require_once('modules/Studio/wizards/RenameModules.php'); + $newWiz = new RenameModules(); + $newWiz->process(); break; case 'ConfigureTabs': header('Location: index.php?module=Administration&action=ConfigureTabs'); diff --git a/modules/SugarFeed/Dashlets/SugarFeedDashlet/Options.tpl b/modules/SugarFeed/Dashlets/SugarFeedDashlet/Options.tpl index a61d314c..b53e8175 100644 --- a/modules/SugarFeed/Dashlets/SugarFeedDashlet/Options.tpl +++ b/modules/SugarFeed/Dashlets/SugarFeedDashlet/Options.tpl @@ -90,6 +90,7 @@ + @@ -155,7 +156,7 @@ function promptAuthentication() categoryElement = YAHOO.util.Dom.get('categories_{$id}'); {literal} //Only check for prompt warning if the 'ALL' option was selected - if(categoryElement.options[categoryElement.selectedIndex].value != 'ALL') + if(categoryElement.selectedIndex != -1 && categoryElement.options[categoryElement.selectedIndex].value != 'ALL') { return; } diff --git a/modules/SugarFeed/Dashlets/SugarFeedDashlet/SugarFeedDashlet.php b/modules/SugarFeed/Dashlets/SugarFeedDashlet/SugarFeedDashlet.php index ae27b789..ac6f8efe 100644 --- a/modules/SugarFeed/Dashlets/SugarFeedDashlet/SugarFeedDashlet.php +++ b/modules/SugarFeed/Dashlets/SugarFeedDashlet/SugarFeedDashlet.php @@ -214,7 +214,7 @@ var $selectedCategories = array(); 'description', 'date_entered', 'created_by', - + 'related_module', 'link_url', 'link_type')); @@ -222,6 +222,19 @@ var $selectedCategories = array(); $this->lvs->data['data'][$row]['NAME'] = str_replace("{this.CREATED_BY}",get_assigned_user_name($this->lvs->data['data'][$row]['CREATED_BY']),$data['NAME']); + //Translate the SugarFeeds labels if necessary. + preg_match('/\{([^\^ }]+)\.([^\}]+)\}/', $this->lvs->data['data'][$row]['NAME'] ,$modStringMatches ); + if(count($modStringMatches) == 3 && $modStringMatches[1] == 'SugarFeed' && !empty($data['RELATED_MODULE']) ) + { + $modKey = $modStringMatches[2]; + $modString = translate($modKey, $modStringMatches[1]); + if( strpos($modString, '{0}') === FALSE || !isset($GLOBALS['app_list_strings']['moduleListSingular'][$data['RELATED_MODULE']]) ) + continue; + + $modStringSingular = $GLOBALS['app_list_strings']['moduleListSingular'][$data['RELATED_MODULE']]; + $modString = string_format($modString, array($modStringSingular) ); + $this->lvs->data['data'][$row]['NAME'] = preg_replace('/' . $modStringMatches[0] . '/', strtolower($modString), $this->lvs->data['data'][$row]['NAME']); + } } // assign a baseURL w/ the action set as DisplayDashlet @@ -330,6 +343,7 @@ var $selectedCategories = array(); $ss->assign('autenticationPendingLBL', translate('LBL_AUTHENTICATION_PENDING', 'SugarFeed')); $ss->assign('rowsLBL', translate('LBL_ROWS', 'SugarFeed')); $ss->assign('saveLBL', $app_strings['LBL_SAVE_BUTTON_LABEL']); + $ss->assign('clearLBL', $app_strings['LBL_CLEAR_BUTTON_LABEL']); $ss->assign('title', $this->title); $ss->assign('categories', $this->categories); if ( empty($this->selectedCategories) ) { diff --git a/modules/SugarFeed/language/en_us.lang.php b/modules/SugarFeed/language/en_us.lang.php index ab9ff04b..4038e11b 100644 --- a/modules/SugarFeed/language/en_us.lang.php +++ b/modules/SugarFeed/language/en_us.lang.php @@ -93,14 +93,14 @@ $mod_strings = array ( 'LBL_TIME_SECOND' =>'Second', 'LBL_TIME_AGO' =>'ago', - 'CREATED_CONTACT'=>'created a NEW contact', - 'CREATED_OPPORTUNITY'=>'created a NEW opportunity', - 'CREATED_CASE'=>'created a NEW case', - 'CREATED_LEAD'=>'created a NEW lead', + 'CREATED_CONTACT'=>'created a NEW {0}', + 'CREATED_OPPORTUNITY'=>'created a NEW {0}', + 'CREATED_CASE'=>'created a NEW {0}', + 'CREATED_LEAD'=>'created a NEW {0}', 'FOR'=>'for', - 'CLOSED_CASE'=>'CLOSED a case ', - 'CONVERTED_LEAD'=>'CONVERTED a lead', - 'WON_OPPORTUNITY'=>'has WON an opportunity', + 'CLOSED_CASE'=>'CLOSED a {0} ', + 'CONVERTED_LEAD'=>'CONVERTED a {0}', + 'WON_OPPORTUNITY'=>'has WON an {0}', 'WITH' => 'with', 'LBL_LINK_TYPE_Link' => 'Link', diff --git a/modules/TableDictionary.php b/modules/TableDictionary.php index f7d46a09..fb50f72c 100644 --- a/modules/TableDictionary.php +++ b/modules/TableDictionary.php @@ -93,8 +93,9 @@ include("metadata/documents_contactsMetaData.php"); include("metadata/documents_opportunitiesMetaData.php"); include("metadata/documents_casesMetaData.php"); include("metadata/documents_bugsMetaData.php"); +include("metadata/oauth_nonce.php"); if(file_exists('custom/application/Ext/TableDictionary/tabledictionary.ext.php')){ - include('custom/application/Ext/TableDictionary/tabledictionary.ext.php'); + include('custom/application/Ext/TableDictionary/tabledictionary.ext.php'); } ?> diff --git a/modules/Tasks/Task.php b/modules/Tasks/Task.php index 963f720d..d022ca77 100644 --- a/modules/Tasks/Task.php +++ b/modules/Tasks/Task.php @@ -122,7 +122,7 @@ class Task extends SugarBean { $contact_required = stristr($where,"contacts"); if($contact_required) { - $query = "SELECT tasks.*, contacts.first_name, contacts.last_name"; + $query = "SELECT tasks.*, contacts.first_name, contacts.last_name, users.user_name as assigned_user_name "; if($custom_join){ $query .= $custom_join['select']; } @@ -131,7 +131,7 @@ class Task extends SugarBean { } else { - $query = 'SELECT tasks.*'; + $query = 'SELECT tasks.*, users.user_name as assigned_user_name '; if($custom_join){ $query .= $custom_join['select']; } @@ -143,6 +143,7 @@ class Task extends SugarBean { if($custom_join){ $query .= $custom_join['join']; } + $query .= " LEFT JOIN users ON tasks.assigned_user_id=users.id "; if($where != "") $query .= "where $where AND ".$where_auto; @@ -336,7 +337,8 @@ class Task extends SugarBean { $xtpl->assign("TASK_SUBJECT", $task->name); //MFH #13507 $xtpl->assign("TASK_PRIORITY", (isset($task->priority)?$app_list_strings['task_priority_dom'][$task->priority]:"")); - $xtpl->assign("TASK_DUEDATE", $timedate->to_display_date_time($task->date_due . " " . $task->time_due,true,true,$notifyUser)." ".$prefDate['userGmt']); + $userGMT = !empty($prefDate['userGmt']) ? $prefDate['userGmt'] : ''; + $xtpl->assign("TASK_DUEDATE", $timedate->to_display_date_time($task->date_due . " " . $task->time_due,true,true,$notifyUser)." ".$userGMT); $xtpl->assign("TASK_STATUS", (isset($task->status)?$app_list_strings['task_status_dom'][$task->status]:"")); $xtpl->assign("TASK_DESCRIPTION", $task->description); diff --git a/modules/Tasks/language/en_us.lang.php b/modules/Tasks/language/en_us.lang.php index b548c670..cc36d3b1 100644 --- a/modules/Tasks/language/en_us.lang.php +++ b/modules/Tasks/language/en_us.lang.php @@ -106,6 +106,14 @@ $mod_strings = array ( 'LBL_ACTIVITIES_REPORTS' => 'Activities Report', 'LBL_TASK_INFORMATION' => 'Task Overview', 'LBL_HISTORY_SUBPANEL_TITLE' => 'Notes', + //For export labels + 'LBL_DATE_DUE' => 'Date Due', + 'LBL_EXPORT_ASSIGNED_USER_NAME' => 'Assigned User Name', + 'LBL_EXPORT_ASSIGNED_USER_ID' => 'Assigned User ID', + 'LBL_EXPORT_MODIFIED_USER_ID' => 'Modified By ID', + 'LBL_EXPORT_CREATED_BY' => 'Created By ID', + 'LBL_EXPORT_PARENT_TYPE' => 'Related To Module', + 'LBL_EXPORT_PARENT_ID' => 'Related To ID', ); diff --git a/modules/Tasks/metadata/editviewdefs.php b/modules/Tasks/metadata/editviewdefs.php index 0bd578c4..aafc0ed1 100644 --- a/modules/Tasks/metadata/editviewdefs.php +++ b/modules/Tasks/metadata/editviewdefs.php @@ -52,7 +52,7 @@ array ( 'CANCEL', array ( - 'customCode' => '{if $fields.status.value != "Completed"}{/if}', + 'customCode' => '{if $fields.status.value != "Completed"}{/if}', ), ), ), diff --git a/modules/Tasks/vardefs.php b/modules/Tasks/vardefs.php index f4301d7d..2e4539a2 100644 --- a/modules/Tasks/vardefs.php +++ b/modules/Tasks/vardefs.php @@ -313,6 +313,7 @@ $dictionary['Task'] = array('table' => 'tasks', array('name' =>'idx_task_con_del', 'type'=>'index', 'fields'=>array('contact_id','deleted')), array('name' =>'idx_task_par_del', 'type'=>'index', 'fields'=>array('parent_id','parent_type','deleted')), array('name' =>'idx_task_assigned', 'type'=>'index', 'fields'=>array('assigned_user_id')), + array('name' =>'idx_task_status', 'type'=>'index', 'fields'=>array('status')), ) //This enables optimistic locking for Saves From EditView diff --git a/modules/UpgradeWizard/commit.php b/modules/UpgradeWizard/commit.php index 028a7124..8c5c7441 100644 --- a/modules/UpgradeWizard/commit.php +++ b/modules/UpgradeWizard/commit.php @@ -279,8 +279,12 @@ $uwMain = $upgrade_directories_not_found; } } - //COPY ALL FILES FROM UPLOADED UPGRADE PACKAGE + //Bug #47110 + if(file_exists("include/Expressions/Actions/SetValueAction.php")){ + require_once("include/Expressions/Actions/SetValueAction.php"); + } + //COPY ALL FILES FROM UPLOADED UPGRADE PACKAGE if(!didThisStepRunBefore('commit','commitCopyNewFiles')){ set_upgrade_progress('commit','in_progress','commitCopyNewFiles','in_progress'); $split = commitCopyNewFiles($unzip_dir, $zip_from_dir); @@ -385,7 +389,7 @@ if($_SESSION['current_db_version'] == $_SESSION['target_db_version']){ } } } - + } logThis('finished check to see if current_db_version in $_SESSION equals target_db_version in $_SESSION'); @@ -655,14 +659,29 @@ $stepRecheck = $_REQUEST['step']; $_SESSION['step'][$steps['files'][$_REQUEST['step']]] =($stop) ? 'failed' : 'success'; -// clear out the theme cache // clear out the theme cache if(!class_exists('SugarThemeRegistry')){ require_once('include/SugarTheme/SugarTheme.php'); } + +$themeObject = SugarThemeRegistry::current(); + +$styleJSFilePath = $GLOBALS['sugar_config']['cache_dir']. $themeObject->getJSPath() . DIRECTORY_SEPARATOR . 'style-min.js'; +if( file_exists($styleJSFilePath) ) +{ + logThis("Rebuilding style js file: $styleJSFilePath"); + unlink($styleJSFilePath); + SugarThemeRegistry::current()->clearJSCache(); + SugarThemeRegistry::current()->getJS(); +} SugarThemeRegistry::buildRegistry(); SugarThemeRegistry::clearAllCaches(); +//Clean out the language files +logThis("Rebuilding language cache"); +sugar_cache_reset_full(); +LanguageManager::clearLanguageCache(); + // re-minify the JS source files $_REQUEST['root_directory'] = getcwd(); $_REQUEST['js_rebuild_concat'] = 'rebuild'; diff --git a/modules/UpgradeWizard/end.php b/modules/UpgradeWizard/end.php index df458133..c23adc62 100644 --- a/modules/UpgradeWizard/end.php +++ b/modules/UpgradeWizard/end.php @@ -133,6 +133,10 @@ if(!isset($sugar_config['logger'])){ ), ); } +//for upgraded version, set default lead conversion activity option to 'copy' +if(!isset($sugar_config['lead_conv_activity_opt'])) { + $sugar_config['lead_conv_activity_opt'] = 'copy'; +} if(!rebuildConfigFile($sugar_config, $sugar_version)) { logThis('*** WARNING: could not write config.php!', $path); @@ -257,6 +261,9 @@ resetUwSession(); // flag to say upgrade has completed $_SESSION['upgrade_complete'] = true; +//Clear any third party caches +sugar_cache_reset_full(); + //add the clean vardefs here if(!class_exists('VardefManager')){ diff --git a/modules/UpgradeWizard/silentUpgrade_step1.php b/modules/UpgradeWizard/silentUpgrade_step1.php index 68061f38..ff83c957 100644 --- a/modules/UpgradeWizard/silentUpgrade_step1.php +++ b/modules/UpgradeWizard/silentUpgrade_step1.php @@ -118,6 +118,20 @@ function checkLoggerSettings(){ } } +function checkLeadConversionSettings() { + if (file_exists(getcwd().'/config.php')) { + require(getcwd().'/config.php'); + } + global $sugar_config; + if (!isset($sugar_config['lead_conv_activity_opt'])) { + $sugar_config['lead_conv_activity_opt'] = 'copy'; + ksort($sugar_config); + if (is_writable('config.php') && write_array_to_file("sugar_config", $sugar_config,'config.php')) { + //writing to the file + } + } +} + function checkResourceSettings(){ if(file_exists(getcwd().'/config.php')){ require(getcwd().'/config.php'); @@ -791,6 +805,11 @@ if(!didThisStepRunBefore('commit')){ set_upgrade_progress('commit','in_progress','commitMakeBackupFiles','done'); } + //Need to make sure we have the matching copy of SetValueAction for static/instance method matching + if(file_exists("include/Expressions/Actions/SetValueAction.php")){ + require_once("include/Expressions/Actions/SetValueAction.php"); + } + /////////////////////////////////////////////////////////////////////////////// //// HANDLE PREINSTALL SCRIPTS if(empty($errors)) { @@ -907,6 +926,10 @@ if(!didThisStepRunBefore('commit')){ checkLoggerSettings(); logThis('begin check logger settings .', $path); + logThis('begin check lead conversion settings .', $path); + checkLeadConversionSettings(); + logThis('end check lead conversion settings .', $path); + logThis('begin check resource settings .', $path); checkResourceSettings(); logThis('begin check resource settings .', $path); diff --git a/modules/UpgradeWizard/silentUpgrade_step2.php b/modules/UpgradeWizard/silentUpgrade_step2.php index 6d4a3f04..208534da 100644 --- a/modules/UpgradeWizard/silentUpgrade_step2.php +++ b/modules/UpgradeWizard/silentUpgrade_step2.php @@ -330,6 +330,10 @@ copy($argv[1], $install_file); //// END UPGRADE PREP /////////////////////////////////////////////////////////////////////////////// +if(function_exists('repairTableDictionaryExtFile')) +{ + repairTableDictionaryExtFile(); +} if(function_exists('set_upgrade_vars')){ set_upgrade_vars(); diff --git a/modules/UpgradeWizard/uw_utils.php b/modules/UpgradeWizard/uw_utils.php index 4321676e..722c5072 100644 --- a/modules/UpgradeWizard/uw_utils.php +++ b/modules/UpgradeWizard/uw_utils.php @@ -5272,12 +5272,12 @@ if (!function_exists("getValidDBName")) if ($ensureUnique) { $md5str = md5($name); - $tail = substr ( $name, -8) ; + $tail = substr ( $name, -11) ; $temp = substr($md5str , strlen($md5str)-4 ); - $result = substr ( $name, 0, 7) . $temp . $tail ; + $result = substr ( $name, 0, 10) . $temp . $tail ; }else if ($len > ($maxLen - 5)) { - $result = substr ( $name, 0, 8) . substr ( $name, 8 - $maxLen + 5); + $result = substr ( $name, 0, 11) . substr ( $name, 11 - $maxLen + 5); } return strtolower ( $result ) ; } diff --git a/modules/Users/Changenewpassword.php b/modules/Users/Changenewpassword.php index dd9c5e27..3d2d06b9 100644 --- a/modules/Users/Changenewpassword.php +++ b/modules/Users/Changenewpassword.php @@ -112,7 +112,7 @@ if (isset($_REQUEST['guid'])) if($pwd_settings['linkexpiration']){ $delay=$pwd_settings['linkexpirationtime']*$pwd_settings['linkexpirationtype']; $stim = strtotime($row['date_generated']); - $expiretime = TimeDate::getInstance()->fromTimestamp($stim)->get("+"+$delay+" minutes")->asDb(); + $expiretime = TimeDate::getInstance()->fromTimestamp($stim)->get("+$delay minutes")->asDb(); $timenow = TimeDate::getInstance()->nowDb(); if ($timenow > $expiretime) $expired='1'; diff --git a/modules/Users/DetailView.php b/modules/Users/DetailView.php index 21badf34..925367e7 100644 --- a/modules/Users/DetailView.php +++ b/modules/Users/DetailView.php @@ -46,6 +46,9 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); require_once('include/DetailView/DetailView.php'); require_once('include/export_utils.php'); +require_once('include/SugarOAuthServer.php'); +require_once('include/SubPanel/SubPanelTiles.php'); + global $current_user; global $theme; global $app_strings; @@ -88,7 +91,7 @@ if(isset($_REQUEST['reset_homepage'])){ $params = array(); $params[] = $locale->getLocaleFormattedName($focus->first_name,$focus->last_name); -$index_url = ($is_current_admin) ? "index.php?module=Users&action=index" : "index.php?module=Users&action=DetailView&record={$focus->id}"; +$index_url = ($is_current_admin) ? "index.php?module=Users&action=index" : "index.php?module=Users&action=DetailView&record={$focus->id}"; echo getClassicModuleTitle("Users", $params, true,$index_url); @@ -127,13 +130,13 @@ if (isset($sugar_config['show_download_tab'])) { $enable_download_tab = $sugar_config['show_download_tab']; }else{ - + $enable_download_tab = true; -} +} $sugar_smarty->assign('SHOW_DOWNLOADS_TAB', $enable_download_tab); - - + + @@ -471,6 +474,10 @@ $sugar_smarty->display('modules/Users/DetailView.tpl'); if($show_roles){ echo "
    "; require_once('modules/ACLRoles/DetailUserRole.php'); + if(SugarOAuthServer::enabled()) { + $subpanel = new SubPanelTiles($focus, 'UserOAuth'); + echo $subpanel->display(true,true); + } echo "
    "; } diff --git a/modules/Users/DetailView.tpl b/modules/Users/DetailView.tpl index 015b2ee3..0d2e55e9 100644 --- a/modules/Users/DetailView.tpl +++ b/modules/Users/DetailView.tpl @@ -56,7 +56,7 @@ var user_detailview_tabs = new YAHOO.widget.TabView("user_detailview_tabs"); user_detailview_tabs.on('contentReady', function(e){ {/literal} }); - + @@ -95,7 +95,7 @@ user_detailview_tabs.on('contentReady', function(e){ {if $SHOW_ROLES}
  • {$MOD.LBL_USER_ACCESS}
  • {/if} - +
    @@ -112,7 +112,7 @@ user_detailview_tabs.on('contentReady', function(e){
    {$USER_TYPE_LABEL} 
    - +
    @@ -143,7 +143,7 @@ user_detailview_tabs.on('contentReady', function(e){ - + @@ -172,7 +172,7 @@ user_detailview_tabs.on('contentReady', function(e){
    {$MOD.LBL_FAX}: {$PHONE_FAX} 
    {$MOD.LBL_HOME_PHONE}: {$PHONE_HOME}    
    - +
    @@ -232,7 +232,7 @@ user_detailview_tabs.on('contentReady', function(e){ - + @@ -262,7 +262,7 @@ user_detailview_tabs.on('contentReady', function(e){ {$EXTERNAL_AUTH}
    {$MOD.LBL_REMINDER}:  {$REMINDER_TIME} {$MOD.LBL_REMINDER_TEXT} 
    {$MOD.LBL_MAILMERGE}:
    - +
    @@ -310,8 +310,8 @@ user_detailview_tabs.on('contentReady', function(e){
    - - + +
    @@ -357,6 +357,9 @@ user_detailview_tabs.on('contentReady', function(e){
    {$USER_HOLIDAYS_SUBPANEL}
    +
    + {$OAUTH_TOKENS_SUBPANEL} +
    {if !$SHOW_ROLES} diff --git a/modules/Users/Save.php b/modules/Users/Save.php index 0c602963..d8169c1c 100644 --- a/modules/Users/Save.php +++ b/modules/Users/Save.php @@ -406,6 +406,27 @@ if(!$current_user->is_admin && !$GLOBALS['current_user']->isAdminForModule('Use } + + //handle navigation from user wizard + if(isset($_REQUEST['whatnext'])){ + if($_REQUEST['whatnext']== 'import'){ + header("Location:index.php?module=Import&action=step1&import_module=Administration"); + return; + }elseif($_REQUEST['whatnext']== 'users'){ + header("Location:index.php?module=Users&action=index"); + return; + }elseif($_REQUEST['whatnext']== 'settings'){ + header("Location:index.php?module=Configurator&action=EditView"); + return; + }elseif($_REQUEST['whatnext']== 'studio'){ + header("Location:index.php?module=ModuleBuilder&action=index&type=studio"); + return; + }else{ + //do nothing, let the navigation continue as normal using code below + } + + } + if(isset($_REQUEST['return_module']) && $_REQUEST['return_module'] != "") $return_module = $_REQUEST['return_module']; else $return_module = "Users"; if(isset($_REQUEST['return_action']) && $_REQUEST['return_action'] != "") $return_action = $_REQUEST['return_action']; diff --git a/modules/Users/User.php b/modules/Users/User.php index bb291b44..a7965b47 100644 --- a/modules/Users/User.php +++ b/modules/Users/User.php @@ -414,6 +414,8 @@ class User extends Person { } function save($check_notify = false) { + $isUpdate = !empty($this->id) && !$this->new_with_id; + $query = "SELECT count(id) as total from users WHERE status='Active' AND deleted=0 AND is_group=0 AND portal_only=0"; @@ -864,10 +866,6 @@ EOQ; return $list_form; } - function save_relationship_changes($is_update) { - } - - function create_export_query($order_by, $where) { diff --git a/modules/Users/authentication/SugarAuthenticate/SugarAuthenticate.php b/modules/Users/authentication/SugarAuthenticate/SugarAuthenticate.php index f75ddb9b..bdddc91f 100644 --- a/modules/Users/authentication/SugarAuthenticate/SugarAuthenticate.php +++ b/modules/Users/authentication/SugarAuthenticate/SugarAuthenticate.php @@ -159,7 +159,7 @@ class SugarAuthenticate{ if (isset ($sugar_config['unique_key']))$_SESSION['unique_key'] = $sugar_config['unique_key']; //set user language - if (isset ($reset_language_on_default_user) && $reset_language_on_default_user && $$GLOBALS['current_user']->user_name == $sugar_config['default_user_name']) { + if (isset ($reset_language_on_default_user) && $reset_language_on_default_user && $GLOBALS['current_user']->user_name == $sugar_config['default_user_name']) { $authenticated_user_language = $sugar_config['default_language']; } else { $authenticated_user_language = isset($_REQUEST['login_language']) ? $_REQUEST['login_language'] : (isset ($_REQUEST['ck_login_language_20']) ? $_REQUEST['ck_login_language_20'] : $sugar_config['default_language']); diff --git a/modules/Users/language/en_us.lang.php b/modules/Users/language/en_us.lang.php index 9f10a49e..dc7afef4 100644 --- a/modules/Users/language/en_us.lang.php +++ b/modules/Users/language/en_us.lang.php @@ -88,7 +88,7 @@ $mod_strings = array ( 'ERR_RECIPIENT_EMAIL' => 'Recipient Email Address', 'ERR_SERVER_STATUS' => 'Your server status', 'ERR_SERVER_SMTP_EMPTY' => 'The system is unable to send an email to the user. Please check the Outgoing Mail Configuration in Email Settings.', - + 'LBL_ADDRESS_CITY' => 'Address City', 'LBL_ADDRESS_COUNTRY' => 'Address Country', 'LBL_ADDRESS_INFORMATION' => 'Address Information', @@ -103,7 +103,7 @@ $mod_strings = array ( 'LBL_REGULAR_DESC' => 'User can access modules and records based on roles.', - + 'LBL_ADMIN' => 'System Administrator', 'LBL_ADVANCED' => 'Advanced', 'LBL_ANY_ADDRESS' => 'Any Address:', @@ -277,7 +277,7 @@ $mod_strings = array ( 'LBL_PASSWORD_EXPIRATION_LOGIN' => 'Your password has expired. Please provide a new password.', 'LBL_PASSWORD_EXPIRATION_GENERATED' => 'Your password is system-generated', 'LBL_PASSWORD_EXPIRATION_TIME' => 'Your password has expired. Please provide a new password.', - + 'LBL_PSW_MODIFIED' => 'password last changed', 'LBL_PHONE' => 'Phone', 'LBL_PICK_TZ_WELCOME' => 'Welcome to Sugar.', @@ -290,7 +290,7 @@ $mod_strings = array ( 'LBL_PROMPT_TIMEZONE' => 'User Wizard Prompt', 'LBL_PROVIDE_USERNAME_AND_EMAIL' => 'Provide both a User Name and an Email Address.', 'LBL_PUBLISH_KEY' => 'Publish Key', - + 'LBL_RECAPTCHA_NEW_CAPTCHA' => 'Get another CAPTCHA', 'LBL_RECAPTCHA_SOUND' => 'Switch to Sound', 'LBL_RECAPTCHA_IMAGE' => 'Switch to Image', @@ -300,7 +300,7 @@ $mod_strings = array ( 'LBL_RECAPTCHA_INVALID_PRIVATE_KEY' => 'Invalid Recaptcha Private Key', 'LBL_RECAPTCHA_INVALID_REQUEST_COOKIE'=> 'The challenge parameter of the verify Recaptcha script was incorrect.', 'LBL_RECAPTCHA_UNKNOWN' => 'Unknown Recaptcha Error', - + 'LBL_RECEIVE_NOTIFICATIONS_TEXT' => 'Receive an email notification when a record is assigned to you.', 'LBL_RECEIVE_NOTIFICATIONS' => 'Notify on Assignment', 'LBL_REGISTER' => 'New user? Please register', @@ -317,9 +317,9 @@ $mod_strings = array ( 'LBL_RESET_PREFERENCES_WARNING' => 'Are you sure you want reset all of your user preferences? Warning: This will also log you out of the application.', 'LBL_RESET_PREFERENCES_WARNING_USER' => 'Are you sure you want reset all of the preferences for this user?', 'LBL_RESET_HOMEPAGE' => 'Reset Homepage', - 'LBL_RESET_DASHBOARD' => 'Reset Dashboard', + 'LBL_RESET_DASHBOARD' => 'Reset Dashboard', 'LBL_RESET_HOMEPAGE_WARNING' => 'Are you sure you want reset your Homepage?', - 'LBL_RESET_HOMEPAGE_WARNING_USER' => 'Are you sure you want reset the Homepage for this user?', + 'LBL_RESET_HOMEPAGE_WARNING_USER' => 'Are you sure you want reset the Homepage for this user?', 'LBL_SALUTATION' => 'Salutation', 'LBL_ROLES_SUBPANEL_TITLE' => 'Roles', 'LBL_SEARCH_FORM_TITLE' => 'User Search', @@ -430,7 +430,7 @@ $mod_strings = array ( 'LBL_LDAP_ERROR' => 'LDAP Error: Please contact an Admin', 'LBL_LDAP_EXTENSION_ERROR' => 'LDAP Error: Extensions not loaded', -// PROJECT RESOURCES STRINGS +// PROJECT RESOURCES STRINGS 'LBL_USER_HOLIDAY_SUBPANEL_TITLE' => 'User Holidays', 'LBL_RESOURCE_NAME' => 'Name', 'LBL_RESOURCE_TYPE' => 'Type', @@ -499,16 +499,26 @@ $mod_strings = array ( 'LBL_WIZARD_FINISH_BUTTON' => 'Finish', 'LBL_WIZARD_FINISH_TAB' => 'Finish', 'LBL_WIZARD_FINISH_TITLE' => 'You are ready to use Sugar!', - 'LBL_WIZARD_FINISH' => 'Click Finish below to save your settings and to begin using Sugar. For more information on using Sugar:

    -
    - - - - - - - -
    Sugar University
    End-user and System Administrator Training and Resources

    Documentation
    Product Guides and Release Notes

    Knowledge Base
    Tips from SugarCRM Support for performing common tasks and processes in Sugar

    Forums
    Forums dedicated to the Sugar Community to discuss topics of interest with each other and with SugarCRM Developers
    ', + + 'LBL_WIZARD_FINISH1' => 'What would you like to do next?', + 'LBL_WIZARD_FINISH2' => 'Start Using Sugar', + 'LBL_WIZARD_FINISH3' => 'Import Data ', + 'LBL_WIZARD_FINISH4' => 'Import data from external sources into the application.', + 'LBL_WIZARD_FINISH5' => 'Create Users', + 'LBL_WIZARD_FINISH6' => 'Create new user accounts for people to use to access the application.', + 'LBL_WIZARD_FINISH7' => 'View and Manage Application Settings', + 'LBL_WIZARD_FINISH8' => 'Manage advanced settings, including default application settings.', + 'LBL_WIZARD_FINISH9' => 'Configure the Application ', + 'LBL_WIZARD_FINISH10' => 'Use Studio to create and manage application fields and layouts.', + 'LBL_WIZARD_FINISH11' => 'Visit Sugar University ', + 'LBL_WIZARD_FINISH12' => 'Find training materials and classes that will help you get started as a system administrator or end user of the application.', + 'LBL_WIZARD_FINISH14' => 'Documentation ', + 'LBL_WIZARD_FINISH15' => 'Product Guides and Release Notes ', + 'LBL_WIZARD_FINISH16' => 'Knowledge Base ', + 'LBL_WIZARD_FINISH17' => 'Tips from SugarCRM Support for performing common tasks and processes in Sugar ', + 'LBL_WIZARD_FINISH18' => 'Forums ', + 'LBL_WIZARD_FINISH19' => 'Forums dedicated to the Sugar Community to discuss topics of interest with each other and with SugarCRM Developers ', + 'LBL_WIZARD_FINISH2DESC' => 'Go directly to the application Home page.', 'LBL_WIZARD_PERSONALINFO' => 'Your Information', 'LBL_WIZARD_LOCALE' => 'Your Locale', 'LBL_WIZARD_SMTP' => 'Your Email Account', @@ -516,6 +526,19 @@ $mod_strings = array ( 'LBL_WIZARD_LOCALE_DESC' => 'Specify your time zone and how you would like dates, currencies and names to appear in Sugar.', 'LBL_WIZARD_SMTP_DESC' => 'Provide your email account username and password for the default outbound email server.', 'LBL_EAPM_SUBPANEL_TITLE' => 'External Accounts', + 'LBL_OAUTH_TOKENS' => 'OAuth Tokens', + 'LBL_OAUTH_TOKENS_SUBPANEL_TITLE' => "OAuth Access Tokens", + + //For export labels + 'LBL_MODIFIED_USER_ID' => 'Modified User ID', + 'LBL_PHONE_HOME' => 'Phone Home', + 'LBL_PHONE_MOBILE' => 'Phone Mobile', + 'LBL_PHONE_WORK' => 'Phone Work', + 'LBL_PHONE_OTHER' => 'Phone Other', + 'LBL_PHONE_FAX' => 'Phone Fax', + 'LBL_PORTAL_ONLY' => 'Portal Only', + 'LBL_IS_GROUP' => 'Is Group', + 'LBL_EXPORT_CREATED_BY' => 'Created By ID', ); // END STRINGS DEFS ?> diff --git a/modules/Users/metadata/subpaneldefs.php b/modules/Users/metadata/subpaneldefs.php index 6129ffa3..62673bd0 100644 --- a/modules/Users/metadata/subpaneldefs.php +++ b/modules/Users/metadata/subpaneldefs.php @@ -35,7 +35,7 @@ if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point'); * "Powered by SugarCRM". ********************************************************************************/ - + $layout_defs['Users'] = array( @@ -137,5 +137,3 @@ $layout_defs['UserEAPM'] = array( ), ); - - diff --git a/modules/Users/reassignUserRecords.php b/modules/Users/reassignUserRecords.php index 0d77970c..6e4bcf57 100644 --- a/modules/Users/reassignUserRecords.php +++ b/modules/Users/reassignUserRecords.php @@ -52,9 +52,9 @@ $return_action = isset($_REQUEST['return_action']) ? $_REQUEST['return_action'] $return_id = isset($_REQUEST['return_id']) ? $_REQUEST['return_id'] : ''; if(!empty($return_module)) $cancel_location = "index.php?module=".$return_module."&action=".$return_action."&record=".$return_id; -else +else $cancel_location = "index.php?module=Users&action=index"; - + echo "

    {$mod_strings_users['LBL_REASS_SCRIPT_TITLE']}

    "; // Include Metadata for processing @@ -77,6 +77,8 @@ if(!isset($_POST['fromuser']) && !isset($_GET['execute'])){ "SavedSearch", "UserPreference", "SugarFavorites", + 'OAuthKey', + 'OAuthToken', ); if(isset($_GET['clear']) && $_GET['clear'] == 'true'){ @@ -159,7 +161,7 @@ if(!isset($_SESSION['reassignRecords']['assignedModuleListCache'])){ } } $beanListDup = array_diff($beanListDup, $exclude_modules); - + //Leon bug 20739 $beanListDupDisp=array() ; foreach($beanListDup as $m => $p){ @@ -205,7 +207,7 @@ foreach($moduleFilters as $modFilter => $fieldArray){ $multi = "multiple=\"true\""; $name .= "[]"; // NO BREAK - Continue into select - case "select": + case "select": $tag = "select"; $sel = ''; if(!empty($_SESSION['reassignRecords']['filters'][$meta['name']])){ @@ -249,12 +251,12 @@ else if(!isset($_GET['execute'])){ if($_POST['fromuser'] == $_POST['touser']){ sugar_die($mod_strings_users['ERR_REASS_DIFF_USERS']); } - + global $current_user; // Set the from and to user names so that we can display them in the results $fromusername = $_POST['fromuser']; $tousername = $_POST['touser']; - + $query = "select user_name, id from users where id in ('{$_POST['fromuser']}', '{$_POST['touser']}')"; $res = $GLOBALS['db']->query($query); while($row = $GLOBALS['db']->fetchByAssoc($res)){ @@ -281,20 +283,20 @@ else if(!isset($_GET['execute'])){ continue; } $p_module = $beanListFlip[$module]; - + require_once($beanFiles[$module]); $object = new $module(); if(empty($object->table_name)){ // echo "
    Could not find the database table for $p_module.
    "; continue; } - + echo "
    {$mod_strings_users['LBL_REASS_ASSESSING']} {$app_list_strings['moduleList'][$p_module]}
    "; - + echo "\n"; echo "\n"; echo "
    \n"; - + $q_select = "select id"; $q_update = "update "; $q_set = " set assigned_user_id = '{$_POST['touser']}', ". @@ -344,28 +346,28 @@ else if(!isset($_GET['execute'])){ $query = "$q_select from $q_tables $q_where"; $countquery = "select count(*) AS count from $q_tables $q_where"; $updatequery = "$q_update $q_tables $q_set $q_where"; - + $_SESSION['reassignRecords']['fromuser'] = $_POST['fromuser']; $_SESSION['reassignRecords']['touser'] = $_POST['touser']; $_SESSION['reassignRecords']['fromusername'] = $fromusername; $_SESSION['reassignRecords']['tousername'] = $tousername; $_SESSION['reassignRecords']['modules'][$module]['query'] = $query; $_SESSION['reassignRecords']['modules'][$module]['update'] = $updatequery; - + $res = $GLOBALS['db']->query($countquery); $row = $GLOBALS['db']->fetchByAssoc($res); - + echo "{$row['count']} {$mod_strings_users['LBL_REASS_RECORDS_FROM']} {$app_list_strings['moduleList'][$p_module]} {$mod_strings_users['LBL_REASS_WILL_BE_UPDATED']}\n
    \n"; echo " {$mod_strings_users['LBL_REASS_WORK_NOTIF_AUDIT']}
    \n"; echo "
    \n"; } - + echo "
    \n"; echo " \n"; echo " \n"; - + echo "\n"; - + // debug //print_r($_SESSION['reassignRecords']); ///////////////////// END STEP 2 - Confirm Selections ///////////////////////// @@ -376,7 +378,7 @@ else if(isset($_GET['execute']) && $_GET['execute'] == true){ $touser = $_SESSION['reassignRecords']['touser']; $fromusername = $_SESSION['reassignRecords']['fromusername']; $tousername = $_SESSION['reassignRecords']['tousername']; - + $beanListFlip = array_flip($_SESSION['reassignRecords']['assignedModuleListCache']); foreach($_SESSION['reassignRecords']['modules'] as $module => $queries){ @@ -384,13 +386,13 @@ else if(isset($_GET['execute']) && $_GET['execute'] == true){ $workflow = false; if(isset($_POST[$module."_workflow"]) && $_POST[$module."_workflow"] = "on") $workflow = true; - + $query = $workflow ? $queries['query'] : $queries['update']; - + echo "
    {$mod_strings_users['LBL_PROCESSING']} {$app_list_strings['moduleList'][$p_module]}
    "; - + $res = $GLOBALS['db']->query($query, true); - + //echo "Workflow and Notifications ".($workflow ? "enabled" : "disabled")." for this module record reassignment\n
    \n"; echo "\n"; echo "\n"; @@ -402,7 +404,7 @@ else if(isset($_GET['execute']) && $_GET['execute'] == true){ else{ $successarr = array(); $failarr = array(); - + require_once($beanFiles[$module]); while($row = $GLOBALS['db']->fetchByAssoc($res)){ $bean = new $module(); @@ -410,13 +412,13 @@ else if(isset($_GET['execute']) && $_GET['execute'] == true){ continue; } $bean->retrieve($row['id']); - + // So that we don't create new blank records. if(!isset($bean->id)){ continue; - } + } $bean->assigned_user_id = $touser; - + if($bean->save()){ $linkname = "record with id {$bean->id}"; if(!empty($bean->name)){ @@ -435,7 +437,7 @@ else if(isset($_GET['execute']) && $_GET['execute'] == true){ $failarr[] = "{$mod_strings_users['LBL_REASS_FAILED_SAVE']} \"module_dir}&action=DetailView&record={$bean->id}\">$linkname\"."; } } - + if(isset($_POST['verbose']) && $_POST['verbose'] == "on"){ echo "
    {$mod_strings_users['LBL_REASS_THE_FOLLOWING']} {$app_list_strings['moduleList'][$p_module]} {$mod_strings_users['LBL_REASS_HAVE_BEEN_UPDATED']}
    \n"; foreach($successarr as $ord){ @@ -443,7 +445,7 @@ else if(isset($_GET['execute']) && $_GET['execute'] == true){ } if(empty($successarr)) echo "{$mod_strings_users['LBL_REASS_NONE']}\n
    \n"; - + echo "
    {$mod_strings_users['LBL_REASS_THE_FOLLOWING']} {$app_list_strings['moduleList'][$p_module]} {$mod_strings_users['LBL_REASS_CANNOT_PROCESS']}
    \n"; foreach($failarr as $failure){ echo $failure."\n
    \n"; @@ -479,7 +481,7 @@ function clearCurrentRecords() updateDivDisplay(document.getElementById('modulemultiselect')); } }; - + YAHOO.util.Connect.asyncRequest('POST', 'index.php?module=Users&action=clearreassignrecords&to_pdf=1', callback, null); } @@ -488,7 +490,7 @@ function updateDivDisplay(multiSelectObj){ for(var i = 0; i < multiSelectObj.options.length; i++){ if(multiSelectObj.options[i].selected != allselected[i]){ allselected[i] = multiSelectObj.options[i].selected; - + if(allselected[i]){ theElement = document.getElementById('reassign_'+multiSelectObj.options[i].value); if(theElement != null){ @@ -502,7 +504,7 @@ function updateDivDisplay(multiSelectObj){ } } } - } + } } -
    -
    +
    +
    -
    -
    + +
    @@ -334,7 +334,35 @@ function disableReturnSubmission(e) { - +

    {$MOD.LBL_WIZARD_FINISH_TITLE}

    {$MOD.LBL_WIZARD_FINISH} +

    {$MOD.LBL_WIZARD_FINISH1}

    + + + {if $IS_ADMIN} + + + + + + + + + + + + + {else} + + + + + + + + + {/if} +
    {$MOD.LBL_WIZARD_FINISH2}
    {$MOD.LBL_WIZARD_FINISH2DESC}

    {$MOD.LBL_WIZARD_FINISH3}
    {$MOD.LBL_WIZARD_FINISH4}

    {$MOD.LBL_WIZARD_FINISH5}
    {$MOD.LBL_WIZARD_FINISH6}

    {$MOD.LBL_WIZARD_FINISH7}
    {$MOD.LBL_WIZARD_FINISH8}

    {$MOD.LBL_WIZARD_FINISH9}
    {$MOD.LBL_WIZARD_FINISH10}

    {$MOD.LBL_WIZARD_FINISH11}
    {$MOD.LBL_WIZARD_FINISH12}

    {$MOD.LBL_WIZARD_FINISH11}
    {$MOD.LBL_WIZARD_FINISH12}

    {$MOD.LBL_WIZARD_FINISH14}
    {$MOD.LBL_WIZARD_FINISH15}

    {$MOD.LBL_WIZARD_FINISH16}
    {$MOD.LBL_WIZARD_FINISH17}

    {$MOD.LBL_WIZARD_FINISH18}
    {$MOD.LBL_WIZARD_FINISH19}

    +
    @@ -354,11 +382,11 @@ function disableReturnSubmission(e) { - -
    + + -
    + {literal} @@ -603,4 +631,4 @@ setSigDigits(); - + \ No newline at end of file diff --git a/modules/Users/vardefs.php b/modules/Users/vardefs.php index ffd21354..3e703dec 100644 --- a/modules/Users/vardefs.php +++ b/modules/Users/vardefs.php @@ -68,7 +68,7 @@ $dictionary['User'] = array( 'reportable' => false, 'massupdate' => false, ) , - + 'pwd_last_changed' => array( 'name' => 'pwd_last_changed', 'vname' => 'LBL_PSW_MODIFIED', @@ -376,11 +376,12 @@ $dictionary['User'] = array( 'vname' => 'LBL_MEETINGS' ) , 'contacts_sync' => array( - 'name' => 'contacts', + 'name' => 'contacts_sync', 'type' => 'link', 'relationship' => 'contacts_users', 'source' => 'non-db', - 'vname' => 'LBL_CONTACTS_SYNC' + 'vname' => 'LBL_CONTACTS_SYNC', + 'reportable' => false, ) , 'reports_to_link' => array( 'name' => 'reports_to_link', @@ -391,6 +392,16 @@ $dictionary['User'] = array( 'source' => 'non-db', 'vname' => 'LBL_REPORTS_TO', ) , + 'reportees' => array( + 'name' => 'reportees', + 'type' => 'link', + 'relationship' => 'user_direct_reports', + 'link_type' => 'many', + 'side' => 'left', + 'source' => 'non-db', + 'vname' => 'LBL_REPORTS_TO', + 'reportable' => false, + ) , 'email1' => array( 'name' => 'email1', 'vname' => 'LBL_EMAIL', @@ -509,7 +520,26 @@ $dictionary['User'] = array( 'vname' => 'LBL_ASSIGNED_TO_USER', 'source'=>'non-db', ), - + 'oauth_tokens' => + array ( + 'name' => 'oauth_tokens', + 'type' => 'link', + 'relationship' => 'oauthtokens_assigned_user', + 'vname' => 'LBL_OAUTH_TOKENS', + 'link_type' => 'one', + 'module'=>'OAuthTokens', + 'bean_name'=>'OAuthToken', + 'source'=>'non-db', + 'side' => 'left', + ), + 'project_resource'=> + array ( + 'name' => 'project_resource', + 'type' => 'link', + 'relationship' => 'projects_users_resources', + 'source' => 'non-db', + 'vname' => 'LBL_PROJECTS', + ), ) , 'indices' => array( array( @@ -537,32 +567,32 @@ $dictionary['User'] = array( 'users_users_signatures' => array( 'lhs_module'=> 'Users', - 'lhs_table'=> 'users', + 'lhs_table'=> 'users', 'lhs_key' => 'id', - 'rhs_module'=> 'UserSignature', - 'rhs_table'=> 'users_signatures', + 'rhs_module'=> 'UserSignature', + 'rhs_table'=> 'users_signatures', 'rhs_key' => 'user_id', 'relationship_type'=>'one-to-many' ), - 'users_email_addresses' => + 'users_email_addresses' => array( 'lhs_module'=> "Users", 'lhs_table'=> 'users', 'lhs_key' => 'id', 'rhs_module'=> 'EmailAddresses', 'rhs_table'=> 'email_addresses', 'rhs_key' => 'id', 'relationship_type'=>'many-to-many', - 'join_table'=> 'email_addr_bean_rel', 'join_key_lhs'=>'bean_id', 'join_key_rhs'=>'email_address_id', + 'join_table'=> 'email_addr_bean_rel', 'join_key_lhs'=>'bean_id', 'join_key_rhs'=>'email_address_id', 'relationship_role_column'=>'bean_module', 'relationship_role_column_value'=>"Users" ), - 'users_email_addresses_primary' => + 'users_email_addresses_primary' => array('lhs_module'=> "Users", 'lhs_table'=> 'users', 'lhs_key' => 'id', 'rhs_module'=> 'EmailAddresses', 'rhs_table'=> 'email_addresses', 'rhs_key' => 'id', 'relationship_type'=>'many-to-many', - 'join_table'=> 'email_addr_bean_rel', 'join_key_lhs'=>'bean_id', 'join_key_rhs'=>'email_address_id', - 'relationship_role_column'=>'primary_address', + 'join_table'=> 'email_addr_bean_rel', 'join_key_lhs'=>'bean_id', 'join_key_rhs'=>'email_address_id', + 'relationship_role_column'=>'primary_address', 'relationship_role_column_value'=>'1' ), ), - - + + ); diff --git a/modules/Users/views/view.list.php b/modules/Users/views/view.list.php index ab1c166d..4db9fbfb 100644 --- a/modules/Users/views/view.list.php +++ b/modules/Users/views/view.list.php @@ -51,4 +51,22 @@ class UsersViewList extends ViewList $this->lv->email = false; } + public function listViewProcess() + { + $this->processSearchForm(); + $this->lv->searchColumns = $this->searchForm->searchColumns; + + if(!$this->headers) + return; + if(empty($_REQUEST['search_form_only']) || $_REQUEST['search_form_only'] == false){ + $this->lv->ss->assign("SEARCH",true); + if(!empty($this->where)){ + $this->where .= " AND"; + } + $this->where .= " (users.status !='Reserved' or users.status is null) "; + $this->lv->setup($this->seed, 'include/ListView/ListViewGeneric.tpl', $this->where, $this->params); + $savedSearchName = empty($_REQUEST['saved_search_select_name']) ? '' : (' - ' . $_REQUEST['saved_search_select_name']); + echo $this->lv->display(); + } + } } diff --git a/modules/Users/views/view.wizard.php b/modules/Users/views/view.wizard.php index 32308d03..ba4f975d 100644 --- a/modules/Users/views/view.wizard.php +++ b/modules/Users/views/view.wizard.php @@ -221,26 +221,31 @@ eoq; $mail_smtppass = ""; $hide_if_can_use_default = true; $mail_smtpauth_req=true; - if( !$systemOutboundEmail->isAllowUserAccessToSystemDefaultOutbound() ) - { - - $mail_smtpauth_req = $systemOutboundEmail->mail_smtpauth_req; - $userOverrideOE = $systemOutboundEmail->getUsersMailerForSystemOverride($current_user->id); - if($userOverrideOE != null) { - $mail_smtpuser = $userOverrideOE->mail_smtpuser; - $mail_smtppass = $userOverrideOE->mail_smtppass; - } - if(!$mail_smtpauth_req && - (empty($systemOutboundEmail->mail_smtpserver) || empty($systemOutboundEmail->mail_smtpuser) - || empty($systemOutboundEmail->mail_smtppass))) - { - $hide_if_can_use_default = true; - } - else{ - $hide_if_can_use_default = false; + if(!empty($mail_smtpserver) && !empty($mail_smtptype)) { + if( !$systemOutboundEmail->isAllowUserAccessToSystemDefaultOutbound() ) + { + + $mail_smtpauth_req = $systemOutboundEmail->mail_smtpauth_req; + $userOverrideOE = $systemOutboundEmail->getUsersMailerForSystemOverride($current_user->id); + if($userOverrideOE != null) { + $mail_smtpuser = $userOverrideOE->mail_smtpuser; + $mail_smtppass = $userOverrideOE->mail_smtppass; + } + if(!$mail_smtpauth_req && + (empty($systemOutboundEmail->mail_smtpserver) || empty($systemOutboundEmail->mail_smtpuser) + || empty($systemOutboundEmail->mail_smtppass))) + { + $hide_if_can_use_default = true; + } + else{ + $hide_if_can_use_default = false; + } } } - + + $isAdmin = is_admin($current_user); + $this->ss->assign('IS_ADMIN', $isAdmin); + $this->ss->assign("mail_smtpdisplay", $mail_smtpdisplay); $this->ss->assign("mail_smtpuser", $mail_smtpuser); $this->ss->assign("mail_smtppass", $mail_smtppass); @@ -250,7 +255,7 @@ eoq; $this->ss->assign('MAIL_SMTPSSL',$mail_smtpssl); $this->ss->assign('HIDE_IF_CAN_USE_DEFAULT_OUTBOUND',$hide_if_can_use_default); - + $this->ss->display('modules/Users/tpls/wizard.tpl'); } } diff --git a/modules/vCals/vCal.php b/modules/vCals/vCal.php index efb72184..6030df8b 100644 --- a/modules/vCals/vCal.php +++ b/modules/vCals/vCal.php @@ -136,7 +136,7 @@ class vCal extends SugarBean { // get activities.. queries Meetings and Calls $acts_arr = CalendarActivity::get_activities($user_bean->id, - false, + array("show_calls" => true), $start_date_time, $end_date_time, 'freebusy'); diff --git a/service/core/SoapHelperWebService.php b/service/core/SoapHelperWebService.php index 22dfe276..9f7afafb 100644 --- a/service/core/SoapHelperWebService.php +++ b/service/core/SoapHelperWebService.php @@ -546,80 +546,37 @@ function validate_user($user_name, $password){ function getRelationshipResults($bean, $link_field_name, $link_module_fields, $optional_where = '') { $GLOBALS['log']->info('Begin: SoapHelperWebServices->getRelationshipResults'); require_once('include/TimeDate.php'); - global $beanList, $beanFiles, $current_user; - global $disable_date_format; + global $current_user, $disable_date_format, $timedate;; $bean->load_relationship($link_field_name); if (isset($bean->$link_field_name)) { - // get the query object for this link field - $query_array = $bean->$link_field_name->getQuery(true,array(),0,'',true); - if (isset($query_array['where'])) { - $query_array['where'] = str_ireplace("where", "", $query_array['where']); - if (!empty($optional_where)) { - $optional_where = $query_array['where'] . " and " . $optional_where; - } else { - $optional_where = $query_array['where']; - } // else - } // if - - $params = array(); - $params['joined_tables'] = $query_array['join_tables']; - - // get the related module name and instantiate a bean for that. - $submodulename = $bean->$link_field_name->getRelatedModuleName(); - $submoduleclass = $beanList[$submodulename]; - require_once($beanFiles[$submoduleclass]); - $submodule = new $submoduleclass(); + //First get all the related beans + $related_beans = $bean->$link_field_name->getBeans(); $filterFields = $this->filter_fields($submodule, $link_module_fields); - $relFields = $bean->$link_field_name->getRelatedFields(); - $roleSelect = ''; - - $idSetInSubModule = false; - if($submodulename == 'Users' && !in_array('id', $link_module_fields)){ - $link_module_fields[] = 'id'; - $idSetInSubModule = true; - } - - if(!empty($relFields)){ - foreach($link_module_fields as $field){ - if(!empty($relFields[$field])){ - $roleSelect .= ', ' . $query_array['join_tables'][0] . '.'. $field; - } - } - } - // create a query - $subquery = $submodule->create_new_list_query('',$optional_where ,$filterFields,$params, 0,'', true,$bean); - $query = $subquery['select'].$roleSelect . $subquery['from'].$query_array['join']. $subquery['where']; - $GLOBALS['log']->info('SoapHelperWebServices->getRelationshipResults query = ' . $query); - - $result = $submodule->db->query($query, true); + //Create a list of field/value rows based on $link_module_fields $list = array(); - while($row = $submodule->db->fetchByAssoc($result)) { - if (!$disable_date_format) { - foreach ($filterFields as $field) { - if (isset($submodule->field_defs[$field]) && - isset($submodule->field_defs[$field]['type']) && - isset($row[$field])) { - - if ($submodule->field_defs[$field]['type'] == 'date') { - global $timedate; - $row[$field] = $timedate->to_display_date_time($row[$field]); - } - if ($submodule->field_defs[$field]['type'] == 'currency') { - // TODO: convert data from db to user preferred format absed on the community input - } // if - } // if - - } // foreach - } - if($submodulename == 'Users' && $current_user->id != $row['id']) { - $row['user_hash'] = ""; - } // if - if ($idSetInSubModule) { - unset($row['id']); - } // if - $list[] = $row; - } + foreach($related_beans as $id => $bean) + { + $row = array(); + foreach ($filterFields as $field) { + if (isset($bean->$field)) + { + if (isset($bean->field_defs[$field]['type']) && $bean->field_defs[$field]['type'] == 'date') { + $row[$field] = $timedate->to_display_date_time($bean->$field); + } + $row[$field] = $bean->$field; + } + else + { + $row[$field] = ""; + } + } + //Users can't see other user's hashes + if(is_a($bean, 'User') && $current_user->id != $bean->id && isset($row['user_hash'])) { + $row['user_hash'] = ""; + } + $list[] = $row; + } $GLOBALS['log']->info('End: SoapHelperWebServices->getRelationshipResults'); return array('rows' => $list, 'fields_set_on_rows' => $filterFields); } else { diff --git a/service/v3/SugarWebServiceImplv3.php b/service/v3/SugarWebServiceImplv3.php index fa8e8ddb..7898f4f2 100644 --- a/service/v3/SugarWebServiceImplv3.php +++ b/service/v3/SugarWebServiceImplv3.php @@ -574,8 +574,7 @@ class SugarWebServiceImplv3 extends SugarWebServiceImpl { * @exception 'SoapFault' -- The SOAP error, if any */ function get_relationships($session, $module_name, $module_id, $link_field_name, $related_module_query, $related_fields, $related_module_link_name_to_fields_array, $deleted, $order_by = ''){ - - $GLOBALS['log']->info('Begin: SugarWebServiceImpl->get_relationships'); + $GLOBALS['log']->info('Begin: SugarWebServiceImpl->get_relationships'); global $beanList, $beanFiles; $error = new SoapError(); if (!self::$helperObject->checkSessionAndModuleAccess($session, 'invalid_session', $module_name, 'read', 'no_access', $error)) { diff --git a/service/v3/SugarWebServiceUtilv3.php b/service/v3/SugarWebServiceUtilv3.php index f39a27de..e2ffa26e 100644 --- a/service/v3/SugarWebServiceUtilv3.php +++ b/service/v3/SugarWebServiceUtilv3.php @@ -37,6 +37,13 @@ require_once('service/core/SoapHelperWebService.php'); class SugarWebServiceUtilv3 extends SoapHelperWebServices { + function get_name_value($field,$value) + { + if($value instanceof Link2 && !method_exists($value, '__toString')) + $value = ''; + return array('name'=>$field, 'value'=>$value); + } + function filter_fields($value, $fields) { $GLOBALS['log']->info('Begin: SoapHelperWebServices->filter_fields'); @@ -82,81 +89,47 @@ class SugarWebServiceUtilv3 extends SoapHelperWebServices { $GLOBALS['log']->info('Begin: SoapHelperWebServices->getRelationshipResults'); require_once('include/TimeDate.php'); global $beanList, $beanFiles, $current_user; - global $disable_date_format; + global $disable_date_format, $timedate; $bean->load_relationship($link_field_name); if (isset($bean->$link_field_name)) { - // get the query object for this link field - $query_array = $bean->$link_field_name->getQuery(true,array(),0,'',true); - if (isset($query_array['where'])) { - $query_array['where'] = str_ireplace("where", "", $query_array['where']); - if (!empty($optional_where)) { - $optional_where = $query_array['where'] . " and " . $optional_where; - } else { - $optional_where = $query_array['where']; - } // else - } // if - - $params = array(); - $params['joined_tables'] = $query_array['join_tables']; - - // get the related module name and instantiate a bean for that. - $submodulename = $bean->$link_field_name->getRelatedModuleName(); - $submoduleclass = $beanList[$submodulename]; - require_once($beanFiles[$submoduleclass]); - $submodule = new $submoduleclass(); - $filterFields = $this->filter_fields($submodule, $link_module_fields); - $relFields = $bean->$link_field_name->getRelatedFields(); - $roleSelect = ''; - - $idSetInSubModule = false; - if($submodulename == 'Users' && !in_array('id', $link_module_fields)){ - $link_module_fields[] = 'id'; - $idSetInSubModule = true; - } - - if(!empty($relFields)){ - foreach($link_module_fields as $field){ - if(!empty($relFields[$field])){ - $roleSelect .= ', ' . $query_array['join_tables'][0] . '.'. $field; - } - } - } - // create a query - $subquery = $submodule->create_new_list_query($order_by,$optional_where ,$filterFields,$params, 0,'', true,$bean); - $query = $subquery['select'].$roleSelect . $subquery['from'].$query_array['join']. $subquery['where'].$subquery['order_by']; - $GLOBALS['log']->info('SoapHelperWebServices->getRelationshipResults query = ' . $query); - - $result = $submodule->db->query($query, true); + //First get all the related beans + $related_beans = $bean->$link_field_name->getBeans(); + //Create a list of field/value rows based on $link_module_fields $list = array(); - while($row = $submodule->db->fetchByAssoc($result)) { - if (!$disable_date_format) { - foreach ($filterFields as $field) { - if (isset($submodule->field_defs[$field]) && - isset($submodule->field_defs[$field]['type']) && - isset($row[$field])) { - - if ($submodule->field_defs[$field]['type'] == 'date') { - global $timedate; - $row[$field] = $timedate->to_display_date_time($row[$field]); - } - if ($submodule->field_defs[$field]['type'] == 'currency') { - // TODO: convert data from db to user preferred format absed on the community input - } // if - } // if - - } // foreach - } - if($submodulename == 'Users' && $current_user->id != $row['id']) { - $row['user_hash'] = ""; - } // if - if ($idSetInSubModule) { - unset($row['id']); - } // if - $list[] = $row; - } - $GLOBALS['log']->info('End: SoapHelperWebServices->getRelationshipResults'); - return array('rows' => $list, 'fields_set_on_rows' => $filterFields); + $filterFields = array(); + if (!empty($order_by) && !empty($related_beans)) + { + $related_beans = order_beans($related_beans, $order_by); + } + foreach($related_beans as $id => $bean) + { + if (empty($filterFields) && !empty($link_module_fields)) + { + $filterFields = $this->filter_fields($bean, $link_module_fields); + } + $row = array(); + foreach ($filterFields as $field) { + if (isset($bean->$field)) + { + if (isset($bean->field_defs[$field]['type']) && $bean->field_defs[$field]['type'] == 'date') { + $row[$field] = $timedate->to_display_date_time($bean->$field); + } + $row[$field] = $bean->$field; + } + else + { + $row[$field] = ""; + } + } + //Users can't see other user's hashes + if(is_a($bean, 'User') && $current_user->id != $bean->id && isset($row['user_hash'])) { + $row['user_hash'] = ""; + } + $list[] = $row; + } + $GLOBALS['log']->info('End: SoapHelperWebServices->getRelationshipResults'); + return array('rows' => $list, 'fields_set_on_rows' => $filterFields); } else { $GLOBALS['log']->info('End: SoapHelperWebServices->getRelationshipResults - ' . $link_field_name . ' relationship does not exists'); return false; diff --git a/service/v3_1/SugarWebServiceUtilv3_1.php b/service/v3_1/SugarWebServiceUtilv3_1.php index f1400b7e..ca2ced69 100644 --- a/service/v3_1/SugarWebServiceUtilv3_1.php +++ b/service/v3_1/SugarWebServiceUtilv3_1.php @@ -148,8 +148,7 @@ class SugarWebServiceUtilv3_1 extends SugarWebServiceUtilv3 if (!isset($beanFiles[$beanName])) return array(); - if($beanName == 'aCase') - $beanName = 'Case'; + $beanName = BeanFactory::getObjectName($moduleName); $manager = new VardefManager ( ); $manager->loadVardef( $moduleName , $beanName ) ; diff --git a/service/v4/SugarWebServiceImplv4.php b/service/v4/SugarWebServiceImplv4.php index b3f5dad9..de55efe3 100644 --- a/service/v4/SugarWebServiceImplv4.php +++ b/service/v4/SugarWebServiceImplv4.php @@ -49,7 +49,7 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { { self::$helperObject = new SugarWebServiceUtilv4(); } - + /** * Log the user into the application * @@ -111,21 +111,35 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { self::$helperObject->setFaultObject($error); return; } - else if( $authController->authController->userAuthenticateClass == "LDAPAuthenticateUser" - && (empty($user_auth['encryption']) || $user_auth['encryption'] !== 'PLAIN' ) ) - { - $error->set_error('ldap_error'); - LogicHook::initialize(); - $GLOBALS['logic_hook']->call_custom_logic('Users', 'login_failed'); - self::$helperObject->setFaultObject($error); - return; - } - else if(function_exists('mcrypt_cbc')) + else if(function_exists('mcrypt_cbc') && $authController->authController->userAuthenticateClass == "LDAPAuthenticateUser" + && (empty($user_auth['encryption']) || $user_auth['encryption'] !== 'PLAIN' ) ) { $password = self::$helperObject->decrypt_string($user_auth['password']); + $authController->loggedIn = false; // reset login attempt to try again with decrypted password if($authController->login($user_auth['user_name'], $password) && isset($_SESSION['authenticated_user_id'])) $success = true; } + else if( $authController->authController->userAuthenticateClass == "LDAPAuthenticateUser" + && (empty($user_auth['encryption']) || $user_auth['encryption'] == 'PLAIN' ) ) + { + + $authController->loggedIn = false; // reset login attempt to try again with md5 password + if($authController->login($user_auth['user_name'], md5($user_auth['password']), array('passwordEncrypted' => true)) + && isset($_SESSION['authenticated_user_id'])) + { + $success = true; + } + else + { + + $error->set_error('ldap_error'); + LogicHook::initialize(); + $GLOBALS['logic_hook']->call_custom_logic('Users', 'login_failed'); + self::$helperObject->setFaultObject($error); + return; + } + } + if($success) { @@ -163,7 +177,7 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { $nameValueArray['mobile_max_list_entries'] = self::$helperObject->get_name_value('mobile_max_list_entries', $sugar_config['wl_list_max_entries_per_page'] ); $nameValueArray['mobile_max_subpanel_entries'] = self::$helperObject->get_name_value('mobile_max_subpanel_entries', $sugar_config['wl_list_max_entries_per_subpanel'] ); - + $currencyObject = new Currency(); $currencyObject->retrieve($cur_id); $nameValueArray['user_currency_name'] = self::$helperObject->get_name_value('user_currency_name', $currencyObject->name); @@ -176,8 +190,8 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { self::$helperObject->setFaultObject($error); $GLOBALS['log']->info('End: SugarWebServiceImpl->login - failed login'); } - - + + /** * Retrieve a list of SugarBean's based on provided IDs. This API will not wotk with report module * @@ -207,11 +221,11 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { } $returnRelationshipList[]['link_list'] = $link_output; } - + $result['relationship_list'] = $returnRelationshipList; return $result; } - + /** * Retrieve a list of beans. This is the primary method for getting list of SugarBeans from Sugar using the SOAP API. * @@ -312,7 +326,7 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { $GLOBALS['log']->info('End: SugarWebServiceImpl->get_entry_list'); return array('result_count'=>sizeof($output_list), 'total_count' => $totalRecordCount, 'next_offset'=>$next_offset, 'entry_list'=>$output_list, 'relationship_list' => $returnRelationshipList); } // fn - + /** * Retrieve the layout metadata for a given module given a specific type and view. * @@ -324,7 +338,7 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { */ function get_module_layout($session, $a_module_names, $a_type, $a_view,$acl_check = TRUE, $md5 = FALSE){ $GLOBALS['log']->fatal('Begin: SugarWebServiceImpl->get_module_layout'); - + global $beanList, $beanFiles; $error = new SoapError(); $results = array(); @@ -338,7 +352,7 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { if( empty($module_name) ) continue; - + $class_name = $beanList[$module_name]; require_once($beanFiles[$class_name]); $seed = new $class_name(); @@ -359,13 +373,13 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { } } } - + $GLOBALS['log']->info('End: SugarWebServiceImpl->get_module_layout'); - + return $results; } - - + + /** * Given a list of modules to search and a search string, return the id, module_name, along with the fields * We will support Accounts, Bug Tracker, Cases, Contacts, Leads, Opportunities, Project, ProjectTask, Quotes @@ -377,8 +391,8 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { * @param int $max_results - max number of records to return * @param string $assigned_user_id - a user id to filter all records by, leave empty to exclude the filter * @param string[] $select_fields - An array of fields to return. If empty the default return fields will be from the active list view defs. - * @param bool $unified_search_only - A boolean indicating if we should only search against those modules participating in the unified search. - * @param bool $favorites - A boolean indicating if we should only search against records marked as favorites. + * @param bool $unified_search_only - A boolean indicating if we should only search against those modules participating in the unified search. + * @param bool $favorites - A boolean indicating if we should only search against records marked as favorites. * @return Array return_search_result - Array('Accounts' => array(array('name' => 'first_name', 'value' => 'John', 'name' => 'last_name', 'value' => 'Do'))) * @exception 'SoapFault' -- The SOAP error, if any */ @@ -386,7 +400,7 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { $GLOBALS['log']->info('Begin: SugarWebServiceImpl->search_by_module'); global $beanList, $beanFiles; global $sugar_config,$current_language; - + $error = new SoapError(); $output_list = array(); if (!self::$helperObject->checkSessionAndModuleAccess($session, 'invalid_session', '', '', '', $error)) { @@ -398,20 +412,20 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { if($max_results > 0){ $sugar_config['list_max_entries_per_page'] = $max_results; } - + require_once('modules/Home/UnifiedSearchAdvanced.php'); require_once 'include/utils.php'; $usa = new UnifiedSearchAdvanced(); if(!file_exists($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php')) { $usa->buildCache(); } - + include($GLOBALS['sugar_config']['cache_dir'].'modules/unified_search_modules.php'); $modules_to_search = array(); $unified_search_modules['Users'] = array('fields' => array()); - + $unified_search_modules['ProjectTask'] = array('fields' => array()); - + //If we are ignoring the unified search flag within the vardef we need to re-create the search fields. This allows us to search //against a specific module even though it is not enabled for the unified search within the application. if( !$unified_search_only ) @@ -425,16 +439,16 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { } } } - - + + foreach($unified_search_modules as $module=>$data) { if (in_array($module, $modules)) { $modules_to_search[$module] = $beanList[$module]; } // if } // foreach - + $GLOBALS['log']->info('SugarWebServiceImpl->search_by_module - search string = ' . $search_string); - + if(!empty($search_string) && isset($search_string)) { $search_string = trim($GLOBALS['db']->quote(securexss(from_html(clean_string($search_string, 'UNIFIED_SEARCH'))))); foreach($modules_to_search as $name => $beanName) { @@ -444,11 +458,11 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { $unifiedSearchFields[$name] [ $field ] = $def ; $unifiedSearchFields[$name] [ $field ]['value'] = $search_string; } - + require_once $beanFiles[$beanName] ; $seed = new $beanName(); require_once 'include/SearchForm/SearchForm2.php' ; - if ($beanName == "User" + if ($beanName == "User" || $beanName == "ProjectTask" ) { if(!self::$helperObject->check_modules_access($current_user, $seed->module_dir, 'read')){ @@ -458,45 +472,45 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { continue; } // if } - - if ($beanName != "User" + + if ($beanName != "User" && $beanName != "ProjectTask" ) { $searchForm = new SearchForm ($seed, $name ) ; - + $searchForm->setup(array ($name => array()) ,$unifiedSearchFields , '' , 'saved_views' /* hack to avoid setup doing further unwanted processing */ ) ; $where_clauses = $searchForm->generateSearchWhere() ; require_once 'include/SearchForm/SearchForm2.php' ; $searchForm = new SearchForm ($seed, $name ) ; - + $searchForm->setup(array ($name => array()) ,$unifiedSearchFields , '' , 'saved_views' /* hack to avoid setup doing further unwanted processing */ ) ; $where_clauses = $searchForm->generateSearchWhere() ; $emailQuery = false; - + $where = ''; if (count($where_clauses) > 0 ) { $where = '('. implode(' ) OR ( ', $where_clauses) . ')'; } - + $mod_strings = return_module_language($current_language, $seed->module_dir); - - if(count($select_fields) > 0) + + if(count($select_fields) > 0) $filterFields = $select_fields; else { if(file_exists('custom/modules/'.$seed->module_dir.'/metadata/listviewdefs.php')) require_once('custom/modules/'.$seed->module_dir.'/metadata/listviewdefs.php'); else require_once('modules/'.$seed->module_dir.'/metadata/listviewdefs.php'); - + $filterFields = array(); foreach($listViewDefs[$seed->module_dir] as $colName => $param) { - if(!empty($param['default']) && $param['default'] == true) + if(!empty($param['default']) && $param['default'] == true) $filterFields[] = strtolower($colName); - } + } if (!in_array('id', $filterFields)) $filterFields[] = 'id'; } - + //Pull in any db fields used for the unified search query so the correct joins will be added $selectOnlyQueryFields = array(); foreach ($unifiedSearchFields[$name] as $field => $def){ @@ -511,14 +525,14 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { $ownerWhere = $seed->getOwnerWhere($assigned_user_id); $where = "($where) AND $ownerWhere"; } - + if( $beanName == "Employee" ) { $where = "($where) AND users.deleted = 0 AND users.is_group = 0 AND users.employee_status = 'Active'"; } - + $list_params = array(); - + $ret_array = $seed->create_new_list_query('', $where, $filterFields, $list_params, 0, '', true, $seed, true); if(empty($params) or !is_array($params)) $params = array(); if(!isset($params['custom_select'])) $params['custom_select'] = ''; @@ -556,7 +570,7 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { } $result = $seed->db->limitQuery($main_query, $offset, $limit + 1); } - + $rowArray = array(); while($row = $seed->db->fetchByAssoc($result)) { $nameValueArray = array(); @@ -572,7 +586,7 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { } // while $output_list[] = array('name' => $name, 'records' => $rowArray); } // foreach - + $GLOBALS['log']->info('End: SugarWebServiceImpl->search_by_module'); return array('entry_list'=>$output_list); } // if @@ -580,6 +594,59 @@ class SugarWebServiceImplv4 extends SugarWebServiceImplv3_1 { } // fn + + public function oauth_request_token() + { + $GLOBALS['log']->info('Begin: SugarWebServiceImpl->oauth_request_token'); + require_once "include/SugarOAuthServer.php"; + try { + $oauth = new SugarOAuthServer($GLOBALS['sugar_config']['site_url'].'service/v4/rest.php'); + $result = $oauth->requestToken()."&oauth_callback_confirmed=true&authorize_url=".$oauth->authURL(); + } catch(OAuthException $e) { + $GLOBALS['log']->debug("OAUTH Exception: $e"); + $errorObject = new SoapError(); + $errorObject->set_error('invalid_login'); + self::$helperObject->setFaultObject($errorObject); + $result = null; + } + $GLOBALS['log']->info('End: SugarWebServiceImpl->oauth_request_token'); + return $result; + } + + public function oauth_access_token() + { + $GLOBALS['log']->info('Begin: SugarWebServiceImpl->oauth_access_token'); + require_once "include/SugarOAuthServer.php"; + try { + $oauth = new SugarOAuthServer(); + $result = $oauth->accessToken(); + } catch(OAuthException $e) { + $GLOBALS['log']->debug("OAUTH Exception: $e"); + $errorObject = new SoapError(); + $errorObject->set_error('invalid_login'); + self::$helperObject->setFaultObject($errorObject); + $result = null; + } + $GLOBALS['log']->info('End: SugarWebServiceImpl->oauth_access_token'); + return $result; + } + + public function oauth_access($session) + { + $GLOBALS['log']->info('Begin: SugarWebServiceImpl->oauth_access'); + $error = new SoapError(); + $output_list = array(); + if (!self::$helperObject->checkSessionAndModuleAccess($session, 'invalid_session', '', '', '', $error)) { + $error->set_error('invalid_login'); + $GLOBALS['log']->info('End: SugarWebServiceImpl->oauth_access'); + $result = $error; + } else { + $result = array('id'=>session_id()); + } + $GLOBALS['log']->info('End: SugarWebServiceImpl->oauth_access'); + return $result; + } + } SugarWebServiceImplv4::$helperObject = new SugarWebServiceUtilv4(); diff --git a/service/v4/SugarWebServiceUtilv4.php b/service/v4/SugarWebServiceUtilv4.php index 16134749..3ab4452f 100644 --- a/service/v4/SugarWebServiceUtilv4.php +++ b/service/v4/SugarWebServiceUtilv4.php @@ -273,7 +273,7 @@ class SugarWebServiceUtilv4 extends SugarWebServiceUtilv3_1 return $results; } - + /** * Processes the filter_fields attribute to use with SugarBean::create_new_list_query() * @@ -287,7 +287,7 @@ class SugarWebServiceUtilv4 extends SugarWebServiceUtilv3_1 $filterFields = array(); foreach($fields as $field) { - if (isset($value->field_defs[$field])) + if (isset($value->field_defs[$field])) { $filterFields[$field] = $value->field_defs[$field]; } @@ -296,98 +296,6 @@ class SugarWebServiceUtilv4 extends SugarWebServiceUtilv3_1 return $filterFields; } - /** - * @see SugarWebServiceUtilv3::getRelationshipResults() - */ - public function getRelationshipResults($bean, $link_field_name, $link_module_fields, $optional_where = '', $order_by = '') - { - $GLOBALS['log']->info('Begin: SoapHelperWebServices->getRelationshipResults'); - require_once('include/TimeDate.php'); - global $beanList, $beanFiles, $current_user; - global $disable_date_format; - - $bean->load_relationship($link_field_name); - if (isset($bean->$link_field_name)) { - // get the query object for this link field - $query_array = $bean->$link_field_name->getQuery(true,array(),0,'',true); - if (isset($query_array['where'])) { - $query_array['where'] = str_ireplace("where", "", $query_array['where']); - if (!empty($optional_where)) { - $optional_where = $query_array['where'] . " and " . $optional_where; - } else { - $optional_where = $query_array['where']; - } // else - } // if - - $params = array(); - $params['joined_tables'] = $query_array['join_tables']; - - // get the related module name and instantiate a bean for that. - $submodulename = $bean->$link_field_name->getRelatedModuleName(); - $submoduleclass = $beanList[$submodulename]; - require_once($beanFiles[$submoduleclass]); - $submodule = new $submoduleclass(); - $filterFields = $this->filter_fields($submodule, $link_module_fields); - $filterFieldsForQuery = $this->filter_fields_for_query($submodule, $filterFields); - $relFields = $bean->$link_field_name->getRelatedFields(); - $roleSelect = ''; - - $idSetInSubModule = false; - if($submodulename == 'Users' && !in_array('id', $link_module_fields)){ - $link_module_fields[] = 'id'; - $idSetInSubModule = true; - } - - if(!empty($relFields)){ - foreach($link_module_fields as $field){ - if(!empty($relFields[$field])){ - $roleSelect .= ', ' . $query_array['join_tables'][0] . '.'. $field; - } - } - } - // create a query - $subquery = $submodule->create_new_list_query($order_by,$optional_where ,$filterFieldsForQuery,$params, 0,'', true,$bean); - $query = $subquery['select'].$roleSelect . $subquery['from'].$query_array['join']. $subquery['where'].$subquery['order_by']; - $GLOBALS['log']->info('SoapHelperWebServices->getRelationshipResults query = ' . $query); - - $result = $submodule->db->query($query, true); - $list = array(); - while($row = $submodule->db->fetchByAssoc($result)) { - if (!$disable_date_format) { - foreach ($filterFields as $field) { - if (isset($submodule->field_defs[$field]) && - isset($submodule->field_defs[$field]['type']) && - isset($row[$field])) { - - if ($submodule->field_defs[$field]['type'] == 'date') { - global $timedate; - $row[$field] = $timedate->to_display_date_time($row[$field]); - } - if ($submodule->field_defs[$field]['type'] == 'currency') { - // TODO: convert data from db to user preferred format absed on the community input - } // if - } // if - - } // foreach - } - if($submodulename == 'Users' && $current_user->id != $row['id']) { - $row['user_hash'] = ""; - } // if - if ($idSetInSubModule) { - unset($row['id']); - } // if - $list[] = $row; - } - $GLOBALS['log']->info('End: SoapHelperWebServices->getRelationshipResults'); - return array('rows' => $list, 'fields_set_on_rows' => $filterFields); - } else { - $GLOBALS['log']->info('End: SoapHelperWebServices->getRelationshipResults - ' . $link_field_name . ' relationship does not exists'); - return false; - } // else - - } // fn - - function get_field_list($value,$fields, $translate=true) { $GLOBALS['log']->info('Begin: SoapHelperWebServices->get_field_list'); @@ -518,7 +426,7 @@ class SugarWebServiceUtilv4 extends SugarWebServiceUtilv3_1 return array('module_fields' => $module_fields, 'link_fields' => $link_fields); } - + function new_handle_set_entries($module_name, $name_value_lists, $select_fields = FALSE) { $GLOBALS['log']->info('Begin: SoapHelperWebServices->new_handle_set_entries'); global $beanList, $beanFiles, $current_user, $app_list_strings; @@ -554,7 +462,7 @@ class SugarWebServiceUtilv4 extends SugarWebServiceUtilv3_1 $field_name = $value['name']; $val = $value['value']; } - + if($seed->field_name_map[$field_name]['type'] == 'enum'){ $vardef = $seed->field_name_map[$field_name]; if(isset($app_list_strings[$vardef['options']]) && !isset($app_list_strings[$vardef['options']][$val]) ) { @@ -673,5 +581,52 @@ class SugarWebServiceUtilv4 extends SugarWebServiceUtilv3_1 ); } } - + + + function checkSessionAndModuleAccess($session, $login_error_key, $module_name, $access_level, $module_access_level_error_key, $errorObject) + { + if(isset($_REQUEST['oauth_token'])) { + $session = $this->checkOAuthAccess($errorObject); + } + if(!$session) return false; + return parent::checkSessionAndModuleAccess($session, $login_error_key, $module_name, $access_level, $module_access_level_error_key, $errorObject); + } + + public function checkOAuthAccess($errorObject) + { + require_once "include/SugarOAuthServer.php"; + try { + $oauth = new SugarOAuthServer(); + $token = $oauth->authorizedToken(); + if(empty($token) || empty($token->assigned_user_id)) { + return false; + } + } catch(OAuthException $e) { + $GLOBALS['log']->debug("OAUTH Exception: $e"); + $errorObject->set_error('invalid_login'); + $this->setFaultObject($errorObject); + return false; + } + + $user = new User(); + $user->retrieve($token->assigned_user_id); + if(empty($user->id)) { + return false; + } + global $current_user; + $current_user = $user; + ini_set("session.use_cookies", 0); // disable cookies to prevent session ID from going out + session_start(); + session_regenerate_id(); + $_SESSION['oauth'] = $oauth->authorization(); + $_SESSION['avail_modules'] = $this->get_user_module_list($user); + // TODO: handle role + // handle session + $_SESSION['is_valid_session']= true; + $_SESSION['ip_address'] = query_client_ip(); + $_SESSION['user_id'] = $current_user->id; + $_SESSION['type'] = 'user'; + $_SESSION['authenticated_user_id'] = $current_user->id; + return session_id(); + } } \ No newline at end of file diff --git a/soap/SoapHelperFunctions.php b/soap/SoapHelperFunctions.php index 0971dfa6..6c17b3d8 100644 --- a/soap/SoapHelperFunctions.php +++ b/soap/SoapHelperFunctions.php @@ -970,20 +970,6 @@ function check_for_duplicate_contacts($seed){ } return null; } - }else{ - $query = "contacts.last_name = '".$seed->db->quote($trimmed_last,false)."'"; - $query .= " AND contacts.first_name = '".$seed->db->quote($trimmed_first,false)."'"; - $contacts = $seed->get_list('', $query); - if (count($contacts) == 0){ - return null; - }else{ - foreach($contacts['list'] as $contact){ - if (empty($contact->email1)){ - return $contact->id; - } - } - return null; - } } } diff --git a/soap/SoapPortalUsers.php b/soap/SoapPortalUsers.php index ccfc1ac1..639f67d7 100644 --- a/soap/SoapPortalUsers.php +++ b/soap/SoapPortalUsers.php @@ -420,7 +420,10 @@ function portal_set_entry($session,$module_name, $name_value_list){ } $id = $seed->save(); }else{ - $seed->contact_id = $_SESSION['user_id']; + $contact = new Contact(); + $contact->disable_row_level_security = TRUE; + $contact->retrieve($_SESSION['user_id']); + $seed->contact_id = $contact; if(isset( $_SESSION['account_id'])){ $seed->account_id = $_SESSION['account_id']; diff --git a/sugar_version.php b/sugar_version.php index 8bc70ef5..289d526f 100644 --- a/sugar_version.php +++ b/sugar_version.php @@ -38,10 +38,10 @@ -$sugar_version = '6.2.4'; -$sugar_db_version = '6.2.4'; +$sugar_version = '6.3.0'; +$sugar_db_version = '6.3.0'; $sugar_flavor = 'CE'; -$sugar_build = '6735'; -$sugar_timestamp = '2011-10-21 12:40pm'; +$sugar_build = '7004'; +$sugar_timestamp = '2011-11-09 05:10pm'; ?> diff --git a/tests/ModuleInstall/ExtTest.php b/tests/ModuleInstall/ExtTest.php new file mode 100755 index 00000000..b0a60cd0 --- /dev/null +++ b/tests/ModuleInstall/ExtTest.php @@ -0,0 +1,189 @@ +is_admin = "1"; + $GLOBALS['current_language'] = "en_us"; + $GLOBALS['app_strings'] = return_application_language($GLOBALS['current_language']); + $GLOBALS['mod_strings'] = return_module_language($GLOBALS['current_language'], 'Administration'); + mkdir_recursive("cache/ExtTest"); + } + + public function setUp() + { + $this->module_installer = new ModuleInstaller(); + $this->module_installer->silent = true; + $this->module_installer->base_dir = "cache/ExtTest"; + $this->module_installer->id_name = 'ExtFrameworkTest'; + $this->testvalue = uniqid("ext", true); + file_put_contents($this->module_installer->base_dir."/test.ext.php", "testvalue';"); + } + + public function tearDown() + { + if($this->module_installer) { + $this->module_installer->uninstall_extensions(); + } + if(file_exists($this->module_installer->base_dir."/test.ext.php")) { + @unlink($this->module_installer->base_dir."/test.ext.php"); + } + } + + public static function tearDownAfterClass() + { + SugarTestUserUtilities::removeAllCreatedAnonymousUsers(); + unset($GLOBALS['current_user']); + unset($GLOBALS['current_language']); + unset($GLOBALS['app_strings']); + unset($GLOBALS['mod_strings']); + if(file_exists("cache/ExtTest/test.ext.php")) { + @unlink("cache/ExtTest/test.ext.php"); + } + rmdir_recursive("cache/ExtTest"); + } + + public function getExt() + { + include 'ModuleInstall/extensions.php'; + $params = array(); + foreach($extensions as $name => $ext) { + if($name == 'modules') continue; + $params[] = array($name, $ext['section'], $ext['extdir'], $ext['file'], isset($ext['module'])?$ext['module']:''); + } + return $params; + } + + /** + * @dataProvider getExt + * @param string $extname + * @param string $section + * @param string $dir + * @param string $file + * @param string $module + */ + public function testExtFramework($extname, $section, $extdir, $file, $module = '') + { + if(empty($module)) { + $module = 'application'; + } + $this->module_installer->installdefs[$section] = array( + array("from" => '/test.ext.php', 'to_module' => $module) + ); + $prefix = ''; + $srcFileName = "test.ext.php"; + if($extname == 'languages') { + $this->module_installer->installdefs[$section][0]['language'] = 'en_us'; + $prefix = 'en_us.'; + $file = 'lang.ext.php'; + $srcFileName = "ExtFrameworkTest.php"; + } + if($module == 'application') { + $srcfile = "custom/Extension/application/Ext/$extdir/{$prefix}{$srcFileName}"; + $dstfile = "custom/application/Ext/$extdir/{$prefix}$file"; + } else { + $srcfile = "custom/Extension/modules/$module/Ext/$extdir/{$prefix}{$srcFileName}"; + $dstfile = "custom/modules/$module/Ext/$extdir/{$prefix}$file"; + } + $this->module_installer->install_extensions(); + // check file is there + $this->assertFileExists($srcfile); + $testvalue = null; + // check it works + include($dstfile); + $this->assertEquals($this->testvalue, $testvalue); + $testvalue = null; + // check disable + $this->module_installer->disable_extensions(); + if(file_exists($dstfile)) include($dstfile); + $this->assertNull($testvalue); + // check enable + $this->module_installer->enable_extensions(); + $this->assertFileExists($srcfile); + include($dstfile); + $this->assertEquals($this->testvalue, $testvalue); + $testvalue = null; + // check uninstall + $this->module_installer->uninstall_extensions(); + if(file_exists($dstfile)) include($dstfile); + $this->assertNull($testvalue); + } + + public function testExtModules() + { + $this->module_installer->installdefs['beans'] = array( + array( + 'module' => 'ExtFrameworkTest', + 'class' => 'ExtFrameworkTest', + 'path' => 'ExtFrameworkTest', + 'tab' => true + ) + ); + $srcfile = "custom/Extension/application/Ext/Include/ExtFrameworkTest.php"; + $dstfile = "custom/application/Ext/Include/modules.ext.php"; + $this->module_installer->install_extensions(); + // check file is there + $this->assertFileExists($srcfile); + $beanList = null; + // check it works + include($dstfile); + $this->assertEquals('ExtFrameworkTest', $beanList['ExtFrameworkTest']); + // check disable + $this->module_installer->disable_extensions(); + $beanList = array(); + if(file_exists($dstfile)) include($dstfile); + $this->assertArrayNotHasKey('ExtFrameworkTest', $beanList); + // check enable + $beanList = array(); + $this->module_installer->enable_extensions(); + $this->assertFileExists($srcfile); + include($dstfile); + $this->assertEquals('ExtFrameworkTest', $beanList['ExtFrameworkTest']); + $beanList = array(); + // check uninstall + $this->module_installer->uninstall_extensions(); + if(file_exists($dstfile)) include($dstfile); + $this->assertArrayNotHasKey('ExtFrameworkTest', $beanList); + } +} diff --git a/tests/SugarTestHelper.php b/tests/SugarTestHelper.php index 9c516fd5..50beaf46 100755 --- a/tests/SugarTestHelper.php +++ b/tests/SugarTestHelper.php @@ -124,6 +124,13 @@ class Sugar_PHPUnit_Framework_TestCase extends PHPUnit_Framework_TestCase protected $useOutputBuffering = true; + protected function assertPreConditions() + { + if(isset($GLOBALS['log'])) { + $GLOBALS['log']->info("START TEST: {$this->getName(false)}"); + } + } + protected function assertPostConditions() { if(!empty($_REQUEST)) { foreach(array_keys($_REQUEST) as $k) { @@ -142,11 +149,16 @@ class Sugar_PHPUnit_Framework_TestCase extends PHPUnit_Framework_TestCase unset($_GET[$k]); } } + if(isset($GLOBALS['log'])) { + $GLOBALS['log']->info("DONE TEST: {$this->getName(false)}"); + } } public static function tearDownAfterClass() { unset($GLOBALS['disable_date_format']); + unset($GLOBALS['saving_relationships']); + unset($GLOBALS['updating_relationships']); $GLOBALS['timedate']->clearCache(); } } diff --git a/tests/SugarTestImportUtilities.php b/tests/SugarTestImportUtilities.php index 5e8d2e00..fb387b7b 100755 --- a/tests/SugarTestImportUtilities.php +++ b/tests/SugarTestImportUtilities.php @@ -48,12 +48,9 @@ class SugarTestImportUtilities self::removeAllCreatedFiles(); } - public static function createFile( - $lines = 2000, - $columns = 3 - ) + public static function createFile($lines = 2000,$columns = 3, $dir = 'upload_dir') { - $filename = $GLOBALS['sugar_config']['import_dir'].'test'.date("YmdHis"); + $filename = $GLOBALS['sugar_config'][$dir].'test'. uniqid(); $fp = fopen($filename,"w"); for ($i = 0; $i < $lines; $i++) { $line = array(); @@ -73,7 +70,7 @@ class SugarTestImportUtilities $columns = 3 ) { - $filename = $GLOBALS['sugar_config']['import_dir'].'test'.date("YmdHis"); + $filename = $GLOBALS['sugar_config']['upload_dir'].'test'.date("YmdHis"); $fp = fopen($filename,"w"); for ($i = 0; $i < $lines; $i++) { $line = array(); @@ -92,7 +89,7 @@ class SugarTestImportUtilities public static function createFileWithWhiteSpace() { - $filename = $GLOBALS['sugar_config']['import_dir'].'testWhiteSpace'.date("YmdHis"); + $filename = $GLOBALS['sugar_config']['upload_dir'].'testWhiteSpace'.date("YmdHis"); $contents = <<query(sprintf("DELETE FROM meetings_contacts WHERE meeting_id IN ('%s')", implode("', '", $meeting_ids))); } + public static function addMeetingLeadRelation($meeting_id, $lead_id) { + $id = create_guid(); + $GLOBALS['db']->query("INSERT INTO meetings_leads (id, meeting_id, lead_id) values ('{$id}', '{$meeting_id}', '{$lead_id}')"); + return $id; + } + + public static function deleteMeetingLeadRelation($id) { + $GLOBALS['db']->query("delete from meetings_leads where id='{$id}'"); + } + + + public static function addMeetingParent($meeting_id, $lead_id) { + $sql = "update meetings set parent_type='Leads', parent_id='{$lead_id}' where id='{$meeting_id}'"; + $GLOBALS['db']->query($sql); + } + public static function removeMeetingUsers() { $meeting_ids = self::getCreatedMeetingIds(); $GLOBALS['db']->query(sprintf("DELETE FROM meetings_users WHERE meeting_id IN ('%s')", implode("', '", $meeting_ids))); } + public static function getCreatedMeetingIds() { $meeting_ids = array(); diff --git a/tests/SugarTestUserUtilities.php b/tests/SugarTestUserUtilities.php index 47ecab95..f39cc866 100755 --- a/tests/SugarTestUserUtilities.php +++ b/tests/SugarTestUserUtilities.php @@ -48,7 +48,7 @@ class SugarTestUserUtilities self::removeAllCreatedAnonymousUsers(); } - public static function createAnonymousUser($save = true) + public static function createAnonymousUser($save = true, $is_admin=0) { if (isset($_REQUEST['action'])) { unset($_REQUEST['action']); @@ -62,6 +62,9 @@ class SugarTestUserUtilities $user->first_name = $userId; $user->last_name = $time; $user->status='Active'; + if ($is_admin) { + $user->is_admin = 1; + } if ( $save ) { $user->save(); } diff --git a/tests/data/Bug39780Test.php b/tests/data/Bug39780Test.php index 1a6fa8e3..54db5970 100755 --- a/tests/data/Bug39780Test.php +++ b/tests/data/Bug39780Test.php @@ -39,20 +39,22 @@ class Bug39780Test extends Sugar_PHPUnit_Framework_TestCase { protected $contact; - + public function setUp() { $GLOBALS['current_user'] = SugarTestUserUtilities::createAnonymousUser(); $this->contact = SugarTestContactUtilities::createContact(); + $this->defs = $this->contact->field_defs; } - + public function tearDown() { + $this->contact->field_defs = $this->defs; SugarTestUserUtilities::removeAllCreatedAnonymousUsers(); unset($GLOBALS['current_user']); SugarTestContactUtilities::removeAllCreatedContacts(); } - + // Test unPopulateDefaultValues to make sure it doesn't generate any notices /* * @group bug39780 @@ -68,7 +70,7 @@ class Bug39780Test extends Sugar_PHPUnit_Framework_TestCase $this->assertTrue(false, "SugarBean->unPopulateDefaultValues is generating a notice/warning/fatal: " .$e->getMessage()); return; } - + $this->assertTrue(true); } } diff --git a/tests/data/Bug40989Test.php b/tests/data/Bug40989Test.php index 5ae46727..2037fe6f 100755 --- a/tests/data/Bug40989Test.php +++ b/tests/data/Bug40989Test.php @@ -65,7 +65,7 @@ class Bug40989 extends Sugar_PHPUnit_Framework_TestCase unset($GLOBALS['current_user']); SugarTestContactUtilities::removeAllCreatedContacts(); } - + /* * @group bug40989 */ diff --git a/tests/include/SugarFields/Fields/Encrypt/SugarFieldEncryptTest.php b/tests/data/Bug47949Test.php similarity index 70% rename from tests/include/SugarFields/Fields/Encrypt/SugarFieldEncryptTest.php rename to tests/data/Bug47949Test.php index 90299769..bb9ca5d9 100755 --- a/tests/include/SugarFields/Fields/Encrypt/SugarFieldEncryptTest.php +++ b/tests/data/Bug47949Test.php @@ -1,4 +1,5 @@ -markTestSkipped('Marking this skipped until we figure out why it is failing.'); $GLOBALS['current_user'] = SugarTestUserUtilities::createAnonymousUser(); - } - + } + public function tearDown() { SugarTestUserUtilities::removeAllCreatedAnonymousUsers(); unset($GLOBALS['current_user']); } - - public function _providerEmailTemplateFormat() - { - require_once("include/utils/encryption_utils.php"); - return array( - array(blowfishEncode(blowfishGetKey('encrypt_field'),'Test value'), 'Test value'), - ); - } - - /** - * @dataProvider _providerEmailTemplateFormat + + /* + * @group bug47949 */ - public function testEmailTemplateFormat($unformattedValue, $expectedValue) - { - require_once('include/SugarFields/SugarFieldHandler.php'); - $sfr = SugarFieldHandler::getSugarField('encrypt'); - $formattedValue = $sfr->getEmailTemplateValue($unformattedValue,array(), array('notify_user' => $GLOBALS['current_user'])); - $this->assertEquals($expectedValue, $formattedValue); + public function testGetRelatedBean() + { + $team_id = 1; + $case = new aCase(); + $case->name = 'testBug47949'; + $case->team_id = $team_id; + $case->team_set_id = 1; + $case->save(); + + $beans = $case->get_linked_beans('teams', 'Team'); + + // teams is based on Link (not Link2), should still work + $this->assertEquals(1, count($beans), 'should have one and only one team'); + $this->assertEquals($team_id, $beans[0]->id, 'incorrect team id, should be ' . $team_id); + + // cleanup + $GLOBALS['db']->query("delete from cases where id= '{$case->id}'"); } } - -?> \ No newline at end of file diff --git a/tests/include/Bug33806.php b/tests/include/Bug33806.php new file mode 100755 index 00000000..e89e26ab --- /dev/null +++ b/tests/include/Bug33806.php @@ -0,0 +1,92 @@ + 'Account', 'module' => 'Accounts'), + array( 'singular' => 'Contact', 'module' => 'Contacts'), + ); + } + + /** + * Test the getMime function for the use case where the mime type is already provided. + * + * @dataProvider _moduleNameProvider + */ + public function testGetModuleFromSingular($singular, $expectedName) + { + $GLOBALS['app_list_strings'] = return_app_list_strings_language($GLOBALS['current_language']); + + $module = get_module_from_singular($singular); + + $this->assertEquals($expectedName, $module); + } + + function _moduleNameProvider2() + { + return array( + array( 'renamed' => 'Acct', 'module' => 'Accounts'), + ); + } + + /** + * Test the getMime function for the use case where the mime type is already provided. + * + * @dataProvider _moduleNameProvider2 + */ + public function testGetModuleFromRenamed($renamed, $expectedName) + { + $GLOBALS['app_list_strings'] = return_app_list_strings_language($GLOBALS['current_language']); + + // manually rename the module name to 'Acct' + $GLOBALS['app_list_strings']['moduleList']['Accounts'] = 'Acct'; + + $module = get_module_from_singular($renamed); + + $this->assertEquals($expectedName, $module); + } +} diff --git a/tests/include/ListView/ListViewDisplayTest.php b/tests/include/ListView/ListViewDisplayTest.php index 885d13e9..ba384fd6 100755 --- a/tests/include/ListView/ListViewDisplayTest.php +++ b/tests/include/ListView/ListViewDisplayTest.php @@ -333,8 +333,8 @@ class ListViewDisplayTest extends Sugar_PHPUnit_Framework_TestCase public function testBuildMassUpdateLink() { $output = $this->_lvd->buildMassUpdateLink(); - - $this->assertContains("assertRegExp("/.*document\.getElementById\(['\"]massupdate_form['\"]\)\.style\.display\s*=\s*['\"]['\"].*/", $output); } public function testComposeEmailIfFieldDefsNotAnArray() @@ -392,6 +392,7 @@ class ListViewDisplayTest extends Sugar_PHPUnit_Framework_TestCase $this->_lvd->seed = new stdClass; $this->_lvd->seed->object_name = 'foobar'; $this->_lvd->seed->module_dir = 'foobarfoobar'; + $_REQUEST['module'] = 'foobarfoobar'; $this->_lvd->seed->field_defs = array( 'field1' => array( 'type' => 'link', diff --git a/tests/include/MVC/SugarApplicationTest.php b/tests/include/MVC/SugarApplicationTest.php index 4012d7be..679913a4 100755 --- a/tests/include/MVC/SugarApplicationTest.php +++ b/tests/include/MVC/SugarApplicationTest.php @@ -52,6 +52,12 @@ class SugarApplicationTest extends Sugar_PHPUnit_Framework_TestCase $this->_app = new SugarApplicationMock(); if ( isset($_SESSION['authenticated_user_theme']) ) unset($_SESSION['authenticated_user_theme']); + + if ( isset($GLOBALS['sugar_config']['http_referer']) ) { + $this->prevRefererList = $GLOBALS['sugar_config']['http_referer']; + } + + $GLOBALS['sugar_config']['http_referer'] = array('list' => array(), 'actions' => array()); } private function _loadUser() @@ -66,6 +72,7 @@ class SugarApplicationTest extends Sugar_PHPUnit_Framework_TestCase unset($GLOBALS['current_user']); } + public function tearDown() { unset($GLOBALS['current_user']); @@ -84,6 +91,12 @@ class SugarApplicationTest extends Sugar_PHPUnit_Framework_TestCase unset($GLOBALS['sugar_version']); unset($GLOBALS['sugar_flavor']); $GLOBALS['current_language'] = $GLOBALS['sugar_config']['default_language']; + + if ( isset($this->prevRefererList)) { + $GLOBALS['sugar_config']['http_referer'] = $this->prevRefererList; + } else { + unset ($GLOBALS['sugar_config']['http_referer']); + } } public function testSetupPrint() @@ -259,16 +272,9 @@ class SugarApplicationTest extends Sugar_PHPUnit_Framework_TestCase $_SERVER['SERVER_NAME'] = 'cat'; $this->_app->controller->action = 'index'; - if ( !empty($GLOBALS['sugar_config']['http_referer']['list']) ) { - $prevRefererList = $GLOBALS['sugar_config']['http_referer']['list']; - } - $GLOBALS['sugar_config']['http_referer']['list'][] = 'http://dog'; - + $GLOBALS['sugar_config']['http_referer']['list'][] = 'dog'; + $this->assertTrue($this->_app->checkHTTPReferer()); - - if ( isset($prevRefererList) ) { - $GLOBALS['sugar_config']['http_referer']['list'] = $prevRefererList; - } } public function testCheckHTTPRefererReturnsFalseIfRefererIsNotInWhitelist() @@ -276,7 +282,9 @@ class SugarApplicationTest extends Sugar_PHPUnit_Framework_TestCase $_SERVER['HTTP_REFERER'] = 'http://dog'; $_SERVER['SERVER_NAME'] = 'cat'; $this->_app->controller->action = 'poo'; - + + $GLOBALS['sugar_config']['http_referer']['list'] = array(); + $this->assertFalse($this->_app->checkHTTPReferer()); } @@ -285,7 +293,7 @@ class SugarApplicationTest extends Sugar_PHPUnit_Framework_TestCase $_SERVER['HTTP_REFERER'] = 'http://dog'; $_SERVER['SERVER_NAME'] = 'cat'; $this->_app->controller->action = 'index'; - + $this->assertTrue($this->_app->checkHTTPReferer()); } @@ -295,16 +303,9 @@ class SugarApplicationTest extends Sugar_PHPUnit_Framework_TestCase $_SERVER['SERVER_NAME'] = 'cat'; $this->_app->controller->action = 'poo'; - if ( !empty($GLOBALS['sugar_config']['http_referer']['actions']) ) { - $prevRefererList = $GLOBALS['sugar_config']['http_referer']['actions']; - } $GLOBALS['sugar_config']['http_referer']['actions'][] = 'poo'; $this->assertTrue($this->_app->checkHTTPReferer()); - - if ( isset($prevRefererList) ) { - $GLOBALS['sugar_config']['http_referer']['actions'] = $prevRefererList; - } } } diff --git a/tests/include/MVC/View/views/Bug47572Test.php b/tests/include/MVC/View/views/Bug47572Test.php new file mode 100755 index 00000000..969637d6 --- /dev/null +++ b/tests/include/MVC/View/views/Bug47572Test.php @@ -0,0 +1,61 @@ +module = 'Cases'; + ViewFactory::_loadConfig($view, $type); + + $_REQUEST['print'] = true; + $view->preDisplay(); + + $this->assertFalse($view->options['show_subpanels'], 'show_subpanels should be false for print'); + } +} \ No newline at end of file diff --git a/tests/include/SearchForm/Bug43452Test.php b/tests/include/SearchForm/Bug43452Test.php index f6dcf5d1..efa31889 100755 --- a/tests/include/SearchForm/Bug43452Test.php +++ b/tests/include/SearchForm/Bug43452Test.php @@ -1,4 +1,39 @@ hasExistingCustomSearchFields = true; + copy('custom/modules/Cases/metadata/SearchFields.php', 'custom/modules/Cases/metadata/SearchFields.php.bak'); + unlink('custom/modules/Cases/metadata/SearchFields.php'); + } else if(!file_exists('custom/modules/Cases/metadata')) { + mkdir_recursive('custom/modules/Cases/metadata'); + } + + //Setup Opportunities module and date_closed field + $_REQUEST['view_module'] = 'Cases'; + $_REQUEST['name'] = 'date_closed'; + $templateDate = new TemplateDate(); + $templateDate->enable_range_search = true; + $templateDate->populateFromPost(); + include('custom/modules/Cases/metadata/SearchFields.php'); + + //Prepare SearchForm + $seed = new aCase(); + $module = 'Cases'; + $this->searchForm = new SearchForm($seed, $module); + $this->searchForm->searchFields = array( + 'range_case_number' => array + ( + 'query_type' => 'default', + 'enable_range_search' => true + ), + ); + $this->originalDbType = $GLOBALS['db']->dbType; + } + + public function tearDown() + { + $GLOBALS['db']->dbType = $this->originalDbType; + + if(!$this->hasExistingCustomSearchFields) + { + unlink('custom/modules/Cases/metadata/SearchFields.php'); + } + + if(file_exists('custom/modules/Cases/metadata/SearchFields.php.bak')) { + copy('custom/modules/Cases/metadata/SearchFields.php.bak', 'custom/modules/Cases/metadata/SearchFields.php'); + unlink('custom/modules/Cases/metadata/SearchFields.php.bak'); + } + + if(file_exists($this->smartyTestFile)) + { + unlink($this->smartyTestFile); + } + + } + + public function testRangeNumberSearches() + { + $GLOBALS['db']->dbType = 'mysql'; + + $this->searchForm->searchFields['range_case_number'] = array ( + 'query_type' => 'default', + 'enable_range_search' => 1, + 'value' => '0', + 'operator' => '=', + ); + + $where_clauses = $this->searchForm->generateSearchWhere(); + $this->assertEquals("cases.case_number = '0'", $where_clauses[0], 'Unexpected where clause'); + } +} +?> \ No newline at end of file diff --git a/tests/include/Smarty/plugins/FunctionSugarLinkTest.php b/tests/include/Smarty/plugins/FunctionSugarLinkTest.php index 57b956e2..6a6a4415 100755 --- a/tests/include/Smarty/plugins/FunctionSugarLinkTest.php +++ b/tests/include/Smarty/plugins/FunctionSugarLinkTest.php @@ -53,7 +53,7 @@ class FunctionSugarLinkTest extends Sugar_PHPUnit_Framework_TestCase array('module'=>'Dog','link_only'=>'1'), $this->_smarty); - $this->assertContains("index.php?module=Dog&action=index",$output); + $this->assertContains(ajaxLink("index.php?module=Dog&action=index"),$output); } public function testReturnModuleLinkWithAction() @@ -62,7 +62,7 @@ class FunctionSugarLinkTest extends Sugar_PHPUnit_Framework_TestCase array('module'=>'Dog','action'=>'cat','link_only'=>'1'), $this->_smarty); - $this->assertContains("index.php?module=Dog&action=cat",$output); + $this->assertContains(ajaxLink("index.php?module=Dog&action=cat"),$output); } public function testReturnModuleLinkWithActionAndExtraParams() @@ -71,7 +71,7 @@ class FunctionSugarLinkTest extends Sugar_PHPUnit_Framework_TestCase array('module'=>'Dog','action'=>'cat','extraparams'=>'foo=bar','link_only'=>'1'), $this->_smarty); - $this->assertContains("index.php?module=Dog&action=cat&foo=bar",$output); + $this->assertContains(ajaxLink("index.php?module=Dog&action=cat&foo=bar"),$output); } /** @@ -92,7 +92,7 @@ class FunctionSugarLinkTest extends Sugar_PHPUnit_Framework_TestCase array('module'=>'Dog','data'=>$data,'link_only'=>'1'), $this->_smarty); - $this->assertContains("index.php?module=iFrames&action=index&record=63edeacd-6ba5-b658-5e2a-4af9a5d682be&tab=true",$output); + $this->assertContains(ajaxLink("index.php?module=iFrames&action=index&record=63edeacd-6ba5-b658-5e2a-4af9a5d682be&tab=true"),$output); } public function testCreatingFullLink() @@ -112,7 +112,7 @@ class FunctionSugarLinkTest extends Sugar_PHPUnit_Framework_TestCase $this->_smarty); $this->assertContains( - 'foo3',$output); + 'foo3',$output); } } diff --git a/tests/include/SugarEmailAddress/Bug41557Test.php b/tests/include/SugarEmailAddress/Bug41557Test.php new file mode 100755 index 00000000..0711b3eb --- /dev/null +++ b/tests/include/SugarEmailAddress/Bug41557Test.php @@ -0,0 +1,88 @@ +emailAddress->addAddress($oldemail, true, false); + $user->emailAddress->save($user->id, $user->module_dir); + + $this->assertEquals($oldemail, $user->emailAddress->getPrimaryAddress($user), 'Primary email should be '.$oldemail); + + // second email + $user->emailAddress->addAddress($newemail, true, false); + + // simulate lead conversion mode + if ($conversion) { + $_REQUEST['action'] = 'ConvertLead'; + } + $user->emailAddress->save($user->id, $user->module_dir); + + $query = "select count(*) as CNT from email_addr_bean_rel eabr WHERE eabr.bean_id = '{$user->id}' AND eabr.bean_module = 'Users' and primary_address = 1 and eabr.deleted=0"; + $result = $GLOBALS['db']->query($query); + $count = $GLOBALS['db']->fetchByAssoc($result); + $this->assertEquals($primary_count, $count['CNT'], 'Incorrect primary email count'); + + // cleanup + SugarTestUserUtilities::removeAllCreatedAnonymousUsers(); + } +} diff --git a/tests/include/SugarFields/Fields/Currency/Bug38424CurrencyTest.php b/tests/include/SugarFields/Fields/Currency/Bug38424CurrencyTest.php index 7db93d4a..192dc8f3 100755 --- a/tests/include/SugarFields/Fields/Currency/Bug38424CurrencyTest.php +++ b/tests/include/SugarFields/Fields/Currency/Bug38424CurrencyTest.php @@ -34,6 +34,7 @@ * "Powered by SugarCRM". ********************************************************************************/ + require_once('include/SugarFields/Fields/Currency/SugarFieldCurrency.php'); class Bug38424CurrencyTest extends Sugar_PHPUnit_Framework_TestCase diff --git a/tests/include/SugarFields/Fields/Float/Bug38424FloatTest.php b/tests/include/SugarFields/Fields/Float/Bug38424FloatTest.php index 3ac55e92..82b4bfa9 100755 --- a/tests/include/SugarFields/Fields/Float/Bug38424FloatTest.php +++ b/tests/include/SugarFields/Fields/Float/Bug38424FloatTest.php @@ -34,6 +34,7 @@ * "Powered by SugarCRM". ********************************************************************************/ + require_once('include/SugarFields/Fields/Float/SugarFieldFloat.php'); class Bug38424FloatTest extends Sugar_PHPUnit_Framework_TestCase diff --git a/tests/include/SugarFields/Fields/Int/Bug38424IntTest.php b/tests/include/SugarFields/Fields/Int/Bug38424IntTest.php index c706fa0f..aaf0c315 100755 --- a/tests/include/SugarFields/Fields/Int/Bug38424IntTest.php +++ b/tests/include/SugarFields/Fields/Int/Bug38424IntTest.php @@ -34,6 +34,7 @@ * "Powered by SugarCRM". ********************************************************************************/ + require_once('include/SugarFields/Fields/Int/SugarFieldInt.php'); class Bug38424IntTest extends Sugar_PHPUnit_Framework_TestCase diff --git a/tests/include/SugarFolders/SugarFoldersTest.php b/tests/include/SugarFolders/SugarFoldersTest.php index c700e196..7c27045d 100755 --- a/tests/include/SugarFolders/SugarFoldersTest.php +++ b/tests/include/SugarFolders/SugarFoldersTest.php @@ -55,7 +55,16 @@ class SugarFoldersTest extends Sugar_PHPUnit_Framework_TestCase $this->folder = new SugarFolder(); $this->additionalFolders = array(); $this->emails = array(); - } + $beanList = array(); + $beanFiles = array(); + require('include/modules.php'); + $GLOBALS['beanList'] = $beanList; + $GLOBALS['beanFiles'] = $beanFiles; + if (empty($GLOBALS['current_language'])) { + $GLOBALS['current_language'] = 'en_us'; + } + $GLOBALS['app_strings'] = return_application_language($GLOBALS['current_language']); + } public function tearDown() { diff --git a/tests/include/TimeDateTest.php b/tests/include/TimeDateTest.php index c61b2351..feb8ec29 100755 --- a/tests/include/TimeDateTest.php +++ b/tests/include/TimeDateTest.php @@ -34,7 +34,7 @@ * "Powered by SugarCRM". ********************************************************************************/ - + require_once 'include/TimeDate.php'; class TimeDateTest extends Sugar_PHPUnit_Framework_TestCase @@ -899,4 +899,35 @@ class TimeDateTest extends Sugar_PHPUnit_Framework_TestCase $f = $this->time_date->get_date_time_format($current_user); $this->assertEquals("Y-m-d H:i", $f); } + + public function dateRanges() + { + return array( + array("yesterday", "2011-08-29 00:00:00", "2011-08-29 23:59:59"), + array("today", "2011-08-30 00:00:00", "2011-08-30 23:59:59"), + array("tomorrow", "2011-08-31 00:00:00", "2011-08-31 23:59:59"), + array("last_7_days", "2011-08-24 00:00:00", "2011-08-30 23:59:59"), + array("next_7_days", "2011-08-30 00:00:00", "2011-09-05 23:59:59"), + array("last_30_days", "2011-08-01 00:00:00", "2011-08-30 23:59:59"), + array("next_30_days", "2011-08-30 00:00:00", "2011-09-28 23:59:59"), + array("next_month", "2011-09-01 00:00:00", "2011-09-30 23:59:59"), + array("last_month", "2011-07-01 00:00:00", "2011-07-31 23:59:59"), + array("this_month", "2011-08-01 00:00:00", "2011-08-31 23:59:59"), + array("next_year", "2012-01-01 00:00:00", "2012-12-31 23:59:59"), + array("last_year", "2010-01-01 00:00:00", "2010-12-31 23:59:59"), + array("this_year", "2011-01-01 00:00:00", "2011-12-31 23:59:59"), + ); + } + + /** + * @dataProvider dateRanges + */ + public function testparseDateRange($range, $start, $end) + { + $this->time_date->setNow(SugarDateTime::createFromFormat(TimeDate::DB_DATETIME_FORMAT, "2011-08-30 12:01:02", new DateTimeZone($this->time_date->userTimezone()))); + $this->time_date->allow_cache = true; + $daterage = $this->time_date->parseDateRange($range); + $this->assertEquals($start, $daterage[0]->format(TimeDate::DB_DATETIME_FORMAT), 'Start date is wrong'); + $this->assertEquals($end, $daterage[1]->format(TimeDate::DB_DATETIME_FORMAT), 'End date is wrong'); + } } diff --git a/tests/include/ValidDBNameTest.php b/tests/include/ValidDBNameTest.php index ed029861..9bc5fecc 100755 --- a/tests/include/ValidDBNameTest.php +++ b/tests/include/ValidDBNameTest.php @@ -46,14 +46,6 @@ class ValidDBNameTest extends Sugar_PHPUnit_Framework_TestCase getValidDBName('idx_test_123_id') ); } - - public function testLongNameEffected() - { - $this->assertNotEquals( - getValidDBName('eeeee_eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_opportunities'), - getValidDBName('eeeee_eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1_opportunities') - ); - } public function testmaxLengthParam() { @@ -119,4 +111,12 @@ class ValidDBNameTest extends Sugar_PHPUnit_Framework_TestCase $this->assertFalse(isValidDBName('sugar crm', 'mssql')); $this->assertFalse(isValidDBName('#sugarCRM_ver6', 'mssql')); } + + public function testLongNameEffected() + { + $this->assertNotEquals( + getValidDBName('eeeee_eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_opportunities', true), + getValidDBName('eeeee_eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee1_opportunities', true) + ); + } } diff --git a/tests/include/generic/SugarWidgets/Bug44272Test.php b/tests/include/generic/SugarWidgets/Bug44272Test.php index a3d2b02a..26053f14 100755 --- a/tests/include/generic/SugarWidgets/Bug44272Test.php +++ b/tests/include/generic/SugarWidgets/Bug44272Test.php @@ -46,18 +46,18 @@ var $account; public function setUp() { - require('include/modules.php'); - $GLOBALS['beanList'] = $beanList; - $GLOBALS['beanFiles'] = $beanFiles; - $GLOBALS['current_user'] = SugarTestUserUtilities::createAnonymousUser(); - $GLOBALS['current_user']->is_admin = true; + $beanList = array(); + $beanFiles = array(); + require('include/modules.php'); + $GLOBALS['beanList'] = $beanList; + $GLOBALS['beanFiles'] = $beanFiles; + $this->account = SugarTestAccountUtilities::createAccount(); } public function tearDown() { SugarTestAccountUtilities::removeAllCreatedAccounts(); - SugarTestUserUtilities::removeAllCreatedAnonymousUsers(); } public function testSugarWidgetSubpanelTopButtonQuickCreate() @@ -69,7 +69,7 @@ public function testSugarWidgetSubpanelTopButtonQuickCreate() $subpanel_definitions = new SubPanelDefinitions(new Contact()); $contactSubpanelDef = $subpanel_definitions->load_subpanel('contacts'); - + $subpanel = new SubPanel('Accounts', $this->account->id, 'contacts', $contactSubpanelDef, 'Accounts'); $defines['subpanel_definition'] = $subpanel->subpanel_defs; diff --git a/tests/include/javascript/JSAlertsTest.php b/tests/include/javascript/JSAlertsTest.php index c3b678c6..45efbc75 100755 --- a/tests/include/javascript/JSAlertsTest.php +++ b/tests/include/javascript/JSAlertsTest.php @@ -43,6 +43,10 @@ class JSAlertsTest extends Sugar_PHPUnit_Framework_TestCase public function setUp() { + require('include/modules.php'); + $GLOBALS['beanList'] = $beanList; + $GLOBALS['beanFiles'] = $beanFiles; + global $current_user; $this->beans = array(); $this->old_user = $current_user; @@ -61,6 +65,8 @@ class JSAlertsTest extends Sugar_PHPUnit_Framework_TestCase unset($GLOBALS['app_list_strings']); unset($GLOBALS['current_user']); unset($GLOBALS['app_strings']); + unset($GLOBALS['beanList']); + unset($GLOBALS['beanFiles']); } protected function createNewMeeting() diff --git a/tests/include/utils/Bug46122Test.php b/tests/include/utils/Bug46122Test.php index 2ca5bac8..7624e26e 100755 --- a/tests/include/utils/Bug46122Test.php +++ b/tests/include/utils/Bug46122Test.php @@ -65,6 +65,7 @@ class Bu46122Test extends Sugar_PHPUnit_Framework_TestCase } $this->useOutputBuffering = false; + LogicHook::refreshHooks(); } public function tearDown() @@ -85,26 +86,30 @@ class Bu46122Test extends Sugar_PHPUnit_Framework_TestCase } else if(file_exists($this->contactsHookFile)) { unlink($this->contactsHookFile); } - + unset($GLOBALS['logic_hook']); } public function testSugarViewProcessLogicHookWithModule() { $GLOBALS['logic_hook'] = new LogicHookMock(); + $hooks = $GLOBALS['logic_hook']->getHooks('Contacts'); $sugarViewMock = new SugarViewMock(); $sugarViewMock->module = 'Contacts'; $sugarViewMock->process(); - $this->assertEquals(2, $GLOBALS['logic_hook']->hookRunCount, 'Assert that two logic hook files were run'); + $expectedHookCount = isset($hooks['after_ui_frame']) ? count($hooks['after_ui_frame']) : 0; + $this->assertEquals($expectedHookCount, $GLOBALS['logic_hook']->hookRunCount, 'Assert that two logic hook files were run'); } public function testSugarViewProcessLogicHookWithoutModule() { $GLOBALS['logic_hook'] = new LogicHookMock(); + $hooks = $GLOBALS['logic_hook']->getHooks(''); $sugarViewMock = new SugarViewMock(); $sugarViewMock->module = ''; $sugarViewMock->process(); - $this->assertEquals(1, $GLOBALS['logic_hook']->hookRunCount, 'Assert that one logic hook file was run'); + $expectedHookCount = isset($hooks['after_ui_frame']) ? count($hooks['after_ui_frame']) : 0; + $this->assertEquals($expectedHookCount, $GLOBALS['logic_hook']->hookRunCount, 'Assert that one logic hook file was run'); } } diff --git a/tests/include/utils/Bug46850Test.php b/tests/include/utils/Bug46850Test.php new file mode 100755 index 00000000..14919940 --- /dev/null +++ b/tests/include/utils/Bug46850Test.php @@ -0,0 +1,166 @@ + array(array(1, 'test_logic_hook', __FILE__, 'LogicHookTest', 'testLogicHook')), + ); + + public function setUp() + { + LogicHookTest::$called = false; + unset($GLOBALS['logic_hook']); + $GLOBALS['logic_hook'] = LogicHook::initialize(); + LogicHook::refreshHooks(); + } + + public function tearDown() + { + foreach($this->renames as $file) { + rename($file.".bak", $file); + } + foreach($this->deletes as $file) { + unlink($file); + } + unset($GLOBALS['logic_hook']); + LogicHook::refreshHooks(); + } + + protected function saveHook($file) + { + if(file_exists($file)) { + rename($file, $file.".bak"); + $this->renames[] = $file; + } else { + $this->deletes[] = $file; + } + } + + public function getModules() + { + return array( + array(''), + array('Contacts'), + array('Accounts'), + ); + } + + /** + * @dataProvider getModules + */ + public function testHooksDirect($module) + { + $dir = rtrim("custom/modules/$module", "/"); + $file = "$dir/logic_hooks.php"; + $this->saveHook($file); + if(!is_dir($dir)) { + mkdir($dir, 0755, true); + } + write_array_to_file('hook_array', $this->hook, $file); + $GLOBALS['logic_hook']->getHooks($module, true); // manually refresh + $GLOBALS['logic_hook']->call_custom_logic($module, 'test_logic_hook'); + $this->assertTrue(LogicHookTest::$called); + } + + /** + * @dataProvider getModules + */ + public function testHooksExtDirect($module) + { + if(empty($module)) { + $dir = "custom/application/Ext/LogicHooks"; + } else { + $dir = "custom/modules/$module/Ext/LogicHooks"; + } + if(!is_dir($dir)) { + mkdir($dir, 0755, true); + } + $file = "$dir/logichooks.ext.php"; + $this->saveHook($file); + write_array_to_file('hook_array', $this->hook, $file); + $GLOBALS['logic_hook']->getHooks($module, true); // manually refresh + $GLOBALS['logic_hook']->call_custom_logic($module, 'test_logic_hook'); + $this->assertTrue(LogicHookTest::$called); + } + + /** + * @dataProvider getModules + */ + public function testHooksUtils($module) + { + $dir = rtrim("custom/modules/$module", "/"); + $file = "$dir/logic_hooks.php"; + if(!is_dir($dir)) { + mkdir($dir, 0755, true); + } + $this->saveHook($file); + check_logic_hook_file($module, 'test_logic_hook', $this->hook['test_logic_hook'][0]); + $GLOBALS['logic_hook']->getHooks($module, true); // manually refresh + $GLOBALS['logic_hook']->call_custom_logic($module, 'test_logic_hook'); + $this->assertTrue(LogicHookTest::$called); + } + + + /** + * @dataProvider getModules + */ + public function testGeHookArray($module) + { + $dir = rtrim("custom/modules/$module", "/"); + $file = "$dir/logic_hooks.php"; + if(!is_dir($dir)) { + mkdir($dir, 0755, true); + } + $this->saveHook($file); + check_logic_hook_file($module, 'test_logic_hook', $this->hook['test_logic_hook'][0]); + $array = get_hook_array($module); + $this->assertEquals($this->hook, $array); + } +} + +class LogicHookTest { + public static $called = false; + function testLogicHook() { + self::$called = true; + } +} diff --git a/tests/modules/Administration/Bug36978Test.php b/tests/modules/Administration/Bug36978Test.php index 0e145795..28d9ab5f 100755 --- a/tests/modules/Administration/Bug36978Test.php +++ b/tests/modules/Administration/Bug36978Test.php @@ -242,7 +242,7 @@ EOQ; $GLOBALS['db']->query($sql); $rel = new Relationship(); - $rel->delete_cache(); + Relationship::delete_cache(); $rel->build_relationship_cache(); $this->moduleList = $GLOBALS['moduleList']; diff --git a/tests/modules/Currencies/CurrencyTest.php b/tests/modules/Currencies/CurrencyTest.php index 5e22438f..7ce153f5 100755 --- a/tests/modules/Currencies/CurrencyTest.php +++ b/tests/modules/Currencies/CurrencyTest.php @@ -45,8 +45,8 @@ class CurrencyTest extends Sugar_PHPUnit_Framework_TestCase { global $current_user; $this->previousCurrentUser = $current_user; $current_user = SugarTestUserUtilities::createAnonymousUser(); - $current_user->setPreference('num_grp_sep', ',', 0, 'global'); - $current_user->setPreference('dec_sep', '.', 0, 'global'); + $current_user->setPreference('number_grouping_seperator', ',', 0, 'global'); + $current_user->setPreference('decimal_seperator', '.', 0, 'global'); $current_user->save(); //Force reset on dec_sep and num_grp_sep because the dec_sep and num_grp_sep values are stored as static variables get_number_seperators(true); diff --git a/tests/modules/DynamicFields/Bug43471Test.php b/tests/modules/DynamicFields/Bug43471Test.php index 762f573b..707400f0 100755 --- a/tests/modules/DynamicFields/Bug43471Test.php +++ b/tests/modules/DynamicFields/Bug43471Test.php @@ -34,6 +34,7 @@ * "Powered by SugarCRM". ********************************************************************************/ + /** * @ticket 43471 */ diff --git a/tests/modules/Emails/Bug45960Test.php b/tests/modules/Emails/Bug45960Test.php new file mode 100755 index 00000000..73372305 --- /dev/null +++ b/tests/modules/Emails/Bug45960Test.php @@ -0,0 +1,91 @@ +_user = SugarTestUserUtilities::createAnonymousUser(); + $GLOBALS['current_user'] = $this->_user; + $this->_account = SugarTestAccountUtilities::createAccount(); + } + + public function tearDown() + { + if ($this->email_id) { + $GLOBALS['db']->query("delete from emails where id='{$this->email_id}'"); + } + SugarTestAccountUtilities::removeAllCreatedAccounts(); + SugarTestUserUtilities::removeAllCreatedAnonymousUsers(); + unset($GLOBALS['current_user']); + } + + public function testSaveNewEmailWithParent() + { + $email = new Email(); + $email->type = 'out'; + $email->status = 'sent'; + $email->from_addr_name = $email->cleanEmails("sender@domain.eu"); + $email->to_addrs_names = $email->cleanEmails("to@domain.eu"); + $email->cc_addrs_names = $email->cleanEmails("cc@domain.eu"); + + // set a few parent info to test the scenario + $email->parent_type = 'Accounts'; + $email->parent_id = $this->_account->id; + $email->fetched_row['parent_type'] = 'Accounts'; + $email->fetched_row['parent_id'] = $this->_account->id; + + $email->save(); + + $this->assertNotNull($email->id, 'Null email id'); + $this->email_id = $email->id; + + // ensure record is inserted into emails_beans table + $query = "select count(*) as CNT from emails_beans eb WHERE eb.bean_id = '{$this->_account->id}' AND eb.bean_module = 'Accounts' AND eb.email_id = '{$email->id}' AND eb.deleted=0"; + $result = $GLOBALS['db']->query($query); + $count = $GLOBALS['db']->fetchByAssoc($result); + $this->assertEquals(1, $count['CNT'], 'Incorrect emails_beans count'); + } + +} + + diff --git a/tests/modules/Employees/Bug46923Test.php b/tests/modules/Employees/Bug46923Test.php new file mode 100755 index 00000000..74eab40f --- /dev/null +++ b/tests/modules/Employees/Bug46923Test.php @@ -0,0 +1,88 @@ +last_name = $last_name; + $user->default_team = 1; + $user->status = 'Active'; + $user->employee_status = 'Active'; + $user->user_name = 'test_user_name'; + $user->save(); + $user_id = $user->id; + $this->assertNotNull($user_id, 'User id should not be null.'); + + // list view + $view = new EmployeesViewList(); + $GLOBALS['action'] = 'index'; + $GLOBALS['module'] = 'Employees'; + $_REQUEST['module'] = 'Employees'; + $view->init($user); + $view->lv = new ListViewSmarty(); + $view->display(); + + // ensure the new user shows up in the employees list view + $this->expectOutputRegex('/.*'.$last_name.'.*/'); + + // cleanup + unset($GLOBALS['action']); + unset($GLOBALS['module']); + unset($_REQUEST['module']); + $GLOBALS['db']->query("delete from users where id='{$user_id}'"); + } +} + +?> \ No newline at end of file diff --git a/tests/modules/Home/Bug43653Test.php b/tests/modules/Home/Bug43653Test.php index 3b0882d7..788d3251 100755 --- a/tests/modules/Home/Bug43653Test.php +++ b/tests/modules/Home/Bug43653Test.php @@ -37,8 +37,7 @@ class Bug43653Test extends Sugar_PHPUnit_Framework_OutputTestCase { - - public function setUp() + public function setUp() { $GLOBALS['current_user'] = SugarTestUserUtilities::createAnonymousUser(); if(file_exists($GLOBALS['sugar_config']['cache_dir']. 'modules/unified_search_modules.php')) @@ -46,15 +45,15 @@ class Bug43653Test extends Sugar_PHPUnit_Framework_OutputTestCase copy($GLOBALS['sugar_config']['cache_dir']. 'modules/unified_search_modules.php', $GLOBALS['sugar_config']['cache_dir']. 'modules/unified_search_modules.php.bak'); unlink($GLOBALS['sugar_config']['cache_dir']. 'modules/unified_search_modules.php'); } - + if(file_exists('custom/modules/unified_search_modules_display.php')) { copy('custom/modules/unified_search_modules_display.php', 'custom/modules/unified_search_modules_display.php.bak'); unlink('custom/modules/unified_search_modules_display.php'); - } + } } - - public function tearDown() + + public function tearDown() { SugarTestUserUtilities::removeAllCreatedAnonymousUsers(); unset($GLOBALS['current_user']); @@ -64,17 +63,17 @@ class Bug43653Test extends Sugar_PHPUnit_Framework_OutputTestCase copy($GLOBALS['sugar_config']['cache_dir']. 'modules/unified_search_modules.php.bak', $GLOBALS['sugar_config']['cache_dir']. 'modules/unified_search_modules.php'); unlink($GLOBALS['sugar_config']['cache_dir']. 'modules/unified_search_modules.php.bak'); } - + if(file_exists('custom/modules/unified_search_modules_display.php.bak')) { copy('custom/modules/unified_search_modules_display.php.bak', 'custom/modules/unified_search_modules_display.php'); unlink('custom/modules/unified_search_modules_display.php.bak'); - } - + } + SugarTestTaskUtilities::removeAllCreatedTasks(); SugarTestAccountUtilities::removeAllCreatedAccounts(); } - + public function testFisrtUnifiedSearchWithoutUserPreferences() { //Enable the Tasks, Accounts and Contacts modules @@ -82,20 +81,20 @@ class Bug43653Test extends Sugar_PHPUnit_Framework_OutputTestCase $_REQUEST = array(); $_REQUEST['enabled_modules'] = 'Tasks,Accounts,Contacts'; $unifiedSearchAdvanced = new UnifiedSearchAdvanced(); - $unifiedSearchAdvanced->saveGlobalSearchSettings(); - + $unifiedSearchAdvanced->saveGlobalSearchSettings(); + $_REQUEST = array(); $_REQUEST['advanced'] = 'false'; $unifiedSearchAdvanced->query_stirng = 'blah'; - $unifiedSearchAdvanced->search(); + $unifiedSearchAdvanced->search(); global $current_user; $users_modules = $current_user->getPreference('globalSearch', 'search'); $this->assertTrue(!empty($users_modules), 'Assert we have set the user preferences properly'); $this->assertTrue(isset($users_modules['Tasks']), 'Assert that we have added the Tasks module'); $this->assertEquals(count($users_modules), 3, 'Assert that we have 3 modules in user preferences for global search'); } - + } ?> \ No newline at end of file diff --git a/tests/modules/Import/Bug45907Test.csv b/tests/modules/Import/Bug45907Test.csv new file mode 100755 index 00000000..c9584d96 --- /dev/null +++ b/tests/modules/Import/Bug45907Test.csv @@ -0,0 +1,11 @@ +"Account Name","Website","Billing Street","Billing City","Billing State/Province","Billing Zip/Postal Code","Billing Country","Phone","Created Date" +"Acme","","10 Main Rd.","New York","NY","31349","USA","(212) 555-5555","3/10/2011" +"salesforce.com","http://www.salesforce.com","The Landmark @ One Market, Suite 300","San Francisco","CA","94105","USA","(415) 901-7000","3/10/2011" +"Global Media","","150 Chestnut Street","Toronto","Ontario","L4B 1Y3","Canada","(905) 555-1212","3/10/2011" + + +"Account List Report" +"Copyright (c) 2000-2011 salesforce.com, inc. All rights reserved." +"Confidential Information - Do Not Distribute" +"Generated By: trampus richmond 3/22/2011 11:20 PM" +"none" diff --git a/tests/modules/Import/Bug45907Test.php b/tests/modules/Import/Bug45907Test.php new file mode 100755 index 00000000..57e85838 --- /dev/null +++ b/tests/modules/Import/Bug45907Test.php @@ -0,0 +1,89 @@ +getCsvSettings($del, $enc); + $this->assertEquals(true, $ret, 'Failed to parse and get csv properties'); + + // delimiter + $this->assertEquals(',', $del, 'Incorrect delimiter'); + + // enclosure + $this->assertEquals('"', $enc, 'Incorrect enclosure'); + + // header + $ret = $auto->hasHeader($hasHeader, 'Accounts'); + $this->assertTrue($ret, 'Failed to detect header'); + $this->assertTrue($hasHeader, 'Incorrect header'); + + // remove temp file + unlink($sample_file); + } + +} diff --git a/tests/modules/Import/Bug45963Test.php b/tests/modules/Import/Bug45963Test.php new file mode 100755 index 00000000..40dc5464 --- /dev/null +++ b/tests/modules/Import/Bug45963Test.php @@ -0,0 +1,64 @@ +assertEmpty($modules['Groups']); + $this->assertNotEmpty($modules['Contacts']); + $this->assertNotEmpty($modules['Accounts']); + } +} + diff --git a/tests/modules/Import/Bug47737Test.php b/tests/modules/Import/Bug47737Test.php new file mode 100755 index 00000000..5e252406 --- /dev/null +++ b/tests/modules/Import/Bug47737Test.php @@ -0,0 +1,97 @@ +convertID($dirty); + + $this->assertEquals($expected, $actual, "Error converting id during import process $actual , expected: $expected, before conversion: $dirty"); + } + +} + + +class ImporterStub extends Importer +{ + + public function convertID($id) + { + return $this->_convertId($id); + } +} \ No newline at end of file diff --git a/tests/modules/Import/CsvAutoDetectTest.php b/tests/modules/Import/CsvAutoDetectTest.php new file mode 100755 index 00000000..2dc6147a --- /dev/null +++ b/tests/modules/Import/CsvAutoDetectTest.php @@ -0,0 +1,116 @@ + "\"date_entered\",\"description\"\n\"3/26/2011 10:02am\",\"test description\"", + 1 => "\"date_entered\"\t\"description\"\n\"2011-3-26 10:2 am\"\t\"test description\"", + 2 => "\"date_entered\",\"description\"\n\"3.26.2011 15.02\",\"test description\"", + 3 => "\"3/26/2011 10:02am\",\"some text\"\n\"4/26/2011 11:20am\",\"some more jim's text\"", + 4 => "\"date_entered\",\"description\"\n\"2010/03/26 10:2am\",\"test description\"", + 5 => "'date_entered','description'\n'26/3/2011 15:02','test description'", + 6 => "\"date_entered\"|\"description\"\n\"3/26/2011 10:02am\"|\"test description\"", + ); + + public function setUp() + { + // if beanList got unset, set it back + if (!isset($GLOBALS['beanList'])) { + require('include/modules.php'); + $GLOBALS['beanList'] = $beanList; + } + } + + public function tearDown() + { + } + + public function providerCsvData() + { + return array( + array(0, ',', '"', 'm/d/Y', 'h:ia', true), + array(1, "\t", '"', 'Y-m-d', 'h:i a', true), + array(2, ",", '"', 'm.d.Y', 'H.i', true), + array(3, ',', '"', 'm/d/Y', 'h:ia', false), + array(4, ',', '"', 'Y/m/d', 'h:ia', true), + array(5, ',', "'", 'd/m/Y', 'H:i', true), + array(6, '|', '"', 'm/d/Y', 'h:ia', true), + ); + } + + /** + * @dataProvider providerCsvData + */ + public function testGetCsvProperties($content_idx, $delimiter, $enclosure, $date, $time, $header) + { + $file = $GLOBALS['sugar_config']['tmp_dir'].'test.csv'; + $ret = file_put_contents($file, self::$CsvContent[$content_idx]); + $this->assertGreaterThan(0, $ret, 'Failed to write to '.$file .' for content '.$content_idx); + + $auto = new CsvAutoDetect($file); + $del = $enc = $hasHeader = false; + $ret = $auto->getCsvSettings($del, $enc); + $this->assertEquals(true, $ret, 'Failed to parse and get csv properties'); + + // delimiter + $this->assertEquals($delimiter, $del, 'Incorrect delimiter'); + + // enclosure + $this->assertEquals($enclosure, $enc, 'Incorrect enclosure'); + + // date format + $date_format = $auto->getDateFormat(); + $this->assertEquals($date, $date_format, 'Incorrect date format'); + + // time format + $time_format = $auto->getTimeFormat(); + $this->assertEquals($time, $time_format, 'Incorrect time format'); + + // header + $ret = $auto->hasHeader($hasHeader, 'Contacts'); + $this->assertTrue($ret, 'Failed to detect header'); + $this->assertEquals($header, $hasHeader, 'Incorrect header'); + + // remove temp file + unlink($GLOBALS['sugar_config']['tmp_dir'].'test.csv'); + } + +} diff --git a/tests/modules/Import/ImportDuplicateCheckTest.php b/tests/modules/Import/ImportDuplicateCheckTest.php index 142ff2f7..a8f7669c 100755 --- a/tests/modules/Import/ImportDuplicateCheckTest.php +++ b/tests/modules/Import/ImportDuplicateCheckTest.php @@ -34,7 +34,7 @@ * "Powered by SugarCRM". ********************************************************************************/ - + require_once 'modules/Import/ImportDuplicateCheck.php'; class ImportDuplicateCheckTest extends Sugar_PHPUnit_Framework_TestCase @@ -104,7 +104,7 @@ class ImportDuplicateCheckTest extends Sugar_PHPUnit_Framework_TestCase $idc = new ImportDuplicateCheck($focus); - $this->assertTrue($idc->isADuplicateRecord(array('idx_contacts_del_last'))); + $this->assertTrue($idc->isADuplicateRecord(array('idx_contacts_del_last::last_name'))); $focus->mark_deleted($id); } @@ -136,7 +136,7 @@ class ImportDuplicateCheckTest extends Sugar_PHPUnit_Framework_TestCase $idc = new ImportDuplicateCheck($focus); - $this->assertFalse($idc->isADuplicateRecord(array('idx_contacts_del_last'))); + $this->assertFalse($idc->isADuplicateRecord(array('idx_contacts_del_last::'.$last_name))); } public function testIsADuplicateRecordEmailNotFound() @@ -150,4 +150,77 @@ class ImportDuplicateCheckTest extends Sugar_PHPUnit_Framework_TestCase $this->assertFalse($idc->isADuplicateRecord(array('special_idx_email1'))); } + + //make sure exclusion array is respected when displaying the list of available indexes for dupe checking + public function testExcludeIndexesFromDupeCheck() + { + //create the bean to test on + $focus = loadBean('Contacts'); + + //create the importDuplicateCheck object and get the list of duplicateCheckIndexes + $idc = new ImportDuplicateCheck($focus); + + //get the list of importable indexes + $indexes = $import_indexes = $focus->getIndices(); + + + //grab any custom indexes if they exist + if($focus->hasCustomFields()){ + $custmIndexes = $focus->db->helper->get_indices($focus->table_name.'_cstm'); + $indexes = array_merge($custmIndexes,$indexes); + } + + //get list indexes to be displayed + $dupe_check_indexes = $idc->getDuplicateCheckIndexedFiles(); + + //Make sure that the indexes used for dupe checking honors the exclusion array. At a minimum, all beans will have + //their id and teamset indexes excluded. + $this->assertTrue(count($indexes) > count($dupe_check_indexes), 'Indexes specified for exclusion are not getting excluded from getDuplicateCheckIndexedFiles()'); + } + + + //make sure only selected indexes are checked for dupes + public function testCompareOnlySelectedIndexesFromDupeCheck() + { + //create a bean, values, populate and save + $focus = loadBean('Contacts'); + $focus->first_name = 'first '.date("YmdHis"); + $focus->last_name = 'last '.date("YmdHis"); + $focus->assigned_user_id = '1'; + $focus->save(); + + + //create the importDuplicateCheck object and get the list of duplicateCheckIndexes + $idc = new ImportDuplicateCheck($focus); + + //we are going to test agains the first name, last name, full name, and assigned to indexes + //to prove that only selected indexes are being used. + + //lets do a straight dupe check with the same bean on first name, should return true + $this->assertTrue($idc->isADuplicateRecord(array('idx_cont_last_first::first_name')),'simulated check against first name index (idx_cont_last_first::first_name) failed (returned false instead of true).'); + + //now lets test on full name index should also return true + $this->assertTrue($idc->isADuplicateRecord(array('full_name::full_name')),'first simulated check against full name index (full_name::full_name) failed (returned false instead of true). This check means BOTH first AND last name must match.'); + + //now lets remove the first name and redo the check, should return false + $focus->first_name = ''; + $idc = new ImportDuplicateCheck($focus); + $this->assertFalse($idc->isADuplicateRecord(array('idx_cont_last_first::first_name')),'simulated check against first name index (idx_cont_last_first::first_name) failed (returned true instead of false). This is wrong because we removed the first name so there should be no match.'); + + //lets retest on full name index should return false now as first AND last do not match the original + $this->assertFalse($idc->isADuplicateRecord(array('full_name::full_name')),'second simulated check against full name index (full_name::full_name) failed (returned true instead of false). This check means BOTH first AND last name must match and is wrong because we removed the first name so there should be no match.'); + + //now lets rename the contact and test on assigned user, should return true + $focus->first_name = 'first '.date("YmdHis"); + $focus->last_name = 'last '.date("YmdHis"); + $idc = new ImportDuplicateCheck($focus); + $this->assertTrue($idc->isADuplicateRecord(array('idx_del_id_user::assigned_user_id')),'simulated check against assigned user index (idx_del_id_user::assigned_user_id) failed (returned false instead of true). This is wrong because we have not changed this field and it should remain a duplicate'); + + //we're done, lets delete the focus bean now + $focus->mark_deleted($focus->id); + + } + + + } diff --git a/tests/modules/Import/ImportFieldSanitizeTest.php b/tests/modules/Import/ImportFieldSanitizeTest.php index 1542a5f4..ce684379 100755 --- a/tests/modules/Import/ImportFieldSanitizeTest.php +++ b/tests/modules/Import/ImportFieldSanitizeTest.php @@ -36,7 +36,7 @@ require_once('modules/Import/ImportFieldSanitize.php'); -require_once("modules/Import/ImportFile.php"); +require_once('modules/Import/sources/ImportFile.php'); require_once('tests/SugarTestLangPackCreator.php'); class ImportFieldSanitizeTest extends Sugar_PHPUnit_Framework_TestCase diff --git a/tests/modules/Import/ImportFileLimitTest.php b/tests/modules/Import/ImportFileLimitTest.php new file mode 100755 index 00000000..39b1e79e --- /dev/null +++ b/tests/modules/Import/ImportFileLimitTest.php @@ -0,0 +1,81 @@ +_fileSample1 = SugarTestImportUtilities::createFile( $this->_fileLineCount1, 3, 'upload_dir' ); + $this->_fileSample2 = SugarTestImportUtilities::createFile( $this->_fileLineCount2, 3, 'upload_dir' ); + $this->_fileSample3 = SugarTestImportUtilities::createFile( $this->_fileLineCount3, 3, 'upload_dir' ); + $this->_fileSample4 = SugarTestImportUtilities::createFile( $this->_fileLineCount4, 3, 'upload_dir' ); + } + + public function tearDown() + { + SugarTestImportUtilities::removeAllCreatedFiles(); + SugarTestUserUtilities::removeAllCreatedAnonymousUsers(); + unset($GLOBALS['current_user']); + } + + public function testGetFileRowCount() + { + $if1 = new ImportFile($this->_fileSample1, ',', "\"", FALSE); + $if2 = new ImportFile($this->_fileSample2, ',', "\"", FALSE); + $if3 = new ImportFile($this->_fileSample3, ',', "\"", FALSE); + $if4 = new ImportFile($this->_fileSample4, ',', "\"", FALSE); + + $this->assertEquals($this->_fileLineCount1, $if1->getNumberOfLinesInfile() ); + $this->assertEquals($this->_fileLineCount2, $if2->getNumberOfLinesInfile() ); + $this->assertEquals($this->_fileLineCount3, $if3->getNumberOfLinesInfile() ); + $this->assertEquals($this->_fileLineCount4, $if4->getNumberOfLinesInfile() ); + } +} + diff --git a/tests/modules/Import/ImportFileSplitterTest.php b/tests/modules/Import/ImportFileSplitterTest.php index 097cb8c7..5eadc7ae 100755 --- a/tests/modules/Import/ImportFileSplitterTest.php +++ b/tests/modules/Import/ImportFileSplitterTest.php @@ -35,7 +35,7 @@ ********************************************************************************/ -require_once 'modules/Import/ImportFile.php'; +require_once('modules/Import/sources/ImportFile.php'); require_once 'modules/Import/ImportFileSplitter.php'; class ImportFileSplitterTest extends Sugar_PHPUnit_Framework_TestCase @@ -124,8 +124,6 @@ class ImportFileSplitterTest extends Sugar_PHPUnit_Framework_TestCase $splitter = new ImportFileSplitter($this->_whiteSpaceFile); $splitter->splitSourceFile(',',' ',false); - $csvString = file_get_contents("{$this->_whiteSpaceFile}-0"); - $this->assertEquals( trim(file_get_contents("{$this->_whiteSpaceFile}-0")), trim(file_get_contents("{$this->_whiteSpaceFile}")) diff --git a/tests/modules/Import/ImportFileTest.php b/tests/modules/Import/ImportFileTest.php index 19ee0931..8d29ece2 100755 --- a/tests/modules/Import/ImportFileTest.php +++ b/tests/modules/Import/ImportFileTest.php @@ -35,7 +35,7 @@ ********************************************************************************/ -require_once 'modules/Import/ImportFile.php'; +require_once('modules/Import/sources/ImportFile.php'); class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase { @@ -57,7 +57,7 @@ class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase public function testFileImportNoEnclosers() { $file = SugarTestImportUtilities::createFile(2,1); - $importFile = new ImportFile($file,',',''); + $importFile = new ImportFile($file,',','', TRUE, FALSE); $row = $importFile->getNextRow(); $this->assertEquals($row, array('foo00')); $row = $importFile->getNextRow(); @@ -73,7 +73,7 @@ class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase public function testLoadGoodFile() { $file = SugarTestImportUtilities::createFile(2,1); - $importFile = new ImportFile($file,',','"'); + $importFile = new ImportFile($file,',','"', TRUE, FALSE); $this->assertTrue($importFile->fileExists()); } @@ -82,18 +82,21 @@ class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase */ public function testLoadFileWithByteOrderMark() { - $importFile = new ImportFile('tests/modules/Import/Bug39494ImportFile.txt',"\t",'',false); + $sample_file = $GLOBALS['sugar_config']['upload_dir'].'/Bug39494ImportFile.txt'; + copy('tests/modules/Import/Bug39494ImportFile.txt', $sample_file); + $importFile = new ImportFile($sample_file,"\t",'',false); $this->assertTrue($importFile->fileExists()); $row = $importFile->getNextRow(); $this->assertEquals($row,array('name','city')); $row = $importFile->getNextRow(); $this->assertEquals($row,array('tester1','wuhan')); + unlink($sample_file); } public function testGetNextRow() { $file = SugarTestImportUtilities::createFile(3,2); - $importFile = new ImportFile($file,',','"'); + $importFile = new ImportFile($file,',','"', TRUE, FALSE); $row = $importFile->getNextRow(); $this->assertEquals(array("foo00","foo01"),$row); @@ -109,7 +112,7 @@ class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase public function testGetNextRowWithEOL() { $file = SugarTestImportUtilities::createFileWithEOL(1, 1); - $importFile = new ImportFile($file,',','"'); + $importFile = new ImportFile($file,',','"', TRUE, FALSE); $row = $importFile->getNextRow(); // both \r\n and \n should be properly replaced with PHP_EOL $this->assertEquals(array("start0".PHP_EOL."0".PHP_EOL."end"), $row); @@ -134,7 +137,7 @@ class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase public function testDeleteFileOnDestroy() { $file = SugarTestImportUtilities::createFile(3,2); - $importFile = new ImportFile($file,',','"',true); + $importFile = new ImportFile($file,',','"',true, FALSE); unset($importFile); @@ -154,16 +157,16 @@ class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase public function testGetFieldCount() { $file = SugarTestImportUtilities::createFile(3,2); - $importFile = new ImportFile($file,',','"'); + $importFile = new ImportFile($file,',','"',TRUE, FALSE); $importFile->getNextRow(); - $this->assertEquals($importFile->getFieldCount(),2); + $this->assertEquals(2,$importFile->getFieldCount()); } public function testMarkRowAsDuplicate() { $file = SugarTestImportUtilities::createFile(3,2); - $importFile = new ImportFile($file,',','"'); + $importFile = new ImportFile($file,',','"', TRUE, FALSE); $row = $importFile->getNextRow(); $importFile->markRowAsDuplicate(); @@ -178,7 +181,7 @@ class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase public function testWriteError() { $file = SugarTestImportUtilities::createFile(3,2); - $importFile = new ImportFile($file,',','"'); + $importFile = new ImportFile($file,',','"', TRUE, FALSE); $row = $importFile->getNextRow(); $importFile->writeError('Some Error','field1','foo'); @@ -189,7 +192,7 @@ class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase $this->assertEquals(array('Some Error','field1','foo',1),$errorrow); - $fp = sugar_fopen(ImportCacheFiles::getErrorRecordsFileName(),'r'); + $fp = sugar_fopen(ImportCacheFiles::getErrorRecordsWithoutErrorFileName(),'r'); $errorrecordrow = fgetcsv($fp); fclose($fp); @@ -199,12 +202,12 @@ class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase public function testWriteErrorRecord() { $file = SugarTestImportUtilities::createFile(3,2); - $importFile = new ImportFile($file,',','"'); + $importFile = new ImportFile($file,',','"', TRUE, FALSE); $row = $importFile->getNextRow(); $importFile->writeErrorRecord(); - $fp = sugar_fopen(ImportCacheFiles::getErrorRecordsFileName(),'r'); + $fp = sugar_fopen(ImportCacheFiles::getErrorRecordsWithoutErrorFileName(),'r'); $errorrecordrow = fgetcsv($fp); fclose($fp); @@ -214,7 +217,7 @@ class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase public function testWriteStatus() { $file = SugarTestImportUtilities::createFile(3,2); - $importFile = new ImportFile($file,',','"'); + $importFile = new ImportFile($file,',','"', TRUE, FALSE); $importFile->getNextRow(); $importFile->writeError('Some Error','field1','foo'); @@ -234,7 +237,7 @@ class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase public function testWriteStatusWithTwoErrorsInOneRow() { $file = SugarTestImportUtilities::createFile(3,2); - $importFile = new ImportFile($file,',','"'); + $importFile = new ImportFile($file,',','"', TRUE, FALSE); $row = $importFile->getNextRow(); $importFile->writeError('Some Error','field1','foo'); @@ -251,10 +254,11 @@ class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase $this->assertEquals(array(3,1,0,2,0,$file),$statusrow); - $fp = sugar_fopen(ImportCacheFiles::getErrorRecordsFileName(),'r'); + $fp = sugar_fopen(ImportCacheFiles::getErrorRecordsWithoutErrorFileName(),'r'); $errorrecordrow = fgetcsv($fp); - + $this->assertEquals($row,$errorrecordrow); + $this->assertFalse(fgetcsv($fp),'Should be only 1 record in the csv file'); fclose($fp); @@ -263,7 +267,7 @@ class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase public function testWriteStatusWithTwoUpdatedRecords() { $file = SugarTestImportUtilities::createFile(3,2); - $importFile = new ImportFile($file,',','"'); + $importFile = new ImportFile($file,',','"', TRUE, FALSE); $row = $importFile->getNextRow(); $importFile->markRowAsImported(false); @@ -276,7 +280,7 @@ class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase $fp = sugar_fopen(ImportCacheFiles::getStatusFileName(),'r'); $statusrow = fgetcsv($fp); fclose($fp); - + $this->assertEquals(array(3,0,0,2,1,$file),$statusrow); } @@ -308,4 +312,181 @@ class ImportFileTest extends Sugar_PHPUnit_Framework_TestCase AND deleted=0"; $GLOBALS['db']->query($query); } + + public function providerEncodingData() + { + return array( + array('TestCharset.csv', 'UTF-8'), + array('TestCharset2.csv', 'ISO-8859-1'), + ); + } + + /** + * @dataProvider providerEncodingData + */ + public function testCharsetDetection($file, $encoding) { + // create the test file + $sample_file = $GLOBALS['sugar_config']['upload_dir'].'/'.$file; + copy('tests/modules/Import/'.$file, $sample_file); + + // auto detect charset + $importFile = new ImportFile($sample_file, ",", '', false, false); + $this->assertTrue($importFile->fileExists()); + $charset = $importFile->autoDetectCharacterSet(); + $this->assertEquals($encoding, $charset, 'detected char encoding is incorrect.'); + + // cleanup + unlink($sample_file); + } + + public function providerRowCountData() + { + return array( + array('TestCharset.csv', 2, false), + array('TestCharset2.csv', 11, true), + array('TestCharset2.csv', 12, false), + ); + } + + /** + * @dataProvider providerRowCountData + */ + public function testRowCount($file, $count, $hasHeader) { + // create the test file + $sample_file = $GLOBALS['sugar_config']['upload_dir'].'/'.$file; + copy('tests/modules/Import/'.$file, $sample_file); + + $importFile = new ImportFile($sample_file, ",", '', false, false); + $this->assertTrue($importFile->fileExists()); + $importFile->setHeaderRow($hasHeader); + $c = $importFile->getTotalRecordCount(); + $this->assertEquals($count, $c, 'incorrect row count.'); + + // cleanup + unlink($sample_file); + } + + public function providerFieldCountData() + { + return array( + array('TestCharset.csv', 2), + array('TestCharset2.csv', 5), + ); + } + + /** + * @dataProvider providerFieldCountData + */ + public function testFieldCount($file, $count) { + // create the test file + $sample_file = $GLOBALS['sugar_config']['upload_dir'].'/'.$file; + copy('tests/modules/Import/'.$file, $sample_file); + + $importFile = new ImportFile($sample_file, ",", '"', false, false); + $this->assertTrue($importFile->fileExists()); + $c = $importFile->getNextRow(); + $c = $importFile->getFieldCount(); + $this->assertEquals($count, $c, 'incorrect row count.'); + + // cleanup + unlink($sample_file); + } + + public function providerLineCountData() + { + return array( + array('TestCharset.csv', 2), + array('TestCharset2.csv', 12), + ); + } + + /** + * @dataProvider providerLineCountData + */ + public function testLineCount($file, $count) { + // create the test file + $sample_file = $GLOBALS['sugar_config']['upload_dir'].'/'.$file; + copy('tests/modules/Import/'.$file, $sample_file); + + $importFile = new ImportFile($sample_file, ",", '"', false, false); + $this->assertTrue($importFile->fileExists()); + $c = $importFile->getNumberOfLinesInfile(); + $this->assertEquals($count, $c, 'incorrect row count.'); + + // cleanup + unlink($sample_file); + } + + public function providerDateFormatData() + { + return array( + array('TestCharset.csv', 'd/m/Y'), + array('TestCharset2.csv', 'm/d/Y'), + ); + } + + /** + * @dataProvider providerDateFormatData + */ + public function testDateFormat($file, $format) { + // create the test file + $sample_file = $GLOBALS['sugar_config']['upload_dir'].'/'.$file; + copy('tests/modules/Import/'.$file, $sample_file); + + $importFile = new ImportFile($sample_file, ",", '"', false, false); + $this->assertTrue($importFile->fileExists()); + $ret = $importFile->autoDetectCSVProperties(); + $this->assertTrue($ret, 'Failed to auto detect properties.'); + $c = $importFile->getDateFormat(); + $this->assertEquals($format, $c, 'incorrect date format.'); + + // cleanup + unlink($sample_file); + } + + public function providerTimeFormatData() + { + return array( + array('TestCharset.csv', 'h:ia'), + array('TestCharset2.csv', 'H:i'), + ); + } + + /** + * @dataProvider providerTimeFormatData + */ + public function testTimeFormat($file, $format) { + // create the test file + $sample_file = $GLOBALS['sugar_config']['upload_dir'].'/'.$file; + copy('tests/modules/Import/'.$file, $sample_file); + + $importFile = new ImportFile($sample_file, ",", '"', false, false); + $this->assertTrue($importFile->fileExists()); + $ret = $importFile->autoDetectCSVProperties(); + $this->assertTrue($ret, 'Failed to auto detect properties.'); + $c = $importFile->getTimeFormat(); + $this->assertEquals($format, $c, 'incorrect time format.'); + + // cleanup + unlink($sample_file); + } + + /** + * @ticket 48289 + */ + public function testTabDelimiter() { + // create the test file + $sample_file = $GLOBALS['sugar_config']['upload_dir'].'/TestCharset.csv'; + copy('tests/modules/Import/TestCharset.csv', $sample_file); + + // use '\t' to simulate the bug + $importFile = new ImportFile($sample_file, '\t', '"', false, false); + $this->assertTrue($importFile->fileExists()); + $c = $importFile->getNextRow(); + $this->assertTrue(is_array($c), 'incorrect return type.'); + $this->assertEquals(1, count($c), 'incorrect array count.'); + + // cleanup + unlink($sample_file); + } } diff --git a/tests/modules/Import/ImportFormsTest.php b/tests/modules/Import/ImportFormsTest.php index 60f85897..5fcb3858 100755 --- a/tests/modules/Import/ImportFormsTest.php +++ b/tests/modules/Import/ImportFormsTest.php @@ -40,6 +40,7 @@ require_once 'include/Sugar_Smarty.php'; require_once 'modules/Import/controller.php'; require_once 'modules/Import/views/view.step3.php'; require_once 'modules/Import/views/view.step4.php'; +require_once 'modules/Import/Importer.php'; class ImportFormsTest extends Sugar_PHPUnit_Framework_OutputTestCase { @@ -117,7 +118,7 @@ class ImportFormsTest extends Sugar_PHPUnit_Framework_OutputTestCase { $old_error_reporting = error_reporting(E_ALL); - ImportViewStep4::handleImportErrors($errno, $errstr, $errfile, $errline); + Importer::handleImportErrors($errno, $errstr, $errfile, $errline); switch ($errno) { case E_USER_WARNING: diff --git a/tests/modules/Import/ImportMapTest.php b/tests/modules/Import/ImportMapTest.php index a4b8dffe..4f630d3c 100755 --- a/tests/modules/Import/ImportMapTest.php +++ b/tests/modules/Import/ImportMapTest.php @@ -35,7 +35,7 @@ ********************************************************************************/ -require_once 'modules/Import/ImportMap.php'; +require_once 'modules/Import/maps/ImportMap.php'; class ImportMapTest extends Sugar_PHPUnit_Framework_TestCase { diff --git a/tests/modules/Import/ImporterTest.php b/tests/modules/Import/ImporterTest.php new file mode 100755 index 00000000..a63b1d80 --- /dev/null +++ b/tests/modules/Import/ImporterTest.php @@ -0,0 +1,122 @@ + "\"3/26/2011 10:02am\",\"Doe\"", + 1 => "\"2011-3-26 10:2 am\",\"Doe\"", + 2 => "\"3.26.2011 10.02\",\"Doe\"", + ); + + public function setUp() + { + $beanList = array(); + $beanFiles = array(); + require('include/modules.php'); + $GLOBALS['beanList'] = $beanList; + $GLOBALS['beanFiles'] = $beanFiles; + + $GLOBALS['current_user'] = SugarTestUserUtilities::createAnonymousUser(); + $this->_importModule = 'Contacts'; + $this->_importObject = 'Contact'; + } + + public function tearDown() + { + $GLOBALS['db']->query("DELETE FROM contacts where created_by='{$GLOBALS['current_user']->id}'"); + + SugarTestUserUtilities::removeAllCreatedAnonymousUsers(); + } + + public function providerCsvData() + { + return array( + array(0, '2011-03-26 10:02:00', 'm/d/Y', 'h:ia'), + array(1, '2011-03-26 10:02:00', 'Y-m-d', 'h:ia'), + array(2, '2011-03-26 10:02:00', 'm.d.Y', 'H.i'), + ); + } + + /** + * @dataProvider providerCsvData + */ + public function testDateTimeImport($content_idx, $expected_datetime, $date_format, $time_format) + { + $file = $GLOBALS['sugar_config']['upload_dir'].'test.csv'; + $ret = file_put_contents($file, self::$CsvContent[$content_idx]); + $this->assertGreaterThan(0, $ret, 'Failed to write to '.$file .' for content '.$content_idx); + + $importSource = new ImportFile($file, ',', '"'); + + $bean = loadBean($this->_importModule); + + $_REQUEST['columncount'] = 2; + $_REQUEST['colnum_0'] = 'date_entered'; + $_REQUEST['colnum_1'] = 'last_name'; + $_REQUEST['import_module'] = 'Contacts'; + $_REQUEST['importlocale_charset'] = 'UTF-8'; + $_REQUEST['importlocale_dateformat'] = $date_format; + $_REQUEST['importlocale_timeformat'] = $time_format; + $_REQUEST['importlocale_timezone'] = 'GMT'; + $_REQUEST['importlocale_default_currency_significant_digits'] = '2'; + $_REQUEST['importlocale_currency'] = '-99'; + $_REQUEST['importlocale_dec_sep'] = '.'; + $_REQUEST['importlocale_currency'] = '-99'; + $_REQUEST['importlocale_default_locale_name_format'] = 's f l'; + $_REQUEST['importlocale_num_grp_sep'] = ','; + + $importer = new Importer($importSource, $bean); + $importer->import(); + + $query = "SELECT date_entered from contacts where created_by='{$GLOBALS['current_user']->id}'"; + $result = $GLOBALS['db']->query($query); + $row = $GLOBALS['db']->fetchByAssoc($result); + + $this->assertEquals($expected_datetime, $row['date_entered'], 'Got incorrect date_entered.'); + + } +} + diff --git a/tests/modules/Import/TestCharset.csv b/tests/modules/Import/TestCharset.csv new file mode 100755 index 00000000..dc2b16cc --- /dev/null +++ b/tests/modules/Import/TestCharset.csv @@ -0,0 +1,2 @@ +name,city +tester1,20/9/1934 9:58am diff --git a/tests/modules/Import/TestCharset2.csv b/tests/modules/Import/TestCharset2.csv new file mode 100755 index 00000000..304e879e --- /dev/null +++ b/tests/modules/Import/TestCharset2.csv @@ -0,0 +1,12 @@ +first,last,province,postal,description + rue Notre-Dame,Lavaltrie,Québec,1/3/1940 13:25,D'Autray + rue Principale,Saint-Basile-le-Grand,Québec,J3N 1M1,La Vallée-du-Richelieu + Avenue Saint-Paul,Saint-Césaire,Québec,J0L 1T0,Rouville + Chemin D'Oka,Sainte-Marthe-sur-le-Lac,Québec,J0N 1P0,Deux-Montagnes + avenue du Palais,Saint-Hyacinthe,Québec,J2S 5C6,Montérégie + boulevard Perrot,L'ÃŽle-Perrot,Québec,J7V 3G1,Vaudreuil-Soulanges + boulevard Beaconsfield,Beaconsfield,Québec,H9W 4A7,Hors MRC : Montréal + chemin Lakeshore,Baie-D'Urfé,Québec,H9X 1P7,Hors MRC + rue du Pont,Mont-Laurier ,Québec,J9L 2R6,Laurentides + chemin de Hatley,Compton,Québec,J0B 1L0,Coaticook + rue St-Jean-Baptiste Est,Montmagny,Québec,G5V 1K4,Montmagny diff --git a/tests/modules/Leads/Bug40209Test.php b/tests/modules/Leads/Bug40209Test.php index 66452dbe..6e2b9ce9 100755 --- a/tests/modules/Leads/Bug40209Test.php +++ b/tests/modules/Leads/Bug40209Test.php @@ -34,8 +34,8 @@ * "Powered by SugarCRM". ********************************************************************************/ - -class Bug40209Test extends Sugar_PHPUnit_Framework_TestCase + +class Bug40209Test extends Sugar_PHPUnit_Framework_OutputTestCase { var $user; var $account; @@ -44,6 +44,8 @@ class Bug40209Test extends Sugar_PHPUnit_Framework_TestCase public function setUp() { + global $_POST; + $_POST = array(); //create user $this->user = $GLOBALS['current_user'] = SugarTestUserUtilities::createAnonymousUser(); @@ -57,7 +59,7 @@ class Bug40209Test extends Sugar_PHPUnit_Framework_TestCase $this->lead = SugarTestLeadUtilities::createLead(); } - + public function tearDown() { //delete records created from db @@ -72,17 +74,14 @@ class Bug40209Test extends Sugar_PHPUnit_Framework_TestCase unset($this->account); unset($this->contact); } - + //run test to make sure accounts related to leads record are copied over to contact recor during conversion (bug 40209) public function testConvertAccountCopied() { - //there will be output from display function, so call ob_start to trap it - ob_start(); - $_POST = array(); - + //set the request parameters and convert the lead $_REQUEST['module'] = 'Leads'; $_REQUEST['action'] = 'ConvertLead'; @@ -102,14 +101,10 @@ class Bug40209Test extends Sugar_PHPUnit_Framework_TestCase $contact_id = $this->lead->contact_id; //throw error if contact id was not retrieved and exit test - $this->assertTrue(!empty($contact_id), "contact id was not created during conversion process. An error has ocurred, aborting rest of test."); - if (empty($contact_id)){ - return; - } + $this->assertNotEmpty($contact_id, "contact id was not created during conversion process. An error has ocurred, aborting rest of test."); //make sure the new contact has the account related and that it matches the lead account $this->contact->retrieve($contact_id); - $this->assertTrue($this->contact->account_id == $this->lead->account_id, "Account id from converted lead does not match the new contact account id, there was an error during conversion."); - $output = ob_get_clean(); + $this->assertEquals($this->lead->account_id, $this->contact->account_id, "Account id from converted lead does not match the new contact account id, there was an error during conversion."); } } \ No newline at end of file diff --git a/tests/modules/Leads/Bug45187Test.php b/tests/modules/Leads/Bug45187Test.php new file mode 100755 index 00000000..b01a9ff1 --- /dev/null +++ b/tests/modules/Leads/Bug45187Test.php @@ -0,0 +1,97 @@ +id; + unset($_REQUEST['handle']); + $_REQUEST['selectedAccount'] = $account->id; + $sugar_config['lead_conv_activity_opt'] = 'move'; + + // call display to trigger conversion + $vc = new ViewConvertLead(); + $vc->init($lead); + $vc->display(); + + // the activity options dropdown should use the renamed module label + $this->expectOutputRegex('/.*People<\/OPTION>.*/'); + + // cleanup + $app_list_strings['moduleListSingular']['Contacts'] = $org_name; + unset($_REQUEST['module']); + unset($_REQUEST['action']); + unset($_REQUEST['record']); + unset($_REQUEST['selectedAccount']); + SugarTestAccountUtilities::removeAllCreatedAccounts(); + SugarTestLeadUtilities::removeAllCreatedLeads(); + } + +} diff --git a/tests/modules/Leads/ConvertLeadTests.php b/tests/modules/Leads/ConvertLeadTests.php index cb352b92..eb50453a 100755 --- a/tests/modules/Leads/ConvertLeadTests.php +++ b/tests/modules/Leads/ConvertLeadTests.php @@ -34,7 +34,10 @@ * "Powered by SugarCRM". ********************************************************************************/ - + +require_once 'modules/Leads/views/view.convertlead.php'; + + class ConvertLeadTests extends Sugar_PHPUnit_Framework_TestCase { public function setUp() @@ -96,21 +99,373 @@ class ConvertLeadTests extends Sugar_PHPUnit_Framework_TestCase unset($_REQUEST['record']); SugarTestLeadUtilities::removeAllCreatedLeads(); } + + /** + * @group bug44033 + */ + public function testActivityMove() { + // init + $lead = SugarTestLeadUtilities::createLead(); + $contact = SugarTestContactUtilities::createContact(); + $meeting = SugarTestMeetingUtilities::createMeeting(); + SugarTestMeetingUtilities::addMeetingParent($meeting->id, $lead->id); + $relation_id = SugarTestMeetingUtilities::addMeetingLeadRelation($meeting->id, $lead->id); + $_REQUEST['record'] = $lead->id; + + // refresh the meeting to include parent_id and parent_type + $meeting_id = $meeting->id; + $meeting = new Meeting(); + $meeting->retrieve($meeting_id); + + // action: move meeting from lead to contact + $convertObj = new TestViewConvertLead(); + $convertObj->moveActivityWrapper($meeting, $contact); + + // verification 1, parent id should be contact id + $this->assertTrue($meeting->parent_id == $contact->id, 'Meeting parent id is not converted to contact id.'); + + // verification 2, parent type should be "Contacts" + $this->assertTrue($meeting->parent_type == 'Contacts', 'Meeting parent type is not converted to Contacts.'); + + // verification 3, record should be deleted from meetings_leads table + $sql = "select id from meetings_leads where meeting_id='{$meeting->id}' and lead_id='{$lead->id}' and deleted=0"; + $result = $GLOBALS['db']->query($sql); + $row = $GLOBALS['db']->fetchByAssoc($result); + $this->assertFalse($row, "Meeting-Lead relationship is not removed."); + + // verification 4, record should be added to meetings_contacts table + $sql = "select id from meetings_contacts where meeting_id='{$meeting->id}' and contact_id='{$contact->id}' and deleted=0"; + $result = $GLOBALS['db']->query($sql); + $row = $GLOBALS['db']->fetchByAssoc($result); + $this->assertFalse(empty($row), "Meeting-Contact relationship is not added."); + + // clean up + unset($_REQUEST['record']); + $GLOBALS['db']->query("delete from meetings_contacts where meeting_id='{$meeting->id}' and contact_id= '{$contact->id}'"); + SugarTestMeetingUtilities::deleteMeetingLeadRelation($relation_id); + SugarTestMeetingUtilities::removeMeetingContacts(); + SugarTestMeetingUtilities::removeAllCreatedMeetings(); + SugarTestContactUtilities::removeAllCreatedContacts(); + SugarTestLeadUtilities::removeAllCreatedLeads(); + } + + public function testActivityCopy() { + // init + $lead = SugarTestLeadUtilities::createLead(); + $contact = SugarTestContactUtilities::createContact(); + $meeting = SugarTestMeetingUtilities::createMeeting(); + SugarTestMeetingUtilities::addMeetingParent($meeting->id, $lead->id); + $relation_id = SugarTestMeetingUtilities::addMeetingLeadRelation($meeting->id, $lead->id); + $_REQUEST['record'] = $lead->id; + + // refresh the meeting to include parent_id and parent_type + $meeting_id = $meeting->id; + $meeting = new Meeting(); + $meeting->retrieve($meeting_id); + + // action: copy meeting from lead to contact + $convertObj = new TestViewConvertLead(); + $convertObj->copyActivityWrapper($meeting, $contact); + + // 1. the original meeting should still have the same parent_type and parent_id + $meeting->retrieve($meeting_id); + $this->assertEquals('Leads', $meeting->parent_type, 'parent_type of the original meeting was changed from Leads to '.$meeting->parent_type); + $this->assertEquals($lead->id, $meeting->parent_id, 'parent_id of the original meeting was changed from '.$lead->id.' to '.$meeting->parent_id); + + // 2. a newly created meeting with parent type=Contatcs and parent_id=$contact->id + $sql = "select id from meetings where parent_id='{$contact->id}' and parent_type= 'Contacts' and deleted=0"; + $result = $GLOBALS['db']->query($sql); + $row = $GLOBALS['db']->fetchByAssoc($result); + $this->assertNotNull($row, 'Could not find the newly created meeting with parent_type=Contacts and parent_id='.$contact->id); + $new_meeting_id = ''; + if ($row) { + $new_meeting_id = $row['id']; + } + + // 3. record should not be deleted from meetings_leads table + $sql = "select id from meetings_leads where meeting_id='{$meeting->id}' and lead_id='{$lead->id}' and deleted=0"; + $result = $GLOBALS['db']->query($sql); + $row = $GLOBALS['db']->fetchByAssoc($result); + $this->assertNotNull($row, "Meeting-Lead relationship was removed."); + + // 4. new meeting record should be added to meetings_contacts table + $sql = "select id from meetings_contacts where meeting_id='{$new_meeting_id}' and contact_id='{$contact->id}' and deleted=0"; + $result = $GLOBALS['db']->query($sql); + $row = $GLOBALS['db']->fetchByAssoc($result); + $this->assertFalse(empty($row), "Meeting-Contact relationship has not been added."); + + // clean up + unset($_REQUEST['record']); + $GLOBALS['db']->query("delete from meetings where parent_id='{$contact->id}' and parent_type= 'Contacts'"); + $GLOBALS['db']->query("delete from meetings where parent_id='{$lead->id}' and parent_type= 'Leads'"); + $GLOBALS['db']->query("delete from meetings_contacts where meeting_id='{$new_meeting_id}' and contact_id= '{$contact->id}'"); + SugarTestMeetingUtilities::deleteMeetingLeadRelation($relation_id); + SugarTestMeetingUtilities::removeMeetingContacts(); + SugarTestMeetingUtilities::removeAllCreatedMeetings(); + SugarTestContactUtilities::removeAllCreatedContacts(); + SugarTestLeadUtilities::removeAllCreatedLeads(); + } + + public function testConversionAndMoveActivities() { + global $sugar_config; + + // init + $lead = SugarTestLeadUtilities::createLead(); + $account = SugarTestAccountUtilities::createAccount(); + $meeting = SugarTestMeetingUtilities::createMeeting(); + SugarTestMeetingUtilities::addMeetingParent($meeting->id, $lead->id); + $relation_id = SugarTestMeetingUtilities::addMeetingLeadRelation($meeting->id, $lead->id); + $_REQUEST['record'] = $lead->id; + + // set the request/post parameters before converting the lead + $_REQUEST['module'] = 'Leads'; + $_REQUEST['action'] = 'ConvertLead'; + $_REQUEST['record'] = $lead->id; + $_REQUEST['handle'] = 'save'; + $_REQUEST['selectedAccount'] = $account->id; + $sugar_config['lead_conv_activity_opt'] = 'move'; + $_POST['lead_conv_ac_op_sel'] = 'Contacts'; + + // call display to trigger conversion + $vc = new ViewConvertLead(); + $vc->display(); + + // refresh meeting + $meeting_id = $meeting->id; + $meeting = new Meeting(); + $meeting->retrieve($meeting_id); + + // refresh lead + $lead_id = $lead->id; + $lead = new Lead(); + $lead->retrieve($lead_id); + + // retrieve the new contact id from the conversion + $contact_id = $lead->contact_id; + + // 1. Lead's contact_id should not be null + $this->assertNotNull($contact_id, 'Lead has null contact id after conversion.'); + + // 2. Lead status should be 'Converted' + $this->assertEquals('Converted', $lead->status, "Lead atatus should be 'Converted'."); + + // 3. new parent_type should be Contacts + $this->assertEquals('Contacts', $meeting->parent_type, 'Meeting parent type has not been set to Contacts'); + + // 4. new parent_id should be contact id + $this->assertEquals($contact_id, $meeting->parent_id, 'Meeting parent id has not been set to contact id.'); + + // 5. record should be deleted from meetings_leads table + $sql = "select id from meetings_leads where meeting_id='{$meeting->id}' and lead_id='{$lead->id}' and deleted=0"; + $result = $GLOBALS['db']->query($sql); + $row = $GLOBALS['db']->fetchByAssoc($result); + $this->assertFalse($row, "Meeting-Lead relationship is not removed."); + + // 6. record should be added to meetings_contacts table + $sql = "select id from meetings_contacts where meeting_id='{$meeting->id}' and contact_id='{$contact_id}' and deleted=0"; + $result = $GLOBALS['db']->query($sql); + $row = $GLOBALS['db']->fetchByAssoc($result); + $this->assertFalse(empty($row), "Meeting-Contact relationship is not added."); + + // clean up + unset($_REQUEST['record']); + $GLOBALS['db']->query("delete from meetings where parent_id='{$lead->id}' and parent_type= 'Leads'"); + $GLOBALS['db']->query("delete from meetings where parent_id='{$contact_id}' and parent_type= 'Contacts'"); + $GLOBALS['db']->query("delete from contacts where id='{$contact_id}'"); + $GLOBALS['db']->query("delete from meetings_contacts where meeting_id='{$meeting->id}' and contact_id= '{$contact_id}'"); + SugarTestMeetingUtilities::deleteMeetingLeadRelation($relation_id); + SugarTestMeetingUtilities::removeMeetingContacts(); + SugarTestMeetingUtilities::removeAllCreatedMeetings(); + SugarTestAccountUtilities::removeAllCreatedAccounts(); + SugarTestLeadUtilities::removeAllCreatedLeads(); + } + + public function testConversionAndCopyActivities() { + global $sugar_config; + + // init + $lead = SugarTestLeadUtilities::createLead(); + $account = SugarTestAccountUtilities::createAccount(); + $meeting = SugarTestMeetingUtilities::createMeeting(); + SugarTestMeetingUtilities::addMeetingParent($meeting->id, $lead->id); + $relation_id = SugarTestMeetingUtilities::addMeetingLeadRelation($meeting->id, $lead->id); + $_REQUEST['record'] = $lead->id; + + // set the request/post parameters before converting the lead + $_REQUEST['module'] = 'Leads'; + $_REQUEST['action'] = 'ConvertLead'; + $_REQUEST['record'] = $lead->id; + $_REQUEST['handle'] = 'save'; + $_REQUEST['selectedAccount'] = $account->id; + $sugar_config['lead_conv_activity_opt'] = 'copy'; + $_POST['lead_conv_ac_op_sel'] = array('Contacts'); + + // call display to trigger conversion + $vc = new ViewConvertLead(); + $vc->display(); + + // refresh meeting + $meeting_id = $meeting->id; + $meeting = new Meeting(); + $meeting->retrieve($meeting_id); + + // refresh lead + $lead_id = $lead->id; + $lead = new Lead(); + $lead->retrieve($lead_id); + + // retrieve the new contact id from the conversion + $contact_id = $lead->contact_id; + + // 1. Lead's contact_id should not be null + $this->assertNotNull($contact_id, 'Lead has null contact id after conversion.'); + + // 2. Lead status should be 'Converted' + $this->assertEquals('Converted', $lead->status, "Lead atatus should be 'Converted'."); + + // 3. parent_type of the original meeting should be Leads + $this->assertEquals('Leads', $meeting->parent_type, 'Meeting parent should be Leads'); + + // 4. parent_id of the original meeting should be contact id + $this->assertEquals($lead_id, $meeting->parent_id, 'Meeting parent id should be lead id.'); + + // 5. record should NOT be deleted from meetings_leads table + $sql = "select id from meetings_leads where meeting_id='{$meeting->id}' and lead_id='{$lead->id}' and deleted=0"; + $result = $GLOBALS['db']->query($sql); + $row = $GLOBALS['db']->fetchByAssoc($result); + $this->assertFalse(empty($row), "Meeting-Lead relationship is removed."); + + // 6. record should be added to meetings_contacts table + $sql = "select meeting_id from meetings_contacts where contact_id='{$contact_id}' and deleted=0"; + $result = $GLOBALS['db']->query($sql); + $row = $GLOBALS['db']->fetchByAssoc($result); + $this->assertFalse(empty($row), "Meeting-Contact relationship is not added."); + + // 7. the parent_type of the new meeting should be Contacts + $new_meeting_id = $row['meeting_id']; + $sql = "select id, parent_type, parent_id from meetings where id='{$new_meeting_id}' and deleted=0"; + $result = $GLOBALS['db']->query($sql); + $row = $GLOBALS['db']->fetchByAssoc($result); + $this->assertFalse(empty($row), "New meeting is not added for contact."); + $this->assertEquals('Contacts', $row['parent_type'], 'Parent type of the new meeting should be Contacts'); + + // 8. the parent_id of the new meeting should be contact id + $this->assertEquals($contact_id, $row['parent_id'], 'Parent id of the new meeting should be contact id.'); + + // clean up + unset($_REQUEST['record']); + $GLOBALS['db']->query("delete from meetings where parent_id='{$lead->id}' and parent_type= 'Leads'"); + $GLOBALS['db']->query("delete from meetings where parent_id='{$contact_id}' and parent_type= 'Contacts'"); + $GLOBALS['db']->query("delete from contacts where id='{$contact_id}'"); + $GLOBALS['db']->query("delete from meetings_leads where meeting_id='{$meeting->id}' and lead_id= '{$lead_id}'"); + $GLOBALS['db']->query("delete from meetings_contacts where contact_id= '{$contact_id}'"); + SugarTestMeetingUtilities::deleteMeetingLeadRelation($relation_id); + SugarTestMeetingUtilities::removeMeetingContacts(); + SugarTestMeetingUtilities::removeAllCreatedMeetings(); + SugarTestAccountUtilities::removeAllCreatedAccounts(); + SugarTestLeadUtilities::removeAllCreatedLeads(); + } + + public function testConversionAndDoNothing() { + global $sugar_config; + + // init + $lead = SugarTestLeadUtilities::createLead(); + $account = SugarTestAccountUtilities::createAccount(); + $meeting = SugarTestMeetingUtilities::createMeeting(); + SugarTestMeetingUtilities::addMeetingParent($meeting->id, $lead->id); + $relation_id = SugarTestMeetingUtilities::addMeetingLeadRelation($meeting->id, $lead->id); + $_REQUEST['record'] = $lead->id; + + // set the request/post parameters before converting the lead + $_REQUEST['module'] = 'Leads'; + $_REQUEST['action'] = 'ConvertLead'; + $_REQUEST['record'] = $lead->id; + $_REQUEST['handle'] = 'save'; + $_REQUEST['selectedAccount'] = $account->id; + $sugar_config['lead_conv_activity_opt'] = 'none'; + + // call display to trigger conversion + $vc = new ViewConvertLead(); + $vc->display(); + + // refresh meeting + $meeting_id = $meeting->id; + $meeting = new Meeting(); + $meeting->retrieve($meeting_id); + + // refresh lead + $lead_id = $lead->id; + $lead = new Lead(); + $lead->retrieve($lead_id); + + // retrieve the new contact id from the conversion + $contact_id = $lead->contact_id; + + // 1. Lead's contact_id should not be null + $this->assertNotNull($contact_id, 'Lead has null contact id after conversion.'); + + // 2. Lead status should be 'Converted' + $this->assertEquals('Converted', $lead->status, "Lead atatus should be 'Converted'."); + + // 3. parent_type of the original meeting should be Leads + $this->assertEquals('Leads', $meeting->parent_type, 'Meeting parent should be Leads'); + + // 4. parent_id of the original meeting should be contact id + $this->assertEquals($lead_id, $meeting->parent_id, 'Meeting parent id should be lead id.'); + + // 5. record should NOT be deleted from meetings_leads table + $sql = "select id from meetings_leads where meeting_id='{$meeting->id}' and lead_id='{$lead->id}' and deleted=0"; + $result = $GLOBALS['db']->query($sql); + $row = $GLOBALS['db']->fetchByAssoc($result); + $this->assertFalse(empty($row), "Meeting-Lead relationship is removed."); + + // 6. record should NOT be added to meetings_contacts table + $sql = "select meeting_id from meetings_contacts where contact_id='{$contact_id}' and deleted=0"; + $result = $GLOBALS['db']->query($sql); + $row = $GLOBALS['db']->fetchByAssoc($result); + $this->assertFalse($row, "Meeting-Contact relationship should not be added."); + + // clean up + unset($_REQUEST['record']); + $GLOBALS['db']->query("delete from meetings where parent_id='{$lead->id}' and parent_type= 'Leads'"); + $GLOBALS['db']->query("delete from meetings where parent_id='{$contact_id}' and parent_type= 'Contacts'"); + $GLOBALS['db']->query("delete from contacts where id='{$contact_id}'"); + $GLOBALS['db']->query("delete from meetings_leads where meeting_id='{$meeting->id}' and lead_id= '{$lead_id}'"); + $GLOBALS['db']->query("delete from meetings_contacts where contact_id= '{$contact_id}'"); + SugarTestMeetingUtilities::deleteMeetingLeadRelation($relation_id); + SugarTestMeetingUtilities::removeMeetingContacts(); + SugarTestMeetingUtilities::removeAllCreatedMeetings(); + SugarTestAccountUtilities::removeAllCreatedAccounts(); + SugarTestLeadUtilities::removeAllCreatedLeads(); + } + public function testMeetingsUsersRelationships() { global $current_user; - + $bean = SugarTestMeetingUtilities::createMeeting(); $convert_lead = SugarTestViewConvertLeadUtilities::createViewConvertLead(); - + if ($bean->object_name == "Meeting") { $convert_lead->setMeetingsUsersRelationship($bean); } - + $this->assertTrue(is_object($bean->users), "Relationship wasn't set."); - + SugarTestMeetingUtilities::removeMeetingUsers(); SugarTestMeetingUtilities::removeAllCreatedMeetings(); } -} \ No newline at end of file +} + +class TestViewConvertLead extends ViewConvertLead +{ + public function moveActivityWrapper($activity, $bean) { + parent::moveActivity($activity, $bean); + } + + public function copyActivityWrapper($activity, $bean) { + parent::copyActivityAndRelateToBean($activity, $bean); + } +} diff --git a/tests/modules/ModuleBuilder/MB/Bug39598Test.php b/tests/modules/ModuleBuilder/MB/Bug39598Test.php index f1ac82f1..b875c052 100755 --- a/tests/modules/ModuleBuilder/MB/Bug39598Test.php +++ b/tests/modules/ModuleBuilder/MB/Bug39598Test.php @@ -1,4 +1,40 @@ $new_label), $test_module); + + // read the language file to get the new value + include("custom/modules/$test_module/language/en_us.lang.php"); + + $this->assertEquals($new_label, $mod_strings[$test_label], 'Label not changed.'); + } +} + + +?> diff --git a/tests/modules/Notes/Bug40263Test.php b/tests/modules/Notes/Bug40263Test.php index 8c89bd68..088686c5 100755 --- a/tests/modules/Notes/Bug40263Test.php +++ b/tests/modules/Notes/Bug40263Test.php @@ -46,23 +46,23 @@ class Bug40263Test extends Sugar_PHPUnit_Framework_TestCase var $user; var $note; - public function setUp() + public function setUp() { global $current_user; - + $this->user = SugarTestUserUtilities::createAnonymousUser();//new User(); $this->user->first_name = "test"; $this->user->last_name = "user"; $this->user->user_name = "test_test"; $this->user->save(); $current_user=$this->user; - + $this->note = new Note(); $this->note->name = "Bug40263 test Note"; $this->note->save(); } - public function tearDown() + public function tearDown() { SugarTestUserUtilities::removeAllCreatedAnonymousUsers(); $this->note->mark_deleted($this->note->id); @@ -85,15 +85,15 @@ class Bug40263Test extends Sugar_PHPUnit_Framework_TestCase 'label' => 'LBL_CREATED_BY', 'width' => '10%', 'default' => true, - ), + ), ); $lvd = new ListViewDisplay(); $lvd->displayColumns = $displayColumns; $fields = $lvd->setupFilterFields(); $query = $this->note->create_new_list_query('', 'id="' . $this->note->id . '"', $fields); - $regex = "/select.* created_by_name.*LEFT JOIN\s*users jt\d ON\s*jt\d\.id\s*=\s*notes.created_by.*/si"; + $regex = '/select.* created_by_name.*LEFT JOIN\s*users jt\d ON\s*notes.created_by\s*=\s*jt\d\.id.*/si'; return $this->assertRegExp($regex, $query, "Unable to find the created user in the notes list view query: $query"); } - + } diff --git a/tests/modules/Project/Bug37123Test.php b/tests/modules/Project/Bug37123Test.php index 21f06e4d..87085303 100755 --- a/tests/modules/Project/Bug37123Test.php +++ b/tests/modules/Project/Bug37123Test.php @@ -35,6 +35,7 @@ ********************************************************************************/ + class Bug37123Test extends Sugar_PHPUnit_Framework_TestCase { public function setUp() diff --git a/tests/modules/Reports/Bug47271Test.php b/tests/modules/Reports/Bug47271Test.php new file mode 100755 index 00000000..15485170 --- /dev/null +++ b/tests/modules/Reports/Bug47271Test.php @@ -0,0 +1,78 @@ + \ No newline at end of file diff --git a/tests/modules/SNIP/SampleEvent.ics b/tests/modules/SNIP/SampleEvent.ics new file mode 100755 index 00000000..deaf2d0a --- /dev/null +++ b/tests/modules/SNIP/SampleEvent.ics @@ -0,0 +1,29 @@ +BEGIN:VCALENDAR +CALSCALE:GREGORIAN +X-WR-TIMEZONE;VALUE=TEXT:US/Pacific +METHOD:PUBLISH +PRODID:-//Apple Computer\, Inc//iCal 1.0//EN +X-WR-CALNAME;VALUE=TEXT:Example +VERSION:2.0 +BEGIN:VEVENT +SEQUENCE:0 +CREATED;TZID=US/Pacific:20021028T140000 +LAST-MODIFIED;TZID=US/Pacific:20021028T140000 +DTSTART;TZID=US/Pacific:20021028T140000 +DTSTAMP:20021028T011706Z +SUMMARY:Coffee with Jason +DESCRIPTION:Event reminder +ORGANIZER:MAILTO:mailtotest@example.com +LOCATION;LANGUAGE=en:Germany +LOCATION;LANGUAGE=no:Tyskland +LOCATION;ALTREP="http://xyzcorp.com/conf-rooms/f123.vcf":Conference Room - F123, Bldg. 002 +LOCATION:Conference Room - F123, Bldg. 002 +ATTENDEE;PARTSTAT=ACCEPTED:MAILTO:testemail@example.com +UID:EC9439B1-FF65-11D6-9973-003065F99D04 +DTEND;TZID=US/Pacific:20021028T150000 +BEGIN:VALARM +TRIGGER;VALUE=DURATION:-P1D +ACTION:DISPLAY +END:VALARM +END:VEVENT +END:VCALENDAR \ No newline at end of file diff --git a/tests/modules/Studio/RenameModulesTest.php b/tests/modules/Studio/RenameModulesTest.php new file mode 100755 index 00000000..c97ac1fe --- /dev/null +++ b/tests/modules/Studio/RenameModulesTest.php @@ -0,0 +1,253 @@ +language = 'en_us'; + } + + public function tearDown() + { + SugarTestUserUtilities::removeAllCreatedAnonymousUsers(); + unset($GLOBALS['current_user']); + } + + + public function testGetRenamedModules() + { + $rm = new RenameModules(); + $this->assertEquals(0, count($rm->getRenamedModules()) ); + } + + + public function testRenameContactsModule() + { + $module = 'Accounts'; + $newSingular = 'Company'; + $newPlural = 'Companies'; + + $rm = new RenameModules(); + + $_REQUEST['slot_0'] = 0; + $_REQUEST['key_0'] = $module; + $_REQUEST['svalue_0'] = $newSingular; + $_REQUEST['value_0'] = $newPlural; + $_REQUEST['delete_0'] = ''; + $_REQUEST['dropdown_lang'] = $this->language; + $_REQUEST['dropdown_name'] = 'moduleList'; + + global $app_list_strings; + if (!isset($app_list_strings['parent_type_display'][$module])) { + $app_list_strings['parent_type_display'][$module] = 'Account'; + } + $rm->save(FALSE); + + //Test app list strings + $app_list_string = return_app_list_strings_language('en_us'); + $this->assertEquals($newSingular, $app_list_string['moduleListSingular'][$module] ); + $this->assertEquals($newPlural, $app_list_string['moduleList'][$module] ); + $this->assertEquals($newSingular, $app_list_string['parent_type_display'][$module] ); + + //Test module strings for account + $accountStrings = return_module_language('en_us',$module, TRUE); + $this->assertEquals('Create Company', $accountStrings['LNK_NEW_ACCOUNT'], "Rename module failed for modules modStrings."); + $this->assertEquals('View Companies', $accountStrings['LNK_ACCOUNT_LIST'], "Rename module failed for modules modStrings."); + $this->assertEquals('Import Companies', $accountStrings['LNK_IMPORT_ACCOUNTS'], "Rename module failed for modules modStrings."); + $this->assertEquals('Company Search', $accountStrings['LBL_SEARCH_FORM_TITLE'], "Rename module failed for modules modStrings."); + + //Test related link renames + $contactStrings = return_module_language('en_us','Contacts', TRUE); + $this->assertEquals('Company Name:', $contactStrings['LBL_ACCOUNT_NAME'], "Rename related links failed for module."); + $this->assertEquals('Company ID:', $contactStrings['LBL_ACCOUNT_ID'], "Rename related links failed for module."); + + //Test subpanel renames + $campaignStrings = return_module_language('en_us','Campaigns', TRUE); + $this->assertEquals('Companies', $campaignStrings['LBL_CAMPAIGN_ACCOUNTS_SUBPANEL_TITLE'], "Renaming subpanels failed for module."); + // bug 45554: ensure labels are changed + $this->assertEquals('Companies', $campaignStrings['LBL_ACCOUNTS'], 'Renaming labels failed for module.'); + + //Ensure we recorded which modules were modified. + $renamedModules = $rm->getRenamedModules(); + $this->assertTrue( count($renamedModules) > 0 ); + + $this->removeCustomAppStrings(); + $this->removeModuleStrings( $renamedModules ); + } + + public function testRenameNonExistantModule() + { + $module = 'UnitTestDNEModule'; + $newSingular = 'UnitTest'; + $newPlural = 'UnitTests'; + + $rm = new RenameModules(); + + $_REQUEST['slot_0'] = 0; + $_REQUEST['key_0'] = $module; + $_REQUEST['svalue_0'] = $newSingular; + $_REQUEST['value_0'] = $newPlural; + $_REQUEST['delete_0'] = ''; + $_REQUEST['dropdown_lang'] = $this->language; + $_REQUEST['dropdown_name'] = 'moduleList'; + $_REQUEST['use_push'] = TRUE; + + $rm->save(FALSE); + + //Ensure no modules were modified + $renamedModules = $rm->getRenamedModules(); + $this->assertTrue( count($renamedModules) == 0 ); + + //Ensure none of the app list strings were modified. + $app_list_string = return_app_list_strings_language('en_us'); + $this->assertNotEquals($newSingular, $app_list_string['moduleListSingular'][$module] ); + $this->assertNotEquals($newPlural, $app_list_string['moduleList'][$module] ); + + } + + + private function removeCustomAppStrings() + { + $fileName = 'custom'. DIRECTORY_SEPARATOR . 'include'. DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR . $this->language . '.lang.php'; + if( file_exists($fileName) ) + { + @unlink($fileName); + } + } + + private function removeModuleStrings($modules) + { + foreach($modules as $module => $v) + { + $fileName = 'custom'. DIRECTORY_SEPARATOR . 'modules'. DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . 'language' . DIRECTORY_SEPARATOR . $this->language . '.lang.php'; + if( file_exists($fileName) ) + { + @unlink($fileName); + } + + } + + } + + /** + * @group bug46880 + * making sure subpanel is not renamed twice by both plural name and singular name + */ + public function testSubpanelRenaming() + { + $this->markTestSkipped('Because of bug 47239, Skipping test.'); + + $module = 'Accounts'; + $newSingular = 'Account1'; + $newPlural = 'Accounts2'; + + $rm = new RenameModules(); + + $_REQUEST['slot_0'] = 0; + $_REQUEST['key_0'] = $module; + $_REQUEST['svalue_0'] = $newSingular; + $_REQUEST['value_0'] = $newPlural; + $_REQUEST['delete_0'] = ''; + $_REQUEST['dropdown_lang'] = $this->language; + $_REQUEST['dropdown_name'] = 'moduleList'; + + global $app_list_strings; + if (!isset($app_list_strings['parent_type_display'][$module])) { + $app_list_strings['parent_type_display'][$module] = 'Account'; + } + $rm->save(FALSE); + + //Test subpanel renames + $bugStrings = return_module_language('en_us','Bugs', TRUE); + $this->assertEquals('Accounts2', $bugStrings['LBL_ACCOUNTS_SUBPANEL_TITLE'], "Renaming subpanels failed for module."); + + //Ensure we recorded which modules were modified. + $renamedModules = $rm->getRenamedModules(); + $this->assertTrue( count($renamedModules) > 0 ); + + //cleanup + $this->removeCustomAppStrings(); + $this->removeModuleStrings( $renamedModules ); + } + + /** + * @group bug45804 + */ + public function testDashletsRenaming() + { + $this->markTestSkipped('Because of bug 47239, Skipping test.'); + + $module = 'Accounts'; + $newSingular = 'Account1'; + $newPlural = 'Accounts2'; + + $rm = new RenameModules(); + + $_REQUEST['slot_0'] = 0; + $_REQUEST['key_0'] = $module; + $_REQUEST['svalue_0'] = $newSingular; + $_REQUEST['value_0'] = $newPlural; + $_REQUEST['delete_0'] = ''; + $_REQUEST['dropdown_lang'] = $this->language; + $_REQUEST['dropdown_name'] = 'moduleList'; + + global $app_list_strings; + if (!isset($app_list_strings['parent_type_display'][$module])) { + $app_list_strings['parent_type_display'][$module] = 'Account'; + } + $rm->save(FALSE); + + //Test dashlets renames + $callStrings = return_module_language('en_us', 'Accounts', TRUE); + $this->assertEquals('My Accounts2', $callStrings['LBL_HOMEPAGE_TITLE'], "Renaming dashlets failed for module."); + + //Ensure we recorded which modules were modified. + $renamedModules = $rm->getRenamedModules(); + $this->assertTrue( count($renamedModules) > 0 ); + + //cleanup + $this->removeCustomAppStrings(); + $this->removeModuleStrings( $renamedModules ); + } +} diff --git a/tests/modules/SubPanel/Bug40434Test.php b/tests/modules/SubPanel/Bug40434Test.php index a9cc9aac..40b4315e 100755 --- a/tests/modules/SubPanel/Bug40434Test.php +++ b/tests/modules/SubPanel/Bug40434Test.php @@ -1,4 +1,40 @@ setOutputBuffering = false; + SugarTestMergeUtilities::setupFiles(array('Calls'), array('editviewdefs'), 'tests/modules/UpgradeWizard/SugarMerge/metadata_files'); +} - function setUp() - { - $this->setOutputBuffering = false; - SugarTestMergeUtilities::setupFiles(array('Calls', 'Meetings'), array('editviewdefs'), 'tests/modules/UpgradeWizard/SugarMerge/metadata_files'); - } +function tearDown() { + SugarTestMergeUtilities::teardownFiles(); +} - function tearDown() - { - SugarTestMergeUtilities::teardownFiles(); - } +function testMegreCallsEditviewdefsFor611() { + require_once 'modules/UpgradeWizard/SugarMerge/EditViewMerge.php'; + $this->merge = new EditViewMerge(); + $this->merge->merge('Calls', 'tests/modules/UpgradeWizard/SugarMerge/metadata_files/611/modules/Calls/metadata/editviewdefs.php','modules/Calls/metadata/editviewdefs.php','custom/modules/Calls/metadata/editviewdefs.php'); - function testMergeCallsEditviewdefsFor611() - { - require_once 'modules/UpgradeWizard/SugarMerge/EditViewMerge.php'; - $this->merge = new EditViewMerge(); - $this->merge->merge('Calls', 'tests/modules/UpgradeWizard/SugarMerge/metadata_files/611/modules/Calls/metadata/editviewdefs.php','modules/Calls/metadata/editviewdefs.php','custom/modules/Calls/metadata/editviewdefs.php'); + //Load file + require('custom/modules/Calls/metadata/editviewdefs.php'); - //Load file - require('custom/modules/Calls/metadata/editviewdefs.php'); + //If we comment out EdtiViewMerge mergeTemplateMeta, then we don't see the forms[0] anymore + //echo var_export($viewdefs['Calls'], true); + - $this->assertNotContains('forms[0]', $viewdefs['Calls']['EditView']['templateMeta']['form']['buttons'][0]['customCode'], "forms[0] did not get replaced"); - } - - function testMergeMeetingsEditviewdefsFor611() - { - require_once 'modules/UpgradeWizard/SugarMerge/EditViewMerge.php'; - $this->merge = new EditViewMerge(); - $this->merge->merge('Meetings', 'tests/modules/UpgradeWizard/SugarMerge/metadata_files/611/modules/Meetings/metadata/editviewdefs.php','modules/Meetings/metadata/editviewdefs.php','custom/modules/Meetings/metadata/editviewdefs.php'); - - //Load file - require('custom/modules/Meetings/metadata/editviewdefs.php'); - - $this->assertNotContains('this.form.', $viewdefs['Meetings']['EditView']['templateMeta']['form']['buttons'][0]['customCode'], "this.form did not get replaced"); - } +} } \ No newline at end of file diff --git a/tests/modules/UpgradeWizard/SugarMerge/metadata_files/600/modules/Documents/metadata/editviewdefs.php b/tests/modules/UpgradeWizard/SugarMerge/metadata_files/600/modules/Documents/metadata/editviewdefs.php index eb6f7ebd..b257352a 100755 --- a/tests/modules/UpgradeWizard/SugarMerge/metadata_files/600/modules/Documents/metadata/editviewdefs.php +++ b/tests/modules/UpgradeWizard/SugarMerge/metadata_files/600/modules/Documents/metadata/editviewdefs.php @@ -45,9 +45,7 @@ $viewdefs['Documents']['EditView'] = array( array('label' => '10', 'field' => '30') ), 'javascript' => ' - - - + ', ), diff --git a/tests/modules/UpgradeWizard/SugarMerge/metadata_files/610/modules/Calls/metadata/editviewdefs.php b/tests/modules/UpgradeWizard/SugarMerge/metadata_files/610/modules/Calls/metadata/editviewdefs.php index bb240bb4..977f24ae 100755 --- a/tests/modules/UpgradeWizard/SugarMerge/metadata_files/610/modules/Calls/metadata/editviewdefs.php +++ b/tests/modules/UpgradeWizard/SugarMerge/metadata_files/610/modules/Calls/metadata/editviewdefs.php @@ -83,11 +83,8 @@ array ( ), ), 'javascript' => ' - - - - + ', 'useTabs' => false, diff --git a/tests/modules/UpgradeWizard/SugarMerge/metadata_files/610/modules/Documents/metadata/editviewdefs.php b/tests/modules/UpgradeWizard/SugarMerge/metadata_files/610/modules/Documents/metadata/editviewdefs.php index 92448b1f..5cd1ac82 100755 --- a/tests/modules/UpgradeWizard/SugarMerge/metadata_files/610/modules/Documents/metadata/editviewdefs.php +++ b/tests/modules/UpgradeWizard/SugarMerge/metadata_files/610/modules/Documents/metadata/editviewdefs.php @@ -46,10 +46,7 @@ $viewdefs['Documents']['EditView'] = array( array('label' => '10', 'field' => '30') ), 'javascript' => ' - - - - + ', ), 'panels' =>array ( diff --git a/tests/modules/UpgradeWizard/SugarMerge/metadata_files/610/modules/Documents/metadata/quickcreatedefs.php b/tests/modules/UpgradeWizard/SugarMerge/metadata_files/610/modules/Documents/metadata/quickcreatedefs.php index 2f421c5a..97578380 100755 --- a/tests/modules/UpgradeWizard/SugarMerge/metadata_files/610/modules/Documents/metadata/quickcreatedefs.php +++ b/tests/modules/UpgradeWizard/SugarMerge/metadata_files/610/modules/Documents/metadata/quickcreatedefs.php @@ -49,10 +49,7 @@ $viewdefs['Documents']['QuickCreate'] = array( 'includes' => array ( array('file' => 'include/javascript/popup_parent_helper.js'), - array('file' => 'include/jsolait/init.js'), - array('file' => 'include/jsolait/lib/urllib.js'), - array('file' => 'include/javascript/jsclass_base.js'), - array('file' => 'include/javascript/jsclass_async.js'), + array('file' => 'include/javascript/sugar_grp_jsolait.js'), array('file' => 'modules/Documents/documents.js'), ), ), diff --git a/tests/modules/UpgradeWizard/SugarMerge/metadata_files/611/modules/Calls/metadata/editviewdefs.php b/tests/modules/UpgradeWizard/SugarMerge/metadata_files/611/modules/Calls/metadata/editviewdefs.php index 5aecd4b8..f9ecd735 100755 --- a/tests/modules/UpgradeWizard/SugarMerge/metadata_files/611/modules/Calls/metadata/editviewdefs.php +++ b/tests/modules/UpgradeWizard/SugarMerge/metadata_files/611/modules/Calls/metadata/editviewdefs.php @@ -83,13 +83,10 @@ array ( 'field' => '30', ), ), - 'javascript' => ' - - + 'javascript' => ' - - - + + ', 'useTabs' => false, diff --git a/tests/modules/UpgradeWizard/SugarMerge/metadata_files/611/modules/Meetings/metadata/editviewdefs.php b/tests/modules/UpgradeWizard/SugarMerge/metadata_files/611/modules/Meetings/metadata/editviewdefs.php deleted file mode 100755 index f20af740..00000000 --- a/tests/modules/UpgradeWizard/SugarMerge/metadata_files/611/modules/Meetings/metadata/editviewdefs.php +++ /dev/null @@ -1,176 +0,0 @@ - - array ( - 'templateMeta' => - array ( - 'maxColumns' => '2', - 'form' => - array ( - 'hidden' => - array ( - 0 => '', - ), - 'buttons' => - array ( - 0 => - array ( - 'customCode' => '', - ), - 1 => 'CANCEL', - 2 => - array ( - 'customCode' => '', - ), - 3 => - array ( - 'customCode' => '{if $fields.status.value != "Held"}{/if}', - ), - ), - 'headerTpl' => 'modules/Meetings/tpls/header.tpl', - 'footerTpl' => 'modules/Meetings/tpls/footer.tpl', - ), - 'widths' => - array ( - 0 => - array ( - 'label' => '10', - 'field' => '30', - ), - 1 => - array ( - 'label' => '10', - 'field' => '30', - ), - ), - 'javascript' => ' - - - - - - -', - 'useTabs' => false, - ), - 'panels' => - array ( - 'lbl_meeting_information' => - array ( - array ( - array ( - 'name' => 'name', - - ), - array ( - 'name' => 'status', - 'fields' => - array ( - array ( - 'name' => 'status', - ), - ), - ), - array ( - 'name' => 'type', - 'fields' => - array ( - array ( - 'name' => 'type', - ), - ), - ), - ), - array ( - array ( - 'name' => 'date_start', - 'type' => 'datetimecombo', - 'displayParams' => - array ( - - 'updateCallback' => 'SugarWidgetScheduler.update_time();', - ), - ), - 1 => - array ( - 'name' => 'parent_name', - 'label' => 'LBL_LIST_RELATED_TO', - ), - ), - 2 => - array ( - array ( - 'name' => 'duration_hours', - 'label' => 'LBL_DURATION', - 'customCode' => '{literal}{/literal}{$fields.duration_minutes.value} {$MOD.LBL_HOURS_MINS}', - ), - array ( - 'name' => 'location', - 'comment' => 'Meeting location', - 'label' => 'LBL_LOCATION', - ), - ), - array ( - array ( - 'name' => 'reminder_time', - 'customCode' => '{if $fields.reminder_checked.value == "1"}{assign var="REMINDER_TIME_DISPLAY" value="inline"}{assign var="REMINDER_CHECKED" value="checked"}{else}{assign var="REMINDER_TIME_DISPLAY" value="none"}{assign var="REMINDER_CHECKED" value=""}{/if}
    {$fields.reminder_time.value}
    ', - 'label' => 'LBL_REMINDER', - ), - ), - array ( - array ( - 'name' => 'description', - 'comment' => 'Full text of the note', - 'label' => 'LBL_DESCRIPTION', - ), - ), - ), - 'LBL_PANEL_ASSIGNMENT' => - array ( - array ( - array ( - 'name' => 'assigned_user_name', - 'label' => 'LBL_ASSIGNED_TO_NAME', - ), - ), - ), - ), - ), -); -?> \ No newline at end of file diff --git a/tests/modules/Users/Bug46473Test.php b/tests/modules/Users/Bug46473Test.php new file mode 100755 index 00000000..be7f2824 --- /dev/null +++ b/tests/modules/Users/Bug46473Test.php @@ -0,0 +1,88 @@ +last_name = $last_name; + $emp->default_team = 1; + $emp->status = 'Active'; + $emp->employee_status = 'Active'; + $emp->user_name = 'test_user_name'; + $emp->save(); + $emp_id = $emp->id; + $this->assertNotNull($emp_id, 'User id should not be null.'); + + // list view + $view = new UsersViewList(); + $GLOBALS['action'] = 'index'; + $GLOBALS['module'] = 'Users'; + $_REQUEST['module'] = 'Users'; + $view->init($emp); + $view->lv = new ListViewSmarty(); + $view->display(); + + // ensure the new employee shows up in the users list view + $this->expectOutputRegex('/.*'.$last_name.'.*/'); + + // cleanup + unset($GLOBALS['action']); + unset($GLOBALS['module']); + unset($_REQUEST['module']); + $GLOBALS['db']->query("delete from users where id='{$emp_id}'"); + } +} + +?> \ No newline at end of file diff --git a/tests/service/Bug31003Test.php b/tests/service/Bug31003Test.php index fc993279..228e4c98 100755 --- a/tests/service/Bug31003Test.php +++ b/tests/service/Bug31003Test.php @@ -65,8 +65,8 @@ class Bug31003Test extends SOAPTestCase public function tearDown() { parent::tearDown(); - $GLOBALS['db']->query(sprintf("DELETE FROM prospects WHERE id = '%d'", $this->contact->id)); + $GLOBALS['db']->query("DELETE FROM prospects WHERE id = '{$this->contact->id}'"); SugarTestContactUtilities::removeAllCreatedContacts(); } -} \ No newline at end of file +} diff --git a/tests/service/Bug41296Test.php b/tests/service/Bug41296Test.php new file mode 100755 index 00000000..49767b9c --- /dev/null +++ b/tests/service/Bug41296Test.php @@ -0,0 +1,95 @@ +_soapURL = $GLOBALS['sugar_config']['site_url'].'/soap.php'; + $GLOBALS['current_user'] = SugarTestUserUtilities::createAnonymousUser(); + + $unid = uniqid(); + $time = date('Y-m-d H:i:s'); + + $contact = new Contact(); + $contact->id = 'c_'.$unid; + $contact->first_name = 'testfirst'; + $contact->last_name = 'testlast'; + $contact->email1 = 'one@example.com'; + $contact->email2 = 'one_other@example.com'; + $contact->new_with_id = true; + $contact->disable_custom_fields = true; + $contact->save(); + $this->c = $contact; + + parent::setUp(); + } + + public function tearDown() + { + $GLOBALS['db']->query("DELETE FROM contacts WHERE id= '{$this->c->id}'"); + $GLOBALS['db']->query("DELETE FROM contacts WHERE id= '{$this->_resultId}'"); + unset($this->c); + parent::tearDown(); + } + + public function testCreateNewContactWithNoEmail() + { + $this->_login(); + + $contacts_list=array( 'session'=>$this->_sessionId, 'module_name' => 'Contacts', + 'name_value_lists' => array( + array(array('name'=>'assigned_user_id' , 'value'=>$this->_user->id),array('name'=>'first_name' , 'value'=>'testfirst'),array('name'=>'last_name' , 'value'=>'testlast')) + )); + + $result = $this->_soapClient->call('set_entries',$contacts_list); + $this->_resultId = $result['ids'][0]; + $this->assertNotEquals($this->c->id, $result['ids'][0], "Contacts should not match"); + } + +} \ No newline at end of file diff --git a/tests/service/OAuthTest.php b/tests/service/OAuthTest.php new file mode 100755 index 00000000..a19ec7b8 --- /dev/null +++ b/tests/service/OAuthTest.php @@ -0,0 +1,209 @@ +query("DELETE FROM oauth_consumer where c_key='TESTCUSTOMER'"); + $GLOBALS['db']->query("DELETE FROM oauth_nonce where conskey='TESTCUSTOMER'"); + self::$_consumer = new OAuthKey(); + self::$_consumer->c_key = "TESTCUSTOMER"; + self::$_consumer->c_secret = "TESTSECRET"; + self::$_consumer->save(); + } + + public static function tearDownAfterClass() + { + unset($GLOBALS['beanList']); + unset($GLOBALS['beanFiles']); + unset($GLOBALS['app_list_strings']); + unset($GLOBALS['app_strings']); + unset($GLOBALS['mod_strings']); + unset($GLOBALS['current_user']); + $GLOBALS['db']->query("DELETE FROM oauth_consumer where c_key='TESTCUSTOMER'"); + $GLOBALS['db']->query("DELETE FROM oauth_nonce where conskey='TESTCUSTOMER'"); + $GLOBALS['db']->query("DELETE FROM oauth_tokens where consumer='".self::$_consumer->id."'"); + SugarTestUserUtilities::removeAllCreatedAnonymousUsers(); + } + + public function setUp() + { + if(!SugarOAuthServer::enabled() || !extension_loaded('oauth')) { + $this->markTestSkipped("No OAuth support"); + } + $this->oauth = new OAuth('TESTCUSTOMER','TESTSECRET',OAUTH_SIG_METHOD_HMACSHA1,OAUTH_AUTH_TYPE_URI); + $this->url = $GLOBALS['sugar_config']['site_url'].'service/v4/rest.php'; + $GLOBALS['current_user'] = self::$_user; + } + + protected function _returnLastRawResponse() + { + return "Error in web services call. Response was: {$this->_lastRawResponse}"; + } + + public function testOauthRequestToken() + { + $request_token_info = $this->oauth->getRequestToken($this->url."?method=oauth_request_token"); + $this->assertEquals($GLOBALS['sugar_config']['site_url'].'index.php?module=OAuthTokens&action=authorize', $request_token_info["authorize_url"]); + $this->assertEquals("true", $request_token_info["oauth_callback_confirmed"]); + $this->assertNotEmpty($request_token_info['oauth_token']); + $this->assertNotEmpty($request_token_info['oauth_token_secret']); + $rtoken = OAuthToken::load($request_token_info['oauth_token']); + $this->assertInstanceOf('OAuthToken', $rtoken); + $this->assertEquals(OAuthToken::REQUEST, $rtoken->tstate); + } + + public function testOauthAccessToken() + { + global $current_user; + $request_token_info = $this->oauth->getRequestToken($this->url."?method=oauth_request_token"); + $this->assertNotEmpty($request_token_info['oauth_token']); + $this->assertNotEmpty($request_token_info['oauth_token_secret']); + $token = $request_token_info['oauth_token']; + $secret = $request_token_info['oauth_token_secret']; + + $c_token = OAuthToken::load($token); + $this->assertInstanceOf('OAuthToken', $c_token); + // check token is in the right state + $this->assertEquals(OAuthToken::REQUEST, $c_token->tstate, "Request token has wrong state"); + $verify = $c_token->authorize(array("user" => $current_user->id)); + + $this->oauth->setToken($token, $secret); + $access_token_info = $this->oauth->getAccessToken($this->url."?method=oauth_access_token&oauth_verifier=$verify"); + $this->assertNotEmpty($access_token_info['oauth_token']); + $this->assertNotEmpty($access_token_info['oauth_token_secret']); + + $atoken = OAuthToken::load($access_token_info['oauth_token']); + $this->assertInstanceOf('OAuthToken', $atoken); + $this->assertEquals($current_user->id, $atoken->assigned_user_id); + // check this is an access token + $this->assertEquals(OAuthToken::ACCESS, $atoken->tstate, "Access token has wrong state"); + // check old token was invalidated + $rtoken = OAuthToken::load($token); + $this->assertInstanceOf('OAuthToken', $rtoken); + $this->assertEquals(OAuthToken::INVALID, $rtoken->tstate, "Request token was not invalidated"); + } + + protected function _makeRESTCall($method,$parameters) + { + // specify the REST web service to interact with + $url = $GLOBALS['sugar_config']['site_url'].'/service/v4/rest.php'; + // Open a curl session for making the call + $curl = curl_init($url); + // set URL and other appropriate options + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_POST, 1); + curl_setopt($curl, CURLOPT_HEADER, 0); + curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 0); + curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 ); + // build the request URL + $json = json_encode($parameters); + $postArgs = "method=$method&input_type=JSON&response_type=JSON&rest_data=$json"; + curl_setopt($curl, CURLOPT_POSTFIELDS, $postArgs); + // Make the REST call, returning the result + $response = curl_exec($curl); + // Close the connection + curl_close($curl); + + $this->_lastRawResponse = $response; + + // Convert the result from JSON format to a PHP array + return json_decode($response,true); + } + + public function testOauthServiceAccess() + { + global $current_user; + $request_token_info = $this->oauth->getRequestToken($this->url."?method=oauth_request_token"); + $token = $request_token_info['oauth_token']; + $secret = $request_token_info['oauth_token_secret']; + + $c_token = OAuthToken::load($token); + $verify = $c_token->authorize(array("user" => $current_user->id)); + + $this->oauth->setToken($token, $secret); + $access_token_info = $this->oauth->getAccessToken($this->url."?method=oauth_access_token&oauth_verifier=$verify"); + $token = $access_token_info['oauth_token']; + $secret = $access_token_info['oauth_token_secret']; + $this->oauth->setToken($token, $secret); + + $res = $this->oauth->fetch($this->url."?method=oauth_access&input_type=JSON&response_type=JSON"); + $this->assertTrue($res); + $session = json_decode($this->oauth->getLastResponse(), true); + $this->assertNotEmpty($session["id"]); + + // test fetch through OAuth + $res = $this->oauth->fetch($this->url."?method=get_user_id&input_type=JSON&response_type=JSON"); + $this->assertTrue($res); + $id = json_decode($this->oauth->getLastResponse(), true); + $this->assertEquals($current_user->id, $id); + // test fetch through session initiated by OAuth + $id2 = $this->_makeRESTCall('get_user_id', array("session" => $session["id"])); + $this->assertEquals($current_user->id, $id2); + } +} \ No newline at end of file diff --git a/tests/service/RESTAPI3Test.php b/tests/service/RESTAPI3Test.php index 1c5f7467..f5822886 100755 --- a/tests/service/RESTAPI3Test.php +++ b/tests/service/RESTAPI3Test.php @@ -619,6 +619,20 @@ class RESTAPI3Test extends Sugar_PHPUnit_Framework_TestCase $contactId1 = $result['id']; + $result = $this->_makeRESTCall('set_entry', + array( + 'session' => $session, + 'module' => 'Contacts', + 'name_value_list' => array( + array('name' => 'last_name', 'value' => 'New Contact 3'), + array('name' => 'description', 'value' => 'This is a contact created from a REST web services call'), + ), + ) + ); + + $this->assertTrue(!empty($result['id']) && $result['id'] != -1,$this->_returnLastRawResponse()); + $contactId3 = $result['id']; + $result = $this->_makeRESTCall('set_entry', array( 'session' => $session, @@ -641,7 +655,7 @@ class RESTAPI3Test extends Sugar_PHPUnit_Framework_TestCase 'module' => 'Accounts', 'module_id' => $accountId, 'link_field_name' => 'contacts', - 'related_ids' => array($contactId1,$contactId2), + 'related_ids' => array($contactId1,$contactId3,$contactId2), ) ); @@ -665,10 +679,12 @@ class RESTAPI3Test extends Sugar_PHPUnit_Framework_TestCase $GLOBALS['db']->query("DELETE FROM accounts WHERE id= '{$accountId}'"); $GLOBALS['db']->query("DELETE FROM contacts WHERE id= '{$contactId1}'"); $GLOBALS['db']->query("DELETE FROM contacts WHERE id= '{$contactId2}'"); + $GLOBALS['db']->query("DELETE FROM contacts WHERE id= '{$contactId3}'"); $GLOBALS['db']->query("DELETE FROM accounts_contacts WHERE account_id= '{$accountId}'"); - + $this->assertEquals($result['entry_list'][0]['name_value_list']['last_name']['value'],'New Contact 1',$this->_returnLastRawResponse()); $this->assertEquals($result['entry_list'][1]['name_value_list']['last_name']['value'],'New Contact 2',$this->_returnLastRawResponse()); + $this->assertEquals($result['entry_list'][2]['name_value_list']['last_name']['value'],'New Contact 3',$this->_returnLastRawResponse()); } public static function _subpanelLayoutProvider() diff --git a/tests/service/RESTAPI4Test.php b/tests/service/RESTAPI4Test.php index 3f28728f..cf148ed4 100755 --- a/tests/service/RESTAPI4Test.php +++ b/tests/service/RESTAPI4Test.php @@ -290,4 +290,96 @@ class RESTAPI4Test extends Sugar_PHPUnit_Framework_TestCase ) ); } + + + public function testRelateAccountToTwoContacts() + { + $result = $this->_login(); + $this->assertTrue(!empty($result['id']) && $result['id'] != -1,$this->_returnLastRawResponse()); + $session = $result['id']; + + $result = $this->_makeRESTCall('set_entry', + array( + 'session' => $session, + 'module' => 'Accounts', + 'name_value_list' => array( + array('name' => 'name', 'value' => 'New Account'), + array('name' => 'description', 'value' => 'This is an account created from a REST web services call'), + ), + ) + ); + + $this->assertTrue(!empty($result['id']) && $result['id'] != -1,$this->_returnLastRawResponse()); + + $accountId = $result['id']; + + $result = $this->_makeRESTCall('set_entry', + array( + 'session' => $session, + 'module' => 'Contacts', + 'name_value_list' => array( + array('name' => 'last_name', 'value' => 'New Contact 1'), + array('name' => 'description', 'value' => 'This is a contact created from a REST web services call'), + ), + ) + ); + + $this->assertTrue(!empty($result['id']) && $result['id'] != -1,$this->_returnLastRawResponse()); + + $contactId1 = $result['id']; + + $result = $this->_makeRESTCall('set_entry', + array( + 'session' => $session, + 'module' => 'Contacts', + 'name_value_list' => array( + array('name' => 'last_name', 'value' => 'New Contact 2'), + array('name' => 'description', 'value' => 'This is a contact created from a REST web services call'), + ), + ) + ); + + $this->assertTrue(!empty($result['id']) && $result['id'] != -1,$this->_returnLastRawResponse()); + + $contactId2 = $result['id']; + + // now relate them together + $result = $this->_makeRESTCall('set_relationship', + array( + 'session' => $session, + 'module' => 'Accounts', + 'module_id' => $accountId, + 'link_field_name' => 'contacts', + 'related_ids' => array($contactId1,$contactId2), + ) + ); + + $this->assertEquals($result['created'],1,$this->_returnLastRawResponse()); + + // check the relationship + $result = $this->_makeRESTCall('get_relationships', + array( + 'session' => $session, + 'module' => 'Accounts', + 'module_id' => $accountId, + 'link_field_name' => 'contacts', + 'related_module_query' => '', + 'related_fields' => array('last_name','description'), + 'related_module_link_name_to_fields_array' => array(), + 'deleted' => false, + ) + ); + + $returnedValues = array(); + $returnedValues[] = $result['entry_list'][0]['name_value_list']['last_name']['value']; + $returnedValues[] = $result['entry_list'][1]['name_value_list']['last_name']['value']; + + $GLOBALS['db']->query("DELETE FROM accounts WHERE id= '{$accountId}'"); + $GLOBALS['db']->query("DELETE FROM contacts WHERE id= '{$contactId1}'"); + $GLOBALS['db']->query("DELETE FROM contacts WHERE id= '{$contactId2}'"); + $GLOBALS['db']->query("DELETE FROM accounts_contacts WHERE account_id= '{$accountId}'"); + + $this->assertContains('New Contact 1',$returnedValues,$this->_returnLastRawResponse()); + $this->assertContains('New Contact 2',$returnedValues,$this->_returnLastRawResponse()); + } } \ No newline at end of file diff --git a/tests/tests/SugarTestLangPackCreatorTest.php b/tests/tests/SugarTestLangPackCreatorTest.php index 0a549b53..57a5531f 100755 --- a/tests/tests/SugarTestLangPackCreatorTest.php +++ b/tests/tests/SugarTestLangPackCreatorTest.php @@ -37,6 +37,14 @@ class SugarTestLangPackCreatorTest extends Sugar_PHPUnit_Framework_TestCase { + public function setUp() + { + SugarCache::$isCacheReset = false; + + if( empty($GLOBALS['current_language']) ) + $GLOBALS['current_language'] = $GLOBALS['sugar_config']['default_language']; + } + public function testSetAnyLanguageStrings() { $langpack = new SugarTestLangPackCreator(); diff --git a/themes/Sugar5/css/style.css b/themes/Sugar5/css/style.css index f9f194b7..315fa0bc 100644 --- a/themes/Sugar5/css/style.css +++ b/themes/Sugar5/css/style.css @@ -1564,8 +1564,8 @@ table.reportlistView{ padding: 4px 5px 4px 5px; border-left: none; border-right: none; - border-top: 1px solid black; - border-bottom: 1px solid black; + border-top: 1px solid Blackccc; + border-bottom: 1px solid Blackccc; background:Gainsboro; } @@ -2279,6 +2279,23 @@ embed padding-right: 0px; } +.dashletPanelMenu.wizard.import .bd .screen { + padding: 20px; + border: 0px none; + border-radius: 0px; + height: 487px; + overflow-x: hidden; + overflow-y: auto; + width: auto; + display: block; + background-color: #fff; +} +div.confirmTable { + overflow: auto; + width: 1056px; + position: relative; + margin-bottom: 20px; + } /* Bug 19728 - Email Templates detail view is different with edit view */ #html_div p { diff --git a/themes/Sugar5/js/style.js b/themes/Sugar5/js/style.js index be2b2791..f3cb901a 100644 --- a/themes/Sugar5/js/style.js +++ b/themes/Sugar5/js/style.js @@ -37,7 +37,7 @@ YAHOO.util.Event.onAvailable('sitemapLinkSpan',function() {ajaxStatus.showStatus(SUGAR.language.get('app_strings','LBL_LOADING_PAGE'));var smMarkup='';var callback={success:function(r){ajaxStatus.hideStatus();document.getElementById('sm_holder').innerHTML=r.responseText;with(document.getElementById('sitemap').style){display="block";position="absolute";right=0;top=80;} document.getElementById('sitemapClose').onclick=function() {document.getElementById('sitemap').style.display="none";}}} -postData='module=Home&action=sitemap&GetSiteMap=now&sugar_body_only=true';YAHOO.util.Connect.asyncRequest('POST','index.php',callback,postData);}});YAHOO.util.Event.onAvailable('subModuleList',IKEADEBUG);function IKEADEBUG() +postData='module=Home&action=sitemap&GetSiteMap=now&sugar_body_only=true';YAHOO.util.Connect.asyncRequest('POST','index.php',callback,postData);}});function IKEADEBUG() {var moduleLinks=document.getElementById('moduleList').getElementsByTagName("a");moduleLinkMouseOver=function() {var matches=/grouptab_([0-9]+)/i.exec(this.id);var tabNum=matches[1];var moduleGroups=document.getElementById('subModuleList').getElementsByTagName("span");for(var i=0;i=1){el.removeChild(el.firstChild);}} +el.innerHTML+=html;this.loadModuleList();}},loadModuleList:function(){var nodes=YAHOO.util.Selector.query('#moduleList>div'),currMenuBar;this.allMenuBars={};for(var i=0;i