Commit 409dcdbc9ac9edee1b6c8c582e3f21b6b86b3ece

Authored by Adhidarma Hadiwinoto
1 parent 8a09c214f0
Exists in master and in 1 other branch webadmin

awal webadmin

Showing 17 changed files with 338 additions and 0 deletions Side-by-side Diff

... ... @@ -15,3 +15,4 @@ const transport = require('./lib/transport');
15 15 messagingClient.setTransport(transport);
16 16  
17 17 require('./lib/apiserver');
  18 +require('./lib/webadmin');
18 19 \ No newline at end of file
lib/webadmin/index.js
1 1 const express = require('express');
  2 +const morgan = require('morgan');
  3 +const rfs = require('rotating-file-stream');
  4 +const nunjucks = require('nunjucks');
  5 +const moment = require('moment');
2 6  
3 7 const config = require('komodo-sdk/config');
4 8 const logger = require('komodo-sdk/logger');
5 9  
  10 +const routerConfig = require('./router/config');
6 11  
7 12 const app = express();
8 13  
  14 +nunjucks.configure('./webadmin-views', {
  15 + autoescape: true,
  16 + express: app,
  17 + noCache: true,
  18 +});
  19 +
  20 +app.use(express.static('./webadmin-statics'));
  21 +
  22 +const accessLogStream = rfs.createStream(
  23 + (time, index) => {
  24 + const ts = time ? `.${moment(time).format('YYYY-MM-DD')}` : '';
  25 + const idx = index ? `.${index}` : '';
  26 + return `apiserver.access_log${ts}${idx}`;
  27 + },
  28 + {
  29 + interval: '1d',
  30 + path: './logs',
  31 + },
  32 +);
  33 +
  34 +app.use(morgan('combined', { stream: accessLogStream }));
  35 +
  36 +app.use('/config', routerConfig);
  37 +
