├── .gitignore ├── CDN ├── addContent.sh ├── devicemgmtserver ├── get_internet_status ├── get_ssid.sh ├── getall_stations.sh ├── modeChange.sh ├── netconnect_status.sh ├── postpreinstall.sh ├── profile.json ├── revert.sh ├── telemetry_upload.py ├── upgrade.sh ├── usb_handler-2.sh ├── usb_handler.sh └── version.txt ├── Documents ├── MeghashalaProductionSteps.txt ├── SystemTest.txt ├── example_cmdline.txt ├── modeChangeUT.txt ├── telemetry_upload_2_qa.sh └── upgradeUT.txt ├── INSTALL.md ├── LICENSE ├── README.md ├── appServer ├── index.js ├── package-lock.json ├── package.json └── plugins │ ├── ekStep │ ├── config.js │ ├── ekstep.controller.js │ ├── ekstep.db_restart.js │ ├── ekstep.init.js │ ├── ekstep.middleware.js │ ├── ekstep.routes.js │ ├── ekstep.telemetry_upload.js │ ├── ekstep_config.json │ ├── homePageResponseSkeleton.json │ ├── madhi_config.json │ ├── profile.json │ ├── searchIdResponseSkeleton.json │ ├── searchResponseSkeleton.json │ └── telemetryResponseSkeleton.json │ └── template │ ├── template.controller.js │ └── template.routes.js ├── buildimage.py ├── dbsdk ├── index.js ├── package-lock.json └── package.json ├── dbsdk2 ├── config.js ├── index.js ├── mysqlWrapper.test.js ├── package-lock.json ├── package.json ├── sqliteWrapper.js └── sqliteWrapper.test.js ├── devmgmtV2 ├── config.js ├── controllers │ ├── auth.controller.js │ ├── captive.controller.js │ ├── cloud.controller.js │ ├── config.controller.js │ ├── dashboard.controller.js │ ├── filemgmt.controller.js │ ├── ssid.controller.js │ ├── upgrade.controller.js │ └── users.controller.js ├── helpers │ ├── cloud.helper.js │ └── telemetry.helper.js ├── index.js ├── init.sql ├── middlewares │ └── telemetry.middleware.js ├── package-lock.json ├── package.json ├── routes │ ├── auth.routes.js │ ├── captive.routes.js │ ├── cloud.routes.js │ ├── config.routes.js │ ├── dashboard.routes.js │ ├── filemgmt.routes.js │ ├── ssid.routes.js │ ├── upgrade.routes.js │ └── users.routes.js ├── telemetry_cron.js ├── telemetry_sync.js └── writeToDB.js ├── devmgmtui ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json └── src │ ├── App.js │ ├── actions │ ├── auth.js │ ├── captive.js │ ├── cloud.js │ ├── config.js │ ├── dashboard.js │ ├── filemgmt.js │ ├── ssid.js │ ├── upgrade.js │ └── user.js │ ├── components │ ├── VerifyAuthentication.js │ ├── auth │ │ ├── Login.js │ │ └── login.css │ ├── captive │ │ ├── Captive.js │ │ ├── UploadApkButton.js │ │ └── captive.css │ ├── cloud │ │ ├── CloudDownload.js │ │ ├── ContentArea.js │ │ ├── DownloadManager.js │ │ ├── Downloads.js │ │ ├── Results.js │ │ ├── SearchBar.js │ │ └── cloud.css │ ├── common │ │ └── Sidebar.js │ ├── dashboard │ │ ├── ChartSegment.js │ │ ├── Dashboard.js │ │ ├── SysInfo.js │ │ └── dashboard.css │ ├── filemgmt │ │ ├── FileDisplayComponent.js │ │ ├── FileMgmt.js │ │ ├── FileUnitComponent.js │ │ ├── FileUploadComponent.js │ │ ├── FolderUnitComponent.js │ │ └── SelectedFileShowComponent.js │ ├── ssid │ │ └── SetSSID.js │ ├── upgrade │ │ ├── Upgrade.js │ │ └── UpgradeDisplayComponent.js │ └── user │ │ ├── CreateUser.js │ │ ├── EditUser.js │ │ ├── UpdatePassword.js │ │ └── UserList.js │ ├── config │ └── config.js │ ├── index.css │ ├── index.js │ └── reducers │ ├── auth.js │ ├── cloud.js │ ├── config.js │ ├── dashboard.js │ ├── filemgmt.js │ ├── index.js │ ├── ssid.js │ ├── upgrade.js │ └── user.js ├── filesdk ├── index.js ├── package-lock.json ├── package.json └── test │ ├── filesdk.test.js │ └── playground │ └── testRead ├── package-lock.json ├── profile ├── ekstep │ └── rootfs_overlay │ │ ├── etc │ │ └── nginx │ │ │ └── sites-enabled │ │ │ └── opencdn_nginx │ │ └── var │ │ └── www │ │ └── ekstep │ │ └── config_json │ │ └── config.json └── meghshala │ └── rootfs_overlay │ └── etc │ └── nginx │ └── sites-enabled │ └── opencdn_nginx ├── rootfs_overlay ├── etc │ ├── avahi │ │ └── services │ │ │ └── openrap.service │ ├── default │ │ ├── dnsmasq │ │ └── hostapd │ ├── dnsmasq.conf │ ├── hostapd │ │ └── hostapd.conf │ ├── hostname │ ├── hosts │ ├── init.d │ │ ├── apiserver │ │ └── first_time_boot │ ├── modprobe.d │ │ └── blacklist-opencdn.conf │ ├── network │ │ └── interfaces │ ├── nginx │ │ └── sites-enabled │ │ │ └── opencdn_nginx │ ├── rc.local │ ├── systemd │ │ └── system │ │ │ └── systemd-udevd.service │ └── udev │ │ └── rules.d │ │ └── 99-zzz-opencdn.rules ├── lib │ └── systemd │ │ └── system │ │ ├── appserver.service │ │ ├── aria2.service │ │ ├── avahi-daemon.service │ │ ├── devmgmt.service │ │ ├── searchserver.service │ │ ├── syncthing.service │ │ └── telemetry.service ├── root │ └── .config │ │ └── syncthing │ │ └── config.xml ├── tmp │ └── aria2_deb │ │ ├── aria2_1.30.0-2_armhf.deb │ │ └── libc-ares2_1.12.0-1+deb9u1_armhf.deb └── var │ └── www │ └── html │ ├── admin │ ├── asset-manifest.json │ ├── favicon.ico │ ├── index.html │ ├── manifest.json │ ├── service-worker.js │ └── static │ │ ├── css │ │ ├── main.3f599e58.css │ │ ├── main.3f599e58.css.map │ │ ├── main.5ac9ad8d.css │ │ └── main.5ac9ad8d.css.map │ │ ├── js │ │ ├── main.1ac1ce3a.js │ │ ├── main.1ac1ce3a.js.map │ │ ├── main.97fa9602.js │ │ ├── main.97fa9602.js.map │ │ ├── main.9e2ec340.js │ │ ├── main.9e2ec340.js.map │ │ ├── main.d3827fe7.js │ │ └── main.d3827fe7.js.map │ │ └── media │ │ ├── flags.9c74e172.png │ │ ├── icons.674f50d2.eot │ │ ├── icons.912ec66d.svg │ │ ├── icons.af7ae505.woff2 │ │ ├── icons.b06871f2.ttf │ │ └── icons.fee66e71.woff │ ├── index.html │ ├── public │ ├── .DS_Store │ ├── ._images │ ├── app.apk │ ├── google-font │ ├── images │ │ ├── CaptivePortalLogo.png │ │ ├── android_app_download.png │ │ └── header-bg1.jpg │ ├── jquery-3.2.1.min.js │ └── stylesheets │ │ └── style.css │ └── text.json ├── searchServer ├── build.sh ├── config │ ├── deviceConfig.go │ ├── ekstep_config.json │ └── tracelog.go ├── edu │ ├── commonUtil.go │ ├── contentHomeUtil.go │ ├── ecarManifest.go │ ├── eduInit.go │ ├── eduRouter.go │ ├── esContentListingJson.go │ ├── searchEngine.go │ ├── searchQuery.go │ └── searchResponse.go ├── http_util.go ├── main.go ├── server.go └── test │ ├── abc.json │ ├── test_script.sh │ └── xyz.json ├── searchsdk ├── config.js ├── index.js ├── package-lock.json └── package.json └── telemetrysdk ├── index.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | build 3 | node_modules/ 4 | apiserver/vendor 5 | devmgmtV2/.eslintrc.json 6 | devmgmtui/.eslintrc.json 7 | -------------------------------------------------------------------------------- /CDN/addContent.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #### Scripto add content(teach kits for example) to flash 4 | 5 | 6 | start=128 7 | blocksize=512 8 | 9 | #To update 10 | datafile_path=/var/www/HMLT/docs 11 | database_path=/var/www/api_server/ 12 | 13 | 14 | mount_path=/tmp/mount 15 | 16 | help () 17 | { 18 | echo $0 " " 19 | echo "Will add the files in to and will also update the databasefile " 20 | exit -1 21 | } 22 | 23 | 24 | if [ $# -lt 3 ] 25 | then 26 | help 27 | fi 28 | 29 | echo "Now coping all the contents in $1/ to $3 and will update database file $2" 30 | echo "Hit any key to continue.." 31 | 32 | read 33 | 34 | offset=`expr $start '*' $blocksize` 35 | 36 | mkdir -p $mount_path 37 | 38 | ## First let us mount the img file.. 39 | mount -o loop,offset=$offset $3 $mount_path 40 | 41 | 42 | ## cp the contents 43 | cp $1/* $mount_path/$1 44 | 45 | ## copy the database files 46 | 47 | cp $2 $mount_path/$database_path/ 48 | 49 | umount $mount_path 50 | 51 | rmdir $mount_path 52 | 53 | -------------------------------------------------------------------------------- /CDN/devicemgmtserver: -------------------------------------------------------------------------------- 1 | sleep 2 2 | /usr/bin/python /opt/opencdn/devmgmt/file_upload/manage.py runserver 0.0.0.0:8008 3 | -------------------------------------------------------------------------------- /CDN/get_internet_status: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ### Script to get internet status, an optimized logic need to be developed, until than, a simple approach 3 | 4 | ### For now it is not connected 5 | echo 0 6 | exit -1 7 | -------------------------------------------------------------------------------- /CDN/get_ssid.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ##Works only on device that has wlan device name as wlan0 4 | 5 | iw dev wlan0 info | grep ssid | cut -f 2 -d ' ' 6 | -------------------------------------------------------------------------------- /CDN/getall_stations.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | iw dev wlan0 station dump | grep Station | wc -l 3 | -------------------------------------------------------------------------------- /CDN/modeChange.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Script to move device from AP mode to client mode and vice-a-versa 3 | 4 | 5 | ### Copy interfaces file for static config 6 | 7 | static () { 8 | 9 | cat << EOF > /etc/network/interfaces 10 | auto lo 11 | iface lo inet loopback 12 | 13 | #auto eth0 14 | allow-hotplug eth0 15 | iface eth0 inet dhcp 16 | 17 | 18 | auto wlan0 19 | allow-hotplug wlan0 20 | iface wlan0 inet static 21 | address 192.168.0.1 22 | netmask 255.255.255.0 23 | EOF 24 | 25 | } 26 | 27 | ## Copy interfaces file for dhcp config 28 | 29 | dynamic_psk () { 30 | 31 | cat << EOF > /etc/network/interfaces 32 | auto lo 33 | iface lo inet loopback 34 | 35 | #auto eth0 36 | allow-hotplug eth0 37 | iface eth0 inet dhcp 38 | 39 | auto wlan0 40 | allow-hotplug wlan0 41 | iface wlan0 inet dhcp 42 | wpa-psk "$PSK" 43 | wpa-ssid "$SSID" 44 | EOF 45 | 46 | } 47 | 48 | 49 | dynamic_none () { 50 | 51 | cat << EOF > /etc/network/interfaces 52 | auto lo 53 | iface lo inet loopback 54 | 55 | #auto eth0 56 | allow-hotplug eth0 57 | iface eth0 inet dhcp 58 | 59 | auto wlan0 60 | allow-hotplug wlan0 61 | iface wlan0 inet dhcp 62 | wpa-ssid "$SSID" 63 | wpa-key-mgmt NONE 64 | EOF 65 | 66 | 67 | } 68 | 69 | hostapd_conf () { 70 | cat << EOF > /etc/hostapd/hostapd.conf 71 | interface=wlan0 72 | ssid=$SSID 73 | hw_mode=g 74 | channel=2 75 | ieee80211n=1 76 | auth_algs=1 77 | 78 | EOF 79 | } 80 | 81 | help () { 82 | echo "" 83 | echo "$0 hostmode []|apmode " 84 | echo "" 85 | 86 | exit -1 87 | 88 | } 89 | 90 | stop_apmode() 91 | { 92 | 93 | #stop few services 94 | /usr/sbin/service hostapd stop #if called second time, just to change the SSID 95 | /usr/sbin/service dnsmasq stop 96 | /usr/sbin/service dhcpcd stop 97 | /usr/sbin/service wpa_supplicant stop 98 | 99 | #Kill manually triggered wpa_supplicant 100 | killall -15 wpa_supplicant # Stop any manually triggered process 101 | } 102 | 103 | start_apmode() 104 | { 105 | 106 | # restart networking 107 | /usr/sbin/service networking restart 108 | 109 | # restart other services 110 | /usr/sbin/service hostapd start 111 | /usr/sbin/service dnsmasq start 112 | 113 | # Enable services 114 | /bin/systemctl enable hostapd 115 | /bin/systemctl enable dnsmasq 116 | 117 | } 118 | 119 | 120 | ###Parse the commands 121 | 122 | if [ "$1" == "apmode_restore" ] # hidden option to start AP mode with a file 123 | then 124 | 125 | stop_apmode 126 | #update /etc/network/interfaces 127 | static 128 | 129 | start_apmode 130 | 131 | exit 0 132 | fi 133 | 134 | if [ $# -lt 1 ] 135 | then 136 | help 137 | fi 138 | 139 | if [ "$1" == "hostmode" ] 140 | then 141 | ## move to hostmode 142 | ## Stop hostapd, dhcpserver, dns server and dhcpclient (cleanup) 143 | 144 | stop_apmode 145 | 146 | SSID=$2 147 | if [ $# -eq 3 ] 148 | then 149 | PSK=$3 150 | dynamic_psk 151 | else 152 | dynamic_none 153 | fi 154 | 155 | sync; sync; sync 156 | 157 | sleep 2 158 | ifdown wlan0 159 | sleep 2 160 | ifup wlan0 161 | 162 | echo Done... 163 | 164 | 165 | exit 0 166 | 167 | 168 | ##Let us verify if connection was succefull 169 | STATUS=`cat /sys/class/net/wlan0/operstate` 170 | 171 | if [ "$STATUS" == "up" ] 172 | then 173 | ### put the /etc/networking/interfaces file back, so that across reload, the box 174 | ### come back as AP 175 | static 176 | exit 0 177 | fi 178 | 179 | ##status not ok, we will start apmode again 180 | 181 | $0 apmode_restore 182 | exit 0 183 | 184 | 185 | fi 186 | 187 | if [ "$1" == "apmode" ] 188 | then 189 | 190 | stop_apmode 191 | #update /etc/network/interfaces 192 | static 193 | #update hostapd.conf 194 | SSID=$2 195 | hostapd_conf 196 | start_apmode 197 | 198 | exit 0 199 | fi 200 | 201 | help 202 | -------------------------------------------------------------------------------- /CDN/netconnect_status.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | status="false" 3 | errcode=1 4 | for i in 1 2 3; do 5 | ping -q -c 1 -w 2 8.8.8.8 6 | if [ $? -eq 0 ]; then 7 | #connected 8 | status="true" 9 | errcode=0 10 | break 11 | fi 12 | done 13 | echo $status 14 | return $errcode -------------------------------------------------------------------------------- /CDN/postpreinstall.sh: -------------------------------------------------------------------------------- 1 | ## Save fles 2 | 3 | files_saved=" 4 | /opt/opencdn/rootfs_overlay/etc/hostapd/hostapd.conf 5 | /opt/opencdn/rootfs_overlay/var/www/ekstep/config_json/config.json 6 | " 7 | save_files() 8 | { 9 | echo "Saving files" 10 | 11 | for i in $files_saved 12 | do 13 | cp $i /tmp 14 | done 15 | 16 | } 17 | 18 | restore_files() 19 | { 20 | echo "Restoring files" 21 | 22 | for i in $files_saved 23 | do 24 | mv /tmp/`echo $i | awk -F/ '{print $NF}'` $i 25 | done 26 | } 27 | 28 | install_aria2() 29 | { 30 | echo "Installing aria2" 31 | dpkg -i /tmp/aria2_deb/* 32 | } 33 | 34 | remove_aria2_deb() 35 | { 36 | echo "Cleaning aria2 deb files" 37 | rm -rf /tmp/aria2_deb 38 | } 39 | 40 | post_install() 41 | { 42 | echo "Running post install scripts" 43 | restore_files 44 | 45 | # Create a dir for searchdb (if not present) 46 | mkdir -p /opt/searchEngine/bleveDbDir/ 47 | mkdir -p /home/admin/GoK/ 48 | 49 | #Set System time-zone 50 | sudo timedatectl set-timezone Asia/Kolkata 51 | 52 | # Install aria2 and clean up the deb files used 53 | install_aria2 54 | remove_aria2_deb 55 | 56 | systemctl enable searchserver 57 | 58 | systemctl enable appserver 59 | 60 | systemctl enable syncthing 61 | 62 | systemctl enable aria2 63 | 64 | which ntpd 65 | x=$(echo $?) 66 | if [ $x -eq 0 ] 67 | then 68 | #There were two NTP clients on the system, ntp and systemd-timesyncd.Both were trying to set the date and were conflicting.The ntp is purged to resolve the conflict. 69 | echo "Y" | apt purge ntp 70 | fi 71 | 72 | #Optimize the system 73 | rm -rf /var/log/daemon.log 74 | ln -s /dev/null /var/log/daemon.log 75 | 76 | rm -rf /var/log/dnsmasq.log 77 | ln -s /dev/null /var/log/dnsmasq.log 78 | 79 | rm -rf /var/log/syslog 80 | ln -s /dev/null /var/log/syslog 81 | 82 | update-rc.d dphys-swapfile remove 83 | 84 | exit 0 85 | } 86 | 87 | pre_install() 88 | { 89 | echo "Running pre install scripts" 90 | save_files 91 | 92 | exit 0 93 | } 94 | 95 | 96 | if [ "$1" == "-post" ] 97 | then 98 | post_install 99 | fi 100 | 101 | if [ "$1" == "-pre" ] 102 | then 103 | pre_install 104 | fi 105 | 106 | echo "$0 <-post | -pre>" 107 | -------------------------------------------------------------------------------- /CDN/profile.json: -------------------------------------------------------------------------------- 1 | { 2 | "active_profile": "ekstep", 3 | "available_profiles": { 4 | "ekstep": { 5 | "accepted_extensions": [ 6 | ".ecar", 7 | ".json" 8 | ], 9 | "cdn_scripts_dir": "/opt/opencdn/CDN/", 10 | "cdn_url": "http://cdn.ekstep.com", 11 | "config_json_dir": "/var/www/ekstep/config_json/", 12 | "config_json_name": "config.json", 13 | "content_root": "/var/www/ekstep/ecar_files/", 14 | "json_dir": "/var/www/ekstep/json_dir/", 15 | "media_root": "/var/www/ekstep/", 16 | "profile_name": "ekstep", 17 | "server_root": "/opt/opencdn/devmgmt/file_upload/", 18 | "telemetry": "/var/www/ekstep/telemetry/", 19 | "unzip_content": "/var/www/ekstep/xcontent/", 20 | "unzip_contentdir_name": "xcontent", 21 | "usb_dir": "ecar_files", 22 | "usb_on_automount": "/media/" 23 | }, 24 | "meghshala": { 25 | "accepted_extensions": [ 26 | ".data", 27 | ".json" 28 | ], 29 | "cdn_scripts_dir": "/opt/opencdn/CDN/", 30 | "cdn_url": "http://edge.meghshala.com", 31 | "config_json_dir": "/var/www/meghshala/config_json/", 32 | "config_json_name": "config.json", 33 | "content_root": "/var/www/meghshala/content/", 34 | "json_dir": "/var/www/meghshala/json_dir/", 35 | "media_root": "/var/www/meghshala/", 36 | "profile_name": "meghshala", 37 | "server_root": "/opt/opencdn/devmgmt/file_upload/", 38 | "telemetry": "/var/www/meghshala/telemetry/", 39 | "unzip_content": "/var/www/meghshala/content/", 40 | "unzip_contentdir_name": "content", 41 | "usb_dir": "data_files", 42 | "usb_on_automount": "/media/" 43 | }, 44 | "pinut": { 45 | "accepted_extensions": [ 46 | ".mp4", 47 | ".mov", 48 | ".mp3", 49 | ".png", 50 | ".jpeg", 51 | ".pdf" 52 | ], 53 | "cdn_scripts_dir": "/opt/opencdn/CDN/", 54 | "cdn_url": "http://app.pinut.in", 55 | "config_json_dir": "/var/www/pinut_data/config_json/", 56 | "config_json_name": "config.json", 57 | "content_root": "/var/www/pinut_data/content/", 58 | "json_dir": "/var/www/pinut_data/json_dir/", 59 | "media_root": "/var/www/pinut_data/", 60 | "profile_name": "pinut", 61 | "server_root": "/opt/opencdn/devmgmt/file_upload/", 62 | "telemetry": "/var/www/pinut_data/telemetry/", 63 | "unzip_content": "/var/www/pinut_data/content/", 64 | "unzip_contentdir_name": "content", 65 | "usb_dir": "pinut_data", 66 | "usb_on_automount": "/media/" 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /CDN/revert.sh: -------------------------------------------------------------------------------- 1 | 2 | rm -rf /opt/opencdn; 3 | 4 | mv /opt/opencdn.old /opt/opencdn; 5 | -------------------------------------------------------------------------------- /CDN/usb_handler-2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | logdir=/tmp/ 3 | 4 | #/bin/udisksctl 5 | 6 | usb_logfile=$logdir/usb_handler.log 7 | 8 | #Make sure directory structure exists 9 | #mkdir -p $logdir > /dev/null 2>&1 10 | 11 | sleep 2 12 | echo "$(date): $ACTION: Calling usb_handler for $@" >> $usb_logfile 13 | 14 | if [ $# != 1 ]; then 15 | echo "$(date): $ACTION: No device mentioned to handle...." >> $usb_logfile 16 | exit 0; 17 | fi 18 | 19 | mount_dir=/media/$1 20 | 21 | if [ "X_$ACTION" = "X_add" ]; then 22 | echo "$(date): $ACTION: device $1 ....">> $usb_logfile 23 | mkdir -p $mount_dir > /dev/null 2>&1 24 | #echo "mount -w /dev/$1 $mount_dir" >> $usb_logfile 25 | #/usr/bin/udisksctl mount -b /dev/$1 26 | /bin/mount -w -o utf8 /dev/$1 $mount_dir >> $usb_logfile 27 | status=$? 28 | if [ "$status" -ne "0" ]; then 29 | echo "failure($status): mount -w /dev/$1 $mount_dir" >> $usb_logfile 30 | else 31 | echo "success($status): mount -w /dev/$1 $mount_dir" >> $usb_logfile 32 | fi 33 | #/usr/bin/pmount --umask 000 --noatime --charset utf8 $1 $1 34 | 35 | elif [ "X_$ACTION" = "X_remove" ]; then 36 | echo "$(date): $ACTION: device $1 ....">> $usb_logfile 37 | #/usr/bin/pumount $1 38 | #/usr/bin/udisksctl unmount -b /dev/$1 39 | /bin/umount $mount_dir 40 | status=$? 41 | if [ "$status" -ne "0" ]; then 42 | echo "failure($status): umount $mount_dir" >> $usb_logfile 43 | else 44 | echo "success($status): umount $mount_dir" >> $usb_logfile 45 | fi 46 | rmdir -r $mount_dir > /dev/null 2>&1 47 | fi 48 | sleep 2 49 | -------------------------------------------------------------------------------- /CDN/usb_handler.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | ACTION=$ACTION /opt/opencdn/CDN/usb_handler-2.sh $@ & 3 | -------------------------------------------------------------------------------- /CDN/version.txt: -------------------------------------------------------------------------------- 1 | 2.21.1-DK 2 | -------------------------------------------------------------------------------- /Documents/MeghashalaProductionSteps.txt: -------------------------------------------------------------------------------- 1 | a. A base image, pristibe image is polished with all necessary software, 2 | made avilable as img file 3 | b. Run "upgrade " 4 | c. dd the image from step b, to a 32G flash 5 | d. boot the new flash 6 | d1. You may have to run raspi-config --> expand-rootfs 7 | e. run "megshala_custom" as pi user 8 | f. re-load the box 9 | g. login into admin portal, upload the teach-kit 10 | h. shutdown the box, now the flash in the box is ready for imaging 11 | 12 | i. subsequent images are dd from the imaging flash -------------------------------------------------------------------------------- /Documents/SystemTest.txt: -------------------------------------------------------------------------------- 1 | System test cases 2 | 3 | Test case 1 4 | 5 | Description: Verify production 6 | a. Install opencdn.tgz into opencdn_nocdn image, via upgrade command 7 | b. DD image to flash 8 | c. boot with the new flash and verify 9 | i. WiFi comes up with correct SSID ---> Verified 10 | ii. All IP address are ok ---> Verified 11 | iii. admin page is accesable ---FAILED!! --> Fixed, issue with django version 12 | iv. Meghashala app works ---> Verified 13 | 14 | 15 | Test case 2 16 | Decription: Verify upgrade --> PASSED 17 | 18 | 19 | Test case 3 20 | Description: Verify Mode change to client 21 | 22 | a. Once OCDN is booted, login to to admin page 23 | b. Change the mode to host mode, connect to a AP 24 | c. Verify mode change is succsful 25 | d. Reboot, verify box come back as AP mode 26 | 27 | Test case 4 28 | Description: Verify mode change from AP -> Host -> AP 29 | 30 | 31 | Test case 5 32 | DHCP client longivity test 33 | After couple of days, plugin ethernet cable to ethernet port, verify IP 34 | address is leased on eth0 interface 35 | 36 | -------------------------------------------------------------------------------- /Documents/example_cmdline.txt: -------------------------------------------------------------------------------- 1 | # Pristine raspbian options: 2 | dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=ee397c53-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet init=/usr/lib/raspi-config/init_resize.sh 3 | # No flash expansion: 4 | dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=ee397c53-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet 5 | # No renaming of eth0: 6 | dwc_otg.lpm_enable=0 console=serial0,115200 console=tty1 root=PARTUUID=ee397c53-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet net.ifnames=0 7 | 8 | 9 | -------------------------------------------------------------------------------- /Documents/modeChangeUT.txt: -------------------------------------------------------------------------------- 1 | a. The box comes up as AP, change to host mode 2 | --> Verify the box in host node, reboot the box and verify in host mode 3 | --> verify connects to AP with correct credentials 4 | TESTED PASSED 5 | 6 | 7 | b. The box comes up in host mode, change to ap mode, 8 | --> verify the box is in AP mode, re-boot and confirm 9 | --> Verify the AP SSID is as per configurations 10 | TESTED PASSED 11 | 12 | c. The box comes up in AP mode, change to host mode and back to AP mode 13 | --> Verify box moves from AP, host and AP 14 | --> re-boot and verify the box is in AP mode 15 | TESTED PASSS 16 | 17 | d. The box comes up in host mode, change to AP mode and back to host mode 18 | --> Verify box moves from host to AP to host 19 | --> re-bbot and verify the box is in host mode 20 | TESTED PASS 21 | 22 | e. The box is AP mode, change to AP mode, with different SSID 23 | --> Verify SSID changes, reboot and confirm new SSID is workig 24 | TESTED PASS 25 | 26 | f. The box is host mode, change it AP mode with different AP to join 27 | --> Verify new SSID is used for connection, also verify across re-boot 28 | TESTED PASS 29 | 30 | g. Verify connecting to AP with WPA, PSK 31 | TESTED PASS 32 | 33 | h. Verify connecting to AP run on a phone hotspot 34 | TESTED PASS 35 | -------------------------------------------------------------------------------- /Documents/telemetry_upload_2_qa.sh: -------------------------------------------------------------------------------- 1 | #curl -X POST -H "Content-Type: application/octet-stream" --data-binary '@filename' http://127.0.0.1:5050/upload 2 | #curl -X POST -H "Content-Type: application/json" -H "Content-Encoding: gzip" --data-binary '@filename' http://127.0.0.1:5050/api/telemetry/v1/telemetry 3 | set -xv 4 | 5 | #!/bin/bash 6 | if [ $# -ne 1 ]; then 7 | echo "Usage: request.sh " 8 | exit 1 9 | fi 10 | 11 | addr=qa.ekstep.in 12 | 13 | contentfile=$1 14 | 15 | tmp_out_file=/tmp/abc.json 16 | out_file=output_telemetry_upload 17 | 18 | admin_key="" 19 | app_key="" 20 | app_secret="" 21 | mobile_key="" 22 | mobile_secret="" 23 | 24 | 25 | #post query to upload telemetry into ekstep server 26 | 27 | 28 | curl \ 29 | -v \ 30 | -H 'Content-Type:application/json' \ 31 | -H 'Content-Encoding:gzip' \ 32 | -H 'Authorization:bearer eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwaWVudXQxIn0.6iJ5n_A3FKQjxouDkLdnm1lLSehYX4aDGfEDP5J_9is' \ 33 | -X POST \ 34 | -o $tmp_out_file \ 35 | --data-binary @$contentfile \ 36 | https://${addr}/api/data/v3/telemetry 37 | -------------------------------------------------------------------------------- /Documents/upgradeUT.txt: -------------------------------------------------------------------------------- 1 | UT test case for upgrade 2 | 3 | a. Verify upgrade with standard package, version grater than current one 4 | --> Expect new package is installed correctly 5 | --> old paclage is removed 6 | --> link created to new package in /opt/opencdn 7 | --> all the files in rootfs_overlay are linked to / dir correctly 8 | 9 | ===> Passed 10 | 11 | 12 | b. Verify upgrade with older version 13 | --> Installed package must not be installed 14 | --> /opt/opencdn lilnk is intact with older package 15 | 16 | ===> Passed -------------------------------------------------------------------------------- /INSTALL.md: -------------------------------------------------------------------------------- 1 | # OpenRAP 2 | 3 | This repository contains the information and references needed to run [OpenRAP](http://openrap.io/) in a Production environment. 4 | 5 | ## Table of content 6 | 7 | - [Prerequisites](#prerequisites) 8 | - [Installation](#installation) 9 | - [Developer](#developer) 10 | - [Production](#production) 11 | - [Installation Details](#installation-details) 12 | - [Deployment architecture](#deployment-architecture) 13 | - [License](#license) 14 | 15 | ## Prerequisites 16 | This section should expand as open source contributions to support multiple run times increase over time. Presently, the software and reference steps consider the following tech stack: 17 | 18 | Required: 19 | - Linux, preferably Raspbian Jessie 20 | 21 | ## Installation 22 | ### Developer 23 | Make sure that golang compiler is installed in your Linux/MacOS development environment 24 | ### Production 25 | The software is based on linux debian(raspbian) based raspberrypi3 board device. It can be installed on different boards supporting similar linux platform with required packages installed. 26 | - Visit raspbian page to download and burn a flash image 27 | - Boot the image 28 | - Clone this repository and build it. 29 | - Copy the software package into the raspbian and install it 30 | - Reboot the system 31 | 32 | ## Installation Details 33 | Following are some sample commands to automate various acts. 34 | ### Install golang into development laptop 35 | ### Build the image 36 | ./buildimage.py --help 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Ekstep Org. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenRAP 2 | Repository for Content related to Open RAP (Resource Access Point) 3 | 4 | **Note:** 5 | All the releases will be made from `master` branch. 6 | `develop-v3` is the development branch and finally this will be merged with the `master` branch. 7 | 8 | Following branches are archived: 9 | * diksha-specific-changes 10 | * forwater-specific-changes-update 11 | * forwater-specific-changes 12 | * ravish/decouple-plugin-code 13 | * master_old 14 | * develop_old 15 | * develop-v2 16 | 17 | One can get back these branches using the command: `git checkout -b archive/` 18 | For more details you can refer to [this](https://stackoverflow.com/questions/1307114/how-can-i-archive-git-branches/4292670#4292670) website 19 | 20 | 21 | -------------------------------------------------------------------------------- /appServer/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | Server entry file. 3 | No changes are required here to load a plugin 4 | */ 5 | 6 | 'use strict'; 7 | 8 | const express = require('express'); 9 | const bodyParser = require('body-parser'); 10 | const app = express(); 11 | //app.use(bodyParser.urlencoded({ extended: true })); 12 | //app.use(bodyParser.raw()); 13 | app.use(bodyParser.json()); 14 | const glob = require('glob'); 15 | const pluginPath = '/opt/opencdn/appServer/plugins'; 16 | /* 17 | Loading all the plugins from plugin directory 18 | */ 19 | 20 | glob(pluginPath + "/**/*.routes.js", function (er, files) { 21 | for (let i = 0; i < files.length; i++) { 22 | require(files[i])(app); 23 | } 24 | }); 25 | 26 | /* 27 | Starting the server on port 9090. 28 | TODO: make the port configurable later 29 | */ 30 | 31 | app.listen(9090, err => { 32 | if (err) 33 | console.log(err); 34 | else 35 | console.log("listening on 9998"); 36 | }) 37 | -------------------------------------------------------------------------------- /appServer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "appserver", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "MIT", 11 | "dependencies": { 12 | "bcrypt": "^2.0.1", 13 | "body-parser": "^1.18.2", 14 | "connect-multiparty": "^2.1.0", 15 | "cors": "^2.8.4", 16 | "express": "^4.16.3", 17 | "form-data": "^2.3.2", 18 | "getmac": "^1.4.3", 19 | "glob": "^7.1.2", 20 | "jsonwebtoken": "^8.2.1", 21 | "moment": "^2.22.2", 22 | "node-cron": "^1.2.1", 23 | "node-zip": "^1.1.1", 24 | "q": "^1.5.1", 25 | "random-mac": "0.0.4", 26 | "request": "^2.87.0", 27 | "uniqid": "^5.0.3", 28 | "unzip2": "^0.2.5", 29 | "winston": "^2.4.2", 30 | "xlsx": "^0.14.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /appServer/plugins/ekStep/config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const BASE_URL = 'http://localhost:9090'; 4 | const HOME_EXT = 'api/page/v1/assemble/org.ekstep.genie.content.home'; 5 | const SEARCH_EXT = 'api/search/v2/search'; 6 | const ID_MIDDLE = 'api/learning/v2/content/'; 7 | const TELEMETRY_EXT = 'api/telemetry/v1/telemetry'; 8 | 9 | module.exports = { 10 | BASE_URL, 11 | HOME_EXT, 12 | SEARCH_EXT, 13 | ID_MIDDLE, 14 | TELEMETRY_EXT, 15 | } 16 | -------------------------------------------------------------------------------- /appServer/plugins/ekStep/ekstep.db_restart.js: -------------------------------------------------------------------------------- 1 | 2 | let q = require('q'); 3 | let { init, createIndex, deleteIndex, getAllIndices } = require('../../../searchsdk/index.js'); 4 | 5 | 6 | /* 7 | * Check if index exists 8 | * If not, create 9 | * If so, carpet bomb 10 | * Then load 11 | */ 12 | 13 | 14 | let checkIfIndexExists = (iName) => { 15 | let defer = q.defer(); 16 | getAllIndices().then(value => { 17 | let indices = JSON.parse(value.body).indexes; 18 | console.log(indices); 19 | if (indices.indexOf(iName) === -1) { 20 | console.log("The database does not exist, create new one."); 21 | return defer.reject(); 22 | } else { 23 | console.log("The database exists, delete and create new one."); 24 | return defer.resolve(); 25 | } 26 | }); 27 | return defer.promise; 28 | } 29 | 30 | let initializeESDB = () => { 31 | let defer = q.defer(); 32 | checkIfIndexExists("es.db").then(value => { 33 | deleteIndex({indexName: "es.db"}).then(value => { 34 | console.log("Deleted index"); 35 | return createIndex({indexName: "es.db"}); 36 | }).then(value => { 37 | console.log("Index created"); 38 | return init(); 39 | }).then(value => { 40 | return defer.resolve(); 41 | }).catch(e => { 42 | console.log("Recreate error: "); 43 | return defer.rejeect(e); 44 | }); 45 | }, reason => { 46 | createIndex({indexName: "es.db"}).then(value => { 47 | console.log("Created new index"); 48 | return init(); 49 | }).then(value => { 50 | return defer.resolve(); 51 | }).catch(e => { 52 | console.log("Create error: "); 53 | return defer.reject(e); 54 | }); 55 | }); 56 | return defer.promise; 57 | } 58 | 59 | /* 60 | initializeESDB().then(value => { 61 | console.log("successfully initialized DB"); 62 | }).catch(e => { 63 | console.log(e); 64 | }); 65 | */ 66 | 67 | module.exports = { 68 | initializeESDB 69 | } 70 | -------------------------------------------------------------------------------- /appServer/plugins/ekStep/ekstep.middleware.js: -------------------------------------------------------------------------------- 1 | let { initializeEkstepData } = require('./ekstep.init.js') 2 | 3 | let ekStepData = {}; 4 | 5 | let addEkStepData = (req, res, next) => { 6 | req.ekStepData = ekStepData; 7 | next(); 8 | } 9 | 10 | initalizeMiddleWare = () => { 11 | initializeEkstepData('/opt/opencdn/appServer/plugins/ekStep/profile.json').then(value => { 12 | ekStepData = value; 13 | }); 14 | } 15 | 16 | initalizeMiddleWare(); 17 | 18 | module.exports = { 19 | addEkStepData 20 | } 21 | -------------------------------------------------------------------------------- /appServer/plugins/ekStep/ekstep.routes.js: -------------------------------------------------------------------------------- 1 | 2 | let { addEkStepData } = require('./ekstep.middleware.js') 3 | let { getHomePage, getEcarById, performSearch, telemetryData, extractFile, performRecommendation, createFolderIfNotExists, syncMadhi } = require('./ekstep.controller.js'); 4 | // let { uploadTelemetryToCloud } = require('./ekstep.telemetry_upload.js'); 5 | 6 | module.exports = app => { 7 | /* 8 | EkStep routes as defined in apiserver/ekstep/esInit.go 9 | */ 10 | app.post('/api/page/v1/assemble/org.ekstep.genie.content.home', getHomePage); 11 | app.post('/data/v3/pageApi/assemble/org.ekstep.genie.content.home', getHomePage); 12 | app.post('/api/data/v3/pageApi/assemble/org.ekstep.genie.content.home', getHomePage); 13 | 14 | app.get('/api/learning/v2/content/:contentID', getEcarById); 15 | app.get('/content/v3/read/:contentID', getEcarById); 16 | app.get('/api/content/v3/read/:contentID', getEcarById); 17 | 18 | app.post('/api/telemetry/v1/telemetry', addEkStepData, telemetryData); 19 | app.post('/data/v3/telemetry', addEkStepData, telemetryData); 20 | app.post('/api/data/v3/telemetry', addEkStepData, telemetryData); 21 | 22 | app.post('/api/search/v2/search', performSearch); 23 | app.post('/composite/v3/search', performSearch); 24 | app.post('/api/composite/v3/search', performSearch); 25 | 26 | app.get('/api/sync/:profile', syncMadhi); 27 | 28 | app.post('/api/content/v3/recommend', performRecommendation); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /appServer/plugins/ekStep/madhi_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "teacher": "/home/admin/ekstep/config_madhi/Madhi Teacher Master data.xlsx", 3 | "student": [ 4 | ["CHENNAI", "ADYAR", "1", "ADR", "TEST_SCHOOL", "A", "MAS_ADR_001_002", "Ashok", "MALE"] 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /appServer/plugins/ekStep/profile.json: -------------------------------------------------------------------------------- 1 | { 2 | "active_profile": "ekstep", 3 | "available_profiles": { 4 | "ekstep": { 5 | "accepted_extensions": [ 6 | ".ecar", 7 | ".json" 8 | ], 9 | "cdn_scripts_dir": "/opt/opencdn/CDN/", 10 | "cdn_url": "http://www.openrap.com", 11 | "config_json_dir": "/home/admin/ekstep/config_json/", 12 | "config_json_name": "config.json", 13 | "content_root": "/home/admin/ekstep/ecar_files/", 14 | "json_dir": "/home/admin/ekstep/json_dir/", 15 | "media_root": "/home/admin/ekstep/", 16 | "profile_name": "ekstep", 17 | "server_root": "/opt/opencdn/devmgmt/file_upload/", 18 | "telemetry": "/home/admin/ekstep/telemetry/", 19 | "unzip_content": "/home/admin/ekstep/xcontent/", 20 | "unzip_contentdir_name": "xcontent", 21 | "usb_dir": "ecar_files", 22 | "usb_on_automount": "/media/" 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /appServer/plugins/ekStep/searchIdResponseSkeleton.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "ekstep.content.find", 3 | "params": { 4 | "err": "", 5 | "errmsg": "", 6 | "msgid": "", 7 | "resmsgid": "fecdd171-826b-4287-b6a4-8b136b94bc48", 8 | "status": "successful" 9 | }, 10 | "responseCode": "OK", 11 | "result": { 12 | "content": {}, 13 | "count": 0 14 | }, 15 | "ts": "", 16 | "ver": "3" 17 | } 18 | -------------------------------------------------------------------------------- /appServer/plugins/ekStep/searchResponseSkeleton.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "ekstep.composite-search.search", 3 | "ver": "2.0", 4 | "ts": "2017-06-21T08:45:23ZZ", 5 | "params": { 6 | "resmsgid": "0211201a-c91e-41d6-ad25-392de813124c", 7 | "msgid": "", 8 | "err": "", 9 | "status": "successful", 10 | "errmsg": "" 11 | }, 12 | "responseCode": "OK", 13 | "result": { 14 | "count": 0, 15 | "content": [], 16 | "facets": [ 17 | { 18 | "values": [], 19 | "name": "" 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /appServer/plugins/ekStep/telemetryResponseSkeleton.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "ekstep.telemetry", 3 | "ver": "1.0", 4 | "ts": "2017-06-21T08:20:46+00:00", 5 | "params": { 6 | "resmsgid": "7e6213b5dd4ebde1c5021d4ea0f8b6cbec5aeb18", 7 | "msgid": "7x87bc52-afbg-4344-88bc-a2a90df5fe37", 8 | "status": "successful", 9 | "err": "", 10 | "errmsg": "" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /appServer/plugins/template/template.controller.js: -------------------------------------------------------------------------------- 1 | /* 2 | Template controller files 3 | Your program logic goes here . 4 | The functions contains the logic and should be exported to be used in routes 5 | */ 6 | 7 | 8 | let getAllUsers = (req, res) => { 9 | res.send("All Users"); 10 | } 11 | 12 | module.exports = { 13 | getAllUsers 14 | } 15 | -------------------------------------------------------------------------------- /appServer/plugins/template/template.routes.js: -------------------------------------------------------------------------------- 1 | /* 2 | Sample plugin entry file. 3 | File must be named as .routes.js and kept in plugin root directory 4 | A function is exported which takes in express app instance as argument 5 | 6 | */ 7 | 8 | /* 9 | Import the controller logic 10 | can be used for writing our logic for routes 11 | 12 | */ 13 | let { getAllUsers } = require('./template.controller'); 14 | 15 | 16 | module.exports = app => { 17 | 18 | /* 19 | Declare your middlewares here on app instance if required 20 | 21 | */ 22 | /* 23 | All your routes go here . 24 | Routes must be namespaced with plugin names to avoid any conflicting routes 25 | Each route will have respective controller attached to it 26 | */ 27 | 28 | //app.get(, [optional middleware], ) 29 | app.get('/template/allUsers', getAllUsers); 30 | 31 | /* 32 | You can also provide a init function here. 33 | This will get called while the plugin is initialized 34 | */ 35 | function init() { 36 | console.log("running init function") 37 | } 38 | /* 39 | Calling the init function here. {do not edit} 40 | */ 41 | init(); 42 | 43 | /* 44 | You can have multiple init functions here with diffferent name. 45 | Which can be used to seperate out logic into different groups 46 | */ 47 | } 48 | -------------------------------------------------------------------------------- /dbsdk/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dbsdk", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "bignumber.js": { 8 | "version": "4.0.4", 9 | "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.0.4.tgz", 10 | "integrity": "sha512-LDXpJKVzEx2/OqNbG9mXBNvHuiRL4PzHCGfnANHMJ+fv68Ads3exDVJeGDJws+AoNEuca93bU3q+S0woeUaCdg==" 11 | }, 12 | "core-util-is": { 13 | "version": "1.0.2", 14 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 15 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 16 | }, 17 | "inherits": { 18 | "version": "2.0.3", 19 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 20 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 21 | }, 22 | "isarray": { 23 | "version": "1.0.0", 24 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 25 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 26 | }, 27 | "mysql": { 28 | "version": "2.15.0", 29 | "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.15.0.tgz", 30 | "integrity": "sha512-C7tjzWtbN5nzkLIV+E8Crnl9bFyc7d3XJcBAvHKEVkjrYjogz3llo22q6s/hw+UcsE4/844pDob9ac+3dVjQSA==", 31 | "requires": { 32 | "bignumber.js": "4.0.4", 33 | "readable-stream": "2.3.3", 34 | "safe-buffer": "5.1.1", 35 | "sqlstring": "2.3.0" 36 | } 37 | }, 38 | "process-nextick-args": { 39 | "version": "1.0.7", 40 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", 41 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" 42 | }, 43 | "q": { 44 | "version": "1.5.1", 45 | "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", 46 | "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" 47 | }, 48 | "readable-stream": { 49 | "version": "2.3.3", 50 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", 51 | "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", 52 | "requires": { 53 | "core-util-is": "1.0.2", 54 | "inherits": "2.0.3", 55 | "isarray": "1.0.0", 56 | "process-nextick-args": "1.0.7", 57 | "safe-buffer": "5.1.1", 58 | "string_decoder": "1.0.3", 59 | "util-deprecate": "1.0.2" 60 | } 61 | }, 62 | "safe-buffer": { 63 | "version": "5.1.1", 64 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 65 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 66 | }, 67 | "sqlstring": { 68 | "version": "2.3.0", 69 | "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.0.tgz", 70 | "integrity": "sha1-UluKT9Jtb3GqYegipsr5dtMa0qg=" 71 | }, 72 | "string_decoder": { 73 | "version": "1.0.3", 74 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", 75 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", 76 | "requires": { 77 | "safe-buffer": "5.1.1" 78 | } 79 | }, 80 | "util-deprecate": { 81 | "version": "1.0.2", 82 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 83 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /dbsdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dbsdk", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "mysql": "^2.15.0", 13 | "q": "^1.5.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /dbsdk2/config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | getDbCredentials : (dbName) => { 5 | return { 6 | host : 'localhost', 7 | user : 'root', 8 | password : 'root', 9 | database : dbName 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /dbsdk2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdk", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "MIT", 11 | "dependencies": { 12 | "better-sqlite3": "^4.1.0", 13 | "mysql": "^2.15.0", 14 | "q": "^1.5.1", 15 | "sqlite3": "^3.1.13", 16 | "sqlstring": "^2.3.1" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /devmgmtV2/config.js: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is only a placeholder and will be replaced by the config.js under the plugin directory. 3 | */ 4 | 5 | module.exports = { 6 | "FS_ROOT": "/home/admin/", 7 | "username": "brandonStark", 8 | "password": "theBuilder", 9 | "serverIP": "35.198.199.222", 10 | "root_dir": "/home/admin/diksha/", 11 | "telemetryAPI": { 12 | "init": "http://35.198.199.222:8888/api/auth/v1/init", // Authenticates user and returns a token 13 | "hello": "http://35.198.199.222:8000/api/auth/v1/hello", // Checks if the user is authenticated 14 | "upload": "http://35.198.199.222:8000/api/auth/v1/telemetry/couchbase" // Load telemetry 15 | }, 16 | "keyFile": "/etc/telemetry_key", 17 | "cloud": { 18 | "search_api": { 19 | "url": "https://diksha.gov.in/api/composite/v1/search", 20 | "auth_token": "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJzdW5iaXJkLTUzMjhkMWFkMTE1ODNjMGM5OTRkM2M4MDY3MDdmMjYwODhkN2Q2MDkifQ.XKRvs1BCSeutDIc8VGuxq_v_JX0Z3flWbnmOhxVHEVU", 21 | "user_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ1WXhXdE4tZzRfMld5MG5PS1ZoaE5hU0gtM2lSSjdXU25ibFlwVVU0TFRrIn0.eyJqdGkiOiJjMDc0ODgxYi01OGYxLTQ2YzAtYWUwZC1hNTkwZGVkZWRhMTUiLCJleHAiOjE1MzYzNDc0MzcsIm5iZiI6MCwiaWF0IjoxNTM2MzA0MjM3LCJpc3MiOiJodHRwczovL3N0YWdpbmcub3Blbi1zdW5iaXJkLm9yZy9hdXRoL3JlYWxtcy9zdW5iaXJkIiwiYXVkIjoiYWRtaW4tY2xpIiwic3ViIjoiNWJkODIwYTItNTk5Zi00ZDEyLTliYzQtZjg3YTg5MjU2ZGU2IiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiYWRtaW4tY2xpIiwiYXV0aF90aW1lIjowLCJzZXNzaW9uX3N0YXRlIjoiYTZlNjZjOTMtNjliYS00NmM3LWJkMzAtMDE2MzAxOGQ3ZGI5IiwiYWNyIjoiMSIsImFsbG93ZWQtb3JpZ2lucyI6W10sInJlc291cmNlX2FjY2VzcyI6e30sIm5hbWUiOiLgrobgrprgrr_grrDgrr_grq_grrDgr40iLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJjb250ZW50Y3JlYXRvcmp1bmVvcmdAc3VuYmlyZC1zdGFnaW5nIiwiZ2l2ZW5fbmFtZSI6IuCuhuCumuCuv-CusOCuv-Cur-CusOCvjSIsImZhbWlseV9uYW1lIjoiIiwiZW1haWwiOiJjb250ZW50Y3JlYXRvckBqdW5lb3JnLmNvbSJ9.RIDIsVXvTY5UPibUYxaQKtS5ARhwPFPDYsJw_n2Xe5u_xJuxkTCCceO8ECojnt-9WRrDhUwQm7kiAK0h-4LFcqOrDwsXmh09xvAQ_FNcTbeRL0Rg_Qj1rQgNHE9M7tmZx1LZUe8FzDwxFhaQaeQ-wb9-o4wuAGjt5AuNQy6ffmS29iZlpuxLoJGy89b61Cytm-h_GAGfG9qmqIPQ_HIfT0XiEyuuHXS-A4Kiii5qDusTlb78mJRGbQ_BOBlRNmmCpVBUVyJ-AwjJyg7RHaHz9uHn0iRvh-BHH9xSfpxLSZxlkLCilJ048uLqjEwMGc35RqIspazW19cAa4XPwEO4Mg" 22 | }, 23 | "app_register_api": { 24 | "url": "https://diksha.gov.in/api/api-manager/v1/consumer/mobile_app_openrap/credential/register", 25 | "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIyZjg5NGZhOTAzY2M0NWU3ODc2NzdkNTdhMmJjZDY1NyJ9.j6PENpl5brIYYRoSf7kHI9JCHxQit-4_eKXJkBR_OVM" 26 | }, 27 | "device_register_api": { 28 | "url": "https://diksha.gov.in/api/api-manager/v1/consumer/mobile_device_openrap/credential/register", 29 | "token": "" 30 | }, 31 | "filter": { 32 | "keysToUse": [ 33 | "subject", 34 | "downloadUrl", 35 | "language", 36 | "appIcon", 37 | "gradeLevel", 38 | "contentType", 39 | "identifier", 40 | "size", 41 | "lastPublishedOn", 42 | "name", 43 | "status", 44 | "description", 45 | "creator", 46 | "pkgVersion" 47 | ] 48 | } 49 | } 50 | } 51 | 52 | -------------------------------------------------------------------------------- /devmgmtV2/controllers/auth.controller.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | let {selectFields, updateFields, deleteFields, insertFields} = require('dbsdk'); 3 | let q = require('q'); 4 | 5 | let defaultDbName = 'device_mgmt'; 6 | let defaultTableName = 'users'; 7 | 8 | 9 | function getColumnFromDB(name, column) { 10 | let queryObject = { 11 | dbName : defaultDbName, 12 | tableName : defaultTableName, 13 | fields : [column], 14 | where : "where username = '" + name + "'" 15 | }; 16 | return selectFields(queryObject); 17 | } 18 | 19 | function writeColumnToDB(name, column, newValue) { 20 | let queryObject = { 21 | dbName : defaultDbName, 22 | tableName : defaultTableName, 23 | fields : [{key:column, value:newValue}], 24 | where : "where username = '" + name + "'" 25 | }; 26 | return updateFields(queryObject); 27 | } 28 | 29 | function verifyIfUserExists(name) { 30 | 31 | let queryObject = { 32 | dbName : defaultDbName, 33 | tableName : defaultTableName, 34 | where : "where username = '" + name + "'" 35 | }; 36 | return selectFields(queryObject); 37 | } 38 | 39 | 40 | let authLogin = (req,res) => { 41 | 42 | let userName = req.body['username']; 43 | let password = req.body['password']; 44 | 45 | let responseStructure = { 46 | successful : false, 47 | msg : "", 48 | permissions: {} 49 | }; 50 | 51 | verifyIfUserExists(userName) 52 | .then( response => { 53 | if(typeof response[0] === "undefined" || response[0].password != password) { 54 | return { 55 | msg : "Invalid username or password", 56 | } 57 | }else{ 58 | return { 59 | successful :true, 60 | data : response[0]['permission'] 61 | } 62 | } 63 | }).then(data => { 64 | if(data.successful){ 65 | responseStructure.msg = "Login successful!"; 66 | responseStructure.successful = data.successful; 67 | } 68 | if(data.msg){ 69 | responseStructure.msg = data.msg; 70 | } 71 | if(data.data){ 72 | responseStructure.username = userName; 73 | responseStructure.permissions = data.data; 74 | } 75 | return res.status(200).send(responseStructure); 76 | }, err => { 77 | console.lg(err); 78 | responseStructure.msg = "Some server Error!!!"; 79 | return res.status(500).send(responseStructure); 80 | }); 81 | } 82 | 83 | 84 | let updatePassword = (req, res) => { 85 | let userName = req.body['username']; 86 | let newPassword = req.body['password']; 87 | let responseStructure = { 88 | successful : false, 89 | msg : "" 90 | } 91 | verifyIfUserExists(userName).then(response => { 92 | if (typeof response[0] === "undefined") { 93 | return { 94 | msg : "User does not exist" 95 | } 96 | } 97 | else { 98 | return { 99 | successful : true 100 | } 101 | } 102 | }, reject => { 103 | return { 104 | msg : "Check your input for illegal characters!" 105 | } 106 | }).then(response => { 107 | if (response.successful) { 108 | return writeColumnToDB(userName, 'password', newPassword); 109 | } 110 | else { 111 | responseStructure.msg = response.msg; 112 | let resStatus = response.msg.search("SQL") ? res.status(500) : res.status(404); 113 | return resStatus.json(responseStructure); 114 | } 115 | }).then(response => { 116 | responseStructure.msg = "Modification successful"; 117 | responseStructure.successful = true; 118 | return res.status(200).json(responseStructure); 119 | }, reject => { 120 | responseStructure.msg = "Unanticipated SQL error!"; 121 | return res.status(500).json(responseStructure); 122 | }); 123 | } 124 | 125 | module.exports = { 126 | authLogin, 127 | updatePassword 128 | } 129 | -------------------------------------------------------------------------------- /devmgmtV2/controllers/config.controller.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const config = require('../config'); 4 | 5 | const getConfig = (req, res) => { 6 | res.status(200).json(config); 7 | } 8 | 9 | module.exports = { 10 | getConfig 11 | } 12 | -------------------------------------------------------------------------------- /devmgmtV2/controllers/dashboard.controller.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const dns = require('dns'); 4 | const os = require('os-utils'); 5 | const diskspace = require('diskspace'); 6 | const fs = require("fs"); 7 | const path = require('path'); 8 | const exec = require('child_process').exec; 9 | 10 | const config = require('../config'); 11 | let { selectFields } = require('dbsdk'); 12 | 13 | let getInternetStatus = (req, res) => { 14 | let responseData = { 15 | retrieveSuccessful : true, 16 | data : false, 17 | msg : 'Successfully retrieved internet Status.' 18 | } 19 | 20 | const cmd = path.join(__dirname, '../../CDN/netconnect_status.sh'); 21 | 22 | exec(cmd, { shell: '/bin/bash' }, (err, stdout, stderr) => { 23 | 24 | if(err) { 25 | responseData.retrieveSuccessful = false; 26 | responseData.msg = err; 27 | } else { 28 | responseData.data = stdout.trim(); 29 | } 30 | 31 | res.status(200).json(responseData); 32 | }); 33 | } 34 | 35 | let getLastRefresh = (req, res) => { 36 | let meta = path.join(config.FS_ROOT, '.meta'); 37 | fs.readFile(meta, 'utf-8', (err, data = "Not refreshed yet") => { 38 | res.send({ data }); 39 | }) 40 | } 41 | 42 | let getNumberOfUsersConnected = (req, res) => { 43 | let responseData = { 44 | retrieveSuccessful : true, 45 | numberOfUsers : undefined, 46 | msg : 'Successfully retrieved number of users connected.' 47 | } 48 | 49 | const cmd = path.join(__dirname, '../../CDN/getall_stations.sh'); 50 | 51 | exec(cmd, { shell: '/bin/bash' }, (err, stdout, stderr) => { 52 | // console.log('Error: ' + err); 53 | // console.log('stdout: ' + stdout); 54 | // console.log('stderr: ' + stderr); 55 | 56 | if(err) { 57 | responseData.retrieveSuccessful = false; 58 | responseData.msg = err; 59 | } else { 60 | responseData.numberOfUsers = stdout.trim(); 61 | } 62 | 63 | res.status(200).json(responseData); 64 | }); 65 | } 66 | 67 | let getSystemMemory = (req, res) => { 68 | const total = os.totalmem(); 69 | const free = os.freemem(); 70 | const usage = os.freememPercentage()*100; 71 | const sysUpTime = os.sysUptime(); 72 | res.send({ 73 | total, 74 | free, 75 | usage, 76 | sysUpTime 77 | }) 78 | } 79 | 80 | 81 | let getSystemSpace = (req, res) => { 82 | diskspace.check('/', function (err, result) { 83 | res.send(result) 84 | }); 85 | } 86 | 87 | let getSystemCpu = (req,res) => { 88 | os.cpuUsage(function(v){ 89 | v = v * 100; 90 | res.send({v}) 91 | }); 92 | } 93 | 94 | let getSystemVersion = (req,res) => { 95 | let cdn = path.join(__dirname,"../../CDN/version.txt"); 96 | fs.readFile(cdn, 'utf-8', (err,data)=>{ 97 | // console.log(err); 98 | res.send({data}); 99 | }) 100 | } 101 | 102 | let getDeviceID = (req,res) => { 103 | let responseData = { 104 | retrieveSuccessful : true, 105 | deviceID : undefined, 106 | msg : 'Successfully retrieved device ID' 107 | } 108 | 109 | selectFields({dbName : 'device_mgmt', tableName : 'device', columns : ["dev_id"]}) 110 | .then(response => { 111 | responseData.deviceID = response[0].dev_id; 112 | return res.status(200).json(responseData); 113 | }, reject => { 114 | responseData.retrieveSuccessful = false; 115 | responseData.msg = err; 116 | return res.status(200).json(responseData); 117 | }); 118 | } 119 | 120 | let getSyncthingID = (req, res) => { 121 | let responseData = { 122 | retrieveSuccessful: true, 123 | syncthingID: undefined, 124 | msg: 'Successfully retrieved syncthing ID' 125 | } 126 | 127 | const cmd = 'sudo /opt/opencdn/CDN/syncthing -device-id'; 128 | 129 | exec(cmd, { shell: '/bin/bash' }, (err, stdout, stderr) => { 130 | if (err) { 131 | console.log("Error occurred while fetching syncthing ID\n", JSON.stringify({ err, stderr }, null, 4)); 132 | 133 | responseData.retrieveSuccessful = false; 134 | responseData.msg = err; 135 | } else { 136 | responseData.syncthingID = stdout.trim(); 137 | } 138 | 139 | res.status(200).json(responseData); 140 | }); 141 | } 142 | 143 | module.exports = { 144 | getInternetStatus, 145 | getLastRefresh, 146 | getNumberOfUsersConnected, 147 | getSystemMemory, 148 | getSystemSpace, 149 | getSystemCpu, 150 | getSystemVersion, 151 | getDeviceID, 152 | getSyncthingID 153 | } 154 | -------------------------------------------------------------------------------- /devmgmtV2/controllers/ssid.controller.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | const path = require('path'); 4 | const exec = require('child_process').exec; 5 | 6 | 7 | const setSSID = (req, res) => { 8 | const ssid = req.body['ssid'].trim(); 9 | 10 | let responseData = { 11 | ssidSetSuccessful : true, 12 | msg : 'Successfully set the ssid id to ' + ssid 13 | } 14 | 15 | if (typeof ssid === "undefined" || ssid.length < 1) { 16 | responseData.ssidSetSuccessful = false; 17 | responseData.msg = "Empty ssid not allowed!"; 18 | 19 | return res.status(200).json(responseData); 20 | } 21 | 22 | const cmd = path.join(__dirname, '../../CDN/modeChange.sh') + ' apmode ' + ssid 23 | 24 | // executing the bash script for updating SSID 25 | exec(cmd, { shell: '/bin/bash' }, (err, stdout, stderr) => { 26 | 27 | // console.log('Error: ' + err); 28 | // console.log('stdout: ' + stdout); 29 | // console.log('stderr: ' + stderr); 30 | 31 | if(stderr || err) { 32 | responseData.ssidSetSuccessful = false; 33 | responseData.msg = stderr || err; 34 | } 35 | 36 | res.status(200).json(responseData); 37 | }); 38 | } 39 | 40 | const getSSID = (req, res) => { 41 | let responseData = { 42 | currentSSID : undefined, 43 | msg : '' 44 | } 45 | 46 | const cmd = path.join(__dirname, '../../CDN/get_ssid.sh'); 47 | 48 | // executing the bash script for updating SSID 49 | exec(cmd, { shell: '/bin/bash' }, (err, stdout, stderr) => { 50 | 51 | // console.log('Error: ' + err); 52 | // console.log('stdout: ' + stdout); 53 | // console.log('stderr: ' + stderr); 54 | 55 | if(stderr || err) { 56 | responseData.msg = stderr || err; 57 | } 58 | else { 59 | responseData.currentSSID = stdout.trim(); 60 | responseData.msg = 'SSID successfully retrieved.'; 61 | } 62 | 63 | res.status(200).json(responseData); 64 | }); 65 | } 66 | 67 | module.exports = { 68 | setSSID, 69 | getSSID 70 | } 71 | -------------------------------------------------------------------------------- /devmgmtV2/controllers/upgrade.controller.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | let q = require('q') 4 | let fs = require('fs') 5 | let { exec } = require('child_process') 6 | let updateFileLocation = '/opt/OpenCDN_upgrade.tgz' 7 | 8 | let writeUpdateFile = (req, res) => { 9 | let temporaryPath = req.files.file.path 10 | let updateFileArgument = 'file://' + updateFileLocation; 11 | fs.rename(temporaryPath, updateFileLocation, (err) => { 12 | if (err) { 13 | console.log(err); 14 | res.status(500).json({success : false}); 15 | } else { 16 | exec('/opt/opencdn/CDN/upgrade.sh ' + updateFileArgument, (error, stdout, stderr) => { 17 | if (error) { 18 | res.status(200).json({success : false}); 19 | } else { 20 | console.log(`stdout: ${stdout}`); 21 | console.log(`stderr: ${stderr}`); 22 | res.status(200).json({success : true}); 23 | setTimeout(() => { 24 | exec('/sbin/reboot'); 25 | }, 10000); 26 | 27 | } 28 | }) 29 | } 30 | }) 31 | } 32 | 33 | let checkPreviousVersion = (req,res) => { 34 | let previousVersionPath = '/opt/opencdn.old/CDN/version.txt' 35 | if(fs.existsSync(previousVersionPath)) { 36 | res.status(200).json({success : true}); 37 | } else { 38 | res.status(200).json({success : false}); 39 | } 40 | } 41 | 42 | let revertVersion = (req, res) => { 43 | exec('/opt/opencdn/CDN/revert.sh', (error, stdout, stderr) => { 44 | if (error) { 45 | console.log("Error occured while reverting version"); 46 | res.status(200).json({success : false}); 47 | } else { 48 | console.log(`stdout: ${stdout}`); 49 | console.log(`stderr: ${stderr}`); 50 | res.status(200).json({success : true}); 51 | setTimeout(() => { 52 | exec('/sbin/reboot'); 53 | }, 5000); 54 | } 55 | }); 56 | } 57 | 58 | module.exports = { 59 | writeUpdateFile, 60 | revertVersion, 61 | checkPreviousVersion 62 | } 63 | -------------------------------------------------------------------------------- /devmgmtV2/helpers/telemetry.helper.js: -------------------------------------------------------------------------------- 1 | const prc = require('process'); 2 | const fs = require('fs'); 3 | const uniqid = require('uniqid'); 4 | const path = require('path'); 5 | const q = require('q'); 6 | 7 | const { selectFields } = require('dbsdk'); 8 | const { saveTelemetry } = require('/opt/opencdn/telemetrysdk'); 9 | 10 | const _getDeviceID = () => { 11 | let defer = q.defer(); 12 | 13 | selectFields({dbName : 'device_mgmt', tableName : 'device', columns : ["dev_id"]}) 14 | .then(response => { 15 | defer.resolve(response); 16 | }).catch(e => { 17 | console.log(e); 18 | defer.reject(e); 19 | }) 20 | 21 | return defer.promise; 22 | } 23 | 24 | const _getSystemVersion = () => { 25 | let defer = q.defer(); 26 | 27 | const cdn = '/opt/opencdn/CDN/version.txt'; 28 | 29 | fs.readFile(cdn, 'utf-8', (err, data) => { 30 | if(err) { 31 | defer.reject(err); 32 | } else { 33 | defer.resolve(data); 34 | } 35 | }); 36 | 37 | return defer.promise; 38 | } 39 | 40 | let addAgnosticDataAndSave = (telemetryData, actor, timestamp) => { 41 | let defer = q.defer(); 42 | 43 | const promises = [ 44 | _getSystemVersion(), 45 | _getDeviceID() 46 | ]; 47 | 48 | q.all(promises) 49 | .then(values => { 50 | const systemVersion = values[0].replace(/\n$/, ''); 51 | const deviceID = values[1][0].dev_id; 52 | 53 | telemetryData = { 54 | ...telemetryData, 55 | 'ets' : timestamp.getTime(), 56 | 'ver' : '3.0', 57 | 'actor' : { 58 | 'id' : actor 59 | }, 60 | 'mid' : uniqid(`${deviceID}-`), 61 | 'context': { 62 | 'channel' : 'OpenRAP', 63 | 'pdata' : { 64 | 'pid' : prc.pid, 65 | 'ver' : systemVersion, 66 | 'id' : deviceID 67 | }, 68 | 'env' : 'Device Management' 69 | } 70 | }; 71 | 72 | console.log('Saving telemetry.'); // JSON.stringify(telemetryData, null, 4)) 73 | saveTelemetry(telemetryData, 'devmgmt'); 74 | 75 | defer.resolve(); 76 | }) 77 | .catch(err => { 78 | console.log(err); 79 | defer.reject(); 80 | }); 81 | 82 | return defer.promise; 83 | } 84 | 85 | module.exports = { 86 | addAgnosticDataAndSave 87 | } 88 | -------------------------------------------------------------------------------- /devmgmtV2/index.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | 4 | 5 | 6 | let cron = require('node-cron'); 7 | let express = require("express"); 8 | let bodyParser = require('body-parser'); 9 | let cors = require('cors'); 10 | let app = express(); 11 | let { exec } = require('child_process'); 12 | let { repeatedlyCheckForInternet, repeatedlyCheckUsers, repeatedlyCheckCpu, repeatedlyCheckMemory } = require('./telemetry_cron.js'); 13 | let { initiateTelemetrySync } = require('./telemetry_sync'); 14 | let { generateOriginalJWTs } = require('./helpers/cloud.helper.js'); 15 | 16 | const fs = require('fs'); 17 | const request = require('request'); 18 | const q = require('q'); 19 | 20 | const { 21 | isInternetActive, 22 | getTelemetryData, 23 | zipContents 24 | } = require('../telemetrysdk'); 25 | 26 | app.use(cors()) 27 | // parse application/x-www-form-urlencoded 28 | app.use(bodyParser.urlencoded({ extended: true })); 29 | 30 | // parse application/json 31 | app.use(bodyParser.json()); 32 | 33 | require('./routes/auth.routes.js')(app); 34 | require('./routes/users.routes.js')(app); 35 | require('./routes/upgrade.routes.js')(app); 36 | require('./routes/dashboard.routes.js')(app); 37 | require('./routes/filemgmt.routes.js')(app); 38 | require('./routes/ssid.routes.js')(app); 39 | require('./routes/captive.routes.js')(app); 40 | require('./routes/config.routes.js')(app); 41 | require('./routes/cloud.routes.js')(app); 42 | 43 | app.listen(8080, err => { 44 | if (err) 45 | console.log(err); 46 | else { 47 | initiateTelemetrySync(); 48 | 49 | cron.schedule("*/15 * * * * *", () => { 50 | repeatedlyCheckForInternet(); 51 | repeatedlyCheckUsers(); 52 | repeatedlyCheckCpu(); 53 | repeatedlyCheckMemory(); 54 | }); 55 | 56 | console.log("server running on port 8080"); 57 | exec('mysql -u root -proot < /opt/opencdn/devmgmtV2/init.sql', (err, stdout, stderr) => { 58 | if (err) { 59 | console.log(err); 60 | console.log("error in init script"); 61 | } else { 62 | console.log("init script success"); 63 | } 64 | }); 65 | exec('NODE_PATH=$NODE_PATH:"/opt/opencdn/" node /opt/opencdn/devmgmtV2/writeToDB.js', (err, stdout, stderr) => { 66 | if (err) { 67 | console.log(err); 68 | console.log("DB Initialization error"); 69 | } else { 70 | console.log(stdout); 71 | } 72 | }); 73 | } 74 | }); 75 | -------------------------------------------------------------------------------- /devmgmtV2/init.sql: -------------------------------------------------------------------------------- 1 | create database if not exists device_mgmt; 2 | create database if not exists test; 3 | 4 | use device_mgmt; 5 | CREATE TABLE if not exists users (id int(10) PRIMARY KEY AUTO_INCREMENT, username VARCHAR(100), password VARCHAR(100), permission VARCHAR(500), UNIQUE(username)); 6 | CREATE TABLE if not exists device (dev_id VARCHAR(100), UNIQUE(dev_id)); -------------------------------------------------------------------------------- /devmgmtV2/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "devmgmtv2", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "body-parser": "^1.18.2", 13 | "connect-multiparty": "^2.1.0", 14 | "cors": "^2.8.4", 15 | "diskspace": "^2.0.0", 16 | "express": "^4.16.2", 17 | "image-size": "^0.6.2", 18 | "jsonwebtoken": "^8.3.0", 19 | "moment": "^2.22.2", 20 | "node-cron": "^1.2.1", 21 | "os-utils": "0.0.14", 22 | "q": "^1.5.1", 23 | "random-mac": "0.0.4", 24 | "request": "^2.87.0", 25 | "uniqid": "^5.0.3", 26 | "unzip": "^0.1.11", 27 | "uuid": "^3.3.2" 28 | }, 29 | "devDependencies": { 30 | "eslint": "^5.6.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /devmgmtV2/routes/auth.routes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | let {authLogin, updatePassword} = require("../controllers/auth.controller.js"); 4 | 5 | const { saveTelemetryData } = require('../middlewares/telemetry.middleware.js'); 6 | 7 | module.exports = app => { 8 | app.post("/auth/login", authLogin); 9 | app.put("/auth/password", updatePassword); 10 | } 11 | -------------------------------------------------------------------------------- /devmgmtV2/routes/captive.routes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | let { uploadImage, uploadApk, writeToHtmlFile, getCurrentCaptivePortal } = require("../controllers/captive.controller.js"); 4 | let multiparty = require('connect-multiparty') 5 | let multipartMiddle = multiparty() 6 | 7 | const { saveTelemetryData } = require('../middlewares/telemetry.middleware.js'); 8 | 9 | module.exports = app => { 10 | app.post("/captive/uploadImage", multipartMiddle, uploadImage); 11 | app.post("/captive/uploadApk", multipartMiddle, uploadApk); 12 | app.post("/captive/writeHtml", writeToHtmlFile); 13 | app.get("/captive/getCurrent", getCurrentCaptivePortal); 14 | } 15 | -------------------------------------------------------------------------------- /devmgmtV2/routes/cloud.routes.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let { 4 | searchContent, 5 | getDependencies 6 | } = require('../controllers/cloud.controller.js'); 7 | 8 | module.exports = app => { 9 | app.get('/cloud/search', searchContent); 10 | app.get('/cloud/dependencies/:parent', getDependencies); 11 | }; -------------------------------------------------------------------------------- /devmgmtV2/routes/config.routes.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const { getConfig } = require('../controllers/config.controller.js'); 4 | 5 | const { saveTelemetryData } = require('../middlewares/telemetry.middleware.js'); 6 | 7 | module.exports = app => { 8 | app.get('/config', getConfig); 9 | } 10 | -------------------------------------------------------------------------------- /devmgmtV2/routes/dashboard.routes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | let { 4 | getInternetStatus, 5 | getLastRefresh, 6 | getNumberOfUsersConnected, 7 | getSystemMemory, 8 | getSystemSpace, 9 | getSystemCpu, 10 | getSystemVersion, 11 | getDeviceID, 12 | getSyncthingID 13 | } = require("../controllers/dashboard.controller") 14 | 15 | const { saveTelemetryData } = require('../middlewares/telemetry.middleware.js'); 16 | 17 | module.exports = app => { 18 | app.get("/dashboard/system/internetStatus", getInternetStatus); 19 | app.get("/dashboard/system/lastRefresh", getLastRefresh); 20 | app.get("/dashboard/system/usersConnected", getNumberOfUsersConnected); 21 | app.get("/dashboard/system/memory", getSystemMemory); 22 | app.get("/dashboard/system/space", getSystemSpace); 23 | app.get("/dashboard/system/cpu", getSystemCpu); 24 | app.get("/dashboard/system/version", getSystemVersion); 25 | app.get("/dashboard/system/deviceID", getDeviceID); 26 | app.get("/dashboard/system/syncthingID", getSyncthingID); 27 | } 28 | -------------------------------------------------------------------------------- /devmgmtV2/routes/filemgmt.routes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | let {writeFileToDisk, deleteFileFromDisk, createNewFolder, openDirectory, copyFile, moveFile, getUSB, storeTimestamp, applyChangesToPlugins} = require("../controllers/filemgmt.controller.js") 4 | let multiparty = require('connect-multiparty') 5 | let multipartMiddle = multiparty() 6 | 7 | const { saveTelemetryData } = require('../middlewares/telemetry.middleware.js'); 8 | 9 | const setTimeout = (req, res, next) => { 10 | req.setTimeout(0); 11 | next(); 12 | } 13 | 14 | module.exports = app => { 15 | app.post('/file/new', multipartMiddle, storeTimestamp, saveTelemetryData, writeFileToDisk); 16 | app.delete('/file/delete', storeTimestamp, saveTelemetryData, deleteFileFromDisk); 17 | app.post('/file/newFolder', storeTimestamp, saveTelemetryData, createNewFolder) 18 | app.get('/file/open', openDirectory); 19 | app.put('/file/copy', storeTimestamp, setTimeout, copyFile); 20 | app.put('/file/move', storeTimestamp, moveFile); 21 | app.get('/file/getUSB', getUSB); 22 | app.put('/file/apply', applyChangesToPlugins); 23 | } 24 | -------------------------------------------------------------------------------- /devmgmtV2/routes/ssid.routes.js: -------------------------------------------------------------------------------- 1 | "use strict" 2 | 3 | let { setSSID, getSSID } = require("../controllers/ssid.controller") 4 | 5 | const { saveTelemetryData } = require('../middlewares/telemetry.middleware.js'); 6 | 7 | module.exports = app => { 8 | app.put("/ssid/set", saveTelemetryData, setSSID); 9 | app.get("/ssid", getSSID); 10 | } 11 | -------------------------------------------------------------------------------- /devmgmtV2/routes/upgrade.routes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | let {writeUpdateFile} = require("../controllers/upgrade.controller.js"); 4 | let {revertVersion} = require("../controllers/upgrade.controller.js"); 5 | let {checkPreviousVersion} = require("../controllers/upgrade.controller.js") 6 | let multipart = require('connect-multiparty') 7 | let multipartMiddle = multipart() 8 | 9 | const { saveTelemetryData } = require('../middlewares/telemetry.middleware.js'); 10 | 11 | module.exports = app => { 12 | app.post('/upgrade', multipartMiddle, writeUpdateFile); 13 | app.post('/revert', revertVersion); 14 | app.get('/check',checkPreviousVersion); 15 | } 16 | -------------------------------------------------------------------------------- /devmgmtV2/routes/users.routes.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | let {createUser, updateUser, deleteUser, getAllUsers} = require("../controllers/users.controller.js"); 4 | 5 | const { saveTelemetryData } = require('../middlewares/telemetry.middleware.js'); 6 | 7 | module.exports = app => { 8 | app.post('/user/create', saveTelemetryData, createUser); 9 | app.put('/user/update', saveTelemetryData, updateUser); 10 | app.delete('/user/delete/:username', saveTelemetryData, deleteUser); 11 | app.get('/user/list', getAllUsers); 12 | } 13 | -------------------------------------------------------------------------------- /devmgmtV2/writeToDB.js: -------------------------------------------------------------------------------- 1 | let {selectFields, insertFields} = require('dbsdk'); 2 | const uuidv4 = require('uuid/v4'); 3 | const deviceID = uuidv4(); 4 | // console.log(dbsdk); 5 | 6 | insertFields({dbName : 'device_mgmt', tableName : 'users', columns : ["username", "password", "permission"], values : ["root", "root", JSON.stringify(["ALL"])]}).then(response => { 7 | console.log("Initialized Database"); 8 | }, reject => { 9 | console.log("Using already built configuration"); 10 | }); 11 | 12 | selectFields({dbName : 'device_mgmt', tableName : 'device', columns : ["dev_id"]}).then(response => { 13 | if (response.length > 0) { 14 | console.log("Using already created Device ID"); 15 | } else { 16 | insertFields({dbName : 'device_mgmt', tableName : 'device', columns : ["dev_id"], values: [deviceID]}).then(response => { 17 | console.log("Added Device ID"); 18 | }, reject => { 19 | console.log("Couldn't add Device ID"); 20 | }); 21 | } 22 | }, reject => { 23 | console.log("Couldn't fetch the Device ID"); 24 | }); -------------------------------------------------------------------------------- /devmgmtui/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /devmgmtui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "devmgmtui", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "aria2": "^4.0.3", 7 | "axios": "^0.17.1", 8 | "draft-js": "^0.10.5", 9 | "draftjs-to-html": "^0.8.2", 10 | "immutable": "^3.8.2", 11 | "local-storage": "^1.4.2", 12 | "lodash": "^4.17.11", 13 | "react": "^16.2.0", 14 | "react-dom": "^16.2.0", 15 | "react-draft-wysiwyg": "^1.12.5", 16 | "react-redux": "^5.0.6", 17 | "react-router-dom": "^4.2.2", 18 | "react-scripts": "2.0.5", 19 | "react-svg-piechart": "^2.0.3", 20 | "redux": "^3.7.2", 21 | "redux-form": "^7.2.0", 22 | "redux-logger": "^3.0.6", 23 | "redux-thunk": "^2.2.0", 24 | "semantic-ui-css": "^2.2.12", 25 | "semantic-ui-react": "^0.77.1" 26 | }, 27 | "scripts": { 28 | "start": "react-scripts start", 29 | "build": "react-scripts build", 30 | "test": "react-scripts test --env=jsdom", 31 | "eject": "react-scripts eject" 32 | }, 33 | "devDependencies": { 34 | "eslint-plugin-react": "^7.11.1" 35 | }, 36 | "browserslist": [ 37 | ">0.2%", 38 | "not dead", 39 | "not ie <= 11", 40 | "not op_mini all" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /devmgmtui/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectOpenRAP/OpenRAP/858bcdc23d7cd1ad22388ef9779e6779384f963a/devmgmtui/public/favicon.ico -------------------------------------------------------------------------------- /devmgmtui/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 22 | React App 23 | 24 | 25 | 28 |
29 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /devmgmtui/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /devmgmtui/src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { BrowserRouter, Route } from 'react-router-dom' 3 | 4 | import { connect } from 'react-redux'; 5 | import * as actions from './actions/config'; 6 | 7 | import Login from './components/auth/Login' 8 | import CreateUser from './components/user/CreateUser' 9 | import EditUser from './components/user/EditUser' 10 | import UpdatePassword from './components/user/UpdatePassword' 11 | import UserList from './components/user/UserList' 12 | import SetSSID from './components/ssid/SetSSID' 13 | import Dashboard from './components/dashboard/Dashboard' 14 | import Upgrade from './components/upgrade/Upgrade' 15 | import FileMgmt from './components/filemgmt/FileMgmt' 16 | // import Captive from './components/captive/Captive' 17 | import CloudDownload from './components/cloud/CloudDownload' 18 | 19 | import verifyAuth from './components/VerifyAuthentication'; 20 | 21 | class App extends Component { 22 | 23 | componentDidMount() { 24 | this.props.fetchConfig((error) => { 25 | if(error) { 26 | alert('Error occurred during configuration.'); 27 | this.props.history.push('/'); 28 | } else { 29 | console.log('Configuation successful.'); 30 | } 31 | }); 32 | } 33 | 34 | render() { 35 | return ( 36 |
37 | 38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | {/* */} 49 | 50 |
51 |
52 |
53 | ); 54 | } 55 | } 56 | 57 | export default connect(null, actions)(App); 58 | -------------------------------------------------------------------------------- /devmgmtui/src/actions/auth.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { BASE_URL } from '../config/config' 3 | 4 | export const login = (user, password, cb) => (dispatch) => { 5 | let data = { 6 | "username": user, 7 | "password": password 8 | } 9 | axios.post(`${BASE_URL}/auth/login`, data) 10 | .then((response) => { 11 | // console.log(response.data) 12 | if (response.data.successful) { 13 | dispatch({ type: "ENABLE_AUTH", payload: response.data }); 14 | localStorage.setItem('authData',JSON.stringify(response.data)); 15 | cb(null); 16 | }else{ 17 | cb("error", response.data); 18 | } 19 | }) 20 | .catch(e => { 21 | cb(e,{msg:"some server error"}); 22 | }) 23 | 24 | } 25 | 26 | export const createUser = (user, password, actor, cb) => (dispatch) => { 27 | console.log("Calling Auth"); 28 | console.log(user); 29 | console.log(password); 30 | let data = { 31 | "username": user, 32 | "password": password, 33 | "timestamp": `${new Date().getTime()}`, 34 | actor 35 | } 36 | axios.post(`${BASE_URL}/user/create`, data) 37 | .then((response) => { 38 | if(response.data.createSuccessful) { 39 | cb(null, "success"); 40 | } else if(JSON.stringify(response).includes('ER_DUP_ENTRY')) { 41 | cb("error", "User already exists."); 42 | } else { 43 | cb("error","Error in creating user"); 44 | } 45 | }) 46 | .catch(e => { 47 | console.log(e); 48 | cb("error","Some server error"); 49 | }) 50 | 51 | } 52 | 53 | export const editUserPermissions = (user, oldPermissions, permissions, actor, cb) => (dispatch) => { 54 | let data = { 55 | "username" : user, 56 | "field" : "permission", 57 | "oldValue" : oldPermissions, 58 | "value" : permissions, 59 | "timestamp" : `${new Date().getTime()}`, 60 | actor 61 | } 62 | axios.put(`${BASE_URL}/user/update`, data) 63 | .then((response) => { 64 | if (response.data.updateSuccessful){ 65 | cb(null, "Success"); 66 | }else{ 67 | cb("error", "Such a user does not exist"); 68 | } 69 | }) 70 | .catch(e => { 71 | console.log(e); 72 | cb("error", "some server error"); 73 | }); 74 | } 75 | 76 | export const logout = () => (dispatch) => { 77 | localStorage.removeItem('authData'); 78 | dispatch({ type: 'DISABLE_AUTH' }); 79 | } 80 | 81 | export const changePassword = (user, password, cb) => () => { 82 | let data = { 83 | "username" : user, 84 | "field" : "password", 85 | "value" : password, 86 | "timestamp" : `${new Date().getTime()}` 87 | } 88 | axios.put(`${BASE_URL}/user/update`, data) 89 | .then((response) => { 90 | if (response.data.updateSuccessful){ 91 | cb(null, response.data.msg); 92 | } else { 93 | cb("error",response.data.msg); 94 | } 95 | }) 96 | .catch(e => { 97 | console.log(e); 98 | cb("error", "Some Server Error"); 99 | }); 100 | } -------------------------------------------------------------------------------- /devmgmtui/src/actions/captive.js: -------------------------------------------------------------------------------- 1 | import { BASE_URL } from '../config/config' 2 | import axios from 'axios'; 3 | export const uploadImageToCaptive = (file) => (dispatch) => { 4 | return new Promise( 5 | (resolve, reject) => { 6 | const xhr = new XMLHttpRequest(); 7 | xhr.open('POST', `${BASE_URL}/captive/uploadImage`); 8 | const data = new FormData(); 9 | data.append('image', file); 10 | xhr.send(data); 11 | xhr.addEventListener('load', () => { 12 | const response = JSON.parse(xhr.responseText); 13 | response.data.link = response.data.link.replace("BASE_URL", `${BASE_URL}`.slice(0, BASE_URL.indexOf(":",6))); 14 | resolve(response); 15 | }) 16 | xhr.addEventListener('error', () => { 17 | const error = JSON.parse(xhr.responseText); 18 | console.log(error); 19 | reject(error); 20 | }) 21 | } 22 | ) 23 | } 24 | 25 | export const uploadApksToCaptive = (file) => (dispatch) => { 26 | return new Promise( 27 | (resolve, reject) => { 28 | let xhr = new XMLHttpRequest(); 29 | xhr.open('POST', `${BASE_URL}/captive/uploadApk`); 30 | const data = new FormData(); 31 | data.append('apk', file); 32 | xhr.send(data); 33 | xhr.addEventListener('load', () => { 34 | const response = JSON.parse(xhr.responseText); 35 | response.link = response.link.replace("BASE_URL", `${BASE_URL}`.slice(0, BASE_URL.indexOf(":",6))); 36 | resolve(response); 37 | }) 38 | xhr.addEventListener('error', () => { 39 | const response = JSON.parse(xhr.responseText); 40 | console.log(response); 41 | reject(response); 42 | }) 43 | } 44 | ) 45 | 46 | } 47 | 48 | export const getCurrentCaptivePortal = (cb) => (dispatch) => { 49 | let defaultHtmlContent = '

Error in retrieving captive portal data!

'; 50 | /* 51 | axios.get(`${BASE_URL}`.slice(0, BASE_URL.indexOf(":",6))).then(response => { 52 | console.log("Hello "); 53 | console.log(response); 54 | let cleanedResponse = response.slice(response.IndexOf('')+6, response.indexOf('')) 55 | cb(response); 56 | }).catch(err => { 57 | console.log(err); 58 | cb(defaultHtmlContent); 59 | })*/ 60 | axios.get(`${BASE_URL}/captive/getCurrent`).then(response => { 61 | if (response.data.success) { 62 | let answer = response.data.data; 63 | let cleanedResponse = answer.slice(answer.indexOf('')+6, answer.indexOf('')) 64 | cb(cleanedResponse); 65 | } else { 66 | console.log('something else'); 67 | cb(defaultHtmlContent); 68 | } 69 | }).catch(e => { 70 | console.log(e); 71 | cb(defaultHtmlContent); 72 | }) 73 | } 74 | 75 | export const writeToHtmlFile = (htmlData, cb) => (dispatch) => { 76 | axios.post(`${BASE_URL}/captive/writeHtml`, {htmlData}).then(response => { 77 | if (response.data.success) { 78 | cb(null, 'Success'); 79 | } else { 80 | cb("error", "Cannot write to file"); 81 | } 82 | }, reject => { 83 | console.log(reject); 84 | cb("error", "Server Error!"); 85 | }); 86 | } 87 | -------------------------------------------------------------------------------- /devmgmtui/src/actions/cloud.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { BASE_URL } from '../config/config'; 3 | 4 | export const clearCurrentContent = (cb) => (dispatch) => { 5 | const defaultSearchState = { 6 | content: [], 7 | count: 0, 8 | limit: 33, 9 | offset: 0, 10 | queryString: '', 11 | searching: false 12 | }; 13 | 14 | dispatch({ 15 | type: 'CLEAR_CONTENT', 16 | payload: defaultSearchState 17 | }); 18 | 19 | cb(null); 20 | }; 21 | 22 | export const searchContent = (queryString = '', limit, offset, cb) => (dispatch) => { 23 | dispatch({ 24 | type: 'SEARCHING_CONTENT', 25 | payload: true 26 | }); 27 | 28 | axios.get(`${BASE_URL}/cloud/search?query=${queryString}&limit=${limit}&offset=${offset}`) 29 | .then(({ data }) => { 30 | if (data.success) { 31 | const newSearchState = { 32 | content: data.hits.content, 33 | count: data.hits.count, 34 | queryString, 35 | offset, 36 | searching: false 37 | } 38 | 39 | dispatch({ 40 | type: 'SEARCHED_CONTENT', 41 | payload: newSearchState 42 | }); 43 | 44 | cb(null); 45 | } else { 46 | throw new Error(data.err); 47 | } 48 | }) 49 | .catch(err => { 50 | cb(err); 51 | }); 52 | }; 53 | 54 | const sortByStatus = (downloads, statusMap) => { 55 | return downloads.sort((a, b) => statusMap[a.status] - statusMap[b.status]); 56 | }; 57 | 58 | export const updateDownloadQueue = (downloads, cb) => (dispatch) => { 59 | const statusMap = { 60 | 'ongoing': 1, 61 | 'waiting': 2, 62 | 'failed': 3, 63 | 'done': 4 64 | }; 65 | 66 | downloads = sortByStatus(downloads, statusMap); 67 | 68 | dispatch({ 69 | type: 'UPDATE_DOWNLOAD_QUEUE', 70 | payload: downloads 71 | }); 72 | 73 | cb(null); 74 | }; 75 | 76 | export const loadContent = (cb) => (dispatch) => { 77 | axios.put(`${BASE_URL}/file/apply`) 78 | .then(response => { 79 | if (response.data.success) { 80 | cb(null); 81 | } else { 82 | throw new Error(response.data.message); 83 | } 84 | }) 85 | .catch(error => { 86 | cb(error); 87 | }); 88 | }; -------------------------------------------------------------------------------- /devmgmtui/src/actions/config.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { BASE_URL } from '../config/config'; 3 | 4 | export const fetchConfig = (cb) => (dispatch) => { 5 | 6 | axios.get(`${BASE_URL}/config`) 7 | .then(response => { 8 | dispatch({type : 'CONFIG_FETCH', payload : response.data}); 9 | localStorage.setItem('configData',JSON.stringify(response.data)); 10 | cb(null); 11 | }) 12 | .catch((error) => { 13 | console.log(error); 14 | cb(error); 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /devmgmtui/src/actions/dashboard.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { BASE_URL } from '../config/config'; 3 | 4 | export const fetchSystemData = () => (dispatch) => { 5 | 6 | axios.get(`${BASE_URL}/dashboard/system/internetStatus`) 7 | .then((response) => { 8 | dispatch({type: 'INTERNET_STATUS_FETCH', payload: response.data}) 9 | }) 10 | .catch((e) => { 11 | console.log(e); 12 | }) 13 | 14 | axios.get(`${BASE_URL}/dashboard/system/lastRefresh`) 15 | .then((response) => { 16 | dispatch({type: 'LAST_REFRESH_FETCH', payload: response.data}) 17 | }) 18 | .catch((e) => { 19 | console.log(e); 20 | }) 21 | 22 | axios.get(`${BASE_URL}/dashboard/system/usersConnected`) 23 | .then((response) => { 24 | dispatch({type: 'USERS_CONNECTED_FETCH', payload: response.data}) 25 | }) 26 | .catch((e) => { 27 | console.log(e); 28 | }) 29 | 30 | axios.get(`${BASE_URL}/ssid`) 31 | .then((response) => { 32 | dispatch({type: 'SSID_FETCH', payload: response.data.currentSSID}); 33 | }) 34 | .catch((e) => { 35 | console.log(e); 36 | }) 37 | 38 | axios.get(`${BASE_URL}/dashboard/system/memory`) 39 | .then((response) => { 40 | dispatch({type: 'MEMORY_FETCH', payload: response.data}); 41 | }) 42 | .catch((e) => { 43 | console.log(e); 44 | }) 45 | 46 | axios.get(`${BASE_URL}/dashboard/system/space`) 47 | .then((response) => { 48 | dispatch({type: 'SPACE_FETCH', payload: response.data}) 49 | }) 50 | .catch((e) => { 51 | console.log(e); 52 | }) 53 | 54 | axios.get(`${BASE_URL}/dashboard/system/cpu`) 55 | .then((response) => { 56 | dispatch({type: 'CPU_FETCH', payload: response.data}) 57 | }) 58 | .catch((e) => { 59 | console.log(e); 60 | }) 61 | 62 | axios.get(`${BASE_URL}/dashboard/system/version`) 63 | .then((response) => { 64 | dispatch({type: 'VERSION_FETCH', payload: response.data}) 65 | }) 66 | .catch((e) => { 67 | console.log(e); 68 | }) 69 | 70 | axios.get(`${BASE_URL}/dashboard/system/deviceID`) 71 | .then((response) => { 72 | dispatch({type: 'DEVICEID_FETCH', payload: response.data.deviceID}) 73 | }) 74 | .catch((e) => { 75 | console.log(e); 76 | }) 77 | 78 | axios.get(`${BASE_URL}/dashboard/system/syncthingID`) 79 | .then((response) => { 80 | dispatch({type: 'SYNCTHING_ID_FETCH', payload: response.data.syncthingID}) 81 | }) 82 | .catch((e) => { 83 | console.log(e); 84 | }) 85 | } 86 | -------------------------------------------------------------------------------- /devmgmtui/src/actions/ssid.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { BASE_URL } from '../config/config'; 3 | 4 | export const setSSID = (ssid, cb) => (dispatch) => { 5 | 6 | let data = { 7 | "ssid": ssid, 8 | "timestamp": `${new Date().getTime()}` 9 | } 10 | 11 | axios.put(`${BASE_URL}/ssid/set`, data) 12 | .then((response) => { 13 | if(response.data.ssidSetSuccessful) { 14 | dispatch({type: 'SET_SSID', payload: {resData : response.data, ssid : data.ssid}}); 15 | cb(null); 16 | } 17 | else { 18 | cb("error", response.data) 19 | } 20 | }) 21 | .catch((e) => { 22 | cb(e, { msg: "Internal server error" }); 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /devmgmtui/src/actions/upgrade.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { BASE_URL } from '../config/config' 3 | 4 | let FormData = require('form-data') 5 | 6 | export const uploadFile = (prefix, fileData, cb) => (dispatch) => { 7 | let data = new FormData(); 8 | data.append('file', fileData); 9 | data.append('prefix', prefix); 10 | axios.post(`${BASE_URL}/upgrade`, data, { 11 | headers : { 12 | 'Content-type' : 'multipart/form-data' 13 | }, 14 | onUploadProgress : (progressEvent) => { 15 | if (progressEvent.lengthComputable) { 16 | let progress = (progressEvent.loaded * 100) / progressEvent.total; 17 | // console.log(`Uploading : ${progress} %`); 18 | cb(null, progress, true); 19 | } 20 | } 21 | }).then((response) => { 22 | if(response.data.success) { 23 | cb(null, "success"); 24 | } else { 25 | cb("Error", "Could not ugrade with this file!"); 26 | } 27 | }) 28 | .catch(e => { 29 | cb("Error", "Server error") 30 | }) 31 | } 32 | 33 | export const checkPreviousVersion = (cb) => () => { 34 | axios.get(`${BASE_URL}/check`).then((response) => { 35 | if(response.data.success) { 36 | cb(null, "Previous version exists"); 37 | } else { 38 | cb("Error", "Previous version does not exist"); 39 | } 40 | }) 41 | .catch(e => { 42 | console.log(e); 43 | cb("Error", "Server error") 44 | }) 45 | } 46 | 47 | export const revertVersion = (cb) => () => { 48 | axios.post(`${BASE_URL}/revert`).then((response) => { 49 | if(response.data.success) { 50 | cb(null, "Successfully reverted back"); 51 | } else { 52 | cb("Error", "Could not revert back"); 53 | } 54 | }) 55 | .catch(e => { 56 | console.log(e); 57 | cb("Error", "Server error") 58 | }) 59 | } 60 | 61 | -------------------------------------------------------------------------------- /devmgmtui/src/actions/user.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | import { BASE_URL } from '../config/config' 3 | 4 | export const getAllUser = () => (dispatch) => { 5 | axios.get(`${BASE_URL}/user/list`) 6 | .then((response) => { 7 | dispatch({type: 'USER_LIST', payload : response.data}); 8 | 9 | }) 10 | .catch(e => { 11 | console.log(e); 12 | }) 13 | 14 | } 15 | 16 | export const deleteUser = (user, actor, cb) => (dispatch) => { 17 | const params = { 18 | "timestamp": `${new Date().getTime()}`, 19 | actor 20 | } 21 | 22 | axios.delete(`${BASE_URL}/user/delete/${user}`, { params }) 23 | .then((response) => { 24 | console.log(response.data) 25 | if(response.data.deleteSuccessful){ 26 | cb(null,"Success"); 27 | }else{ 28 | cb("error", "Error in deleting user"); 29 | } 30 | }) 31 | .catch(e => { 32 | console.log(e); 33 | cb("error", "Some server error"); 34 | }) 35 | 36 | } 37 | -------------------------------------------------------------------------------- /devmgmtui/src/components/VerifyAuthentication.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | 4 | export default function(ComposedComponent) { 5 | class Authentication extends Component { 6 | componentWillMount() { 7 | if (!this.props.verify.authenticated) { 8 | this.props.history.push('/'); 9 | } else { 10 | const { pathname } = this.props.location; 11 | if (pathname === "/") { 12 | this.props.history.push("/dashboard"); 13 | } 14 | } 15 | } 16 | 17 | render () { 18 | return 19 | } 20 | } 21 | 22 | function mapStateToProps(state) { 23 | return { verify: state.auth } 24 | } 25 | 26 | return connect(mapStateToProps)(Authentication); 27 | } 28 | -------------------------------------------------------------------------------- /devmgmtui/src/components/auth/Login.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import * as actions from '../../actions/auth' 4 | import './login.css' 5 | import { Container, Grid, Segment, Input, Header, Button, Icon } from 'semantic-ui-react'; 6 | 7 | const styles = { 8 | loginForm: { 9 | height: '100%' 10 | }, 11 | segment: { 12 | maxWidth: '450px' 13 | }, 14 | container: { 15 | marginTop: '10px' 16 | }, 17 | 18 | } 19 | 20 | class Login extends Component { 21 | 22 | constructor(props) { 23 | super(props) 24 | this.state = { 25 | username: "", 26 | password: "", 27 | isLoading: false 28 | } 29 | } 30 | 31 | handleUserChange(e) { 32 | this.setState({ 33 | user: e.target.value 34 | }); 35 | } 36 | 37 | handlePasswordChange(e) { 38 | this.setState({ 39 | password: e.target.value 40 | }); 41 | } 42 | 43 | toggleLoading() { 44 | this.setState({ 45 | isLoading: !this.state.isLoading 46 | }); 47 | } 48 | 49 | handleSubmit() { 50 | this.toggleLoading(); 51 | 52 | this.props.login(this.state.user, this.state.password,(err,data)=>{ 53 | if(err) { 54 | this.toggleLoading(); 55 | alert(data.msg); 56 | } else { 57 | this.props.history.push("/dashboard"); 58 | } 59 | }); 60 | } 61 | 62 | handleKeyPress = (e) => 63 | { 64 | console.log('Key pressed.'); 65 | 66 | if(e.key === 'Enter') 67 | { 68 | this.handleSubmit(); 69 | } 70 | } 71 | 72 | componentWillMount() { 73 | document.title = "Login"; 74 | } 75 | 76 | renderLogin() { 77 | return ( 78 |
79 | 80 | 81 | 82 |
83 | Log-in to your account 84 |
85 | 92 |
93 | 101 | 102 | 103 | 109 | 110 |
111 |
112 |
113 |
114 | ) 115 | } 116 | render() { 117 | return ( 118 |
119 | {this.renderLogin()} 120 |
121 | ) 122 | } 123 | 124 | } 125 | 126 | function mapStateToProps({ auth }) { 127 | return { auth } 128 | } 129 | 130 | export default connect(mapStateToProps, actions)(Login); 131 | -------------------------------------------------------------------------------- /devmgmtui/src/components/auth/login.css: -------------------------------------------------------------------------------- 1 | body > div, 2 | body > div > div, 3 | body > div > div > div { 4 | height: 100%; 5 | } -------------------------------------------------------------------------------- /devmgmtui/src/components/captive/UploadApkButton.js: -------------------------------------------------------------------------------- 1 | import { Icon } from 'semantic-ui-react'; 2 | import React, { Component } from 'react' 3 | 4 | export default class UploadApkButton extends Component { 5 | render() { 6 | return( 7 | 8 | {document.getElementById("apkinput").click()}}> 9 | 10 | 11 | 12 | ) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /devmgmtui/src/components/captive/captive.css: -------------------------------------------------------------------------------- 1 | .rdw-storybook-root { 2 | margin: 5px; 3 | width: 90%; 4 | height: 100%; 5 | } 6 | .rdw-storybook-wrapper { 7 | } 8 | .rdw-storybook-editor { 9 | border: 1px solid #F1F1F1; 10 | padding: 5px; 11 | border-radius: 2px; 12 | height: 700px; 13 | background-color: #ffffff; 14 | } 15 | .rdw-storybook-toolbar { 16 | top: -130px; 17 | } 18 | .rdw-storybook-textarea { 19 | margin-top: 20px; 20 | resize: none; 21 | width: 100%; 22 | border: 1px solid #F1F1F1; 23 | height: 100px; 24 | } 25 | -------------------------------------------------------------------------------- /devmgmtui/src/components/cloud/DownloadManager.js: -------------------------------------------------------------------------------- 1 | import { CLOUD_DOWNLOAD_CONFIG } from '../../config/config'; 2 | 3 | import Aria2 from 'aria2'; 4 | const aria2 = new Aria2(CLOUD_DOWNLOAD_CONFIG); 5 | 6 | export default class DownloadManager { 7 | 8 | constructor(dir) { 9 | this.connected = false; 10 | this.dir = dir; 11 | this.aria2 = aria2; 12 | 13 | this.aria2.on('close', () => { 14 | console.log('Disconnected from the download manager.'); 15 | this.connected = false; 16 | this.connect(); 17 | }); 18 | 19 | this.aria2.on('open', () => { 20 | console.log('Connected to the download manager.'); 21 | this.connected = true; 22 | }); 23 | } 24 | 25 | async connect() { 26 | if (this.connected) { 27 | console.log('Already connected.'); 28 | } else { 29 | try { 30 | await this.aria2.open(); 31 | } catch(err) { 32 | console.log('Error occured while connecting to the download manager.'); 33 | console.log({ err }); 34 | } 35 | } 36 | } 37 | 38 | async downloadData(uri, ecarName, retries = 1) { 39 | if (this.connected) { 40 | try { 41 | // Add option to overwriting existing files 42 | const options = { 43 | out: ecarName, 44 | dir: this.dir 45 | }; 46 | 47 | const guid = await this.aria2.call('addUri', [uri], options); 48 | return guid; 49 | } catch(err) { 50 | console.log('Error occurred while queuing download.', err); 51 | return -1; 52 | } 53 | } else if (retries == 0) { 54 | console.log('Couldn\'t connect to the download manager.'); 55 | return -1; 56 | } else { 57 | await this.connect(); 58 | return this.downloadData(uri, ecarName, --retries); 59 | } 60 | } 61 | 62 | onDownloadComplete(cb) { 63 | this.aria2.on('onDownloadComplete', ([params]) => { 64 | cb(params.gid); 65 | }); 66 | } 67 | 68 | onDownloadStart(cb) { 69 | this.aria2.on('onDownloadStart', ([params]) => { 70 | cb(params.gid); 71 | }); 72 | } 73 | 74 | onDownloadError(cb) { 75 | this.aria2.on('onDownloadError', ([params]) => { 76 | cb(params.gid); 77 | }); 78 | } 79 | 80 | async getDetails(guid) { 81 | const details = await this.aria2.call('tellStatus', guid); 82 | return details; 83 | } 84 | 85 | async getActiveDownloads() { 86 | const details = await this.aria2.call('tellActive'); 87 | return details; 88 | } 89 | 90 | async getWaitingDownloads(offset, num) { 91 | const details = await this.aria2.call('tellWaiting', offset, num); 92 | return details; 93 | } 94 | 95 | async getGlobalStat() { 96 | const details = await this.aria2.call('getGlobalStat'); 97 | return details; 98 | } 99 | } -------------------------------------------------------------------------------- /devmgmtui/src/components/cloud/Downloads.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Grid, Segment, Header, Loader, Icon, List, Transition, Button } from 'semantic-ui-react'; 4 | 5 | const styles = { 6 | parent: { 7 | margin: '0px', 8 | padding: '32px 40px 32px 32px', 9 | height: 'calc(100vh - 240px)', 10 | overflowY: 'scroll' 11 | }, 12 | downloadCard: { 13 | width: '100%' 14 | }, 15 | downloadCardSubheading: { 16 | color: 'grey' 17 | }, 18 | downloadCardList: { 19 | paddingBottom: '32px' 20 | }, 21 | noDownloads: { 22 | paddingTop: '16vh', 23 | textAlign: 'center' 24 | }, 25 | loadContent: { 26 | fontSize: '16px', 27 | width: '100%' 28 | } 29 | }; 30 | 31 | function DownloadCard(props) { 32 | const { 33 | name, 34 | size, 35 | status 36 | } = props; 37 | 38 | let cardStatusIndicator = null; 39 | 40 | switch(status) { 41 | case 'ongoing': cardStatusIndicator = ; break; 42 | case 'done': cardStatusIndicator = ; break; 43 | case 'waiting': cardStatusIndicator = ; break; 44 | case 'failed': cardStatusIndicator = ; break; 45 | } 46 | 47 | return ( 48 | 49 | 50 | 51 |
52 | 53 | {name} 54 | Size: {size} 55 | 56 |
57 |
58 | 59 | 60 | {cardStatusIndicator} 61 | 62 |
63 |
64 | ); 65 | } 66 | 67 | function renderDownloadCards(downloads) { 68 | const downloadCards = downloads.map((item, index) => { 69 | if(item.isRoot) { 70 | return ( 71 | 72 | 73 | 74 | ); 75 | } 76 | }); 77 | 78 | return ( 79 | 80 | {downloadCards} 81 | 82 | ); 83 | } 84 | 85 | function renderNoDownloads() { 86 | return ( 87 |
88 | 89 |

No downloads in progress

90 |
91 | ); 92 | } 93 | 94 | function isListEmpty(list) { 95 | let flag = true; 96 | 97 | if (list && list.length > 0) { 98 | const filteredList = list.filter(item => item); // filtering empty (null/undefined) items here 99 | 100 | if (filteredList.length > 0) { 101 | flag = false; 102 | } 103 | } 104 | 105 | return flag; 106 | } 107 | 108 | function renderLoadContentButton(clickHandler) { 109 | return ( 110 | 117 | ); 118 | } 119 | 120 | function renderDownloadCardsAndLoadContentButton(downloads, loadContentClickHandler) { 121 | return ( 122 |
123 | {renderLoadContentButton(loadContentClickHandler)} 124 | {renderDownloadCards(downloads)} 125 |
126 | ); 127 | } 128 | 129 | function Downloads(props) { 130 | const { 131 | downloads, 132 | handleLoadContentClick 133 | } = props; 134 | 135 | return ( 136 | 137 | { 138 | isListEmpty(downloads) 139 | ? renderNoDownloads() 140 | : renderDownloadCardsAndLoadContentButton(downloads, handleLoadContentClick) 141 | } 142 | 143 | ); 144 | } 145 | 146 | export default Downloads; -------------------------------------------------------------------------------- /devmgmtui/src/components/cloud/Results.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Grid, Button } from 'semantic-ui-react'; 4 | 5 | import ContentArea from './ContentArea'; 6 | 7 | const styles = { 8 | parent: { 9 | backgroundColor: 'white', 10 | margin: '0px', 11 | padding: '32px 32px 32px 48px', 12 | height: 'calc(100vh - 240px)' 13 | }, 14 | loadButton: { 15 | maxHeight: '40px', 16 | width: 'calc((100vh*2)/10)', 17 | alignSelf: 'center', 18 | minHeight: '40px' 19 | } 20 | }; 21 | 22 | function ResultSection(props) { 23 | const { 24 | content, 25 | count, 26 | loading, 27 | query, 28 | moreContent, 29 | 30 | handleDownload, 31 | handleLoadMoreClick 32 | } = props; 33 | 34 | const disabled = !moreContent; 35 | const buttonContent = disabled ? 'Reached Bottom' : 'Load More'; 36 | 37 | return ( 38 | 39 | 46 | 47 | 58 | 59 | 60 | ); 61 | } 62 | 63 | export default ResultSection; -------------------------------------------------------------------------------- /devmgmtui/src/components/cloud/SearchBar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Grid, Icon, Header, Input } from 'semantic-ui-react'; 4 | 5 | function SearchBar(props) { 6 | const searchHeading = 'Search for Collections, Workbooks, Stories and more'; 7 | 8 | const styles = { 9 | parent: { 10 | height: '16em', 11 | backgroundColor: 'white' 12 | }, 13 | 14 | leftCol: { 15 | backgroundColor: 'white' 16 | }, 17 | 18 | header: { 19 | padding: '48px 0px 0px 64px', 20 | margin: '0px', 21 | fontWeight: 'normal' 22 | }, 23 | 24 | input: { 25 | border: 'none', 26 | borderRadius: '0px', 27 | fontSize: '72px', 28 | fontWeight: 'bold', 29 | padding: '0px 0px 0px 56px' 30 | }, 31 | 32 | rightCol: { 33 | backgroundColor: 'white' 34 | } 35 | }; 36 | 37 | return ( 38 | 39 | 40 |
41 | {searchHeading} 42 |
43 | 44 | } 46 | value={props.input} 47 | onChange={props.handleInputChange} 48 | onKeyUp={props.handleKeyUp} 49 | fluid 50 | placeholder='Start typing...' 51 | /> 52 |
53 | 54 | 60 | 66 | 67 |
68 | ); 69 | } 70 | 71 | export default SearchBar; -------------------------------------------------------------------------------- /devmgmtui/src/components/cloud/cloud.css: -------------------------------------------------------------------------------- 1 | .ui.table tr td { 2 | border-top: 0px !important; 3 | } -------------------------------------------------------------------------------- /devmgmtui/src/components/common/Sidebar.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { Link, withRouter } from 'react-router-dom' 3 | import { connect } from 'react-redux' 4 | import * as actions from '../../actions/auth' 5 | import { Sidebar, Menu, Icon } from 'semantic-ui-react' 6 | class SideNav extends Component { 7 | constructor(props){ 8 | super(props); 9 | 10 | this.state= { 11 | sideBarVisible:false, 12 | currentLocation : props.location.pathname 13 | } 14 | } 15 | 16 | toggleSideBarVisibility(){ 17 | this.setState({ 18 | sideBarVisible : !this.state.sideBarVisible 19 | }) 20 | } 21 | 22 | handleLogout() { 23 | this.props.logout(); 24 | } 25 | 26 | render() { 27 | if (typeof this.props.auth.user !== `undefined`) { 28 | return ( 29 |
30 | 31 | 32 | {this.props.auth.user.permissions.search(/VIEW_DASHBOARD|ALL/) >= 0 ? 33 | 34 | Home 35 | : null } 36 | {this.props.auth.user.permissions.search(/VIEW_USERS|ALL/) >= 0 ? 37 | 38 | Users 39 | : null } 40 | {this.props.auth.user.permissions.search(/UPGRADE_DEVICE|ALL/) >= 0 ? 41 | 42 | Upgrade 43 | : null} 44 | { this.props.auth.user.permissions.search(/VIEW_FILES|ALL/) >= 0 ? 45 | 46 | File Management 47 | : null } 48 | { this.props.auth.user.permissions.search(/MODIFY_SSID|ALL/) >= 0 ? 49 | 50 | Modify SSID 51 | : null } 52 | {/* { this.props.auth.user.permissions.search(/CHANGE_CAPTIVE_PORTAL|ALL/) >= 0 ? 53 | 54 | Modify Captive Portal 55 | : null } */} 56 | 57 | { this.props.auth.user.permissions.search(/ALL/) >= 0 ? 58 | 59 | Cloud Download 60 | : null } 61 | 62 | 63 | 64 | Logout 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | {this.props.children} 74 | 75 | 76 |
77 | ); 78 | } else { 79 | return null; 80 | } 81 | } 82 | } 83 | 84 | function mapStateToProps({ auth }) { 85 | return { auth } 86 | } 87 | 88 | export default withRouter(connect(mapStateToProps, actions)(SideNav)); 89 | -------------------------------------------------------------------------------- /devmgmtui/src/components/dashboard/Dashboard.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | 3 | import { connect } from 'react-redux'; 4 | import * as actions from '../../actions/dashboard'; 5 | 6 | import { Segment, Grid } from 'semantic-ui-react'; 7 | 8 | import SideNav from '../common/Sidebar'; 9 | import ChartSegment from './ChartSegment'; 10 | import SysInfo from './SysInfo'; 11 | 12 | let timer; 13 | 14 | class Dashboard extends Component { 15 | 16 | componentWillMount() { 17 | document.title = "Dashboard"; 18 | 19 | this.props.fetchSystemData(); 20 | 21 | timer = setInterval(() => { this.props.fetchSystemData() }, 10 * 1000); 22 | } 23 | 24 | componentWillUnmount() { 25 | clearInterval(timer); 26 | } 27 | 28 | renderCharts() { 29 | const systemInfo = () => { return } 30 | const memoryUsage = () => { return } 31 | const spaceUsage = () => { return } 32 | const cpuUsage = () => { return } 33 | 34 | if(systemInfo && memoryUsage && spaceUsage && cpuUsage) { 35 | return ( 36 | 37 | 38 | 39 | {systemInfo()} 40 | 41 | 42 | 43 | 44 | 45 | {cpuUsage()} 46 | 47 | 48 | 49 | {memoryUsage()} 50 | 51 | 52 | 53 | {spaceUsage()} 54 | 55 | 56 | 57 | 58 | ); 59 | } 60 | else { 61 | return ( Loading... ); 62 | } 63 | } 64 | 65 | render() { 66 | if(typeof this.props.auth.user !== 'undefined') { 67 | return ( 68 | 69 | 70 | { this.renderCharts() } 71 | 72 | 73 | ); 74 | } else { 75 | return (null); 76 | } 77 | } 78 | } 79 | 80 | function mapStateToProps({ dashboard, auth }) { 81 | return { dashboard, auth } 82 | } 83 | 84 | export default connect(mapStateToProps, actions)(Dashboard); 85 | -------------------------------------------------------------------------------- /devmgmtui/src/components/dashboard/dashboard.css: -------------------------------------------------------------------------------- 1 | .progress-bar-content .progress{ 2 | right: .2em !important; 3 | } 4 | .progress-bar-content .label{ 5 | top: 5% !important; 6 | vertical-align: middle !important; 7 | } -------------------------------------------------------------------------------- /devmgmtui/src/components/filemgmt/FileMgmt.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import SideNav from '../common/Sidebar' 4 | import * as actions from '../../actions/filemgmt' 5 | import { Segment, Grid, Header } from 'semantic-ui-react' 6 | import FileUploadComponent from './FileUploadComponent' 7 | import FileDisplayComponent from './FileDisplayComponent' 8 | 9 | const fileMgmtStyles = { 10 | gridGap : { 11 | marginTop : '3%', 12 | paddingLeft : '2%', 13 | paddingRight : '2%' 14 | }, 15 | fileUpload : { 16 | 'position' : '-webkit-sticky', 17 | 'position' : 'sticky', 18 | 'top' : 10 19 | } 20 | } 21 | 22 | class FileMgmt extends Component { 23 | 24 | constructor(props) { 25 | super(props); 26 | this.state = {}; 27 | } 28 | 29 | componentWillMount() { 30 | document.title = "File Management"; 31 | } 32 | 33 | renderFileMgmt() { 34 | return ( 35 | 36 | 37 | 38 | 39 |
File Management
40 |
41 | 42 | { this.props.auth.user.permissions.search(/UPLOAD_FILES|ALL/) >= 0 ? 43 |
File Upload
44 | : 45 | null 46 | } 47 |
48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | { this.props.auth.user.permissions.search(/UPLOAD_FILES|ALL/) >= 0 ?
57 | 58 | 59 | 60 |
: null} 61 |
62 |
63 |
64 |
65 | ) 66 | } 67 | 68 | render() { 69 | if (typeof this.props.auth.user !== `undefined` && (this.props.auth.user.permissions.search(/VIEW_FILES|ALL/) >= 0)) { 70 | return ( 71 |
72 | {this.renderFileMgmt()} 73 |
74 | ) 75 | } else { 76 | return ( 77 | null 78 | ) 79 | } 80 | } 81 | } 82 | 83 | function mapStateToProps({ filemgmt, auth }) { 84 | return { filemgmt, auth } 85 | } 86 | 87 | export default connect(mapStateToProps, actions)(FileMgmt); 88 | -------------------------------------------------------------------------------- /devmgmtui/src/components/filemgmt/FileUnitComponent.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import * as actions from '../../actions/filemgmt' 4 | import { Icon, Divider, Checkbox } from 'semantic-ui-react' 5 | 6 | 7 | let formatBytes = (bytes,decimals) => { 8 | if(bytes === 0) return '0 Bytes'; 9 | var k = 1024, 10 | dm = decimals || 2, 11 | sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], 12 | i = Math.floor(Math.log(bytes) / Math.log(k)); 13 | return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; 14 | } 15 | 16 | let fileDisplayStyles = { 17 | rightPadded : { 18 | 'paddingRight' : '5px', 19 | } 20 | } 21 | 22 | class FileUnitComponent extends Component { 23 | 24 | constructor(props) { 25 | super(props); 26 | this.state = { 27 | selected : (this.props.filemgmt.selectedFiles.indexOf(props.name) >= 0 || this.props.filemgmt.selectedFiles.indexOf(props.id + props.ext) >= 0) 28 | } 29 | this.toggleSelected = this.toggleSelected.bind(this); 30 | } 31 | /* 32 | componentWillMount() { 33 | let currentlySelectedFiles = this.props.filemgmt.selectedFiles; 34 | if (currentlySelectedFiles.indexOf(this.props.name) >= 0) { 35 | this.setState({selected: true}); 36 | } 37 | }*/ 38 | 39 | componentWillReceiveProps(newProps, newState) { 40 | this.setState({selected : (newProps.filemgmt.selectedFiles.indexOf(this.props.name) >= 0 || newProps.filemgmt.selectedFiles.indexOf(this.props.id + this.props.ext) >= 0)}) 41 | } 42 | toggleSelected() { 43 | let currentlySelectedFiles = this.props.filemgmt.selectedFiles; 44 | if (this.state.selected) { 45 | currentlySelectedFiles.splice(currentlySelectedFiles.indexOf(this.props.name), 1); 46 | } else { 47 | if(this.props.filemgmt.currentDir === this.props.config.config.ecar_dir) { 48 | currentlySelectedFiles.push(this.props.id + this.props.ext); 49 | } 50 | else { 51 | currentlySelectedFiles.push(this.props.name); 52 | } 53 | } 54 | this.setState({selected : !this.state.selected}); 55 | this.props.updateSelectedFiles(currentlySelectedFiles); 56 | } 57 | 58 | shortenString(string) { 59 | if (string.length > 45) { 60 | return (string.slice(0, 20) + '...' + string.slice(-22)) 61 | } 62 | return string; 63 | } 64 | 65 | handleDelete() { 66 | let consent = window.confirm("Cannot be reverted once it is deleted. Are you sure you want to delete this file?"); 67 | if (consent) { 68 | const fileToDelete = this.props.ext === '.ecar' ? (this.props.id + this.props.ext) : this.props.name; 69 | 70 | this.props.deleteFile(this.props.filemgmt.currentDir, fileToDelete, this.props.auth.user.username, (err, res) => { 71 | if (err) { 72 | alert(res); 73 | } else { 74 | this.props.readFolder(this.props.filemgmt.currentDir, () => { 75 | alert("File deletion success"); 76 | }); 77 | } 78 | }); 79 | } else { 80 | return; 81 | } 82 | } 83 | 84 | renderFileUnitComponent() { 85 | return ( 86 |
87 | 88 | { this.props.auth.user.permissions.search(/DELETE_FILES|ALL/) >= 0 ? this.toggleSelected(this)} checked={this.state.selected}/> : null} 89 | 90 | {this.shortenString(this.props.name)} 91 | 92 | 93 | {'\t[' + formatBytes(this.props.size) + ']'} 94 | 95 | { this.props.auth.user.permissions.search(/DELETE_FILES|ALL/) >= 0 ? 96 | 97 | 98 | 99 | 100 | 101 | : null} 102 | 103 |
104 | ) 105 | } 106 | render() { 107 | return( 108 |
109 | {this.renderFileUnitComponent()} 110 |
111 | ) 112 | } 113 | } 114 | function mapStateToProps({ filemgmt, auth, config }) { 115 | return { filemgmt, auth, config } 116 | } 117 | 118 | export default connect(mapStateToProps, actions)(FileUnitComponent); 119 | -------------------------------------------------------------------------------- /devmgmtui/src/components/filemgmt/FolderUnitComponent.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import * as actions from '../../actions/filemgmt' 4 | import { Icon, Divider, Checkbox } from 'semantic-ui-react' 5 | 6 | 7 | let fileDisplayStyles = { 8 | rightPadded : { 9 | 'paddingRight' : '5px', 10 | } 11 | } 12 | 13 | class FolderUnitComponent extends Component { 14 | 15 | constructor(props) { 16 | super(props); 17 | this.state = { 18 | selected : false 19 | } 20 | } 21 | /* 22 | componentWillMount() { 23 | let currentlySelectedFiles = this.props.filemgmt.selectedFiles; 24 | if (currentlySelectedFiles.indexOf(this.props.name) >= 0) { 25 | this.setState({selected: true}); 26 | } 27 | } 28 | */ 29 | componentWillReceiveProps(newProps, newState) { 30 | this.setState({selected : (newProps.filemgmt.selectedFiles.indexOf(this.props.name) >= 0)}) 31 | } 32 | 33 | toggleSelected() { 34 | let currentlySelectedFiles = this.props.filemgmt.selectedFiles; 35 | if (this.state.selected) { 36 | currentlySelectedFiles.splice(currentlySelectedFiles.indexOf(this.props.name), 1); 37 | } else { 38 | currentlySelectedFiles.push(this.props.name); 39 | } 40 | this.setState({selected : !this.state.selected}); 41 | this.props.updateSelectedFiles(currentlySelectedFiles); 42 | } 43 | 44 | shortenString(string) { 45 | if (string.length > 45) { 46 | return (string.slice(0, 20) + '...' + string.slice(-22)) 47 | } 48 | return string; 49 | } 50 | 51 | handleFolderClick() { 52 | this.props.readFolder(this.props.filemgmt.currentDir + this.props.name + '/') 53 | } 54 | 55 | handleDelete() { 56 | let consent = window.confirm("Cannot be reverted once it is deleted. Are you sure you want to delete this folder?"); 57 | if (consent) { 58 | this.props.deleteFolder(this.props.filemgmt.currentDir, this.props.name, this.props.auth.user.username, (err, res) => { 59 | if (err) { 60 | alert(res); 61 | } else { 62 | this.props.readFolder(this.props.filemgmt.currentDir, () =>{ 63 | alert("Folder deletion success"); 64 | }); 65 | } 66 | }); 67 | } else { 68 | return; 69 | } 70 | } 71 | 72 | renderFolderUnitComponent() { 73 | return ( 74 |
75 | { this.props.auth.user.permissions.search(/DELETE_FILES|ALL/) >= 0 ? this.toggleSelected(this)} checked={this.state.selected}/> : null} 76 | 77 | 78 | 79 | {this.shortenString(this.props.name)} 80 | 81 | 82 | { this.props.auth.user.permissions.search(/DELETE_FILES|ALL/) >= 0 ? 83 | 84 | 85 | 86 | : null} 87 | 88 |
89 | ) 90 | } 91 | render() { 92 | return( 93 |
94 | {this.renderFolderUnitComponent()} 95 |
96 | ) 97 | } 98 | } 99 | function mapStateToProps({ filemgmt, auth }) { 100 | return { filemgmt, auth } 101 | } 102 | 103 | export default connect(mapStateToProps, actions)(FolderUnitComponent); 104 | -------------------------------------------------------------------------------- /devmgmtui/src/components/filemgmt/SelectedFileShowComponent.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import * as actions from '../../actions/filemgmt' 4 | import { Segment, Button, Icon, Divider, Dimmer, Loader, Progress } from 'semantic-ui-react' 5 | 6 | let selectedStyles = { 7 | 'upload_wrapper' : { 8 | 'color' : 'teal', 9 | fontWeight : 'bold', 10 | verticalAlign : 'text-center', 11 | paddingBottom : '4%' 12 | } 13 | } 14 | 15 | class SelectedFileShowComponent extends Component { 16 | constructor(props) { 17 | super(props); 18 | this.state = { 19 | uploadProgress : 0, 20 | uploadStatus : 'INACTIVE', 21 | cancelUpload : undefined 22 | } 23 | this.initiateUpload = this.initiateUpload.bind(this); 24 | this.handleDeleteClick = this.handleDeleteClick.bind(this); 25 | } 26 | 27 | initiateUpload() { 28 | let that = this; 29 | 30 | if (this.props.filemgmt.files.find(file => file.name === this.props.file.name)) { 31 | alert(`${this.props.file.name} will be overwritten.`); 32 | } 33 | 34 | this.props.uploadFile(this.props.filemgmt.currentDir, this.props.file, this.props.auth.user.username, function(err, res, uploading, cancelUpload) { 35 | if (err) { 36 | alert(res); 37 | that.setState({ 38 | uploadProgress : 0, 39 | uploadStatus : 'ERROR' 40 | }); 41 | } else if(uploading) { 42 | that.setState({ 43 | cancelUpload, 44 | uploadProgress : res, 45 | uploadStatus : 'UPLOADING' 46 | }); 47 | } else { 48 | that.setState({ 49 | uploadProgress : res, 50 | uploadStatus : 'UPLOADED' 51 | }, () => { 52 | that.props.readFolder(that.props.filemgmt.currentDir); 53 | that.handleDeleteClick(); 54 | }); 55 | } 56 | }); 57 | } 58 | 59 | handleUploadClick() { 60 | this.initiateUpload(); 61 | } 62 | 63 | handleDeleteClick() { 64 | if(this.state.uploadStatus !== 'INACTIVE') { 65 | this.state.cancelUpload(); 66 | } 67 | 68 | let uploadableFiles = this.props.filemgmt.uploadableFiles; 69 | let fileIndex = uploadableFiles.indexOf(this.props.file); 70 | 71 | if(fileIndex !== -1) { 72 | delete uploadableFiles[fileIndex]; 73 | this.props.updateUploadableFiles(uploadableFiles); 74 | } 75 | } 76 | 77 | componentDidUpdate() { 78 | if(this.props.autoUpload === true && this.state.uploadStatus === 'INACTIVE') { 79 | this.initiateUpload(); 80 | } 81 | } 82 | 83 | shortenString(string) { 84 | if (string.length > 70) { 85 | return (string.slice(0, 50) + '...' + string.slice(-10)) 86 | } 87 | return string; 88 | } 89 | 90 | renderSelectedFileShowComponent() { 91 | let isUploading = this.state.uploadStatus === 'UPLOADING' 92 | let hasUploaded = this.state.uploadStatus === 'UPLOADED' 93 | 94 | return ( 95 | 96 | { 97 | isUploading 98 | ? 99 | : null 100 | } 101 | 102 | {this.shortenString(this.props.file.name)} 103 | 104 | 105 | 75 | 76 | 77 | 78 | 79 | ) 80 | } 81 | 82 | render() { 83 | if (typeof this.props.auth.user !== `undefined` && (this.props.auth.user.permissions.search(/MODIFY_SSID|ALL/) >= 0)) { 84 | return ( 85 | 86 | {this.renderSSIDForm()} 87 | 88 | ) 89 | } else { 90 | return null; 91 | } 92 | } 93 | } 94 | 95 | function mapStateToProps({ ssid, auth }) { 96 | return { ssid, auth } 97 | } 98 | 99 | export default connect(mapStateToProps, actions)(SetSSID); 100 | -------------------------------------------------------------------------------- /devmgmtui/src/components/upgrade/Upgrade.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { connect } from 'react-redux' 3 | import * as actions from '../../actions/upgrade' 4 | import UpgradeDisplayComponent from './UpgradeDisplayComponent.js' 5 | import SideNav from '../common/Sidebar' 6 | 7 | class Upgrade extends Component { 8 | 9 | componentWillMount() { 10 | document.title = "Upgrade Device"; 11 | } 12 | 13 | renderUpgrade() { 14 | return ( 15 |
16 |
17 |

Upgrade Firmware

18 |
19 |
20 | 21 |
22 |
23 | ); 24 | } 25 | 26 | render() { 27 | if (typeof this.props.auth.user !== `undefined` && (this.props.auth.user.permissions.search(/UPGRADE_DEVICE|ALL/) >= 0)) { 28 | return ( 29 | 30 |
31 |
32 | {this.renderUpgrade()} 33 |
34 |
35 |
36 | ) 37 | } else { 38 | return ( 39 | null 40 | ) 41 | } 42 | } 43 | } 44 | 45 | function mapStateToProps({ upgrade, auth }) { 46 | return { upgrade, auth } 47 | } 48 | 49 | export default connect(mapStateToProps, actions)(Upgrade); 50 | -------------------------------------------------------------------------------- /devmgmtui/src/components/user/UpdatePassword.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import * as actions from '../../actions/auth'; 4 | 5 | import { Container, Grid, Segment, Input, Header, Button, Icon } from 'semantic-ui-react'; 6 | 7 | const styles = { 8 | passwordUpdateForm: { 9 | height: '100%' 10 | }, 11 | segment: { 12 | maxWidth: '450px' 13 | }, 14 | container: { 15 | marginTop: '10px' 16 | } 17 | } 18 | 19 | class UpdatePassword extends Component { 20 | 21 | constructor(props) { 22 | super(props); 23 | 24 | this.state = { 25 | password: "", 26 | user: props.match.params.username 27 | } 28 | } 29 | 30 | componentWillMount() { 31 | document.title = "Update Password"; 32 | } 33 | 34 | handlePasswordChange(e) { 35 | this.setState({ 36 | password: e.target.value 37 | }) 38 | } 39 | 40 | handleSubmit() { 41 | if(this.state.password.length>0) { 42 | this.props.changePassword(this.state.user, this.state.password, (err, res) => { 43 | if (!err) { 44 | alert(res); 45 | } else { 46 | console.log(res); 47 | } 48 | this.props.history.push("/users"); 49 | }); 50 | } else { 51 | alert(" Please Enter a New Password"); 52 | } 53 | } 54 | 55 | renderPasswordUpdateForm() { 56 | return ( 57 |
58 | 59 | 60 | 61 |
62 | {' '}Set a new password 63 |
64 | 65 | 73 | 74 |
75 | 76 | 77 | 83 | 84 |
85 |
86 |
87 |
88 | ) 89 | } 90 | 91 | render() { 92 | return ( 93 |
94 | {this.renderPasswordUpdateForm()} 95 |
96 | ) 97 | } 98 | 99 | } 100 | export default connect(null, actions)(UpdatePassword); 101 | -------------------------------------------------------------------------------- /devmgmtui/src/config/config.js: -------------------------------------------------------------------------------- 1 | export const BASE_URL = "http://devmgmt.openrap.com" 2 | export const CLOUD_DOWNLOAD_CONFIG = { 3 | host: 'openrap.com', 4 | port: 80, 5 | secure: false, 6 | secret: '', 7 | path: '/jsonrpc' 8 | }; -------------------------------------------------------------------------------- /devmgmtui/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: sans-serif; 5 | } 6 | -------------------------------------------------------------------------------- /devmgmtui/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import 'semantic-ui-css/semantic.min.css'; 4 | 5 | import { Provider } from 'react-redux'; 6 | import { createStore, applyMiddleware } from 'redux' 7 | import reduxThunk from 'redux-thunk' 8 | 9 | import './index.css'; 10 | import App from './App'; 11 | import reducers from './reducers' 12 | 13 | const store = createStore(reducers,{}, applyMiddleware(reduxThunk)) 14 | 15 | const authData = JSON.parse(localStorage.getItem('authData')); 16 | const configData = JSON.parse(localStorage.getItem('configData')); 17 | const directoryData = localStorage.getItem('directoryData'); 18 | 19 | if (authData && configData) { 20 | store.dispatch({ type : 'ENABLE_AUTH', payload : authData }) 21 | store.dispatch({ type : 'CONFIG_FETCH', payload : configData }); 22 | store.dispatch({ type : 'OPEN_DIR', payload : directoryData }); 23 | } else { 24 | store.dispatch({ type: 'DISABLE_AUTH' }) 25 | } 26 | 27 | ReactDOM.render( 28 | 29 | 30 | 31 | , document.getElementById('root')); 32 | -------------------------------------------------------------------------------- /devmgmtui/src/reducers/auth.js: -------------------------------------------------------------------------------- 1 | export default function (state={authenticated:false}, action){ 2 | switch(action.type){ 3 | case 'ENABLE_AUTH': 4 | return {...state, authenticated : true, user : action.payload} 5 | case 'DISABLE_AUTH': 6 | return {...state, authenticated : false} 7 | default: 8 | return state 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /devmgmtui/src/reducers/cloud.js: -------------------------------------------------------------------------------- 1 | const defaultState = { 2 | content: [], 3 | count: 0, 4 | limit: 33, 5 | offset: 0, 6 | queryString: '', 7 | searching: false, 8 | downloads: [] 9 | }; 10 | 11 | export default function (state = defaultState, action) { 12 | const { 13 | type, 14 | payload 15 | } = action; 16 | 17 | switch(type) { 18 | case 'SEARCHED_CONTENT': 19 | return { 20 | ...state, 21 | ...payload, 22 | content: state.content.concat(payload.content), 23 | }; 24 | case 'SEARCHING_CONTENT': 25 | return { 26 | ...state, 27 | searching: payload 28 | }; 29 | case 'CLEAR_CONTENT': 30 | return { 31 | ...state, 32 | ...payload 33 | }; 34 | case 'UPDATE_DOWNLOAD_QUEUE': 35 | return { 36 | ...state, 37 | downloads: payload 38 | }; 39 | default: 40 | return state; 41 | } 42 | } -------------------------------------------------------------------------------- /devmgmtui/src/reducers/config.js: -------------------------------------------------------------------------------- 1 | export default function (state={}, action) { 2 | switch(action.type){ 3 | case 'CONFIG_FETCH': 4 | return { ...state, config : action.payload } 5 | default: 6 | return state 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /devmgmtui/src/reducers/dashboard.js: -------------------------------------------------------------------------------- 1 | export default function (state={}, action) { 2 | switch(action.type) { 3 | case 'LAST_REFRESH_FETCH': 4 | return {...state, lastRefreshTime: action.payload} 5 | case 'INTERNET_STATUS_FETCH': 6 | return {...state, internetStatus : action.payload} 7 | case 'USERS_CONNECTED_FETCH': 8 | return {...state, usersConnected: action.payload} 9 | case 'SSID_FETCH': 10 | return {...state, currentSSID: action.payload}; 11 | case 'MEMORY_FETCH': 12 | return {...state, memoryData: action.payload}; 13 | case 'SPACE_FETCH': 14 | return {...state, spaceData: action.payload}; 15 | case 'CPU_FETCH': 16 | return {...state, cpuData: action.payload}; 17 | case 'VERSION_FETCH': 18 | return {...state, version: action.payload}; 19 | case 'DEVICEID_FETCH': 20 | return {...state, deviceID: action.payload}; 21 | case 'SYNCTHING_ID_FETCH': 22 | return {...state, syncthingID: action.payload}; 23 | default: 24 | return state; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /devmgmtui/src/reducers/filemgmt.js: -------------------------------------------------------------------------------- 1 | export default function (state={files : [], uploadableFiles : [], selectedFiles : [], allSelected : false, usbDir : '', usbDownFiles : []}, action){ 2 | switch(action.type){ 3 | case 'OPEN_DIR' : 4 | return {...state, currentDir : action.payload} 5 | case 'READ_DIR' : 6 | return {...state, files : action.payload} 7 | case 'UPLOAD_FILES' : 8 | return {...state, uploadableFiles : action.payload} 9 | case 'SELECT_FILES' : 10 | return {...state, selectedFiles : action.payload} 11 | case 'USB_DIR' : 12 | return {...state, usbDir : action.payload} 13 | case 'USB_DIR_DOWN' : 14 | return {...state, usbDownFiles : action.payload} 15 | default: 16 | return state 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /devmgmtui/src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import auth from './auth'; 3 | import user from './user'; 4 | import filemgmt from './filemgmt'; 5 | import dashboard from './dashboard'; 6 | import ssid from './ssid'; 7 | import config from './config'; 8 | import cloud from './cloud'; 9 | 10 | export default combineReducers({ 11 | auth, 12 | user, 13 | filemgmt, 14 | dashboard, 15 | ssid, 16 | config, 17 | cloud 18 | }); 19 | -------------------------------------------------------------------------------- /devmgmtui/src/reducers/ssid.js: -------------------------------------------------------------------------------- 1 | export default function (state={ ssidSet: false }, action) { 2 | switch(action.type) { 3 | case 'SET_SSID': 4 | return {...state, ssidSet: action.payload.resData.ssidSetSuccessful, currentSSID: action.payload.ssid}; 5 | default: 6 | return state; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /devmgmtui/src/reducers/upgrade.js: -------------------------------------------------------------------------------- 1 | export default function (state={authenticated:false}, action){ 2 | switch(action.type){ 3 | case 'UPGRADE_SUCCESS': 4 | return {...state, data : action.payload} 5 | case 'UPGRADE_FAIL': 6 | return {...state, error : action.payload} 7 | default: 8 | return state 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /devmgmtui/src/reducers/user.js: -------------------------------------------------------------------------------- 1 | export default function (state={}, action){ 2 | switch(action.type){ 3 | case 'USER_LIST': 4 | return {...state, list : action.payload} 5 | case 'USER_PERMISSIONS': 6 | return {...state, permissions : action.payload} 7 | default: 8 | return state 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /filesdk/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const fs = require('fs'); 4 | const q = require('q'); 5 | const rimraf = require('rimraf'); 6 | const unzip = require('unzip-stream'); 7 | const targz = require('targz'); 8 | const ncp = require('ncp').ncp; 9 | ncp.limit = 16; 10 | 11 | let readFile = (path) => { 12 | let defer = q.defer(); 13 | fs.readFile(path, 'utf8', function (err, contents) { 14 | if (err) return defer.reject(err); 15 | return defer.resolve(contents); 16 | }); 17 | return defer.promise; 18 | } 19 | let writeFile = (path, contents) => { 20 | let defer = q.defer(); 21 | fs.writeFile(path, contents, (err) => { 22 | if (err) return defer.reject(err); 23 | return defer.resolve("File has been written"); 24 | }); 25 | return defer.promise; 26 | } 27 | let deleteFile = (path) => { 28 | let defer = q.defer(); 29 | fs.unlink(path, function (err) { 30 | if (err) return defer.reject(err); 31 | return defer.resolve("File has been deleted"); 32 | }); 33 | return defer.promise; 34 | } 35 | let deleteDir = (path) => { 36 | let defer = q.defer(); 37 | rimraf(path, function (err) { 38 | if (err) return defer.reject(err); 39 | return defer.resolve("Directory has been deleted"); 40 | }); 41 | return defer.promise; 42 | } 43 | let copy = (source, destination) => { 44 | let defer = q.defer(); 45 | ncp(source, destination, function (err) { 46 | if (err) return defer.reject(err); 47 | return defer.resolve("Copied!!!"); 48 | }); 49 | return defer.promise; 50 | } 51 | let move = (source, destination) => { 52 | let defer = q.defer(); 53 | fs.rename(source, destination, function (err) { 54 | if (err) return defer.reject(err); 55 | return defer.resolve("Moved!!!"); 56 | }); 57 | return defer.promise; 58 | } 59 | 60 | let readdir = (path) => { 61 | let defer = q.defer(); 62 | fs.readdir(path, function (err, items) { 63 | if (err) return defer.reject(err); 64 | return defer.resolve(items); 65 | }); 66 | return defer.promise; 67 | } 68 | 69 | let getInfo = (path) => { 70 | let defer = q.defer(); 71 | fs.stat(path, function (err, stats) { 72 | if (err) return defer.reject(err); 73 | return defer.resolve(stats); 74 | }); 75 | return defer.promise; 76 | } 77 | let extractZip = (source, destination) => { 78 | return extractWithUnzipStream(source, destination); 79 | } 80 | let extractWithUnzipStream = (src, dest) => { 81 | let defer = q.defer(); 82 | fs.createReadStream(src) 83 | .pipe(unzip.Extract({ path: dest })) 84 | .on('close', (err) => { 85 | if (err) { 86 | defer.reject(err); 87 | } 88 | else { 89 | defer.resolve('Done!!!'); 90 | } 91 | }).on('error', (err) => { 92 | defer.reject(err); 93 | }); 94 | return defer.promise; 95 | } 96 | let extractTar = (source, destination) => { 97 | let defer = q.defer(); 98 | targz.decompress({ 99 | src: source, 100 | dest: destination 101 | }, function (err) { 102 | if (err) return defer.reject(err); 103 | return defer.resolve("Done!!!"); 104 | }); 105 | return defer.promise; 106 | } 107 | let createTar = (source, destination) => { 108 | let defer = q.defer(); 109 | targz.compress({ 110 | src: source, 111 | dest: destination 112 | }, function (err) { 113 | if (err) return defer.reject(err); 114 | return defer.resolve("Done!!!"); 115 | }); 116 | return defer.promise; 117 | } 118 | module.exports = { 119 | readFile, 120 | writeFile, 121 | deleteFile, 122 | deleteDir, 123 | copy, 124 | move, 125 | //rename, 126 | readdir, 127 | getInfo, 128 | extractZip, 129 | extractTar, 130 | createTar 131 | } 132 | -------------------------------------------------------------------------------- /filesdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "filesdk", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "chai": "^4.1.2", 13 | "extract-zip": "^1.6.6", 14 | "ncp": "^2.0.0", 15 | "q": "^1.5.1", 16 | "rimraf": "^2.6.2", 17 | "targz": "^1.0.1", 18 | "unzip-stream": "^0.3.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /filesdk/test/filesdk.test.js: -------------------------------------------------------------------------------- 1 | const chai = require('chai'); 2 | const { 3 | readFile, 4 | writeFile, 5 | deleteFile, 6 | deleteDir, 7 | copy, 8 | move, 9 | rename, 10 | readdir, 11 | getInfo, 12 | extractZip, 13 | extractTar, 14 | createTar 15 | } = require('../index'); 16 | const should = chai.should(); 17 | let playground = './test/playground/'; 18 | 19 | 20 | 21 | describe('Testing Reading files', function () { 22 | it('should return a string', () => { 23 | return readFile(playground+'testRead').then(function (res) { 24 | res.should.be.a('string') 25 | }) 26 | }); 27 | it('should return an error', () => { 28 | return readFile(playground+'testReads').then(function (res) { 29 | }).catch(err => { 30 | should.exist(err); 31 | }) 32 | }); 33 | }); 34 | 35 | describe('Testing Write files', function () { 36 | it('should return a string', () => { 37 | return writeFile(playground+'testReadTemp', "Hello World").then(function (res) { 38 | res.should.be.a('string') 39 | }) 40 | }); 41 | it('New File Should Be created', () => { 42 | return readFile(playground+'testReadTemp').then(function (res) { 43 | res.should.be.a('string') 44 | }) 45 | }); 46 | it('New File Should contain Hello World', () => { 47 | return readFile(playground+'testReadTemp').then(function (res) { 48 | res.should.equal("Hello World"); 49 | }) 50 | }); 51 | 52 | }); 53 | 54 | describe('Testing Delete files', function () { 55 | it('should return a string', () => { 56 | return deleteFile(playground+'testReadTemp').then(function (res) { 57 | res.should.be.a('string') 58 | }) 59 | }); 60 | it('should return a error', () => { 61 | return deleteFile(playground+'testReadTemp').then(function (res) { 62 | }).catch(err => { 63 | should.exist(err); 64 | }) 65 | }); 66 | }); 67 | describe('Testing Copying files', function () { 68 | it('should return a string', () => { 69 | return copy(playground+'testRead',playground+'testReadTemp').then(function (res) { 70 | res.should.be.a('string') 71 | }) 72 | }); 73 | it('New File Should contain a Hello', () => { 74 | return readFile(playground+'testReadTemp').then(function (res) { 75 | res.should.a('string'); 76 | res.should.be.equal('Hello'); 77 | }) 78 | }); 79 | }); 80 | 81 | describe('Testing Moving files', function () { 82 | it('should return a string', () => { 83 | return move(playground+'testReadTemp',playground+'testReadv2').then(function (res) { 84 | res.should.be.a('string') 85 | }) 86 | }); 87 | it('New File Should contain a Hello', () => { 88 | return readFile(playground+'testReadv2').then(function (res) { 89 | res.should.a('string'); 90 | res.should.be.equal('Hello'); 91 | }) 92 | }); 93 | }); 94 | describe('Testing Renaming files', function () { 95 | it('should return a string', () => { 96 | return rename(playground+'testReadv2',playground+'testReadv3').then(function (res) { 97 | res.should.be.a('string') 98 | }) 99 | }); 100 | it('New File Should contain a Hello', () => { 101 | return readFile(playground+'testReadv3').then(function (res) { 102 | res.should.a('string'); 103 | res.should.be.equal('Hello'); 104 | }) 105 | }); 106 | it('should return a string', () => { 107 | return deleteFile(playground+'testReadv3').then(function (res) { 108 | res.should.be.a('string') 109 | }) 110 | }); 111 | }); 112 | describe('Testing Read dir files', function () { 113 | it('should return a array', () => { 114 | return readdir(playground).then(function (res) { 115 | res.should.be.a('array') 116 | res.should.have.length(1); 117 | }) 118 | }); 119 | }); 120 | describe('Testing Get Info files', function () { 121 | it('should return a object', () => { 122 | return getInfo(playground).then(function (res) { 123 | res.should.be.a('object') 124 | res.should.have.property('size'); 125 | }) 126 | }); 127 | }); -------------------------------------------------------------------------------- /filesdk/test/playground/testRead: -------------------------------------------------------------------------------- 1 | Hello -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "lockfileVersion": 1 3 | } 4 | -------------------------------------------------------------------------------- /profile/ekstep/rootfs_overlay/etc/nginx/sites-enabled/opencdn_nginx: -------------------------------------------------------------------------------- 1 | # WebSocket config for aria2 2 | upstream websocket { 3 | server localhost:6800; 4 | } 5 | 6 | map $http_upgrade $connection_upgrade { 7 | default upgrade; 8 | '' close; 9 | } 10 | 11 | # Default server configuration 12 | # 13 | server { 14 | listen 80 default_server; 15 | root /var/www/html; 16 | 17 | # Add index.php to the list if you are using PHP 18 | index index.html index.htm index.nginx-debian.html; 19 | 20 | server_name _; 21 | 22 | location / { 23 | # First attempt to serve request as file, then 24 | # as directory, then look up @ekstep. 25 | 26 | try_files $uri $uri/ @ekstep; 27 | } 28 | 29 | location @ekstep { 30 | # On encountering a 404 here, it will 31 | # resort to @diksha, and then fallback 32 | # to displaying 404. 33 | 34 | root /home/admin/ekstep/; 35 | proxy_intercept_errors on; 36 | recursive_error_pages on; 37 | error_page 404 = @diksha; 38 | } 39 | 40 | location @diksha { 41 | root /home/admin/diksha/; 42 | } 43 | 44 | # 45 | #openRAP apiserver configuration 46 | # 47 | location /api { 48 | proxy_pass http://127.0.0.1:9090; 49 | } 50 | location /content { 51 | proxy_pass http://127.0.0.1:9090; 52 | } 53 | location /composite { 54 | proxy_pass http://127.0.0.1:9090; 55 | } 56 | location /data { 57 | proxy_pass http://127.0.0.1:9090; 58 | } 59 | location /gok { 60 | proxy_pass http://127.0.0.1:9090; 61 | } 62 | location /devmgmt/api { 63 | proxy_pass http://127.0.0.1:8080; 64 | } 65 | location /jsonrpc { 66 | proxy_pass http://websocket; 67 | proxy_http_version 1.1; 68 | proxy_set_header Upgrade $http_upgrade; 69 | proxy_set_header Connection $connection_upgrade; 70 | } 71 | # Redirect requests for /generate_204 to open the captive portal screen 72 | location /generate_204 { 73 | return 302 http://download.localnet/index.html; 74 | } 75 | } 76 | 77 | # 78 | # Device management python server 79 | # 80 | server { 81 | listen 80; 82 | server_name admin.openrap.com; 83 | root /var/www/html/admin; 84 | index index.php index.html; 85 | 86 | location / { 87 | #proxy_pass http://127.0.0.1:8008; 88 | try_files $uri $uri/ /index.html; 89 | } 90 | } 91 | server { 92 | listen 80; 93 | server_name gok.openrap.com; 94 | root /var/www/gok; 95 | index index.php index.html; 96 | 97 | location / { 98 | #proxy_pass http://127.0.0.1:8008; 99 | try_files $uri $uri/ /index.html; 100 | } 101 | } 102 | server { 103 | listen 80; 104 | server_name devmgmt.openrap.com; 105 | #root /var/www/html/admin; 106 | index index.php index.html; 107 | 108 | location / { 109 | proxy_connect_timeout 999999; 110 | proxy_send_timeout 999999; 111 | proxy_read_timeout 999999; 112 | send_timeout 999999; 113 | client_max_body_size 0; 114 | proxy_pass http://127.0.0.1:8080; 115 | #try_files $uri $uri/ @ekstep; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /profile/meghshala/rootfs_overlay/etc/nginx/sites-enabled/opencdn_nginx: -------------------------------------------------------------------------------- 1 | # Default server configuration 2 | # 3 | server { 4 | listen 80 default_server; 5 | root /var/www/html; 6 | 7 | # Add index.php to the list if you are using PHP 8 | index index.html index.htm index.nginx-debian.html; 9 | 10 | server_name _; 11 | 12 | location / { 13 | # First attempt to serve request as file, then 14 | # as directory, then fall back to displaying a 404. 15 | try_files $uri $uri/ @meghshala; 16 | 17 | } 18 | 19 | location @meghshala { 20 | # First attempt to serve request as file, then 21 | # as directory, then fall back to displaying a 404. 22 | root /var/www/meghshala; 23 | } 24 | 25 | # 26 | # apiserver configuration to serve APIs 27 | # 28 | location /apis { 29 | proxy_pass http://127.0.0.1:9000; 30 | } 31 | } 32 | 33 | # 34 | # Device management python server 35 | # 36 | server { 37 | listen 80; 38 | server_name admin.openrap.com; 39 | client_max_body_size 0; 40 | index index.php index.html; 41 | 42 | location / { 43 | proxy_pass http://127.0.0.1:8008; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /rootfs_overlay/etc/avahi/services/openrap.service: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 22 | 23 | 24 | 25 | 26 | 27 | Open Resource Access Point on %h 28 | 29 | 30 | _openrap._tcp 31 | 80 32 | admin_url="ip:8008" 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /rootfs_overlay/etc/default/dnsmasq: -------------------------------------------------------------------------------- 1 | # This file has five functions: 2 | # 1) to completely disable starting dnsmasq, 3 | # 2) to set DOMAIN_SUFFIX by running `dnsdomainname` 4 | # 3) to select an alternative config file 5 | # by setting DNSMASQ_OPTS to --conf-file= 6 | # 4) to tell dnsmasq to read the files in /etc/dnsmasq.d for 7 | # more configuration variables. 8 | # 5) to stop the resolvconf package from controlling dnsmasq's 9 | # idea of which upstream nameservers to use. 10 | # For upgraders from very old versions, all the shell variables set 11 | # here in previous versions are still honored by the init script 12 | # so if you just keep your old version of this file nothing will break. 13 | 14 | #DOMAIN_SUFFIX=`dnsdomainname` 15 | #DNSMASQ_OPTS="--conf-file=/etc/dnsmasq.alt" 16 | 17 | # Whether or not to run the dnsmasq daemon; set to 0 to disable. 18 | ENABLED=1 19 | 20 | # By default search this drop directory for configuration options. 21 | # Libvirt leaves a file here to make the system dnsmasq play nice. 22 | # Comment out this line if you don't want this. The dpkg-* are file 23 | # endings which cause dnsmasq to skip that file. This avoids pulling 24 | # in backups made by dpkg. 25 | CONFIG_DIR=/etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new 26 | 27 | # If the resolvconf package is installed, dnsmasq will use its output 28 | # rather than the contents of /etc/resolv.conf to find upstream 29 | # nameservers. Uncommenting this line inhibits this behaviour. 30 | # Note that including a "resolv-file=" line in 31 | # /etc/dnsmasq.conf is not enough to override resolvconf if it is 32 | # installed: the line below must be uncommented. 33 | #IGNORE_RESOLVCONF=yes 34 | DNSMASQ_EXCEPT=lo 35 | -------------------------------------------------------------------------------- /rootfs_overlay/etc/default/hostapd: -------------------------------------------------------------------------------- 1 | DAEMON_CONF="/etc/hostapd/hostapd.conf" 2 | -------------------------------------------------------------------------------- /rootfs_overlay/etc/hostapd/hostapd.conf: -------------------------------------------------------------------------------- 1 | interface=wlan0 2 | driver=nl80211 3 | ssid=OpenRAP 4 | hw_mode=g 5 | channel=6 6 | ieee80211n=1 7 | wmm_enabled=1 8 | ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40] 9 | macaddr_acl=0 10 | ignore_broadcast_ssid=0 11 | -------------------------------------------------------------------------------- /rootfs_overlay/etc/hostname: -------------------------------------------------------------------------------- 1 | OpenRAP 2 | -------------------------------------------------------------------------------- /rootfs_overlay/etc/hosts: -------------------------------------------------------------------------------- 1 | 127.0.0.1 localhost 2 | 127.0.1.1 OpenRAP 3 | -------------------------------------------------------------------------------- /rootfs_overlay/etc/init.d/apiserver: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # kFreeBSD do not accept scripts as interpreters, using #!/bin/sh and sourcing. 3 | if [ true != "$INIT_D_SCRIPT_SOURCED" ] ; then 4 | set "$0" "$@"; INIT_D_SCRIPT_SOURCED=true . /lib/init/init-d-script 5 | fi 6 | ### BEGIN INIT INFO 7 | # Provides: restserver 8 | # Required-Start: $remote_fs $syslog 9 | # Required-Stop: $remote_fs $syslog 10 | # Default-Start: 2 3 4 5 11 | # Default-Stop: 0 1 6 12 | # Short-Description: Example initscript 13 | # Description: This file should be used to construct scripts to be 14 | # placed in /etc/init.d. This example start a 15 | # single forking daemon capable of writing a pid 16 | # file. To get other behavoirs, implemend 17 | # do_start(), do_stop() or other functions to 18 | # override the defaults in /lib/init/init-d-script. 19 | ### END INIT INFO 20 | 21 | # Author: Pronoy Debnath 22 | # 23 | # Please remove the "Author" lines above and replace them 24 | # with your own name if you copy and modify this script. 25 | 26 | DESC="REST API server for opencdn" 27 | 28 | DAEMON=/opt/opencdn/CDN/apiserver 29 | -------------------------------------------------------------------------------- /rootfs_overlay/etc/modprobe.d/blacklist-opencdn.conf: -------------------------------------------------------------------------------- 1 | #Blacklist modules that are not needed by opencdn 2 | 3 | #install ipv6 /bin/false 4 | 5 | #bluez is uninstalled already 6 | install bluetooth /bin/false 7 | install snd /bin/false 8 | 9 | #No one is referring the below modules, 10 | #so don't load them 11 | #install bcm2835_gpiomem /bin/false 12 | 13 | -------------------------------------------------------------------------------- /rootfs_overlay/etc/network/interfaces: -------------------------------------------------------------------------------- 1 | auto lo 2 | iface lo inet loopback 3 | 4 | #auto eth0 5 | allow-hotplug eth0 6 | iface eth0 inet dhcp 7 | 8 | 9 | auto wlan0 10 | allow-hotplug wlan0 11 | iface wlan0 inet static 12 | address 192.168.0.1 13 | netmask 255.255.255.0 14 | 15 | -------------------------------------------------------------------------------- /rootfs_overlay/etc/nginx/sites-enabled/opencdn_nginx: -------------------------------------------------------------------------------- 1 | # WebSocket config for aria2 2 | upstream websocket { 3 | server localhost:6800; 4 | } 5 | 6 | map $http_upgrade $connection_upgrade { 7 | default upgrade; 8 | '' close; 9 | } 10 | 11 | # Default server configuration 12 | # 13 | server { 14 | listen 80 default_server; 15 | root /var/www/html; 16 | 17 | # Add index.php to the list if you are using PHP 18 | index index.html index.htm index.nginx-debian.html; 19 | 20 | server_name _; 21 | 22 | location / { 23 | # First attempt to serve request as file, then 24 | # as directory, then look up @ekstep. 25 | 26 | try_files $uri $uri/ @ekstep; 27 | } 28 | 29 | location @ekstep { 30 | # On encountering a 404 here, it will 31 | # resort to @diksha, and then fallback 32 | # to displaying 404. 33 | 34 | root /home/admin/ekstep/; 35 | proxy_intercept_errors on; 36 | recursive_error_pages on; 37 | error_page 404 = @diksha; 38 | } 39 | 40 | location @diksha { 41 | root /home/admin/diksha/; 42 | } 43 | 44 | # 45 | #openRAP apiserver configuration 46 | # 47 | location /api { 48 | proxy_pass http://127.0.0.1:9000; 49 | } 50 | location /content { 51 | proxy_pass http://127.0.0.1:9000; 52 | } 53 | location /composite { 54 | proxy_pass http://127.0.0.1:9000; 55 | } 56 | location /data { 57 | proxy_pass http://127.0.0.1:9000; 58 | } 59 | location /devmgmt/api { 60 | proxy_pass http://127.0.0.1:8080; 61 | } 62 | location /jsonrpc { 63 | proxy_pass http://websocket; 64 | proxy_http_version 1.1; 65 | proxy_set_header Upgrade $http_upgrade; 66 | proxy_set_header Connection $connection_upgrade; 67 | } 68 | # Redirect requests for /generate_204 to open the captive portal screen 69 | location /generate_204 { 70 | return 302 http://download.localnet/index.html; 71 | } 72 | } 73 | 74 | # 75 | # Device management python server 76 | # 77 | server { 78 | listen 80; 79 | server_name admin.openrap.com; 80 | root /var/www/html/admin; 81 | index index.php index.html; 82 | 83 | location / { 84 | #proxy_pass http://127.0.0.1:8008; 85 | try_files $uri $uri/ @ekstep; 86 | } 87 | } 88 | server { 89 | listen 80; 90 | server_name devmgmt.openrap.com; 91 | #root /var/www/html/admin; 92 | index index.php index.html; 93 | 94 | location / { 95 | 96 | proxy_pass http://127.0.0.1:8080; 97 | proxy_connect_timeout 999999; 98 | proxy_send_timeout 999999; 99 | proxy_read_timeout 999999; 100 | send_timeout 999999; 101 | client_max_body_size 0; 102 | 103 | #try_files $uri $uri/ @ekstep; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /rootfs_overlay/etc/rc.local: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | service udev restart & 3 | exit 0 4 | -------------------------------------------------------------------------------- /rootfs_overlay/etc/systemd/system/systemd-udevd.service: -------------------------------------------------------------------------------- 1 | # This file is part of systemd. 2 | # 3 | # systemd is free software; you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as published by 5 | # the Free Software Foundation; either version 2.1 of the License, or 6 | # (at your option) any later version. 7 | 8 | [Unit] 9 | Description=udev Kernel Device Manager 10 | Documentation=man:systemd-udevd.service(8) man:udev(7) 11 | DefaultDependencies=no 12 | Wants=systemd-udevd-control.socket systemd-udevd-kernel.socket 13 | After=systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-sysusers.service 14 | Before=sysinit.target 15 | ConditionPathIsReadWrite=/sys 16 | 17 | [Service] 18 | Type=notify 19 | OOMScoreAdjust=-1000 20 | Sockets=systemd-udevd-control.socket systemd-udevd-kernel.socket 21 | Restart=always 22 | RestartSec=0 23 | ExecStart=/lib/systemd/systemd-udevd 24 | KillMode=mixed 25 | WatchdogSec=3min 26 | TasksMax=infinity 27 | MountFlags=shared 28 | MemoryDenyWriteExecute=yes 29 | RestrictRealtime=yes 30 | RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6 31 | -------------------------------------------------------------------------------- /rootfs_overlay/etc/udev/rules.d/99-zzz-opencdn.rules: -------------------------------------------------------------------------------- 1 | ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{UDISKS_FILESYSTEM_SHARED}="1" 2 | ACTION=="add", KERNEL=="sd[a-z][1-9]*", RUN+="/opt/opencdn/CDN/usb_handler.sh %k" 3 | ACTION=="remove", KERNEL=="sd[a-z][1-9]*", RUN+="/opt/opencdn/CDN/usb_handler.sh %k" 4 | -------------------------------------------------------------------------------- /rootfs_overlay/lib/systemd/system/appserver.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=App Server 3 | #After=network.target 4 | 5 | [Service] 6 | Type=simple 7 | Environment="NODE_PATH=$NODE_PATH:/opt/opencdn/" 8 | ExecStart=/usr/bin/node /opt/opencdn/appServer/index.js 9 | PIDFile=/tmp/opencdn/appserver.pid 10 | Restart=always 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /rootfs_overlay/lib/systemd/system/aria2.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=aria2, "The next generation download utility." 3 | #After=network.target 4 | 5 | [Service] 6 | Type=simple 7 | ExecStart=/usr/bin/aria2c --enable-rpc --rpc-listen-all=true --rpc-allow-origin-all 8 | PIDFile=/tmp/opencdn/aria2.pid 9 | Restart=always 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /rootfs_overlay/lib/systemd/system/avahi-daemon.service: -------------------------------------------------------------------------------- 1 | # This file is part of avahi. 2 | # 3 | # avahi is free software; you can redistribute it and/or modify it 4 | # under the terms of the GNU Lesser General Public License as 5 | # published by the Free Software Foundation; either version 2 of the 6 | # License, or (at your option) any later version. 7 | # 8 | # avahi is distributed in the hope that it will be useful, but WITHOUT 9 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 10 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 11 | # License for more details. 12 | # 13 | # You should have received a copy of the GNU Lesser General Public 14 | # License along with avahi; if not, write to the Free Software 15 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 16 | # USA. 17 | 18 | [Unit] 19 | Description=Avahi mDNS/DNS-SD Stack 20 | Requires=avahi-daemon.socket 21 | 22 | [Service] 23 | Type=dbus 24 | BusName=org.freedesktop.Avahi 25 | ExecStart=/usr/sbin/avahi-daemon --no-chroot -s 26 | ExecReload=/usr/sbin/avahi-daemon --no-chroot -r 27 | NotifyAccess=main 28 | 29 | [Install] 30 | WantedBy=multi-user.target 31 | Also=avahi-daemon.socket 32 | Alias=dbus-org.freedesktop.Avahi.service 33 | -------------------------------------------------------------------------------- /rootfs_overlay/lib/systemd/system/devmgmt.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Device management server 3 | #After=network.target 4 | 5 | [Service] 6 | Type=simple 7 | Environment="NODE_PATH=$NODE_PATH:/opt/opencdn/" 8 | ExecStart=/usr/bin/node /opt/opencdn/devmgmtV2/index.js 9 | PIDFile=/tmp/opencdn/devmgmt.pid 10 | Restart=always 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /rootfs_overlay/lib/systemd/system/searchserver.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=API server 3 | #After=network.target 4 | Before=udev-finish.service 5 | 6 | [Service] 7 | Type=simple 8 | ExecStart=/opt/opencdn/CDN/searchServer -http ":9095" 9 | PIDFile=/tmp/opencdn/apiserver.pid 10 | Restart=always 11 | 12 | [Install] 13 | WantedBy=multi-user.target 14 | -------------------------------------------------------------------------------- /rootfs_overlay/lib/systemd/system/syncthing.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Syncthing - Open Source Continuous File Synchronization 3 | After=network.target 4 | 5 | [Service] 6 | Type=simple 7 | Environment="HOME=/root" 8 | ExecStart=/opt/opencdn/CDN/syncthing -no-browser -no-restart -logflags=0 9 | Restart=on-failure 10 | SuccessExitStatus=3 4 11 | RestartForceExitStatus=3 4 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | -------------------------------------------------------------------------------- /rootfs_overlay/lib/systemd/system/telemetry.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=telemetry cloudsync server 3 | After=apiserver.service 4 | 5 | [Service] 6 | Type=simple 7 | ExecStart=/opt/opencdn/CDN/telemetry_upload.py 8 | PIDFile=/tmp/opencdn/telemetry.pid 9 | Restart=always 10 | 11 | [Install] 12 | WantedBy=multi-user.target 13 | -------------------------------------------------------------------------------- /rootfs_overlay/root/.config/syncthing/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
dynamic
4 | false 5 | true 6 | 0 7 | 0 8 |
9 | 10 |
127.0.0.1:8384
11 | 7i3w4cJ3ZH9DryCWdbe7HLdZVDtUxhDt 12 | default 13 |
14 | 15 | default 16 | default 17 | true 18 | true 19 | 21027 20 | [ff12::8384]:21027 21 | 0 22 | 0 23 | 60 24 | true 25 | 10 26 | true 27 | true 28 | 60 29 | 30 30 | 10 31 | 0 32 | 0 33 | nazWmbVt 34 | https://data.syncthing.net/newdata 35 | false 36 | 1800 37 | true 38 | 12 39 | false 40 | 24 41 | false 42 | 5 43 | false 44 | 1 45 | https://upgrades.syncthing.net/meta.json 46 | false 47 | 10 48 | 0 49 | /home/admin/diksha 50 | true 51 | 0 52 | 53 |
54 | -------------------------------------------------------------------------------- /rootfs_overlay/tmp/aria2_deb/aria2_1.30.0-2_armhf.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectOpenRAP/OpenRAP/858bcdc23d7cd1ad22388ef9779e6779384f963a/rootfs_overlay/tmp/aria2_deb/aria2_1.30.0-2_armhf.deb -------------------------------------------------------------------------------- /rootfs_overlay/tmp/aria2_deb/libc-ares2_1.12.0-1+deb9u1_armhf.deb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectOpenRAP/OpenRAP/858bcdc23d7cd1ad22388ef9779e6779384f963a/rootfs_overlay/tmp/aria2_deb/libc-ares2_1.12.0-1+deb9u1_armhf.deb -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/admin/asset-manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "main.css": "static/css/main.3f599e58.css", 3 | "main.css.map": "static/css/main.3f599e58.css.map", 4 | "main.js": "static/js/main.1ac1ce3a.js", 5 | "main.js.map": "static/js/main.1ac1ce3a.js.map", 6 | "static/media/flags.png": "static/media/flags.9c74e172.png", 7 | "static/media/icons.eot": "static/media/icons.674f50d2.eot", 8 | "static/media/icons.svg": "static/media/icons.912ec66d.svg", 9 | "static/media/icons.ttf": "static/media/icons.b06871f2.ttf", 10 | "static/media/icons.woff": "static/media/icons.fee66e71.woff", 11 | "static/media/icons.woff2": "static/media/icons.af7ae505.woff2" 12 | } -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/admin/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectOpenRAP/OpenRAP/858bcdc23d7cd1ad22388ef9779e6779384f963a/rootfs_overlay/var/www/html/admin/favicon.ico -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/admin/index.html: -------------------------------------------------------------------------------- 1 | React App
-------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/admin/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": "./index.html", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/admin/service-worker.js: -------------------------------------------------------------------------------- 1 | "use strict";function setOfCachedUrls(e){return e.keys().then(function(e){return e.map(function(e){return e.url})}).then(function(e){return new Set(e)})}var precacheConfig=[["/index.html","20f99424054ed3fb6bd134c9eb60e97d"],["/static/css/main.3f599e58.css","77144a1268158a0f633c1342a6fe179d"],["/static/js/main.1ac1ce3a.js","9398bd118e052fb15d4837957f556960"],["/static/media/flags.9c74e172.png","9c74e172f87984c48ddf5c8108cabe67"],["/static/media/icons.674f50d2.eot","674f50d287a8c48dc19ba404d20fe713"],["/static/media/icons.912ec66d.svg","912ec66d7572ff821749319396470bde"],["/static/media/icons.af7ae505.woff2","af7ae505a9eed503f8b8e6982036873e"],["/static/media/icons.b06871f2.ttf","b06871f281fee6b241d60582ae9369b9"],["/static/media/icons.fee66e71.woff","fee66e712a8a08eef5805a46892932ad"]],cacheName="sw-precache-v3-sw-precache-webpack-plugin-"+(self.registration?self.registration.scope:""),ignoreUrlParametersMatching=[/^utm_/],addDirectoryIndex=function(e,t){var n=new URL(e);return"/"===n.pathname.slice(-1)&&(n.pathname+=t),n.toString()},cleanResponse=function(e){if(!e.redirected)return Promise.resolve(e);return("body"in e?Promise.resolve(e.body):e.blob()).then(function(t){return new Response(t,{headers:e.headers,status:e.status,statusText:e.statusText})})},createCacheKey=function(e,t,n,r){var a=new URL(e);return r&&a.pathname.match(r)||(a.search+=(a.search?"&":"")+encodeURIComponent(t)+"="+encodeURIComponent(n)),a.toString()},isPathWhitelisted=function(e,t){if(0===e.length)return!0;var n=new URL(t).pathname;return e.some(function(e){return n.match(e)})},stripIgnoredUrlParameters=function(e,t){var n=new URL(e);return n.hash="",n.search=n.search.slice(1).split("&").map(function(e){return e.split("=")}).filter(function(e){return t.every(function(t){return!t.test(e[0])})}).map(function(e){return e.join("=")}).join("&"),n.toString()},hashParamName="_sw-precache",urlsToCacheKeys=new Map(precacheConfig.map(function(e){var t=e[0],n=e[1],r=new URL(t,self.location),a=createCacheKey(r,hashParamName,n,/\.\w{8}\./);return[r.toString(),a]}));self.addEventListener("install",function(e){e.waitUntil(caches.open(cacheName).then(function(e){return setOfCachedUrls(e).then(function(t){return Promise.all(Array.from(urlsToCacheKeys.values()).map(function(n){if(!t.has(n)){var r=new Request(n,{credentials:"same-origin"});return fetch(r).then(function(t){if(!t.ok)throw new Error("Request for "+n+" returned a response with status "+t.status);return cleanResponse(t).then(function(t){return e.put(n,t)})})}}))})}).then(function(){return self.skipWaiting()}))}),self.addEventListener("activate",function(e){var t=new Set(urlsToCacheKeys.values());e.waitUntil(caches.open(cacheName).then(function(e){return e.keys().then(function(n){return Promise.all(n.map(function(n){if(!t.has(n.url))return e.delete(n)}))})}).then(function(){return self.clients.claim()}))}),self.addEventListener("fetch",function(e){if("GET"===e.request.method){var t,n=stripIgnoredUrlParameters(e.request.url,ignoreUrlParametersMatching),r="index.html";(t=urlsToCacheKeys.has(n))||(n=addDirectoryIndex(n,r),t=urlsToCacheKeys.has(n));var a="/index.html";!t&&"navigate"===e.request.mode&&isPathWhitelisted(["^(?!\\/__).*"],e.request.url)&&(n=new URL(a,self.location).toString(),t=urlsToCacheKeys.has(n)),t&&e.respondWith(caches.open(cacheName).then(function(e){return e.match(urlsToCacheKeys.get(n)).then(function(e){if(e)return e;throw Error("The cached response that was expected is missing.")})}).catch(function(t){return console.warn('Couldn\'t serve response for "%s" from cache: %O',e.request.url,t),fetch(e.request)}))}}); -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/admin/static/media/flags.9c74e172.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectOpenRAP/OpenRAP/858bcdc23d7cd1ad22388ef9779e6779384f963a/rootfs_overlay/var/www/html/admin/static/media/flags.9c74e172.png -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/admin/static/media/icons.674f50d2.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectOpenRAP/OpenRAP/858bcdc23d7cd1ad22388ef9779e6779384f963a/rootfs_overlay/var/www/html/admin/static/media/icons.674f50d2.eot -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/admin/static/media/icons.af7ae505.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectOpenRAP/OpenRAP/858bcdc23d7cd1ad22388ef9779e6779384f963a/rootfs_overlay/var/www/html/admin/static/media/icons.af7ae505.woff2 -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/admin/static/media/icons.b06871f2.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectOpenRAP/OpenRAP/858bcdc23d7cd1ad22388ef9779e6779384f963a/rootfs_overlay/var/www/html/admin/static/media/icons.b06871f2.ttf -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/admin/static/media/icons.fee66e71.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectOpenRAP/OpenRAP/858bcdc23d7cd1ad22388ef9779e6779384f963a/rootfs_overlay/var/www/html/admin/static/media/icons.fee66e71.woff -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/public/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectOpenRAP/OpenRAP/858bcdc23d7cd1ad22388ef9779e6779384f963a/rootfs_overlay/var/www/html/public/.DS_Store -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/public/._images: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectOpenRAP/OpenRAP/858bcdc23d7cd1ad22388ef9779e6779384f963a/rootfs_overlay/var/www/html/public/._images -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/public/app.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectOpenRAP/OpenRAP/858bcdc23d7cd1ad22388ef9779e6779384f963a/rootfs_overlay/var/www/html/public/app.apk -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/public/google-font: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Lato'; 3 | font-style: normal; 4 | font-weight: 400; 5 | src: local('Lato Regular'), local('Lato-Regular'), url(https://fonts.gstatic.com/s/lato/v11/v0SdcGFAl2aezM9Vq_aFTQ.ttf) format('truetype'); 6 | } 7 | @font-face { 8 | font-family: 'Lato'; 9 | font-style: normal; 10 | font-weight: 700; 11 | src: local('Lato Bold'), local('Lato-Bold'), url(https://fonts.gstatic.com/s/lato/v11/DvlFBScY1r-FMtZSYIYoYw.ttf) format('truetype'); 12 | } 13 | -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/public/images/CaptivePortalLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectOpenRAP/OpenRAP/858bcdc23d7cd1ad22388ef9779e6779384f963a/rootfs_overlay/var/www/html/public/images/CaptivePortalLogo.png -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/public/images/android_app_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectOpenRAP/OpenRAP/858bcdc23d7cd1ad22388ef9779e6779384f963a/rootfs_overlay/var/www/html/public/images/android_app_download.png -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/public/images/header-bg1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/projectOpenRAP/OpenRAP/858bcdc23d7cd1ad22388ef9779e6779384f963a/rootfs_overlay/var/www/html/public/images/header-bg1.jpg -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } -------------------------------------------------------------------------------- /rootfs_overlay/var/www/html/text.json: -------------------------------------------------------------------------------- 1 | {"data": {"text": "

Welcome to the world of Free and Interactive Education.
Turn OFF your data connection (3G/4G), download the Diksha App from below and enjoy Learning

", "head": "OpenRAP"}} 2 | 3 | -------------------------------------------------------------------------------- /searchServer/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # NOTE: Run this scripts from inside go env (from soft link) 3 | # Assume that apiserver is softlink to build/go/src/bitbucket.org/teamopencdn/apiserver 4 | # cd build/go/src/bitbucket.org/teamopencdn 5 | # And ./build.sh pc 6 | 7 | if [ $# -ne 1 ]; then 8 | echo "$0 " 9 | exit 0 10 | fi 11 | 12 | export GOPATH=$PWD/../../../../.. 13 | export GOBIN=$GOPATH/bin 14 | export PATH=/usr/local/go/bin:$GOBIN:$PATH 15 | 16 | arch=$1 17 | 18 | exe_name=searchServer 19 | echo "GOPATH=$GOPATH" 20 | 21 | 22 | if [ $arch == "arm" ]; then 23 | env CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -o $exe_name 24 | else 25 | env CGO_ENABLED=0 go build -o $exe_name 26 | fi 27 | 28 | -------------------------------------------------------------------------------- /searchServer/config/deviceConfig.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "log" 7 | ) 8 | 9 | type DeviceConfig struct { 10 | deviceConfigJson DeviceConfigJson 11 | ActiveProfile DeviceInfo 12 | Logger *Tracelog 13 | } 14 | 15 | var DevConfig *DeviceConfig 16 | 17 | type DeviceInfo struct { 18 | AcceptedExtensions []string `json:"accepted_extensions"` // .ecar 19 | CdnURL string `json:"cdn_url"` // http://cdn.pinut.com 20 | CdnScriptsURL string `json:"cdn_scripts_url"` // /opt/opencdn/CDN 21 | ConfigJsonDir string `json:"config_json_dir"` // /var/www/ekstep/config_json/ 22 | ConfigJsonName string `json:"config_json_name"` // config.json 23 | ContentRoot string `json:"content_root"` // /var/www/ekstep/ecar_files/ 24 | JsonDir string `json:"json_dir"` // /var/www/ekstep/json_dir/ 25 | MediaRoot string `json:"media_root"` // /var/www/ekstep/ 26 | ProfileName string `json:"profile_name"` // ekstep 27 | ServerRoot string `json:"server_root"` // /home/pi/usb-backend-pinut/file_upload/ 28 | Telemetry string `json:"telemetry"` // /var/www/ekstep/telemetry/ 29 | UnzipContent string `json:"unzip_content"` // /var/www/ekstep/content/ 30 | UnzipContentdirName string `json:"unzip_contentdir_name"` // /var/www/ekstep/content/ 31 | UsbOnAutomount string `json:"usb_on_automount"` // /media/ 32 | UsbDir string `json:"usb_dir"` // ecar_files 33 | } 34 | 35 | type DeviceConfigJson struct { 36 | ActiveProfileName string `json:"active_profile"` // ekstep 37 | AvailableProfiles map[string]DeviceInfo `json:"available_profiles"` // ekstep 38 | } 39 | 40 | func DeviceConfigLoad() *DeviceConfig { 41 | var ch DeviceConfig 42 | // var configfile = flags.Configfile 43 | var configfile = "/opt/opencdn/CDN/profile.json" 44 | 45 | raw, err := ioutil.ReadFile(configfile) 46 | if err != nil { 47 | log.Fatalf("Error opening device config JSON file: %v", err) 48 | return &ch 49 | } 50 | 51 | dcj := ch.deviceConfigJson 52 | err = json.Unmarshal(raw, &dcj) 53 | if err != nil { 54 | log.Fatalf("Invalid format device config JSON file: %v", err) 55 | return &ch 56 | } 57 | pn := dcj.ActiveProfileName 58 | profiles := dcj.AvailableProfiles 59 | 60 | for k, v := range profiles { 61 | if k == pn { 62 | ch.ActiveProfile = v 63 | } 64 | } 65 | 66 | return &ch 67 | } 68 | 69 | func DeviceConfigInit() { 70 | DevConfig = DeviceConfigLoad() 71 | logfile := DevConfig.ActiveProfile.MediaRoot + "searchServer.log" 72 | DevConfig.Logger = LoggerInit(logfile) 73 | } 74 | 75 | func DeviceConfigGet() *DeviceConfig { 76 | return DevConfig 77 | } 78 | 79 | func DeviceConfigJsonAbsFile() *string { 80 | if DevConfig == nil { 81 | return nil 82 | } 83 | af := DevConfig.ActiveProfile.ConfigJsonDir + DevConfig.ActiveProfile.ConfigJsonName 84 | return &af 85 | } 86 | 87 | func DeviceConfigJsonDirPath() *string { 88 | if DevConfig == nil { 89 | return nil 90 | } 91 | return (&DevConfig.ActiveProfile.ConfigJsonDir) 92 | } 93 | 94 | func DeviceDataJsonDirPath() *string { 95 | if DevConfig == nil { 96 | return nil 97 | } 98 | return (&DevConfig.ActiveProfile.JsonDir) 99 | } 100 | 101 | func (dc *DeviceConfig) CdnURL() string { 102 | return dc.ActiveProfile.CdnURL 103 | } 104 | 105 | func (dc *DeviceConfig) ContentRootPath() string { 106 | return dc.ActiveProfile.ContentRoot 107 | } 108 | 109 | func (dc *DeviceConfig) UnzipContentdirName() string { 110 | return dc.ActiveProfile.UnzipContentdirName 111 | } 112 | 113 | func DeviceProfileTelemetryDir() string { 114 | if DevConfig == nil { 115 | return "/tmp/" 116 | } 117 | return (DevConfig.ActiveProfile.Telemetry) 118 | } 119 | 120 | func (dc *DeviceConfig) ConfigJsonAbsFilename() string { 121 | af := dc.ActiveProfile.ConfigJsonDir + dc.ActiveProfile.ConfigJsonName 122 | log.Printf("config file abs: %s\n", af) 123 | return af 124 | } 125 | -------------------------------------------------------------------------------- /searchServer/config/tracelog.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "io" 5 | "io/ioutil" 6 | "log" 7 | "os" 8 | "sync/atomic" 9 | ) 10 | 11 | const systemAlertSubject = "TraceLog Exception" 12 | 13 | const ( 14 | // LevelTrace logs everything 15 | LevelTrace int32 = 1 16 | 17 | // LevelInfo logs Info, Warnings and Errors 18 | LevelInfo int32 = 2 19 | 20 | // LevelWarn logs Warning and Errors 21 | LevelWarn int32 = 4 22 | 23 | // LevelError logs just Errors 24 | LevelError int32 = 8 25 | ) 26 | 27 | // traceLog provides support to write to log files. 28 | type Tracelog struct { 29 | LogLevel int32 30 | Trace *log.Logger 31 | Info *log.Logger 32 | Warning *log.Logger 33 | Error *log.Logger 34 | File *log.Logger 35 | LogFile *os.File 36 | } 37 | 38 | // log maintains a pointer to a singleton for the logging system. 39 | var logger *Tracelog 40 | 41 | func LoggerInit(logfile string) *Tracelog { 42 | 43 | if logger != nil { 44 | return logger 45 | } 46 | 47 | // FIXME: Need log rotation, till then create the log file in /tmp 48 | logfile = "/tmp/searchServer.log" 49 | 50 | log.SetPrefix("TRACE: ") 51 | log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile) 52 | 53 | logf, err := os.OpenFile(logfile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666) 54 | if err != nil { 55 | log.Println("cannot create log file: ", err) 56 | } 57 | 58 | // Create a new logger 59 | //logger = &Tracelog{LevelTrace, ioutil.Discard, ioutil.Discard, ioutil.Discard, ioutil.Discard, ioutil.Discard, logf} 60 | logger = &Tracelog{LevelTrace, nil, nil, nil, nil, nil, logf} 61 | 62 | // Turn the logging trace level 63 | turnOnLogging(LevelTrace, logf) 64 | 65 | logger.Trace.Printf("Storing the log messages into file: %s\n", logfile) 66 | 67 | return logger 68 | } 69 | 70 | // Start initializes tracelog and only displays the specified logging level. 71 | func Start(logLevel int32) { 72 | turnOnLogging(logLevel, nil) 73 | } 74 | 75 | // Stop will release resources and shutdown all processing. 76 | func Stop() error { 77 | 78 | var err error 79 | if logger.LogFile != nil { 80 | err = logger.LogFile.Close() 81 | } 82 | 83 | return err 84 | } 85 | 86 | // LogLevel returns the configured logging level. 87 | func LogLevel() int32 { 88 | return atomic.LoadInt32(&logger.LogLevel) 89 | } 90 | 91 | // turnOnLogging configures the logging writers. 92 | func turnOnLogging(logLevel int32, fileHandle io.Writer) { 93 | traceHandle := ioutil.Discard 94 | infoHandle := ioutil.Discard 95 | warnHandle := ioutil.Discard 96 | errorHandle := ioutil.Discard 97 | 98 | if logLevel&LevelTrace != 0 { 99 | traceHandle = os.Stdout 100 | infoHandle = os.Stdout 101 | warnHandle = os.Stdout 102 | errorHandle = os.Stderr 103 | } 104 | 105 | if logLevel&LevelInfo != 0 { 106 | infoHandle = os.Stdout 107 | warnHandle = os.Stdout 108 | errorHandle = os.Stderr 109 | } 110 | 111 | if logLevel&LevelWarn != 0 { 112 | warnHandle = os.Stdout 113 | errorHandle = os.Stderr 114 | } 115 | 116 | if logLevel&LevelError != 0 { 117 | errorHandle = os.Stderr 118 | } 119 | 120 | if fileHandle != nil { 121 | if traceHandle == os.Stdout { 122 | traceHandle = io.MultiWriter(fileHandle, traceHandle) 123 | } 124 | 125 | if infoHandle == os.Stdout { 126 | infoHandle = io.MultiWriter(fileHandle, infoHandle) 127 | } 128 | 129 | if warnHandle == os.Stdout { 130 | warnHandle = io.MultiWriter(fileHandle, warnHandle) 131 | } 132 | 133 | if errorHandle == os.Stderr { 134 | errorHandle = io.MultiWriter(fileHandle, errorHandle) 135 | } 136 | } 137 | 138 | logger.Trace = log.New(traceHandle, "TRACE: ", log.Ldate|log.Ltime|log.Lshortfile) 139 | logger.Info = log.New(infoHandle, "INFO: ", log.Ldate|log.Ltime|log.Lshortfile) 140 | logger.Warning = log.New(warnHandle, "WARNING: ", log.Ldate|log.Ltime|log.Lshortfile) 141 | logger.Error = log.New(errorHandle, "ERROR: ", log.Ldate|log.Ltime|log.Lshortfile) 142 | 143 | atomic.StoreInt32(&logger.LogLevel, logLevel) 144 | } 145 | -------------------------------------------------------------------------------- /searchServer/edu/commonUtil.go: -------------------------------------------------------------------------------- 1 | package edu 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | type CommonUtilParams struct { 8 | Err string `json:"err"` // 9 | Errmsg string `json:"errmsg"` // 10 | Msgid string `json:"msgid"` // ff305d54-85b4-341b-da2f-eb6b9e5460fa 11 | Resmsgid string `json:"resmsgid"` // c3800c567711b10e128d3b1353328a60f6bb5583 12 | Status string `json:"status"` // successful 13 | } 14 | 15 | type CommonUtilFilters struct { 16 | AgeGroup []string `json:"ageGroup,omitempty"` // 8-10 17 | Board []string `json:"board,omitempty"` // CBSE 18 | CompatibilityLevel struct { 19 | Max int64 `json:"max"` // 2 20 | Min int64 `json:"min"` // 1 21 | } `json:"compatibilityLevel,omitempty"` 22 | ContentType []string `json:"contentType,omitempty"` // Story 23 | Domain []string `json:"domain,omitempty"` // numeracy 24 | GradeLevel []string `json:"gradeLevel,omitempty"` // Grade 5 25 | GenieScore struct { 26 | Min float64 `json:"min"` // 0 27 | } `json:"genieScore,omitempty"` 28 | Identifier []string `json:"identifier,omitempty"` // do_30031995 29 | Language []string `json:"language,omitempty"` // english 30 | Medium []string `json:"medium,omitempty"` // Hindi 31 | ObjectType []string `json:"objectType,omitempty"` // Content 32 | Subject []string `json:"subject,omitempty"` // domain 33 | Status []string `json:"status,omitempty"` // Live 34 | } 35 | 36 | type CommonUtilSortBy struct { 37 | GenieScore string `json:"genieScore,omitempty"` // desc 38 | LastPublishedOn string `json:"lastPublishedOn,omitempty"` //desc 39 | Popularity string `json:"popularity,omitempty"` //desc 40 | } 41 | 42 | type CommonUtilPageSectionsSearch struct { 43 | Facets []string `json:"facets,omitempty"` // contentType 44 | Filters CommonUtilFilters `json:"filters"` 45 | Limit int `json:"limit,omitempty"` 46 | Mode string `json:"mode,omitempty"` // soft 47 | Query string `json:"query"` 48 | SortBy *CommonUtilSortBy `json:"sort_by"` 49 | } 50 | 51 | // merge merges the two JSON-marshalable values x1 and x2, 52 | // preferring x1 over x2 except where x1 and x2 are 53 | // JSON objects, in which case the keys from both objects 54 | // are included and their values merged recursively. 55 | // 56 | // It returns an error if x1 or x2 cannot be JSON-marshaled. 57 | 58 | func MergeJson(x1, x2 interface{}) (interface{}, error) { 59 | data1, err := json.Marshal(x1) 60 | if err != nil { 61 | return nil, err 62 | } 63 | data2, err := json.Marshal(x2) 64 | if err != nil { 65 | return nil, err 66 | } 67 | var j1 interface{} 68 | err = json.Unmarshal(data1, &j1) 69 | if err != nil { 70 | return nil, err 71 | } 72 | var j2 interface{} 73 | err = json.Unmarshal(data2, &j2) 74 | if err != nil { 75 | return nil, err 76 | } 77 | return merge1(j1, j2), nil 78 | } 79 | 80 | func merge1(x1, x2 interface{}) interface{} { 81 | switch x1 := x1.(type) { 82 | case map[string]interface{}: 83 | x2, ok := x2.(map[string]interface{}) 84 | if !ok { 85 | return x1 86 | } 87 | for k, v2 := range x2 { 88 | if v1, ok := x1[k]; ok { 89 | x1[k] = merge1(v1, v2) 90 | } else { 91 | x1[k] = v2 92 | } 93 | } 94 | case nil: 95 | // merge(nil, map[string]interface{...}) -> map[string]interface{...} 96 | x2, ok := x2.(map[string]interface{}) 97 | if ok { 98 | return x2 99 | } 100 | } 101 | return x1 102 | } 103 | 104 | func mergeFilters(x1, x2 *CommonUtilFilters) (*CommonUtilFilters, error) { 105 | data1, err := json.Marshal(x1) 106 | if err != nil { 107 | return nil, err 108 | } 109 | data2, err := json.Marshal(x2) 110 | if err != nil { 111 | return nil, err 112 | } 113 | var mf *CommonUtilFilters 114 | err = json.Unmarshal(data1, &mf) 115 | if err != nil { 116 | return nil, err 117 | } 118 | err = json.Unmarshal(data2, &mf) 119 | if err != nil { 120 | return nil, err 121 | } 122 | return mf, nil 123 | } 124 | -------------------------------------------------------------------------------- /searchServer/edu/contentHomeUtil.go: -------------------------------------------------------------------------------- 1 | package edu 2 | 3 | type ContentHomeUtilPageSectionsDisplay struct { 4 | Name struct { 5 | En string `json:"en"` // Best of Genie 6 | Hn string `json:"hn"` // लोकप्रिय कहानियां 7 | } `json:"name"` 8 | } 9 | type ContentHomeUtilPageSectionsRecommend struct { 10 | Context struct { 11 | ContentId string `json:"contentid"` 12 | Did string `json:"did"` 13 | Dlang string `json:"dlang"` 14 | } `json:"context"` 15 | Facets []string `json:"facets,omitempty"` // contentType 16 | Filters *CommonUtilFilters `json:"filters"` 17 | Limit int `json:"limit,omitempty"` 18 | SortBy *CommonUtilSortBy `json:"sort_by"` 19 | } 20 | 21 | type ContentHomeUtilPageSections struct { 22 | Display ContentHomeUtilPageSectionsDisplay `json:"display"` 23 | Recommend *ContentHomeUtilPageSectionsRecommend `json:"recommend"` 24 | //Recommend ContentHomeUtilPageSectionsRecommend `json:"recommend,omitempty"` 25 | FilterModifiable bool `json:"filterModifiable"` // true 26 | Search CommonUtilPageSectionsSearch `json:"search,omitempty"` 27 | //Contents []ContentHomeUtilPageSectionsContents `json:"contents,omitempty"` 28 | Contents []EcarManifestArchiveItems `json:"contents,omitempty"` 29 | Apiid string `json:"apiid,omitempty"` // ekstep.composite-search.search 30 | } 31 | 32 | type ContentHomeUtilPage struct { 33 | ID string `json:"id"` // org.ekstep.genie.content.home 34 | Banners interface{} `json:"banners,omitempty"` // 35 | Sections []ContentHomeUtilPageSections `json:"sections"` 36 | } 37 | -------------------------------------------------------------------------------- /searchServer/edu/eduInit.go: -------------------------------------------------------------------------------- 1 | package edu 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "log" 8 | "net/http" 9 | "os" 10 | 11 | "github.com/gorilla/mux" 12 | "github.com/projectOpenRAP/OpenRAP/searchServer/config" 13 | ) 14 | 15 | type EkstepConfig struct { 16 | router *mux.Router 17 | contentJson ContentListingJson 18 | // contentJson ContentHomeConfig 19 | deviceConfig *config.DeviceConfig 20 | } 21 | 22 | var EkstepConfigGlobal *EkstepConfig 23 | var logger *config.Tracelog 24 | 25 | var routes map[string]http.HandlerFunc = map[string]http.HandlerFunc{ 26 | "/api/search/v2/edu/init": eduInitHandler, 27 | //API for homepage 28 | "/api/search/v2/edu/homepage": contentHomeHandler, 29 | "/api/search/v2/edu/doc/{contentID}": contentIdHandler, 30 | 31 | //API for different types of search 32 | "/api/search/v2/edu/search": searchHandler, 33 | //QA api 34 | "/api/composite/v3/search": searchHandler, 35 | 36 | //Private api 37 | //API to add/remove ecar from search index 38 | "/api/ekstepdb/{jsonfile}": ekstepIndexJsonFileHandler, 39 | } 40 | 41 | func EduInit(router *mux.Router) { 42 | c := &EkstepConfig{} 43 | 44 | //Load Device configuration 45 | c.deviceConfig = config.DeviceConfigGet() 46 | if c.deviceConfig == nil { 47 | logger.Error.Fatal("ES: Couldn't parse device config json") 48 | } 49 | logger = c.deviceConfig.Logger 50 | 51 | c.router = router 52 | c.contentJson = c.ContentListingJsonLoad() 53 | c.registerRoute() 54 | EkstepConfigGlobal = c 55 | 56 | uuidInit() 57 | //Call it from API 58 | //eduSearchInit("/opt/searchEngine/bleveDbDir", "es.db", "/var/www/ekstep/json_dir") 59 | logger.Trace.Println("ES module initialized...") 60 | } 61 | 62 | func (ms *EkstepConfig) ContentListingJsonLoad() ContentListingJson { 63 | var c ContentListingJson 64 | 65 | cj := ms.deviceConfig.ConfigJsonAbsFilename() 66 | 67 | raw, err := ioutil.ReadFile(cj) 68 | if err != nil { 69 | logger.Error.Printf("ES: Error opening content json file: %v", err) 70 | return c 71 | } 72 | json.Unmarshal(raw, &c) 73 | return c 74 | } 75 | 76 | func (c *EkstepConfig) registerRoute() error { 77 | for route, handler := range routes { 78 | c.router.HandleFunc(route, handler) 79 | } 80 | logger.Trace.Println("ES: Registered route for REST api") 81 | return nil 82 | } 83 | 84 | var RFd *os.File 85 | 86 | func uuidInit() { 87 | f, err := os.Open("/dev/urandom") 88 | if err != nil { 89 | log.Fatal(err) 90 | } 91 | RFd = f 92 | } 93 | 94 | func UUIDGet() string { 95 | b := make([]byte, 16) 96 | RFd.Read(b) 97 | b[6] = (b[6] & 0x0f) | 0x40 98 | b[8] = (b[8] & 0x3f) | 0x80 99 | return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) 100 | } 101 | -------------------------------------------------------------------------------- /searchServer/edu/esContentListingJson.go: -------------------------------------------------------------------------------- 1 | package edu 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | "time" 8 | 9 | "github.com/mohae/deepcopy" //to copy a slice 10 | ) 11 | 12 | //var ContentHomeConfigGlobal ContentHomeConfig 13 | 14 | type ContentListingJson struct { 15 | Page ContentHomeUtilPage `json:"page"` 16 | } 17 | 18 | /* 19 | POST /api/page/v1/assemble/org.ekstep.genie.content.home 20 | Accept-Encoding: gzip, deflate 21 | Content-Type: application/json; charset=utf-8 22 | Content-Length: 216 23 | Host: cdn.pinut.com 24 | Connection: Keep-Alive 25 | */ 26 | 27 | type ContentHomeRequestRequest struct { 28 | Context struct { 29 | Contentid string `json:"contentid"` // 30 | Did string `json:"did"` // 4e7839c64fe0b2da27a3d322a851a9038ee20240 31 | Dlang string `json:"dlang"` // en 32 | Uid string `json:"uid"` // 7c68ee48-7695-473f-8699-d1de2ff32beb 33 | } `json:"context"` 34 | Filters CommonUtilFilters `json:"filters"` 35 | } 36 | 37 | type ContentHomeRequest struct { 38 | ID string `json:"id"` // ekstep.genie.content.home 39 | Ets int64 `json:"ets"` // 1.499853989625e+12 40 | Request ContentHomeRequestRequest `json:"request"` 41 | //Ver string `json:"ver,string"` // 1.0 42 | Ver string `json:"ver"` // 1.0 43 | } 44 | type ContentHomeResponseResult struct { 45 | Page ContentHomeUtilPage `json:"page"` 46 | } 47 | 48 | type ContentHomeResponse struct { 49 | ID string `json:"id"` // ekstep.genie.content.home 50 | Params CommonUtilParams `json:"params"` 51 | Result ContentHomeResponseResult `json:"result"` 52 | Ts time.Time `json:"ts"` // 2017-06-13T12:05:30+00:00 53 | Ver string `json:"ver"` // 1.0 54 | } 55 | 56 | /* 57 | * Response to create the first page in mobile app 58 | */ 59 | func contentHomeResponseGenerate(chReq *ContentHomeRequest) (ContentHomeResponse, error) { 60 | var ch ContentHomeResponse 61 | 62 | fmt.Println("contentHomeResponseGenerate start...\n") 63 | 64 | /* 65 | * This dynamic json data will be constructed based on the 66 | * global config and request body 67 | * Dynamic search api will be called to construct the page sections 68 | */ 69 | 70 | //Fill the id (from the request body) 71 | ch.ID = chReq.ID 72 | //Fill the version (from the request body) 73 | ch.Ver = chReq.Ver 74 | //TODO: Fill the timestamp 75 | 76 | //redData is "request:" data in the body 77 | var err error 78 | var reqData ContentHomeRequestRequest 79 | reqData = chReq.Request 80 | //log.Printf("%s", toJson(reqData)) 81 | // var sections []ContentHomeConfigPageSections 82 | //sections := ContentHomeConfigGlobal.Page.Sections 83 | tmpSections := deepcopy.Copy(EkstepConfigGlobal.contentJson.Page.Sections) 84 | sections := tmpSections.([]ContentHomeUtilPageSections) 85 | 86 | // page := ch.Result.Page 87 | // log.Printf("%s", toJson(page)) 88 | // docs := make([]EcarManifest, 0) 89 | 90 | for idx, section := range sections { 91 | 92 | docs, err := SearchContentHomePageSection(§ion, &reqData) 93 | // raw, err := ioutil.ReadFile("search/contentHomeResponse.json") 94 | if err != nil { 95 | fmt.Println("Error opening JSON file:", err) 96 | return ch, err 97 | } 98 | 99 | for _, d := range docs { 100 | //sections[idx].Contents = append(sections[idx].Contents, d.Archive.Items...) 101 | sections[idx].Contents = append(sections[idx].Contents, d) 102 | } 103 | } 104 | 105 | //json.Unmarshal(raw, &ch) 106 | // fmt.Println(ch.toString()) 107 | ch.Result.Page.Sections = sections 108 | ch.Result.Page.ID = EkstepConfigGlobal.contentJson.Page.ID 109 | 110 | //TODO: Fill the "params:" 111 | ch.Params.Resmsgid = "c3800c567711b10e128d3b1353328a60f6bb5583" 112 | ch.Params.Msgid = "ff305d54-85b4-341b-da2f-eb6b9e5460fa" 113 | ch.Params.Status = "successful" 114 | ch.Params.Err = "" 115 | ch.Params.Errmsg = "" 116 | 117 | return ch, err 118 | } 119 | 120 | func (p ContentHomeResponse) toString() string { 121 | return toJsonStr(p) 122 | } 123 | 124 | func toJsonStr(p interface{}) string { 125 | bytes, err := json.Marshal(p) 126 | if err != nil { 127 | fmt.Println(err.Error()) 128 | os.Exit(1) 129 | } 130 | return string(bytes) 131 | } 132 | -------------------------------------------------------------------------------- /searchServer/http_util.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014 Couchbase, Inc. 2 | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 3 | // except in compliance with the License. You may obtain a copy of the License at 4 | // http://www.apache.org/licenses/LICENSE-2.0 5 | // Unless required by applicable law or agreed to in writing, software distributed under the 6 | // License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 7 | // either express or implied. See the License for the specific language governing permissions 8 | // and limitations under the License. 9 | 10 | package main 11 | 12 | //go:generate go-bindata-assetfs -pkg=main ./static/... 13 | //go:generate go fmt . 14 | 15 | import ( 16 | "encoding/json" 17 | "io" 18 | "log" 19 | "net/http" 20 | 21 | "github.com/gorilla/mux" 22 | ) 23 | 24 | func staticFileRouter(r *mux.Router, static http.Handler) *mux.Router { 25 | // static 26 | r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", 27 | myFileHandler{static})) 28 | // bootstrap ui insists on loading templates from this path 29 | r.PathPrefix("/template/").Handler(http.StripPrefix("/template/", 30 | myFileHandler{static})) 31 | 32 | // application pages 33 | appPages := []string{ 34 | "/overview", 35 | "/search", 36 | "/indexes", 37 | "/analysis", 38 | "/monitor", 39 | } 40 | 41 | for _, p := range appPages { 42 | // if you try to use index.html it will redirect...poorly 43 | r.PathPrefix(p).Handler(RewriteURL("/", static)) 44 | } 45 | 46 | r.Handle("/", http.RedirectHandler("/static/index.html", 302)) 47 | 48 | return r 49 | } 50 | 51 | type myFileHandler struct { 52 | h http.Handler 53 | } 54 | 55 | func (mfh myFileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 56 | //if *staticEtag != "" { 57 | // w.Header().Set("Etag", *staticEtag) 58 | //} 59 | mfh.h.ServeHTTP(w, r) 60 | } 61 | 62 | func RewriteURL(to string, h http.Handler) http.Handler { 63 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 64 | r.URL.Path = to 65 | h.ServeHTTP(w, r) 66 | }) 67 | } 68 | 69 | func muxVariableLookup(req *http.Request, name string) string { 70 | return mux.Vars(req)[name] 71 | } 72 | 73 | func docIDLookup(req *http.Request) string { 74 | return muxVariableLookup(req, "docID") 75 | } 76 | 77 | func indexNameLookup(req *http.Request) string { 78 | return muxVariableLookup(req, "indexName") 79 | } 80 | 81 | func showError(w http.ResponseWriter, r *http.Request, 82 | msg string, code int) { 83 | log.Printf("Reporting error %v/%v", code, msg) 84 | http.Error(w, msg, code) 85 | } 86 | 87 | func mustEncode(w io.Writer, i interface{}) { 88 | if headered, ok := w.(http.ResponseWriter); ok { 89 | headered.Header().Set("Cache-Control", "no-cache") 90 | headered.Header().Set("Content-type", "application/json") 91 | } 92 | 93 | e := json.NewEncoder(w) 94 | if err := e.Encode(i); err != nil { 95 | panic(err) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /searchServer/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "log" 6 | "os" 7 | 8 | "github.com/projectOpenRAP/OpenRAP/searchServer/config" 9 | ) 10 | 11 | var ( 12 | httpAddr string 13 | bleveDbDir, indexName string 14 | telemetryEnable, devmgmtEnable bool 15 | indexDbPath string 16 | logger *config.Tracelog 17 | ) 18 | 19 | func createActiveProfileDirectories(activeProfile config.DeviceInfo) { 20 | var pathErr error 21 | // Create directories based on profile.json 22 | dirpath := []string{ 23 | activeProfile.ConfigJsonDir, 24 | activeProfile.JsonDir, 25 | activeProfile.ContentRoot, 26 | activeProfile.UnzipContent, 27 | activeProfile.Telemetry} 28 | 29 | for _, dp := range dirpath { 30 | logger.Trace.Printf("Creating dir: %s", dp) 31 | pathErr = os.MkdirAll(dp, 0755) 32 | if pathErr != nil { 33 | logger.Error.Println(pathErr) 34 | } 35 | } 36 | } 37 | 38 | func main() { 39 | flag.StringVar(&httpAddr, "http", "0.0.0.0:9095", "HTTP service ip:port") 40 | flag.StringVar(&bleveDbDir, "bleveDbDir", "/opt/searchEngine/bleveDbDir", "HTTP server root dir") 41 | flag.StringVar(&indexName, "index", "default.bleve", "index name") 42 | 43 | flag.Parse() 44 | 45 | //Load Device configuration 46 | config.DeviceConfigInit() 47 | dconfig := config.DeviceConfigGet() 48 | if dconfig == nil { 49 | log.Fatal("Couldn't parse config json") 50 | } 51 | //profile := dconfig.ActiveProfile.ProfileName 52 | 53 | logger = dconfig.Logger 54 | 55 | createActiveProfileDirectories(dconfig.ActiveProfile) 56 | 57 | loadIndexAndServe(bleveDbDir, httpAddr) 58 | 59 | // serve(profile) 60 | } 61 | -------------------------------------------------------------------------------- /searchServer/test/abc.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Feature game for ekstep" 3 | } 4 | -------------------------------------------------------------------------------- /searchServer/test/test_script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | searchServerURL="http://localhost:9095" 3 | indexName="myindex" 4 | 5 | echo "Creating an index: $indexName into the searchServer ..." 6 | sleep 1 7 | curl -X PUT $searchServerURL/api/search/v2/index/$indexName 8 | 9 | for doc in abc.json xyz.json 10 | do 11 | echo "Adding document: $doc into index: $indexName" 12 | sleep 1 13 | curl -X PUT $searchServerURL/api/search/v2/index/$indexName/document/$doc -d @$doc 14 | done 15 | 16 | echo "Searching word: ekstep in the index : $indexName" 17 | sleep 1 18 | curl -X POST $searchServerURL/api/search/v2/index/$indexName/_search -d '{"query":{"query": "ekstep"}}' 19 | 20 | docId="abc.json" 21 | echo "Get documentById for doc: $docId" 22 | sleep 1 23 | curl -X GET $searchServerURL/api/search/v2/index/$indexName/document/$docId 24 | 25 | echo "Searching word: game in the index : $indexName" 26 | sleep 1 27 | curl -X POST $searchServerURL/api/search/v2/index/$indexName/_search -d '{"query":{"query": "game"}}' 28 | 29 | 30 | -------------------------------------------------------------------------------- /searchServer/test/xyz.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "Feature game for meghshala" 3 | } 4 | -------------------------------------------------------------------------------- /searchsdk/config.js: -------------------------------------------------------------------------------- 1 | const SEARCH_SERVER = `http://0.0.0.0:9095`; 2 | const INIT_BASE_URL = `api/search/v2/edu/init`; 3 | const INDEX_BASE_URL = `api/search/v2/index`; 4 | const DOCUMENT_URL_EXT = `document`; 5 | 6 | module.exports = { 7 | SEARCH_SERVER, 8 | INIT_BASE_URL, 9 | INDEX_BASE_URL, 10 | DOCUMENT_URL_EXT 11 | } 12 | -------------------------------------------------------------------------------- /searchsdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "searchsdk", 3 | "version": "1.0.0", 4 | "description": "Search SDK", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "MIT", 11 | "dependencies": { 12 | "q": "^1.5.1", 13 | "request": "^2.88.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /telemetrysdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "telemetrysdk", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "aws-sdk": "^2.457.0", 13 | "child_process": "^1.0.2", 14 | "diskspace": "^2.0.0", 15 | "node-zip": "^1.1.1", 16 | "os-utils": "0.0.14", 17 | "q": "^1.5.1", 18 | "request": "^2.88.0", 19 | "util": "^0.10.3" 20 | } 21 | } 22 | --------------------------------------------------------------------------------