From 62b81786795f08d8c9d1b71c749172c313892bcc Mon Sep 17 00:00:00 2001
From: satish <satish.dvnk@vtiger.com>
Date: Tue, 31 Jan 2017 14:09:06 +0530
Subject: [PATCH] Enhanced install module from zip.

---
 .../ModuleManager/ImportUserModuleStep1.tpl   |  50 ++++++
 .../ModuleManager/ImportUserModuleStep2.tpl   | 123 ++++++++++++++
 .../Settings/ModuleManager/ListContents.tpl   |   5 +
 .../ModuleManager/resources/ModuleManager.js  | 114 ++++++++++---
 .../Vtiger/DetailViewHeaderFieldsView.tpl     |   9 +
 .../Settings/ModuleManager/actions/Basic.php  | 159 +++++++++---------
 .../ModuleManager/views/ModuleImport.php      |  73 +++++++-
 7 files changed, 423 insertions(+), 110 deletions(-)
 create mode 100644 layouts/v7/modules/Settings/ModuleManager/ImportUserModuleStep1.tpl
 create mode 100644 layouts/v7/modules/Settings/ModuleManager/ImportUserModuleStep2.tpl

diff --git a/layouts/v7/modules/Settings/ModuleManager/ImportUserModuleStep1.tpl b/layouts/v7/modules/Settings/ModuleManager/ImportUserModuleStep1.tpl
new file mode 100644
index 000000000..c1c5d03b4
--- /dev/null
+++ b/layouts/v7/modules/Settings/ModuleManager/ImportUserModuleStep1.tpl
@@ -0,0 +1,50 @@
+{*+**********************************************************************************
+* The contents of this file are subject to the vtiger CRM Public License Version 1.1
+* ("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="detailViewContainer col-lg-12 col-md-12 col-sm-12" id="importModules">
+		<div class="widget_header row col-lg-12 col-md-12 col-sm-12">
+			<h4>{vtranslate('LBL_IMPORT_MODULE_FROM_ZIP', $QUALIFIED_MODULE)}</h4>
+		</div>
+		<form class="form-horizontal" id="importUserModule" name="importUserModule" action='index.php' method="POST" enctype="multipart/form-data">
+			<input type="hidden" name="module" value="ModuleManager" />
+			<input type="hidden" name="moduleAction" value="Import"/>
+			<input type="hidden" name="parent" value="Settings" />
+			<input type="hidden" name="view" value="ModuleImport" />
+			<input type="hidden" name="mode" value="importUserModuleStep2" />
+			<div class="contents">
+				<div class="row col-lg-12 col-md-12 col-sm-12" style="margin-top:3%">
+					<div class="col-lg-1 col-md-1 col-sm-1">&nbsp;</div>
+					<div class="col-lg-10 col-md-10 col-sm-10">
+						<div class="alert alert-danger">
+							{vtranslate('LBL_DISCLAIMER_FOR_IMPORT_FROM_ZIP', $QUALIFIED_MODULE)}
+						</div>
+						<div>
+							<input type="checkbox" name="acceptDisclaimer" /> &nbsp;&nbsp;<b>{vtranslate('LBL_ACCEPT_WITH_THE_DISCLAIMER', $QUALIFIED_MODULE)}</b>
+						</div>
+						<div name="proceedInstallation" style="margin-top: 15px;" class="fileUploadBtn btn btn-primary">
+							<span><i class="fa fa-laptop"></i> {vtranslate('Select from My Computer', $MODULE)}</span>
+							<input type="file" name="moduleZip" id="moduleZip" size="80px" data-validation-engine="validate[required, funcCall[Vtiger_Base_Validator_Js.invokeValidation]]"
+									data-validator={Zend_Json::encode([['name'=>'UploadModuleZip']])} />
+						</div>
+						<div id="moduleFileDetails" style="margin-top: 15px;"></div>
+					</div>
+				</div>
+			</div>
+			<div class="modal-overlay-footer clearfix">
+				<div class="row clearfix">
+					<div class="textAlignCenter col-lg-12 col-md-12 col-sm-12">
+						<button class="btn btn-success saveButton" disabled="disabled" type="submit" name="importFromZip"><strong>{vtranslate('LBL_IMPORT', $MODULE)}</strong></button>&nbsp;&nbsp;
+						<a class="cancelLink" href="index.php?module=ExtensionStore&parent=Settings&view=ExtensionImport&mode=step1">{vtranslate('LBL_CANCEL', $QUALIFIED_MODULE)}</a>
+					</div>
+				</div>
+			</div>
+		</form>
+	</div>
+{/strip}
\ No newline at end of file
diff --git a/layouts/v7/modules/Settings/ModuleManager/ImportUserModuleStep2.tpl b/layouts/v7/modules/Settings/ModuleManager/ImportUserModuleStep2.tpl
new file mode 100644
index 000000000..3aced8c87
--- /dev/null
+++ b/layouts/v7/modules/Settings/ModuleManager/ImportUserModuleStep2.tpl
@@ -0,0 +1,123 @@
+{*+**********************************************************************************
+* The contents of this file are subject to the vtiger CRM Public License Version 1.1
+* ("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="container-fluid" id="importModules">
+		<div>
+			<div class="row">
+				<div id="vtlib_modulemanager_import_div">
+					{if $MODULEIMPORT_FAILED neq ''}
+						<div class="col-lg-2"></div>
+						<div class="col-lg-10">
+							<b>{vtranslate('LBL_FAILED', $QUALIFIED_MODULE)}</b>
+						</div>
+						<div class="col-lg-2"></div>
+						<div class="col-lg-10">
+							{if $VERSION_NOT_SUPPORTED eq 'true'}
+								<font color=red><b>{vtranslate('LBL_VERSION_NOT_SUPPORTED', $QUALIFIED_MODULE)}</b></font>
+							{else}
+								{if $MODULEIMPORT_FILE_INVALID eq "true"}
+									<font color=red><b>{vtranslate('LBL_INVALID_FILE', $QUALIFIED_MODULE)}</b></font> {vtranslate('LBL_INVALID_IMPORT_TRY_AGAIN', $QUALIFIED_MODULE)}
+								{else}
+									<font color=red>{vtranslate('LBL_UNABLE_TO_UPLOAD', $QUALIFIED_MODULE)}</font> {vtranslate('LBL_UNABLE_TO_UPLOAD2', $QUALIFIED_MODULE)}
+								{/if}
+							{/if}
+						</div>
+						<input type="hidden" name="view" value="List">
+					{else}
+						<div class="row" style="margin-top: 2%">
+							<div>
+								<h3>{vtranslate('LBL_VERIFY_IMPORT_DETAILS',$QUALIFIED_MODULE)}</h3>
+							</div><hr>
+						</div>
+						<div class="container-fluid"><br>
+							<div class="row">
+								<div class="col-lg-12">
+									<h4>
+										{vtranslate($MODULEIMPORT_NAME, $QUALIFIED_MODULE)}
+										{if $MODULEIMPORT_EXISTS eq 'true'} <font color=red><b>{vtranslate('LBL_EXISTS', $QUALIFIED_MODULE)}</b></font> {/if}
+									</h4>
+								</div>
+							</div>
+							<div class="row">
+								<div class="col-lg-12">
+									<p>
+										<small>{vtranslate('LBL_REQ_VTIGER_VERSION', $QUALIFIED_MODULE)} : {$MODULEIMPORT_DEP_VTVERSION}</small>
+									</p>
+								</div>
+							</div>
+							{assign var="need_license_agreement" value="false"}
+							{if $MODULEIMPORT_LICENSE}
+								{assign var="need_license_agreement" value="true"}
+								<div class="row">
+									<div class="col-lg-12">
+										<p>{vtranslate('LBL_LICENSE', $QUALIFIED_MODULE)}</p>
+									</div>
+								</div>
+								<div class="row">
+									<div class="col-lg-12">
+										<div style="background: #eee;padding: 20px;box-sizing: border-box;height: 150px;overflow-y: scroll;">
+											<p>{$MODULEIMPORT_LICENSE|nl2br}</p>
+										</div>
+									</div>
+								</div>
+							{/if}
+							<br>
+							<div class="row">
+								<div class="col-lg-4">
+									{if $MODULEIMPORT_EXISTS neq 'true'}
+										<input type="checkbox" class="acceptLicense"> {vtranslate('LBL_LICENSE_ACCEPT_AGREEMENT', $QUALIFIED_MODULE)}
+									{/if}&nbsp;
+								</div>
+								<div class="col-lg-8">
+									<span class="pull-right">
+										<div class="row">
+											{if $MODULEIMPORT_EXISTS eq 'true' || $MODULEIMPORT_DIR_EXISTS eq 'true'}
+												<div class="col-lg-2"></div>
+												<div class="col-lg-10">
+													{if $MODULEIMPORT_EXISTS eq 'true'}
+														<input type="hidden" name="module_import_file" value="{$MODULEIMPORT_FILE}">
+														<input type="hidden" name="module_import_type" value="{$MODULEIMPORT_TYPE}">
+														<input type="hidden" name="module_import_name" value="{$MODULEIMPORT_NAME}">
+													{else}
+														<p class="alert-info">{vtranslate('LBL_DELETE_EXIST_DIRECTORY', $QUALIFIED_MODULE)}</p>
+													{/if}
+												</div>
+											{else}
+												<input type="hidden" name="module_import_file" value="{$MODULEIMPORT_FILE}">
+												<input type="hidden" name="module_import_type" value="{$MODULEIMPORT_TYPE}">
+												<input type="hidden" name="module_import_name" value="{$MODULEIMPORT_NAME}">
+											{/if}
+										</div>
+									</span>
+								</div>
+							</div>
+						</div>
+						<br><br>
+					{/if}
+				</div>
+			</div>
+		</div>
+		<div class="modal-overlay-footer clearfix">
+			<div class="row clearfix">
+				<div class="textAlignCenter col-lg-12 col-md-12 col-sm-12">
+					{if $MODULEIMPORT_FAILED neq ''}
+						<button class="btn btn-success finishButton" type="submit"><strong>{vtranslate('LBL_FINISH', $QUALIFIED_MODULE)}</strong></button>
+					{else if $MODULEIMPORT_EXISTS eq 'true' || $MODULEIMPORT_DIR_EXISTS eq 'true'}
+						<button class="btn btn-success updateModule" name="saveButton">{vtranslate('LBL_UPDATE_NOW', $QUALIFIED_MODULE)}</button>
+					{else}
+						<button class="btn btn-success importModule" name="saveButton" {if $need_license_agreement eq 'true'} disabled {/if}><strong>{vtranslate('LBL_IMPORT_NOW', $QUALIFIED_MODULE)}</strong></button>
+					{/if}
+					&nbsp;&nbsp;
+					<a class="cancelLink" href="index.php?module=ModuleManager&parent=Settings&view=ModuleImport&mode=importUserModuleStep1">{vtranslate('LBL_CANCEL', $QUALIFIED_MODULE)}</a>
+				</div>
+			</div>
+		</div>
+	</div>
+{/strip}
\ No newline at end of file
diff --git a/layouts/v7/modules/Settings/ModuleManager/ListContents.tpl b/layouts/v7/modules/Settings/ModuleManager/ListContents.tpl
index b80e4eb5d..6a8d45986 100644
--- a/layouts/v7/modules/Settings/ModuleManager/ListContents.tpl
+++ b/layouts/v7/modules/Settings/ModuleManager/ListContents.tpl
@@ -15,6 +15,11 @@
 				<div class="clearfix">
 					<h4 class="pull-left">{vtranslate('LBL_MODULE_MANAGER', $QUALIFIED_MODULE)}</h4>
 					<div class="pull-right">
+						<div class="btn-group">
+							<button class="btn btn-default" type="button" onclick='window.location.href="{$IMPORT_USER_MODULE_FROM_FILE_URL}"'>
+								{vtranslate('LBL_IMPORT_MODULE_FROM_ZIP', $QUALIFIED_MODULE)}
+							</button>
+						</div>&nbsp;
 						<div class="btn-group">
 							<button class="btn btn-default" type="button" onclick='window.location.href = "{$IMPORT_MODULE_URL}"'>
 								{vtranslate('LBL_EXTENSION_STORE', 'Settings:ExtensionStore')}
diff --git a/layouts/v7/modules/Settings/ModuleManager/resources/ModuleManager.js b/layouts/v7/modules/Settings/ModuleManager/resources/ModuleManager.js
index fe04cc991..6edcf3981 100644
--- a/layouts/v7/modules/Settings/ModuleManager/resources/ModuleManager.js
+++ b/layouts/v7/modules/Settings/ModuleManager/resources/ModuleManager.js
@@ -41,9 +41,92 @@ Vtiger.Class('Settings_Module_Manager_Js', {
 		);
 		return aDeferred.promise();
 	},
+	registerEventsForImportFromZip: function (container) {
+		container.on('change', '[name="acceptDisclaimer"]', function (e) {
+			var element = jQuery(e.currentTarget);
+			var importFromZip = container.find('[name="importFromZip"]');
+			var uploadedFile = jQuery('#moduleZip').val();
+			var disabledStatus = importFromZip.attr('disabled');
+			if ((element.is(':checked')) && (uploadedFile != '')) {
+				if (typeof disabledStatus != "undefined") {
+					importFromZip.removeAttr('disabled');
+				}
+			} else {
+				if (typeof disabledStatus == "undefined") {
+					importFromZip.attr('disabled', "disabled");
+				}
+			}
+		});
+
+		container.on('change', '[name="moduleZip"]', function (e) {
+			container.find('[name="acceptDisclaimer"]').trigger('click');
+		});
+
+		container.on('click', '.finishButton', function() {
+			window.location.href = jQuery('[data-name="VTLIB_LBL_MODULE_MANAGER"]').attr('href');
+		});
+
+		container.on('click', '.importModule, .updateModule', function (e) {
+			var element = jQuery(e.currentTarget);
+			var params = {};
+			if (element.hasClass('updateModule')) {
+				params = {
+					'module': app.getModuleName(),
+					'parent': app.getParentModuleName(),
+					'action': 'Basic',
+					'mode': 'updateUserModuleStep3'
+				};
+			} else if (element.hasClass('importModule')) {
+				params = {
+					'module': app.getModuleName(),
+					'parent': app.getParentModuleName(),
+					'action': 'Basic',
+					'mode': 'importUserModuleStep3'
+				};
+			}
+			params['module_import_file'] = container.find('[name="module_import_file"]').val();
+			params['module_import_type'] = container.find('[name="module_import_type"]').val();
+			params['module_import_name'] = container.find('[name="module_import_name"]').val();
+
+			AppConnector.request(params).then(
+				function (data) {
+					element.addClass('hide');
+					var headerMessage, containerMessage;
+
+					if (element.hasClass('updateModule')) {
+						headerMessage = app.vtranslate('JS_UPDATE_SUCCESSFULL');
+						containerMessage = app.vtranslate('JS_UPDATED_MODULE');
+					} else if (element.hasClass('importModule')) {
+						headerMessage = app.vtranslate('JS_IMPORT_SUCCESSFULL');
+						containerMessage = app.vtranslate('JS_IMPORTED_MODULE');
+					}
+					app.helper.showSuccessNotification({'title': headerMessage, 'message': data.result.importModuleName+' '+containerMessage});
+					setTimeout(function() {
+						window.location.href = jQuery('[data-name="VTLIB_LBL_MODULE_MANAGER"]').attr('href');
+					}, 3000);
+				}
+			);
+		});
+
+		container.on('click', '.acceptLicense', function (e) {
+			var element = jQuery(e.currentTarget);
+			var saveButton = container.find('[name="saveButton"]')
+			if (element.is(':checked')) {
+				saveButton.removeAttr("disabled");
+			} else {
+				if (typeof saveButton.attr('disabled') == 'undefined') {
+					saveButton.attr('disabled', "disabled");
+				}
+			}
+		});
+	},
 	registerEvents: function (e) {
 		var thisInstance = this;
 		var container = jQuery('#moduleManagerContents');
+		var importFromZipContainer = jQuery('#importModules');
+		if (importFromZipContainer.length > 0) {
+			thisInstance.registerEventsForImportFromZip(importFromZipContainer);
+		}
 
 		//register click event for check box to update the module status
 		container.on('click', '[name="moduleStatus"]', function (e) {
@@ -61,13 +144,10 @@ Vtiger.Class('Settings_Module_Manager_Js', {
 				moduleDetails.removeClass('dull');
 
 				//update the module status as enabled
-				thisInstance.updateModuleStatus(currentTarget).then(
-					function (data) {
-						var message = forModule+' '+app.vtranslate('JS_MODULE_ENABLED');
-						app.helper.showSuccessNotification({'message': message});
-					}
-				);
-
+				thisInstance.updateModuleStatus(currentTarget).then(function (data) {
+					var message = forModule+' '+app.vtranslate('JS_MODULE_ENABLED');
+					app.helper.showSuccessNotification({'message': message});
+				});
 			} else {
 				//hide the settings button for the module.
 				actionButtons.addClass('hide');
@@ -76,22 +156,14 @@ Vtiger.Class('Settings_Module_Manager_Js', {
 				moduleDetails.addClass('dull');
 
 				//update the module status as disabled
-				thisInstance.updateModuleStatus(currentTarget).then(
-					function (data) {
-						var message = forModule+' '+app.vtranslate('JS_MODULE_DISABLED');
-						app.helper.showSuccessNotification({'message': message});
-					}
-
-				);
+				thisInstance.updateModuleStatus(currentTarget).then(function (data) {
+					var message = forModule+' '+app.vtranslate('JS_MODULE_DISABLED');
+					app.helper.showSuccessNotification({'message': message});
+				});
 			}
-
 		});
-
 	}
 });
 
-Settings_Module_Manager_Js('Settings_ModuleManager_List_Js', {}, {
-	init: function () {
-		this.addModuleSpecificComponent('Index', 'Vtiger', app.getParentModuleName());
-	}
-});
+var moduleManagerInstance = new Settings_Module_Manager_Js();
+moduleManagerInstance.registerEvents();
diff --git a/layouts/v7/modules/Vtiger/DetailViewHeaderFieldsView.tpl b/layouts/v7/modules/Vtiger/DetailViewHeaderFieldsView.tpl
index 4eb388c0e..8b9bb7254 100644
--- a/layouts/v7/modules/Vtiger/DetailViewHeaderFieldsView.tpl
+++ b/layouts/v7/modules/Vtiger/DetailViewHeaderFieldsView.tpl
@@ -1,3 +1,12 @@
+{*+**********************************************************************************
+* The contents of this file are subject to the vtiger CRM Public License Version 1.1
+* ("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}
 <form id="headerForm" method="POST">
     {assign var=FIELDS_MODELS_LIST value=$MODULE_MODEL->getFields()}
diff --git a/modules/Settings/ModuleManager/actions/Basic.php b/modules/Settings/ModuleManager/actions/Basic.php
index e4ecf3dfb..3f488c505 100644
--- a/modules/Settings/ModuleManager/actions/Basic.php
+++ b/modules/Settings/ModuleManager/actions/Basic.php
@@ -10,96 +10,95 @@
 require_once('vtlib/Vtiger/Layout.php'); 
 
 class Settings_ModuleManager_Basic_Action extends Settings_Vtiger_IndexAjax_View {
-    function __construct() {
+	function __construct() {
 		parent::__construct();
 		$this->exposeMethod('updateModuleStatus');
-                $this->exposeMethod('importUserModuleStep3');
-                $this->exposeMethod('updateUserModuleStep3');
+		$this->exposeMethod('importUserModuleStep3');
+		$this->exposeMethod('updateUserModuleStep3');
 	}
-    
-    function process(Vtiger_Request $request) {
+
+	function process(Vtiger_Request $request) {
 		$mode = $request->getMode();
 		if(!empty($mode)) {
 			echo $this->invokeExposedMethod($mode, $request);
 			return;
 		}
 	}
-    
-    public function updateModuleStatus(Vtiger_Request $request) {
-        $moduleName = $request->get('forModule');
-        $updateStatus = $request->get('updateStatus');
-        
-        $moduleManagerModel = new Settings_ModuleManager_Module_Model();
-        
-        if($updateStatus == 'true') {
-            $moduleManagerModel->enableModule($moduleName);
-        }else{
-            $moduleManagerModel->disableModule($moduleName);
-        }
-        
-        $response = new Vtiger_Response();
+
+	public function updateModuleStatus(Vtiger_Request $request) {
+		$moduleName = $request->get('forModule');
+		$updateStatus = $request->get('updateStatus');
+
+		$moduleManagerModel = new Settings_ModuleManager_Module_Model();
+
+		if($updateStatus == 'true') {
+			$moduleManagerModel->enableModule($moduleName);
+		}else{
+			$moduleManagerModel->disableModule($moduleName);
+		}
+
+		$response = new Vtiger_Response();
 		$response->emit();
-    }
-    
-    public function importUserModuleStep3(Vtiger_Request $request) {
-        $importModuleName = $request->get('module_import_name');
-        $uploadFile = $request->get('module_import_file');
-        $uploadDir = Settings_ModuleManager_Extension_Model::getUploadDirectory();
-        $uploadFileName = "$uploadDir/$uploadFile";
-        checkFileAccess($uploadFileName);
-
-        $importType = $request->get('module_import_type');
-        if(strtolower($importType) == 'language') {
-                $package = new Vtiger_Language();
-        }else  if(strtolower($importType) == 'layout') {
-                 $package = new Vtiger_Layout();
-                 }
-        else {
-                $package = new Vtiger_Package();
-        }
-
-        $package->import($uploadFileName);
-        checkFileAccessForDeletion($uploadFileName);
-        unlink($uploadFileName);
-        
-        $result = array('success'=>true, 'importModuleName'=> $importModuleName);
-        $response = new Vtiger_Response();
-        $response->setResult($result);
-        $response->emit();
-    }
-    
-    public function updateUserModuleStep3(Vtiger_Request $request){
-        $importModuleName = $request->get('module_import_name');
-        $uploadFile = $request->get('module_import_file');
-        $uploadDir = Settings_ModuleManager_Extension_Model::getUploadDirectory();
-        $uploadFileName = "$uploadDir/$uploadFile";
-        checkFileAccess($uploadFileName);
-
-        $importType = $request->get('module_import_type');
-        if(strtolower($importType) == 'language') {
-                $package = new Vtiger_Language();
-        } else if(strtolower($importType) == 'layout') { 
-            $package = new Vtiger_Layout(); 
-        } else { 
-                $package = new Vtiger_Package();
-        }
-
-        if (strtolower($importType) == 'language' || strtolower($importType) == 'layout' ) {
-                $package->import($uploadFileName);
-        } else {
-                $package->update(Vtiger_Module::getInstance($importModuleName), $uploadFileName);
-        }
-
-        checkFileAccessForDeletion($uploadFileName);
-        unlink($uploadFileName);
-        
-        $result = array('success'=>true, 'importModuleName'=> $importModuleName);
-        $response = new Vtiger_Response();
-        $response->setResult($result);
-        $response->emit();
-    }
+	}
+
+	public function importUserModuleStep3(Vtiger_Request $request) {
+		$importModuleName = $request->get('module_import_name');
+		$uploadFile = $request->get('module_import_file');
+		$uploadDir = Settings_ModuleManager_Extension_Model::getUploadDirectory();
+		$uploadFileName = "$uploadDir/$uploadFile";
+		checkFileAccess($uploadFileName);
+
+		$importType = $request->get('module_import_type');
+		if(strtolower($importType) == 'language') {
+			$package = new Vtiger_Language();
+		} else if(strtolower($importType) == 'layout') {
+			$package = new Vtiger_Layout();
+		} else {
+			$package = new Vtiger_Package();
+		}
+
+		$package->import($uploadFileName);
+		checkFileAccessForDeletion($uploadFileName);
+		unlink($uploadFileName);
+
+		$result = array('success'=>true, 'importModuleName'=> $importModuleName);
+		$response = new Vtiger_Response();
+		$response->setResult($result);
+		$response->emit();
+	}
+
+	public function updateUserModuleStep3(Vtiger_Request $request){
+		$importModuleName = $request->get('module_import_name');
+		$uploadFile = $request->get('module_import_file');
+		$uploadDir = Settings_ModuleManager_Extension_Model::getUploadDirectory();
+		$uploadFileName = "$uploadDir/$uploadFile";
+		checkFileAccess($uploadFileName);
+
+		$importType = $request->get('module_import_type');
+		if(strtolower($importType) == 'language') {
+			$package = new Vtiger_Language();
+		} else if(strtolower($importType) == 'layout') { 
+			$package = new Vtiger_Layout(); 
+		} else { 
+			$package = new Vtiger_Package();
+		}
+
+		if (strtolower($importType) == 'language' || strtolower($importType) == 'layout' ) {
+			$package->import($uploadFileName);
+		} else {
+			$package->update(Vtiger_Module::getInstance($importModuleName), $uploadFileName);
+		}
+
+		checkFileAccessForDeletion($uploadFileName);
+		unlink($uploadFileName);
+
+		$result = array('success'=>true, 'importModuleName'=> $importModuleName);
+		$response = new Vtiger_Response();
+		$response->setResult($result);
+		$response->emit();
+	}
 
 	 public function validateRequest(Vtiger_Request $request) { 
-        $request->validateWriteAccess(); 
-    } 
+		$request->validateWriteAccess(); 
+	} 
 }
diff --git a/modules/Settings/ModuleManager/views/ModuleImport.php b/modules/Settings/ModuleManager/views/ModuleImport.php
index 56ebed368..cf5bad4e2 100644
--- a/modules/Settings/ModuleManager/views/ModuleImport.php
+++ b/modules/Settings/ModuleManager/views/ModuleImport.php
@@ -14,6 +14,8 @@ class Settings_ModuleManager_ModuleImport_View extends Settings_Vtiger_Index_Vie
 		parent::__construct();
 		$this->exposeMethod('step2');
 		$this->exposeMethod('step3');
+		$this->exposeMethod('importUserModuleStep1');
+		$this->exposeMethod('importUserModuleStep2');
 	}
 
 	public function process(Vtiger_Request $request) {
@@ -23,10 +25,12 @@ class Settings_ModuleManager_ModuleImport_View extends Settings_Vtiger_Index_Vie
 			return;
 		}
 
+		$EXTENSIONS = Settings_ModuleManager_Extension_Model::getAll();
 		$qualifiedModuleName = $request->getModule(false);
 		$viewer = $this->getViewer($request);
 		$viewer->assign('QUALIFIED_MODULE', $qualifiedModuleName);
-		$viewer->assign('EXTENSIONS', Settings_ModuleManager_Extension_Model::getAll());
+		$viewer->assign('EXTENSIONS', $EXTENSIONS);
+		$viewer->assign('EXTENSIONS_AVAILABLE', (count($EXTENSIONS) > 0)? true :false);
 		$viewer->view('Step1.tpl', $qualifiedModuleName);
 	}
 
@@ -71,7 +75,7 @@ class Settings_ModuleManager_ModuleImport_View extends Settings_Vtiger_Index_Vie
 					$viewer->assign('FILE_NAME', $extensionModel->getFileName());
 					$viewer->assign('MODULE_LICENSE', (string)$package->getLicense());
 					$viewer->assign('SUPPORTED_VTVERSION', $package->getDependentVtigerVersion());
-					
+
 				} else {
 					$viewer->assign('ERROR', true);
 					$viewer->assign('ERROR_MESSAGE', vtranslate('LBL_INVALID_FILE', $qualifiedModuleName));
@@ -125,8 +129,8 @@ class Settings_ModuleManager_ModuleImport_View extends Settings_Vtiger_Index_Vie
 		$viewer->assign('QUALIFIED_MODULE', $qualifiedModuleName);
 		$viewer->view('Step3.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
@@ -143,8 +147,59 @@ class Settings_ModuleManager_ModuleImport_View extends Settings_Vtiger_Index_Vie
 		$headerScriptInstances = array_merge($headerScriptInstances, $jsScriptInstances);
 		return $headerScriptInstances;
 	}
-    
-    public function validateRequest(Vtiger_Request $request) {
-        $request->validateReadAccess();
-    }
-}
\ No newline at end of file
+
+	public function importUserModuleStep1(Vtiger_Request $request){
+		$viewer = $this->getViewer($request);
+		$qualifiedModuleName = $request->getModule(false);
+		$viewer->assign('QUALIFIED_MODULE', $qualifiedModuleName);
+		$viewer->view('ImportUserModuleStep1.tpl', $qualifiedModuleName);
+	}
+
+	public function importUserModuleStep2(Vtiger_Request $request){
+		$viewer = $this->getViewer($request);
+		$uploadDir = Settings_ModuleManager_Extension_Model::getUploadDirectory();
+		$qualifiedModuleName = $request->getModule(false);
+
+		$uploadFile = 'usermodule_'.time().'.zip';
+		$uploadFileName = "$uploadDir/$uploadFile";
+		checkFileAccess($uploadDir);
+		if(!move_uploaded_file($_FILES['moduleZip']['tmp_name'], $uploadFileName)) {
+			$viewer->assign('MODULEIMPORT_FAILED', true);
+		}else{
+			$package = new Vtiger_Package();
+			$importModuleName = $package->getModuleNameFromZip($uploadFileName);
+			$importModuleDepVtVersion = $package->getDependentVtigerVersion();
+
+			if($importModuleName == null ) {
+				$viewer->assign('MODULEIMPORT_FAILED', true);
+				$viewer->assign("MODULEIMPORT_FILE_INVALID", true);
+				checkFileAccessForDeletion($uploadFileName);
+				unlink($uploadFileName);
+			} else {
+				// We need these information to push for Update if module is detected to be present.
+				$moduleLicence = vtlib_purify($package->getLicense());
+
+				$viewer->assign("MODULEIMPORT_FILE", $uploadFile);
+				$viewer->assign("MODULEIMPORT_TYPE", $package->type());
+				$viewer->assign("MODULEIMPORT_NAME", $importModuleName);
+				$viewer->assign("MODULEIMPORT_DEP_VTVERSION", $importModuleDepVtVersion);
+				$viewer->assign("MODULEIMPORT_LICENSE", $moduleLicence);
+
+				if(!$package->isLanguageType() && !$package->isModuleBundle()) {
+					$moduleInstance = Vtiger_Module::getInstance($importModuleName);
+					$moduleimport_exists = ($moduleInstance)? "true" : "false";
+					$moduleimport_dir_name = "modules/$importModuleName";
+					$moduleimport_dir_exists = (is_dir($moduleimport_dir_name)? "true" : "false");
+					$viewer->assign("MODULEIMPORT_EXISTS", $moduleimport_exists);
+					$viewer->assign("MODULEIMPORT_DIR", $moduleimport_dir_name);
+					$viewer->assign("MODULEIMPORT_DIR_EXISTS", $moduleimport_dir_exists);
+				}
+			}
+		}
+		$viewer->view('ImportUserModuleStep2.tpl', $qualifiedModuleName);
+	}
+
+	public function validateRequest(Vtiger_Request $request) {
+		$request->validateReadAccess();
+	}
+}
-- 
GitLab