diff --git a/lib/local-db.js b/lib/local-db.js index 894ea24..f62087d 100644 --- a/lib/local-db.js +++ b/lib/local-db.js @@ -23,13 +23,18 @@ function getConnection() { return db; } function initTables() { logger.verbose('Preparing database tables'); db.serialize(function() { - db.run('CREATE TABLE IF NOT EXISTS sms( created TEXT, direction TEXT, imsi TEXT, partner TEXT, msg TEXT )'); + db.run('CREATE TABLE IF NOT EXISTS ussd( created TEXT, created_date TEXT, direction TEXT, imsi TEXT, msg TEXT )'); + db.run('CREATE INDEX IF NOT EXISTS idx_ussd_created ON ussd(created)'); + db.run('CREATE INDEX IF NOT EXISTS idx_ussd_created_date_created ON ussd(created_date, created)'); + + db.run('CREATE TABLE IF NOT EXISTS sms( created TEXT, created_date TEXT, direction TEXT, imsi TEXT, partner TEXT, msg TEXT )'); db.run('CREATE INDEX IF NOT EXISTS idx_sms_created ON sms(created)'); + db.run('CREATE INDEX IF NOT EXISTS idx_sms_created_date_created ON sms(created_date, created)'); db.run('CREATE TABLE IF NOT EXISTS pendingtrx ( created TEXT, created_date TEXT, trx_id TEXT, destination TEXT, product TEXT )'); db.run('CREATE INDEX IF NOT EXISTS idx_pendingtrx_created ON pendingtrx(created)'); - db.run('CREATE UNIQUE INDEX IF NOT EXISTS idx_pendingtrx_created_date ON pendingtrx(created_date, destination, product)'); db.run('CREATE UNIQUE INDEX IF NOT EXISTS idx_pendingtrx_trx_id ON pendingtrx(trx_id)'); + db.run('CREATE INDEX IF NOT EXISTS idx_pendingtrx_created_date ON pendingtrx(created_date, destination, product)'); }) } @@ -37,11 +42,12 @@ function cleanup(max_days) { logger.info('Doing database cleanup'); if (!max_days) { - max_days = 7; + max_days = 31; } const oldest = moment().add(-1 * max_days, 'days').format('YYYY-MM-DD'); db.serialize(function() { + db.run('DELETE FROM ussd WHERE created < ?', oldest); db.run('DELETE FROM sms WHERE created < ?', oldest); db.run('DELETE FROM pendingtrx WHERE created_date < ?', oldest); db.run('VACUUM'); diff --git a/lib/modem-dashboard/index.js b/lib/modem-dashboard/index.js new file mode 100644 index 0000000..cdf59fe --- /dev/null +++ b/lib/modem-dashboard/index.js @@ -0,0 +1,64 @@ +"use strict"; + +const express = require('express'); +const nunjucks = require('nunjucks'); + +const config = require('komodo-sdk/config'); +const logger = require('komodo-sdk/logger'); +const matrix = require('komodo-sdk/matrix'); + + +const routerSms = require('./router-sms'); +const routerUssd = require('./router-ussd'); + +const app = express(); + +app.use(express.static(__dirname + '/public', {maxAge: 24 * 3600 * 1000})); + +nunjucks.configure(__dirname + '/views', { + autoescape: true, + noCache: true, + express: app +}); + +function modemSignal(req, res, next) { + const signal_strength = matrix && matrix.modem && matrix.modem.signal_strength ? matrix.modem.signal_strength : 0; + res.locals.signal_strength = signal_strength; + + if (signal_strength < 2 || !signal_strength) { + res.locals.signal_strength_image = 'signal-0.png'; + res.locals.signal_strength_title = 'No signal'; + } + else if (signal_strength < 10) { + res.locals.signal_strength_image = 'signal-1.png'; + res.locals.signal_strength_title = 'Marginal'; + } + else if (signal_strength < 15) { + res.locals.signal_strength_image = 'signal-2.png'; + res.locals.signal_strength_title = 'OK'; + } + else if (signal_strength < 20) { + res.locals.signal_strength_image = 'signal-3.png'; + res.locals.signal_strength_title = 'Good'; + } + else { + res.locals.signal_strength_image = 'signal-4.png'; + res.locals.signal_strength_title = 'Excelent'; + } + + next(); +} + +app.use(modemSignal); + +app.get('/', function(req, res, next) { + res.redirect('/sms'); +}) + +app.use('/sms', routerSms); +app.use('/ussd', routerUssd); + +const modem_dashboard_port = (config && config.modem_dashboard && config.modem_dashboard.port) ? config.modem_dashboard.port : 22765; +app.listen(modem_dashboard_port, function () { + logger.info('Web control panel started', {listen_port: modem_dashboard_port}); +}); diff --git a/lib/modem-dashboard/public/ie10-viewport-bug-workaround.css b/lib/modem-dashboard/public/ie10-viewport-bug-workaround.css new file mode 100644 index 0000000..4b9518e --- /dev/null +++ b/lib/modem-dashboard/public/ie10-viewport-bug-workaround.css @@ -0,0 +1,13 @@ +/*! + * IE10 viewport hack for Surface/desktop Windows 8 bug + * Copyright 2014-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +/* + * See the Getting Started docs for more information: + * http://getbootstrap.com/getting-started/#support-ie10-width + */ +@-ms-viewport { width: device-width; } +@-o-viewport { width: device-width; } +@viewport { width: device-width; } diff --git a/lib/modem-dashboard/public/ie10-viewport-bug-workaround.js b/lib/modem-dashboard/public/ie10-viewport-bug-workaround.js new file mode 100644 index 0000000..479a6eb --- /dev/null +++ b/lib/modem-dashboard/public/ie10-viewport-bug-workaround.js @@ -0,0 +1,23 @@ +/*! + * IE10 viewport hack for Surface/desktop Windows 8 bug + * Copyright 2014-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +// See the Getting Started docs for more information: +// http://getbootstrap.com/getting-started/#support-ie10-width + +(function () { + 'use strict'; + + if (navigator.userAgent.match(/IEMobile\/10\.0/)) { + var msViewportStyle = document.createElement('style') + msViewportStyle.appendChild( + document.createTextNode( + '@-ms-viewport{width:auto!important}' + ) + ) + document.querySelector('head').appendChild(msViewportStyle) + } + +})(); diff --git a/lib/modem-dashboard/public/img/signal-0.png b/lib/modem-dashboard/public/img/signal-0.png new file mode 100644 index 0000000000000000000000000000000000000000..ddf4ba4f063cc1f56464dae9ff11e2090d843c4e GIT binary patch literal 953 zcmeAS@N?(olHy`uVBq!ia0vp^K0xfi!3HEZgiZ_qQY^(zo*^7SP{WbZ0pxQQctjR6 zFfd*PVaCrnryl|ZB}-f*N`mv#O3D+9QW?t2%k?tzvWt@w3sUv+i_&Mmvyoz8U^eq~ zaSW-L^LEyGZ;?Qm1NQm1r-lA%l;V)nnV>r12Gf7Ww~N~OTql)ye0U(&b0fK3FScpH z<vUR-OrI61Hg*S=y}EQz$ks!mg|+dL)2T%_cA2bio}M}@W8b?Mx2L{mXPZ{}x%U2d zyEng$^3xb{nq|uiJPxIPa#LZfDYNBZtUeGvo!Q_(W&+cWxVsZhro4FlTDa8A)YNrl z$gkIb9z0N3yLRow-;vSL$#r#h6;-l3IQNM2zM5cgp!R`z=+~r*iW~3Vyt%QWq_nj4 z+T5p4pPr~abLPyAY15`9$jdkQvB&*8ZJN-%>R?%U`R%1kmpY4wX-&=1o6g-mpJA5F zj*c^~4}?RT{gz+8_Sxq3?|%z9q9Y<U%=A%{2v7VUe_vn@W1P^8iu(HfvGMW!zBAtc z1}dBFwY165zTw{D`DM8h4-_8+o6h|9t<2ioJbd$p-d<j70|SAwzwWQL#JN5d+u(b3 zNspn~{PVYqcGf5)Zr;3k+uF6dZ*GZSsodM;CHBK9p~=?Pwyd<&bkl~rcVlOtf4<gm z*}~VMAyJLyEGZ_Yrjh4A|I^M%O+A{n`R0aiN(#FlW-ItH^m9%$GBHW9wz6_+?d|Qo zSz;x7Z5ziN`%jS;56m_==gxlN+2^^p>y&5$@6Hv;k?R)~@l|-2M7lm$HF@GSLC=4I z*O`th6&yS(@c8hN8`n8Lh<LPa@nu?kV7<iWt3C?@cAWnA&(i3m#AkbUIfhupT>llu zkqpOXcwf84=-FdeD7xrS%L)TUEuRi9VHne6j`=$Gb3cAmT>Ji4deRIRrH?r!C0~9! z7MpD`$bOsp?Y^}~(z8Zp?#rs0F0Gt_iB2IiChX|`XZs-J#Ls-g=Y?)}4#ge46MuK1 zcMy`P9hdh$`SPV?RfLY)|0s!!yu5o-l9Gkr*iNn7aQ5ukdnragqlAK2hP2)M-*<*{ zmr5(Ts~|>QDOnz`A!5~7K1m|^%;Fe5^EmIg=~s4{T6O-h{=M1sSxJ|kC#r8yoUq+( w-~0EfLY?yuZ76!M-DF?T)cV^J%3c4NGxPr{gmv(H1G5=}r>mdKI$&%90L{F!IsgCw literal 0 HcmV?d00001 diff --git a/lib/modem-dashboard/public/img/signal-1.png b/lib/modem-dashboard/public/img/signal-1.png new file mode 100644 index 0000000000000000000000000000000000000000..e0a47af94f0fe08c6e7b6169e62533df83ebc634 GIT binary patch literal 946 zcmeAS@N?(olHy`uVBq!ia0vp^K0xfi!3HEZgiZ_qQY^(zo*^7SP{WbZ0pxQQctjR6 zFfd*PVaCrnryl|ZB}-f*N`mv#O3D+9QW?t2%k?tzvWt@w3sUv+i_&Mmvyoz8VAl6^ zaSW-L^LEz$Y~ete1NP#{9^LjC+9FmViYyB~M1Jva(L4KKL4*#UnAH|%S0k$(J2;vy z=T1{_dK++Ssh;TC$=%Ldw>VGa3Sw0}+Mv5|;j)9(e36GLAJxvzjt|-=Z^7~XQ|<lt zzbAZus#ngi>}a2Lgi4xmrM3{W-EBRm19l&-rZMsrNX=kdcb$L9<xDnqcGt;g&z%d> zn)=Vm-p0l!Jw5$JrJ1>TWK`6r`FafIjo%k7;^SoB!T)F3y7->HzF9>(a}G`NTFUhM z+^t(tFD#!uf9~t<-d^9w@35X#|Nm2|4bHI}Yin!MN=v_9Xr1b%YHVmIC}PjMC9*(p zR`&t*S6zN;laH0gKCZmCkRv)S&g^B$E&1@J-&W^yo@3Des9TefaYBTv^+ZeMy!4ps zrkyT_<Ucb@So}&gZ)3J$v3VtS`R?6ZF>!Hev29zorf#~KbK$%Fr6qs0bhbCdz7l(C z(RcD`(XybGG9EV$9cp^{>J`_ocigk~#J8$4*Bsn_;NQQx%^NogM%}n~Zyr$LvBEji z-i0T=WV!cX^2KY{(qgXvUBBV$*V4%+Q<{!-H@s<D-)g~Vqvmkx#EFiVFJE$sm|0q8 zPCA)#;RaX1zZ2n!jkg_U9?M&lZlMNrKzM`ilSO^0`?*eAKG1!bD%!X@Oe<IE(VxZZ zfA)z!Xqqdu_;6>zI>QH=6F4MhGahS<7krjIW97<~yRW>P?=0MJ@W1#0;{+~=YNyF3 znF?f{Pcl@~?z~tZ)4IYyQOl=;OL)<t78q0LY3u8Wlg~dlp7;Fjgd<0iHl{y*{P;fq ztj$YXC6o1ntKTVfMl$i~_-tPyAgbol${CpGv?%Y__l97`=lfmf9G42@t`_}R<J+F+ ziEMP(d)4R9o(UaIGW>J<kVAF#?{hb9%-E_P5Z0QTpU;2f@yF|vW@K%(@_K7)r2S%= z2$Fk{n3rBmt<(SDC-Ir%g!zo?QoUT(oque9Z{~frr3=+IR6ku^?l$lF+v7<a=O5b8 n^?tL-zNqQ-*9&C=|H!}f{H1X3tsXlte=&Hv`njxgN@xNA5}m41 literal 0 HcmV?d00001 diff --git a/lib/modem-dashboard/public/img/signal-2.png b/lib/modem-dashboard/public/img/signal-2.png new file mode 100644 index 0000000000000000000000000000000000000000..9bd2fb75461f48f90502c3ac300cf105016e7b49 GIT binary patch literal 924 zcmeAS@N?(olHy`uVBq!ia0vp^K0xfi!3HEZgiZ_qQY^(zo*^7SP{WbZ0pxQQctjR6 zFfd*PVaCrnryl|ZB}-f*N`mv#O3D+9QW?t2%k?tzvWt@w3sUv+i_&Mmvyoz8V3zcB zaSW-L^LEz$Y~ete1NP$C9tY%2M7d;F2{Z+$aQ$VEnx0k=pd-f4%=a>2Vh^95Uekk; z*{U4@)*`#EEL~JsRJdYVnMRP~B84Rp6NIF)qV_x&XepRiasSz^=~Ldb^YvAKuYLd9 z?n!OsbZdsosmFD7gf?4Nm<uu6-Sl%hp!eZu8WUfE&<w_P+ssmoB;DNIUFV)Xdp2<O z)qlI}?CkusrgGi&UmCP9M(?+Nc;o8>)`3CnEzEbA>n;ZAfBLy+<@MKUIxkDCHoRN2 zZe82E<hr_hU%q|&^}B+fC+fqe_;n1?TU4w~Oj5$a!uVn$)`l5Ro;=y{qp`!KrtS-K z*zGP&Dp8tfu<o_g`OkbVH!fY8bTY;0-wxYZ`+u!_Ao79f{*mLyj`?hj>h+oNyz*FS ztZ@JFzlQf4Cmx<(R&8;B`M}~-qrZRurWF=$%uSS*mR6g7n)UAgM!vP-i8~o{E*ohc zFZ9_MVbbfC9DhhmOw1=fKK{bq^DjSCiB8k`AbFpqy}kYHuU}OeiPqNE%OZ57ju-CQ z71yfDy62d>@=PD8>!ts-b8>Ufrfj~s;G3_*wui5k`WX8;CKwqSCbF@yF}3>o`p$Gw z61=jFXO8Wc$cP7O0n7KczliMf*voZVbwN|im5FP@6D^tdDDGL~`(V>lAL|aee}UI) zjvE!6^Xt0!(B;PU+y|Tj{28-ZxelD?IG#QG<;$1WCiCYzUlxA&<9x$!2df2d4Q181 z4;0SfJ~m^HirfD}(M5+^Rv0L1`E+mz!<ZgZq^~<K57A1sJ-=J6v-4<@KX>b)?SK1j zUOm)fD4w~me8Q0_jkVmDRW)5&IRg`&LS{@@(fu#>fy;rf>jnFhdsnpX?b)%v&w2V1 z0Z}!W5`o+2Cl$_;-|2DV&?9M$+lSm5!Vk@`Is5*^ng!lLNR}fpJ$76Fb$qba;F)4T zR&h-B7VS3{pWeUm-)^}qw8WDOY%#J0FuQX0o8Drr<4Bg;SDg9h-hAQnpSQ^#7d-l( Z%`N41Sj~@($-tb%;OXk;vd$@?2>={wmFNHf literal 0 HcmV?d00001 diff --git a/lib/modem-dashboard/public/img/signal-3.png b/lib/modem-dashboard/public/img/signal-3.png new file mode 100644 index 0000000000000000000000000000000000000000..83801cab4b44a48645863700b78e4870df594c0a GIT binary patch literal 910 zcmeAS@N?(olHy`uVBq!ia0vp^K0xfi!3HEZgiZ_qQY^(zo*^7SP{WbZ0pxQQctjR6 zFfd*PVaCrnryl|ZB}-f*N`mv#O3D+9QW?t2%k?tzvWt@w3sUv+i_&Mmvyoz8VCMF8 zaSW-L^LEyGZ;?Qm1NP^0ZnoAvkm8WjiJ0b)#QleTOLz5)02R-6F{>vBJ8a8dTvFw* zI;-2sai;mfQ9ZZZ<$AI@7n@rga~v0_wCHrLy|jnVdxMYgx$Tm*yFdLsaKIpc-}~D8 z?X~gu-taW!Zhp+h_p-pU!uk?pP0`$z2H6MQr&)LkWM;7FnVUcPT-nyv<}%mU-#>Wu z)qlI}jEtPjX7}Fl-x{?vXeEpOdZzHk@<mI&aWdawt-Bba@3nN&-CMUd1)h9bw6HWi zGgGrj-q_f9+v?TYH;z{?INvzkb|*{Dg(*4p_4{LEV(yeDZjCzI*W25A)SpR`T~Dc4 z?1xA2rI#hQs^+EF-oG!N`1$i^v-#)QAD3nRd3C!<_y9MPu)Lfc(7e^1oS$p&1C<4@ z3^90SZBX&ya$h^+J7zoI$uD2N+*n*(ys>rd+O;>6HcFKJXOG$v=lWD?gXiTXJ%-z2 z^ln$}{TF{IEj>LK7y~!<p3nSPB|4Sq!^{IL>}+grPMz{fNxXggHc(-7vQPB&)hkjO zud}427)idayf^RAwCU4x7Y1--$FrwM?=ySE@nM31=HkVRw{72U9&+Qyj~%|tFDK@5 zA9%?;zm<6%bM%qwj(LwJTv@#$hGEqSSJ_iQn}QEWFFGB?u4i>}OY4g#@};^3It=M| zmdub*JGd{8slPGA<F-fv_m7zmDmKoXF=L1C<DZsBb2<C|^Xy=M;&e;yV$vpt9>eEr zwz_)u{ClkB(#jc_=oB(TKvWIJoS<U9PEUg&yv5MJG5^1H!ftMB|HpfqTeu8cUQQBO zbf{&8fufd=$0gVQd<8mBeqC=lUg&n|P@LMG_|pr$gF3i`VM;n)r=Jw*?T=B(dGLXE zN_JxN0qsPe&ST{%eiu|VVYVSz3}mXj^V`o~q1{u-VAE;2&iE0Rb=M#3-;)iGmvrfQ z0&PV$9oeGoZq^6*6Mbw8^m_0AEq?U--!eltk^j<4%J*ZIefi}D%sUL8u6{1-oD!M< Dm86h> literal 0 HcmV?d00001 diff --git a/lib/modem-dashboard/public/img/signal-4.png b/lib/modem-dashboard/public/img/signal-4.png new file mode 100644 index 0000000000000000000000000000000000000000..2d090ffebca73c091d782c99a0b88da5104c397e GIT binary patch literal 889 zcmeAS@N?(olHy`uVBq!ia0vp^K0xfi!3HEZgiZ_qQY^(zo*^7SP{WbZ0pxQQctjR6 zFfd*PVaCrnryl|ZB}-f*N`mv#O3D+9QW?t2%k?tzvWt@w3sUv+i_&Mmvyoz8VEX3i z;uumf=k2Wh*}{P`2kgVMJr2m5h;qrU3TV2Z$n}@~mfqP13nFy**ks-WOzc^w*Yw(# z>rs$3%dRV`iwcVhS4=C@2nt-Juq0xFkW^OGp63&uTKHGrzqeIi^FF_f%=dS{?|rY` z@%?EX;|#sqd5II{W;d5B+a6HA?a6V2b>A(Y1B`ym#Ro#`o%N<C*VM#ZiQE~p>|(~B z(weNSt{gMzo%5sCx^0c(m0QPry|H}J5<X7$9sGZeh3j`6U6g4yTTScm;lm3{(@RTD zi{!bvxtFb9uYcosb;60J>9sqVavpk@rKB8Lvu2IVt_^OB6VuYt4n2C_(8DS|aVJO3 zk?AE?bIsPhmOB5L&-KQoOOsAMEjqZv_EvapcmZ35W5T1!lP52WTd%Hm=CjS?UF$rT z1|6Isf8fSNe``6u4-6kZ_@*T!90<{xdgG9pnVHYR01oT_%(7AI7ZowzIA*SSywGQ5 zh|$`x*A9oo#KnE<>+5gqJpb}TmFQHP53L7S+}+*J{`yswl4xyhy(~ma@_6B{U2(3e z+<Vj%lqa8*xL*2QblbLVX`g=9MEq7$*!}Rek{?4q$3!Dr+gvtwcIVc!=g!S4v68*E zjc1Pir^tv0Y8O=QIe)P^z9i1|sZoHl-m8dft5?inz9$fSP0b)t^)lb0>GfB(9@xec zvte>lkp<_sQt1k&B~G`VHCi87&vM+mY4?`-^Vfcy`C+wozVXWcA0!faubHoN3Yj4w zs^-$l8JGxXzT7(3!RONf)5J5z4}LqczbQ+co>5;uAwadwAa)X5mFKP(_nG}#W&Th5 zU~$bO>c;7o->)r7Jh_kz+W1#z=AyroyIXX1>eg-6&Ecs~?a{pSum23!E|u0528vof z9bCeT4z(aLkL<lH&vcI~S&qp+xi7nS$00wZ|L6bZoH1Ox$U6u_HB4jD@6{LeJ_Ji# l=6d7(_<POo+n0XWt6YEf=Exd{SHNt-;OXk;vd$@?2>{@ZhE)In literal 0 HcmV?d00001 diff --git a/lib/modem-dashboard/public/starter-template.css b/lib/modem-dashboard/public/starter-template.css new file mode 100644 index 0000000..dc15c49 --- /dev/null +++ b/lib/modem-dashboard/public/starter-template.css @@ -0,0 +1,7 @@ +body { + padding-top: 50px; +} +.starter-template { + padding: 40px 15px; + /* text-align: center; */ +} diff --git a/lib/modem-dashboard/router-sms.js b/lib/modem-dashboard/router-sms.js new file mode 100644 index 0000000..f7009da --- /dev/null +++ b/lib/modem-dashboard/router-sms.js @@ -0,0 +1,35 @@ +"use strict"; + +const moment = require('moment'); +const express = require('express'); + +const localDb = require('../local-db'); + +const router = express.Router(); +module.exports = router; + +function pageSmsIndex(req, res, next) { + res.render( + 'sms.index.html', + { + page_title: 'Histori SMS' + } + ) +} + +function pageSmsDataTables(req, res, next) { + const db = localDb.getConnection(); + + const created_date = moment().format('YYYY-MM-DD'); + const query = "SELECT rowid, * FROM sms WHERE created_date = ? ORDER BY created DESC, rowid DESC"; + db.all(query, created_date, function (err, rows) { + if (err) { + res.end("Ada error: " + err); + return; + } + res.json({data: rows}); + }); +} + +router.get('/', pageSmsIndex); +router.get('/datatables', pageSmsDataTables); diff --git a/lib/modem-dashboard/router-ussd.js b/lib/modem-dashboard/router-ussd.js new file mode 100644 index 0000000..6cd346f --- /dev/null +++ b/lib/modem-dashboard/router-ussd.js @@ -0,0 +1,35 @@ +"use strict"; + +const moment = require('moment'); +const express = require('express'); + +const localDb = require('../local-db'); + +const router = express.Router(); +module.exports = router; + +function pageIndex(req, res, next) { + res.render( + 'ussd.index.html', + { + page_title: 'Histori USSD' + } + ) +} + +function pageDataTables(req, res, next) { + const db = localDb.getConnection(); + + const created_date = moment().format('YYYY-MM-DD'); + const query = "SELECT rowid, * FROM ussd WHERE created_date = ? ORDER BY created DESC, rowid DESC"; + db.all(query, created_date, function (err, rows) { + if (err) { + res.end("Ada error: " + err); + return; + } + res.json({data: rows}); + }); +} + +router.get('/', pageIndex); +router.get('/datatables', pageDataTables); diff --git a/lib/modem-dashboard/views/sms.index.html b/lib/modem-dashboard/views/sms.index.html new file mode 100644 index 0000000..293d2af --- /dev/null +++ b/lib/modem-dashboard/views/sms.index.html @@ -0,0 +1,55 @@ +{% extends "template.html" %} + +{% block head %} +<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.18/css/dataTables.bootstrap.min.css"> +<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.js"></script> +<script type="text/javascript" src="https://cdn.datatables.net/1.10.18/js/dataTables.bootstrap.min.js"></script> +{% endblock %} + +{% block content %} + +<table id="smsHistory" class="display table table-hover table-striped"> + <thead> + <tr> + <th>#</th> + <th>Tanggal</th> + <th>Arah</th> + <th>IMSI Modem</th> + <th>Dari/Ke</th> + <th>Pesan</th> + </tr> + </thead> + <tfoot> + <tr> + <th>#</th> + <th>Tanggal</th> + <th>Arah</th> + <th>IMSI Modem</th> + <th>Dari / Ke</th> + <th>Pesan</th> + </tr> + </tfoot> +</table> + +<script> + $(document).ready(function() { + $('#smsHistory').DataTable( { + "ajax": "/sms/datatables", + "language": { "url": "//cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/Indonesian.json" }, + "columns": [ + { "data": "rowid" }, + { "data": "created" }, + { "data": "direction" }, + { "data": "imsi" }, + { "data": "partner" }, + { "data": "msg" } + ], + "order": [ + [1, "desc"] + ], + "lengthMenu": [[50, 100, 200, -1], [50, 100, 200, "All"]] + } ); + } ); +</script> + +{% endblock %} diff --git a/lib/modem-dashboard/views/template.html b/lib/modem-dashboard/views/template.html new file mode 100644 index 0000000..6ba9703 --- /dev/null +++ b/lib/modem-dashboard/views/template.html @@ -0,0 +1,102 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> + + <meta name="description" content=""> + <meta name="author" content=""> + <link rel="icon" href="/favicon.ico"> + + <title> + {% if page_title %} + {{ page_title }} + - + {% endif %} + Modem Dashboard + </title> + + <!-- Latest compiled and minified CSS --> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> + + <!-- Optional theme --> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"> + + + + <!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> + <link href="/ie10-viewport-bug-workaround.css" rel="stylesheet"> + + <!-- Custom styles for this template --> + <link href="starter-template.css" rel="stylesheet"> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> + + <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> + + {% block head %} + {% endblock %} + </head> + + <body> + + <nav class="navbar navbar-inverse navbar-fixed-top"> + <div class="container"> + <div class="navbar-header"> + <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <a class="navbar-brand" href="/">Modem Dashboard</a> + </div> + <div id="navbar" class="collapse navbar-collapse"> + <ul class="nav navbar-nav"> + <li><a href="/sms">SMS</a></li> + <li><a href="/ussd">USSD</a></li> + </ul> + </div><!--/.nav-collapse --> + </div> + </nav> + + <div class="container"> + + <div class="starter-template"> + + <div style="text-align: right;"> + <img src="/img/{{ signal_strength_image }}" alt="Signal: {{ signal_strength_title }}" title="Signal: {{ signal_strength_title }} ({{ signal_strength }})"> + </div> + + {% if page_title%} + <h1> {{ page_title }} </h1> + {% endif %} + + {% block content %} + + + + {% endblock %} + + </div> + + </div><!-- /.container --> + + + <!-- Bootstrap core JavaScript + ================================================== --> + <!-- Placed at the end of the document so the pages load faster --> + <script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script> + <!-- Latest compiled and minified JavaScript --> + <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> + + <!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> + <script src="/ie10-viewport-bug-workaround.js"></script> + </body> +</html> diff --git a/lib/modem-dashboard/views/ussd.index.html b/lib/modem-dashboard/views/ussd.index.html new file mode 100644 index 0000000..e84613b --- /dev/null +++ b/lib/modem-dashboard/views/ussd.index.html @@ -0,0 +1,52 @@ +{% extends "template.html" %} + +{% block head %} +<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.18/css/dataTables.bootstrap.min.css"> +<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.js"></script> +<script type="text/javascript" src="https://cdn.datatables.net/1.10.18/js/dataTables.bootstrap.min.js"></script> +{% endblock %} + +{% block content %} + +<table id="smsHistory" class="display table table-hover table-striped"> + <thead> + <tr> + <th>#</th> + <th>Tanggal</th> + <th>Arah</th> + <th>IMSI Modem</th> + <th>Pesan</th> + </tr> + </thead> + <tfoot> + <tr> + <th>#</th> + <th>Tanggal</th> + <th>Arah</th> + <th>IMSI Modem</th> + <th>Pesan</th> + </tr> + </tfoot> +</table> + +<script> + $(document).ready(function() { + $('#smsHistory').DataTable( { + "ajax": "/ussd/datatables", + "language": { "url": "//cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/Indonesian.json" }, + "columns": [ + { "data": "rowid" }, + { "data": "created" }, + { "data": "direction" }, + { "data": "imsi" }, + { "data": "msg" } + ], + "order": [ + [1, "desc"] + ], + "lengthMenu": [[50, 100, 200, -1], [50, 100, 200, "All"]] + } ); + } ); +</script> + +{% endblock %} diff --git a/lib/modem/index.js b/lib/modem/index.js index 7eb2e89..3078693 100644 --- a/lib/modem/index.js +++ b/lib/modem/index.js @@ -43,7 +43,7 @@ class Modem extends EventEmitter { }); this.port.on('open', function() { - self.disableEcho(function() { + self.resetModem(function() { self.getIMSI(function() { self.emit('open'); self.getSignalStrength(cb); @@ -145,7 +145,7 @@ class Modem extends EventEmitter { this.emit('incoming sms', sms); } - disableEcho(cb) { + resetModem(cb) { const self = this; if (this.parser) { this.port.unpipe(this.parser)}; @@ -154,7 +154,7 @@ class Modem extends EventEmitter { parser.on('data', function(data) { const value = data.toString().replace(/^\s+/, '').replace(/\s+$/, ''); - debugLog('PARSER-DISABLEECHO: echo disabled'); + debugLog('PARSER-RESETMODEM: modem reseted'); self.port.unpipe(parser); self.resetParserToDefault(); @@ -164,7 +164,7 @@ class Modem extends EventEmitter { } }) - this.write('ATE0\r'); + this.write('AT &F Z E0\r'); } getIMSI(cb) { diff --git a/lib/partner-mkios.js b/lib/partner-mkios.js index 68fbb64..6bf239f 100644 --- a/lib/partner-mkios.js +++ b/lib/partner-mkios.js @@ -1,5 +1,7 @@ "use strict"; +const moment = require('moment'); + const Modem = require('./modem'); const pullgw = require('komodo-sdk/gateway/pull'); @@ -8,6 +10,8 @@ const config = require('komodo-sdk/config'); const logger = require('komodo-sdk/logger'); const matrix = require('komodo-sdk/matrix'); +const modemDashboard = require('./modem-dashboard'); + matrix.modem = {}; matrix.not_ready = true; matrix.stock = {}; @@ -36,9 +40,9 @@ modem.on('imsi', function(imsi) { function onIncomingSMS(sms) { logger.info('Incoming SMS', {sms: sms}); - db.run("INSERT INTO sms VALUES (?, 'IN', ?, ?, ?)", sms.created, matrix.modem.imsi, sms.sender, sms.msg, function(err) { + db.run("INSERT INTO sms VALUES (?, ?, 'IN', ?, ?, ?)", sms.created, moment(sms.created).format('YYYY-MM-DD'), matrix.modem.imsi, sms.sender, sms.msg, function(err) { if (err) { - logger.warn('Error inserting sms to local database'); + logger.warn('Error inserting sms to local database', {err: err}); } }); @@ -105,9 +109,16 @@ modem.on('signal strength', function(signal_strength) { logger.verbose('Signal strength: ' + signal_strength); }) -modem.on('ussd response', function(data) { +function onUSSDResponse(data) { logger.verbose('Got USSD response', {response: data}); + db.run("INSERT INTO ussd VALUES (?, ?, 'IN', ?, ?)", moment().format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD'), matrix.modem.imsi, data, function(err) { + if (err) { + logger.warn('Error inserting ussd response to local database', {err: err}); + } + }); + + if (!last_trx_id) return; @@ -128,7 +139,9 @@ modem.on('ussd response', function(data) { updateStock(stock_name, stock_balance); last_trx_id = null; -}) +} + +modem.on('ussd response', onUSSDResponse); logger.info('Opening MODEM'); @@ -212,7 +225,7 @@ function suspendPull(trx_id) { rc: '68', message: 'USSD timeout' }) - }, Number(config.partner.modem.suspend_time_ms) || 30000) + }, Number(config.partner.modem.suspend_time_ms) || 20 * 1000 ) } function deleteResumeHandler(trx_id) { @@ -249,6 +262,11 @@ function buy(task) { const ussd_command = task.remote_product.split(',')[0].replace("<DESTINATION>", task.destination).replace("<PIN>", config.partner.pin); logger.verbose('Going to execute USSD', {trx_id: task.trx_id, destination: task.destination, product: task.product, ussd: ussd_command}); + db.run("INSERT INTO ussd VALUES (?, ?, 'OUT', ?, ?)", moment().format('YYYY-MM-DD HH:mm:ss'), moment().format('YYYY-MM-DD'), matrix.modem.imsi, 'AT+CUSD=1,"' + ussd_command + '",15', function(err) { + if (err) { + logger.warn('Error inserting ussd command to local database', {err: err}); + } + }); modem.sendUSSD(ussd_command, function() {}); }) diff --git a/lib/pending-archive.js b/lib/pending-archive.js index 16a209b..b7ecad0 100644 --- a/lib/pending-archive.js +++ b/lib/pending-archive.js @@ -49,7 +49,7 @@ function get(destination, product, created_date, cb) { logger.verbose('PENDING-ARCHIVE: Trying to get trx from table', {destination: destination, product: product, created_date: created_date}); - const query = "SELECT trx_id FROM pendingtrx WHERE created_date = ? AND destination = ? AND product = ? "; + const query = "SELECT trx_id FROM pendingtrx WHERE created_date = ? AND destination = ? AND product = ? ORDER BY created DESC LIMIT 1"; db.get(query, created_date, destination, product, function (err, row) { if (err) { logger.warn('PENDING-ARCHIVE: Error retrieving', {destination: destination, product: product, created_date: created_date, err: err}); diff --git a/lib/sms-handler.js b/lib/sms-handler.js index 7a31c2f..a070bc2 100644 --- a/lib/sms-handler.js +++ b/lib/sms-handler.js @@ -14,7 +14,7 @@ function isAllowedSender(sender) { function getDestination(msg) { const result = patternMatcher(msg, config.sms_parser.destination); if (result && typeof result === 'string') { - return result.replace(/^62/, '0'); + return result.replace(/^62/, '0').replace(/^8/, '08'); } } diff --git a/package-lock.json b/package-lock.json index 63b68a3..534bf43 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1267,11 +1267,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" - }, - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" } } }, @@ -1392,11 +1387,6 @@ "requires": { "ms": "2.0.0" } - }, - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" } } }, @@ -2081,7 +2071,7 @@ "depd": "1.1.2", "inherits": "2.0.3", "setprototypeof": "1.1.0", - "statuses": "1.5.0" + "statuses": "1.4.0" } }, "http-signature": { @@ -3540,11 +3530,6 @@ "requires": { "ms": "2.0.0" } - }, - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" } } }, @@ -4020,9 +4005,9 @@ } }, "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" }, "strftime": { "version": "0.10.0", diff --git a/package.json b/package.json index da06b9f..92d00c3 100644 --- a/package.json +++ b/package.json @@ -23,9 +23,11 @@ "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "cron": "^1.3.0", + "express": "^4.16.3", "jsesc": "^2.5.1", "komodo-sdk": "git+http://gitlab.kodesumber.com/komodo/komodo-sdk.git", "moment": "^2.22.2", + "nunjucks": "^3.1.3", "serialport": "^6.2.2", "sqlite3": "^4.0.2" }, diff --git a/pid.txt b/pid.txt index 42324a4..b606877 100644 --- a/pid.txt +++ b/pid.txt @@ -1 +1 @@ -28464 \ No newline at end of file +6300 \ No newline at end of file