Browse Source

Added Base/Notify module

tags/v1.6.3
Georgi Hristov 7 years ago
parent
commit
7d42fdaadc
11 changed files with 508 additions and 6 deletions
  1. +3
    -1
      .gitignore
  2. +5
    -2
      modules/Apps/Shoutbox/ShoutboxCommon_0.php
  3. +82
    -0
      modules/Base/Notify/NotifyCommon_0.php
  4. +56
    -0
      modules/Base/Notify/NotifyInstall.php
  5. +33
    -0
      modules/Base/Notify/Notify_0.php
  6. +205
    -0
      modules/Base/Notify/js/desktop-notify.js
  7. +48
    -0
      modules/Base/Notify/js/main.js
  8. +65
    -0
      modules/Base/Notify/refresh.php
  9. BIN
      modules/Base/Notify/theme/icon.png
  10. +4
    -1
      modules/Utils/Messenger/MessengerCommon_0.php
  11. +7
    -2
      modules/Utils/Watchdog/WatchdogCommon_0.php

+ 3
- 1
.gitignore View File

@@ -18,4 +18,6 @@ modules/*
!modules/Utils

# IDE dirs/files
.idea
.idea
Thumbs.db

+ 5
- 2
modules/Apps/Shoutbox/ShoutboxCommon_0.php View File

@@ -54,16 +54,19 @@ class Apps_ShoutboxCommon extends ModuleCommon {
public static function tray_notification($time) {
if(!$time)
$time = time()-24*3600;
$arr = DB::GetAll('SELECT ul.login, asm.id, asm.message, asm.posted_on FROM apps_shoutbox_messages asm LEFT JOIN user_login ul ON ul.id=asm.base_user_login_id WHERE asm.posted_on>=%T AND asm.base_user_login_id!=%d AND (asm.to_user_login_id=%d OR asm.to_user_login_id is null) ORDER BY asm.posted_on DESC LIMIT 10',array($time, Base_AclCommon::get_user(), Base_AclCommon::get_user()));
$arr = DB::GetAll('SELECT ul.login, ul.id as user_id, asm.id, asm.message, asm.posted_on FROM apps_shoutbox_messages asm LEFT JOIN user_login ul ON ul.id=asm.base_user_login_id WHERE asm.posted_on>=%T AND asm.base_user_login_id!=%d AND (asm.to_user_login_id=%d OR asm.to_user_login_id is null) ORDER BY asm.posted_on DESC LIMIT 10',array($time, Base_AclCommon::get_user(), Base_AclCommon::get_user()));
if(empty($arr)) return array();
//print it out
$ret = array();
$tray = array();
foreach($arr as $row) {
if(!$row['login']) $row['login']='Anonymous';
$ret['shoutbox_'.$row['id']] = vsprintf('<font color="gray">[%s]</font><font color="blue">%s</font>: %s',array(Base_RegionalSettingsCommon::time2reg($row['posted_on']), $row['login'], $row['message']));
$tray['shoutbox_'.$row['id']] = array('title'=>__('Shoutbox - New Message'), 'body'=>__('You have new message by %s', array(Base_UserCommon::get_user_label($row['user_id'], true))));
}

return array('notifications'=>$ret);
return array('notifications'=>$ret, 'tray'=>$tray);
}

public static function user_settings(){


+ 82
- 0
modules/Base/Notify/NotifyCommon_0.php View File

@@ -0,0 +1,82 @@
<?php
/**
*
* @author Georgi Hristov <ghristov@gmx.de>
* @copyright Copyright &copy; 2014, Xoff Software GmbH
* @license MIT
* @version 1.0
* @package epesi-notify
*
*/

defined("_VALID_ACCESS") || die('Direct access forbidden');

