Browse Source

Added Pi-hole homepage item

Henry Whitaker 6 năm trước cách đây
mục cha
commit
8fa3865974

+ 6 - 1
api/config/default.php

@@ -162,6 +162,7 @@ return array(
 	'homepageOrderhealthchecks' => '17',
 	'homepageOrderjdownloader' => '18',
 	'homepageOrderunifi' => '19',
+	'homepageOrderPihole' => '20',
 	'homepageShowStreamNames' => false,
 	'homepageShowStreamNamesAuth' => '1',
 	'homepageStreamRefresh' => '60000',
@@ -262,5 +263,9 @@ return array(
 	'enableLocalAddressForward' => false,
 	'performanceDisableIconDropdown' => false,
 	'performanceDisableImageDropdown' => false,
-	'traefikAuthEnable' => false
+	'traefikAuthEnable' => false,
+	'homepagePiholeEnabled' => 'false',
+	'homepagePiholeAuth' => '1',
+	'homepagePiholeRefresh' => '10000',
+	'homepagePiholeCombine' => false,
 );

+ 27 - 0
api/functions/homepage-connect-functions.php

@@ -60,6 +60,9 @@ function homepageConnect($array)
 		case 'getUnifi':
 			return unifiConnect();
 			break;
+		case 'getPihole':
+			return getPihole();
+			break;
 		default:
 			# code...
 			break;
@@ -113,6 +116,30 @@ function getHealthChecks($tags = null)
 	return false;
 }
 
+function getPihole()
+{
+	if ($GLOBALS['homepagePiholeEnabled'] && !empty($GLOBALS['piholeURL'])) {
+		$api = array();
+		$urls = explode(',', $GLOBALS['piholeURL']);
+		foreach($urls as $url) {
+			$url = $url . '/api.php?';
+			try {
+				$response = Requests::get($url, [], []);
+				if ($response->success) {
+					$piholeResults = json_decode($response->body, true);
+					$api['data'][substr($url, 7, -16)] = $piholeResults;
+				}
+			} catch (Requests_Exception $e) {
+				writeLog('error', 'Pi-hole Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
+			};
+		}
+		$api['options']['combine'] = $GLOBALS['homepagePiholeCombine'];
+		$api = isset($api) ? $api : false;
+		return $api;
+	}
+	return false;
+}
+
 function streamType($value)
 {
 	if ($value == "transcode" || $value == "Transcode") {

+ 55 - 1
api/functions/homepage-functions.php

@@ -22,6 +22,7 @@ function homepageOrder()
 		"homepageOrderdownloader" => $GLOBALS['homepageOrderdownloader'],
 		"homepageOrderhealthchecks" => $GLOBALS['homepageOrderhealthchecks'],
 		"homepageOrderunifi" => $GLOBALS['homepageOrderunifi'],
+		"homepageOrderPihole" => $GLOBALS['homepageOrderPihole'],
 	);
 	asort($homepageOrder);
 	return $homepageOrder;
@@ -331,6 +332,17 @@ function buildHomepageItem($homepageItem)
 				';
 			}
 			break;
+		case 'homepageOrderPihole':
+			if ($GLOBALS['homepagePiholeEnabled']) {
+				$item .= '<div class="white-box"><h2 class="text-center" lang="en">Loading Pi-hole Stats...</h2></div>';
+				$item .= '
+				<script>
+				// Pi-hole Stats
+				homepagePihole();
+				// End Pi-hole Stats
+				</script>
+				';
+			}
 		default:
 			# code...
 			break;
@@ -2488,7 +2500,49 @@ function getHomepageList()
 					),
 				)
 			)
