diff --git a/pkg/vtiger/modules/ExtensionStore/languages/en_us/Settings/ExtensionStore.php b/pkg/vtiger/modules/ExtensionStore/languages/en_us/Settings/ExtensionStore.php new file mode 100644 index 0000000000000000000000000000000000000000..6e96e8baf39b7dd09f21e48c551746d170e3047c --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/languages/en_us/Settings/ExtensionStore.php @@ -0,0 +1,123 @@ +<?php +/* +* Copyright (C) www.vtiger.com. All rights reserved. +* @license Proprietary +*/ +$languageStrings = array( + 'LBL_PUBLISHER' => 'Publisher', + 'LBL_LICENSE' => 'License', + 'LBL_PUBLISHED_ON' => 'Published on', + 'LBL_INSTALL' => 'Install', + 'LBL_UPGRADE' => 'Upgrade', + 'LBL_VERSION' => 'Version', + 'LBL_DECLINE' => 'Decline', + 'LBL_ACCEPT_AND_INSTALL' => 'Accept and Install', + 'LBL_OK' => 'OK', + 'LBL_EXTENSION_NOT_COMPATABLE' => 'Extension is not Compatable', + 'LBL_INVALID_FILE' => 'Invalid File', + 'LBL_NO_LICENSE_PROVIDED' => 'No License Provided', + 'LBL_INSTALLATION' => 'Installation', + 'LBL_FAILED' => 'Failed', + 'LBL_SUCCESSFULL' => 'Successful', + 'LBL_INSTALLATION_LOG' => 'Installation Log', + 'LBL_UPDATED_MODULE' => ' module was updated successfully.', + 'LBL_UPDATING_MODULE' => 'Updating Module', + + //Extension Store translations + 'LBL_VTIGER_EXTENSION_STORE' => 'Vtiger Extension Store', + 'LBL_SEARCH_FOR_AN_EXTENSION' => 'Search for an extension..', + 'LBL_DOWNLOADS' => 'Downloads', + 'LBL_NO_EXTENSIONS_FOUND' => 'No Extensions Found', + 'LBL_REGISTER_TO_MARKET_PLACE' => 'Register to Marketplace', + 'LBL_MARKETPLACE_REGISTRATION' => 'Marketplace Registration', + 'LBL_MARKETPLACE_LOGIN' => 'Marketplace Login', + 'LBL_NEW_TO_MARKETPLCAE' => 'New to Marketplace ?', + 'LBL_CREATE_AN_ACCOUNT' => 'Create a new account', + 'LBL_SETUP_CARD_DETAILS' => 'Setup Card Details', + 'LBL_SETUP_CARD' => 'Setup Card', + 'LBL_CARD_NUMBER' => 'Card Number', + 'LBL_EXP_MONTH' => 'Exp Month', + 'LBL_EXP_YEAR' => 'Exp Year', + 'LBL_CVC_CODE' => 'CVC Code', + 'LBL_RESET' => 'Reset', + 'LBL_EXTENSION_STORE' => 'Extension Store', + 'LBL_INSTALLED' => 'Installed', + 'LBL_UPDATE_CARD_DETAILS' => 'Update Card Details', + 'LBL_BY' => 'by', + 'LBL_RATINGS' => 'Ratings', + 'LBL_DESCRIPTION' => 'Description', + 'LBL_AUTHOR_INFORMATION' => 'Author Information', + 'LBL_AUTHOR_NAME' => 'Author Name', + 'LBL_PHONE' => 'Phone', + 'LBL_EMAIL' => 'Email', + 'LBL_SCREEN_SHOTS' => 'Screenshots', + 'LBL_CUSTOMER_RATINGS' => 'Customer Ratings', + 'LBL_CUSTOMER_REVIEWS' => 'Customer Reviews', + 'LBL_WRITE_A_REVIEW' => 'Write a Review', + 'LBL_CUSTOMER_REVIEW' => 'Customer Review', + 'LBL_REVIEW' => 'Review', + 'LBL_CUSTOMERS_REVIEWED' => 'Customers Reviewed', + 'LBL_SINGLE_CUSTOMER_REVIEWED' => 'Single Customer Reviewed', + 'LBL_INSTALLATION_FAILED' => 'Installation Failed', + 'LBL_SUCCESSFULL_INSTALLATION' => 'Successful Installation', + 'LBL_INSTALL_FROM_ZIP' => 'Install from Zip', + 'LBL_MORE_DETAILS' => 'More Details', + 'Install' => 'Install', + 'Upgrade' => 'Upgrade', + 'LBL_RATE_IT' => 'Rate it.', + 'LBL_UNINSTALL' => 'UnInstall', + 'LBL_LAUNCH' => 'Launch', + 'LBL_SIGN_UP_FOR_FREE' => 'Sign up for free', + 'LBL_EMAIL_ADDRESS' => 'Email address', + 'LBL_FIRST_NAME' => 'First name', + 'LBL_LAST_NAME' => 'Last name', + 'LBL_COMPANY_NAME' => 'Company name', + 'LBL_PASSWORD' => 'Password', + 'LBL_CONFIRM_PASSWORD' => 'Confirm password', + 'LBL_REGISTER' => 'Register', + 'LBL_EXTENSION_STORE_LOGIN' => 'Extensionstore Login', + 'LBL_REMEMBER_ME' => 'Remember me', + 'LBL_TRY_IT' => 'Try it', + 'LBL_TRIAL_INSTALLED' => 'Trial Installed', + 'LBL_BUY' => 'Buy ', + 'LBL_LOGIN_TO_MARKET_PLACE' => 'Login to Marketplace', + 'LBL_LOGIN' => 'Login', + 'LBL_PHP_EXTENSION_LOADER_IS_NOT_AVAIABLE' => 'Please install extension loader', + 'LBL_INSTALL_EXTENSION_LOADER' => 'Install Extension Loader', + 'LBL_TO_CONTINUE_USING_EXTENSION_STORE' => 'To continue using Extension Store please install ', + 'LBL_DOWNLOAD' => 'Download', + 'LBL_COMPATIABLE_EXTENSION' => ' and enable it as zend_extension.', + 'LBL_MORE_DETAILS_ON_INSTALLATION' => 'For more details on installation ', + 'LBL_READ_HERE' => 'read here', + 'LBL_REVIEWS' => 'Reviews', + 'LBL_SIGNUP_FOR_MARKET_PLACE' => 'Signup for Marketplace', + 'LBL_UNAUTHORIZED' => 'Unauthorized', + 'LBL_EXPIRY_DATE' => 'Expiry Date', + 'LBL_LOGOUT' => 'Logout', + + 'firstname' => 'First Name', + 'lastname' => 'Last Name', + 'email' => 'Email', + 'company' => 'Company', + 'Phone' => 'Phone', + 'Website' => 'Website', + 'LBL_SECURITY_CODE' => 'Security Code', + 'LBL_WHAT_IS_SECURITY_CODE' => 'What is Security Code ?', + 'LBL_CARD_NUMBER_PLACEHOLDER' => '16 digit number on your card', + 'LBL_SECURITY_CODE_HELP_CONTENT' => 'The CVV Number(Card Verification Value) on your credit/debit card is a 3 digit number on VISA®, MasterCard® etc.. branded credit/debit cards.', +); +$jsLanguageStrings = array( + 'JS_PLEASE_SETUP_CARD_DETAILS_TO_INSTALL_THIS_EXTENSION' => 'Please setup card details to install this extension', + 'JS_UPDATE_CARD_DETAILS' => 'Update Card Details', + 'JS_ON' => 'on', + 'JS_RATINGS' => 'Ratings', + 'JS_INSTALLED' => 'Installed', + 'JS_TRIAL_INSTALLED' => 'Trial Installed', + 'JS_PLEASE_INSTALL_EXTENSION_LOADER_TO_INSTALL_THIS_EXTENSION_FROM_BELOW_LINK' => 'Please install extension loader to install this extension from below link', + 'JS_PLEASE_LOGIN_TO_MARKETPLACE_FOR_INSTALLING_EXTENSION' => 'Please login to marketplace for installing extension', + 'JS_PLEASE_SETUP_CARD_DETAILS_TO_INSTALL_EXTENSION' => 'Please setup card details to install extension', + 'JS_PLEASE_LOGIN_TO_MARKETPLACE_FOR_UNINSTALLING_EXTENSION' => 'Please login to marketplace for uninstalling extension', + 'JS_LBL_ARE_YOU_SURE_YOU_WANT_TO_INSTALL_THIS_EXTENSION' => 'Are you sure you want to install this extension?', + 'JS_CARD_DETAILS_UPDATED' => 'Card details updated!', + 'JS_LBL_ARE_YOU_SURE_YOU_WANT_TO_LOGOUT_FROM_EXTENSION' => 'Are you sure you want to log out from extension?', +); diff --git a/pkg/vtiger/modules/ExtensionStore/manifest.xml b/pkg/vtiger/modules/ExtensionStore/manifest.xml new file mode 100644 index 0000000000000000000000000000000000000000..4794c2b57429894132daba3c78bffe63b07155bc --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/manifest.xml @@ -0,0 +1,35 @@ +<?xml version='1.0'?> +<module> + <type>extension</type> + <name>ExtensionStore</name> + <label>Extension Store</label> + <parent>Settings</parent> + <version>1.2</version> + <dependencies> + <vtiger_version>6.0.0</vtiger_version> + <vtiger_max_version>6.*</vtiger_max_version> + </dependencies> + <tables> + <table> + <name>vtiger_extnstore_users</name> + <sql><![CDATA[CREATE TABLE `vtiger_extnstore_users` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `username` varchar(50) DEFAULT NULL, + `password` varchar(75) DEFAULT NULL, + `instanceurl` varchar(255) DEFAULT NULL, + `createdon` datetime DEFAULT NULL, + `deleted` int(1) NOT NULL DEFAULT 0, + PRIMARY KEY (`id`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8]]></sql> + </table> + </tables> + <customlinks> + <customlink> + <linktype>HEADERSCRIPT</linktype> + <linklabel>ExtensionStoreCommonHeaderScript</linklabel> + <linkurl><![CDATA[modules/ExtensionStore/ExtensionStore.js]]></linkurl> + <linkicon><![CDATA[]]></linkicon> + <sequence>0</sequence> + </customlink> + </customlinks> +</module> diff --git a/pkg/vtiger/modules/ExtensionStore/modules/ExtensionStore/ExtensionStore.js b/pkg/vtiger/modules/ExtensionStore/modules/ExtensionStore/ExtensionStore.js new file mode 100644 index 0000000000000000000000000000000000000000..7cd67416c8b8de4cf8f44eeabffb402cfdf8d8bf --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/modules/ExtensionStore/ExtensionStore.js @@ -0,0 +1,149 @@ +/* + * Copyright (C) www.vtiger.com. All rights reserved. + * @license Proprietary + */ + +jQuery.Class("ExtensionStore_ExtensionStore_Js", {}, { + + /** + * Function to register events for banner + */ + registerEventsForBanner : function(){ + var bxTarget = jQuery('.bxslider'); + var items = jQuery('li', bxTarget); + if (items.length) { + bxTarget.bxSlider({ + mode: 'fade', + auto: true, + pager: items.length > 1, + speed: items.length > 1 ? 1500 : 0, + pause: 3000, + onSlideBefore : function(){ + jQuery('.bx-viewport').css({'height': '110px', 'overflow': 'hidden'}); + } + }); + } + }, + + /** + * Function to getPromotions from marketplace + */ + getPromotions : function(){ + var thisInstance = this; + var params = { + 'module': 'ExtensionStore', + 'view': 'Listings', + 'mode': 'getPromotions' + }; + AppConnector.request(params).then( + function(data) { + if((typeof data != 'undefined') && (jQuery(data).find('img').length > 0)){ + jQuery('.dashboardHeading').append(data); + thisInstance.registerEventsForBanner(); + }else{ + jQuery('.togglePromotion').trigger('click'); + } + }, + function(error) {} + ); + }, + + /** + * Function to request get promotions from market place based on promotion closed date + */ + getPromotionsFromMarketPlace : function(promotionClosedDate){ + var thisInstance = this; + if(promotionClosedDate != null){ + var maxPromotionParams = { + 'module' : 'ExtensionStore', + 'action' : 'Promotion', + 'mode' : 'maxCreatedOn' + }; + AppConnector.request(maxPromotionParams).then( + function(data) { + var date = data['result']; + var dateObj = new Date(date); + var closedDate = new Date(promotionClosedDate); + var dateDiff = ((dateObj.getTime()) - (closedDate.getTime()))/(1000*60*60*24); + if(dateDiff > 0){ + thisInstance.getPromotions(); + } + }); + }else if(promotionClosedDate == null){ + thisInstance.getPromotions(); + } + }, + + registerEventsForTogglePromotion : function() { + var thisInstance = this; + jQuery('.togglePromotion').on('click', function(e){ + var element = jQuery(e.currentTarget); + var bannerContainer = jQuery(".banner-container"); + + if(element.hasClass('up')){ + bannerContainer.slideUp(); + element.find('.icon-chevron-up').addClass('hide'); + element.find('.icon-chevron-down').removeClass('hide'); + element.addClass('down').removeClass('up'); + }else if(element.hasClass('down')){ + if(bannerContainer.find('img').length <= 0){ + thisInstance.getPromotionsFromMarketPlace(null); + } + bannerContainer.slideDown(); + element.find('.icon-chevron-down').addClass('hide'); + element.find('.icon-chevron-up').removeClass('hide'); + element.addClass('up').removeClass('down'); + } + }); + }, + + insertTogglePromotionHtml : function(){ + var toggleHtml = '<span class="btn-group">'+ + '<button class="btn addButton togglePromotion up">'+ + '<span id="hide" class="icon icon-chevron-up"></span>'+ + '<span id="show" class="icon icon-chevron-down hide"></span>'+ + '</button>'+ + '</span>'; + jQuery('.dashboardHeading').find('.btn-toolbar').append(toggleHtml); + }, + + registerEvents: function() { + var thisInstance = this; + var moduleName = app.getModuleName(); + var date = new Date(); + var promotionClosedDate = date.getUTCFullYear()+"-"+(date.getMonth()+1)+"-"+date.getDate(); + var getPromotion = false; + thisInstance.insertTogglePromotionHtml(); + if(promotionClosedDate == null){ + getPromotion = true; + }else if(promotionClosedDate.length > 0){ + var closedDate = promotionClosedDate.split("-"); + var closedOn = new Date(parseInt(closedDate[0]), parseInt(closedDate[1]), parseInt(closedDate[2])); + var currentDate = new Date(); + var diff = (currentDate.getTime()) - (closedOn.getTime()); + var days = diff/(1000*60*60*24); + if(days >= 7){ + getPromotion = true; + }else { + getPromotion = false; + } + } + + if ((moduleName == "Home") && getPromotion) { + thisInstance.getPromotionsFromMarketPlace(promotionClosedDate); + }else if((moduleName == "Home") && !getPromotion){ + jQuery('.togglePromotion').find('.icon-chevron-up').addClass('hide'); + jQuery('.togglePromotion').find('.icon-chevron-down').removeClass('hide'); + jQuery('.togglePromotion').addClass('down').removeClass('up'); + } + thisInstance.registerEventsForTogglePromotion(); + } +}); + +jQuery(document).ready(function() { + var moduleName = app.getModuleName(); + if (moduleName == "Home") { + var instance = new ExtensionStore_ExtensionStore_Js(); + instance.registerEvents(); + } +}); diff --git a/pkg/vtiger/modules/ExtensionStore/modules/ExtensionStore/ExtensionStore.php b/pkg/vtiger/modules/ExtensionStore/modules/ExtensionStore/ExtensionStore.php new file mode 100644 index 0000000000000000000000000000000000000000..a93ae9f3e973f9f66ad2203a4c984bdf65c8a054 --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/modules/ExtensionStore/ExtensionStore.php @@ -0,0 +1,9 @@ +<?php +/* +* Copyright (C) www.vtiger.com. All rights reserved. +* @license Proprietary +*/ +Class ExtensionStore{ + +} +?> diff --git a/pkg/vtiger/modules/ExtensionStore/modules/ExtensionStore/actions/Promotion.php b/pkg/vtiger/modules/ExtensionStore/modules/ExtensionStore/actions/Promotion.php new file mode 100644 index 0000000000000000000000000000000000000000..f212c50bf042113687687e2b273ee62ed4ef000d --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/modules/ExtensionStore/actions/Promotion.php @@ -0,0 +1,34 @@ +<?php + +/* + * Copyright (C) www.vtiger.com. All rights reserved. + * @license Proprietary + */ + +class ExtensionStore_Promotion_Action extends Vtiger_Index_View{ + + public function __construct() { + parent::__construct(); + $this->exposeMethod('maxCreatedOn'); + } + + public function process(Vtiger_Request $request) { + $mode = $request->getMode(); + if (!empty($mode)) { + $this->invokeExposedMethod($mode, $request); + return; + } + } + + protected function maxCreatedOn(Vtiger_Request $request){ + $modelInstance = Settings_ExtensionStore_Extension_Model::getInstance(); + $promotions = $modelInstance->getMaxCreatedOn('Promotion', 'max', 'createdon'); + $response = new Vtiger_Response(); + if ($promotions['success'] != 'true') { + $response->setError('', $promotions['error']); + } else { + $response->setResult($promotions['response']); + } + $response->emit(); + } +} \ No newline at end of file diff --git a/pkg/vtiger/modules/ExtensionStore/modules/ExtensionStore/views/Listings.php b/pkg/vtiger/modules/ExtensionStore/modules/ExtensionStore/views/Listings.php new file mode 100644 index 0000000000000000000000000000000000000000..3632827920d767ef40114226dc7e5a378c2e535d --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/modules/ExtensionStore/views/Listings.php @@ -0,0 +1,36 @@ +<?php + +/* + * Copyright (C) www.vtiger.com. All rights reserved. + * @license Proprietary + */ + +class ExtensionStore_Listings_View extends Vtiger_Index_View{ + + public function __construct() { + parent::__construct(); + $this->exposeMethod('getPromotions'); + } + + public function process(Vtiger_Request $request) { + $mode = $request->getMode(); + if (!empty($mode)) { + $this->invokeExposedMethod($mode, $request); + return; + } + } + + /** + * Function to get news listings by passing type as News + */ + protected function getPromotions(Vtiger_Request $request) { + $modelInstance = Settings_ExtensionStore_Extension_Model::getInstance(); + $promotions = $modelInstance->getListings('','Promotion'); + $qualifiedModuleName = $request->getModule(false); + + $viewer = $this->getViewer($request); + $viewer->assign('PROMOTIONS', $promotions); + $viewer->assign('QUALIFIED_MODULE', $qualifiedModuleName); + $viewer->view('Promotions.tpl', $qualifiedModuleName); + } +} \ No newline at end of file diff --git a/pkg/vtiger/modules/ExtensionStore/settings/actions/Basic.php b/pkg/vtiger/modules/ExtensionStore/settings/actions/Basic.php new file mode 100644 index 0000000000000000000000000000000000000000..9ac901c2132696dac7dd1321a5caabc5c2f662e8 --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/settings/actions/Basic.php @@ -0,0 +1,208 @@ +<?php + +/* + * Copyright (C) www.vtiger.com. All rights reserved. + * @license Proprietary + */ + +class Settings_ExtensionStore_Basic_Action extends Settings_Vtiger_IndexAjax_View { + + protected $modelInstance; + + function __construct() { + parent::__construct(); + $this->exposeMethod('postReview'); + $this->exposeMethod('getDateString'); + $this->exposeMethod('uninstallExtension'); + $this->exposeMethod('registerAccount'); + $this->exposeMethod('updateTrialMode'); + $this->exposeMethod('updateCardDetails'); + $this->exposeMethod('logoutMarketPlace'); + } + + function process(Vtiger_Request $request) { + $mode = $request->getMode(); + if (!empty($mode)) { + echo $this->invokeExposedMethod($mode, $request); + return; + } + } + + protected function getModelInstance() { + if (!isset($this->modelInstance)) { + $this->modelInstance = Settings_ExtensionStore_Extension_Model::getInstance(); + } + return $this->modelInstance; + } + + protected function postReview(Vtiger_Request $request) { + $listing = $request->get('listing'); + $comment = $request->get('comment'); + $rating = $request->get('rating'); + $modelInstance = $this->getModelInstance(); + + $postResponse = $modelInstance->postReview($listing, $comment, $rating); + $response = new Vtiger_Response(); + if ($postResponse['success']) { + $postResult = $postResponse['result']; + $createdTime = str_replace('T', " ", $postResult['createdon']); + $postResult['createdon'] = $this->getDateString($createdTime); + $customerInfo = $modelInstance->getCustomerDetails($postResult['CustomerId']); + $postResult['Customer'] = $customerInfo['result']; + $response = new Vtiger_Response(); + $response->setResult($postResult); + } else { + $response->setError($postResponse['error']); + } + $response->emit(); + } + + protected function getDateString($date) { + $dateString = Vtiger_Util_Helper::formatDateTimeIntoDayString($date); + return $dateString; + } + + protected function logoutMarketPlace(Vtiger_Request $request) { + $modelInstance = $this->getModelInstance(); + $modelInstance->logoutMarketPlace($request); + } + + protected function uninstallExtension(Vtiger_Request $request) { + $extensionName = $request->get('extensionName'); + $extensionInstance = Settings_ExtensionStore_Extension_Model::getModuleFromExtnName($extensionName); + $extnType = $extensionInstance->get('extnType'); + $response = new Vtiger_Response(); + + if ($extnType == 'module') { + $extensionInstance->delete(); + //Remove extension files + global $root_directory; + $deletePaths = array(); + $pathToExtensionLayouts = $root_directory."layouts/vlayout/modules/$extensionName"; + $layoutDirAccessible = isFileAccessible($pathToExtensionLayouts); + if ($layoutDirAccessible) { + $deletePaths['layouts'] = $pathToExtensionLayouts; + } + + $pathToExtensionSettingsLayouts = $root_directory."layouts/vlayout/modules/Settings/$extensionName"; + $layoutSettingsDirAccessible = isFileAccessible($pathToExtensionSettingsLayouts); + if ($layoutSettingsDirAccessible) { + $deletePaths['settingsLayouts'] = $pathToExtensionSettingsLayouts; + } + + $pathToExtensionModule = $root_directory."modules/$extensionName"; + $moduleDirAccessible = isFileAccessible($pathToExtensionModule); + if ($moduleDirAccessible) { + $deletePaths['modules'] = $pathToExtensionModule; + } + + $pathToExtensionModuleSettings = $root_directory."modules/Settings/$extensionName"; + $moduleSettingsDirAccessible = isFileAccessible($pathToExtensionModuleSettings); + if ($moduleSettingsDirAccessible) { + $deletePaths['settingsModules'] = $pathToExtensionModuleSettings; + } + + foreach ($deletePaths as $dirName) { + $this->deleteRecursively($dirName); + } + $response->setResult(array('success' => true, 'message' => 'extension deleted')); + } else if ($extnType == 'language') { + $languageInstance = Settings_ExtensionStore_Extension_Model::getLanguageInstance($extensionName); + if ($languageInstance) { + $langPrefix = $languageInstance->get('prefix'); + Vtiger_Language::deregister($langPrefix); + //remove files + $langDir = "languages/$langPrefix"; + if (isFileAccessible($langDir)) { + $this->deleteRecursively($langDir); + } + } + $response->setResult(array('success' => true, 'message' => 'extension deleted')); + } else { + $response->setError('Error in deleting extension'); + } + $response->emit(); + } + + //Source from http:/ /php.net/manual/en/function.rmdir.php + protected function deleteRecursively($dirName) { + $files = array_diff(scandir($dirName), array('.', '..')); + foreach ($files as $file) { + (is_dir("$dirName/$file")) ? $this->deleteRecursively("$dirName/$file") : unlink("$dirName/$file"); + $afterDeletefiles = array_diff(scandir($dirName), array('.', '..')); + if (count($afterDeletefiles) == 0) { + rmdir($dirName); + } + } + return true; + } + + protected function registerAccount(Vtiger_Request $request) { + $options = array(); + $userAction = $request->get('userAction'); + $options['emailAddress'] = $request->get('emailAddress'); + $options['password'] = $request->get('password'); + $modelInstance = $this->getModelInstance(); + + if ($userAction == 'signup') { + $options['firstName'] = $request->get('firstName'); + $options['lastName'] = $request->get('lastName'); + $options['companyName'] = $request->get('companyName'); + $options['confirmPassword'] = $request->get('confirmPassword'); + $profieInfo = $modelInstance->signup($options); + } elseif ($userAction == 'login') { + $options['savePassword'] = ($request->get('savePassword') == 'true') ? true : false; + $options['password'] = md5($options['password']); + $profieInfo = $modelInstance->login($options); + } elseif ($userAction == 'register') { + $options['savePassword'] = $request->get('savePassword'); + $options['password'] = $options['password']; + $profieInfo = $modelInstance->register($options); + } + $response = new Vtiger_Response(); + if ($profieInfo['success'] != 'true') { + $response->setError('', $profieInfo['error']); + } else { + $response->setResult($profieInfo['result']); + } + $response->emit(); + } + + protected function updateTrialMode(Vtiger_Request $request) { + $response = new Vtiger_Response(); + $importedModuleName = $request->get('extensionName'); + $trial = $request->get('trial'); + $db = PearDatabase::getInstance(); + $db->pquery('UPDATE vtiger_tab SET trial = ? WHERE name = ?', array($trial, $importedModuleName)); + $response->setResult(array('success' => true, 'message' => 'Extension Store Installed')); + $response->emit(); + } + + protected function updateCardDetails(Vtiger_Request $request) { + $number = $request->get('cardNumber'); + $expmonth = (int) $request->get('expMonth'); + $expyear = (int) $request->get('expYear'); + $cvc = (int) $request->get('cvccode'); + $customerId = (int) $request->get('customerId'); + $customerCardId = (int) $request->get('customerCardId'); + $modelInstance = $this->getModelInstance(); + + if (empty($customerCardId)) { + $result = $modelInstance->createCard($number, $expmonth, $expyear, $cvc); + } else { + $result = $modelInstance->updateCard($number, $expmonth, $expyear, $cvc, $customerId); + } + $response = new Vtiger_Response(); + if ($result['success'] != 'true') { + $response->setError('', $result['error']); + } else { + $response->setResult($result['result']); + } + $response->emit(); + } + + public function validateRequest(Vtiger_Request $request) { + $request->validateWriteAccess(); + } + +} diff --git a/pkg/vtiger/modules/ExtensionStore/settings/connectors/ExtnStore.php b/pkg/vtiger/modules/ExtensionStore/settings/connectors/ExtnStore.php new file mode 100644 index 0000000000000000000000000000000000000000..4e76c3f4eaeb31ec8a595e46019d05c8626e4dbf --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/settings/connectors/ExtnStore.php @@ -0,0 +1,470 @@ +<?php + +/* + * Copyright (C) www.vtiger.com. All rights reserved. + * @license Proprietary + */ + +include_once dirname(__FILE__).'/../libraries/NetClient.php'; + +class Settings_ExtensionStore_ExtnStore_Connector { + + protected $url; + protected $auth; + protected $user_table = 'vtiger_extnstore_users'; + protected $identifier_name = 'extnstore'; + + protected function __construct($url) { + $this->url = $url; + } + + /** + * Function to get connector instance either pro or free version + * @staticvar null $singletons + * @param type $url + * @return \self + */ + public static function getInstance($url) { + static $singletons = null; + if ($singletons === null) { + $singletons = array(); + } + if (!isset($singletons[$url])) { + $singletons[$url] = new self($url); + } + return $singletons[$url]; + } + + /** + * Function to intialize basic auth based on data in database or session + * @global type $currentModule + * @return auth + * @throws Exception + */ + protected function initializeAuth() { + $db = PearDatabase::getInstance(); + if (!$this->auth) { + // Quick way to check if entry exists and pull 1st undeleted is + // to pull only one record by the order on deleted column and + // evaluating at-least one row exists. + $authResult = $db->pquery('SELECT * FROM '.$this->user_table.' ORDER BY deleted LIMIT 1', array()); + if ($db->num_rows($authResult)) { + $this->auth = $db->fetch_array($authResult); + if ($this->auth['deleted'] == 1) + $this->auth = null; + } + if (empty($this->auth['password'])) + $this->auth['password'] = isset($_SESSION[$this->identifier_name.'_password']) ? $_SESSION[$this->identifier_name.'_password'] : null; + if (empty($this->auth['username'])) + $this->auth['username'] = isset($_SESSION[$this->identifier_name.'_username']) ? $_SESSION[$this->identifier_name.'_username'] : null; + if (empty($this->auth['password']) && (empty($this->auth['username']))) { + throw new Exception(vtranslate('LBL_USERNAME_AND_PASSWORD_REQUIRED_FOR_AUTHENTICATION')); + } + } + return $this->auth; + } + + /** + * Function to perform client request to get response + * @param type $uri + * @param type $method + * @param type $params + * @param type $auth + * @return json response + * @throws Exception + */ + protected function api($uri, $method, $params, $auth) { + if ($auth) { + try { + $this->initializeAuth(); + } catch (Exception $ex) { + return array('success' => 'false', 'error' => $ex->getMessage()); + } + } + + $fn = ($method == "GET" || $method == "DLD") ? "doGet" : "doPost"; + if ($method == "PUT") + $fn = "doPut"; + $client = $this->getNetClientInstance($method, $uri); + + if ($auth && $this->auth) { + $authParams = $this->prepareAuthParams($this->auth['username'], $this->auth['password']); + $client->setAuthorization($authParams['username'], $authParams['password']); + } + + $content = $client->$fn($params); + $response = $content['response']; + $status = $content['status']; + + if (($status != 200)) { + throw new Exception(isset($content['errorMessage']) ? $content['errorMessage'] : $response); + } + + if ($method == "DLD") { + return $response; + } else { + $json = Zend_Json::decode($response); + if ($json) { + if ($json['success']) { + return $json['result']; + } else { + throw new Exception($json['error']['message']); + } + } + } + return null; + } + + /** + * Function to get net client instance for free version + * @param type $method + * @param type $uri + * @return \Settings_ExtensionStore_NetClient + */ + protected function getNetClientInstance($method, $uri) { + $clientInstance = new Settings_ExtensionStore_NetClient($method == "DLD" ? $uri : ($this->url.$uri)); + return $clientInstance; + } + + /** + * Function to generate suth params for free version + * @param type $username + * @param type $password + * @return type array + */ + protected function prepareAuthParams($username, $password) { + return array('username' => $username, + 'password' => urlencode(Zend_Json::encode(array('password' => $password)))); + } + + /** + * Function to get session identifier name + * @return type string + */ + public function getSessionIdentifier() { + return $this->identifier_name; + } + + /** + * Function to get extension table name + * @return type string + */ + public function getExtensionTable() { + return $this->user_table; + } + + /** + * Function to get max created on for promotions + */ + public function getMaxCreatedOn($type = 'Extension', $function, $field) { + $q = array('type' => $type); + try { + $response = $this->api('/app/listings', 'GET', $q ? array('q' => Zend_Json::encode($q), 'fn' => $function, 'max' => $field) : null, false); + return array('success' => true, 'response' => $response); + } catch (Exception $ex) { + return array('success' => false, 'error' => $ex->getMessage()); + } + } + + /** + * Function to get basic listings based on type of listing + * @param type $id + * @param type $type + * @return type json reponse + */ + public function getListings($id = null, $type = 'Extension') { + $q = $id ? array('id' => $id, 'type' => $type) : array('type' => $type); + try { + $response = $this->api('/app/listings', 'GET', $q ? array('q' => Zend_Json::encode($q)) : null, false); + return array('success' => true, 'response' => $response); + } catch (Exception $ex) { + return array('success' => false, 'error' => $ex->getMessage()); + } + } + + /** + * Function to get specified listing based on type of listing + * @param type $term + * @param type $type + * @return type json response + */ + public function findListings($term = null, $type = 'Extension') { + $q = array('term' => $term, 'type' => $type); + try { + $response = $this->api('/app/searchlistings', 'GET', array('q' => Zend_Json::encode($q)), false); + return array('success' => true, 'response' => $response); + } catch (Exception $ex) { + return array('success' => false, 'error' => $ex->getMessage()); + } + } + + /** + * Function to download listing + * @param type $downloadurl + * @return type + */ + public function download($downloadurl) { + try { + $response = $this->api($downloadurl, 'DLD', null, true); + return array('success' => true, 'response' => $response); + } catch (Exception $ex) { + return array('success' => false, 'error' => $ex->getMessage()); + } + } + + /** + * Function to get customer reviews of listing + * @param type $extensionId + * @return type json response + */ + public function getCustomerReviews($extensionId) { + $q = $extensionId ? array('listing' => $extensionId) : null; + try { + return $this->api('/app/reviews', 'GET', $q ? array('q' => Zend_Json::encode($q)) : null, false); + } catch (Exception $ex) { + return array('success' => false, 'error' => $ex->getMessage()); + } + } + + /** + * Function to get author information of listing + * @param type $extensionId + * @return type json response + */ + public function getListingAuthor($extensionId) { + $q = $extensionId ? array('listing' => $extensionId) : null; + try { + return $this->api('/app/listingauthor', 'GET', $q ? array('q' => Zend_Json::encode($q)) : null, false); + } catch (Exception $ex) { + return array('success' => false, 'error' => $ex->getMessage()); + } + } + + /** + * Function to post review for listing + * @param type $listing + * @param type $comment + * @param type $rating + * @return type json response + */ + public function postReview($listing, $comment, $rating) { + $listing = $listing ? array('listing' => $listing) : null; + $comment = $comment ? array('comment' => $comment, 'rating' => $rating) : null; + try { + $response = $this->api('/customer/reviews', 'POST', $listing ? array('q' => Zend_Json::encode($listing), 'review' => Zend_Json::encode($comment)) : null, true); + return array('success' => true, 'result' => $response); + } catch (Exception $ex) { + return array('success' => false, 'error' => $ex->getMessage()); + } + } + + /** + * Function to get screen shots of listing + * @param type $extensionId + * @return type json response + */ + public function getScreenShots($extensionId) { + $q = $extensionId ? array('listing' => $extensionId) : null; + try { + return $this->api('/app/listingscreenshots', 'GET', $q ? array('q' => Zend_Json::encode($q)) : null, false); + } catch (Exception $ex) { + return array('success' => false, 'error' => $ex->getMessage()); + } + } + + /** + * Function to verify purchase of extension + * @param $listingName => extension name to verify purchase + */ + public function verifyPurchase($listingName) { + $q = $listingName ? array('identifier' => $listingName) : null; + try { + return $this->api('/customer/mysubscriptions', 'GET', $q ? array('type' => 'verifypurchase', 'q' => Zend_Json::encode($q)) : null, true); + } catch (Exception $ex) { + return array('success' => false, 'error' => $ex->getMessage()); + } + } + + /** + * Function to retrieve profile of loged in user + * @return type + */ + public function getProfile() { + try { + return $this->api('/customer/profile', 'GET', '', true); + } catch (Exception $ex) { + return array('success' => false, 'error' => $ex->getMessage()); + } + } + + /** + * Function to create card details for logged in user in pro version + * @param type $number + * @param type $expmonth + * @param type $expyear + * @param type $cvc + * @return type json response + */ + public function createCard($number, $expmonth, $expyear, $cvc) { + $cardDetails = array('number' => $number, 'expmonth' => $expmonth, 'expyear' => $expyear, 'cvc' => $cvc); + try { + $response = $this->api('/customer/card', 'POST', $cardDetails, true); + return array('success' => true, 'result' => $response); + } catch (Exception $ex) { + return array('success' => false, 'error' => $ex->getMessage()); + } + } + + /** + * Function to update card details for logged in user + * @param type $number + * @param type $expmonth + * @param type $expyear + * @param type $cvc + * @param type $customerId + * @return type json response + */ + public function updateCard($number, $expmonth, $expyear, $cvc, $customerId) { + $cardDetails = array('number' => $number, 'expmonth' => $expmonth, 'expyear' => $expyear, 'cvc' => $cvc, 'id' => $customerId); + try { + $response = $this->api('/customer/card', 'PUT', $cardDetails, true); + return array('success' => true, 'result' => $response); + } catch (Exception $ex) { + return array('success' => false, 'error' => $ex->getMessage()); + } + } + + /** + * Function to get Customer Card Details + * @param array $cardId + * @return type array + */ + public function getCardDetails($cardId) { + $cardId = array('id' => $cardId); + try { + return $this->api('/customer/card', 'GET', $cardId, true); + } catch (Exception $ex) { + return array('success' => false, 'error' => $ex->getMessage()); + } + } + + /** + * Function to signup for marketplace + * @param type $username + * @param type $password + * @param type $confirmPassword + * @param type $firstName + * @param type $lastName + * @param type $companyName + * @return type json result + */ + public function signUp($username, $password, $confirmPassword, $firstName, $lastName, $companyName) { + $signupParams = $this->prepareSignUpParams($username, $password, $confirmPassword, $firstName, $lastName, $companyName); + try { + $this->auth = $this->api('/app/customer', 'POST', $signupParams, false); + if ($this->auth) { + $this->persistLogin($this->auth['email'], $this->auth['password'], false); + } + return array('success' => true, 'result' => $this->auth); + } catch (Exception $ex) { + return array('success' => false, 'error' => $ex->getMessage()); + } + } + + /** + * Function to prepare signup params for signup operation + * @param type $username + * @param type $password + * @param type $confirmPassword + * @param type $firstName + * @param type $lastName + * @param type $companyName + * @return type array + */ + protected function prepareSignUpParams($username, $password, $confirmPassword, $firstName, $lastName, $companyName) { + return array('email' => $username, + 'password' => $password, + 'confirmPassword' => $confirmPassword, + 'firstname' => $firstName, + 'lastname' => $lastName, + 'company' => $companyName); + } + + /** + * Function to retrieve persistence status of login + * @return boolean + */ + protected function getPersistenceStatus() { + $db = PearDatabase::getInstance(); + $result = $db->pquery('SELECT 1 FROM '.$this->user_table, array()); + if ($db->num_rows($result)) { + return true; + } + return false; + } + + /** + * Function to persist login based on status of $persistLogin + * @param type $userName + * @param type $password + * @param type $persistLogin + */ + protected function persistLogin($userName, $password, $rememberPassword) { + $db = PearDatabase::getInstance(); + if ($rememberPassword) { + $db->pquery('DELETE FROM '.$this->user_table, array()); + $db->pquery('INSERT INTO '.$this->user_table.'(username,password, createdon) VALUES(?,?,?)', array($userName, $password, date('Y-m-d H:i:s'))); + } else { + $persistanceStatus = $this->getPersistenceStatus(); + if (!$persistanceStatus) { + $db->pquery('INSERT INTO '.$this->user_table.' (username, createdon) VALUES(?,?)', array($userName, date('Y-m-d H:i:s'))); + } + $_SESSION[$this->identifier_name.'_username'] = $userName; + $_SESSION[$this->identifier_name.'_password'] = $password; + } + } + + /** + * Function to login to market place and persist data based on $persistLogin + * @param type $userName + * @param type $password + * @param type $persistLogin + * @return type + */ + public function login($userName, $password, $persistLogin) { + try { + /** set user entered password to session as we are using to set auth + * header initializeAuth() function which we are depending on session + * password if password not exists in db + **/ + $_SESSION[$this->identifier_name.'_username'] = $userName; + $_SESSION[$this->identifier_name.'_password'] = $password; + $this->auth = $this->api('/customer/profile', 'GET', '', true); + if ($this->auth) { + $this->persistLogin($this->auth['email'], $this->auth['password'], $persistLogin); + } + return array('success' => true, 'result' => $this->auth); + } catch (Exception $ex) { + //Should flush credentials from session if login fails + $_SESSION[$this->identifier_name.'_username'] = null; + $_SESSION[$this->identifier_name.'_password'] = null; + $exceptionMessage = $ex->getMessage(); + if (empty($exceptionMessage)) { + $error = vtranslate('LBL_UNAUTHORIZED', 'Settings:ExtensionStore'); + } else { + $error = $exceptionMessage; + } + return array('success' => false, 'error' => $error); + } + } + + public function getCustomerDetails($customerId) { + try { + $response = $this->api("/app/customer?id=$customerId", 'GET', '', true); + return array('success' => true, 'result' => $response); + } catch (Exception $ex) { + return array('success' => false, 'error' => $ex->getMessage()); + } + } + +} diff --git a/pkg/vtiger/modules/ExtensionStore/settings/libraries/LoaderSuggest.php b/pkg/vtiger/modules/ExtensionStore/settings/libraries/LoaderSuggest.php new file mode 100644 index 0000000000000000000000000000000000000000..047ad18c100286735dcb1db6625410ee9d4d6f40 --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/settings/libraries/LoaderSuggest.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright (c) 2004-2014 All Right Reserved, www.vtiger.com + * Vtiger Proprietary License + * The contents of this file cannot be modified or redistributed + * without explicit permission from Vtiger (www.vtiger.com). + */ + +Class Settings_ModuleManager_LoaderSuggest { + + function vtiger_extensionloader_suggest() { + $PHPVER = sprintf("%s.%s", PHP_MAJOR_VERSION, PHP_MINOR_VERSION); + $OSHWINFO= str_replace('Darwin', 'Mac', PHP_OS) . '_' . php_uname('m'); + + $WIN = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')? true : false; + + $EXTFNAME = 'vtigerextn_loader'; + $EXTNFILE = $EXTFNAME . ($WIN? '.dll' :'.so'); + + $DISTFILE = sprintf("%s_%s_%s.so", $EXTFNAME, $PHPVER, $OSHWINFO); + $DISTFILEZIP = sprintf("%s_%s_%s-yyyymmdd.zip", $EXTFNAME, $PHPVER, $OSHWINFO); + + return array( + 'loader_zip' => $DISTFILEZIP, + 'loader_file' => $DISTFILE, + 'php_ini' => php_ini_loaded_file(), + 'extensions_dir' => ini_get('extension_dir') + ); + } +} \ No newline at end of file diff --git a/pkg/vtiger/modules/ExtensionStore/settings/libraries/NetClient.php b/pkg/vtiger/modules/ExtensionStore/settings/libraries/NetClient.php new file mode 100644 index 0000000000000000000000000000000000000000..26c6919d39201fc78b4f5ed7a5632026ca1e8221 --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/settings/libraries/NetClient.php @@ -0,0 +1,95 @@ +<?php + +/* + * Copyright (C) www.vtiger.com. All rights reserved. + * @license Proprietary + */ + +include_once dirname(__FILE__).'/RestClient.php'; + +/** + * Provides API to work with HTTP Connection. + * @package vtlib + */ +class Settings_ExtensionStore_NetClient { + + protected $client; + protected $url; + protected $response; + protected $headers = array(); + + /** + * Constructor + * @param String URL of the site + * Example: + * $client = new Vtiger_New_Client('http://www.vtiger.com'); + */ + function __construct($url) { + $this->url = $url; + $this->client = new Settings_ExtensionStore_RestClient(); + $this->response = false; + $this->setDefaultHeaders(); + } + + function setDefaultHeaders() { + $headers = array(); + if (isset($_SERVER)) { + global $site_URL; + $headers['referer'] = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : ($site_URL."?noreferer"); + + if (isset($_SERVER['HTTP_USER_AGENT'])) { + $headers['user-agent'] = $_SERVER['HTTP_USER_AGENT']; + } + } else { + global $site_URL; + $headers['referer'] = ($site_URL."?noreferer"); + } + + $this->headers = $headers; + } + + function setAuthorization($username, $password) { + $this->client->setBasicAuthentication($username, $password); + } + + /** + * Set custom HTTP Headers + * @param Map HTTP Header and Value Pairs + */ + function setHeaders($headers) { + $this->client->buildCurlOptions($headers, array()); + } + + /** + * Perform a GET request + * @param Map key-value pair or false + * @param Integer timeout value + */ + function doGet($params = false) { + $response = $this->client->get($this->url, $params, $this->headers); + return $response; + } + + /** + * Perform a POST request + * @param Map key-value pair or false + * @param Integer timeout value + */ + function doPost($params = false) { + $response = $this->client->post($this->url, $params, $this->headers); + return $response; + } + + /** + * Perform a PUT request + * @param Map key-value pair or false + * @param Integer timeout value + */ + function doPut($params = false) { + $response = $this->client->put($this->url, $params, $this->headers); + return $response; + } + +} + +?> \ No newline at end of file diff --git a/pkg/vtiger/modules/ExtensionStore/settings/libraries/RestClient.php b/pkg/vtiger/modules/ExtensionStore/settings/libraries/RestClient.php new file mode 100644 index 0000000000000000000000000000000000000000..ca302382482ceea5f809907c812fb737974199c2 --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/settings/libraries/RestClient.php @@ -0,0 +1,151 @@ +<?php + +/* + * Copyright (C) www.vtiger.com. All rights reserved. + * @license Proprietary + */ + +class Settings_ExtensionStore_RestClient { + + protected static $name = 'ExtensionStoreRestClient'; + protected static $version = '1.0'; + protected $defaultHeaders = array(); + protected $defaultOptions = array(); + + public function __construct() { + global $site_URL, $current_vtiger_version; + + $this->defaultOptions[CURLOPT_REFERER] = $site_URL; + $this->defaultOptions[CURLOPT_USERAGENT] = self::$name.'/'.self::$version.'(CRM '.$current_vtiger_version.')'; + $this->defaultOptions[CURLOPT_RETURNTRANSFER] = true; + $this->defaultOptions[CURLOPT_FOLLOWLOCATION] = true; + $this->defaultOptions[CURLOPT_MAXREDIRS] = 5; + $this->defaultOptions[CURLOPT_SSL_VERIFYPEER] = 0; + $this->defaultOptions[CURLOPT_SSL_VERIFYHOST] = 0; + $this->defaultOptions[CURLOPT_TIMEOUT] = 30; + + $this->defaultHeaders['Content-Type'] = 'application/x-www-form-urlencoded'; + $this->defaultHeaders['Cache-Control'] = 'no-cache'; + } + + public function setDefaultOption($option, $value) { + $this->defaultOptions[$option] = $value; + return $this; + } + + public function setDefaultHeader($header, $value) { + $this->defaultHeaders[$header] = $value; + return $this; + } + + public function setBasicAuthentication($username, $password) { + $this->defaultHeaders['Authorization'] = 'Basic '.base64_encode($username.':'.$password); + } + + protected function exec($curlopts) { + $curl = curl_init(); + foreach ($curlopts as $option => $value) { + if ($option) { + curl_setopt($curl, $option, $value); + } + } + + // To be secure - we don't want user to override this + // and open doors for hackers. + $cookiefile = tempnam(sys_get_temp_dir(), ".".uniqid()."co"); + $cookiefp = fopen($cookiefile, "w"); + + curl_setopt($curl, CURLOPT_COOKIEJAR, $cookiefile); + curl_setopt($curl, CURLOPT_COOKIEFILE, $cookiefile); + + // Now execute + $response = curl_exec($curl); + $status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + + $responseData = array('response' => $response, 'status' => $status); + if (curl_errno($curl)) { + $errorMessage = curl_error($curl); + $responseData['errorMessage'] = $errorMessage; + } + curl_close($curl); + + fclose($cookiefp); + unlink($cookiefile); + + return $responseData; + } + + protected function buildCurlOptions(array $headers, array $options) { + foreach ($this->defaultOptions as $option => $value) { + switch ($option) { + // Stop overrides on some keys. + case CURLOPT_REFERER: + case CURLOPT_USERAGENT: + $options[$option] = $value; + break; + default: + // Pickup the overriding value + if (!isset($options[$option])) { + $options[$option] = $value; + } + break; + } + } + + $headeropts = array(); + foreach ($this->defaultHeaders as $key => $value) { + // Respect the overriding value + if ($headers && isset($headers[$key])) + continue; + $headeropts[] = ($key.': '.$value); + } + foreach ($headers as $key => $value) + $headeropts[] = ($key.': '.$value); + $options[CURLOPT_HTTPHEADER] = $headeropts; + + return $options; + } + + public function get($url, $params = array(), $headers = array(), $options = array()) { + $curlopts = $this->buildCurlOptions($headers, $options); + + + $curlopts[CURLOPT_HTTPGET] = true; + + if (!empty($params)) { + if (stripos($url, '?') === false) + $url .= '?'; + else + $url .= '&'; + $url .= http_build_query($params, '', '&'); + } + + $curlopts[CURLOPT_URL] = $url; + return $this->exec($curlopts); + } + + public function post($url, $params = array(), $headers = array(), $options = array()) { + $curlopts = $this->buildCurlOptions($headers, $options); + + $curlopts[CURLOPT_POST] = true; + if ($params) { + $curlopts[CURLOPT_POSTFIELDS] = http_build_query($params, '', '&'); + } + + $curlopts[CURLOPT_URL] = $url; + return $this->exec($curlopts); + } + + public function put($url, $params = array(), $headers = array(), $options = array()) { + $curlopts = $this->buildCurlOptions($headers, $options); + + $curlopts[CURLOPT_CUSTOMREQUEST] = 'PUT'; + if ($params) { + $curlopts[CURLOPT_POSTFIELDS] = http_build_query($params, '', '&'); + } + + $curlopts[CURLOPT_URL] = $url; + return $this->exec($curlopts); + } + +} diff --git a/pkg/vtiger/modules/ExtensionStore/settings/libraries/jasny-bootstrap.min.js b/pkg/vtiger/modules/ExtensionStore/settings/libraries/jasny-bootstrap.min.js new file mode 100644 index 0000000000000000000000000000000000000000..6eb175625c1061a57073f4cd2d7fc67878205030 --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/settings/libraries/jasny-bootstrap.min.js @@ -0,0 +1,6 @@ +/*! + * Jasny Bootstrap v3.1.3 (http://jasny.github.io/bootstrap) + * Copyright 2012-2014 Arnold Daniels + * Licensed under Apache-2.0 (https://github.com/jasny/bootstrap/blob/master/LICENSE) + */ +if("undefined"==typeof jQuery)throw new Error("Jasny Bootstrap's JavaScript requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}void 0===a.support.transition&&(a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one(a.support.transition.end,function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b()}))}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.state=null,this.placement=null,this.options.recalc&&(this.calcClone(),a(window).on("resize",a.proxy(this.recalc,this))),this.options.autohide&&a(document).on("click",a.proxy(this.autohide,this)),this.options.toggle&&this.toggle(),this.options.disablescrolling&&(this.options.disableScrolling=this.options.disablescrolling,delete this.options.disablescrolling)};b.DEFAULTS={toggle:!0,placement:"auto",autohide:!0,recalc:!0,disableScrolling:!0},b.prototype.offset=function(){switch(this.placement){case"left":case"right":return this.$element.outerWidth();case"top":case"bottom":return this.$element.outerHeight()}},b.prototype.calcPlacement=function(){function b(a,b){if("auto"===e.css(b))return a;if("auto"===e.css(a))return b;var c=parseInt(e.css(a),10),d=parseInt(e.css(b),10);return c>d?b:a}if("auto"!==this.options.placement)return void(this.placement=this.options.placement);this.$element.hasClass("in")||this.$element.css("visiblity","hidden !important").addClass("in");var c=a(window).width()/this.$element.width(),d=a(window).height()/this.$element.height(),e=this.$element;this.placement=c>=d?b("left","right"):b("top","bottom"),"hidden !important"===this.$element.css("visibility")&&this.$element.removeClass("in").css("visiblity","")},b.prototype.opposite=function(a){switch(a){case"top":return"bottom";case"left":return"right";case"bottom":return"top";case"right":return"left"}},b.prototype.getCanvasElements=function(){var b=this.options.canvas?a(this.options.canvas):this.$element,c=b.find("*").filter(function(){return"fixed"===a(this).css("position")}).not(this.options.exclude);return b.add(c)},b.prototype.slide=function(b,c,d){if(!a.support.transition){var e={};return e[this.placement]="+="+c,b.animate(e,350,d)}var f=this.placement,g=this.opposite(f);b.each(function(){"auto"!==a(this).css(f)&&a(this).css(f,(parseInt(a(this).css(f),10)||0)+c),"auto"!==a(this).css(g)&&a(this).css(g,(parseInt(a(this).css(g),10)||0)-c)}),this.$element.one(a.support.transition.end,d).emulateTransitionEnd(350)},b.prototype.disableScrolling=function(){var b=a("body").width(),c="padding-"+this.opposite(this.placement);if(void 0===a("body").data("offcanvas-style")&&a("body").data("offcanvas-style",a("body").attr("style")||""),a("body").css("overflow","hidden"),a("body").width()>b){var d=parseInt(a("body").css(c),10)+a("body").width()-b;setTimeout(function(){a("body").css(c,d)},1)}},b.prototype.show=function(){if(!this.state){var b=a.Event("show.bs.offcanvas");if(this.$element.trigger(b),!b.isDefaultPrevented()){this.state="slide-in",this.calcPlacement();var c=this.getCanvasElements(),d=this.placement,e=this.opposite(d),f=this.offset();-1!==c.index(this.$element)&&(a(this.$element).data("offcanvas-style",a(this.$element).attr("style")||""),this.$element.css(d,-1*f),this.$element.css(d)),c.addClass("canvas-sliding").each(function(){void 0===a(this).data("offcanvas-style")&&a(this).data("offcanvas-style",a(this).attr("style")||""),"static"===a(this).css("position")&&a(this).css("position","relative"),"auto"!==a(this).css(d)&&"0px"!==a(this).css(d)||"auto"!==a(this).css(e)&&"0px"!==a(this).css(e)||a(this).css(d,0)}),this.options.disableScrolling&&this.disableScrolling();var g=function(){"slide-in"==this.state&&(this.state="slid",c.removeClass("canvas-sliding").addClass("canvas-slid"),this.$element.trigger("shown.bs.offcanvas"))};setTimeout(a.proxy(function(){this.$element.addClass("in"),this.slide(c,f,a.proxy(g,this))},this),1)}}},b.prototype.hide=function(){if("slid"===this.state){var b=a.Event("hide.bs.offcanvas");if(this.$element.trigger(b),!b.isDefaultPrevented()){this.state="slide-out";var c=a(".canvas-slid"),d=(this.placement,-1*this.offset()),e=function(){"slide-out"==this.state&&(this.state=null,this.placement=null,this.$element.removeClass("in"),c.removeClass("canvas-sliding"),c.add(this.$element).add("body").each(function(){a(this).attr("style",a(this).data("offcanvas-style")).removeData("offcanvas-style")}),this.$element.trigger("hidden.bs.offcanvas"))};c.removeClass("canvas-slid").addClass("canvas-sliding"),setTimeout(a.proxy(function(){this.slide(c,d,a.proxy(e,this))},this),1)}}},b.prototype.toggle=function(){"slide-in"!==this.state&&"slide-out"!==this.state&&this["slid"===this.state?"hide":"show"]()},b.prototype.calcClone=function(){this.$calcClone=this.$element.clone().html("").addClass("offcanvas-clone").removeClass("in").appendTo(a("body"))},b.prototype.recalc=function(){if("none"!==this.$calcClone.css("display")&&("slid"===this.state||"slide-in"===this.state)){this.state=null,this.placement=null;var b=this.getCanvasElements();this.$element.removeClass("in"),b.removeClass("canvas-slid"),b.add(this.$element).add("body").each(function(){a(this).attr("style",a(this).data("offcanvas-style")).removeData("offcanvas-style")})}},b.prototype.autohide=function(b){0===a(b.target).closest(this.$element).length&&this.hide()};var c=a.fn.offcanvas;a.fn.offcanvas=function(c){return this.each(function(){var d=a(this),e=d.data("bs.offcanvas"),f=a.extend({},b.DEFAULTS,d.data(),"object"==typeof c&&c);e||d.data("bs.offcanvas",e=new b(this,f)),"string"==typeof c&&e[c]()})},a.fn.offcanvas.Constructor=b,a.fn.offcanvas.noConflict=function(){return a.fn.offcanvas=c,this},a(document).on("click.bs.offcanvas.data-api","[data-toggle=offcanvas]",function(b){var c,d=a(this),e=d.attr("data-target")||b.preventDefault()||(c=d.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,""),f=a(e),g=f.data("bs.offcanvas"),h=g?"toggle":d.data();b.stopPropagation(),g?g.toggle():f.offcanvas(h)})}(window.jQuery),+function(a){"use strict";var b=function(c,d){this.$element=a(c),this.options=a.extend({},b.DEFAULTS,d),this.$element.on("click.bs.rowlink","td:not(.rowlink-skip)",a.proxy(this.click,this))};b.DEFAULTS={target:"a"},b.prototype.click=function(b){var c=a(b.currentTarget).closest("tr").find(this.options.target)[0];if(a(b.target)[0]!==c)if(b.preventDefault(),c.click)c.click();else if(document.createEvent){var d=document.createEvent("MouseEvents");d.initMouseEvent("click",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null),c.dispatchEvent(d)}};var c=a.fn.rowlink;a.fn.rowlink=function(c){return this.each(function(){var d=a(this),e=d.data("bs.rowlink");e||d.data("bs.rowlink",e=new b(this,c))})},a.fn.rowlink.Constructor=b,a.fn.rowlink.noConflict=function(){return a.fn.rowlink=c,this},a(document).on("click.bs.rowlink.data-api",'[data-link="row"]',function(b){if(0===a(b.target).closest(".rowlink-skip").length){var c=a(this);c.data("bs.rowlink")||(c.rowlink(c.data()),a(b.target).trigger("click.bs.rowlink"))}})}(window.jQuery),+function(a){"use strict";var b=void 0!==window.orientation,c=navigator.userAgent.toLowerCase().indexOf("android")>-1,d="Microsoft Internet Explorer"==window.navigator.appName,e=function(b,d){c||(this.$element=a(b),this.options=a.extend({},e.DEFAULTS,d),this.mask=String(this.options.mask),this.init(),this.listen(),this.checkVal())};e.DEFAULTS={mask:"",placeholder:"_",definitions:{9:"[0-9]",a:"[A-Za-z]",w:"[A-Za-z0-9]","*":"."}},e.prototype.init=function(){var b=this.options.definitions,c=this.mask.length;this.tests=[],this.partialPosition=this.mask.length,this.firstNonMaskPos=null,a.each(this.mask.split(""),a.proxy(function(a,d){"?"==d?(c--,this.partialPosition=a):b[d]?(this.tests.push(new RegExp(b[d])),null===this.firstNonMaskPos&&(this.firstNonMaskPos=this.tests.length-1)):this.tests.push(null)},this)),this.buffer=a.map(this.mask.split(""),a.proxy(function(a){return"?"!=a?b[a]?this.options.placeholder:a:void 0},this)),this.focusText=this.$element.val(),this.$element.data("rawMaskFn",a.proxy(function(){return a.map(this.buffer,function(a,b){return this.tests[b]&&a!=this.options.placeholder?a:null}).join("")},this))},e.prototype.listen=function(){if(!this.$element.attr("readonly")){var b=(d?"paste":"input")+".mask";this.$element.on("unmask.bs.inputmask",a.proxy(this.unmask,this)).on("focus.bs.inputmask",a.proxy(this.focusEvent,this)).on("blur.bs.inputmask",a.proxy(this.blurEvent,this)).on("keydown.bs.inputmask",a.proxy(this.keydownEvent,this)).on("keypress.bs.inputmask",a.proxy(this.keypressEvent,this)).on(b,a.proxy(this.pasteEvent,this))}},e.prototype.caret=function(a,b){if(0!==this.$element.length){if("number"==typeof a)return b="number"==typeof b?b:a,this.$element.each(function(){if(this.setSelectionRange)this.setSelectionRange(a,b);else if(this.createTextRange){var c=this.createTextRange();c.collapse(!0),c.moveEnd("character",b),c.moveStart("character",a),c.select()}});if(this.$element[0].setSelectionRange)a=this.$element[0].selectionStart,b=this.$element[0].selectionEnd;else if(document.selection&&document.selection.createRange){var c=document.selection.createRange();a=0-c.duplicate().moveStart("character",-1e5),b=a+c.text.length}return{begin:a,end:b}}},e.prototype.seekNext=function(a){for(var b=this.mask.length;++a<=b&&!this.tests[a];);return a},e.prototype.seekPrev=function(a){for(;--a>=0&&!this.tests[a];);return a},e.prototype.shiftL=function(a,b){var c=this.mask.length;if(!(0>a)){for(var d=a,e=this.seekNext(b);c>d;d++)if(this.tests[d]){if(!(c>e&&this.tests[d].test(this.buffer[e])))break;this.buffer[d]=this.buffer[e],this.buffer[e]=this.options.placeholder,e=this.seekNext(e)}this.writeBuffer(),this.caret(Math.max(this.firstNonMaskPos,a))}},e.prototype.shiftR=function(a){for(var b=this.mask.length,c=a,d=this.options.placeholder;b>c;c++)if(this.tests[c]){var e=this.seekNext(c),f=this.buffer[c];if(this.buffer[c]=d,!(b>e&&this.tests[e].test(f)))break;d=f}},e.prototype.unmask=function(){this.$element.unbind(".mask").removeData("inputmask")},e.prototype.focusEvent=function(){this.focusText=this.$element.val();var a=this.mask.length,b=this.checkVal();this.writeBuffer();var c=this,d=function(){b==a?c.caret(0,b):c.caret(b)};d(),setTimeout(d,50)},e.prototype.blurEvent=function(){this.checkVal(),this.$element.val()!==this.focusText&&this.$element.trigger("change")},e.prototype.keydownEvent=function(a){var c=a.which;if(8==c||46==c||b&&127==c){var d=this.caret(),e=d.begin,f=d.end;return f-e===0&&(e=46!=c?this.seekPrev(e):f=this.seekNext(e-1),f=46==c?this.seekNext(f):f),this.clearBuffer(e,f),this.shiftL(e,f-1),!1}return 27==c?(this.$element.val(this.focusText),this.caret(0,this.checkVal()),!1):void 0},e.prototype.keypressEvent=function(a){var b=this.mask.length,c=a.which,d=this.caret();if(a.ctrlKey||a.altKey||a.metaKey||32>c)return!0;if(c){d.end-d.begin!==0&&(this.clearBuffer(d.begin,d.end),this.shiftL(d.begin,d.end-1));var e=this.seekNext(d.begin-1);if(b>e){var f=String.fromCharCode(c);if(this.tests[e].test(f)){this.shiftR(e),this.buffer[e]=f,this.writeBuffer();var g=this.seekNext(e);this.caret(g)}}return!1}},e.prototype.pasteEvent=function(){var a=this;setTimeout(function(){a.caret(a.checkVal(!0))},0)},e.prototype.clearBuffer=function(a,b){for(var c=this.mask.length,d=a;b>d&&c>d;d++)this.tests[d]&&(this.buffer[d]=this.options.placeholder)},e.prototype.writeBuffer=function(){return this.$element.val(this.buffer.join("")).val()},e.prototype.checkVal=function(a){for(var b=this.mask.length,c=this.$element.val(),d=-1,e=0,f=0;b>e;e++)if(this.tests[e]){for(this.buffer[e]=this.options.placeholder;f++<c.length;){var g=c.charAt(f-1);if(this.tests[e].test(g)){this.buffer[e]=g,d=e;break}}if(f>c.length)break}else this.buffer[e]==c.charAt(f)&&e!=this.partialPosition&&(f++,d=e);return!a&&d+1<this.partialPosition?(this.$element.val(""),this.clearBuffer(0,b)):(a||d+1>=this.partialPosition)&&(this.writeBuffer(),a||this.$element.val(this.$element.val().substring(0,d+1))),this.partialPosition?e:this.firstNonMaskPos};var f=a.fn.inputmask;a.fn.inputmask=function(b){return this.each(function(){var c=a(this),d=c.data("bs.inputmask");d||c.data("bs.inputmask",d=new e(this,b))})},a.fn.inputmask.Constructor=e,a.fn.inputmask.noConflict=function(){return a.fn.inputmask=f,this},a(document).on("focus.bs.inputmask.data-api","[data-mask]",function(){var b=a(this);b.data("bs.inputmask")||b.inputmask(b.data())})}(window.jQuery),+function(a){"use strict";var b="Microsoft Internet Explorer"==window.navigator.appName,c=function(b,c){if(this.$element=a(b),this.$input=this.$element.find(":file"),0!==this.$input.length){this.name=this.$input.attr("name")||c.name,this.$hidden=this.$element.find('input[type=hidden][name="'+this.name+'"]'),0===this.$hidden.length&&(this.$hidden=a('<input type="hidden">').insertBefore(this.$input)),this.$preview=this.$element.find(".fileinput-preview");var d=this.$preview.css("height");"inline"!==this.$preview.css("display")&&"0px"!==d&&"none"!==d&&this.$preview.css("line-height",d),this.original={exists:this.$element.hasClass("fileinput-exists"),preview:this.$preview.html(),hiddenVal:this.$hidden.val()},this.listen()}};c.prototype.listen=function(){this.$input.on("change.bs.fileinput",a.proxy(this.change,this)),a(this.$input[0].form).on("reset.bs.fileinput",a.proxy(this.reset,this)),this.$element.find('[data-trigger="fileinput"]').on("click.bs.fileinput",a.proxy(this.trigger,this)),this.$element.find('[data-dismiss="fileinput"]').on("click.bs.fileinput",a.proxy(this.clear,this))},c.prototype.change=function(b){var c=void 0===b.target.files?b.target&&b.target.value?[{name:b.target.value.replace(/^.+\\/,"")}]:[]:b.target.files;if(b.stopPropagation(),0===c.length)return void this.clear();this.$hidden.val(""),this.$hidden.attr("name",""),this.$input.attr("name",this.name);var d=c[0];if(this.$preview.length>0&&("undefined"!=typeof d.type?d.type.match(/^image\/(gif|png|jpeg)$/):d.name.match(/\.(gif|png|jpe?g)$/i))&&"undefined"!=typeof FileReader){var e=new FileReader,f=this.$preview,g=this.$element;e.onload=function(b){var e=a("<img>");e[0].src=b.target.result,c[0].result=b.target.result,g.find(".fileinput-filename").text(d.name),"none"!=f.css("max-height")&&e.css("max-height",parseInt(f.css("max-height"),10)-parseInt(f.css("padding-top"),10)-parseInt(f.css("padding-bottom"),10)-parseInt(f.css("border-top"),10)-parseInt(f.css("border-bottom"),10)),f.html(e),g.addClass("fileinput-exists").removeClass("fileinput-new"),g.trigger("change.bs.fileinput",c)},e.readAsDataURL(d)}else this.$element.find(".fileinput-filename").text(d.name),this.$preview.text(d.name),this.$element.addClass("fileinput-exists").removeClass("fileinput-new"),this.$element.trigger("change.bs.fileinput")},c.prototype.clear=function(a){if(a&&a.preventDefault(),this.$hidden.val(""),this.$hidden.attr("name",this.name),this.$input.attr("name",""),b){var c=this.$input.clone(!0);this.$input.after(c),this.$input.remove(),this.$input=c}else this.$input.val("");this.$preview.html(""),this.$element.find(".fileinput-filename").text(""),this.$element.addClass("fileinput-new").removeClass("fileinput-exists"),void 0!==a&&(this.$input.trigger("change"),this.$element.trigger("clear.bs.fileinput"))},c.prototype.reset=function(){this.clear(),this.$hidden.val(this.original.hiddenVal),this.$preview.html(this.original.preview),this.$element.find(".fileinput-filename").text(""),this.original.exists?this.$element.addClass("fileinput-exists").removeClass("fileinput-new"):this.$element.addClass("fileinput-new").removeClass("fileinput-exists"),this.$element.trigger("reset.bs.fileinput")},c.prototype.trigger=function(a){this.$input.trigger("click"),a.preventDefault()};var d=a.fn.fileinput;a.fn.fileinput=function(b){return this.each(function(){var d=a(this),e=d.data("bs.fileinput");e||d.data("bs.fileinput",e=new c(this,b)),"string"==typeof b&&e[b]()})},a.fn.fileinput.Constructor=c,a.fn.fileinput.noConflict=function(){return a.fn.fileinput=d,this},a(document).on("click.fileinput.data-api",'[data-provides="fileinput"]',function(b){var c=a(this);if(!c.data("bs.fileinput")){c.fileinput(c.data());var d=a(b.target).closest('[data-dismiss="fileinput"],[data-trigger="fileinput"]');d.length>0&&(b.preventDefault(),d.trigger("click.bs.fileinput"))}})}(window.jQuery); \ No newline at end of file diff --git a/pkg/vtiger/modules/ExtensionStore/settings/models/Extension.php b/pkg/vtiger/modules/ExtensionStore/settings/models/Extension.php new file mode 100644 index 0000000000000000000000000000000000000000..66a716e24cd6b7455e35b1fca53e998e338765c7 --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/settings/models/Extension.php @@ -0,0 +1,652 @@ +<?php + +/* + * Copyright (C) www.vtiger.com. All rights reserved. + * @license Proprietary + */ + +vimport('~~/vtlib/Vtiger/Package.php'); +vimport('~/libraries/PHPMarkdown/Michelf/Markdown.inc.php'); + +class Settings_ExtensionStore_Extension_Model extends Vtiger_Base_Model { + + private static $EXTENSION_MANAGER_URL = false; + protected $EXTENSIONSTORE_LOOKUP_URL = null; + protected $siteURL = null; + var $fileName; + + public function __construct() { + parent::__construct(); + $this->EXTENSIONSTORE_LOOKUP_URL = 'https://marketplace.vtiger.com/api'; + global $site_URL; + if (empty($site_URL)) { + throw new Exception('Invalid configuration.'); + } + $this->siteURL = $site_URL; + } + + public function getExtensionsLookUpUrl() { + return $this->EXTENSIONSTORE_LOOKUP_URL; + } + + public function getExtensionsManagerUrl() { + return self::$EXTENSION_MANAGER_URL ? self::$EXTENSION_MANAGER_URL : $this->EXTENSIONSTORE_LOOKUP_URL; + } + + /** + * Function to set id for this instance + * @param <Integer> $extensionId + * @return <type> + */ + public function setId($extensionId) { + $this->set('id', $extensionId); + return $this; + } + + /** + * Function to set file name for this instance + * @param <type> $fileName + * @return <type> + */ + public function setFileName($fileName) { + $this->fileName = $fileName; + return $this; + } + + /** + * Function to get Id of this instance + * @return <Integer> id + */ + public function getId() { + return $this->get('id'); + } + + /** + * Function to get name of this instance + * @return <String> module name + */ + public function getName() { + return $this->get('name'); + } + + /** + * Function to get file name of this instance + * @return <String> file name + */ + public function getFileName() { + return $this->fileName; + } + + public function getDescription() { + return $this->description; + } + + /** + * Function to store the details of tracking + * @return <boolean> true/false + */ + public function installTrackDetails() { + return true; + } + + /** + * Function to get package of this instance + * @return <Vtiger_Package> package object + */ + public function getPackage() { + $packageModel = new Vtiger_Package(); + $moduleName = $packageModel->getModuleNameFromZip(self::getUploadDirectory().'/'.$this->getFileName()); + if ($moduleName) { + return $packageModel; + } + return false; + } + + /** + * Function to check whether it is compatible with vtiger or not + * @return <boolean> true/false + */ + public function isVtigerCompatible() { + vimport('~~/vtlib/Vtiger/Version.php'); + $vtigerVersion = $this->get('vtigerVersion'); + $vtigerMaxVersion = $this->get('vtigerMaxVersion'); + + if ((Vtiger_Version::check($vtigerVersion, '>=') && $vtigerMaxVersion && Vtiger_Version::check($vtigerMaxVersion, '<')) || Vtiger_Version::check($vtigerVersion, '=')) { + return true; + } + return false; + } + + /** + * Function to check whether the module is already exists or not + * @return <true/false> + */ + public function isAlreadyExists() { + $moduleName = $this->getName(); + $moduleModel = Vtiger_Module_Model::getInstance($moduleName); + if ($moduleModel) { + return true; + } else if (self::getLanguageInstance($moduleName)) { + return true; + } + return false; + } + + public static function getLanguageInstance($lang) { + $sql = 'SELECT id,name,prefix FROM vtiger_language WHERE name = ?'; + $db = PearDatabase::getInstance(); + $result = $db->pquery($sql, array($lang)); + if ($db->num_rows($result) > 0) { + $instance = new self(); + $row = $db->query_result_rowdata($result, 0); + $instance->setData($row); + return $instance; + } else { + return false; + } + } + + /** + * Function to check whether the module is upgradable or not + * @return <type> + */ + public function isUpgradable() { + $moduleName = $this->getName(); + $moduleModel = Vtiger_Module_Model::getInstance($moduleName); + if ($moduleModel) { + if ($moduleModel->get('version') < $this->get('pkgVersion')) { + return true; + } + } + return false; + } + + /** + * Function to get instance by using id + * @param <Integer> $extensionId + * @param <String> $fileName + * @return <Settings_ExtensionStore_Extension_Model> $extension Model + */ + public function getInstanceById($extensionId, $trial = false, $fileName = false) { + $uploadDir = self::getUploadDirectory(); + if ($fileName) { + if (is_dir($uploadDir)) { + $uploadFileName = "$uploadDir/$fileName"; + checkFileAccess(self::getUploadDirectory()); + + $extensionModel = new self(); + $extensionModel->setId($extensionId)->setFileName($fileName); + return $extensionModel; + } + } else { + if (!is_dir($uploadDir)) { + mkdir($uploadDir); + } + $uploadFile = 'usermodule_'.time().'.zip'; + $uploadFileName = "$uploadDir/$uploadFile"; + checkFileAccess(self::getUploadDirectory()); + + $response = $this->download($extensionId, $trial, $uploadFileName); + if ($response['success']) { + $extensionModel = new self(); + $extensionModel->setId($extensionId)->setFileName($uploadFile); + return array('success' => true, 'result' => $extensionModel); + } else { + return array('success' => false, 'message' => $response['message']); + } + } + return false; + } + + /** + * Function to get max created on promotion + */ + public function getMaxCreatedOn($type = 'Extension', $function, $field) { + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $listings = $connector->getMaxCreatedOn($type, $function, $field); + return $listings; + } + } + + /** + * Function to get all availible extensions + * @param <Object> $xmlContent + * @return <Array> list of extensions <Settings_ExtensionStore_Extension_Model> + */ + public function getListings($id = null, $type = 'Extension') { + $extensionModelsList = array(); + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $listings = $connector->getListings($id, $type); + + if ($listings['success']) { + $listings = $listings['response']; + if (!is_array($listings)) + $listings = array($listings); + foreach ($listings as $listing) { + $extensionModelsList[(string) $listing['id']] = $this->getInstanceFromArray($listing); + } + } else { + return array('success' => false, 'message' => $listings['error']); + } + } + return $extensionModelsList; + } + + /** + * Function to get listings of extension id + */ + public function getExtensionListings($extensionId) { + $extensionModelsList = array(); + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $listings = $connector->getListings($extensionId); + if ($listings['success']) { + $listing = $listings['response']; + $extensionModelsList[(string) $listing['id']] = $this->getInstanceFromArray($listing); + return $extensionModelsList; + } else { + return array('success' => false, 'message' => $listings['error']); + } + } + } + + /** + * Function to download the file of this instance + * @param <Integer> $extensionId + * @param <String> $targetFileName + * @return <boolean> true/false + */ + public function download($extensionId, $trial, $targetFileName) { + $extensions = $this->getExtensionListings($extensionId); + $downloadURL = $extensions[$extensionId]->get('downloadURL'); + + if ($trial) { + $downloadURL = $downloadURL.'&mode=Trial'; + } + if ($downloadURL) { + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $response = $connector->download($downloadURL); + if ($response['success']) { + file_put_contents($targetFileName, $response['response']); + return array('success' => true); + } else { + return array('success' => false, 'message' => $response['error']); + } + } + return false; + } + + /** + * Function to get extensions based on search + * @param <String> search term + * @return <Array> list of extensions <Settings_ExtensionStore_Extension_Model> + */ + public function findListings($searchTerm = null, $searchType) { + $extensionModelsList = array(); + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $listings = $connector->findListings($searchTerm, $searchType); + + if ($listings['success']) { + $listings = $listings['response']; + if (!is_array($listings)) + $listings = array($listings); + foreach ($listings as $listing) { + $extensionModelsList[(string) $listing['id']] = $this->getInstanceFromArray($listing); + } + } else { + return array('success' => false, 'message' => $listings['error']); + } + } + return $extensionModelsList; + } + + public function getExtensionTable() { + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $tableName = $connector->getExtensionTable(); + } + return $tableName; + } + + /** + * Function to get registration status of user + */ + public function checkRegistration() { + $tableName = $this->getExtensionTable(); + $db = PearDatabase::getInstance(); + $result = $db->pquery('SELECT 1 FROM '.$tableName, array()); + if ($db->num_rows($result)) { + return true; + } + return false; + } + + public function getSessionIdentifier() { + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + return $connector->getSessionIdentifier(); + } + } + + /** + * Function to get password status of extension store + */ + public function passwordStatus() { + $tableName = $this->getExtensionTable(); + $db = PearDatabase::getInstance(); + $result = $db->pquery('SELECT password FROM '.$tableName, array()); + if ($db->query_result($result, 0, 'password')) { + return true; + } + return false; + } + + /** + * Function to registered user name for market place + */ + public function getRegisteredUser() { + $tableName = $this->getExtensionTable(); + $db = PearDatabase::getInstance(); + $result = $db->pquery('SELECT username FROM '.$tableName, array()); + $userName = $db->query_result($result, 0, 'username'); + if (strlen($userName)) { + return $userName; + } + return false; + } + + /** + * Function to register user for extension store + */ + public function signup($options) { + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $response = $connector->signUp($options['emailAddress'], $options['password'], $options['confirmPassword'], $options['firstName'], $options['lastName'], $options['companyName']); + return $response; + } + } + + /** + * Function to Logout from extension store + */ + public function logoutMarketPlace(Vtiger_Request $request) { + $sql = 'DELETE FROM vtiger_extnstore_users'; + $db = PearDatabase::getInstance(); + $db->pquery($sql, array()); + } + + /** + * Function to login user to extension store + */ + public function login($options) { + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $response = $connector->login($options['emailAddress'], $options['password'], $options['savePassword']); + return $response; + } + } + + /** + * Funstion to get customer reviews based on extension id + */ + public function getCustomerReviews($extensionId) { + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $response = $connector->getCustomerReviews($extensionId); + return $response; + } + } + + /** + * Function to post customer reviews + */ + public function postReview($listing, $comment, $rating) { + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $response = $connector->postReview($listing, $comment, $rating); + return $response; + } + } + + /** + * Function to get screen shots of given extension + */ + public function getScreenShots($extensionId) { + $screenShotListings = array(); + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $listings = $connector->getScreenShots($extensionId); + foreach ($listings as $listing) { + $screenShotListings[(string) $listing['id']] = $this->getInstanceFromScreenShotArray($listing); + } + return $screenShotListings; + } + } + + /** + * Function to verify extension purchase + */ + public function verifyPurchase($listingName) { + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $response = $connector->verifyPurchase($listingName); + if ($response == 1) { + return true; + } + return false; + } + } + + /** + * Function to get listing author information + */ + public function getListingAuthor($extensionId) { + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $authorInfo = $connector->getListingAuthor($extensionId); + return $authorInfo; + } + } + + /** + * Function to get customer profile details + */ + public function getProfile() { + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $customerInfo = $connector->getProfile(); + return $customerInfo; + } + } + + /** + * Function to get instance by using XML node + * @param <XML DOM> $extensionXMLNode + * @return <Settings_ExtensionStore_Extension_Model> $extensionModel + */ + public function getInstanceFromArray($listing) { + $extensionModel = new self(); + + foreach ($listing as $key => $value) { + switch ($key) { + case 'name' : $key = 'label'; + break; + case 'identifier': $key = 'name'; + break; + case 'version' : $key = 'pkgVersion'; + break; + case 'minrange': $key = 'vtigerVersion'; + break; + case 'maxrange': $key = 'vtigerMaxVersion'; + break; + case 'CustomerId': $key = 'publisher'; + break; + case 'price': $value = $value ? $value : 'Free'; + break; + case 'approvedon': $key = 'pubDate'; + break; + case 'ListingFileId': + if ($value) { + $key = 'downloadURL'; + $value = $this->getExtensionsLookUpUrl().'/customer/listingfiles?id='.$value; + } + break; + case 'thumbnail': + if ($value) { + $key = 'thumbnailURL'; + $value = str_replace('api', "_listingimages/$value", $this->getExtensionsLookUpUrl()); + } + break; + case 'banner' : + if ($value) { + $key = 'bannerURL'; + $value = str_replace('api', "_listingimages/$value", $this->getExtensionsLookUpUrl()); + } + break; + case 'description': + if ($value) { + $markDownInstance = new Michelf\Markdown(); + $value = $markDownInstance->transform($value); + } + } + $extensionModel->set($key, $value); + } + + $label = $extensionModel->get('label'); + if (!$label) { + $extensionModel->set('label', $extensionModel->getName()); + } + + $moduleModel = self::getModuleFromExtnName($extensionModel->getName()); + if ($moduleModel && $moduleModel->get('extnType') == 'language') { + $trial = $extensionModel->get('trial'); + $moduleModel->set('trial', $trial); + } + $extensionModel->set('moduleModel', $moduleModel); + return $extensionModel; + } + + public static function getModuleFromExtnName($extnName) { + $moduleModel = Vtiger_Module_Model::getInstance($extnName); + if ($moduleModel) { + $moduleModel->set('extnType', 'module'); + } + if (!$moduleModel) { + if (self::getLanguageInstance($extnName)) { + $moduleModel = new Vtiger_Module_Model(); + $moduleModel->set('name', $extnName); + $moduleModel->set('isentitytype', false); + $moduleModel->set('extnType', 'language'); + } + } + return $moduleModel; + } + + /** + * Function to get instance by using XML node + * @param <XML DOM> $extensionXMLNode + * @return <Settings_ExtensionStore_Extension_Model> $extensionModel + */ + public function getInstanceFromScreenShotArray($listing) { + $extensionModel = new self(); + + foreach ($listing as $key => $value) { + switch ($key) { + case 'location': + if ($value) { + $key = 'screenShotURL'; + $value = str_replace('api', "_listingimages/$value", $this->getExtensionsLookUpUrl()); + } + break; + } + $extensionModel->set($key, $value); + } + return $extensionModel; + } + + public function getCustomerDetails($customerId) { + $extensionLookUpUrl = self::getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $customerInfo = $connector->getCustomerDetails($customerId); + return $customerInfo; + } + } + + /** + * Function to insert card details of registered user + */ + public function createCard($number, $expmonth, $expyear, $cvc) { + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $response = $connector->createCard($number, $expmonth, $expyear, $cvc); + return $response; + } + } + + /** + * Function to update card details of registered user + */ + public function updateCard($number, $expmonth, $expyear, $cvc, $customerId) { + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $response = $connector->updateCard($number, $expmonth, $expyear, $cvc, $customerId); + return $response; + } + } + + /** + * Function to get card details of customer + */ + public function getCardDetails($cardId) { + $extensionLookUpUrl = $this->getExtensionsLookUpUrl(); + if ($extensionLookUpUrl) { + $connector = Settings_ExtensionStore_ExtnStore_Connector::getInstance($extensionLookUpUrl); + $response = $connector->getCardDetails($cardId); + return $response; + } + } + + public static function getInstance() { + return new self(); + } + + public static function getUploadDirectory($isChild = false) { + $uploadDir .= 'test/vtlib'; + if ($isChild) { + $uploadDir = '../'.$uploadDir; + } + return $uploadDir; + } + + public function getLocationUrl($extensionId, $extensionName) { + global $current_user; + + if (is_admin($current_user)) { + return 'index.php?module=ExtensionStore&parent=Settings&view=ExtensionStore&mode=detail&extensionId='.$extensionId.'&extensionName='.$extensionName; + } else { + return 'https://marketplace.vtiger.com/app/listings?id='.$extensionId; + } + } + +} diff --git a/pkg/vtiger/modules/ExtensionStore/settings/models/Module.php b/pkg/vtiger/modules/ExtensionStore/settings/models/Module.php new file mode 100644 index 0000000000000000000000000000000000000000..0f18eccdaafb83a15f1e9478eb331a2b5796a061 --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/settings/models/Module.php @@ -0,0 +1,32 @@ +<?php +/*+*********************************************************************************** + * The contents of this file are subject to the vtiger CRM Public License Version 1.0 + * ("License"); You may not use this file except in compliance with the License + * The Original Code is: vtiger CRM Open Source + * The Initial Developer of the Original Code is vtiger. + * Portions created by vtiger are Copyright (C) vtiger. + * All Rights Reserved. + *************************************************************************************/ + +class Settings_ExtensionStore_Module_Model extends Vtiger_Module_Model { + + public function getDefaultViewName() { + return 'ExtensionStore'; + } + + public function getDefaultUrl() { + return 'index.php?module='.$this->getName().'&parent=Settings&view='.$this->getDefaultViewName(); + } + + public static function getInstance($moduleName = 'ExtensionStore') { + $moduleModel = parent::getInstance($moduleName); + $objectProperties = get_object_vars($moduleModel); + + $instance = new self(); + foreach ($objectProperties as $properName => $propertyValue) { + $instance->$properName = $propertyValue; + } + return $instance; + } + +} diff --git a/pkg/vtiger/modules/ExtensionStore/settings/templates/Detail.tpl b/pkg/vtiger/modules/ExtensionStore/settings/templates/Detail.tpl new file mode 100644 index 0000000000000000000000000000000000000000..388a9841015efeeac80e483c9bb9a7cc5f12fc5f --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/settings/templates/Detail.tpl @@ -0,0 +1,175 @@ +{*<!-- +* +* Copyright (C) www.vtiger.com. All rights reserved. +* @license Proprietary +* +-->*} +{strip} + <div class="container-fluid detailViewInfo extensionDetails" style='margin-top:0px;'> + {if !($ERROR)} + <input type="hidden" name="mode" value="{$smarty.request.mode}" /> + <input type="hidden" name="extensionId" value="{$EXTENSION_ID}" /> + <input type="hidden" name="targetModule" value="{$EXTENSION_DETAIL->get('name')}" /> + <input type="hidden" name="moduleAction" value="{$MODULE_ACTION}" /> + <div class="row-fluid contentHeader"> + <div class="span6"> + <div style="margin-bottom: 5px;"><span class="font-x-x-large">{$EXTENSION_DETAIL->get('name')}</span> <span class="muted">{vtranslate('LBL_BY', $QUALIFIED_MODULE)} {$AUTHOR_INFO['firstname']} {$AUTHOR_INFO['lastname']}</span></div> + {assign var=ON_RATINGS value=$EXTENSION_DETAIL->get('avgrating')} + <div class="row-fluid"> + <span data-score="{$ON_RATINGS}" class="rating span5" data-readonly="true"></span> + <span class="span6">({count($CUSTOMER_REVIEWS)} {vtranslate('LBL_REVIEWS', $QUALIFIED_MODULE)})</span> + </div> + </div> + <div class="span6"> + <div class="pull-right extensionDetailActions"> + {if ($MODULE_ACTION eq 'Installed')} + <button class="btn btn-danger {if ($REGISTRATION_STATUS) and ($PASSWORD_STATUS)}authenticated {else} loginRequired{/if}" type="button" style="margin-right: 6px;" id="uninstallModule"><strong>{vtranslate('LBL_UNINSTALL', $QUALIFIED_MODULE)}</strong></button> + {else} + {if $EXTENSION_DETAIL->get('isprotected') && $IS_PRO && ($EXTENSION_DETAIL->get('price') gt 0)} + <button class="btn btn-info {if (!$CUSTOMER_PROFILE['CustomerCardId'])} setUpCard{/if}{if ($REGISTRATION_STATUS) and ($PASSWORD_STATUS)} authenticated {else} loginRequired{/if}" type="button" id="installExtension"><strong>{vtranslate('LBL_BUY',$QUALIFIED_MODULE)}${$EXTENSION_DETAIL->get('price')}</strong></button> + {elseif (!$EXTENSION_DETAIL->get('isprotected')) && ($EXTENSION_DETAIL->get('price') gt 0)} + <button class="btn btn-info {if (!$CUSTOMER_PROFILE['CustomerCardId'])} setUpCard{/if}{if ($REGISTRATION_STATUS) and ($PASSWORD_STATUS)} authenticated {else} loginRequired{/if}" type="button" id="installExtension"><strong>{vtranslate('LBL_BUY',$QUALIFIED_MODULE)}${$EXTENSION_DETAIL->get('price')}</strong></button> + {elseif !$EXTENSION_DETAIL->get('isprotected') && (($EXTENSION_DETAIL->get('price') eq 0) || ($EXTENSION_DETAIL->get('price') eq 'Free'))} + <button class="btn btn-success {if ($REGISTRATION_STATUS) and ($PASSWORD_STATUS)}authenticated {else} loginRequired{/if}" type="button" id="installExtension"><strong>{vtranslate($MODULE_ACTION, $QUALIFIED_MODULE)}</strong></button> + {elseif $EXTENSION_DETAIL->get('isprotected') && $IS_PRO && (($EXTENSION_DETAIL->get('price') eq 0) || ($EXTENSION_DETAIL->get('price') eq 'Free'))} + <button class="btn btn-success {if ($REGISTRATION_STATUS) and ($PASSWORD_STATUS)}authenticated {else} loginRequired{/if}" type="button" id="installExtension"><strong>{vtranslate($MODULE_ACTION, $QUALIFIED_MODULE)}</strong></button> + {/if} + {/if} + + <button class="btn btn-info {if $MODULE_ACTION eq 'Installed'}{if $EXTENSION_MODULE_MODEL->get('extnType') eq 'language'}hide{/if}{else}hide{/if}" type="button" id="launchExtension" onclick="location.href='index.php?module={$EXTENSION_DETAIL->get('name')}&view=List'"><strong>{vtranslate('LBL_LAUNCH', $QUALIFIED_MODULE)}</strong></button> + <a class="cancelLink" type="reset" id="declineExtension">{vtranslate('LBL_CANCEL', $MODULE)}</a> + </div> + <div class="clearfix"></div> + </div> + </div> + <div class="tabbable margin0px" style="padding-bottom: 20px;"> + <ul id="extensionTab" class="nav nav-tabs" style="margin-bottom: 0px; padding-bottom: 0px;"> + <li class="active"><a href="#description" data-toggle="tab"><strong>{vtranslate('LBL_DESCRIPTION', $QUALIFIED_MODULE)}</strong></a></li> + <li><a href="#CustomerReviews" data-toggle="tab"><strong>{vtranslate('LBL_CUSTOMER_REVIEWS', $QUALIFIED_MODULE)}</strong></a></li> + <li><a href="#Author" data-toggle="tab"><strong>{vtranslate('LBL_PUBLISHER', $QUALIFIED_MODULE)}</strong></a></li> + </ul> + <div class="tab-content row-fluid boxSizingBorderBox" style="background-color: #fff; padding: 20px; border: 1px solid #ddd; border-top-width: 0px;"> + <div class="tab-pane active" id="description"> + <div style="width:90%;padding: 0px 5%;"> + <div class="row-fluid"> + <ul id="imageSlider" class="imageSlider"> + {foreach $SCREEN_SHOTS as $key=>$SCREEN_SHOT} + <li> + <div class="slide"> + <img src="{$SCREEN_SHOT->get('screenShotURL')}" class="sliderImage"/> + </div> + </li> + {/foreach} + </ul> + </div> + </div> + <div class="scrollableTab"> + <p>{$EXTENSION_DETAIL->get('description')}</p> + <p></p> + </div> + </div> + <div class="tab-pane row-fluid" id="CustomerReviews"> + <div class="row-fluid boxSizingBorderBox" style="padding-bottom: 15px;"> + <div class="span6"> + <div class="pull-left"> + <div style="font-size: 55px; padding: 20px 17px 0 0;">{$ON_RATINGS}</div> + </div> + <div class="pull-left"> + <span data-score="{$ON_RATINGS}" class="rating" data-readonly="true"></span> + <div>out of 5</div> + <div>({$ON_RATINGS} Reviews)</div> + </div> + </div> + {if ($REGISTRATION_STATUS) and ($PASSWORD_STATUS)} + <div class="span6"> + <div class="pull-right"> + <button type="button" class="writeReview margin0px pull-right {if $MODULE_ACTION neq 'Installed'} hide{/if}">{vtranslate('LBL_WRITE_A_REVIEW', $QUALIFIED_MODULE)}</button> + </div> + </div> + {/if} + </div><hr> + <div class="scrollableTab"> + <div class="customerReviewContainer" style=""> + {foreach $CUSTOMER_REVIEWS as $key=>$CUSTOMER_REVIEW} + <div class="row-fluid" style="margin: 8px 0 15px;"> + <div class="span3"> + {assign var=ON_RATINGS value=$CUSTOMER_REVIEW['rating']} + <div data-score="{$ON_RATINGS}" class="rating" data-readonly="true"></div> + {assign var=CUSTOMER_INFO value= $CUSTOMER_REVIEW['customer']} + <div> + {assign var=REVIEW_CREATED_TIME value=$CUSTOMER_REVIEW['createdon']|replace:'T':' '} + {$CUSTOMER_INFO['firstname']} {$CUSTOMER_INFO['lastname']} + </div> + <div class="muted">{Vtiger_Util_Helper::formatDateTimeIntoDayString($REVIEW_CREATED_TIME)|substr:4}</div> + </div> + <div class="span9">{$CUSTOMER_REVIEW['comment']}</div> + </div> + <hr> + {/foreach} + </div> + </div> + </div> + <div class="tab-pane row-fluid" id="Author"> + <div class="scrollableTab"> + <div class="row-fluid"> + <div class="span6"> + {if !empty($AUTHOR_INFO['company'])} + <div class="font-x-x-large authorInfo">{$AUTHOR_INFO['company']}</div> + {else} + <div class="font-x-x-large authorInfo">{$AUTHOR_INFO['firstname']} {$AUTHOR_INFO['lastname']}</div> + {/if} + <div class="authorInfo">{$AUTHOR_INFO['phone']}</div> + <div class="authorInfo">{$AUTHOR_INFO['email']}</div> + <div class="authorInfo"><a href="{$AUTHOR_INFO['website']}" target="_blank">{$AUTHOR_INFO['website']}</a></div> + </div> + <div class="span6"></div> + </div> + </div> + </div> + </div> + </div> + {else} + <div class="row-fluid">{$ERROR_MESSAGE}</div> + {/if} + <div class="modal customerReviewModal hide"> + <div class="modal-header contentsBackground"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h3>{vtranslate('LBL_CUSTOMER_REVIEW', $QUALIFIED_MODULE)}</h3> + </div> + <form class="form-horizontal customerReviewForm"> + <input type="hidden" name="extensionId" value="{$EXTENSION_ID}" /> + <div class="modal-body"> + <div class="control-group"> + <span class="control-label"> + <span class="redColor">*</span> + {vtranslate('LBL_REVIEW', $QUALIFIED_MODULE)} + </span> + <div class="controls"> + <textarea name="customerReview" data-validation-engine="validate[required, funcCall[Vtiger_Base_Validator_Js.invokeValidation]]"></textarea> + </div> + </div> + <div class="control-group"> + <span class="control-label"> + {vtranslate('LBL_RATE_IT', $QUALIFIED_MODULE)} + </span> + <div class="controls"> + <div class="span5 rating"></div> + </div> + </div> + </div> + <div class="modal-footer"> + <div class="row-fluid"> + <div class="span12"> + <div class="pull-right"> + <div class="pull-right cancelLinkContainer" style="margin-top:0px;"> + <a class="cancelLink" type="reset" data-dismiss="modal">{vtranslate('LBL_CANCEL', $MODULE)}</a> + </div> + <button class="btn btn-success" type="submit" name="saveButton"><strong>{vtranslate('LBL_SAVE', $MODULE)}</strong></button> + </div> + </div> + </div> + </div> + </form> + </div> + </div> +{/strip} \ No newline at end of file diff --git a/pkg/vtiger/modules/ExtensionStore/settings/templates/ExtensionModules.tpl b/pkg/vtiger/modules/ExtensionStore/settings/templates/ExtensionModules.tpl new file mode 100644 index 0000000000000000000000000000000000000000..26f74ed9d4c43abf238e8e697f637a3be321c610 --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/settings/templates/ExtensionModules.tpl @@ -0,0 +1,106 @@ +{*<!-- +* +* Copyright (C) www.vtiger.com. All rights reserved. +* @license Proprietary +* +-->*} +{strip} + <div class="row-fluid"> + {foreach item=EXTENSION from=$EXTENSIONS_LIST name=extensions} + {if $EXTENSION->isAlreadyExists()} + {assign var=EXTENSION_MODULE_MODEL value= $EXTENSION->get('moduleModel')} + {else} + {assign var=EXTENSION_MODULE_MODEL value= 'false'} + {/if} + <div class="span6"> + <div class="extension_container extensionWidgetContainer"> + <div class="extension_header"> + <div class="font-x-x-large boxSizingBorderBox" style="cursor:pointer">{vtranslate($EXTENSION->get('label'), $QUALIFIED_MODULE)}</div> + <input type="hidden" name="extensionName" value="{$EXTENSION->get('name')}" /> + <input type="hidden" name="moduleAction" value="{if ($EXTENSION->isAlreadyExists()) and (!$EXTENSION_MODULE_MODEL->get('trial'))}{if $EXTENSION->isUpgradable()}Upgrade{else}Installed{/if}{else}Install{/if}" /> + <input type="hidden" name="extensionId" value="{$EXTENSION->get('id')}" /> + </div> + <div> + <div class="row-fluid extension_contents"> + <span class="span8"> + <div class="row-fluid extensionDescription" style="word-wrap:break-word;"> + {assign var=SUMMARY value=$EXTENSION->get('summary')} + {if empty($SUMMARY)} + {assign var=SUMMARY value={$EXTENSION->get('description')|truncate:100}} + {/if} + {$SUMMARY} + </div> + </span> + <span class="span4"> + {if $EXTENSION->get('thumbnailURL') neq NULL} + {assign var=imageSource value=$EXTENSION->get('thumbnailURL')} + {else} + {assign var=imageSource value= vimage_path('unavailable.png')} + {/if} + <img class="thumbnailImage" src="{$imageSource}"/> + </span> + </div> + <div class="extensionInfo"> + <div class="row-fluid"> + {assign var=ON_RATINGS value=$EXTENSION->get('avgrating')} + <div class="span4"><span class="rating" data-score="{$ON_RATINGS}" data-readonly=true></span><span>{if $EXTENSION->get('avgrating')} ({$EXTENSION->get('avgrating')}){/if}</span></div> + <div class="span8"> + <div class="pull-right"> + <button class="btn installExtension addButton" style="margin-right:5px;">{vtranslate('LBL_MORE_DETAILS', $QUALIFIED_MODULE)}</button> + {if $EXTENSION->isVtigerCompatible()} + {if ($EXTENSION->isAlreadyExists()) and (!$EXTENSION_MODULE_MODEL->get('trial'))} + {if ($EXTENSION->isUpgradable())} + {if $EXTENSION->get('isprotected') && $IS_PRO} + <button class="oneclickInstallFree btn btn-success margin0px {if ($REGISTRATION_STATUS) and ($PASSWORD_STATUS)}authenticated {else} loginRequired{/if}"> + {vtranslate('LBL_UPGRADE', $QUALIFIED_MODULE)} + </button> + {elseif !$EXTENSION->get('isprotected')} + <button class="oneclickInstallFree btn btn-success margin0px {if ($REGISTRATION_STATUS) and ($PASSWORD_STATUS)}authenticated {else} loginRequired{/if}"> + {vtranslate('LBL_UPGRADE', $QUALIFIED_MODULE)} + </button> + {/if} + {else} + <span class="alert alert-info" style="vertical-align:middle; padding: 5px 10px;">{vtranslate('LBL_INSTALLED', $QUALIFIED_MODULE)}</span> + {/if} + {elseif (($EXTENSION->get('price') eq 'Free') or ($EXTENSION->get('price') eq 0))} + {if $EXTENSION->get('isprotected') && $IS_PRO} + <button class="oneclickInstallFree btn btn-success {if ($REGISTRATION_STATUS) and ($PASSWORD_STATUS)}authenticated {else} loginRequired{/if}">{vtranslate('LBL_INSTALL', $QUALIFIED_MODULE)}</button> + {elseif !$EXTENSION->get('isprotected')} + <button class="oneclickInstallFree btn btn-success {if ($REGISTRATION_STATUS) and ($PASSWORD_STATUS)}authenticated {else} loginRequired{/if}">{vtranslate('LBL_INSTALL', $QUALIFIED_MODULE)}</button> + {/if} + {elseif ($IS_PRO)} + {if ($EXTENSION->get('trialdays') gt 0) and ($EXTENSION_MODULE_MODEL eq 'false') and ($EXTENSION->get('isprotected') eq 1)} + <button class="oneclickInstallPaid btn btn-success {if ($REGISTRATION_STATUS) and ($PASSWORD_STATUS)}authenticated {else} loginRequired{/if}" data-trial=true>{vtranslate('LBL_TRY_IT', $QUALIFIED_MODULE)}</button> + {elseif (($EXTENSION_MODULE_MODEL neq 'false') and ($EXTENSION_MODULE_MODEL->get('trial')))} + <span class="alert alert-info">{vtranslate('LBL_TRIAL_INSTALLED', $QUALIFIED_MODULE)}</span> + {/if} + <button class="oneclickInstallPaid btn btn-info {if ($REGISTRATION_STATUS) and ($PASSWORD_STATUS)}authenticated {else} loginRequired{/if}" data-trial=false>{vtranslate('LBL_BUY',$QUALIFIED_MODULE)}${$EXTENSION->get('price')}</button> + {/if} + {else} + <span class="alert alert-error">{vtranslate('LBL_EXTENSION_NOT_COMPATABLE', $QUALIFIED_MODULE)}</span> + {/if} + </div> + </div> + </div> + </div> + </div> + </div> + </div> + {if $smarty.foreach.extensions.index % 2 != 0} + </div> + <div class="row-fluid"> + {/if} + {/foreach} + {if empty($EXTENSIONS_LIST)} + <table class="emptyRecordsDiv"> + <tbody> + <tr> + <td> + {vtranslate('LBL_NO_EXTENSIONS_FOUND', $QUALIFIED_MODULE)} + </td> + </tr> + </tbody> + </table> +{/if} +</div> +{/strip} \ No newline at end of file diff --git a/pkg/vtiger/modules/ExtensionStore/settings/templates/Index.tpl b/pkg/vtiger/modules/ExtensionStore/settings/templates/Index.tpl new file mode 100644 index 0000000000000000000000000000000000000000..b6b8cd8bee683d43d1f433bd06495bbe0fc23c5e --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/settings/templates/Index.tpl @@ -0,0 +1,286 @@ +{*<!-- +* +* Copyright (C) www.vtiger.com. All rights reserved. +* @license Proprietary +* +-->*} +{strip} + <div class="container-fluid" id="importModules"> + <div class="widget_header row-fluid"> + <span class="span6"> + <h3>{vtranslate('LBL_VTIGER_EXTENSION_STORE', $QUALIFIED_MODULE)}</h3> + </span> + </div><hr> + + <div class="row-fluid"> + <span class="span6"> + <div class="row-fluid"> + <input type="text" id="searchExtension" class="span7 extensionSearch" placeholder="{vtranslate('LBL_SEARCH_FOR_AN_EXTENSION', $QUALIFIED_MODULE)}"/> + </div> + </span> + <span class="span6"> + <span class="pull-right"> + {if (!$PASSWORD_STATUS)} + <button id="logintoMarketPlace" class="btn btn-primary">{vtranslate('LBL_LOGIN_TO_MARKET_PLACE', $QUALIFIED_MODULE)}</button> + {elseif $IS_PRO} + <button id="setUpCardDetails" class="btn btn-primary ">{if !empty($CUSTOMER_PROFILE['CustomerCardId'])}{vtranslate('LBL_UPDATE_CARD_DETAILS', $QUALIFIED_MODULE)}{else}{vtranslate('LBL_SETUP_CARD_DETAILS', $QUALIFIED_MODULE)}{/if}</button> + <button id="logoutMarketPlace" class="btn btn-primary pull-right">{vtranslate('LBL_LOGOUT', $QUALIFIED_MODULE)}</button> + {/if} + {if $PASSWORD_STATUS && !$IS_PRO} + <span class="btn-toolbar"> + <span class="btn-group"> + <button class='btn btn-danger' id="installLoader"><strong>{vtranslate('LBL_PHP_EXTENSION_LOADER_IS_NOT_AVAIABLE', $QUALIFIED_MODULE)}</strong></button> + </span> + </span> + {/if} + </span> + </span> + </div> + + <div class="contents" id="extensionContainer"> + {include file='ExtensionModules.tpl'|@vtemplate_path:$QUALIFIED_MODULE} + </div> + + <!-- Setup card detals form start--> + <div class="modal setUpCardModal hide"> + <div class="modal-header contentsBackground"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h3>{vtranslate('LBL_SETUP_CARD', $QUALIFIED_MODULE)}</h3> + </div> + <form class="form-horizontal setUpCardForm"> + <input type="hidden" name="customerId" value="{$CUSTOMER_PROFILE['id']}" /> + <input type="hidden" name="customerCardId" value="{$CUSTOMER_PROFILE['CustomerCardId']}" /> + <input type="hidden" name="module" value="ExtensionStore" /> + <input type="hidden" name="parent" value="Settings" /> + <input type="hidden" name="action" value="Basic" /> + <input type="hidden" name="mode" value="updateCardDetails" /> + <div class="modal-body"> + <div class="control-group"> + <span class="control-label"> + <span class="redColor">*</span> + {vtranslate('LBL_CARD_NUMBER', $QUALIFIED_MODULE)} + </span> + <div class="controls"> + <input class="span3" type="text" placeholder="{vtranslate('LBL_CARD_NUMBER_PLACEHOLDER', $QUALIFIED_MODULE)}" name="cardNumber" value="{if !empty($CUSTOMER_CARD_INFO)} {$CUSTOMER_CARD_INFO['number']}{/if}" data-validation-engine="validate[required]" data-mask="9999-9999-9999-9999"/> + </div> + </div> + <div class="control-group"> + <span class="control-label"> + <span class="redColor">*</span> + {vtranslate('LBL_EXPIRY_DATE', $QUALIFIED_MODULE)} + </span> + <div class="controls"> + <input style="width: 40px;" placeholder="mm" type="text" name="expMonth" value="{if !empty($CUSTOMER_CARD_INFO)} {$CUSTOMER_CARD_INFO['expmonth']}{/if}" data-validation-engine="validate[required]" data-mask="99" /> + - + <input style="width: 40px;" placeholder="yyyy" type="text" name="expYear" value="{if !empty($CUSTOMER_CARD_INFO)} {$CUSTOMER_CARD_INFO['expyear']}{/if}" data-validation-engine="validate[required]" data-mask="9999" /> + </div> + </div> + <div class="control-group"> + <span class="control-label"> + <span class="redColor">*</span> + {vtranslate('LBL_SECURITY_CODE', $QUALIFIED_MODULE)} + </span> + <div class="controls"> + <input style="width: 40px;" type="text" name="cvccode" value="{if !empty($CUSTOMER_CARD_INFO)} *** {/if}" data-validation-engine="validate[required]" data-mask="999"/> + + <span class="icon icon-question-sign" id="helpSecurityCode" onmouseover="Settings_ExtensionStore_Js.showPopover(this)" data-title="{vtranslate('LBL_WHAT_IS_SECURITY_CODE', $QUALIFIED_MODULE)}" data-content="{vtranslate('LBL_SECURITY_CODE_HELP_CONTENT', $QUALIFIED_MODULE)}" data-position="right"></span> + </div> + </div> + </div> + <div class="modal-footer"> + <div class="row-fluid"> + <div class="span3"> + <span class="pull-left"><button class="btn btn-danger" type="button" name="resetButton"><strong>{vtranslate('LBL_RESET', $QUALIFIED_MODULE)}</strong></button></span> + </div> + <div class="span9"> + <div class="pull-right"> + <div class="pull-right cancelLinkContainer" style="margin-top:0px;"> + <a class="cancelLink" type="reset" data-dismiss="modal">{vtranslate('LBL_CANCEL', $MODULE)}</a> + </div> + <button class="btn btn-success saveButton" type="submit" name="saveButton"><strong>{vtranslate('LBL_SAVE', $MODULE)}</strong></button> + </div> + </div> + </div> + </div> + </form> + </div> + <!-- Setup card detals form end--> + + <!-- Signup form start--> + <div class="modal signUpAccount hide"> + <div class="modal-header contentsBackground"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h3>{vtranslate('LBL_SIGN_UP_FOR_FREE', $QUALIFIED_MODULE)}</h3> + </div> + <form class="form-horizontal signUpForm"> + <input type="hidden" name="module" value="ExtensionStore" /> + <input type="hidden" name="parent" value="Settings" /> + <input type="hidden" name="action" value="Basic" /> + <input type="hidden" name="userAction" value="signup" /> + <input type="hidden" name="mode" value="registerAccount" /> + <div class="modal-body"> + <div class="control-group"> + <span class="control-label"> + <span class="redColor">*</span> + {vtranslate('LBL_EMAIL_ADDRESS', $QUALIFIED_MODULE)} + </span> + <div class="controls"> + <input type="text" name="emailAddress" data-validation-engine="validate[required, funcCall[Vtiger_Base_Validator_Js.invokeValidation]]" /> + </div> + </div> + <div class="control-group"> + <span class="control-label"> + <span class="redColor">*</span> + {vtranslate('LBL_FIRST_NAME', $QUALIFIED_MODULE)} + </span> + <div class="controls"> + <input type="text" name="firstName" data-validation-engine="validate[required, funcCall[Vtiger_Base_Validator_Js.invokeValidation]]" /> + </div> + </div> + <div class="control-group"> + <span class="control-label"> + <span class="redColor">*</span> + {vtranslate('LBL_LAST_NAME', $QUALIFIED_MODULE)} + </span> + <div class="controls"> + <input type="text" name="lastName" data-validation-engine="validate[required, funcCall[Vtiger_Base_Validator_Js.invokeValidation]]" /> + </div> + </div> + <div class="control-group"> + <span class="control-label"> + <span class="redColor">*</span> + {vtranslate('LBL_COMPANY_NAME', $QUALIFIED_MODULE)} + </span> + <div class="controls"> + <input type="text" name="companyName" data-validation-engine="validate[required, funcCall[Vtiger_Base_Validator_Js.invokeValidation]]" /> + </div> + </div> + <div class="control-group"> + <span class="control-label"> + <span class="redColor">*</span> + {vtranslate('LBL_PASSWORD', $QUALIFIED_MODULE)} + </span> + <div class="controls"> + <input type="password" name="password" data-validation-engine="validate[required, funcCall[Vtiger_Base_Validator_Js.invokeValidation]]" /> + </div> + </div> + <div class="control-group"> + <span class="control-label"> + <span class="redColor">*</span> + {vtranslate('LBL_CONFIRM_PASSWORD', $QUALIFIED_MODULE)} + </span> + <div class="controls"> + <input type="password" name="confirmPassword" data-validation-engine="validate[required, funcCall[Vtiger_Base_Validator_Js.invokeValidation]]" /> + </div> + </div> + </div> + <div class="modal-footer"> + <div class="row-fluid"> + <div class="pull-right"> + <div class="pull-right cancelLinkContainer" style="margin-top:0px;"> + <a class="cancelLink" type="reset" data-dismiss="modal">{vtranslate('LBL_CANCEL', $MODULE)}</a> + </div> + <button class="btn btn-success" type="submit" name="saveButton"><strong>{vtranslate('LBL_REGISTER', $QUALIFIED_MODULE)}</strong></button> + </div> + </div> + </div> + </form> + </div> + <!-- Signup form end--> + + <!-- Login form start--> + <div class="modal loginAccount hide"> + <div class="modal-header contentsBackground"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h3>{vtranslate('LBL_MARKETPLACE_REGISTRATION', $QUALIFIED_MODULE)}</h3> + </div> + <form class="form-horizontal loginForm"> + <input type="hidden" name="module" value="ExtensionStore" /> + <input type="hidden" name="parent" value="Settings" /> + <input type="hidden" name="action" value="Basic" /> + <input type="hidden" name="userAction" value="login" /> + <input type="hidden" name="mode" value="registerAccount" /> + <div class="modal-body"> + <div class="control-group"> + <span class="control-label"> + <span class="redColor">*</span> + {vtranslate('LBL_EMAIL', $QUALIFIED_MODULE)} + </span> + <div class="controls"> + {if $REGISTRATION_STATUS} + <input type="hidden" name="emailAddress" value="{$USER_NAME}" /> + <span class="control-label"><span class="pull-left">{$USER_NAME}</span></span> + {else} + <input type="text" name="emailAddress" data-validation-engine="validate[required, custom[email],funcCall[Vtiger_Base_Validator_Js.invokeValidation]]" /> + {/if} + </div> + </div> + <div class="control-group"> + <span class="control-label"> + <span class="redColor">*</span> + {vtranslate('LBL_PASSWORD', $QUALIFIED_MODULE)} + </span> + <div class="controls"> + <input type="password" name="password" data-validation-engine="validate[required, funcCall[Vtiger_Base_Validator_Js.invokeValidation]]" /> + </div> + </div> + <div class="control-group"> + <span class="control-label"></span> + <div class="controls"> + <span> + <input type="checkbox" name="savePassword" /> {vtranslate('LBL_REMEMBER_ME', $QUALIFIED_MODULE)} + </span> + </div> + </div> + </div> + <div class="modal-footer"> + <div class="row-fluid"> + <div class="span6"> + {if !$REGISTRATION_STATUS} + <div class="row-fluid"> + <a href="#" name="signUp">{vtranslate('LBL_CREATE_AN_ACCOUNT', $QUALIFIED_MODULE)}</a> + </div> + {else} + {/if} + </div> + <div class="span6"> + <div class="pull-right"> + <div class="pull-right cancelLinkContainer" style="margin-top:0px;"> + <a class="cancelLink" type="reset" data-dismiss="modal">{vtranslate('LBL_CANCEL', $MODULE)}</a> + </div> + <button class="btn btn-success" type="submit" name="saveButton"><strong>{vtranslate('LBL_LOGIN', $QUALIFIED_MODULE)}</strong></button> + </div> + </div> + </div> + </div> + </form> + </div> + <!-- Login form end --> + + {if $LOADER_REQUIRED} + <div class="modal extensionLoader hide"> + <div class="modal-header contentsBackground"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + <h3>{vtranslate('LBL_INSTALL_EXTENSION_LOADER', $QUALIFIED_MODULE)}</h3> + </div> + <div class="modal-body"> + <div class="row-fluid"> + <p>{vtranslate('LBL_TO_CONTINUE_USING_EXTENSION_STORE', $QUALIFIED_MODULE)}<a href="https://marketplace.vtiger.com/loaderfiles/{$LOADER_INFO['loader_file']}">{vtranslate('LBL_DOWNLOAD', $QUALIFIED_MODULE)}</a>{vtranslate('LBL_COMPATIABLE_EXTENSION', $QUALIFIED_MODULE)}</p> + </div> + <div class="row-fluid"> + <p>{vtranslate('LBL_MORE_DETAILS_ON_INSTALLATION', $QUALIFIED_MODULE)}<a onclick=window.open("http://community.vtiger.com/help/vtigercrm/php/extension-loader.html")>{vtranslate('LBL_READ_HERE', $QUALIFIED_MODULE)}</a></p> + </div> + </div> + <div class="modal-footer"> + <div class="row-fluid"> + <div class="pull-right"> + <div class="pull-right cancelLinkContainer" style="margin-top:0px;"> + <button class="btn btn-success" data-dismiss="modal">{vtranslate('LBL_OK', $QUALIFIED_MODULE)}</button> + </div> + </div> + </div> + </div> + </div> + {/if} + </div> +{/strip} diff --git a/pkg/vtiger/modules/ExtensionStore/settings/templates/InstallationLog.tpl b/pkg/vtiger/modules/ExtensionStore/settings/templates/InstallationLog.tpl new file mode 100644 index 0000000000000000000000000000000000000000..54ce48aa606a16daea69beec1b1de35af0708b8b --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/settings/templates/InstallationLog.tpl @@ -0,0 +1,42 @@ +{*<!-- +* +* Copyright (C) www.vtiger.com. All rights reserved. +* @license Proprietary +* +-->*} +{strip} +<div class='modelContainer'> + <div class="modal-header contentsBackground"> + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> + {if $ERROR} + <input type="hidden" name="installationStatus" value="error" /> + <h3 style="color: red">{vtranslate('LBL_INSTALLATION_FAILED', $QUALIFIED_MODULE)}</h3> + {else} + <input type="hidden" name="installationStatus" value="success" /> + <h3 style="color:green;">{vtranslate('LBL_SUCCESSFULL_INSTALLATION', $QUALIFIED_MODULE)}</h3> + {/if} + </div> + <div class="modal-body" id="installationLog"> + {if $ERROR} + <p style="color:red;">{vtranslate($ERROR_MESSAGE, $QUALIFIED_MODULE)}</p> + {else} + <div class="row-fluid"> + <span class="font-x-x-large">{vtranslate('LBL_INSTALLATION_LOG', $QUALIFIED_MODULE)}</span> + </div> + <div id="extensionInstallationInfo" class="backgroundImageNone" style="background-color: white;padding: 2%;"> + {if $MODULE_ACTION eq "Upgrade"} + {$MODULE_PACKAGE->update($TARGET_MODULE_INSTANCE, $MODULE_FILE_NAME)} + {else} + {$MODULE_PACKAGE->import($MODULE_FILE_NAME, 'false')} + {/if} + {assign var=UNLINK_RESULT value={unlink($MODULE_FILE_NAME)}} + </div> + {/if} + </div> + <div class="modal-footer"> + <span class="pull-right"> + <button class="btn btn-success" id="importCompleted" onclick="location.reload()">{vtranslate('LBL_OK', $QUALIFIED_MODULE)}</button> + </span> + </div> +</div> +{/strip} \ No newline at end of file diff --git a/pkg/vtiger/modules/ExtensionStore/settings/templates/resources/ExtensionStore.js b/pkg/vtiger/modules/ExtensionStore/settings/templates/resources/ExtensionStore.js new file mode 100644 index 0000000000000000000000000000000000000000..4bf6ae6e2d609db46d3d2306cd5735df656ef4a6 --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/settings/templates/resources/ExtensionStore.js @@ -0,0 +1,754 @@ +/* + * Copyright (C) www.vtiger.com. All rights reserved. + * @license Proprietary + */ + +jQuery.Class('Settings_ExtensionStore_Js', { + showPopover : function(e) { + var ele = jQuery(e); + var options = { + placement : ele.data('position'), + trigger : 'hover', + }; + ele.popover(options); + }, +}, { + /** + * Function to get import module index params + */ + getImportModuleIndexParams: function() { + var params = { + 'module': app.getModuleName(), + 'parent': app.getParentModuleName(), + 'view': 'ExtensionStore', + }; + return params; + }, + /** + * Function to get import module with respect to view + */ + getImportModuleStepView: function(params) { + var aDeferred = jQuery.Deferred(); + var progressIndicatorElement = jQuery.progressIndicator({ + 'position': 'html', + 'blockInfo': { + 'enabled': true + } + }); + + AppConnector.request(params).then( + function(data) { + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + aDeferred.resolve(data); + }, + function(error) { + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + aDeferred.reject(error); + } + ); + return aDeferred.promise(); + }, + /** + * Function to register raty + */ + registerRaty: function() { + jQuery('.rating').raty({ + score: function() { + return this.getAttribute('data-score'); + }, + readOnly: function() { + return this.getAttribute('data-readonly'); + } + }); + }, + /** + * Function to register event for index of import module + */ + registerEventForIndexView: function() { + this.registerRaty(); + app.showScrollBar(jQuery('.extensionDescription'), {'height': '120px', 'width': '100%', 'railVisible': true}); + }, + /** + * Function to register event related to Import extrension Modules in index + */ + registerEventsForExtensionStore: function(container) { + var thisInstance = this; + + jQuery(container).on('click', '.installExtension, .installPaidExtension', function(e) { + thisInstance.installExtension(e); + }); + + jQuery(container).on('keydown', '#searchExtension', function(e) { + var currentTarget = jQuery(e.currentTarget); + var code = e.keyCode; + if (code == 13) { + var searchTerm = currentTarget.val(); + var params = { + 'module': app.getModuleName(), + 'parent': app.getParentModuleName(), + 'view': 'ExtensionStore', + 'mode': 'searchExtension', + 'searchTerm': searchTerm, + 'type': 'Extension' + }; + + var progressIndicatorElement = jQuery.progressIndicator({ + 'position': 'html', + 'blockInfo': { + 'enabled': true + } + }); + AppConnector.request(params).then( + function(data) { + jQuery('#extensionContainer').html(data); + thisInstance.registerRaty(); + thisInstance.registerEventForIndexView(); + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + }, + function(error) { + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + } + ); + } + }); + + jQuery(container).on('click', '#logintoMarketPlace', function(e) { + var loginAccountModal = jQuery(container).find('.loginAccount').clone(true, true); + loginAccountModal.removeClass('hide'); + var progressIndicatorElement = jQuery.progressIndicator(); + + var callBackFunction = function(data) { + jQuery(data).on('click', '[name="signUp"]', function(e) { + app.hideModalWindow(); + var signUpAccountModal = jQuery(container).find('.signUpAccount').clone(true, true); + signUpAccountModal.removeClass('hide'); + + var callBackSignupFunction = function(data) { + var form = data.find('.signUpForm'); + var params = app.getvalidationEngineOptions(true); + params.onValidationComplete = function(form, valid) { + if (valid) { + var formData = form.serializeFormData(); + var progressIndicatorElement = jQuery.progressIndicator(); + AppConnector.request(formData).then( + function(data) { + if (data.success) { + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + app.hideModalWindow(); + location.reload(); + } else { + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + app.hideModalWindow(); + var error = data['error']['message']; + var params = { + text: error, + type: 'error', + title : app.vtranslate('JS_WARNING') + }; + Settings_Vtiger_Index_Js.showMessage(params); + } + } + ); + } + return false; + }; + form.validationEngine(params); + }; + + app.showModalWindow(signUpAccountModal, function(data) { + if (typeof callBackFunction == 'function') { + callBackSignupFunction(data); + } + }, {'width': '1000px'}); + }); + + var form = data.find('.loginForm'); + var params = app.getvalidationEngineOptions(true); + params.onValidationComplete = function(form, valid) { + if (valid) { + var formData = form.serializeFormData(); + var savePassword = form.find('input[name="savePassword"]:checked').length; + if (savePassword) { + formData["savePassword"] = true; + } else { + formData["savePassword"] = false; + } + var progressIndicatorElement = jQuery.progressIndicator(); + AppConnector.request(formData).then( + function(data) { + if (data.success) { + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + app.hideModalWindow(); + location.reload(); + } else { + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + app.hideModalWindow(); + var error = data.error.message; + if (error.length) { + var params = { + type: 'error', + text: error, + title : app.vtranslate('JS_WARNING') + }; + Settings_Vtiger_Index_Js.showMessage(params); + } + } + } + ); + } + return false; + }; + form.validationEngine(params); + } + + app.showModalWindow(loginAccountModal, function(data) { + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + if (typeof callBackFunction == 'function') { + callBackFunction(data); + } + }, {'width': '1000px'}); + + }); + + + jQuery(container).on('click', '#logoutMarketPlace', function(e) { + var element = jQuery(e.currentTarget); + var aDeferred = jQuery.Deferred(); + var message = app.vtranslate('JS_LBL_ARE_YOU_SURE_YOU_WANT_TO_LOGOUT_FROM_EXTENSION'); + + Vtiger_Helper_Js.showConfirmationBox({ + 'message' : message + }).then( + function(e) { + var params = { + 'module': app.getModuleName(), + 'parent': app.getParentModuleName(), + 'action' : "Basic", + 'mode' : "logoutMarketPlace" + }; + var progressIndicatorElement = jQuery.progressIndicator(); + + AppConnector.request(params).then( + function(data) { + progressIndicatorElement.progressIndicator({ + 'mode': 'hide' + }); + location.reload(); + aDeferred.resolve(data); + }, + function(error) { + progressIndicatorElement.progressIndicator({ + 'mode': 'hide' + }); + aDeferred.reject(error); + } + ); + return aDeferred.promise(); + }, + function(error, err){ + } + ); + + }); + /* + * Function related extension store pro + jQuery(container).on('click', '#registerUser', function(e) { + var loginAccountModal = jQuery(container).find('.loginAccount').clone(true, true); + loginAccountModal.removeClass('hide'); + + var callBackFunction = function(data) { + jQuery(data).on('click', '[name="signUp"]', function(e) { + app.hideModalWindow(); + var signUpAccountModal = jQuery(container).find('.signUpAccount').clone(true, true); + signUpAccountModal.removeClass('hide'); + + var callBackSignupFunction = function(data) { + var form = data.find('.signUpForm'); + var params = app.getvalidationEngineOptions(true); + params.onValidationComplete = function(form, valid) { + if (valid) { + var formData = form.serializeFormData(); + var progressIndicatorElement = jQuery.progressIndicator(); + AppConnector.request(formData).then( + function(data) { + if (data['success'] == 'true') { + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + app.hideModalWindow(); + location.reload(); + } else { + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + app.hideModalWindow(); + var error = data['error']; + var params = { + text: error + }; + Settings_Vtiger_Index_Js.showMessage(params); + } + } + ); + } + return false; + }; + form.validationEngine(params); + }; + + app.showModalWindow(signUpAccountModal, function(data) { + if (typeof callBackFunction == 'function') { + callBackSignupFunction(data); + } + }, {'width': '1000px'}); + }); + + var form = data.find('.loginForm'); + var params = app.getvalidationEngineOptions(true); + params.onValidationComplete = function(form, valid) { + if (valid) { + var formData = form.serializeFormData(); + var savePassword = form.find('input[name="savePassword"]:checked').length; + if (savePassword) { + formData["savePassword"] = true; + } else { + formData["savePassword"] = false; + } + formData["userAction"] = 'register'; + var progressIndicatorElement = jQuery.progressIndicator(); + AppConnector.request(formData).then( + function(data) { + if (data.success) { + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + app.hideModalWindow(); + location.reload(); + } else { + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + app.hideModalWindow(); + var error = data.error.message; + if (error.length) { + var params = { + text: error + }; + Settings_Vtiger_Index_Js.showMessage(params); + } + } + } + ); + } + return false; + }; + form.validationEngine(params); + }; + + app.showModalWindow(loginAccountModal, function(data) { + if (typeof callBackFunction == 'function') { + callBackFunction(data); + } + }, {'width': '1000px'}); + });*/ + + jQuery(container).on('click', '#setUpCardDetails', function(e) { + var element = jQuery(e.currentTarget); + var setUpCardModal = jQuery(container).find('.setUpCardModal').clone(true, true); + setUpCardModal.removeClass('hide'); + var progressIndicatorElement = jQuery.progressIndicator(); + + var callBackFunction = function(data) { + jQuery(data).on('click', '[name="resetButton"]', function(e) { + jQuery(data).find('[name="cardNumber"],[name="expMonth"],[name="expYear"],[name="cvccode"]').val(''); + }); + var form = data.find('.setUpCardForm'); + var params = app.getvalidationEngineOptions(true); + params.onValidationComplete = function(form, valid) { + if (valid) { + form.find('.saveButton').attr('disabled','true'); + var formData = form.serializeFormData(); + var progressIndicatorElement = jQuery.progressIndicator(); + AppConnector.request(formData).then( + function(data) { + if (data.success) { + var result = data.result; + jQuery(container).find('[name="customerCardId"]').val(data.result.id); + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + jQuery(container).find('.setUpCardModal').find('[name="cardNumber"]').val(result['number']); + jQuery(container).find('.setUpCardModal').find('[name="expMonth"]').val(result['expmonth']); + jQuery(container).find('.setUpCardModal').find('[name="expYear"]').val(result['expyear']); + jQuery(container).find('.setUpCardModal').find('[name="cvccode"]').val(result['cvc']); + element.html(app.vtranslate('JS_UPDATE_CARD_DETAILS')); + app.hideModalWindow(); + Settings_Vtiger_Index_Js.showMessage({text:app.vtranslate('JS_CARD_DETAILS_UPDATED')}); + } else { + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + app.hideModalWindow(); + var errorMessage = data.error.message; + var params = { + type:'error', + text: errorMessage, + title : app.vtranslate('LBL_WARNING') + }; + Settings_Vtiger_Index_Js.showMessage(params); + } + } + ); + } + return false; + }; + form.validationEngine(params); + }; + + app.showModalWindow(setUpCardModal, function(data) { + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + if (typeof callBackFunction == 'function') { + callBackFunction(data); + } + }, {'width': '1000px'}); + }); + + jQuery(container).on('click', '.oneclickInstallFree, .oneclickInstallPaid', function(e) { + var element = jQuery(e.currentTarget); + var extensionContainer = element.closest('.extension_container'); + var extensionId = extensionContainer.find('[name="extensionId"]').val(); + var moduleAction = extensionContainer.find('[name="moduleAction"]').val(); + var extensionName = extensionContainer.find('[name="extensionName"]').val(); + var message = app.vtranslate('JS_LBL_ARE_YOU_SURE_YOU_WANT_TO_INSTALL_THIS_EXTENSION'); + + Vtiger_Helper_Js.showConfirmationBox({'message' : message}).then( + function(e) { + if(element.hasClass('loginRequired')){ + var loginError = app.vtranslate('JS_PLEASE_LOGIN_TO_MARKETPLACE_FOR_INSTALLING_EXTENSION'); + var loginErrorParam = { + text: loginError, + 'type' : 'error' + }; + Settings_Vtiger_Index_Js.showMessage(loginErrorParam); + return false; + } + var params = { + 'module': app.getModuleName(), + 'parent': app.getParentModuleName(), + 'view': 'ExtensionStore', + 'mode': 'oneClickInstall', + 'extensionId': extensionId, + 'moduleAction': moduleAction, + 'extensionName': extensionName + }; + + if (element.hasClass('oneclickInstallPaid')) { + var trial = element.data('trial'); + if (!trial) { + var customerCardId = jQuery(container).find('[name="customerCardId"]').val(); + if (customerCardId.length == 0) { + var cardSetupError = app.vtranslate('JS_PLEASE_SETUP_CARD_DETAILS_TO_INSTALL_THIS_EXTENSION'); + var params = { + text: cardSetupError + }; + Settings_Vtiger_Index_Js.showMessage(params); + return false; + } + } else { + params['trial'] = trial; + } + } + thisInstance.getImportModuleStepView(params).then(function(installationLogData) { + var callBackFunction = function(data) { + app.showScrollBar(jQuery('#installationLog'), {'height': '150px'}); + var installationStatus = jQuery(data).find('[name="installationStatus"]').val(); + + if (installationStatus == "success") { + if (!trial) { + element.closest('span').html('<span class="alert alert-info">' + app.vtranslate('JS_INSTALLED') + '</span>'); + extensionContainer.find('[name="moduleAction"]').val(app.vtranslate('JS_INSTALLED')); + } else if ((element.hasClass('oneclickInstallPaid')) && trial) { + thisInstance.updateTrialStatus(true, extensionName).then(function(data) { + if (data.success) { + element.closest('span').prepend('<span class="alert alert-info">' + app.vtranslate('JS_TRIAL_INSTALLED') + '</span> '); + element.remove(); + } + }); + } else if ((element.hasClass('oneclickInstallPaid')) && (!trial)) { + thisInstance.updateTrialStatus(false, extensionName).then(function(data) { + if (data.success) { + element.closest('span').html('<span class="alert alert-info">' + app.vtranslate('JS_INSTALLED') + '</span>'); + extensionContainer.find('[name="moduleAction"]').val(app.vtranslate('JS_INSTALLED')); + } + }); + } + } + }; + var modalData = { + data: installationLogData, + css: {'width': '60%', 'height': 'auto'}, + cb: callBackFunction + }; + app.showModalWindow(modalData); + }); + }, + function(error, err){ + } + ); + }); + + jQuery(container).on('click', '#installLoader', function(e) { + var extensionLoaderModal = jQuery(container).find('.extensionLoader').clone(true, true); + extensionLoaderModal.removeClass('hide'); + + var callBackFunction = function(data) { + + }; + app.showModalWindow(extensionLoaderModal, function(data) { + if (typeof callBackFunction == 'function') { + callBackFunction(data); + } + }, {'width': '1000px'}); + }); + }, + updateTrialStatus: function(trialStatus, extensionName) { + var trialParams = { + 'module': app.getModuleName(), + 'parent': app.getParentModuleName(), + 'action': 'Basic', + 'mode': 'updateTrialMode', + 'extensionName': extensionName + }; + if (trialStatus) { + trialParams['trial'] = 1; + } else { + trialParams['trial'] = 0; + } + this.getImportModuleStepView(trialParams).then(function(data) { + return data; + }); + }, + installExtension: function(e) { + var thisInstance = this; + var element = jQuery(e.currentTarget); + thisInstance.ExtensionDetails(element); + }, + /** + * Function to download Extension + */ + ExtensionDetails: function(element) { + var thisInstance = this; + var extensionContainer = element.closest('.extension_container'); + var extensionId = extensionContainer.find('[name="extensionId"]').val(); + var moduleAction = extensionContainer.find('[name="moduleAction"]').val(); + var extensionName = extensionContainer.find('[name="extensionName"]').val(); + var params = { + 'module': app.getModuleName(), + 'parent': app.getParentModuleName(), + 'view': 'ExtensionStore', + 'mode': 'detail', + 'extensionId': extensionId, + 'moduleAction': moduleAction, + 'extensionName': extensionName + }; + + this.getImportModuleStepView(params).then(function(data) { + var detailContentsHolder = jQuery('.contentsDiv'); + detailContentsHolder.html(data); + jQuery(window).scrollTop(10); + thisInstance.registerEventsForExtensionStoreDetail(detailContentsHolder); + }); + }, + /** + * Function to register event related to Import extrension Modules in detail + */ + registerEventsForExtensionStoreDetail: function(container) { + var container = jQuery(container); + app.showScrollBar(jQuery('div.scrollableTab'), {'width': '100%', 'height': '400px'}); + var thisInstance = this; + this.registerRaty(); + slider = jQuery('#imageSlider').bxSlider({ + auto: true, + pause: 1000, + randomStart: true, + autoHover: true + }); + jQuery("#screenShots").on('click', function() { + slider.reloadSlider(); + }); + + container.find('#installExtension').on('click', function(e) { + var element = jQuery(e.currentTarget); + var message = app.vtranslate('JS_LBL_ARE_YOU_SURE_YOU_WANT_TO_INSTALL_THIS_EXTENSION'); + + Vtiger_Helper_Js.showConfirmationBox({'message' : message}).then( + function(e) { + + if(element.hasClass('loginRequired')){ + var loginError = app.vtranslate('JS_PLEASE_LOGIN_TO_MARKETPLACE_FOR_INSTALLING_EXTENSION'); + var loginErrorParam = { + text: loginError, + 'type' : 'error' + }; + Settings_Vtiger_Index_Js.showMessage(loginErrorParam); + return false; + } + + if(element.hasClass('setUpCard')){ + var paidError = app.vtranslate('JS_PLEASE_SETUP_CARD_DETAILS_TO_INSTALL_EXTENSION'); + var paidErrorParam = { + text: paidError, + 'type' : 'error' + }; + Settings_Vtiger_Index_Js.showMessage(paidErrorParam); + return false; + } + var extensionId = jQuery('[name="extensionId"]').val(); + var targetModule = jQuery('[name="targetModule"]').val(); + var moduleType = jQuery('[name="moduleType"]').val(); + var moduleAction = jQuery('[name="moduleAction"]').val(); + var fileName = jQuery('[name="fileName"]').val(); + + var params = { + 'module': app.getModuleName(), + 'parent': app.getParentModuleName(), + 'view': 'ExtensionStore', + 'mode': 'installationLog', + 'extensionId': extensionId, + 'moduleAction': moduleAction, + 'targetModule': targetModule, + 'moduleType': moduleType, + 'fileName': fileName + } + + thisInstance.getImportModuleStepView(params).then(function(installationLogData) { + var callBackFunction = function(data) { + var installationStatus = jQuery(data).find('[name="installationStatus"]').val(); + if (installationStatus == "success") { + jQuery('#installExtension').remove(); + jQuery('#launchExtension').removeClass('hide'); + jQuery('.writeReview').removeClass('hide'); + } + app.showScrollBar(jQuery('#installationLog'), {'height': '150px'}); + }; + var modalData = { + data: installationLogData, + css: {'width': '60%', 'height': 'auto'}, + cb: callBackFunction + }; + app.showModalWindow(modalData); + }); + }, + function(error, err){ + } + ); + }); + + container.find('#uninstallModule').on('click', function(e) { + var element = jQuery(e.currentTarget); + var extensionName = container.find('[name="targetModule"]').val(); + if(element.hasClass('loginRequired')){ + var loginError = app.vtranslate('JS_PLEASE_LOGIN_TO_MARKETPLACE_FOR_UNINSTALLING_EXTENSION'); + var loginErrorParam = { + text: loginError, + 'type' : 'error' + }; + Settings_Vtiger_Index_Js.showMessage(loginErrorParam); + return false; + } + var params = { + 'module': app.getModuleName(), + 'parent': app.getParentModuleName(), + 'action': 'Basic', + 'mode': 'uninstallExtension', + 'extensionName': extensionName + }; + + var progressIndicatorElement = jQuery.progressIndicator(); + AppConnector.request(params).then( + function(data) { + if (data.success) { + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + container.find('#declineExtension').trigger('click'); + } + }); + + }); + + container.find('#declineExtension').on('click', function() { + var params = thisInstance.getImportModuleIndexParams(); + thisInstance.getImportModuleStepView(params).then(function(data) { + var detailContentsHolder = jQuery('.contentsDiv'); + detailContentsHolder.html(data); + thisInstance.registerEventForIndexView(); + }); + }); + + container.on('click', '.writeReview', function(e) { + var customerReviewModal = jQuery(container).find('.customerReviewModal').clone(true, true); + customerReviewModal.removeClass('hide'); + + var callBackFunction = function(data) { + var form = data.find('.customerReviewForm'); + form.find('.rating').raty(); + var params = app.getvalidationEngineOptions(true); + params.onValidationComplete = function(form, valid) { + if (valid) { + var review = form.find('[name="customerReview"]').val(); + var listingId = form.find('[name="extensionId"]').val(); + var rating = form.find('[name="score"]').val(); + var params = { + 'module': app.getModuleName(), + 'parent': app.getParentModuleName(), + 'action': 'Basic', + 'mode': 'postReview', + 'comment': review, + 'listing': listingId, + 'rating': rating + } + var progressIndicatorElement = jQuery.progressIndicator(); + AppConnector.request(params).then( + function(data) { + if (data['success']) { + var result = data['result']; + if (result) { + var html = '<div class="row-fluid" style="margin: 8px 0 15px;">' + + '<div class="span3">'+ + '<div data-score="' + rating + '" class="rating" data-readonly="true"></div>'+ + '<div>'+result.Customer.firstname + ' ' + result.Customer.lastname + '</div>'+ + '<div class="muted">'+(result.createdon).substring(4) +'</div>'+ + '</div>'+ + '<div class="span9">'+ result.comment+'</div>'+ + '</div><hr>'; + container.find('.customerReviewContainer').append(html); + container.find('.rating').raty({ + score: function() { + return this.getAttribute('data-score'); + } + }); + } + progressIndicatorElement.progressIndicator({'mode': 'hide'}); + app.hideModalWindow(); + } + } + ); + } + return false; + } + form.validationEngine(params); + } + + app.showModalWindow(customerReviewModal, function(data) { + if (typeof callBackFunction == 'function') { + callBackFunction(data); + } + }, {'width': '1000px'}); + }); + }, + + registerEvents: function() { + var detailContentsHolder = jQuery('.contentsDiv'); + this.registerEventForIndexView(); + this.registerEventsForExtensionStore(detailContentsHolder); + } +}); + +jQuery(document).ready(function() { + var settingExtensionStoreInstance = new Settings_ExtensionStore_Js(); + settingExtensionStoreInstance.registerEvents(); + var mode = jQuery('[name="mode"]').val(); + if(mode == 'detail'){ + settingExtensionStoreInstance.registerEventsForExtensionStoreDetail(jQuery('.contentsDiv')); + } +}); + + + diff --git a/pkg/vtiger/modules/ExtensionStore/settings/views/ExtensionStore.php b/pkg/vtiger/modules/ExtensionStore/settings/views/ExtensionStore.php new file mode 100644 index 0000000000000000000000000000000000000000..7c210e99a689be75eebc77e5bb9a22614c7c74c3 --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/settings/views/ExtensionStore.php @@ -0,0 +1,316 @@ +<?php + +/* + * Copyright (C) www.vtiger.com. All rights reserved. + * @license Proprietary + */ + +include_once dirname(__FILE__).'/../libraries/LoaderSuggest.php'; + +class Settings_ExtensionStore_ExtensionStore_View extends Settings_Vtiger_Index_View { + + public function __construct() { + parent::__construct(); + $this->exposeMethod('searchExtension'); + $this->exposeMethod('detail'); + $this->exposeMethod('installationLog'); + $this->exposeMethod('oneClickInstall'); + } + + protected function getModelInstance() { + if (!isset($this->modelInstance)) { + $this->modelInstance = Settings_ExtensionStore_Extension_Model::getInstance(); + } + return $this->modelInstance; + } + + public function process(Vtiger_Request $request) { + $mode = $request->getMode(); + if (!empty($mode)) { + $this->invokeExposedMethod($mode, $request); + return; + } + + $viewer = $this->getViewer($request); + $qualifiedModuleName = $request->getModule(false); + $modelInstance = $this->getModelInstance(); + $registrationStatus = $modelInstance->checkRegistration(); + + if ($registrationStatus) { + $userName = $modelInstance->getRegisteredUser(); + //check if remember password is enabled + $pwdStatus = $modelInstance->passwordStatus(); + //check if password set in current session + if (!$pwdStatus) { + $sessionIdentifer = $modelInstance->getSessionIdentifier(); + $pwd = $_SESSION[$sessionIdentifer.'_password']; + if (!empty($pwd)) { + $pwdStatus = true; + } + } + $viewer->assign('USER_NAME', $userName); + } + if ($registrationStatus && $pwdStatus) { + $customerProfile = $modelInstance->getProfile(); + $customerCardId = $customerProfile['CustomerCardId']; + if (!empty($customerCardId)) { + $customerCardDetails = $modelInstance->getCardDetails($customerCardId); + $viewer->assign('CUSTOMER_CARD_INFO', $customerCardDetails); + } + $viewer->assign('CUSTOMER_PROFILE', $customerProfile); + } + + $loaderRequired = false; + $loaderInstance = new Settings_ModuleManager_LoaderSuggest(); + $loaderInfo = $loaderRequired ? $loaderInstance->vtiger_extensionloader_suggest() : null; + + $viewer->assign('LOADER_REQUIRED', $loaderRequired); + $viewer->assign('LOADER_INFO', $loaderInfo); + $viewer->assign('PASSWORD_STATUS', $pwdStatus); + $viewer->assign('IS_PRO', true); + $viewer->assign('QUALIFIED_MODULE', $qualifiedModuleName); + $viewer->assign('EXTENSIONS_LIST', $modelInstance->getListings()); + $viewer->assign('REGISTRATION_STATUS', $registrationStatus); + $viewer->view('Index.tpl', $qualifiedModuleName); + } + + /** + * Function to get the list of Script models to be included + * @param Vtiger_Request $request + * @return <Array> - List of Vtiger_JsScript_Model instances + */ + function getHeaderScripts(Vtiger_Request $request) { + $headerScriptInstances = parent::getHeaderScripts($request); + $moduleName = $request->getModule(); + + $jsFileNames = array( + "libraries.jquery.jqueryRating", + "libraries.jquery.boxslider.jqueryBxslider", + "~modules/Settings/ExtensionStore/libraries/jasny-bootstrap.min.js", + ); + + $jsScriptInstances = $this->checkAndConvertJsScripts($jsFileNames); + $headerScriptInstances = array_merge($headerScriptInstances, $jsScriptInstances); + return $headerScriptInstances; + } + + protected function searchExtension(Vtiger_Request $request) { + $searchTerm = $request->get('searchTerm'); + $searchType = $request->get('type'); + $viewer = $this->getViewer($request); + $qualifiedModuleName = $request->getModule(false); + $modelInstance = $this->getModelInstance(); + $registrationStatus = $modelInstance->checkRegistration(); + + if ($registrationStatus) { + $pwdStatus = $modelInstance->passwordStatus(); + if (!$pwdStatus) { + $sessionIdentifer = $modelInstance->getSessionIdentifier(); + $pwd = $_SESSION[$sessionIdentifer.'_password']; + if (!empty($pwd)) { + $pwdStatus = true; + } + } + } + + $viewer->assign('PASSWORD_STATUS', $pwdStatus); + $viewer->assign('IS_PRO', true); + $viewer->assign('REGISTRATION_STATUS', $registrationStatus); + $viewer->assign('QUALIFIED_MODULE', $qualifiedModuleName); + $viewer->assign('EXTENSIONS_LIST', $modelInstance->findListings($searchTerm, $searchType)); + $viewer->view('ExtensionModules.tpl', $qualifiedModuleName); + } + + protected function detail(Vtiger_Request $request) { + $viewer = $this->getViewer($request); + $qualifiedModuleName = $request->getModule(false); + $extensionId = $request->get('extensionId'); + $moduleAction = $request->get('moduleAction'); + $modelInstance = $this->getModelInstance(); + + $extensionDetail = $modelInstance->getExtensionListings($extensionId); + $customerReviews = $modelInstance->getCustomerReviews($extensionId); + $screenShots = $modelInstance->getScreenShots($extensionId); + $authorInfo = $modelInstance->getListingAuthor($extensionId); + $registrationStatus = $modelInstance->checkRegistration(); + + if ($registrationStatus) { + $pwdStatus = $modelInstance->passwordStatus(); + if (!$pwdStatus) { + $sessionIdentifer = $modelInstance->getSessionIdentifier(); + $pwd = $_SESSION[$sessionIdentifer.'_password']; + if (!empty($pwd)) { + $pwdStatus = true; + } + } + $viewer->assign('PASSWORD_STATUS', $pwdStatus); + } + + if ($registrationStatus && $pwdStatus) { + $customerProfile = $modelInstance->getProfile(); + $customerCardId = $customerProfile['CustomerCardId']; + if (!empty($customerCardId)) { + $customerCardDetails = $modelInstance->getCardDetails($customerCardId); + $viewer->assign('CUSTOMER_CARD_INFO', $customerCardDetails); + } + $viewer->assign('CUSTOMER_PROFILE', $customerProfile); + } + + $extension = $extensionDetail[$extensionId]; + $viewer->assign('IS_PRO', true); + $viewer->assign('MODULE_ACTION', $moduleAction); + $viewer->assign('SCREEN_SHOTS', $screenShots); + $viewer->assign('AUTHOR_INFO', $authorInfo); + $viewer->assign('CUSTOMER_REVIEWS', $customerReviews); + $viewer->assign('EXTENSION_DETAIL', $extension); + $viewer->assign('EXTENSION_MODULE_MODEL', $extension->get('moduleModel')); + $viewer->assign('EXTENSION_ID', $extensionId); + $viewer->assign('QUALIFIED_MODULE', $qualifiedModuleName); + $viewer->assign('REGISTRATION_STATUS', $registrationStatus); + $viewer->view('Detail.tpl', $qualifiedModuleName); + } + + protected function installationLog(Vtiger_Request $request) { + $viewer = $this->getViewer($request); + global $Vtiger_Utils_Log; + $viewer->assign('VTIGER_UTILS_LOG', $Vtiger_Utils_Log); + $Vtiger_Utils_Log = true; + $qualifiedModuleName = $request->getModule(false); + + $extensionId = $request->get('extensionId'); + $targetModuleName = $request->get('targetModule'); + $moduleAction = $request->get('moduleAction'); + $modelInstance = $this->getModelInstance(); + + $response = $modelInstance->getInstanceById($extensionId); + if ($response['success']) { + $extensionModel = $response['result']; + $package = $extensionModel->getPackage(); + if ($package) { + $importedModuleName = $package->getModuleName(); + $isLanguagePackage = $package->isLanguageType(); + + if ($moduleAction === 'Upgrade') { + if (($isLanguagePackage && (trim($package->xpath_value('prefix')) == $targetModuleName)) || (!$isLanguagePackage && $importedModuleName === $targetModuleName)) { + $upgradeError = false; + } + } else { + $upgradeError = false; + } + if (!$upgradeError) { + if (!$isLanguagePackage) { + $moduleModel = Vtiger_Module_Model::getInstance($importedModuleName); + $viewer->assign('MODULE_EXISTS', ($moduleModel) ? true : false); + $viewer->assign('MODULE_DIR_NAME', '../modules/'.$importedModuleName); + + if (!$extensionModel->isUpgradable()) { + $viewer->assign('SAME_VERSION', true); + } + } + $moduleType = $package->type(); + $fileName = $extensionModel->getFileName(); + } else { + $viewer->assign('ERROR', true); + $viewer->assign('ERROR_MESSAGE', vtranslate('LBL_INVALID_FILE', $qualifiedModuleName)); + } + } else { + $viewer->assign('ERROR', true); + $viewer->assign('ERROR_MESSAGE', vtranslate('LBL_INVALID_FILE', $qualifiedModuleName)); + } + } else { + $viewer->assign('ERROR', true); + $viewer->assign('ERROR_MESSAGE', $response['message']); + } + + if ($extensionId && $extensionModel) { + if ($moduleAction !== 'Upgrade') { + $extensionModel->installTrackDetails(); + } + if (strtolower($moduleType) === 'language') { + $package = new Vtiger_Language(); + } else { + $package = new Vtiger_Package(); + } + + $viewer->assign('MODULE_ACTION', $moduleAction); + $viewer->assign('MODULE_PACKAGE', $package); + $viewer->assign('TARGET_MODULE_INSTANCE', Vtiger_Module_Model::getInstance($targetModuleName)); + $viewer->assign('MODULE_FILE_NAME', Settings_ExtensionStore_Extension_Model::getUploadDirectory().'/'.$fileName); + } + $viewer->assign('QUALIFIED_MODULE', $qualifiedModuleName); + $viewer->view('InstallationLog.tpl', $qualifiedModuleName); + } + + protected function oneClickInstall(Vtiger_Request $request) { + $viewer = $this->getViewer($request); + global $Vtiger_Utils_Log; + $viewer->assign('VTIGER_UTILS_LOG', $Vtiger_Utils_Log); + $Vtiger_Utils_Log = true; + $upgradeError = true; + $qualifiedModuleName = $request->getModule(false); + $extensionId = $request->get('extensionId'); + $moduleAction = $request->get('moduleAction'); //Import/Upgrade + $trial = $request->get('trial'); + $modelInstance = $this->getModelInstance(); + $response = $modelInstance->getInstanceById($extensionId, $trial); + + if ($response['success']) { + $extensionModel = $response['result']; + $package = $extensionModel->getPackage(); + if ($package) { + $importedModuleName = $package->getModuleName(); + $isLanguagePackage = $package->isLanguageType(); + + if ($moduleAction === 'Upgrade') { + $targetModuleName = $request->get('extensionName'); + if (($isLanguagePackage && (trim($package->xpath_value('prefix')) == $targetModuleName)) || (!$isLanguagePackage && $importedModuleName === $targetModuleName)) { + $upgradeError = false; + } + } else { + $upgradeError = false; + } + if (!$upgradeError) { + if (!$isLanguagePackage) { + $moduleModel = Vtiger_Module_Model::getInstance($importedModuleName); + + if (!$extensionModel->isUpgradable()) { + $viewer->assign('SAME_VERSION', true); + } + } + + $moduleType = $packageType = $package->type(); + $fileName = $extensionModel->getFileName(); + } else { + $viewer->assign('ERROR', true); + $viewer->assign('ERROR_MESSAGE', vtranslate('LBL_INVALID_FILE', $qualifiedModuleName)); + } + } else { + $viewer->assign('ERROR', true); + $viewer->assign('ERROR_MESSAGE', vtranslate('LBL_INVALID_FILE', $qualifiedModuleName)); + } + } else { + $viewer->assign('ERROR', true); + $viewer->assign('ERROR_MESSAGE', $response['message']); + } + + if ($extensionId && $extensionModel) { + if ($moduleAction !== 'Upgrade') { + $extensionModel->installTrackDetails(); + } + if (strtolower($moduleType) === 'language') { + $package = new Vtiger_Language(); + } else { + $package = new Vtiger_Package(); + } + + $viewer->assign('MODULE_ACTION', $moduleAction); + $viewer->assign('MODULE_PACKAGE', $package); + $viewer->assign('TARGET_MODULE_INSTANCE', Vtiger_Module_Model::getInstance($targetModuleName)); + $viewer->assign('MODULE_FILE_NAME', Settings_ExtensionStore_Extension_Model::getUploadDirectory().'/'.$fileName); + } + + $viewer->assign('QUALIFIED_MODULE', $qualifiedModuleName); + $viewer->view('InstallationLog.tpl', $qualifiedModuleName); + } + +} diff --git a/pkg/vtiger/modules/ExtensionStore/templates/Promotions.tpl b/pkg/vtiger/modules/ExtensionStore/templates/Promotions.tpl new file mode 100644 index 0000000000000000000000000000000000000000..8ed5f3d624cb2d34430a5def5dc7b2f68cf7178f --- /dev/null +++ b/pkg/vtiger/modules/ExtensionStore/templates/Promotions.tpl @@ -0,0 +1,32 @@ +{*<!-- +/********************************************************************************* +** The contents of this file are subject to the vtiger CRM Public License Version 1.0 +* ("License"); You may not use this file except in compliance with the License +* The Original Code is: vtiger CRM Open Source +* The Initial Developer of the Original Code is vtiger. +* Portions created by vtiger are Copyright (C) vtiger. +* All Rights Reserved. +* +********************************************************************************/ +-->*} +{strip} + <div class="banner-container"> + <div class="row-fluid"></div> + <div class="banner"> + <ul class="bxslider"> + {foreach $PROMOTIONS as $PROMOTION} + <li> + {assign var=SUMMARY value=$PROMOTION->get('summary')} + {assign var=EXTENSION_NAME value=$PROMOTION->get('label')} + {if is_numeric($SUMMARY)} + {assign var=LOCATION_URL value=$PROMOTION->getLocationUrl($SUMMARY, $EXTENSION_NAME)} + {else} + {assign var=LOCATION_URL value={$SUMMARY}} + {/if} + <a onclick="window.open('{$LOCATION_URL}')"><img src="{if $PROMOTION->get('bannerURL')}{$PROMOTION->get('bannerURL')}{/if}" title="{$PROMOTION->get('label')}" /></a> + </li> + {/foreach} + </ul> + </div> + </div> +{/strip} \ No newline at end of file