class Base_NotifyCommon extends ModuleCommon {
public static function strip_html ($text) {
return str_replace('&nbsp;',' ',htmlspecialchars_decode(strip_tags(preg_replace('/\<[Bb][Rr]\/?\>/',"\n",$text))));
}

public static function user_settings(){
$caller = debug_backtrace();

if (isset($caller[2]['function']) && $caller[2]['function']=='get_default')
Base_ActionBarCommon::add(Base_ThemeCommon::get_template_file('Base_Notify', 'icon.png'),__('Browser Settings'), 'onClick="Base_Notify__notify (\'Notification\', {body: \'enabled\', icon: \''.self::get_icon('Base_Notify').'\'}, true);"', __('Click to set browser settings for tray notifications'));
$ret = array(
array('name'=>null,'label'=>__('General'),'type'=>'header'),
array('name'=>'general_timeout','label'=>__('Close Message Timeout'),'type'=>'select','values'=>Utils_CommonDataCommon::get_translated_array('Base_TrayNotify/Timeout', true),'default'=>0),
array('name'=>'general_group','label'=>__('Group Similar Notifications'),'type'=>'checkbox','default'=>1),

array('name'=>null,'label'=>__('Module Specific Timeout'),'type'=>'header')
);

$modules = array_keys(self::get_notifications());

foreach ($modules as $module) {
$label = self::get_module_caption($module);

$ret = array_merge($ret, array(array('name'=>$module.'_timeout','label'=>$label,'type'=>'select','values'=>array(-2=>_M('Use general setting')) + Utils_CommonDataCommon::get_translated_array('Base_TrayNotify/Timeout', true),'default'=>-2)));
}

return array(__('Notify')=>$ret);
}
public static function get_notifications() {
return ModuleManager::call_common_methods('tray_notification',false, array(time()-Base_Notify::reset_time*3600));
}
public static function get_module_caption($module) {
$module = rtrim($module, 'Common');
if (is_callable($module.'Common::caption')) {
$caption = call_user_func($module.'Common::caption');
}
elseif (is_callable($module.'Common::applet_caption')) {
$caption = call_user_func($module.'Common::applet_caption');
}
else $caption = $module;

return $caption;
}

public static function get_general_setting() {
return Base_User_SettingsCommon::get('Base_Notify', 'general_timeout');
}

public static function group_similar() {
return Base_User_SettingsCommon::get('Base_Notify', 'general_group')==1;
}

public static function get_module_setting($module) {
$module = rtrim($module);
$module_setting = Base_User_SettingsCommon::get('Base_Notify', $module.'_timeout');

return ($module_setting == -2) ? self::get_general_setting(): $module_setting;
}

public static function get_icon($module, $message = null) {
$icon = Base_ThemeCommon::get_template_file($module, isset($message['icon']) ? $message['icon']:'icon.png');
return isset($icon)? $icon: Base_ThemeCommon::get_template_file('Base_Notify', 'icon.png');
}
}

?>

+ 56
- 0
modules/Base/Notify/NotifyInstall.php View File

@@ -0,0 +1,56 @@
<?php
/**
* @author Georgi Hristov <ghristov@gmx.de>
* @copyright Copyright &copy; 2014, Xoff Software GmbH
* @license MIT
* @version 1.0
* @package epesi-notify
*/
defined("_VALID_ACCESS") || die('Direct access forbidden');