-		)
+		),
+		array(
+			'name' => 'Pi-hole',
+			'enabled' => true,
+			'image' => 'plugins/images/tabs/pihole.png',
+			'category' => 'Monitor',
+			'settings' => array(
+				'Enable' => array(
+					array(
+						'type' => 'switch',
+						'name' => 'homepagePiholeEnabled',
+						'label' => 'Enable',
+						'value' => $GLOBALS['homepagePiholeEnabled']
+					),
+					array(
+						'type' => 'select',
+						'name' => 'homepagePiholeAuth',
+						'label' => 'Minimum Authentication',
+						'value' => $GLOBALS['homepagePiholeAuth'],
+						'options' => $groups
+					)
+				),
+				'Connection' => array(
+					array(
+						'type' => 'input',
+						'name' => 'piholeURL',
+						'label' => 'URL',
+						'value' => $GLOBALS['piholeURL'],
+						'help' => 'Please make sure to use local IP address and port and to include \'/admin/\' at the end of the URL. You can add multiple Pi-holes by comma separating the URLs.',
+						'placeholder' => 'http(s)://hostname:port/admin/'
+					),
+				),
+				'Misc' => array(
+					array(
+						'type' => 'switch',
+						'name' => 'homepagePiholeCombine',
+						'label' => 'Combine stat cards',
+						'value' => $GLOBALS['homepagePiholeCombine'],
+						'help' => 'This controls whether to combine the stats for multiple piholes into 1 card.',
+					),
+				),
+			)
+			),
 	);
 }
 

+ 189 - 0
js/functions.js

