Explorar o código

Plugin work plus Mail plug in

causefx %!s(int64=8) %!d(string=hai) anos
pai
achega
8f27719b7d

+ 1 - 10
api/config/default.php

@@ -7,14 +7,5 @@ return array(
     'useLogo' => false,
     'headerColor' => '',
     'headerTextColor' => '',
-    'lockScreen' => false,
-    'mail' => false,
-    'smtpHost' => '',
-	'smtpHostPort' => '',
-	'smtpHostAuth' => true,
-	'smtpHostUsername' => '',
-	'smtpHostPassword' => '',
-	'smtpHostSenderName' => 'Organizr',
-	'smtpHostSenderEmail' => 'no-reply@Organizr.tld',
-    'smtpHostType' => 'tls'
+    'lockScreen' => false
 );

+ 4 - 0
api/functions.php

@@ -20,3 +20,7 @@ getOrganizrUserToken();
 foreach (glob(__DIR__.DIRECTORY_SEPARATOR.'pages' . DIRECTORY_SEPARATOR . "*.php") as $filename){
     require_once $filename;
 }
+// Include all plugin files
+foreach (glob(__DIR__.DIRECTORY_SEPARATOR.'plugins' . DIRECTORY_SEPARATOR . "*.php") as $filename){
+    require_once $filename;
+}

+ 0 - 24
api/functions/api-functions.php

@@ -756,30 +756,6 @@ function editCategories($array){
             break;
     }
 }