class Base_NotifyInstall extends ModuleInstall {
const version = '1.0';

public function install() {
Base_ThemeCommon::install_default_theme($this->get_type());

$box_ini_file = Base_ThemeCommon::get_template_file('Base/Box', 'default.ini');
$ini_setting = PHP_EOL.'[notify]'.PHP_EOL.'module = "Base/Notify"'.PHP_EOL.'display = "logged"';
file_put_contents($box_ini_file, $ini_setting, FILE_APPEND);

Utils_CommonDataCommon::new_array('Base_TrayNotify/Timeout', array(-1=>_M('Disable Notification'), 0=>_M('Manually'), 10000=>_M('10 seconds'), 30000=>_M('30 seconds'), 60000=>_M('1 minute')), true, true);
return true;
}

public function uninstall() {
Base_ThemeCommon::uninstall_default_theme($this->get_type());
return true;
}

public function version() {
return array(self::version);
}

public function requires($v) {
return array(
array('name'=>'Base/Acl','version'=>0),
array('name'=>'Base/User','version'=>0),
array('name'=>'Base/Theme','version'=>0),
array('name'=>'Libs/QuickForm','version'=>0));
}

public static function info() {
$html="Pops up tray notification in the OS";
return array(
'Description'=>$html,
'Author'=>'<a href="mailto:ghristov@gmx.de">Georgi Hristov</a>',
'License'=>'MIT');
}

public static function simple_setup() {
return array('package'=>__('EPESI Core'), 'option'=>__('Web Notifications'), 'version'=>self::version);
}

}

?>

+ 33
- 0
modules/Base/Notify/Notify_0.php View File

@@ -0,0 +1,33 @@
<?php
/**
*
* @author Georgi Hristov <ghristov@gmx.de>
* @copyright Copyright &copy; 2014, Xoff Software GmbH
* @license MIT
* @version 1.0
* @package epesi-notify
*
*/

defined("_VALID_ACCESS") || die('Direct access forbidden');

class Base_Notify extends Module {
//interval to poll for new notifications
const refresh_rate = 30; //seconds
//interval at which to look back in time
const reset_time = 24; //hours

public function body() {
$this->load_js();
}

private function load_js() {
load_js('modules/Base/Notify/js/desktop-notify.js');
load_js('modules/Base/Notify/js/main.js');

eval_js("if (notify.isSupported) var Base_Notify__interval = setInterval(function () {Base_Notify__refresh('".CID."');}, ".(self::refresh_rate*1000).");");

eval_js('function Base_Notify__alert () {alert(\''.__('Notifications disabled or not supported!').'\n'.__('Check your browser settings...').'\');}');
}
}
?>

+ 205
- 0
modules/Base/Notify/js/desktop-notify.js View File