@@ -5678,6 +5678,23 @@ function buildHealthChecks(array){
 	<div class="clearfix"></div>
 	` : '';
 }
+function buildPihole(array){
+    if(array === false){ return ''; }
+    return (array) ? `
+    <div id="allPihole">
+		<div class="el-element-overlay row">
+		    <div class="col-md-12">
+		        <h4 class="pull-left homepage-element-title"><span lang="en">Pi-hole</span></h4>
+		        <hr class="hidden-xs ml-2">
+		    </div>
+			<div class="clearfix"></div>
+		    <div class="piholeCards col-sm-12">
+			    `+buildPiholeItem(array)+`
+			</div>
+		</div>
+	</div>
+    ` : 'hello';
+}
 function buildUnifi(array){
     if(array === false){ return ''; }
     var items = (typeof array.content.unifi.data !== 'undefined') ? array.content.unifi.data.length : false;
@@ -5859,6 +5876,178 @@ function buildHealthChecksItem(array){
     });
     return checks;
 }
+function buildPiholeItem(array){
+    var stats = `
+    <style>
+    .bg-green {
+        background-color: #00a65a !important;
+    }
+    
+    .bg-aqua {
+        background-color: #00c0ef!important;
+    }
+    
+    .bg-yellow {
+        background-color: #f39c12!important;
+    }
+    
+    .bg-red {
+        background-color: #dd4b39!important;
+    }
+    
+    .pihole-stat {
+        color: #fff !important;
+    }
+    
+    .pihole-stat .card-body h3 {
+        font-size: 38px;
+        font-weight: 700;
+    }
+
+    .pihole-stat .card-body i {
+        font-size: 5em;
+        float: right;
+        color: #ffffff6b;
+    }
+
+    .inline-block {
+        display: inline-block;
+    }
+    </style>
+    `;
+    var length = Object.keys(array['data']).length;
+    var combine = array['options']['combine'];
+    var totalQueries = function(data) {
+        var card = `
+        <div class="col-lg-3 col-md-6 col-sm-6 col-xs-12">
+            <div class="card text-white mb-3 pihole-stat bg-green">
+                <div class="card-body">
+                    <div class="inline-block">
+                        <p>Total queries</p>`;
+        for(var key in data) {
+            var e = data[key];
+            card += `<h3>`+e['ads_blocked_today'].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")+`</h3>`;
+        };
+        card += `
+                    </div>
+                    <i class="fa fa-globe inline-block" aria-hidden="true"></i>
+                </div>
+            </div>
+        </div>
+        `
+        return card;
+    };
+    var totalBlocked = function(data) {
+        var card = `
+        <div class="col-lg-3 col-md-6 col-sm-6 col-xs-12">
+            <div class="card bg-inverse text-white mb-3 pihole-stat bg-aqua">
+                <div class="card-body">
+                    <div class="inline-block">
+                        <p>Queries Blocked</p>`;
+        for(var key in data) {
+            var e = data[key];
+            card += `<h3>`+e['ads_blocked_today'].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")+`</h3>`;
+        };
+        card += `
+                    </div>
+                    <i class="fa fa-hand-paper-o inline-block" aria-hidden="true"></i>
+                </div>
+            </div>
+        </div>
+        `
+        return card;
+    };
+    var percentBlocked = function(data) {
+        var card = `
+        <div class="col-lg-3 col-md-6 col-sm-6 col-xs-12">
+            <div class="card bg-inverse text-white mb-3 pihole-stat bg-yellow">
+                <div class="card-body">
+                    <div class="inline-block">
+                        <p>Percent Blocked</p>`;
+        for(var key in data) {
+            var e = data[key];
+            card += `<h3>`+e['ads_percentage_today'].toFixed(1)+`%</h3>`
+        };
+        card += `
+                    </div>
+                    <i class="fa fa-pie-chart inline-block" aria-hidden="true"></i>
+                </div>
+            </div>
+        </div>
+        `
+        return card;
+    };
+    var domainsBlocked = function(data) {
+        var card = `
+        <div class="col-lg-3 col-md-6 col-sm-6 col-xs-12">
+            <div class="card bg-inverse text-white mb-3 pihole-stat bg-red">
+                <div class="card-body">
+                    <div class="inline-block">
+                        <p>Domains on Blocklist</p>`;
+        for(var key in data) {
+            var e = data[key];
+            card += `<h3>`+e['domains_being_blocked'].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")+`</h3>`;
+        };
+        card += `
+                    </div>
+                    <i class="fa fa-list inline-block" aria-hidden="true"></i>
+                </div>
+            </div>
+        </div>
+        `
+        return card;
+    };
+    if(combine) {
+        stats += '<div class="row">'
+        stats += totalQueries(array['data']);
+        stats += totalBlocked(array['data']);
+        stats += percentBlocked(array['data']);
+        stats += domainsBlocked(array['data']);
+        stats += '</div>';
+    } else {
+        for(var key in array['data']) {
+            if(length > 1) {
+                stats += `
+                <div class="row mb-2">
+                    <div class="col-sm-12">
+                        `+key+`
+                    </div>
+                </div>
+                `;
+            }
+            var data = array['data'][key];
+            stats += '<div class="row">'
+            stats += totalQueries({0: data});
+            stats += totalBlocked({0: data});
+            stats += percentBlocked({0: data});
+            stats += domainsBlocked({0: data});
+            stats += '</div>';
+        };
+    }
+    return stats;
+}
+function homepagePihole(timeout){
+    var timeout = (typeof timeout !== 'undefined') ? timeout : activeInfo.settings.homepage.refresh.homepagePiholeRefresh;
+    organizrAPI('POST','api/?v1/homepage/connect',{action:'getPihole'}).success(function(data) {
+        try {
+            var response = JSON.parse(data);
+        }catch(e) {
+            console.log(e + ' error: ' + data);
+            orgErrorAlert('<h4>' + e + '</h4>' + formatDebug(data));
+            return false;
+        }
+        document.getElementById('homepageOrderPihole').innerHTML = '';
+        if(response.data !== null){
+            buildPihole(response.data)
+            $('#homepageOrderPihole').html(buildPihole(response.data));
+        }
+    }).fail(function(xhr) {
+        console.error("Organizr Function: API Connection Failed");
+    });
+    var timeoutTitle = 'PiHole-Homepage';
+    if(typeof timeouts[timeoutTitle] !== 'undefined'){ clearTimeout(timeouts[timeoutTitle]); }
+    timeouts[timeoutTitle] = setTimeout(function(){ homepagePihole(timeout); }, timeout);
+}
 function homepageHealthChecks(tags, timeout){
     var tags = (typeof tags !== 'undefined') ? tags : activeInfo.settings.homepage.options.healthChecksTags;
     var timeout = (typeof timeout !== 'undefined') ? timeout : activeInfo.settings.homepage.refresh.homepageHealthChecksRefresh;