9 38 const listenPort = (config.webadmin && config.webadmin.port) || 21923;
10 39 app.listen(listenPort, () => {
11 40 logger.info(`WEBADMIN listen on port ${listenPort}`);
lib/webadmin/router/config.js
... ... @@ -0,0 +1,87 @@
  1 +const fs = require('fs');
  2 +const express = require('express');
  3 +
  4 +const config = require('komodo-sdk/config');
  5 +
  6 +const router = express.Router();
  7 +module.exports = router;
  8 +
  9 +function composeNewModem(name, params) {
  10 + return {
  11 + name,
  12 + outgoing: (params && params.outgoing) || false,
  13 + prefix: (params && params.prefix) || [],
  14 + };
  15 +}
  16 +
  17 +async function writeConfigFile() {
  18 + try {
  19 + await fs.promises.writeFile('config.json', JSON.stringify(config, null, 4));
  20 + } catch (e) {
  21 + //
  22 + }
  23 +}
  24 +
  25 +function pageMain(req, res) {
  26 + res.render('config.index.html', {
  27 + config: JSON.stringify(config, null, 4),
  28 + modems: config.modems,
  29 + baseUrl: req.baseUrl,
  30 + });
  31 +}
  32 +
  33 +async function pageSetOutgoing(req, res) {
  34 + const modemName = (req.params.modemName || '').trim();
  35 + if (!modemName) {
  36 + res.end('Invalid modem name');
  37 + return;
  38 + }
  39 +
  40 + const idx = (config.modems || []).findIndex((modem) => modem.name === modemName);
  41 + if (idx < 0) {
  42 + res.end('No modem matched');
  43 + return;
  44 + }
  45 +
  46 + config.modems[idx].outgoing = req.params.newValue === '1' || req.params.newValue === 'true';
  47 +
  48 + await writeConfigFile();
  49 +
  50 + res.redirect(`${req.baseUrl}`);
  51 +}
  52 +
  53 +async function pageDelPrefix(req, res) {
  54 + const modemName = (req.params.modemName || '').trim();
  55 + if (!modemName) {
  56 + res.end('Invalid modem name');
  57 + return;
  58 + }
  59 +
  60 + const prefix = (req.params.prefix || '').trim();
  61 + if (!prefix) {
  62 + res.end('Invalid prefix');
  63 + return;
  64 + }
  65 +
  66 + const modemIdx = (config.modems || []).findIndex((modem) => modem.name === modemName);
  67 + if (modemIdx < 0) {
  68 + res.end('No modem matched');
  69 + return;
  70 + }
  71 +
  72 + const prefixIdx = (config.modems[modemIdx].prefix || []).indexOf(prefix);
  73 + if (prefixIdx < 0) {
  74 + res.end('No prefix matched');
  75 + return;
  76 + }
  77 +
  78 + config.modems[modemIdx].prefix.splice(prefixIdx, 1);
  79 +
  80 + await writeConfigFile();
  81 +
  82 + res.redirect(`${req.baseUrl}`);
  83 +}
  84 +
  85 +router.get('/', pageMain);
  86 +router.get('/modem/set-outgoing/:modemName/:newValue', pageSetOutgoing);
  87 +router.get('/modem/del-prefix/:modemName/:prefix', pageDelPrefix);
... ... @@ -28,6 +28,7 @@
28 28 "locks": "^0.2.2",
29 29 "moment": "^2.24.0",
30 30 "morgan": "^1.9.1",
  31 + "nunjucks": "^3.2.0",
31 32 "rotating-file-stream": "^2.0.0",
32 33 "uniqid": "^5.2.0"
33 34 },
webadmin-statics/assets/img/favicons/android-chrome-192x192.png

1.89 KB

webadmin-statics/assets/img/favicons/apple-touch-icon.png

1.7 KB

webadmin-statics/assets/img/favicons/browserconfig.xml
... ... @@ -0,0 +1,9 @@
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<browserconfig>
  3 + <msapplication>
  4 + <tile>
  5 + <square150x150logo src="/assets/img/favicons/mstile-150x150.png"/>
  6 + <TileColor>#563d7c</TileColor>
  7 + </tile>
  8 + </msapplication>
  9 +</browserconfig>
webadmin-statics/assets/img/favicons/favicon-16x16.png

310 Bytes

webadmin-statics/assets/img/favicons/favicon-32x32.png

491 Bytes

webadmin-statics/assets/img/favicons/favicon.ico
No preview for this file type
webadmin-statics/assets/img/favicons/manifest.json
... ... @@ -0,0 +1,20 @@
  1 +{
  2 + "name": "Bootstrap",
  3 + "short_name": "Bootstrap",
  4 + "icons": [
  5 + {
  6 + "src": "/assets/img/favicons/android-chrome-192x192.png",
  7 + "sizes": "192x192",
  8 + "type": "image/png"
  9 + },
  10 + {
  11 + "src": "/assets/img/favicons/android-chrome-512x512.png",
  12 + "sizes": "512x512",
  13 + "type": "image/png"
  14 + }
  15 + ],
  16 + "start_url": "/?utm_source=a2hs",
  17 + "theme_color": "#563d7c",
  18 + "background_color": "#563d7c",
  19 + "display": "standalone"
  20 +}
webadmin-statics/assets/img/favicons/mstile-150x150.png

1.39 KB

webadmin-statics/assets/img/favicons/safari-pinned-tab.svg
... ... @@ -0,0 +1,4 @@
  1 +<svg xmlns="http://www.w3.org/2000/svg" width="933.333" height="933.333" version="1" viewBox="0 0 700 700">
  2 + <path d="M104.5.7C89.2 2.6 77.4 6.2 63.8 13.2 41.7 24.5 24.5 41.7 13.2 63.8 7.5 75.1 4.8 82.3 2.3 94 .6 102.1.5 114.3.5 350s.1 247.9 1.8 256c2.5 11.7 5.2 18.9 10.9 30.2 11.3 22.1 28.5 39.3 50.6 50.6 11.3 5.7 18.5 8.4 30.2 10.9 8.1 1.7 20.3 1.8 256 1.8s247.9-.1 256-1.8c11.7-2.5 18.9-5.2 30.2-10.9 22.1-11.3 39.3-28.5 50.6-50.6 5.7-11.3 8.4-18.5 10.9-30.2 1.7-8.1 1.8-20.3 1.8-256s-.1-247.9-1.8-256c-2.5-11.7-5.2-18.9-10.9-30.2C670.9 32.6 642.9 11 607 2.4 599.9.7 587.2.6 353.5.4 218.2.3 106.2.5 104.5.7zm315.3 153.6c47.4 9 75.3 30.5 85.6 65.9 5.1 17.8 5.6 43.1 1.1 60.3-2 7.5-7.9 20.3-12.2 26.4-8 11.3-21.9 22.8-36 30-3.5 1.7-6.3 3.5-6.3 3.9 0 .5 2.3 1.4 5.1 2 2.8.7 8.5 2.6 12.7 4.3 37.2 14.8 58.1 50.4 58.2 99 0 28.6-9 53.9-25.7 71.8-18.8 20.3-45.2 32.9-83.3 39.8-8.5 1.5-20.9 1.7-119.2 2l-109.8.4V151.9l110.8.4c95.5.3 111.8.6 119 2z"/>
  3 + <path d="M262 266.5v56.6l65.3-.4c57.2-.3 65.9-.5 70.7-2 15.8-4.8 28.7-14.9 34.4-27.1 4.4-9.2 5.6-15.3 5.6-28.4-.1-25.1-7.5-39.8-24.3-47.7-14.1-6.7-14.2-6.7-86.4-7.2l-65.3-.5v56.7zm0 171.5v64.1l71.3-.3c69.8-.3 71.4-.4 79-2.6 11.4-3.2 19.2-7.7 27.2-15.7 12.1-12 16.8-24.9 16.8-46 0-20.8-5.1-34.3-17.3-45.9-7.9-7.4-15.8-11.6-28.1-14.7-8.1-2.1-10.5-2.2-78.6-2.6l-70.3-.5V438z"/>
  4 +</svg>
webadmin-statics/assets/starter-template.css
... ... @@ -0,0 +1,7 @@
  1 +body {
  2 + padding-top: 5rem;
  3 +}
  4 +.starter-template {
  5 + padding: 3rem 1.5rem;
  6 + text-align: left;
  7 +}
webadmin-views/config.include.addmodem.html
... ... @@ -0,0 +1,8 @@
  1 +<div class="card">
  2 + <div class="card-header bg-info">
  3 + <h3>Tambah Modem</3>
  4 + </div>
  5 + <div class="card-body">
  6 +
  7 + </div>
  8 +</div>
0 9 \ No newline at end of file
webadmin-views/config.index.html
... ... @@ -0,0 +1,80 @@
  1 +{% extends "template.starter.html" %}
  2 +
  3 +{% block content %}
  4 +
  5 +<!--
  6 +<code>
  7 +{{ config | nl2br | safe }}
  8 +</code>
  9 +-->
  10 +
  11 +{% for modem in modems %}
  12 +<div class="card">
  13 + <div class="card-header bg-info">
  14 + <h3>{{ modem.name }}</3>
  15 + </div>
  16 + <div class="card-body">
  17 +
  18 + <dl class="row">
  19 + <dt class="col-sm-3">Outgoing</dt>
  20 + <dd class="col-sm-9">
  21 + {% if modem.outgoing %}
  22 + {% set newValue = 0 %}
  23 + {% else %}
  24 + {% set newValue = 1 %}
  25 + {% endif %}
  26 + <a href="{{ baseUrl }}/modem/set-outgoing/{{ modem.name | urlencode }}/{{ newValue }}" onclick="return window.confirm('Apakah anda yakin ingin mengubah status outgoing modem {{ modem.name }} menjadi {{ not modem.outgoing }}?');">
  27 + {{ modem.outgoing }}
  28 + </a>
  29 + </dd>
  30 + </dl>
  31 +
  32 + <dl class="row">
  33 + <dt class="col-sm-3">IMSI</dt>
  34 + <dd class="col-sm-9">
  35 + {{ modem.imsi or '-' }}
  36 + <br>
  37 + [<a href="{{ baseUrl }}/modem/set-imsi/{{ modem.name | urlencode }}">
  38 + edit
  39 + </a>]
  40 + </dd>
  41 + </dl>
  42 +
  43 + <dl class="row">
  44 + <dt class="col-sm-3">Prefix</dt>
  45 + <dd class="col-sm-9">
  46 + {% for prefix_item in modem.prefix %}
  47 + {{ prefix_item }}
  48 + <a href="{{ baseUrl }}/modem/del-prefix/{{ modem.name | urlencode }}/{{ prefix_item | urlencode}}" onclick="return window.confirm('Apakah anda yakin ingin mengapus prefix {{ prefix_item }} dari modem {{ modem.name }}?');">
  49 + x
  50 + </a>
  51 + <br>
  52 + {% endfor %}
  53 +
  54 + [
  55 + <a href="{{ baseUrl }}/modem/add-prefix/{{ modem.name | urlencode }}">
  56 + tambah
  57 + </a>
  58 + ]
  59 + </dd>
  60 + </dl>
  61 +
  62 + <dl class="row">
  63 + <dt class="col-sm-3">Custom IP</dt>
  64 + <dd class="col-sm-9">
  65 + {{ modem.ip or 'none' }}
  66 + <br>
  67 + [<a href="{{ baseUrl }}/modem/set-ip/{{ modem.name | urlencode }}">
  68 + edit
  69 + </a>]
  70 + </dd>
  71 + </dl>
  72 +
  73 + </div>
  74 +</div>
  75 +<br>
  76 +{% endfor %}
  77 +
  78 +{% include "config.include.addmodem.html" %}
  79 +
  80 +{% endblock %}
0 81 \ No newline at end of file
webadmin-views/template.starter.html
... ... @@ -0,0 +1,92 @@
  1 +
  2 +<!doctype html>
  3 +<html lang="en">
  4 + <head>
  5 + <meta charset="utf-8">
  6 + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  7 + <meta name="description" content="">
  8 + <meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
  9 + <meta name="generator" content="Jekyll v3.8.6">
  10 + <title>Starter Template ยท Bootstrap</title>
  11 +
  12 + <!-- Bootstrap core CSS -->
  13 + <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
  14 +
  15 + <!-- Favicons -->
  16 + <link rel="apple-touch-icon" href="/assets/img/favicons/apple-touch-icon.png" sizes="180x180">
  17 + <link rel="icon" href="/assets/img/favicons/favicon-32x32.png" sizes="32x32" type="image/png">
  18 + <link rel="icon" href="/assets/img/favicons/favicon-16x16.png" sizes="16x16" type="image/png">
  19 + <link rel="manifest" href="/assets/img/favicons/manifest.json">
  20 + <link rel="mask-icon" href="/assets/img/favicons/safari-pinned-tab.svg" color="#563d7c">
  21 + <link rel="icon" href="/assets/img/favicons/favicon.ico">
  22 + <meta name="msapplication-config" content="/assets/img/favicons/browserconfig.xml">
  23 + <meta name="theme-color" content="#563d7c">
  24 +
  25 +
  26 + <style>
  27 + .bd-placeholder-img {
  28 + font-size: 1.125rem;
  29 + text-anchor: middle;
  30 + -webkit-user-select: none;
  31 + -moz-user-select: none;
  32 + -ms-user-select: none;
  33 + user-select: none;
  34 + }
  35 +
  36 + @media (min-width: 768px) {
  37 + .bd-placeholder-img-lg {
  38 + font-size: 3.5rem;
  39 + }
  40 + }
  41 + </style>
  42 + <!-- Custom styles for this template -->
  43 + <link href="/assets/starter-template.css" rel="stylesheet">
  44 + </head>
  45 + <body>
  46 + <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
  47 + <a class="navbar-brand" href="#">Navbar</a>
  48 + <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation">
  49 + <span class="navbar-toggler-icon"></span>
  50 + </button>
  51 +
  52 + <div class="collapse navbar-collapse" id="navbarsExampleDefault">
  53 + <ul class="navbar-nav mr-auto">
  54 + <li class="nav-item active">
  55 + <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
  56 + </li>
  57 + <li class="nav-item">
  58 + <a class="nav-link" href="#">Link</a>
  59 + </li>
  60 + <li class="nav-item">
  61 + <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
  62 + </li>
  63 + <li class="nav-item dropdown">
  64 + <a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Dropdown</a>
  65 + <div class="dropdown-menu" aria-labelledby="dropdown01">
  66 + <a class="dropdown-item" href="#">Action</a>
  67 + <a class="dropdown-item" href="#">Another action</a>
  68 + <a class="dropdown-item" href="#">Something else here</a>
  69 + </div>
  70 + </li>
  71 + </ul>
  72 + <form class="form-inline my-2 my-lg-0">
  73 + <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search">
  74 + <button class="btn btn-secondary my-2 my-sm-0" type="submit">Search</button>
  75 + </form>
  76 + </div>
  77 +</nav>
  78 +
  79 +<main role="main" class="container">
  80 +
  81 + <div class="starter-template">
  82 + {% block content %}
  83 + &nbsp;
  84 + {% endblock %}
  85 + </div>
  86 +
  87 +</main><!-- /.container -->
  88 +
  89 +<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
  90 +<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
  91 +<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
  92 +</html>