From 6fc864c947f85999056657b17dae14e4cd167ecb Mon Sep 17 00:00:00 2001
From: Fabrixxm <fabrix.xm@gmail.com>
Date: Thu, 25 Jun 2015 10:02:26 +0200
Subject: [PATCH] rework mod/ping and desktop notification logic

`mod/ping.php` returns all notifications ordered by date
mixing system notifications, private messages, intros, registrations
remove 'notify_full' mode
remove `&arr;` from unseen notes, 'seen' attrib now is "1" or "0"
new note attribute 'timestamp'
desktop notification logic use timestamp to check which notification show to the user
notification html template use timestamp to show full date to user in tooltip
`relative_date()` don't append full date on dates older than 24 hours
---
 include/datetime.php                      |   4 +-
 js/main.js                                |  13 +-
 mod/ping.php                              | 204 ++++++++++------------
 view/templates/nav.tpl                    |   2 +-
 view/theme/duepuntozero/templates/nav.tpl |   2 +-
 view/theme/quattro/templates/nav.tpl      |   2 +-
 view/theme/vier/templates/nav.tpl         |  38 +---
 7 files changed, 112 insertions(+), 153 deletions(-)

diff --git a/include/datetime.php b/include/datetime.php
index 8ac8ff0f29..6461298ba2 100644
--- a/include/datetime.php
+++ b/include/datetime.php
@@ -262,10 +262,12 @@ function relative_date($posted_date,$format = null) {
 		return t('less than a second ago');
 	}
     
+	/*
 	$time_append = '';
 	if ($etime >= 86400) {
 		$time_append = ' ('.$localtime.')';
 	}
+	*/
 	
 	$a = array( 12 * 30 * 24 * 60 * 60  =>  array( t('year'),   t('years')),
 				30 * 24 * 60 * 60       =>  array( t('month'),  t('months')),
@@ -283,7 +285,7 @@ function relative_date($posted_date,$format = null) {
 			// translators - e.g. 22 hours ago, 1 minute ago
 			if(! $format)
 				$format = t('%1$d %2$s ago');
-			return sprintf( $format,$r, (($r == 1) ? $str[0] : $str[1])).$time_append;
+			return sprintf( $format,$r, (($r == 1) ? $str[0] : $str[1]));
         }
     }
 }}