-function editAppearance($array){
-    switch ($array['data']['value']) {
-        case 'true':
-            $array['data']['value'] = (bool) true;
-            break;
-        case 'false':
-            $array['data']['value'] = (bool) false;
-            break;
-        default:
-            $array['data']['value'] = $array['data']['value'];
-    }
-    //return gettype($array['data']['value']).' - '.$array['data']['value'];
-    switch ($array['data']['action']) {
-        case 'editCustomizeAppearance':
-            $newItem = array(
-                $array['data']['name'] => $array['data']['value']
-            );
-            return (updateConfig($newItem)) ? true : false;
-            break;
-        default:
-            # code...
-            break;
-    }
-}
 function allUsers(){
     try {
     	$connect = new Dibi\Connection([

+ 4 - 0
api/functions/config-functions.php

@@ -114,6 +114,10 @@ function fillDefaultConfig($array) {
 	} else {
 		$loadedDefaults = $path;
 	}
+	// Include all plugin config files
+	foreach (glob(dirname(__DIR__,1).DIRECTORY_SEPARATOR.'plugins' . DIRECTORY_SEPARATOR . 'config' . DIRECTORY_SEPARATOR . "*.php") as $filename){
+		$loadedDefaults = array_merge($loadedDefaults , loadConfig($filename));
+	}
 	return (is_array($loadedDefaults) ? fillDefaultConfig_recurse($array, $loadedDefaults) : false);
 }
 function fillDefaultConfig_recurse($current, $defaults) {

+ 4 - 0
api/functions/normal-functions.php

@@ -247,3 +247,7 @@ function localURL($url){
 		return $result;
 	}
 }
+function array_filter_key(array $array, $callback){
+	$matchedKeys = array_filter(array_keys($array), $callback);
+	return array_intersect_key($array, array_flip($matchedKeys));
+}

+ 82 - 1
api/functions/organizr-functions.php

@@ -165,7 +165,7 @@ function loadAppearance(){
     return $appearance;
 }
 function getCustomizeAppearance(){
-    if(file_exists('config'.DIRECTORY_SEPARATOR.'config.php')){
+    if(file_exists(dirname(__DIR__,1).DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php')){
         return array(
             'config' => array(/*
                 array(
@@ -217,6 +217,85 @@ function getCustomizeAppearance(){
         );
     }
 }
+function editAppearance($array){
+    switch ($array['data']['value']) {
+        case 'true':
+            $array['data']['value'] = (bool) true;
+            break;
+        case 'false':
+            $array['data']['value'] = (bool) false;
+            break;
+        default:
+            $array['data']['value'] = $array['data']['value'];
+    }
+    //return gettype($array['data']['value']).' - '.$array['data']['value'];
+    switch ($array['data']['action']) {
+        case 'editCustomizeAppearance':
+            $newItem = array(
+                $array['data']['name'] => $array['data']['value']
+            );
+            return (updateConfig($newItem)) ? true : false;
+            break;
+        default:
+            # code...
+            break;
+    }
+}
+function updateConfigItem($array){
+    switch ($array['data']['value']) {
+        case 'true':
+            $array['data']['value'] = (bool) true;
+            break;
+        case 'false':
+            $array['data']['value'] = (bool) false;
+            break;
+        default:
+            $array['data']['value'] = $array['data']['value'];
+    }
+	// Hash
+	if($array['data']['type'] == 'password'){
+		$array['data']['value'] = encrypt($array['data']['value']);
+	}
+    //return gettype($array['data']['value']).' - '.$array['data']['value'];
+    $newItem = array(
+        $array['data']['name'] => $array['data']['value']
+    );
+    return (updateConfig($newItem)) ? true : false;
+}
+function getPlugins(){
+    if(file_exists(dirname(__DIR__,1).DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php')){
+		$pluginList = array();
+        foreach($GLOBALS['plugins'] as $plugin){
+			foreach ($plugin as $key => $value) {
+				$plugin[$key]['enabled'] = $GLOBALS[$value['configPrefix'].'-enabled'];
+			}
+			$pluginList = array_merge($pluginList, $plugin);
+		}
+		return $pluginList;
+    }
+	return false;
+}
+function editPlugins($array){
+	switch ($array['data']['action']) {
+        case 'enable':
+            $newItem = array(
+                $array['data']['configName'] => true
+            );
+			writeLog('success', 'Plugin Function -  Enabled Plugin ['.$_POST['data']['name'].']', $GLOBALS['organizrUser']['username']);
+            return (updateConfig($newItem)) ? true : false;
+            break;
+		case 'disable':
+			$newItem = array(
+				$array['data']['configName'] => false
+			);
+			writeLog('success', 'Plugin Function -  Disabled Plugin ['.$_POST['data']['name'].']', $GLOBALS['organizrUser']['username']);
+			return (updateConfig($newItem)) ? true : false;
+			break;
+        default:
+            # code...
+            break;
+    }
+}
 function auth(){
     $debug = false; // CAREFUL WHEN SETTING TO TRUE AS THIS OPENS AUTH UP
     $ban = isset($_GET['ban']) ? strtoupper($_GET['ban']) : "";
@@ -287,6 +366,7 @@ function editImages(){
     }
     return false;
 }
+/*
 function sendEmail($email = null, $username = "Organizr User", $subject, $body, $cc = null, $bcc = null){
 	try {
 		$mail = new PHPMailer(true);
@@ -353,3 +433,4 @@ function sendTestEmail($to, $from, $host, $auth, $username, $password, $type, $p
 	}
 	return false;
 }
+*/

+ 20 - 1
api/functions/static-globals.php

@@ -2,9 +2,28 @@
 
 // ===================================
 // Organizr Version
-$GLOBALS['installedVersion'] = '2.0.0-alpha.125';
+$GLOBALS['installedVersion'] = '2.0.0-alpha.130';
 // ===================================
 // Set GLOBALS from config file
 $GLOBALS['userConfigPath'] = dirname(__DIR__,1).DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php';
 $GLOBALS['defaultConfigPath'] = dirname(__DIR__,1).DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'default.php';
 $GLOBALS['currentTime'] = gmdate("Y-m-d\TH:i:s\Z");
+// Quick function for plugins
+function pluginFiles($type){
+	$files = '';
+	switch ($type) {
+		case 'js':
+			foreach (glob(dirname(__DIR__,1).DIRECTORY_SEPARATOR.'plugins' . DIRECTORY_SEPARATOR . 'js' . DIRECTORY_SEPARATOR . "*.js") as $filename){
+				$files .= '<script src="api/plugins/js/'.basename($filename).'?v='.$GLOBALS['installedVersion'].'"></script>';
+			}
+			break;
+		case 'css':
+			foreach (glob(dirname(__DIR__,1).DIRECTORY_SEPARATOR.'plugins' . DIRECTORY_SEPARATOR . 'css' . DIRECTORY_SEPARATOR . "*.js") as $filename){
+				$files .= '<link href="api/plugins/css/'.basename($filename).$GLOBALS['installedVersion'].'" rel="stylesheet">';
+			}
+			break;
+		default:
+			break;
+	}
+	return $files;
+}

+ 71 - 35
api/index.php

@@ -37,6 +37,55 @@ switch ($function) {
                 break;
         }
         break;
+    case 'v1_settings_plugins':
+        switch ($method) {
+            case 'GET':
+                if(qualifyRequest(1)){
+                    $result['status'] = 'success';
+                    $result['statusText'] = 'success';
+                    $result['data'] = $pageSettingsPlugins;
+                }else{
+                    $result['status'] = 'error';
+                    $result['statusText'] = 'API/Token invalid or not set';
+                    $result['data'] = null;
+                }
+                break;
+            default:
+                $result['status'] = 'error';
+                $result['statusText'] = 'The function requested is not defined for method: '.$method;
+                break;
+        }
+        break;
+    case 'v1_settings_plugins_list':
+        switch ($method) {
+            case 'GET':
+                if(qualifyRequest(1)){
+                    $result['status'] = 'success';
+                    $result['statusText'] = 'success';
+                    $result['data'] = getPlugins();
+                }else{
+                    $result['status'] = 'error';
+                    $result['statusText'] = 'API/Token invalid or not set';
+                    $result['data'] = null;
+                }
+                break;
+            case 'POST':
+                if(qualifyRequest(1)){
+                    $result['status'] = 'success';
+                    $result['statusText'] = 'success';
+                    $result['data'] = editPlugins($_POST);
+                }else{
+                    $result['status'] = 'error';
+                    $result['statusText'] = 'API/Token invalid or not set';
+                    $result['data'] = null;
+                }
+                break;
+            default:
+                $result['status'] = 'error';
+                $result['statusText'] = 'The function requested is not defined for method: '.$method;
+                break;
+        }
+        break;
     case 'v1_settings_settings_logs':
         switch ($method) {
             case 'GET':
@@ -86,6 +135,25 @@ switch ($function) {
                 break;
         }
         break;
+    case 'v1_update_config':
+        switch ($method) {
+            case 'POST':
+                if(qualifyRequest(1)){
+                    $result['status'] = 'success';
+                    $result['statusText'] = 'success';
+                    $result['data'] = updateConfigItem($_POST);
+                }else{
+                    $result['status'] = 'error';
+                    $result['statusText'] = 'API/Token invalid or not set';
+                    $result['data'] = null;
+                }
+                break;
+            default:
+                $result['status'] = 'error';
+                $result['statusText'] = 'The function requested is not defined for method: '.$method;
+                break;
+        }
+        break;
     case 'v1_settings_tab_editor_tabs':
         switch ($method) {
             case 'GET':
@@ -547,42 +615,10 @@ switch ($function) {
         break;
     case 'v1_plugin':
         switch ($method) {
-            case 'GET':
-                if(qualifyRequest(1)){
-                    $result['status'] = 'success';
-                    $result['statusText'] = 'success';
-                    $result['data'] = 'plugin admin';
-                }elseif(qualifyRequest(998)){
-                    $result['status'] = 'success';
-                    $result['statusText'] = 'success';
-                    $result['data'] = 'plugin logged in';
-                }elseif(qualifyRequest(999)){
-                    $result['status'] = 'success';
-                    $result['statusText'] = 'success';
-                    $result['data'] = 'plugin guest';
-                }else{
-                    $result['status'] = 'error';
-                    $result['statusText'] = 'API/Token invalid or not set';
-                    $result['data'] = null;
-                }
-                break;
             case 'POST':
-                if(qualifyRequest(1)){
-                    $result['status'] = 'success';
-                    $result['statusText'] = 'success';
-                    $result['data'] = 'plugin admin';
-                }elseif(qualifyRequest(998)){
-                    $result['status'] = 'success';
-                    $result['statusText'] = 'success';
-                    $result['data'] = 'plugin logged in';
-                }elseif(qualifyRequest(999)){
-                    $result['status'] = 'success';
-                    $result['statusText'] = 'success';
-                    $result['data'] = 'plugin guest';
-                }else{
-                    $result['status'] = 'error';
-                    $result['statusText'] = 'API/Token invalid or not set';
-                    $result['data'] = null;
+                // Include all plugin api Calls
+                foreach (glob(__DIR__.DIRECTORY_SEPARATOR.'plugins' . DIRECTORY_SEPARATOR . 'api' . DIRECTORY_SEPARATOR . "*.php") as $filename){
+                    require_once $filename;
                 }
                 break;
             default:

+ 8 - 0
api/pages/settings-plugins.php

@@ -0,0 +1,8 @@
+<?php
+
+$pageSettingsPlugins = '
+<script>
+	buildPlugins();
+</script>
+<div id="main-plugin-area"></div>
+';

+ 1 - 1
api/pages/settings.php

@@ -34,7 +34,7 @@ $pageSettings = '
                         <li onclick="changeSettingsMenu(\'Settings::Customize\')"><a href="#settings-main-customize" class="sticon ti-paint-bucket"><span lang="en">Customize</span></a></li>
                         <li onclick="changeSettingsMenu(\'Settings::User Management\')"><a href="#settings-main-user-management" class="sticon ti-user"><span lang="en">User Management</span></a></li>
                         <li onclick="changeSettingsMenu(\'Settings::Image Manager\');loadSettingsPage(\'api/?v1/settings/image/manager/view\',\'#settings-image-manager-view\',\'Image Viewer\');"><a href="#settings-main-image-manager" class="sticon ti-image"><span lang="en">Image Manager</span></a></li>
-    					<li onclick="changeSettingsMenu(\'Settings::Plugins\')"><a href="#settings-main-plugins" class="sticon ti-plug"><span lang="en">Plugins</span></a></li>
+    					<li onclick="changeSettingsMenu(\'Settings::Plugins\');loadSettingsPage(\'api/?v1/settings/plugins\',\'#settings-main-plugins\',\'Plugins\');"><a href="#settings-main-plugins" class="sticon ti-plug"><span lang="en">Plugins</span></a></li>
                         <li onclick="changeSettingsMenu(\'Settings::System Settings\')"><a href="#settings-main-system-settings" class="sticon ti-settings"><span lang="en">System Settings</span></a></li>
                     </ul>
                 </nav>

+ 30 - 0
api/plugins/api/php-mailer.php

@@ -0,0 +1,30 @@
+<?php
+if(isset($_POST['data']['plugin'])){
+    switch ($_POST['data']['plugin']) {
+        case 'PHPMailer/settings/get':
+            if(qualifyRequest(1)){
+                $result['status'] = 'success';
+                $result['statusText'] = 'success';
+                $result['data'] = phpmGetSettings();
+            }else{
+                $result['status'] = 'error';
+                $result['statusText'] = 'API/Token invalid or not set';
+                $result['data'] = null;
+            }
+            break;
+        case 'PHPMailer/send/test':
+            if(qualifyRequest(1)){
+                $result['status'] = 'success';
+                $result['statusText'] = 'success';
+                $result['data'] = phpmSendTestEmail();
+            }else{
+                $result['status'] = 'error';
+                $result['statusText'] = 'API/Token invalid or not set';
+                $result['data'] = null;
+            }
+            break;
+        default:
+            //DO NOTHING!!
+            break;
+    }
+}

+ 12 - 0
api/plugins/config/php-mailer.php

@@ -0,0 +1,12 @@
+<?php
+return array(
+    'PHPMAILER-enabled' => false,
+    'PHPMAILER-smtpHost' => '',
+    'PHPMAILER-smtpHostPort' => '',
+    'PHPMAILER-smtpHostAuth' => true,
+    'PHPMAILER-smtpHostUsername' => '',
+    'PHPMAILER-smtpHostPassword' => '',
+    'PHPMAILER-smtpHostSenderName' => 'Organizr',
+    'PHPMAILER-smtpHostSenderEmail' => 'no-reply@Organizr.tld',
+    'PHPMAILER-smtpHostType' => 'tls'
+);

+ 110 - 0
api/plugins/js/php-mailer.js

@@ -0,0 +1,110 @@
+/* PHP MAILER JS FILE */
+/*
+$(document).on('click', '#PHPMAILER-settings-button', function() {
+	var post = {
+        plugin:'PHPMailer/settings/get', // used for switch case in your API call
+        api:'api/?v1/plugin', // API Endpoint will always be this for custom plugin API calls
+        name:$(this).attr('data-plugin-name'),
+        configName:$(this).attr('data-config-name'),
+        messageTitle:'', // Send succees message title (top line)
+        messageBody:'Disabled '+$(this).attr('data-plugin-name'), // Send succees message body (bottom line)
+        error:'Organizr Function: API Connection Failed' // conole error message
+    };
+	var callbacks = $.Callbacks(); // init callbacks var
+    //callbacks.add(  ); // add function to callback to be fired after API call
+    //settingsAPI(post,callbacks); // exec API call
+    //ajaxloader(".content-wrap","in");
+    //setTimeout(function(){ buildPlugins();ajaxloader(); }, 3000);
+});
+*/
+
+// FUNCTIONS
+function phpmBuildSettingsItems(array){
+    if (Array.isArray(array)) {
+        var preRow = `
+            <!-- FORM GROUP -->
+            <h3 class="box-title" lang="en">Mail Settings</h3>
+            <hr class="m-t-0 m-b-40">
+            <div class="row">
+        `;
+        var mailItems = preRow;
+        $.each(array, function(i,v) {
+            mailItems += `
+                <!-- INPUT BOX -->
+                <div class="col-md-6 p-b-10">
+                    <div class="form-group">
+                        <label class="control-label col-md-3" lang="en">`+v.label+`</label>
+                        <div class="col-md-9">
+                            `+buildFormItem(v)+`
+                        </div>
+                    </div>
+                </div>
+                <!--/ INPUT BOX -->
+            `;
+        });
+        mailItems += '</div>';
+    }
+
+    return mailItems;
+}
+
+// EVENTS and LISTENERS
+// CHANGE CUSTOMIZE Options
+$(document).on('change asColorPicker::close', '#PHPMAILER-settings-page :input', function(e) {
+    switch ($(this).attr('type')) {
+        case 'switch':
+        case 'checkbox':
+            var value = $(this).prop("checked") ? true : false;
+            break;
+        default:
+            var value = $(this).val();
+    }
+	var post = {
+        api:'api/?v1/update/config',
+        name:$(this).attr("name"),
+        type:$(this).attr("data-type"),
+        value:value,
+        messageTitle:'',
+        messageBody:'Updated Value for '+$(this).parent().parent().find('label').text(),
+        error:'Organizr Function: API Connection Failed'
+    };
+    //console.log(post);
+    //$('#customize-appearance-reload').removeClass('hidden');
+	var callbacks = $.Callbacks();
+    //callbacks.add( buildCustomizeAppearance );
+    settingsAPI(post,callbacks);
+
+});
+$(document).on('click', '#PHPMAILER-settings-button', function() {
+    var post = {
+        plugin:'PHPMailer/settings/get', // used for switch case in your API call
+    };
+    ajaxloader(".content-wrap","in");
+    organizrAPI('POST','api/?v1/plugin',post).success(function(data) {
+        var response = JSON.parse(data);
+        $('#PHPMAILER-settings-items').html(phpmBuildSettingsItems(response.data));
+    }).fail(function(xhr) {
+        console.error("Organizr Function: API Connection Failed");
+    });
+    ajaxloader();
+});
+// SEND TEST EMAIL
+$(document).on('click', '.phpmSendTestEmail', function() {
+    var post = {
+        plugin:'PHPMailer/send/test', // used for switch case in your API call
+    };
+    ajaxloader(".content-wrap","in");
+    organizrAPI('POST','api/?v1/plugin',post).success(function(data) {
+        var response = JSON.parse(data);
+        if(response.data == true){
+            messageSingle('',window.lang.translate('Email Test Successful'),'bottom-right','#FFF','success','5000');
+        }else{
+            messageSingle('',response.data,'bottom-right','#FFF','error','5000');
+            console.error(response.data);
+        }
+
+    }).fail(function(xhr) {
+        console.error("Organizr Function: API Connection Failed");
+    });
+    ajaxloader();
+});

+ 138 - 0
api/plugins/php-mailer.php

@@ -0,0 +1,138 @@
+<?php
+
+// PLUGIN INFORMATION
+$GLOBALS['plugins'][]['PHP Mailer'] = array( // Plugin Name
+    'name'=>'PHP Mailer', // Plugin Name
+	'author'=>'PHP Mailer', // Who wrote the plugin
+    'category'=>'Mail', // One to Two Word Description
+    'link'=>'https://github.com/PHPMailer/PHPMailer', // Link to plugin info
+    //'fileName'=>'php-mailer.php',
+	//'configFile'=>'php-mailer.php',
+	//'apiFile'=>'php-mailer.php',
+	'idPrefix'=>'PHPMAILER', // html element id prefix
+	'configPrefix'=>'PHPMAILER', // config file prefix for array items without the hypen
+    'version'=>'1.0.0', // SemVer of plugin
+    'image'=>'plugins/images/php-mailer.png', // 1:1 non transparent image for plugin
+	'settings'=>true, // does plugin need a settings page? true or false
+    'homepage'=>false // Is plugin for use on homepage? true or false
+);
+// INCLUDE/REQUIRE FILES
+
+// PLUGIN FUNCTIONS
+function phpmSendTestEmail(){
+	try {
+		$mail = new PHPMailer\PHPMailer\PHPMailer(true);
+		$mail->isSMTP();
+		$mail->Host = $GLOBALS['PHPMAILER-smtpHost'];
+		$mail->SMTPAuth = $GLOBALS['PHPMAILER-smtpHostAuth'];
+		$mail->Username = $GLOBALS['PHPMAILER-smtpHostUsername'];
+		$mail->Password = decrypt($GLOBALS['PHPMAILER-smtpHostPassword']);
+		$mail->SMTPSecure = $GLOBALS['PHPMAILER-smtpHostType'];
+		$mail->Port = $GLOBALS['PHPMAILER-smtpHostPort'];
+		$mail->setFrom($GLOBALS['PHPMAILER-smtpHostSenderEmail'], $GLOBALS['PHPMAILER-smtpHostSenderName']);
+		$mail->addReplyTo($GLOBALS['PHPMAILER-smtpHostSenderEmail'], $GLOBALS['PHPMAILER-smtpHostSenderName']);
+		$mail->isHTML(true);
+		$mail->addAddress($GLOBALS['organizrUser']['email'], $GLOBALS['organizrUser']['username']);
+		$mail->Subject = "Organizr Test E-Mail";
+		$mail->Body    = "This was just a test!";
+		$mail->send();
+		writeLog('success', 'Mail Function -  E-Mail Test Sent', $GLOBALS['organizrUser']['username']);
+		return true;
+	} catch (PHPMailer\PHPMailer\Exception $e) {
+		writeLog('error', 'Mail Function -  E-Mail Test Failed['.$mail->ErrorInfo.']', $GLOBALS['organizrUser']['username']);
+		return $e->errorMessage();
+	}
+	return false;
+}
+/* GET PHPMAILER SETTINGS */
+function phpmGetSettings(){
+	/*$like = 'PHPMAILER';
+	 return array_filter_key(configLazy(), function ($item) use ($like) {
+		if (stripos($item, $like) !== false) {
+			return true;
+		}
+		return false;
+	});*/
+	/*
+	'PHPMAILER-enabled' => false,
+    'PHPMAILER-smtpHost' => '',
+    'PHPMAILER-smtpHostPort' => '',
+    'PHPMAILER-smtpHostAuth' => true,
+    'PHPMAILER-smtpHostUsername' => '',
+    'PHPMAILER-smtpHostPassword' => '',
+    'PHPMAILER-smtpHostSenderName' => 'Organizr',
+    'PHPMAILER-smtpHostSenderEmail' => 'no-reply@Organizr.tld',
+    'PHPMAILER-smtpHostType' => 'tls'
+	*/
+	return array(
+		array(
+			'type' => 'input',
+			'name' => 'PHPMAILER-smtpHost',
+			'label' => 'SMTP Host',
+			'value' => $GLOBALS['PHPMAILER-smtpHost']
+		),
+		array(
+			'type' => 'input',
+			'name' => 'PHPMAILER-smtpHostPort',
+			'label' => 'SMTP Port',
+			'value' => $GLOBALS['PHPMAILER-smtpHostPort']
+		),
+		array(
+			'type' => 'input',
+			'name' => 'PHPMAILER-smtpHostUsername',
+			'label' => 'Username',
+			'value' => $GLOBALS['PHPMAILER-smtpHostUsername']
+		),
+		array(
+			'type' => 'password',
+			'name' => 'PHPMAILER-smtpHostPassword',
+			'label' => 'Password',
+			'value' => $GLOBALS['PHPMAILER-smtpHostPassword']
+		),
+		array(
+			'type' => 'input',
+			'name' => 'PHPMAILER-smtpHostSenderName',
+			'label' => 'Sender Name',
+			'value' => $GLOBALS['PHPMAILER-smtpHostSenderName']
+		),
+		array(
+			'type' => 'input',
+			'name' => 'PHPMAILER-smtpHostSenderEmail',
+			'label' => 'Sender Email',
+			'value' => $GLOBALS['PHPMAILER-smtpHostSenderEmail']
+		),
+		array(
+			'type' => 'select',
+			'name' => 'PHPMAILER-smtpHostType',
+			'label' => 'Authentication Type',
+			'value' => $GLOBALS['PHPMAILER-smtpHostType'],
+			'options' => array(
+				array(
+					'name'=>'tls',
+					'value'=>'tls'
+				),
+				array(
+					'name'=>'ssl',
+					'value'=>'ssl'
+				),
+				array(
+					'name'=>'off',
+					'value'=>'false'
+				)
+			)
+		),
+		array(
+			'type' => 'switch',
+			'name' => 'PHPMAILER-smtpHostAuth',
+			'label' => 'Authentication',
+			'value' => $GLOBALS['PHPMAILER-smtpHostAuth']
+		),
+		array(
+			'type' => 'button',
+			'label' => 'Send Test',
+			'class' => 'phpmSendTestEmail',
+			'icon' => 'fa fa-paper-plane',
+			'text' => 'Send'
+		)
+	);
+}

+ 5 - 1
css/colors/blue-dark.css

@@ -333,7 +333,7 @@ a.mytooltip {
   background: #1f1f1f;
   padding: 20px 30px;
   text-align: left;
-  max-width: 650px;
+  max-width: 90%;
   margin: 40px auto;
   position: relative;
   border: 1px solid #2cabe4;
@@ -416,6 +416,10 @@ body.stop-scrolling {
 .p-5{
   padding:5px!important
 }
+.el-element-overlay .el-card-item .el-overlay-1 .el-info>li a:hover {
+	background: #707cd2;
+	border-color: #707cd2;
+}
 .table-hover>tbody>tr:hover, .table-striped>tbody>tr:nth-of-type(odd), .table>tbody>tr.active>td, .table>tbody>tr.active>th, .table>tbody>tr>td.active, .table>tbody>tr>th.active, .table>tfoot>tr.active>td, .table>tfoot>tr.active>th, .table>tfoot>tr>td.active, .table>tfoot>tr>th.active, .table>thead>tr.active>td, .table>thead>tr.active>th, .table>thead>tr>td.active, .table>thead>tr>th.active {
   background-color: #1f1f1f!important;
 }

+ 2 - 0
index.php

@@ -23,6 +23,7 @@
 	<link href="plugins/bower_components/dropzone-master/dist/dropzone.css" rel="stylesheet" type="text/css" />
 	<link href="css/style.css?v=<?php echo $GLOBALS['installedVersion']; ?>" rel="stylesheet">
 	<link href="css/colors/blue-dark.css?v=<?php echo $GLOBALS['installedVersion']; ?>" rel="stylesheet">
+	<?php echo pluginFiles('css'); ?>
 	<style type="text/css" id="user-appearance"></style>
 	<link id="theme" rel="stylesheet">
 	<!--[if lt IE 9]>
@@ -128,5 +129,6 @@
 	<script src="plugins/bower_components/dropzone-master/dist/dropzone.js"></script>
 	<script src="js/functions.js?v=<?php echo $GLOBALS['installedVersion']; ?>"></script>
 	<script src="js/custom.js?v=<?php echo $GLOBALS['installedVersion']; ?>"></script>
+	<?php echo pluginFiles('js'); ?>
 </body>
 </html>

+ 42 - 1
js/custom.js

@@ -77,6 +77,9 @@ function pageLoad(){
     //Start Organizr
     $(function () {
         $('#side-menu').metisMenu();
+        if($('#preloader:visible').length == 1){
+            $("#preloader").fadeOut();
+        }
         lazyload();
     });
     $(".colorpicker").asColorPicker({
@@ -983,7 +986,7 @@ $(document).on('change asColorPicker::close', '#customize-appearance-form :input
         name:$(this).attr("name"),
         value:value,
         messageTitle:'',
-        messageBody:'Update Value for '+$(this).parent().parent().find('label').text(),
+        messageBody:'Updated Value for '+$(this).parent().parent().find('label').text(),
         error:'Organizr Function: API Connection Failed'
     };
     console.log(post);
@@ -1027,6 +1030,44 @@ $(document).on("click", ".deleteImage", function () {
 $(document).on("click", ".reload", function () {
     location.reload();
 });
+// ENABLE PLUGIN
+$(document).on('click', '.enablePlugin', function() {
+	var post = {
+        action:'enable',
+        api:'api/?v1/settings/plugins/list',
+        name:$(this).attr('data-plugin-name'),
+        configName:$(this).attr('data-config-name'),
+        messageTitle:'',
+        messageBody:'Enabling '+$(this).attr('data-plugin-name'),
+        error:'Organizr Function: API Connection Failed'
+    };
+    //$('#customize-appearance-reload').removeClass('hidden');
+	var callbacks = $.Callbacks();
+    //callbacks.add( buildCustomizeAppearance );
+    settingsAPI(post,callbacks);
+    ajaxloader(".content-wrap","in");
+    setTimeout(function(){ buildPlugins();ajaxloader(); }, 3000);
+
+});
+// DISABLE PLUGIN
+$(document).on('click', '.disablePlugin', function() {
+	var post = {
+        action:'disable',
+        api:'api/?v1/settings/plugins/list',
+        name:$(this).attr('data-plugin-name'),
+        configName:$(this).attr('data-config-name'),
+        messageTitle:'',
+        messageBody:'Disabling '+$(this).attr('data-plugin-name'),
+        error:'Organizr Function: API Connection Failed'
+    };
+    //$('#customize-appearance-reload').removeClass('hidden');
+	var callbacks = $.Callbacks();
+    //callbacks.add( buildCustomizeAppearance );
+    settingsAPI(post,callbacks);
+    ajaxloader(".content-wrap","in");
+    setTimeout(function(){ buildPlugins();ajaxloader(); }, 3000);
+
+});
 /* ===== Open-Close Right Sidebar ===== */
 
 $(document).on("click", ".right-side-toggle", function () {

+ 127 - 6
js/functions.js

@@ -1,4 +1,3 @@
-/* TEST SHIT */
 // Create language switcher instance
 var lang = new Lang();
 loadLanguageList();
@@ -488,26 +487,147 @@ function hasValue(test){
 /* BUILD FUNCTIONS */
 /* END BUILD FUNCTIONS */
 /* ORGANIZR API FUNCTIONS */
+function selectOptions(options, active){
+	var selectOptions = '';
+	$.each(options, function(i,v) {
+		console.log(active);
+		var selected = (active.toString() == v.value) ? 'selected' : '';
+		selectOptions += '<option '+selected+' value="'+v.value+'">'+v.name+'</option>';
+	});
+	return selectOptions;
+}
 function buildFormItem(item){
 	var placeholder = (item.placeholder) ? ' placeholder="'+item.placeholder+'"' : '';
 	var id = (item.id) ? ' id="'+item.placeholder+'"' : '';
+	var type = (item.type) ? ' data-type="'+item.type+'"' : '';
 	var value = (item.value) ? ' value="'+item.value+'"' : '';
 	var name = (item.name) ? ' name="'+item.name+'"' : '';
 	var extraClass = (item.class) ? ' '+item.class : '';
+	var icon = (item.icon) ? ' '+item.icon : '';
+	var text = (item.text) ? ' '+item.text : '';
 	var disabled = (item.disabled) ? ' disabled' : '';
 	//+tof(item.value,'c')+`
 	switch (item.type) {
 		case 'input':
-			return '<input data-changed="false" lang=en" type="text" class="form-control'+extraClass+'"'+placeholder+value+id+name+disabled+' />';
+			return '<input data-changed="false" lang=en" type="text" class="form-control'+extraClass+'"'+placeholder+value+id+name+disabled+type+' />';
+			break;
+		case 'password':
+			return '<input data-changed="false" lang=en" type="password" class="form-control'+extraClass+'"'+placeholder+value+id+name+disabled+type+' />';
+			break;
+		case 'hidden':
+			return '<input data-changed="false" lang=en" type="hidden" class="form-control'+extraClass+'"'+placeholder+value+id+name+disabled+type+' />';
+			break;
+		case 'select':
+			return '<select class="form-control'+extraClass+'"'+placeholder+value+id+name+disabled+type+'>'+selectOptions(item.options, item.value)+'</select>';
 			break;
 		case 'switch':
 		case 'checkbox':
-			return '<input data-changed="false" type="checkbox" class="js-switch'+extraClass+'" data-size="small" data-color="#99d683" data-secondary-color="#f96262"'+name+value+tof(item.value,'c')+id+disabled+' /><input data-changed="false" type="hidden"'+name+'value="false">';
+			return '<input data-changed="false" type="checkbox" class="js-switch'+extraClass+'" data-size="small" data-color="#99d683" data-secondary-color="#f96262"'+name+value+tof(item.value,'c')+id+disabled+type+' /><input data-changed="false" type="hidden"'+name+'value="false">';
+			break;
+		case 'button':
+			return '<button class="btn btn-sm btn-success btn-rounded waves-effect waves-light b-none'+extraClass+'" type="button"><span class="btn-label"><i class="'+icon+'"></i></span><span lang="en">'+text+'</span></button>';
 			break;
 		default:
 			return false;
 	}
 }
+function buildPluginsItem(array){
+	var activePlugins = '';
+	var inactivePlugins = '';
+	$.each(array, function(i,v) {
+		var settingsPage = (v.settings == true) ? `
+		<!-- Plugin Settings Page -->
+		<form id="`+v.idPrefix+`-settings-page" class="mfp-hide white-popup-block mfp-with-anim">
+			<h1 lang="en">`+v.name+` Settings</h1>
+			<fieldset id="`+v.idPrefix+`-settings-items" style="border:0;"></fieldset>
+			<div class="clearfix"></div>
+		</form>
+		` : '';
+		var href = (v.settings == true) ? '#'+v.idPrefix+'-settings-page' : 'javascript:void(0);';
+		if(v.enabled == true){
+			var activeToggle = `<li><a class="btn default btn-outline disablePlugin" href="javascript:void(0);" data-plugin-name="`+v.name+`" data-config-prefix="`+v.configPrefix+`" data-config-name="`+v.configPrefix+`-enabled"><i class="ti-power-off fa-2x"></i></a></li>`;
+			var settings = `<li><a class="btn default btn-outline popup-with-form" href="`+href+`" data-effect="mfp-3d-unfold"data-plugin-name="`+v.name+`" id="`+v.idPrefix+`-settings-button" data-config-prefix="`+v.configPrefix+`"><i class="ti-panel fa-2x"></i></a></li>`;
+		}else{
+			var activeToggle = `<li><a class="btn default btn-outline enablePlugin" href="javascript:void(0);" data-plugin-name="`+v.name+`" data-config-prefix="`+v.configPrefix+`" data-config-name="`+v.configPrefix+`-enabled"><i class="ti-plug fa-2x"></i></a></li>`;
+			var settings = '';
+		}
+		var plugin = `
+		<div class="col-lg-2 col-md-2 col-sm-4 col-xs-4">
+			<div class="white-box m-0">
+				<div class="el-card-item p-0">
+					<div class="el-card-avatar el-overlay-1 m-0"> <img class="lazyload" data-src="`+v.image+`">
+						<div class="el-overlay">
+							<ul class="el-info">
+								`+settings+activeToggle+`
+							</ul>
+						</div>
+					</div>
+					<div class="el-card-content">
+						<h3 class="box-title">`+v.name+`</h3>
+						<small class="elip text-uppercase p-b-10">`+v.category+`</small>
+					</div>
+				</div>
+			</div>
+		</div>
+		`;
+		if(v.enabled == true){
+			activePlugins += plugin+settingsPage;
+		}else{
+			inactivePlugins += plugin+settingsPage;
+		}
+	});
+	activePlugins = (activePlugins.length !== 0) ? activePlugins : '<h2 class="text-center" lang="en">Nothing Active</h2>';
+	inactivePlugins = (inactivePlugins.length !== 0) ? inactivePlugins : '<h2 class="text-center" lang="en">Everything Active</h2>';
+	var panes = `
+	<ul class="nav customtab2 nav-tabs" role="tablist">
+		<li onclick="changeSettingsMenu('Settings::Plugins::Active')" role="presentation" class="active"><a href="#settings-plugins-active" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="false"><span class="visible-xs"><i class="ti-layout-tab-v"></i></span><span class="hidden-xs" lang="en"> Active</span></a>
+		</li>
+		<li onclick="changeSettingsMenu('Settings::Plugins::Inactive')" role="presentation" class=""><a href="#settings-plugins-inactive" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="false"><span class="visible-xs"><i class="ti-layout-list-thumb"></i></span><span class="hidden-xs" lang="en"> Inactive</span></a>
+		</li>
+	</ul>
+	<!-- Tab panes -->
+	<div class="tab-content">
+		<div role="tabpanel" class="tab-pane fade in active" id="settings-plugins-active">
+			<div class="panel bg-theme-dark panel-info">
+				<div class="panel-heading">
+					<span lang="en">Active Plugins</span>
+				</div>
+				<div class="panel-wrapper collapse in" aria-expanded="true">
+					<div class="panel-body bg-theme-dark">
+						<div class="row el-element-overlay m-b-40">`+activePlugins+`</div>
+					</div>
+				</div>
+			</div>
+			<div class="clearfix"></div>
+		</div>
+		<div role="tabpanel" class="tab-pane fade" id="settings-plugins-inactive">
+			<div class="panel bg-theme-dark panel-info">
+				<div class="panel-heading">
+					<span lang="en">Inactive Plugins</span>
+				</div>
+				<div class="panel-wrapper collapse in" aria-expanded="true">
+					<div class="panel-body bg-theme-dark">
+						<div class="row el-element-overlay m-b-40">`+inactivePlugins+`</div>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+
+	`;
+
+	return panes;
+}
+function buildPlugins(){
+	ajaxloader(".content-wrap","in");
+	organizrAPI('GET','api/?v1/settings/plugins/list').success(function(data) {
+		var response = JSON.parse(data);
+		$('#main-plugin-area').html(buildPluginsItem(response.data));
+	}).fail(function(xhr) {
+		console.error("Organizr Function: API Connection Failed");
+	});
+	ajaxloader();
+}
 function buildCustomizeAppearanceItem(array){
 	if (Array.isArray(array.config)) {
 		var preRowConfig = `
@@ -633,7 +753,7 @@ function settingsAPI(post, callbacks=null){
 		var response = JSON.parse(data);
 		console.log(response);
 		message(post.messageTitle,post.messageBody,"bottom-right","#FFF","success","5000");
-		if(callbacks){ callbacks.fire(); console.log('fired'); }
+		if(callbacks){ callbacks.fire(); }
 	}).fail(function(xhr) {
 		console.error(post.error);
 	});
@@ -1161,8 +1281,6 @@ function updateCheck(){
 		if(latest !== currentVersion){
 			console.log('Update Function: Update to '+latest+' is available');
 			message(window.lang.translate('Update Available'),latest+' '+window.lang.translate('is available, goto')+' <a href="javascript:void(0)" onclick="tabActions(event,\'Settings\',0);$.toast().reset(\'all\');"><span lang="en">Update Tab</span></a>','bottom-right','#FFF','update','60000');
-		}else{
-			console.log('Update Function: '+latest+' is the newest version');
 		}
 		$('#githubVersions').html(buildVersion(reverseObject(json)));
 	}).fail(function(xhr) {
@@ -1392,6 +1510,9 @@ function tof(string,type){
 		case 'q':
 			return (result == "0") ? ('yes') : ((result == "1") ? ('no') : (string));
 			break;
+		case 'string':
+			return string.toString();
+			break;
 		default:
 			return (result == "0") ? ("false") : ((result == "1") ? ("true") : (string));
 	}

+ 7 - 0
js/version.json

@@ -33,5 +33,12 @@
         "new": "Added Image Manager",
         "fixed": "Color Selector|Wizard Preloader",
         "notes": "This is alpha - expect bugs|Please report bugs in GitHub issues page"
+    },
+	"2.0.0-alpha.130": {
+        "date":"2018-01-10 23:00",
+        "title": "Plugin Framework",
+        "new": "Plugin Framework nearly complete|Added Mail Plugin",
+        "fixed": "",
+        "notes": "This is alpha - expect bugs|Please report bugs in GitHub issues page"
     }
 }

BIN=BIN
plugins/images/php-mailer.png