Просмотр исходного кода

Merge pull request #386 from causefx/cero-dev

Chat Beta and Plex Cache and Email Changes
causefx 9 лет назад
Родитель
Сommit
2c032d9a01
15 измененных файлов с 811 добавлено и 58 удалено
  1. 42 10
      chat.php
  2. 26 0
      chat/getonline.php
  3. 2 0
      chat/logmessage.php
  4. 2 2
      chat/refreshmessages.php
  5. 86 27
      chatjs.php
  6. 1 0
      check.php
  7. 1 0
      config/configDefaults.php
  8. 1 1
      css/style.css
  9. 38 3
      functions.php
  10. 7 7
      homepage.php
  11. 3 3
      index.php
  12. 581 0
      js/push.js
  13. 11 1
      settings.php
  14. 9 3
      user.php
  15. 1 1
      vendor/phpmailer/phpmailer/class.phpmailer.php

+ 42 - 10
chat.php

@@ -136,6 +136,20 @@ endif; ?>
         
         
             $dbcreated = false;
             $dbcreated = false;
         
         
+            if (!extension_loaded("SQLITE3")){ 
+
+                echo '<div class="row" style="margin: 0"><div class="panel panel-danger" style="margin: 10px";>';
+                echo '<div class="panel-heading">';
+                echo '<h3 class="panel-title">SQLITE3</h3>';
+                echo '</div>';
+                echo '<div style="color: gray" class="panel-body">';
+                echo 'SQLITE3 is NOT loaded!  Please install it before proceeding';
+
+                echo '</div></div></div>';
+                die();
+
+            }  
+        
             if( $db = new SQLite3("chatpack.db") )
             if( $db = new SQLite3("chatpack.db") )
             {
             {
                 if( $db->busyTimeout(5000) )
                 if( $db->busyTimeout(5000) )
@@ -156,8 +170,14 @@ endif; ?>
                                           (id INTEGER PRIMARY KEY,
                                           (id INTEGER PRIMARY KEY,
                                           timestamp INTEGER NOT NULL,
                                           timestamp INTEGER NOT NULL,
                                           user TEXT NOT NULL)";
                                           user TEXT NOT NULL)";
+                            
+                            $onlinetable = "CREATE TABLE IF NOT EXISTS chatpack_last_message
+                                          (
+                                          user TEXT PRIMARY KEY NOT NULL,
+                                          timestamp INTEGER NOT NULL,
+                                          avatar TEXT NOT NULL)";
 
 
-                            if( $db->exec($usertable) )
+                            if( $db->exec($usertable) && $db->exec($onlinetable) )
                             {
                             {
                                 $dbcreated = true;
                                 $dbcreated = true;
                             }
                             }
@@ -200,28 +220,35 @@ endif; ?>
             <div id="content" class="container-fluid">
             <div id="content" class="container-fluid">
                 <br>
                 <br>
                 <div class="row">
                 <div class="row">
-                    <div class="col-lg-12">
-                        <div class="content-box big-box chat">
-                            <div class="content-title i-block">
-                                <h4 class="zero-m">Welcome To The Chat <?php echo $USER->username;?></h4>
-                            </div>
-                            <div class="box" style="overflow: hidden; width: auto; height: calc(100vh - 130px);">
+                    <div class="col-lg-10">
+                        <div class="content-box big-box chat gray-bg">
+                            <div class="box" style="overflow: hidden; width: auto; height: 550px;">
                                 <div id="intro">
                                 <div id="intro">
-                                    <center><img class="logo" alt="logo" src="images/organizr-logo-h-d.png">
+                                    <center><img class="logo" alt="logo" src="images/organizr-logo-h.png">
                                     <br><br>start chatting...</center>
                                     <br><br>start chatting...</center>
                                 </div>
                                 </div>
                                 <ul id="messages" class="chat-double chat-container"></ul>
                                 <ul id="messages" class="chat-double chat-container"></ul>
                                 <ul class="chat-double chat-container" style="padding: 0px;"><li id="istyping"></li></ul>
                                 <ul class="chat-double chat-container" style="padding: 0px;"><li id="istyping"></li></ul>
                             </div>
                             </div>
-            
-                            <input id="message" autofocus type="text" class="form-control" placeholder="Enter your text" autocomplete="off"/>
+                            <br/>
+                            <input id="message" autofocus type="text" class="form-control gray-bg" placeholder="Enter your text" autocomplete="off"/>
                             <audio id="tabalert" preload="auto">
                             <audio id="tabalert" preload="auto">
                                 <source src="chat/audio/newmessage.mp3" type="audio/mpeg">
                                 <source src="chat/audio/newmessage.mp3" type="audio/mpeg">
                             </audio>
                             </audio>
 
 
                         </div>
                         </div>
                     </div>
                     </div>
+                    <div class="col-lg-2">
+                        <div class="content-box">
+                            <div class="content-title big-box i-block gray-bg">
+                                <h4 class="zero-m">Online</h4>
+                            </div>
+                            <div class="clearfix"></div>
+                            <div id="onlineusers" class="big-box"></div>
+                        </div>
+                    </div>
                 </div>
                 </div>
+
             </div>    
             </div>    
         </div>
         </div>
         
         
@@ -246,6 +273,11 @@ endif; ?>
             scrollspeed: 30,
             scrollspeed: 30,
             mousescrollstep: 60
             mousescrollstep: 60
         });
         });
+        $("#onlineusers").niceScroll({
+            railpadding: {top:0,right:0,left:0,bottom:0},
+            scrollspeed: 30,
+            mousescrollstep: 60
+        });
     </script>
     </script>
 
 
 </html>
 </html>

+ 26 - 0
chat/getonline.php