diff --git a/js/main.js b/js/main.js
index b812e25089..239a875cb4 100644
--- a/js/main.js
+++ b/js/main.js
@@ -186,13 +186,20 @@
 				var notification_id = 0;
 				eNotif.children("note").each(function(){
 					e = $(this);
-					text = e.text().format("<span class='contactname'>"+e.attr('name')+"</span>");
-					html = notifications_tpl.format(e.attr('href'),e.attr('photo'), text, e.attr('date'), e.attr('seen'));
+					var text = e.text().format("<span class='contactname'>"+e.attr('name')+"</span>");
+					var seenclass = (e.attr('seen')==1)?"notify-seen":"notify-unseen";
+					var html = notifications_tpl.format(e.attr('href'),
+						e.attr('photo'),                    // {0}
+						text,                               // {1}
+						e.attr('date'),                     // {2}
+						seenclass,                          // {3}
+						new Date(e.attr('timestamp')*1000)  // {4}
+					);
 					nnm.append(html);
 				});
 				$(eNotif.children("note").get().reverse()).each(function(){
 					e = $(this);
-					notification_id = parseInt(e.attr('href').match(/\d+$/)[0]);
+					notification_id = parseInt(e.attr('timestamp'));
 					if (notification_lastitem!== null && notification_id > notification_lastitem) {
 						if (getNotificationPermission()==="granted") {
 							var notification = new Notification(document.title, {
diff --git a/mod/ping.php b/mod/ping.php
index a5f23e1eb9..e87ed98553 100644
--- a/mod/ping.php
+++ b/mod/ping.php
@@ -21,9 +21,7 @@ function ping_init(&$a) {
 			killme();
 		}
 
-		$firehose = intval(get_pconfig(local_user(),'system','notify_full'));
-
-		$z = ping_get_notifications(local_user());
+		$notifs = ping_get_notifications(local_user());
 		$sysnotify = 0; // we will update this in a moment
 
 		$tags = array();
@@ -162,12 +160,23 @@ function ping_init(&$a) {
 		}
 
 
+		/**
+		 * return xml from notification array
+		 *
+		 * @param array $n Notification array:
+		 *		'href' => notification link
+		 *		'name' => subject name
+		 *		'url' => subject url
+		 *		'photo' => subject photo
+		 *		'date' => notification date
+		 *		'seen' => bool true/false
+		 *		'message' => notification message. "{0}" will be replaced by subject name
+		 **/
+		function xmlize($n){
+			$n['photo'] = proxy_url($n['photo']);
 
-		function xmlize($href, $name, $url, $photo, $date, $seen, $message){
-			$photo = proxy_url($photo);
-
-			$message = html_entity_decode($message, ENT_COMPAT | ENT_HTML401, "UTF-8");
-			$name = html_entity_decode($name, ENT_COMPAT | ENT_HTML401, "UTF-8");
+			$n['message'] = html_entity_decode($n['message'], ENT_COMPAT | ENT_HTML401, "UTF-8");
+			$n['name'] = html_entity_decode($n['name'], ENT_COMPAT | ENT_HTML401, "UTF-8");
 
 			// Are the nofications calles from the regular process or via the friendica app?
 			$regularnotifications = (intval($_GET['uid']) AND intval($_GET['_']));
@@ -175,13 +184,16 @@ function ping_init(&$a) {
 			$a = get_app();
 
 			if ($a->is_friendica_app() OR !$regularnotifications)
-				$message = str_replace("{0}", $name, $message);
+				$n['message'] = str_replace("{0}", $n['name'], $n['message']);
 
-			$data = array('href' => &$href, 'name' => &$name, 'url'=>&$url, 'photo'=>&$photo, 'date'=>&$date, 'seen'=>&$seen, 'messsage'=>&$message);
-			call_hooks('ping_xmlize', $data);
-			$notsxml = '<note href="%s" name="%s" url="%s" photo="%s" date="%s" seen="%s" >%s</note>'."\n";
+			$local_time = datetime_convert('UTC',date_default_timezone_get(),$n['date']); 
+				
+			call_hooks('ping_xmlize', $n);
+			$notsxml = '<note href="%s" name="%s" url="%s" photo="%s" date="%s" seen="%s" timestamp="%s" >%s</note>'."\n";
 			return sprintf ( $notsxml,
-				xmlify($href), xmlify($name), xmlify($url), xmlify($photo), xmlify($date), xmlify($seen), xmlify($message)
+				xmlify($n['href']), xmlify($n['name']), xmlify($n['url']), xmlify($n['photo']),
+				xmlify(relative_date($n['date'])), xmlify($n['seen']), xmlify(strtotime($local_time)),
+				xmlify($n['message'])
 			);
 		}
 
@@ -198,98 +210,78 @@ function ping_init(&$a) {
 			<birthdays>$birthdays</birthdays>
 			<birthdays-today>$birthdays_today</birthdays-today>\r\n";
 
-		$tot = $mail+$intro+$register+count($comments)+count($likes)+count($dislikes)+count($friends)+count($posts)+count($tags);
 
-		if($firehose) {
-			echo '	<notif count="'.$tot.'">';
-		}
-		else {
-			if(count($z) && (! $sysnotify)) {
-				foreach($z as $zz) {
-					if($zz['seen'] == 0)
-						$sysnotify ++;
-				}
-			}
-
-			echo '	<notif count="'. ($sysnotify + $intro + $mail + $register) .'">';
-
-			if ($intro>0){
-				foreach ($intros as $i) {
-					echo xmlize($a->get_baseurl().'/notifications/intros/'.$i['id'], $i['name'], $i['url'], $i['photo'], relative_date($i['datetime']), 'notify-unseen', t("{0} wants to be your friend"));
-				};
-			}
-			if ($mail>0){
-				foreach ($mails as $i) {
-					echo xmlize($a->get_baseurl().'/message/'.$i['id'], $i['from-name'], $i['from-url'], $i['from-photo'], relative_date($i['created']), 'notify-unseen', t("{0} sent you a message"));
-				};
-			}
-			if ($register>0){
-				foreach ($regs as $i) {
-					echo xmlize($a->get_baseurl().'/admin/users/', $i['name'], $i['url'], $i['micro'], relative_date($i['created']), 'notify-unseen', t("{0} requested registration"));
-				};
-			}
-
-			if(count($z)) {
-				foreach($z as $zz) {
-					echo xmlize($a->get_baseurl() . '/notify/view/' . $zz['id'], $zz['name'],$zz['url'],$zz['photo'],relative_date($zz['date']), ($zz['seen'] ? 'notify-seen' : 'notify-unseen'), strip_tags(bbcode($zz['msg'])));
-				}
+		if(count($notifs) && (! $sysnotify)) {
+			foreach($notifs as $zz) {
+				if($zz['seen'] == 0)
+					$sysnotify ++;
 			}
 		}
 
-		if($firehose) {
-			if ($intro>0){
-				foreach ($intros as $i) {
-					echo xmlize( $a->get_baseurl().'/notifications/intros/'.$i['id'], $i['name'], $i['url'], $i['photo'], relative_date($i['datetime']), 'notify-unseen',t("{0} wants to be your friend") );
-				};
-			}
-			if ($mail>0){
-				foreach ($mails as $i) {
-					echo xmlize( $a->get_baseurl().'/message/'.$i['id'], $i['from-name'], $i['from-url'], $i['from-photo'], relative_date($i['created']), 'notify-unseen',t("{0} sent you a message") );
-				};
-			}
-			if ($register>0){
-				foreach ($regs as $i) {
-					echo xmlize( $a->get_baseurl().'/admin/users/', $i['name'], $i['url'], $i['micro'], relative_date($i['created']), 'notify-unseen',t("{0} requested registration") );
-				};
-			}
+		echo '	<notif count="'. ($sysnotify + $intro + $mail + $register) .'">';
 
-			if (count($comments)){
-				foreach ($comments as $i) {
-					echo xmlize( $a->get_baseurl().'/display/'.$a->user['nickname']."/".$i['parent'], $i['author-name'], $i['author-link'], $i['author-avatar'], relative_date($i['created']), 'notify-unseen',sprintf( t("{0} commented %s's post"), $i['pname'] ) );
-				};
-			}
-			if (count($likes)){
-				foreach ($likes as $i) {
-					echo xmlize( $a->get_baseurl().'/display/'.$a->user['nickname']."/".$i['parent'], $i['author-name'], $i['author-link'], $i['author-avatar'], relative_date($i['created']), 'notify-unseen',sprintf( t("{0} liked %s's post"), $i['pname'] ) );
-				};
-			}
-			if (count($dislikes)){
-				foreach ($dislikes as $i) {
-					echo xmlize( $a->get_baseurl().'/display/'.$a->user['nickname']."/".$i['parent'], $i['author-name'], $i['author-link'], $i['author-avatar'], relative_date($i['created']), 'notify-unseen',sprintf( t("{0} disliked %s's post"), $i['pname'] ) );
-				};
-			}
-			if (count($friends)){
-				foreach ($friends as $i) {
-					echo xmlize($a->get_baseurl().'/display/'.$a->user['nickname']."/".$i['parent'],$i['author-name'],$i['author-link'], $i['author-avatar'], relative_date($i['created']), 'notify-unseen',sprintf( t("{0} is now friends with %s"), $i['fname'] ) );
-				};
-			}
-			if (count($posts)){
-				foreach ($posts as $i) {
-					echo xmlize( $a->get_baseurl().'/display/'.$a->user['nickname']."/".$i['parent'], $i['author-name'], $i['author-link'], $i['author-avatar'], relative_date($i['created']), 'notify-unseen',sprintf( t("{0} posted") ) );
-				};
-			}
-			if (count($tags)){
-				foreach ($tags as $i) {
-					echo xmlize( $a->get_baseurl().'/display/'.$a->user['nickname']."/".$i['parent'], $i['author-name'], $i['author-link'], $i['author-avatar'], relative_date($i['created']), 'notify-unseen',sprintf( t("{0} tagged %s's post with #%s"), $i['pname'], $i['tname'] ) );
-				};
-			}
-
-			if (count($cit)){
-				foreach ($cit as $i) {
-					echo xmlize( $a->get_baseurl().'/display/'.$a->user['nickname']."/".$i['parent'], $i['author-name'], $i['author-link'], $i['author-avatar'], relative_date($i['created']), 'notify-unseen',t("{0} mentioned you in a post") );
-				};
+		// merge all notification types in one array
+		if ($intro>0){
+			foreach ($intros as $i) {
+				$n = array(
+					'href' => $a->get_baseurl().'/notifications/intros/'.$i['id'],
+					'name' => $i['name'],
+					'url' => $i['url'], 
+					'photo' => $i['photo'],
+					'date' => $i['datetime'],
+					'seen' => false,
+					'message' => t("{0} wants to be your friend"),				
+				);
+				$notifs[] = $n;
 			}
 		}
+		
+		if ($mail>0){
+			foreach ($mails as $i) {
+				$n = array(
+					'href' => $a->get_baseurl().'/message/'.$i['id'],
+					'name' => $i['from-name'],
+					'url' => $i['from-url'], 
+					'photo' => $i['from-photo'],
+					'date' => $i['created'],
+					'seen' => false,
+					'message' => t("{0} sent you a message"),				
+				);
+				$notifs[] = $n;
+			}
+		}
+		
+		if ($register>0){
+			foreach ($regs as $i) {
+				$n = array(
+					'href' => $a->get_baseurl().'/admin/users/',
+					'name' => $i['name'],
+					'url' => $i['url'], 
+					'photo' => $i['micro'],
+					'date' => $i['created'],
+					'seen' => false,
+					'message' => t("{0} requested registration"),				
+				);
+				$notifs[] = $n;
+			}
+		}
+		// sort notifications by $[]['date']
+		$sort_function = function($a, $b) {
+			$adate = date($a['date']);
+			$bdate = date($b['date']);
+			if ($adate == $bdate) {
+				return 0;
+			}
+			return ($adate < $bdate) ? 1 : -1;
+		};
+		usort($notifs, $sort_function);
+
+		if(count($notifs)) {
+			foreach($notifs as $n) {
+				echo xmlize($n);
+			}
+		}
+
 
 		echo "  </notif>";
 	}
@@ -359,16 +351,18 @@ function ping_get_notifications($uid) {
 			if (is_null($notification["deleted"]))
 				$notification["deleted"] = 0;
 
-			$notification["msg"] = strip_tags(bbcode($notification["msg"]));
+			$notification["message"] = strip_tags(bbcode($notification["msg"]));
 			$notification["name"] = strip_tags(bbcode($notification["name"]));
 
 			// Replace the name with {0} but ensure to make that only once
 			// The {0} is used later and prints the name in bold.
 
-			$pos = strpos($notification["msg"],$notification['name']);
+			$pos = strpos($notification["message"],$notification['name']);
 			if ($pos !== false)
-				$notification["msg"] = substr_replace($notification["msg"],"{0}",$pos,strlen($notification["name"]));
+				$notification["message"] = substr_replace($notification["message"],"{0}",$pos,strlen($notification["name"]));
 
+			$notification['href'] = $a->get_baseurl() . '/notify/view/' . $notification['id'];
+				
 			if ($notification["visible"] AND !$notification["spam"] AND
 				!$notification["deleted"] AND !is_array($result[$notification["parent"]])) {
 				$result[$notification["parent"]] = $notification;
@@ -377,14 +371,6 @@ function ping_get_notifications($uid) {
 
 	} while ((count($result) < 50) AND !$quit);
 
-	// sort result by $[]['id'], inversed
-	$sort_function = function($a, $b) {
-		if ($a['id'] == $b['id']) {
-			return 0;
-		}
-		return ($a['id'] < $b['id']) ? 1 : -1;
-	};
-	usort($result, $sort_function);
 	
 	return($result);
 }
diff --git a/view/templates/nav.tpl b/view/templates/nav.tpl
index 3a54066ad1..02fe6da3b9 100644
--- a/view/templates/nav.tpl
+++ b/view/templates/nav.tpl
@@ -65,5 +65,5 @@
 </nav>
 
 <ul id="nav-notifications-template" style="display:none;" rel="template">
-	<li class="{4}"><a href="{0}"><img data-src="{1}" height="24" width="24" alt="" />{2} <span class="notif-when">{3}</span></a></li>
+	<li class="{4}"><a href="{0}" title="{5}"><img data-src="{1}" height="24" width="24" alt="" />{2} <span class="notif-when">{3}</span></a></li>
 </ul>
diff --git a/view/theme/duepuntozero/templates/nav.tpl b/view/theme/duepuntozero/templates/nav.tpl
index 3e821a31c3..8149ef374c 100644
--- a/view/theme/duepuntozero/templates/nav.tpl
+++ b/view/theme/duepuntozero/templates/nav.tpl
@@ -67,5 +67,5 @@
 </nav>
 
 <ul id="nav-notifications-template" style="display:none;" rel="template">
-	<li class="{4}"><a href="{0}"><img data-src="{1}" height="24" width="24" alt="" />{2} <span class="notif-when">{3}</span></a></li>
+	<li class="{4}"><a href="{0}" title="{5}"><img data-src="{1}" height="24" width="24" alt="" />{2} <span class="notif-when">{3}</span></a></li>
 </ul>
diff --git a/view/theme/quattro/templates/nav.tpl b/view/theme/quattro/templates/nav.tpl
index c77ed99e45..e0c7ba8e3b 100644
--- a/view/theme/quattro/templates/nav.tpl
+++ b/view/theme/quattro/templates/nav.tpl
@@ -109,7 +109,7 @@
 
 </nav>
 <ul id="nav-notifications-template" style="display:none;" rel="template">
-	<li class="{4}"><a href="{0}"><img data-src="{1}">{2} <span class="notif-when">{3}</span></a></li>
+	<li class="{4}"><a href="{0}" title="{5}"><img data-src="{1}">{2} <span class="notif-when">{3}</span></a></li>
 </ul>
 
 <div style="position: fixed; top: 3px; left: 5px; z-index:9999">{{$langselector}}</div>
diff --git a/view/theme/vier/templates/nav.tpl b/view/theme/vier/templates/nav.tpl
index 4ef6400809..26b34073a6 100644
--- a/view/theme/vier/templates/nav.tpl
+++ b/view/theme/vier/templates/nav.tpl
@@ -97,44 +97,8 @@
 
 </nav>
 <ul id="nav-notifications-template" style="display:none;" rel="template">
-	<li class="{4}"><a href="{0}"><img data-src="{1}">{2} <span class="notif-when">{3}</span></a></li>
+	<li class="{4}"><a href="{0}" title="{5}"><img data-src="{1}">{2} <span class="notif-when">{3}</span></a></li>
 </ul>
 <!--
 <div class="icon-flag" style="position: fixed; bottom: 10px; left: 20px; z-index:9;">{{$langselector}}</div>
 -->
-{{*
-
-{{if $nav.logout}}<a id="nav-logout-link" class="nav-link {{$nav.logout.2}}" href="{{$nav.logout.0}}" title="{{$nav.logout.3}}" >{{$nav.logout.1}}</a> {{/if}}
-{{if $nav.login}}<a id="nav-login-link" class="nav-login-link {{$nav.login.2}}" href="{{$nav.login.0}}" title="{{$nav.login.3}}" >{{$nav.login.1}}</a> {{/if}}
-
-<span id="nav-link-wrapper" >
-
-{{if $nav.register}}<a id="nav-register-link" class="nav-commlink {{$nav.register.2}}" href="{{$nav.register.0}}" title="{{$nav.register.3}}" >{{$nav.register.1}}</a>{{/if}}
-
-<a id="nav-help-link" class="nav-link {{$nav.help.2}}" target="friendica-help" href="{{$nav.help.0}}" title="{{$nav.help.3}}" >{{$nav.help.1}}</a>
-	
-{{if $nav.apps}}<a id="nav-apps-link" class="nav-link {{$nav.apps.2}}" href="{{$nav.apps.0}}" title="{{$nav.apps.3}}" >{{$nav.apps.1}}</a>{{/if}}
-
-<a id="nav-search-link" class="nav-link {{$nav.search.2}}" href="{{$nav.search.0}}" title="{{$nav.search.3}}" >{{$nav.search.1}}</a>
-<a id="nav-directory-link" class="nav-link {{$nav.directory.2}}" href="{{$nav.directory.0}}" title="{{$nav.directory.3}}" >{{$nav.directory.1}}</a>
-
-{{if $nav.admin}}<a id="nav-admin-link" class="nav-link {{$nav.admin.2}}" href="{{$nav.admin.0}}" title="{{$nav.admin.3}}" >{{$nav.admin.1}}</a>{{/if}}
-
-{{if $nav.notifications}}
-<a id="nav-notify-link" class="nav-commlink {{$nav.notifications.2}}" href="{{$nav.notifications.0}}" title="{{$nav.notifications.3}}" >{{$nav.notifications.1}}</a>
-<span id="notify-update" class="nav-ajax-left"></span>
-{{/if}}
-{{if $nav.messages}}
-<a id="nav-messages-link" class="nav-commlink {{$nav.messages.2}}" href="{{$nav.messages.0}}" title="{{$nav.messages.3}}" >{{$nav.messages.1}}</a>
-<span id="mail-update" class="nav-ajax-left"></span>
-{{/if}}
-
-{{if $nav.manage}}<a id="nav-manage-link" class="nav-commlink {{$nav.manage.2}}" href="{{$nav.manage.0}}" title="{{$nav.manage.3}}">{{$nav.manage.1}}</a>{{/if}}
-{{if $nav.settings}}<a id="nav-settings-link" class="nav-link {{$nav.settings.2}}" href="{{$nav.settings.0}}" title="{{$nav.settings.3}}">{{$nav.settings.1}}</a>{{/if}}
-{{if $nav.profiles}}<a id="nav-profiles-link" class="nav-link {{$nav.profiles.2}}" href="{{$nav.profiles.0}}" title="{{$nav.profiles.3}}" >{{$nav.profiles.1}}</a>{{/if}}
-
-
-</span>
-<span id="nav-end"></span>
-<span id="banner">{{$banner}}</span>
-*}}