@@ -0,0 +1,205 @@
/**
* Copyright 2012 Tsvetan Tsvetkov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Tsvetan Tsvetkov (tsekach@gmail.com)
*/
(function (win) {
/*
Safari native methods required for Notifications do NOT run in strict mode.
*/
//"use strict";
var PERMISSION_DEFAULT = "default",
PERMISSION_GRANTED = "granted",
PERMISSION_DENIED = "denied",
PERMISSION = [PERMISSION_GRANTED, PERMISSION_DEFAULT, PERMISSION_DENIED],
defaultSetting = {
pageVisibility: false,
autoClose: 0
},
empty = {},
emptyString = "",
isSupported = (function () {
var isSupported = false;
/*
* Use try {} catch() {} because the check for IE may throws an exception
* if the code is run on browser that is not Safar/Chrome/IE or
* Firefox with html5notifications plugin.
*
* Also, we canNOT detect if msIsSiteMode method exists, as it is
* a method of host object. In IE check for existing method of host
* object returns undefined. So, we try to run it - if it runs
* successfully - then it is IE9+, if not - an exceptions is thrown.
*/
try {
isSupported = !!(/* Safari, Chrome */win.Notification || /* Chrome & ff-html5notifications plugin */win.webkitNotifications || /* Firefox Mobile */navigator.mozNotification || /* IE9+ */(win.external && win.external.msIsSiteMode() !== undefined));
} catch (e) {}
return isSupported;
}()),
ieVerification = Math.floor((Math.random() * 10) + 1),
isFunction = function (value) { return (value && (value).constructor === Function); },
isString = function (value) {return (value && (value).constructor === String); },
isObject = function (value) {return (value && (value).constructor === Object); },
/**
* Dojo Mixin
*/
mixin = function (target, source) {
var name, s;
for (name in source) {
s = source[name];
if (!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))) {
target[name] = s;
}
}
return target; // Object
},
noop = function () {},
settings = defaultSetting;
function getNotification(title, options) {
var notification;
if (win.Notification) { /* Safari 6, Chrome (23+) */
notification = new win.Notification(title, {
/* The notification's icon - For Chrome in Windows, Linux & Chrome OS */
icon: isString(options.icon) ? options.icon : options.icon.x32,
/* The notification’s subtitle. */
body: options.body || emptyString,
/*
The notification’s unique identifier.
This prevents duplicate entries from appearing if the user has multiple instances of your website open at once.
*/
tag: options.tag || emptyString
});
} else if (win.webkitNotifications) { /* FF with html5Notifications plugin installed */
notification = win.webkitNotifications.createNotification(options.icon, title, options.body);
notification.show();
} else if (navigator.mozNotification) { /* Firefox Mobile */
notification = navigator.mozNotification.createNotification(title, options.body, options.icon);
notification.show();
} else if (win.external && win.external.msIsSiteMode()) { /* IE9+ */
//Clear any previous notifications
win.external.msSiteModeClearIconOverlay();
win.external.msSiteModeSetIconOverlay((isString(options.icon) ? options.icon : options.icon.x16), title);
win.external.msSiteModeActivate();
notification = {
"ieVerification": ieVerification + 1
};
}
return notification;
}
function getWrapper(notification) {
return {
close: function () {
if (notification) {
if (notification.close) {
//http://code.google.com/p/ff-html5notifications/issues/detail?id=58
notification.close();
}
else if (notification.cancel) {
notification.cancel();
} else if (win.external && win.external.msIsSiteMode()) {
if (notification.ieVerification === ieVerification) {
win.external.msSiteModeClearIconOverlay();
}
}
}
}
};
}
function requestPermission(callback) {
if (!isSupported) { return; }
var callbackFunction = isFunction(callback) ? callback : noop;
if (win.webkitNotifications && win.webkitNotifications.checkPermission) {
/*
* Chrome 23 supports win.Notification.requestPermission, but it
* breaks the browsers, so use the old-webkit-prefixed
* win.webkitNotifications.checkPermission instead.
*
* Firefox with html5notifications plugin supports this method
* for requesting permissions.
*/
win.webkitNotifications.requestPermission(callbackFunction);
} else if (win.Notification && win.Notification.requestPermission) {
win.Notification.requestPermission(callbackFunction);
}
}
function permissionLevel() {
var permission;
if (!isSupported) { return; }
if (win.Notification && win.Notification.permissionLevel) {
//Safari 6
permission = win.Notification.permissionLevel();
} else if (win.webkitNotifications && win.webkitNotifications.checkPermission) {
//Chrome & Firefox with html5-notifications plugin installed
permission = PERMISSION[win.webkitNotifications.checkPermission()];
} else if (win.Notification && win.Notification.permission) {
// Firefox 23+
permission = win.Notification.permission;
} else if (navigator.mozNotification) {
//Firefox Mobile
permission = PERMISSION_GRANTED;
} else if (win.external && (win.external.msIsSiteMode() !== undefined)) { /* keep last */
//IE9+
permission = win.external.msIsSiteMode() ? PERMISSION_GRANTED : PERMISSION_DEFAULT;
}
return permission;
}
/**
*
*/
function config(params) {
if (params && isObject(params)) {
mixin(settings, params);
}
return settings;
}
function isDocumentHidden() {
return settings.pageVisibility ? (document.hidden || document.msHidden || document.mozHidden || document.webkitHidden) : true;
}
function createNotification(title, options) {
var notification,
notificationWrapper;
/*
Return undefined if notifications are not supported.
Return undefined if no permissions for displaying notifications.
Title and icons are required. Return undefined if not set.
*/
if (isSupported && isDocumentHidden() && isString(title) && (options && (isString(options.icon) || isObject(options.icon))) && (permissionLevel() === PERMISSION_GRANTED)) {
notification = getNotification(title, options);
}
notificationWrapper = getWrapper(notification);
//Auto-close notification
if (settings.autoClose && notification && !notification.ieVerification && notification.addEventListener) {
notification.addEventListener("show", function () {
var notification = notificationWrapper;
win.setTimeout(function () {
notification.close();
}, settings.autoClose);
});
}
return notificationWrapper;
}
win.notify = {
PERMISSION_DEFAULT: PERMISSION_DEFAULT,
PERMISSION_GRANTED: PERMISSION_GRANTED,
PERMISSION_DENIED: PERMISSION_DENIED,
isSupported: isSupported,
config: config,
createNotification: createNotification,
permissionLevel: permissionLevel,
requestPermission: requestPermission
};
if (isFunction(Object.seal)) {
Object.seal(win.notify);
}
}(window));

