api.fwtbt.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. <?php
  2. /**
  3. * Incoming calls notifications class
  4. */
  5. class ForWhomTheBellTolls {
  6. /**
  7. * Contains system alter config as key=>value
  8. *
  9. * @var array
  10. */
  11. protected $altCfg = array();
  12. /**
  13. * Contains system billing config as key=>value
  14. *
  15. * @var array
  16. */
  17. protected $billingCfg = array();
  18. /**
  19. * Calls polling interval in ms.
  20. *
  21. * @var int
  22. */
  23. protected $pollingInterval = 7000;
  24. /**
  25. * Notification display timeout in ms.
  26. *
  27. * @var int
  28. */
  29. protected $popupTimeout = 10000;
  30. /**
  31. * System cache object placeholder
  32. *
  33. * @var object
  34. */
  35. protected $cache = '';
  36. /**
  37. * Caching timeout based on polling timeout in seconds.
  38. *
  39. * @var int
  40. */
  41. protected $cachingTimeout = 7;
  42. /**
  43. * Default number position offset
  44. *
  45. * @var int
  46. */
  47. protected $offsetNumber = 3;
  48. /**
  49. * Default call status position offset
  50. *
  51. * @var int
  52. */
  53. protected $offsetStatus = 5;
  54. /**
  55. * Default detected login offset
  56. *
  57. * @var int
  58. */
  59. protected $offsetLogin = 7;
  60. /**
  61. * Render notification code everywhere in web interface or just on taskbar
  62. *
  63. * @var bool
  64. */
  65. protected $anywhere = false;
  66. /**
  67. * Array of administrators for whom display notifications.
  68. *
  69. * @var array
  70. */
  71. protected $showFor = array();
  72. /**
  73. * Contains current instance user login
  74. *
  75. * @var string
  76. */
  77. protected $myLogin = '';
  78. /**
  79. * Default log path to parse
  80. */
  81. protected $dataSource = '';
  82. /**
  83. * Reply cache key name
  84. */
  85. const CACHE_KEY = 'FWTBT_REPLY';
  86. /**
  87. * URL with json list of recieved calls
  88. */
  89. const URL_CALLS = '?module=fwtbt&getcalls=true';
  90. /**
  91. * URL of user profile route
  92. */
  93. const URL_PROFILE = '?module=userprofile&username=';
  94. /**
  95. * Creates new FWTBT instance
  96. */
  97. public function __construct() {
  98. $this->loadConfig();
  99. $this->setOptions();
  100. $this->initCache();
  101. }
  102. /**
  103. * Loads required configs and sets some options
  104. *
  105. * @global object $ubillingConfig
  106. *
  107. * @return void
  108. */
  109. protected function loadConfig() {
  110. global $ubillingConfig;
  111. $this->altCfg = $ubillingConfig->getAlter();
  112. $this->billingCfg = $ubillingConfig->getBilling();
  113. }
  114. /**
  115. * Inits system cache
  116. *
  117. * @return void
  118. */
  119. protected function initCache() {
  120. $this->cache = new UbillingCache();
  121. }
  122. /**
  123. * Sets basic object instance options
  124. *
  125. * @return void
  126. */
  127. protected function setOptions() {
  128. /**
  129. * Make his fight on the hill in the early day
  130. * Constant chill deep inside
  131. */
  132. $this->myLogin = whoami();
  133. $this->dataSource = PBXNum::LOG_PATH;
  134. if (@$this->altCfg['FWTBT_INTERVAL']) {
  135. $this->pollingInterval = $this->altCfg['FWTBT_INTERVAL'] * 1000; //option is in seconds
  136. $this->cachingTimeout = $this->altCfg['FWTBT_INTERVAL'];
  137. }
  138. if (@$this->altCfg['FWTBT_TIMER']) {
  139. $this->popupTimeout = $this->altCfg['FWTBT_TIMER'] * 1000; //option is in seconds
  140. }
  141. if (@$this->altCfg['FWTBT_ANYWHERE']) {
  142. $this->anywhere = true;
  143. }
  144. if (@$this->altCfg['FWTBT_ADMINS']) {
  145. $this->showFor = explode(',', $this->altCfg['FWTBT_ADMINS']);
  146. $this->showFor = array_flip($this->showFor);
  147. }
  148. /**
  149. * Shouting gun, on they run through the endless grey
  150. * On the fight, for they are right, yes, by who's to say?
  151. */
  152. }
  153. /**
  154. * Renders calls data by last minute
  155. *
  156. * @return void
  157. */
  158. public function getCalls() {
  159. if (wf_CheckGet(array('getcalls'))) {
  160. $reply = array();
  161. $cachedReply = $this->cache->get(self::CACHE_KEY, $this->cachingTimeout);
  162. if (empty($cachedReply)) {
  163. $allAddress = zb_AddressGetFulladdresslistCached();
  164. if (file_exists($this->dataSource)) {
  165. $curMinute = date("Y-m-d H:i:");
  166. $command = $this->billingCfg['TAIL'] . ' -n 20 ' . $this->dataSource;
  167. $rawData = shell_exec($command);
  168. if (!empty($rawData)) {
  169. $rawData = explodeRows($rawData);
  170. $count = 0;
  171. if (!empty($rawData)) {
  172. foreach ($rawData as $io => $line) {
  173. if (!empty($line)) {
  174. if (ispos($line, $curMinute)) {
  175. $line = explode(' ', $line);
  176. @$number = $line[$this->offsetNumber]; //phone number offset
  177. @$status = $line[$this->offsetStatus]; //call status offset
  178. if (isset($line[$this->offsetLogin])) { //detected login offset
  179. $login = $line[$this->offsetLogin];
  180. } else {
  181. $login = '';
  182. }
  183. switch ($status) {
  184. case '0':
  185. //user not found
  186. $style = 'info';
  187. $icon = 'skins/call_info.png';
  188. break;
  189. case '1':
  190. //user found and active
  191. $style = 'success';
  192. $icon = 'skins/call_success.png';
  193. break;
  194. case '2':
  195. //user is debtor
  196. $style = 'error';
  197. $icon = 'skins/wdycnotify.png';
  198. break;
  199. case '3':
  200. //user is frozen
  201. $style = 'warning';
  202. $icon = 'skins/call_warning.png';
  203. break;
  204. default:
  205. //user not found
  206. $style = 'info';
  207. $icon = 'skins/call_info.png';
  208. break;
  209. }
  210. if (!empty($login)) {
  211. $profileControl = ' ' . wf_Link(self::URL_PROFILE . $login, web_profile_icon(), false, 'ubButton fwtbtprofile') . ' ';
  212. $callerName = isset($allAddress[$login]) ? $allAddress[$login] : '';
  213. $link = self::URL_PROFILE . $login;
  214. } else {
  215. $profileControl = '';
  216. $callerName = '';
  217. $link = '';
  218. }
  219. $notificationText = wf_tag('div', false, 'fwtbttext');
  220. $notificationText .= __('Calling') . ' ' . $number . ' ' . $callerName;
  221. $notificationText .= wf_tag('div', true);
  222. $notificationText .= $profileControl;
  223. $reply[$count]['text'] = $notificationText;
  224. $reply[$count]['cleartext'] = $number . ' ' . $callerName;
  225. $reply[$count]['type'] = $style;
  226. $reply[$count]['icon'] = $icon;
  227. $reply[$count]['link'] = $link;
  228. $reply[$count]['queue'] = 'q' . $count;
  229. $reply[$count]['number'] = $number;
  230. $count++;
  231. }
  232. }
  233. }
  234. }
  235. }
  236. }
  237. $this->cache->set(self::CACHE_KEY, $reply, $this->cachingTimeout);
  238. } else {
  239. $reply = $cachedReply;
  240. }
  241. die(json_encode($reply));
  242. }
  243. }
  244. /**
  245. * Returns notification frontend with some background polling
  246. *
  247. * @return string
  248. */
  249. protected function getCallsNotification() {
  250. $result = '';
  251. //some custom style
  252. $result .= wf_tag('style');
  253. //this style is inline for preventing of css caching
  254. $result .= '
  255. #noty_layout__bottomRight {
  256. width: 425px !important;
  257. }
  258. .fwtbttext {
  259. float: left;
  260. display: block;
  261. height: 32px;
  262. }
  263. .fwtbtprofile {
  264. float: right;
  265. margin-bottom: 5px;
  266. }
  267. ';
  268. if (@$this->altCfg['FWTBT_DESKTOP']) {
  269. $result .= '
  270. #noty_layout__bottomRight {
  271. margin-bottom: 120px !important;
  272. }
  273. ';
  274. }
  275. $result .= wf_tag('style', true);
  276. //basic notification frontend
  277. $result .= wf_tag('script');
  278. $result .= '
  279. $(document).ready(function() {
  280. Notification.requestPermission().then(function(result) {
  281. console.log(result);
  282. });
  283. $(".dismiss").click(function(){$("#notification").fadeOut("slow");});
  284. setInterval(
  285. function() {
  286. $.get("' . self::URL_CALLS . '&reqadm=' . $this->myLogin . '",function(message) {
  287. if (message) {
  288. var data= JSON.parse(message);
  289. data.forEach(function(key) {
  290. new Noty({
  291. theme: \'relax\',
  292. timeout: \'' . $this->popupTimeout . '\',
  293. progressBar: true,
  294. type: key.type,
  295. layout: \'bottomRight\',
  296. killer: key.number,
  297. queue: key.number,
  298. text: key.text
  299. }).show();
  300. if (typeof (sendNotificationDesktop) === "function") {
  301. var title = "' . __('Calling') . '";
  302. var options = {
  303. body: key.cleartext,
  304. icon: key.icon,
  305. tag: key.number,
  306. dir: "auto"
  307. };
  308. sendNotificationDesktop(title, options, key.link);
  309. }
  310. });
  311. }
  312. }
  313. )
  314. },
  315. ' . $this->pollingInterval . ');
  316. })
  317. ';
  318. $result .= wf_tag('script', true);
  319. if (@$this->altCfg['FWTBT_DESKTOP']) {
  320. $result .= wf_tag('script');
  321. $result .= '
  322. function sendNotificationDesktop(title, options, link) {
  323. if (Notification.permission === "granted") {
  324. var notification = new Notification(title, options);
  325. if(link) {
  326. notification.onclick = function() {
  327. window.open(link,"_self");
  328. }
  329. }
  330. } else if (Notification.permission !== "denied") {
  331. Notification.requestPermission(function (permission) {
  332. if (permission === "granted") {
  333. var notification = new Notification(title, options);
  334. if(link) {
  335. notification.onclick = function() {
  336. window.open(link,"_self");
  337. }
  338. }
  339. }
  340. });
  341. }
  342. };
  343. ';
  344. $result .= wf_tag('script', true);
  345. }
  346. return ($result);
  347. }
  348. /**
  349. * Renders widget code if it required for current situation
  350. *
  351. * @return string/void
  352. */
  353. public function renderWidget() {
  354. $result = '';
  355. if (cfr('FWTBT')) {
  356. if (@$this->altCfg['FWTBT_ENABLED']) {
  357. $widget = $this->getCallsNotification();
  358. if ($this->anywhere) {
  359. $result .= $widget;
  360. } else {
  361. if ((@$_GET['module'] == 'taskbar') OR ( !isset($_GET['module']))) {
  362. $result .= $widget;
  363. }
  364. }
  365. //per-admin controls
  366. if ((!empty($this->showFor) AND ( !isset($this->showFor[$this->myLogin])))) {
  367. $result = '';
  368. }
  369. return($result);
  370. }
  371. }
  372. }
  373. }