@@ -0,0 +1,26 @@
+<?php
+
+include("connect.php");
+
+$onlineusers = array();
+
+if( $result = $db->query("SELECT user, timestamp, avatar FROM chatpack_last_message ORDER BY user ASC") )
+{
+    while( $row = $result->fetchArray() )
+    {            
+        $user = $row["user"];
+        $timestamp = $row["timestamp"];
+        $avatar = $row["avatar"];
+        $push = array($user, $timestamp, $avatar);
+
+        array_push($onlineusers, $push);
+    }
+}
+
+$db->close();
+
+// pass online users as JSON back to chat.js
+
+echo json_encode($onlineusers);
+
+?>

+ 2 - 0
chat/logmessage.php

@@ -22,6 +22,8 @@ if( strlen($message) > 0 )
 
 
     $db->exec("INSERT INTO chatpack_log (timestamp, user, avatar, message)
     $db->exec("INSERT INTO chatpack_log (timestamp, user, avatar, message)
                VALUES ('$timestamp', '$user', '$avatar', '$message')");
                VALUES ('$timestamp', '$user', '$avatar', '$message')");
+    $db->exec("REPLACE INTO chatpack_last_message (timestamp, user, avatar)
+               VALUES ('$timestamp', '$user', '$avatar')");
 }
 }
 
 
 function encryptmessage($msg)
 function encryptmessage($msg)

+ 2 - 2
chat/refreshmessages.php

@@ -8,7 +8,7 @@ include("connect.php");
 
 
 if( $result = $db->query("SELECT * FROM
 if( $result = $db->query("SELECT * FROM
                          (SELECT id, timestamp, user, avatar, message
                          (SELECT id, timestamp, user, avatar, message
-                          FROM chatpack_log ORDER BY id DESC LIMIT 250)
+                          FROM chatpack_log ORDER BY id DESC LIMIT 125)
                           ORDER BY id ASC") )
                           ORDER BY id ASC") )
 {   
 {   
     $newmessages = array();
     $newmessages = array();
@@ -22,7 +22,7 @@ if( $result = $db->query("SELECT * FROM
         $message = $row["message"];
         $message = $row["message"];
         
         
         $timenow = time();
         $timenow = time();
-        $messagetime = date("h:i", intval($timestamp));
+        $messagetime = date("h:iA", intval($timestamp));
         $messagedate = date("m-d", intval($timestamp));
         $messagedate = date("m-d", intval($timestamp));
         $message = utf8_encode($message);
         $message = utf8_encode($message);
         
         

+ 86 - 27
chatjs.php

@@ -354,12 +354,7 @@ $(document).ready(function()
     
     
     // allowed characters in message
     // allowed characters in message
     
     
-    $("#message").keyup(function()
-    {
-        var text = $(this).val();
-        $(this).val(text.replace("'", "`")
-                        .replace("###", "#"));
-    });
+
     
     
     // log message
     // log message
     
     
@@ -497,30 +492,79 @@ $(document).ready(function()
                     // check who is still online
                     // check who is still online
                                     
                                     
                     var datetoday = new Date();
                     var datetoday = new Date();
-                    var timenow = datetoday.getTime() / 1000;   
+                    var timenow = datetoday.getTime() / 1000;  
 
 
-                    $(".img-circle").each(function()
+                    $.ajax
+                ({
+                    url: "chat/getonline.php",
+                    cache: false,
+                    success: function(result)
                     {
                     {
-                        var timestamp = this.id;
-                        var avauser = $(this).attr("alt");
-                        var avatarsrc = $(this).attr("src");
+                        var onlineusers = JSON.parse(result);
+                        var oldonlineusers = $("#onlineusers").html();
+                        var newonlineusers = '';
                         
                         
-                        // set user offline avatar
-
-                        if( timestamp < timenow - 2700 )
+                        if( onlineusers.length <= 0 )  // no user typing
                         {
                         {
-                            $(this).addClass("offline");
-                            $(this).removeClass("online");
-                            
+                            newonlineusers += "No Users Online";
                         }
                         }
-                        else  // set user online avatar
-                        {
+                        else
+                        {   
+                            if( onlineusers.length >= 1 )  // one user typing
+                            {
+                                jQuery.each( onlineusers, function( i, val ) {
+                                    var timecheck = val[1];
+                                    var status = "";
+                                    var color = "";
+                                    if( timecheck < timenow - 1800 )
+                                    {
+                                        status = '<span style="min-height: 14px;margin-top: 10px;" class="pull-right badge badge-danger animated pulse"> </span>';
+                                        color = "red";
+                                    }else{
+                                        status = '<span style="min-height: 14px;margin-top: 10px;" class="pull-right badge badge-success animated flash"> </span>';                       
+                                        color = "blue";                       
+                                    }
+                                    if( timecheck < timenow - 3600 )
+                                    {
+                                        newonlineusers += '';      
+                                    }else{
+                                        newonlineusers += '<div class="member-info"><img style="height:40px" src="'+val[2]+'" alt="admin" class="img-circle"><span class="member-name">'+val[0]+'</span>'+status+'</div>'; 
+                                        i++;
+                                    }
+                                    
+                                    $("img[alt^='"+val[0]+"']").each(function()
+                                    {
+                                        var timestamp = val[1];
 
 
-                            $(this).addClass("online");
-                            $(this).removeClass("offline");
-                           
+                                        // set user offline avatar
+
+                                        if( timestamp < timenow - 1800 )
+                                        {
+                                            $(this).addClass("offline");
+                                            $(this).removeClass("online");
+
+                                        }
+                                        else  // set user online avatar
+                                        {
+
+                                            $(this).addClass("online");
+                                            $(this).removeClass("offline");
+
+                                        }
+                                    });
+                                    
+                                });
+                            }
                         }
                         }
-                    });
+                        if(newonlineusers === ''){ newonlineusers = "No Users Online";}
+                        if( newonlineusers != oldonlineusers )
+                        {
+                            $("#onlineusers").html(newonlineusers);
+                        }
+                    }
+                });
+
+                    
                     
                     
                     // new messages
                     // new messages
                     
                     
@@ -559,7 +603,7 @@ $(document).ready(function()
 
 
                                     if( message.lastIndexOf(userwriting) == -1 )
                                     if( message.lastIndexOf(userwriting) == -1 )
                                     {
                                     {
-                                        newmessagealert();
+                                        newmessagealert(message);
                                     }
                                     }
                                     
                                     
                                     // refresh eventlisteners of messages to set likes
                                     // refresh eventlisteners of messages to set likes
@@ -637,7 +681,7 @@ $(document).ready(function()
     window.onfocus = function()
     window.onfocus = function()
     {
     {
         tabinfocus = true;
         tabinfocus = true;
-        parent.document.title = "Organzir Chat";
+        parent.document.title = "Chat";
         window.parent.$("span[id^='chat.phps']").html("");
         window.parent.$("span[id^='chat.phps']").html("");
     };
     };
     
     
@@ -648,7 +692,7 @@ $(document).ready(function()
     
     
     // new message tab alert
     // new message tab alert
     
     
-    function newmessagealert()
+    function newmessagealert(message)
     {   
     {   
         if( !tabinfocus )
         if( !tabinfocus )
         {
         {
@@ -660,9 +704,24 @@ $(document).ready(function()
                 i++
                 i++
              }
              }
 
 
-            parent.document.title = i + " Organzir Chat";
+            parent.document.title = i + " Chat";
             //window.parent.$("#chat.phpx").addClass("gottem");
             //window.parent.$("#chat.phpx").addClass("gottem");
             window.parent.$("span[id^='chat.phps']").html(i);
             window.parent.$("span[id^='chat.phps']").html(i);
+            var $jQueryObject = $($.parseHTML(message));
+            var alertMessage = $jQueryObject.find(".chat-body").html();
+            var alertUsername = $jQueryObject.find("h4[class^='pull-left zero-m']").html();
+            var alertIcon = $jQueryObject.find("img").attr("src");;
+            if(isMobile === false){
+                parent.Push.create(alertUsername, {
+                    body: alertMessage,
+                    icon: alertIcon,
+                    timeout: 4000,
+                    onClick: function () {
+                        window.parent.focus();
+                        this.close();
+                    }
+                });
+            }
                         
                         
             // sound
             // sound
                         
                         

+ 1 - 0
check.php

@@ -162,6 +162,7 @@ $folder = USER_HOME;
                 
                 
                 check("PDO_SQLITE");
                 check("PDO_SQLITE");
                 check("PDO");
                 check("PDO");
+                check("SQLITE3");
                 check("Zip");
                 check("Zip");
                 check("openssl");
                 check("openssl");
                 check("session");
                 check("session");

+ 1 - 0
config/configDefaults.php

@@ -72,4 +72,5 @@ return array(
 	"git_branch" => "master",
 	"git_branch" => "master",
 	"git_check" => true,
 	"git_check" => true,
     "speedTest" => false,
     "speedTest" => false,
+    "smtpHostType" => "tls",
 );
 );

+ 1 - 1
css/style.css

@@ -3265,7 +3265,7 @@ ul.inbox-pagination li {
   /*padding: 22px;*/
   /*padding: 22px;*/
   padding: 19px 22px 19px 22px;
   padding: 19px 22px 19px 22px;
   line-height: 1.4;
   line-height: 1.4;
-  z-index: 4000;
+  z-index: 10000;
   pointer-events: none;
   pointer-events: none;
   color: #fff;
   color: #fff;
   font-size: 80%;
   font-size: 80%;

+ 38 - 3
functions.php

@@ -2,7 +2,7 @@
 
 
 // ===================================
 // ===================================
 // Define Version
 // Define Version
- define('INSTALLEDVERSION', '1.36');
+ define('INSTALLEDVERSION', '1.37');
 // ===================================
 // ===================================
 
 
 // Debugging output functions
 // Debugging output functions
@@ -490,6 +490,7 @@ function resolvePlexItem($server, $token, $item) {
 			$image = 'carousel-image season';
 			$image = 'carousel-image season';
 			$style = '';
 			$style = '';
             $thumb = $item['thumb'];
             $thumb = $item['thumb'];
+            $key = $item['ratingKey'];
 			break;
 			break;
         case 'episode':
         case 'episode':
 			$title = $item['grandparentTitle'];
 			$title = $item['grandparentTitle'];
@@ -498,6 +499,16 @@ function resolvePlexItem($server, $token, $item) {
 			$image = 'carousel-image season';
 			$image = 'carousel-image season';
 			$style = '';
 			$style = '';
             $thumb = $item['parentThumb'];
             $thumb = $item['parentThumb'];
+            $key = $item['ratingKey'];
+			break;
+        case 'clip':
+			$title = $item['title'];
+			$summary = $item['summary'];
+			$width = 100;
+			$image = 'carousel-image movie';
+			$style = '';
+            $thumb = $item['thumb'];
+            $key = "clip";
 			break;
 			break;
 		case 'album':
 		case 'album':
 		case 'track':
 		case 'track':
@@ -507,6 +518,7 @@ function resolvePlexItem($server, $token, $item) {
 			$image = 'album';
 			$image = 'album';
 			$style = 'left: 160px !important;';
 			$style = 'left: 160px !important;';
             $thumb = $item['thumb'];
             $thumb = $item['thumb'];
+            $key = $item['ratingKey'];
 			break;
 			break;
 		default:
 		default:
 			$title = $item['title'];
 			$title = $item['title'];
@@ -515,15 +527,20 @@ function resolvePlexItem($server, $token, $item) {
 			$image = 'carousel-image movie';
 			$image = 'carousel-image movie';
 			$style = '';
 			$style = '';
             $thumb = $item['thumb'];
             $thumb = $item['thumb'];
+            $key = $item['ratingKey'];
 	}
 	}
 	
 	
 	// If No Overview
 	// If No Overview
 	if (!isset($itemDetails['Overview'])) {
 	if (!isset($itemDetails['Overview'])) {
 		$itemDetails['Overview'] = '';
 		$itemDetails['Overview'] = '';
 	}
 	}
+    $image_url = 'ajax.php?a=plex-image&img='.$thumb.'&height='.$height.'&width='.$width.'&key='.$key.'';
+    if (file_exists('images/cache/'.$key.'.jpg')){
+        $image_url = 'images/cache/'.$key.'.jpg';
+    }
 	
 	
 	// Assemble Item And Cache Into Array 
 	// Assemble Item And Cache Into Array 
-	return '<div class="item"><a href="'.$address.'" target="_blank"><img alt="'.$item['Name'].'" class="'.$image.'" src="ajax.php?a=plex-image&img='.$thumb.'&height='.$height.'&width='.$width.'"></a><div class="carousel-caption" style="'.$style.'"><h4>'.$title.'</h4><small><em>'.$summary.'</em></small></div></div>';
+	return '<div class="item"><a href="'.$address.'" target="_blank"><img alt="'.$item['Name'].'" class="'.$image.'" src="'.$image_url.'"></a><div class="carousel-caption" style="'.$style.'"><h4>'.$title.'</h4><small><em>'.$summary.'</em></small></div></div>';
 }
 }
 
 
 // Create Carousel
 // Create Carousel
@@ -726,15 +743,33 @@ function getEmbyImage() {
 // Get Image From Plex
 // Get Image From Plex
 function getPlexImage() {
 function getPlexImage() {
 	$plexAddress = qualifyURL(PLEXURL);
 	$plexAddress = qualifyURL(PLEXURL);
+    if (!file_exists('images/cache')) {
+        mkdir('images/cache', 0777, true);
+    }
 	
 	
 	$image_url = $_GET['img'];
 	$image_url = $_GET['img'];
+	$key = $_GET['key'];
 	$image_height = $_GET['height'];
 	$image_height = $_GET['height'];
 	$image_width = $_GET['width'];
 	$image_width = $_GET['width'];
 	
 	
 	if(isset($image_url) && isset($image_height) && isset($image_width)) {
 	if(isset($image_url) && isset($image_height) && isset($image_width)) {
 		$image_src = $plexAddress . '/photo/:/transcode?height='.$image_height.'&width='.$image_width.'&upscale=1&url=' . $image_url . '&X-Plex-Token=' . PLEXTOKEN;
 		$image_src = $plexAddress . '/photo/:/transcode?height='.$image_height.'&width='.$image_width.'&upscale=1&url=' . $image_url . '&X-Plex-Token=' . PLEXTOKEN;
-		header('Content-type: image/jpeg');
+        $cachefile = 'images/cache/'.$key.'.jpg';
+        $cachetime = 604800;
+        // Serve from the cache if it is younger than $cachetime
+        if (file_exists($cachefile) && time() - $cachetime < filemtime($cachefile)) {
+            header("Content-type: image/jpeg");
+            @readfile($cachefile);
+            exit;
+        }
+		ob_start(); // Start the output buffer
+        header('Content-type: image/jpeg');
 		@readfile($image_src);
 		@readfile($image_src);
+        // Cache the output to a file
+        $fp = fopen($cachefile, 'wb');
+        fwrite($fp, ob_get_contents());
+        fclose($fp);
+        ob_end_flush(); // Send the output to the browser
 		die();
 		die();
 	} else {
 	} else {
 		echo "Invalid Plex Request";	
 		echo "Invalid Plex Request";	

+ 7 - 7
homepage.php

@@ -262,9 +262,9 @@ endif; ?>
                             var ul = document.getElementById('upload')
                             var ul = document.getElementById('upload')
                             var ping = document.getElementById('ping')
                             var ping = document.getElementById('ping')
                             var jitter = document.getElementById('jitter')
                             var jitter = document.getElementById('jitter')
-                            dl.className = status === 1 ? 'w-amount flash' : 'w-amount'
-                            ping.className = status === 2 ? 'w-amount flash' : 'w-amount'
-                            jitter.className = ul.className = status === 3 ? 'w-amount flash' : 'w-amount'
+                            dl.className = status === 1 ? 'w-name flash' : 'w-name'
+                            ping.className = status === 2 ? 'w-name flash' : 'w-name'
+                            jitter.className = ul.className = status === 3 ? 'w-name flash' : 'w-name'
                             if (status >= 4) {
                             if (status >= 4) {
                                 clearInterval(interval)
                                 clearInterval(interval)
                                 document.getElementById('abortBtn').style.display = 'none'
                                 document.getElementById('abortBtn').style.display = 'none'
@@ -300,7 +300,7 @@ endif; ?>
                                 <div class="w-descr left pull-left text-center">
                                 <div class="w-descr left pull-left text-center">
                                     <span class="testName text-uppercase w-name">Download</span>
                                     <span class="testName text-uppercase w-name">Download</span>
                                     <br>
                                     <br>
-                                    <span class="w-amount counter" id="download" ></span>
+                                    <span class="w-name counter" id="download" ></span>
                                 </div>
                                 </div>
                             </div>
                             </div>
                         </div>
                         </div>
@@ -314,7 +314,7 @@ endif; ?>
                                 <div class="w-descr left pull-left text-center">
                                 <div class="w-descr left pull-left text-center">
                                     <span class="testName text-uppercase w-name">Upload</span>
                                     <span class="testName text-uppercase w-name">Upload</span>
                                     <br>
                                     <br>
-                                    <span class="w-amount counter" id="upload" ></span>
+                                    <span class="w-name counter" id="upload" ></span>
                                 </div>
                                 </div>
                             </div>
                             </div>
                         </div>
                         </div>
@@ -328,7 +328,7 @@ endif; ?>
                                 <div class="w-descr left pull-left text-center">
                                 <div class="w-descr left pull-left text-center">
                                     <span class="testName text-uppercase w-name">Latency</span>
                                     <span class="testName text-uppercase w-name">Latency</span>
                                     <br>
                                     <br>
-                                    <span class="w-amount counter" id="ping" ></span>
+                                    <span class="w-name counter" id="ping" ></span>
                                 </div>
                                 </div>
                             </div>
                             </div>
                         </div>
                         </div>
@@ -342,7 +342,7 @@ endif; ?>
                                 <div class="w-descr left pull-left text-center">
                                 <div class="w-descr left pull-left text-center">
                                     <span class="testName text-uppercase w-name">Jitter</span>
                                     <span class="testName text-uppercase w-name">Jitter</span>
                                     <br>
                                     <br>
-                                    <span class="w-amount counter" id="jitter" ></span>
+                                    <span class="w-name counter" id="jitter" ></span>
                                 </div>
                                 </div>
                             </div>
                             </div>
                         </div>
                         </div>

+ 3 - 3
index.php

@@ -265,7 +265,7 @@ if(file_exists("images/settings2.png")) : $iconRotate = "false"; $settingsIcon =
         <meta name="theme-color" content="#2d89ef">
         <meta name="theme-color" content="#2d89ef">
         <link rel="stylesheet" type="text/css" href="css/addtohomescreen.css">
         <link rel="stylesheet" type="text/css" href="css/addtohomescreen.css">
         <script src="js/addtohomescreen.js"></script>
         <script src="js/addtohomescreen.js"></script>
-        <script src="push.js"></script>
+        <script src="js/push.js"></script>
 		<!--Other-->
 		<!--Other-->
 		<script src="js/ajax.js?v=<?php echo INSTALLEDVERSION; ?>"></script>
 		<script src="js/ajax.js?v=<?php echo INSTALLEDVERSION; ?>"></script>
         <!--[if lt IE 9]>
         <!--[if lt IE 9]>
@@ -1427,7 +1427,7 @@ endif; ?>
 
 
                 currentframe.attr("class", "iframe active");
                 currentframe.attr("class", "iframe active");
                 document.title = thistitle;
                 document.title = thistitle;
-                window.location.href = '#' + thisname;
+                //window.location.href = '#' + thisname;
                 setHeight();
                 setHeight();
 
 
                 $("li[class^='tab-item active']").attr("class", "tab-item");
                 $("li[class^='tab-item active']").attr("class", "tab-item");
@@ -1444,7 +1444,7 @@ endif; ?>
 
 
                     $( '<div class="iframe active" data-content-url="'+thisid+'"><iframe scrolling="auto" sandbox="allow-forms allow-same-origin allow-pointer-lock allow-scripts allow-popups allow-modals allow-top-navigation" allowfullscreen="true" webkitallowfullscreen="true" frameborder="0" style="width:100%; height:100%; position: absolute;" src="'+thisid+'"></iframe></div>' ).appendTo( "#content" );
                     $( '<div class="iframe active" data-content-url="'+thisid+'"><iframe scrolling="auto" sandbox="allow-forms allow-same-origin allow-pointer-lock allow-scripts allow-popups allow-modals allow-top-navigation" allowfullscreen="true" webkitallowfullscreen="true" frameborder="0" style="width:100%; height:100%; position: absolute;" src="'+thisid+'"></iframe></div>' ).appendTo( "#content" );
                     document.title = thistitle;
                     document.title = thistitle;
-                    window.location.href = '#' + thisname;
+                   // window.location.href = '#' + thisname;
 
 
                     setHeight();
                     setHeight();
 
 

+ 581 - 0
js/push.js

@@ -0,0 +1,581 @@
+/**
+ * Push
+ * =======
+ * A compact, cross-browser solution for the JavaScript Notifications API
+ *
+ * Credits
+ * -------
+ * Tsvetan Tsvetkov (ttsvetko)
+ * Alex Gibson (alexgibson)
+ *
+ * License
+ * -------
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2015-2017 Tyler Nickerson
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @preserve
+ */
+
+(function (global, factory) {
+
+    'use strict';
+
+    /* Use AMD */
+    if (typeof define === 'function' && define.amd) {
+        define(function () {
+            return new (factory(global, global.document))();
+        });
+    }
+    /* Use CommonJS */
+    else if (typeof module !== 'undefined' && module.exports) {
+        module.exports = new (factory(global, global.document))();
+    }
+    /* Use Browser */
+    else {
+        global.Push = new (factory(global, global.document))();
+    }
+
+})(typeof window !== 'undefined' ? window : this, function (w, d) {
+
+    var Push = function () {
+
+        /**********************
+            Local Variables
+        /**********************/
+
+        var
+        self = this,
+        isUndefined   = function (obj) { return obj === undefined; },
+        isString   = function (obj) { return typeof obj === 'string' },
+        isFunction = function (obj) { return obj && {}.toString.call(obj) === '[object Function]'; },
+
+        /* ID to use for new notifications */
+        currentId = 0,
+
+        /* Message to show if there is no suport to Push Notifications */
+        incompatibilityErrorMessage = 'PushError: push.js is incompatible with browser.',
+
+        /* Map of open notifications */
+        notifications = {},
+
+        /* Testing variable for the last service worker path used */
+        lastWorkerPath = null,
+
+        /**********************
+            Helper Functions
+        /**********************/
+
+        /**
+         * Closes a notification
+         * @param {Notification} notification
+         * @return {Boolean} boolean denoting whether the operation was successful
+         */
+        closeNotification = function (id) {
+            var errored = false,
+                notification = notifications[id];
+
+            if (typeof notification !== 'undefined') {
+                /* Safari 6+, Chrome 23+ */
+                if (notification.close) {
+                    notification.close();
+                /* Legacy webkit browsers */
+                } else if (notification.cancel) {
+                    notification.cancel();
+                /* IE9+ */
+                } else if (w.external && w.external.msIsSiteMode) {
+                    w.external.msSiteModeClearIconOverlay();
+                } else {
+                    errored = true;
+                    throw new Error('Unable to close notification: unknown interface');
+                }
+
+                if (!errored) {
+                    return removeNotification(id);
+                }
+            }
+
+            return false;
+        },
+
+        /**
+         * Adds a notification to the global dictionary of notifications
+         * @param {Notification} notification
+         * @return {Integer} Dictionary key of the notification
+         */
+        addNotification = function (notification) {
+            var id = currentId;
+            notifications[id] = notification;
+            currentId++;
+            return id;
+        },
+
+        /**
+         * Removes a notification with the given ID
+         * @param  {Integer} id - Dictionary key/ID of the notification to remove
+         * @return {Boolean} boolean denoting success
+         */
+        removeNotification = function (id) {
+            var dict = {},
+                success = false,
+                key;
+
+            for (key in notifications) {
+                if (notifications.hasOwnProperty(key)) {
+                    if (key != id) {
+                        dict[key] = notifications[key];
+                    } else {
+                        // We're successful if we omit the given ID from the new array
+                        success = true;
+                    }
+                }
+            }
+            // Overwrite the current notifications dictionary with the filtered one
+            notifications = dict;
+            return success;
+        },
+
+        prepareNotification = function (id, options) {
+            var wrapper;
+
+            /* Wrapper used to get/close notification later on */
+            wrapper = {
+                get: function () {
+                    return notifications[id];
+                },
+
+                close: function () {
+                    closeNotification(id);
+                }
+            };
+
+            /* Autoclose timeout */
+            if (options.timeout) {
+                setTimeout(function () {
+                    wrapper.close();
+                }, options.timeout);
+            }
+
+            return wrapper;
+        },
+
+        /**
+         * Callback function for the 'create' method
+         * @return {void}
+         */
+        createCallback = function (title, options, resolve) {
+            var notification,
+                onClose;
+
+            /* Set empty settings if none are specified */
+            options = options || {};
+
+            /* Set the last service worker path for testing */
+            self.lastWorkerPath = options.serviceWorker || 'serviceWorker.js';
+
+            /* onClose event handler */
+            onClose = function (id) {
+                /* A bit redundant, but covers the cases when close() isn't explicitly called */
+                removeNotification(id);
+                if (isFunction(options.onClose)) {
+                    options.onClose.call(this, notification);
+                }
+            };
+
+            /* Safari 6+, Firefox 22+, Chrome 22+, Opera 25+ */
+            if (w.Notification) {
+                try {
+                    notification =  new w.Notification(
+                        title,
+                        {
+                            icon: (isString(options.icon) || isUndefined(options.icon)) ? options.icon : options.icon.x32,
+                            body: options.body,
+                            tag: options.tag,
+                            requireInteraction: options.requireInteraction,
+                            silent: options.silent
+                        }
+                    );
+                } catch (e) {
+                    if (w.navigator) {
+                        /* Register ServiceWorker using lastWorkerPath */
+                        w.navigator.serviceWorker.register(self.lastWorkerPath);
+                        w.navigator.serviceWorker.ready.then(function(registration) {
+                            var localData = {
+                                id: currentId,
+                                link: options.link,
+                                origin: document.location.href,
+                                onClick: (isFunction(options.onClick)) ? options.onClick.toString() : '',
+                                onClose: (isFunction(options.onClose)) ? options.onClose.toString() : ''
+                            };
+
+                            if (typeof options.data !== 'undefined' && options.data !== null)
+                                localData = Object.assign(localData, options.data);
+
+                            /* Show the notification */
+                            registration.showNotification(
+                                title,
+                                {
+                                    icon: options.icon,
+                                    body: options.body,
+                                    vibrate: options.vibrate,
+                                    tag: options.tag,
+                                    data: localData,
+                                    requireInteraction: options.requireInteraction
+                                }
+                            ).then(function() {
+                                var id;
+
+                                /* Find the most recent notification and add it to the global array */
+                                registration.getNotifications().then(function(notifications) {
+                                    id = addNotification(notifications[notifications.length - 1]);
+
+                                    /* Send an empty message so the ServiceWorker knows who the client is */
+                                    registration.active.postMessage('');
+
+                                    /* Listen for close requests from the ServiceWorker */
+                                    navigator.serviceWorker.addEventListener('message', function (event) {
+                                        var data = JSON.parse(event.data);
+
+                                        if (data.action === 'close' && Number.isInteger(data.id))
+                                            removeNotification(data.id);
+                                    });
+
+                                    resolve(prepareNotification(id, options));
+                                });
+                            });
+                        });
+                    }
+                }
+
+            /* Legacy webkit browsers */
+            } else if (w.webkitNotifications) {
+
+                notification = w.webkitNotifications.createNotification(
+                    options.icon,
+                    title,
+                    options.body
+                );
+
+                notification.show();
+
+            /* Firefox Mobile */
+            } else if (navigator.mozNotification) {
+
+                notification = navigator.mozNotification.createNotification(
+                    title,
+                    options.body,
+                    options.icon
+                );
+
+                notification.show();
+
+            /* IE9+ */
+            } else if (w.external && w.external.msIsSiteMode()) {
+
+                //Clear any previous notifications
+                w.external.msSiteModeClearIconOverlay();
+                w.external.msSiteModeSetIconOverlay(
+                    ((isString(options.icon) || isUndefined(options.icon))
+                    ? options.icon
+                    : options.icon.x16), title
+                );
+                w.external.msSiteModeActivate();
+
+                notification = {};
+            } else {
+                throw new Error('Unable to create notification: unknown interface');
+            }
+
+            if (typeof(notification) !== 'undefined') {
+                var id = addNotification(notification),
+                    wrapper = prepareNotification(id, options);
+
+                /* Notification callbacks */
+                if (isFunction(options.onShow))
+                    notification.addEventListener('show', options.onShow);
+
+                if (isFunction(options.onError))
+                    notification.addEventListener('error', options.onError);
+
+                if (isFunction(options.onClick))
+                    notification.addEventListener('click', options.onClick);
+
+                notification.addEventListener('close', function() {
+                    onClose(id);
+                });
+
+                notification.addEventListener('cancel', function() {
+                    onClose(id);
+                });
+
+                /* Return the wrapper so the user can call close() */
+                resolve(wrapper);
+            }
+
+            resolve({}); // By default, pass an empty wrapper
+        },
+
+        /**
+         * Permission types
+         * @enum {String}
+         */
+        Permission = {
+            DEFAULT: 'default',
+            GRANTED: 'granted',
+            DENIED: 'denied'
+        },
+
+        Permissions = [Permission.GRANTED, Permission.DEFAULT, Permission.DENIED];
+
+        /* Allow enums to be accessible from Push object */
+        self.Permission = Permission;
+
+        /*****************
+            Permissions
+        /*****************/
+
+        /**
+         * Requests permission for desktop notifications
+         * @param {Function} callback - Function to execute once permission is granted
+         * @return {void}
+         */
+        self.Permission.request = function (onGranted, onDenied) {
+            var existing = self.Permission.get();
+
+            /* Return if Push not supported */
+            if (!self.isSupported) {
+                throw new Error(incompatibilityErrorMessage);
+            }
+
+            /* Default callback */
+            callback = function (result) {
+                switch (result) {
+
+                    case self.Permission.GRANTED:
+                        if (onGranted) onGranted();
+                        break;
+
+                    case self.Permission.DENIED:
+                        if (onDenied) onDenied();
+                        break;
+
+                }
+
+            };
+
+            /* Permissions already set */
+            if (existing !== self.Permission.DEFAULT) {
+                callback(existing);
+            }
+            /* Safari 6+, Chrome 23+ */
+            else if (w.Notification && w.Notification.requestPermission) {
+                Notification.requestPermission(callback);
+            }
+            /* Legacy webkit browsers */
+            else if (w.webkitNotifications && w.webkitNotifications.checkPermission) {
+                w.webkitNotifications.requestPermission(callback);
+            } else {
+                throw new Error(incompatibilityErrorMessage);
+            }
+        };
+
+        /**
+         * Returns whether Push has been granted permission to run
+         * @return {Boolean}
+         */
+        self.Permission.has = function () {
+            return Permission.get() === Permission.GRANTED;
+        };
+
+        /**
+         * Gets the permission level
+         * @return {Permission} The permission level
+         */
+        self.Permission.get = function () {
+
+            var permission;
+
+            /* Return if Push not supported */
+            if (!self.isSupported) { throw new Error(incompatibilityErrorMessage); }
+
+            /* Safari 6+, Chrome 23+ */
+            if (w.Notification && w.Notification.permissionLevel) {
+                permission = w.Notification.permissionLevel;
+
+            /* Legacy webkit browsers */
+            } else if (w.webkitNotifications && w.webkitNotifications.checkPermission) {
+                permission = Permissions[w.webkitNotifications.checkPermission()];
+
+            /* Firefox 23+ */
+            } else if (w.Notification && w.Notification.permission) {
+                permission = w.Notification.permission;
+
+            /* Firefox Mobile */
+            } else if (navigator.mozNotification) {
+                permission = Permission.GRANTED;
+
+            /* IE9+ */
+            } else if (w.external && w.external.msIsSiteMode() !== undefined) {
+                permission = w.external.msIsSiteMode() ? Permission.GRANTED : Permission.DEFAULT;
+            } else {
+                throw new Error(incompatibilityErrorMessage);
+            }
+
+            return permission;
+
+        };
+
+        /*********************
+            Other Functions
+        /*********************/
+
+        /**
+         * Detects whether the user's browser supports notifications
+         * @return {Boolean}
+         */
+        self.isSupported = (function () {
+
+             var isSupported = false;
+
+             try {
+
+                 isSupported =
+
+                     /* Safari, Chrome */
+                     !!(w.Notification ||
+
+                     /* Chrome & ff-html5notifications plugin */
+                     w.webkitNotifications ||
+
+                     /* Firefox Mobile */
+                     navigator.mozNotification ||
+
+                     /* IE9+ */
+                     (w.external && w.external.msIsSiteMode() !== undefined));
+
+             } catch (e) {}
+
+             return isSupported;
+
+         })();
+
+         /**
+          * Creates and displays a new notification
+          * @param {Array} options
+          * @return {Promise}
+          */
+        self.create = function (title, options) {
+            var promiseCallback;
+
+            /* Fail if the browser is not supported */
+            if (!self.isSupported) {
+                throw new Error(incompatibilityErrorMessage);
+            }
+
+            /* Fail if no or an invalid title is provided */
+            if (!isString(title)) {
+                throw new Error('PushError: Title of notification must be a string');
+            }
+
+            /* Request permission if it isn't granted */
+            if (!self.Permission.has()) {
+                promiseCallback = function(resolve, reject) {
+                    self.Permission.request(function() {
+                        try {
+                            createCallback(title, options, resolve);
+                        } catch (e) {
+                            reject(e);
+                        }
+                    }, function() {
+                        reject("Permission request declined");
+                    });
+                };
+            } else {
+                promiseCallback = function(resolve, reject) {
+                    try {
+                        createCallback(title, options, resolve);
+                    } catch (e) {
+                        reject(e);
+                    }
+                };
+            }
+
+            return new Promise(promiseCallback);
+        };
+
+        /**
+         * Returns the notification count
+         * @return {Integer} The notification count
+         */
+        self.count = function () {
+            var count = 0,
+                key;
+
+            for (key in notifications)
+                count++;
+
+            return count;
+        },
+
+        /**
+         * Internal function that returns the path of the last service worker used
+         * For testing purposes only
+         * @return {String} The service worker path
+         */
+        self.__lastWorkerPath = function () {
+            return self.lastWorkerPath;
+        },
+
+        /**
+         * Closes a notification with the given tag
+         * @param {String} tag - Tag of the notification to close
+         * @return {Boolean} boolean denoting success
+         */
+        self.close = function (tag) {
+            var key;
+            for (key in notifications) {
+                notification = notifications[key];
+                /* Run only if the tags match */
+                if (notification.tag === tag) {
+                    /* Call the notification's close() method */
+                    return closeNotification(key);
+                }
+            }
+        };
+
+        /**
+         * Clears all notifications
+         * @return {void}
+         */
+        self.clear = function () {
+            var success = true;
+
+            for (key in notifications)
+                success = success && closeNotification(key);
+
+            return success;
+        };
+    };
+
+    return Push;
+
+});

+ 11 - 1
settings.php

@@ -350,7 +350,7 @@ endif; ?>
 <?php
 <?php
 $dirname = "images/";
 $dirname = "images/";
 $images = scandir($dirname);
 $images = scandir($dirname);
-$ignore = Array(".", "..", "favicon/", "favicon", "._.DS_Store", ".DS_Store", "confused.png", "sowwy.png", "sort-btns", "loading.png", "titlelogo.png", "default.svg", "login.png", "themes", "nadaplaying.jpg", "organizr-logo-h-d.png", "organizr-logo-h.png");
+$ignore = Array(".", "..", "favicon", "cache", "._.DS_Store", ".DS_Store", "confused.png", "sowwy.png", "sort-btns", "loading.png", "titlelogo.png", "default.svg", "login.png", "themes", "nadaplaying.jpg", "organizr-logo-h-d.png", "organizr-logo-h.png");
 foreach($images as $curimg){
 foreach($images as $curimg){
 	if(!in_array($curimg, $ignore)) { ?>
 	if(!in_array($curimg, $ignore)) { ?>
 												<div class="col-xs-2" style="width: 75px; height: 75px; padding-right: 0px;">    
 												<div class="col-xs-2" style="width: 75px; height: 75px; padding-right: 0px;">    
@@ -1252,6 +1252,16 @@ echo buildSettings(
 						'name' => 'smtpHostSenderEmail',
 						'name' => 'smtpHostSenderEmail',
 						'value' => SMTPHOSTSENDEREMAIL,
 						'value' => SMTPHOSTSENDEREMAIL,
 					),
 					),
+                    array(
+						'type' => 'select',
+						'labelTranslate' => 'SMTP_HOST_AUTH',
+						'name' => 'smtpHostType',
+						'value' => SMTPHOSTTYPE,
+						'options' => array(
+							'ssl' => 'ssl',
+							'tls' => 'tls',
+						),
+					),
 					array(
 					array(
 						array(
 						array(
 							'type' => 'checkbox',
 							'type' => 'checkbox',

+ 9 - 3
user.php

@@ -134,7 +134,7 @@
             $mail->SMTPAuth = SMTPHOSTAUTH;
             $mail->SMTPAuth = SMTPHOSTAUTH;
             $mail->Username = SMTPHOSTUSERNAME;
             $mail->Username = SMTPHOSTUSERNAME;
             $mail->Password = SMTPHOSTPASSWORD;
             $mail->Password = SMTPHOSTPASSWORD;
-            $mail->SMTPSecure = 'tls';
+            $mail->SMTPSecure = SMTPHOSTTYPE;
             $mail->Port = SMTPHOSTPORT;
             $mail->Port = SMTPHOSTPORT;
             $mail->setFrom(SMTPHOSTSENDEREMAIL, SMTPHOSTSENDERNAME);
             $mail->setFrom(SMTPHOSTSENDEREMAIL, SMTPHOSTSENDERNAME);
             $mail->addReplyTo(SMTPHOSTSENDEREMAIL, SMTPHOSTSENDERNAME);
             $mail->addReplyTo(SMTPHOSTSENDEREMAIL, SMTPHOSTSENDERNAME);
@@ -142,7 +142,13 @@
             $mail->addAddress($email, $username);
             $mail->addAddress($email, $username);
             $mail->Subject = $subject;
             $mail->Subject = $subject;
             $mail->Body    = $body;
             $mail->Body    = $body;
-            $mail->send();
+            //$mail->send();
+            if(!$mail->send()) {
+                $this->error('Mailer Error: ' . $mail->ErrorInfo);
+                $this->error = 'Mailer Error: ' . $mail->ErrorInfo;
+            } else {
+                $this->info('E-Mail sent!');
+            }
             
             
         }
         }
        
        
@@ -352,7 +358,7 @@ EOT;
 			$dbpassword = $this->token_hash_password($username, $sha1, $token);
 			$dbpassword = $this->token_hash_password($username, $sha1, $token);
 			$update = "UPDATE users SET password = '$dbpassword' WHERE email= '$email'";
 			$update = "UPDATE users SET password = '$dbpassword' WHERE email= '$email'";
 			$this->database->exec($update);
 			$this->database->exec($update);
-            $this->info("Email has been sent with new password");
+            //$this->info("Email has been sent with new password");
 			// step 3: notify the user of the new password
 			// step 3: notify the user of the new password
 			$from = User::MAILER_NAME;
 			$from = User::MAILER_NAME;
 			$replyto = User::MAILER_REPLYTO;
 			$replyto = User::MAILER_REPLYTO;

+ 1 - 1
vendor/phpmailer/phpmailer/class.phpmailer.php

@@ -312,7 +312,7 @@ class PHPMailer
      * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
      * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
      * @var integer
      * @var integer
      */
      */
-    public $Timeout = 300;
+    public $Timeout = 10;
 
 
     /**
     /**
      * SMTP class debug output mode.
      * SMTP class debug output mode.