+ 48
- 0
modules/Base/Notify/js/main.js View File

@@ -0,0 +1,48 @@
function Base_Notify__refresh (cid, pileup) {
if (Base_Notify__disable_refresh(false)) return;

pileup = pileup || 1;
jq.getJSON('modules/Base/Notify/refresh.php?cid='+cid, function(json){
if (typeof json === 'undefined' || jq.isEmptyObject(json)) return;
if (Base_Notify__disable_refresh(typeof json.disable !== 'undefined')) return;

if (typeof json.timeout !== 'undefined') notify.config({pageVisibility: false, autoClose: json.timeout});
Base_Notify__notify(json.title, json.opts);

if (typeof json.pileup !== 'undefined' && json.pileup >= 1 && pileup < 3) {
Base_Notify__refresh (cid, pileup+1);
return;
}
});
}

function Base_Notify__notify (title, opts, check) {
if (Base_Notify__disable_refresh(false, check)) return;

if (notify.permissionLevel() === notify.PERMISSION_DEFAULT) {
notify.requestPermission(function (permission) {
if (permission === notify.PERMISSION_GRANTED) {
var n = notify.createNotification(title, opts);
}
});
}
else if (notify.permissionLevel() === notify.PERMISSION_GRANTED) {
var n = notify.createNotification(title, opts);
}
}

function Base_Notify__disable_refresh (force, check) {
disable = !notify.isSupported || (notify.permissionLevel() === notify.PERMISSION_DENIED);

if (disable && check) Base_Notify__alert();

if (disable || force) {
clearInterval(Base_Notify__interval);
Base_Notify__interval = 0;
}

return disable || force;
}




+ 65
- 0
modules/Base/Notify/refresh.php View File

@@ -0,0 +1,65 @@
<?php
/**
*
* @author Georgi Hristov <ghristov@gmx.de>
* @copyright Copyright &copy; 2014, Xoff Software GmbH
* @license MIT
* @version 1.0
* @package epesi-notify
*
*/

ob_start();
define('CID',$_REQUEST['cid']);
require_once('../../../include.php');
ModuleManager::load_modules();

if(!Base_AclCommon::is_user())
exit();

$general_setting = Base_NotifyCommon::get_general_setting();

if ($general_setting == -1) {
echo json_encode(array('disable'=>1));
exit();
}
//unset($_SESSION['Base_Notify']);
$ret = null;
$pileup = -1;
$group_similar = Base_NotifyCommon::group_similar();
$notifications = Base_NotifyCommon::get_notifications();

foreach ($notifications as $module=>$notify) {
$timeout = Base_NotifyCommon::get_module_setting($module);
if ($timeout == -1) continue;

foreach ($notify['tray'] as $id=>$message) {
if (isset($_SESSION['Base_Notify']['notified_cache'][$module][$id])) continue;
$pileup++;
if ($pileup>=1 && !$group_similar) break;

$_SESSION['Base_Notify']['notified_cache'][$module][$id] = 1;

$title = EPESI.' '.Base_NotifyCommon::strip_html($message['title']);
$body = Base_NotifyCommon::strip_html($message['body']);
$icon = Base_NotifyCommon::get_icon($module, $message);
}

if (($pileup>=0 && !$group_similar) || $pileup == 0) break;
if ($pileup == -1) continue;
$title = EPESI.' '.__('Module %s', array(Base_NotifyCommon::get_module_caption($module)));
$body = __('%d new notifications', array($pileup+1));
break;
}

if (!isset($title) || !isset($icon)) {
exit();
}

$ret = array('title'=>$title, 'opts'=>array('body'=>$body, 'icon'=>$icon), 'timeout'=>$timeout, 'pileup'=>$pileup);

if (isset($ret))
echo json_encode($ret);

exit();
?>

BIN
modules/Base/Notify/theme/icon.png View File

Before After
Width: 32  |  Height: 32  |  Size: 2.1 KiB

+ 4
- 1
modules/Utils/Messenger/MessengerCommon_0.php View File

@@ -60,13 +60,16 @@ class Utils_MessengerCommon extends ModuleCommon {
public static function tray_notification() {
$arr = DB::GetAll('SELECT m.* FROM utils_messenger_message m INNER JOIN utils_messenger_users u ON u.message_id=m.id WHERE u.user_login_id=%d AND u.done=0 AND m.alert_on<%T',array(Acl::get_user(),time()));
$ret = array();
$tray = array();
foreach($arr as $row) {
ob_start();
$m = call_user_func_array(unserialize($row['callback_method']),unserialize($row['callback_args']));
ob_clean();
$ret['messenger_'.$row['id']] = __('Alert on: %s',array(Base_RegionalSettingsCommon::time2reg($row['alert_on'])))."<br>".str_replace("\n",'<br>',$m).($row['message']?"<br>".__('Alarm comment: %s',array($row['message'])):'');
$tray['messenger_'.$row['id']] = array('title'=>__('Messenger - %s', array($row['message'])), 'body'=>$m);
}
return array('alerts'=>$ret);
return array('alerts'=>$ret, 'tray'=>$tray);
}
public static function user_settings(){


+ 7
- 2
modules/Utils/Watchdog/WatchdogCommon_0.php View File

@@ -301,16 +301,21 @@ class Utils_WatchdogCommon extends ModuleCommon {
$only_new = ' AND last_seen_event<(SELECT MAX(id) FROM utils_watchdog_event AS uwe WHERE uwe.internal_id=uws.internal_id AND uwe.category_id=uws.category_id)';
$records = DB::GetAll('SELECT internal_id,category_id,last_seen_event FROM utils_watchdog_subscription AS uws WHERE user_id=%d '.$only_new, array(Acl::get_user()));
$ret = array();
$tray = array();
foreach ($records as $v) {
$changes = Utils_WatchdogCommon::check_if_notified($v['category_id'], $v['internal_id']);
if (!is_array($changes)) $changes = array();
$data = call_user_func($methods[$v['category_id']], $v['internal_id'], $changes, false);
if ($data==null) continue;
$ret['watchdog_'.$v['internal_id'].'_'.$v['category_id'].'_'.$v['last_seen_event']] = '<b>'.__('Watchdog - %s', array($data['category'])).':</b> '.$data['title'];
if (isset($data['events']) && $data['events'])
$tray['watchdog_'.$v['internal_id'].'_'.$v['category_id'].'_'.$v['last_seen_event']] = array('title'=>__('Watchdog - %s', array($data['category'])), 'body'=>$data['title']);
if (isset($data['events']) && $data['events']) {
$ret['watchdog_'.$v['internal_id'].'_'.$v['category_id'].'_'.$v['last_seen_event']] .= '<br><font size=-5 color=gray>'.$data['events'].'</font>';
}
}
return array('notifications'=>$ret);
return array('notifications'=>$ret, 'tray'=>$tray);
}
}



Loading…
Cancel
Save