├── .gitignore
├── DBOperations
├── DBCommandLineTool.py
└── DBInsertion.py
├── DBScript
├── CMD2WEB.sqlite
└── DBSetup.sql
├── LICENSE
├── README.md
├── docs
├── cmd2web.js
├── simple.html
└── site.css
├── ex_configs
├── apache_conf.yaml
├── example_config.yaml
├── sample_grep_config.json
└── tabix_config.json
├── flaskapp.wsgi
├── requirements.txt
├── src
├── UploadFileTool.py
├── client.py
├── cmd2web.py
├── database_connection.py
├── server.py
├── settings.py
├── stix_client.py
└── tabix_client.py
├── test
├── data
│ ├── bad.json
│ ├── test_commas.txt
│ ├── test_config.json
│ └── test_tabs.txt
└── func
│ └── cmd2web_test.sh
└── web_client
├── cmd2web.js
├── simple.html
└── site.css
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 |
131 |
--------------------------------------------------------------------------------
/DBOperations/DBCommandLineTool.py:
--------------------------------------------------------------------------------
1 | import click
2 | from flask import Flask,request
3 | import os
4 | import random
5 | from DBInsertion import DBInsertion
6 | from datetime import datetime,timedelta
7 | current_directory= os.path.dirname(__file__)
8 | database_file_path = os.path.join(current_directory, "../DBScript/CMD2WEB.sqlite")
9 | database_object = DBInsertion(database_file_path)
10 | @click.group()
11 | # @click.option('-i', '--input', type=click.File('r'))
12 | def cli():
13 | """Command line interface for database interaction."""
14 | pass
15 |
16 |
17 | @cli.command()
18 | @click.option('--gname', help='The group name.')
19 | @click.option('--gtype', help='Type of the group.')
20 | @click.option('--restricted', help='If the group is restricted group. 1 if group is restricted ,0 if not restricted.')
21 | def createGroup(gname, gtype,restricted):
22 | """Description:Create a new group. \n
23 | Input parameters required: \n
24 | - gname - Group Name \n
25 | - gytpe - Group Type \n
26 | - restricted - Boolean indicating whether group is restricted \n
27 | Example Usage: python DBCommandLineTool.py creategroup --gname=DummyGroup --gtype=Test --restricted=1 """
28 | group_name = gname
29 | group_type = gtype
30 |
31 | if (group_name != None and restricted != None):
32 | # insert
33 | print(group_name, group_type, restricted)
34 | database_object.insert_group(group_name, group_type, restricted)
35 | print("Group {0} created".format(group_name))
36 |
37 | else:
38 | print(group_name, group_type, restricted)
39 | print("Parameter missing")
40 | # click.echo('Hello %s! - %s! - %d' % gname, gtype,restricted)
41 |
42 |
43 | @cli.command()
44 | @click.option('--gid', help='The group id.')
45 | @click.option('--token', help='Token for the user associated to a group.Format (mm-dd-yyyy).')
46 | @click.option('--expiry', help='Expiry date for the token.')
47 | @click.option('--email', help='Email id of the user.')
48 | def createKeyByGroupID(gid, token, expiry, email):
49 | """Description:Create new token by group id.\n
50 | Input parameters required: \n
51 | - gid - Group ID \n
52 | - token - Token for the user \n
53 | - expiry - Token expiry date \n
54 | - email - Email id of the user\n
55 | Example Usage: python DBCommandLineTool.py createkeybygroupid --gid=9 --token=122344434 --expiry=04-27-2019 --email=ro@colorado.edu"""
56 |
57 | group_id = gid
58 | token = token
59 | expiry = expiry
60 | user_email = email
61 | if(expiry==None):
62 | expiry = getNewDate()
63 |
64 | if(token==None):
65 | token = generateNewToken()
66 |
67 | if (group_id != None and token != None and expiry != None and user_email != None):
68 | database_object.insert_key(group_id, token, expiry, user_email)
69 | print("Token:{0} inserted for the user:{1} with expiry:{2}".format(token, user_email, expiry))
70 | else:
71 | print("Parameter missing")
72 | # click.echo('Hello %s! - %s! - %s! - %s!' % gid, token, expiry, email)
73 |
74 |
75 | # Generate new date
76 | def getNewDate():
77 | newdate = datetime.now() + timedelta(days=365)
78 | expiry = newdate.strftime('%m-%d-%Y')
79 | return expiry
80 |
81 | # Generate new random token
82 | def generateNewToken():
83 | new_token= random.randint(10000000,99999999)
84 | if(database_object.check_token_exists(new_token)):
85 | return generateNewToken()
86 | else:
87 | return new_token
88 |
89 | @cli.command()
90 | @click.option('--gname', help='The group name.')
91 | @click.option('--token', help='Token for the user associated to a group.')
92 | @click.option('--expiry', help='Expiry date for the token. Format (mm-dd-yyyy).')
93 | @click.option('--email', help='Email id of the user.')
94 | def createKeyByGroupName(gname, token, expiry, email):
95 | """Description:Create new token by group name. \n
96 | Input parameters required: \n
97 | - gname - Group Name \n
98 | - token - Token for the user \n
99 | - expiry - Token expiry date \n
100 | - email - Email id of the user\n
101 | Example Usage: python DBCommandLineTool.py createkeybygroupname --gname=DummyGroup --token=122344435 --expiry=05-27-2019 --email=rom@colorado.edu """
102 | group_name = gname
103 | token = token
104 | expiry = expiry
105 | user_email = email
106 | if(expiry==None):
107 | expiry = getNewDate()
108 |
109 | if(token==None):
110 | token = generateNewToken()
111 | group_id = None
112 | if (group_name != None):
113 | # get group id
114 | group_id = database_object.get_group_name_from_id(group_name)
115 | else:
116 | return "No group name"
117 | if (group_id != None and token != None and expiry != None and user_email != None):
118 | database_object.insert_key(group_id, token, expiry, user_email)
119 | print("Token:{0} inserted for the user:{1} with expiry:{2}".format(token, user_email, expiry))
120 | else:
121 | print("Parameter missing")
122 |
123 | @cli.command()
124 | @click.option('--gname', help='The group name.')
125 | def deleteGroup(gname):
126 | """Description:Delete group by name.\n
127 | Input parameters required: \n
128 | - gname - Group Name \n
129 | Example Usage: python DBCommandLineTool.py deletegroup --gname=DummyGroup"""
130 | group_name = gname
131 | if (group_name != None):
132 | database_object.delete_group(group_name)
133 | print("Deleted group {0}".format(group_name))
134 | else:
135 | print("Check group info")
136 | # click.echo('Hello %s! - %s! - %s! - %s!' % gname, token, expiry, email)
137 |
138 |
139 | @cli.command()
140 | @click.option('--gname', help='The group name.')
141 | def deleteKeyByGroup(gname):
142 | """Description:Delete key by group name.\n
143 | Input parameters required: \n
144 | - gname - Group Name \n
145 | Example Usage: python DBCommandLineTool.py deletekeybygroup --gname=DummyGroup"""
146 | group_name = gname
147 | if (group_name != None):
148 | database_object.delete_group_keys(group_name)
149 | print("Deleted keys for group {0}".format(group_name))
150 | else:
151 | print("Check group info")
152 | # click.echo('Hello %s! - %s! - %s! - %s!' % gname, token, expiry, email)
153 |
154 | @cli.command()
155 | @click.option('--email', help='The user email.')
156 | def deleteKeyByUser(email):
157 | """Description:Delete key by group user.\n
158 | Input parameters required: \n
159 | - email - email id of the user \n
160 | Example Usage: python DBCommandLineTool.py deletekeybyuser --email=rom@colorado.edu"""
161 | user_email = email
162 | if (user_email != None):
163 | database_object.delete_user_keys(user_email)
164 | print("Deleted keys for user {0}".format(user_email))
165 | else:
166 | print("Check group info")
167 | # click.echo('Hello %s! - %s! - %s! - %s!' % gname, token, expiry, email)
168 |
169 | @cli.command()
170 | @click.option('--email', help='The user email.')
171 | def getKeyByUser(email):
172 | """Description:Get Keys by User.\n
173 | Input parameters required: \n
174 | - email - email id of the user \n
175 | Example Usage: python DBCommandLineTool.py getkeybyuser --email=rom2@colorado.edu"""
176 | user_email = email
177 | if (user_email != None):
178 | result = database_object.get_user_keys(user_email)
179 | print(result)
180 | else:
181 | print("Check group info")
182 |
183 | @cli.command()
184 | @click.option('--gname', help='The Group name.')
185 | def getKeyByGroupName(gname):
186 | """Description:Get keys by Group.\n
187 | Input parameters required: \n
188 | - gname - Group name \n
189 | Example Usage: python DBCommandLineTool.py getkeybygroupname --gname=DummyGroup"""
190 | group_name = gname
191 | if (group_name != None):
192 | result = database_object.get_user_keys_by_group_name(group_name)
193 | print(result)
194 | else:
195 | print("Check group info")
196 |
197 | @cli.command()
198 | def getGroupList():
199 | """Description:Get all the groups.\n
200 | Input parameters required: \n
201 | None \n
202 | Example Usage: python DBCommandLineTool.py getgrouplist """
203 | result = database_object.get_group_list()
204 | print(result)
205 |
206 | @cli.command()
207 | def getKeyList():
208 | """Description:Get all the keys.\n
209 | Input parameters required: \n
210 | None \n
211 | Example Usage: python DBCommandLineTool.py getkeylist """
212 | result = database_object.get_key_list()
213 | print(result)
214 |
215 |
216 | if __name__ == '__main__':
217 | cli()
--------------------------------------------------------------------------------
/DBOperations/DBInsertion.py:
--------------------------------------------------------------------------------
1 | import sqlite3
2 | import pandas as pd
3 | from sqlite3 import Error
4 | class DBInsertion:
5 | def __init__(self,db_file):
6 | try:
7 | self.conn = sqlite3.connect(db_file,check_same_thread=False)
8 | # return self.conn
9 | except Error as e:
10 | print(e)
11 |
12 | # Close connection when deconstructor is called.
13 | def __del__(self):
14 | self.conn.close()
15 |
16 | #Insert new group
17 | def insert_group(self,group_name,group_type,restricted):
18 | cur = self.conn.cursor()
19 | cur.execute("Insert into Groups(GroupName,GroupType,RestrictedGroup) values('{0}','{1}',{2})".format(group_name,group_type,restricted))
20 | self.conn.commit()
21 |
22 | def get_group_name_from_id(self,gid):
23 | cur = self.conn.cursor()
24 | cur.execute("select GroupID from Groups where GroupName='{0}'".format(gid))
25 | rows = cur.fetchall()
26 | if(len(rows) > 0):
27 | return rows[0][0]
28 | else:
29 | # //Error Record does not exist for the gid
30 | return "Group ID does not exist";
31 |
32 | #Insert new key in the Keys table for a particular user with expiry date
33 | def insert_key(self,group_id,token,expiry,user_email):
34 | cur = self.conn.cursor()
35 | cur.execute("Insert into Keys(GroupID,Token,Expiry,UserEmail) values({0},'{1}','{2}','{3}')".format(group_id,token,expiry,user_email))
36 | self.conn.commit()
37 |
38 | #Delete the group. Should keys be deleted for that group?
39 | def delete_group(self,group_name):
40 | cur = self.conn.cursor()
41 | cur.execute("Delete from Groups where GroupName='{0}'".format(group_name))
42 | self.conn.commit()
43 |
44 | #Delete the keys belonging to a particular group
45 | def delete_group_keys(self,group_name):
46 | cur = self.conn.cursor()
47 | cur.execute("Delete from Keys where GroupID in (select GroupID from Groups where GroupName='{0}')".format(group_name))
48 | self.conn.commit()
49 |
50 | #Delete the keys for a particular user
51 | def delete_user_keys(self,user_email):
52 | cur = self.conn.cursor()
53 | cur.execute("Delete from Keys where UserEmail ='{0}'".format(user_email))
54 | self.conn.commit()
55 |
56 | # Get all keys for a user based on user id
57 | def get_user_keys(self, user_email):
58 | query="Select * from Keys where UserEmail ='{0}'".format(user_email)
59 | data = pd.read_sql_query(query, self.conn)
60 | return data
61 | # self.conn.commit()
62 |
63 | # Get all keys for a user based on group name
64 | def get_user_keys_by_group_name(self,group_name):
65 | query = "Select * from Keys where GroupID in (select GroupID from Groups where GroupName='{0}')".format(group_name)
66 | data = pd.read_sql_query(query, self.conn)
67 | return data
68 |
69 | # Get groups list
70 | def get_group_list(self):
71 | query = "Select * from Groups"
72 | data = pd.read_sql_query(query, self.conn)
73 | return data
74 |
75 | # Get keys list
76 | def get_key_list(self):
77 | query = "Select * from Keys"
78 | data = pd.read_sql_query(query, self.conn)
79 | return data
80 |
81 | # Check token
82 | def check_token_exists(self,token):
83 | cur = self.conn.cursor()
84 | query='select Token from Keys where Token={0}'.format(token)
85 | cur.execute(query)
86 | rows = cur.fetchall()
87 | if len(rows) > 0:
88 | return True
89 | else:
90 | return False
--------------------------------------------------------------------------------
/DBScript/CMD2WEB.sqlite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ryanlayer/cmd2web/d8cc66d24909a73deda105377dceacad1d6568c2/DBScript/CMD2WEB.sqlite
--------------------------------------------------------------------------------
/DBScript/DBSetup.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE IF NOT EXISTS Groups (
2 | GroupID integer PRIMARY KEY,
3 | GroupName text,
4 | GroupType text,
5 | RestrictedGroup integer
6 | );
7 | CREATE TABLE IF NOT EXISTS Keys (
8 | GroupID integer,
9 | Token text,
10 | Expiry text,
11 | UserEmail text,
12 | FOREIGN KEY (GroupID) REFERENCES Groups (GroupID)
13 | );
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Ryan Layer
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 | `cmd2web` is a simple framework for enabling a web interface to command
2 | line programs. From this interface, data and methods can be easily accessed
3 | through either a dynamic website or a programmatic interface. This package
4 | includes a server and client javascript and python interfaces.
5 |
6 | # Server
7 |
8 | To stand up a server, you define a mapping between command line parameters and
9 | URL query parameters in a JSON config file. Each command line instance is
10 | referred to as a service, and a server can host multiple services.
11 |
12 | In this example, we will consider a server with just one service to the `tabix`
13 | program (https://github.com/samtools/htslib) and the Repeat Masker track from
14 | UCSC genome browser (based on
15 | http://hgdownload.soe.ucsc.edu/goldenPath/hg19/database/rmsk.txt.gz )
16 |
17 | ## Install Tools
18 | Installation Steps:
19 | Tabix and bgzip
20 | ```
21 | Download latest tabix jar from the link:https://sourceforge.net/projects/samtools/files/tabix/
22 | tar -xjf tabix-0.2.6.tar.bz2
23 | cd tabix-0.2.6/
24 | make
25 | Make install
26 | ```
27 | Bedtools:
28 | Run the following lines in the terminal to install bedtools:
29 | ```
30 | Ubuntu
31 | apt-get install bedtools
32 | ```
33 | ```
34 | Mac
35 | brew tap homebrew/science
36 | brew install bedtools
37 | ```
38 |
39 |
40 | After downloading just extract the .gz file and use head command to see content of the file:
41 |
42 | Extract the bgzip file:
43 | ```
44 | bgzip -d rmsk.txt.gz
45 | Head rmsk.txt
46 | mv rmsk.txt rmsk.bed
47 | ```
48 | For tabix to work start position and end position should be sorted:
49 | Here column 6 is the chromosome and column 7,8 is the starting and the ending position
50 | ```
51 | sort -k6,6 -k7,7n -k8,8n rmsk.bed >> sortedrmsk.bed
52 | ```
53 | Once the file is created, use bgzip to compress the .bed file:
54 | ```
55 | Bgzip sortedrmsk.bed
56 | ```
57 | It will create sortedrmsk.bed.gz file which can be used with the tabix.
58 | To create index file(.tbi) using tabix use the following command:
59 | ```
60 | tabix -p bed sortedrmsk.bed.gz -s6 -b7 -e8
61 | ````
62 | Parameters in the command:
63 | ```
64 | -p bed - Tells about the type of input file
65 | Sortedrmsk.bed.gz - Input file
66 | -s6 - Tells about the column of the sequence (In this case 6th column)
67 | -b7 - Tells about the column having starting position of sequence ( In this case 7th column)
68 | -e8 - Tells about the column having ending position of sequence ( In this case 8th column)
69 | ```
70 | To test from terminal, use the following command:
71 | ```
72 | tabix sortedextrarmsk.bed.gz -s6 -b7 -e8 chr1:10000-20000
73 | ```
74 | Currently the application assumes that the columns in data file starts with the sequence. To convert the downloaded file to that, run the following commands:
75 | ```
76 | Extract the bgzip file:
77 | bgzip -d rmsk.txt.gz
78 | ```
79 | Put columns in new file
80 | ```
81 | cut -f6,7,8,9,10,11,12,13,14,15,16,17 rmsk.txt >> rmsk.bed
82 | ```
83 | Sort the file
84 | ```
85 | Sort -k1,1 -k2,2n -k3,3n rmsk.bed >> sortedrmsk.bed
86 | ```
87 | Alternatively bedtools can be installed to sort the file:
88 |
89 | Run the following lines in the terminal to install bedtools:
90 | ```
91 | Ubuntu
92 | apt-get install bedtools
93 | ```
94 | ```
95 | Mac
96 | brew tap homebrew/science
97 | brew install bedtools
98 | ```
99 | Once it is installed, use the following command to sort the input file
100 | ```
101 | sortBed -i rmsk.bed
102 | ```
103 | Use bgzip to compress the file:
104 | ```
105 | Bgzip -c rmsk.bed >> rmsk.bed.gz
106 | ```
107 | Use tabix to generate .tbi file
108 | ```
109 | Tabix -p bed rmsk.bed.gz
110 | ```
111 | Use tabix to filter by chromosome:
112 | ```
113 | Tabix rmsk.bed.gz chr1:10000-20000
114 | ```
115 | From the `tabix` manual:
116 | ```
117 | Tabix indexes a TAB-delimited genome position file in.tab.bgz and creates an
118 | index file ( in.tab.bgz.tbi or in.tab.bgz.csi ) when region is absent from the
119 | command-line. The input data file must be position sorted and compressed by
120 | bgzip which has a gzip(1) like interface.
121 |
122 | After indexing, tabix is able to quickly retrieve data lines overlapping
123 | regions specified in the format "chr:beginPos-endPos". (Coordinates specified
124 | in this region format are 1-based and inclusive.)
125 | ```
126 |
127 | To use `tabix` on the command line, you pass the file name and the region of
128 | interest and all intervals in the file that overlap that region are returned.
129 | ```
130 | $ tabix rmsk.bed.gz chr1:10000-20000
131 | chr1 10000 10468 (CCCTAA)n Simple_repeat Simple_repeat
132 | chr1 10468 11447 TAR1 Satellite telo
133 | chr1 11503 11675 L1MC LINE L1
134 | chr1 11677 11780 MER5B DNA hAT-Charlie
135 | chr1 15264 15355 MIR3 SINE MIR
136 | chr1 16712 16749 (TGG)n Simple_repeat Simple_repeat
137 | chr1 18906 19048 L2a LINE L2
138 | chr1 19947 20405 L3 LINE CR1
139 | ```
140 |
141 | The URL for this service looks very similar to the command line invocation:
142 | ```
143 | $ curl "http://127.0.0.1:8080/?service=rmsk&chromosome=chr1&start=10000&end=20000"
144 | { "success": 1,
145 | "result": [
146 | [ "chr1", "10000", "10468", "(CCCTAA)n", "Simple_repeat", "Simple_repeat" ],
147 | [ "chr1", "10468", "11447", "TAR1", "Satellite", "telo" ],
148 | [ "chr1", "11503", "11675", "L1MC", "LINE", "L1" ],
149 | [ "chr1", "11677", "11780", "MER5B", "DNA", "hAT-Charlie" ],
150 | [ "chr1", "15264", "15355", "MIR3", "SINE", "MIR" ],
151 | [ "chr1", "16712", "16749", "(TGG)n", "Simple_repeat", "Simple_repeat" ],
152 | [ "chr1", "18906", "19048", "L2a", "LINE", "L2" ],
153 | [ "chr1", "19947", "20405", "L3", "LINE", "CR1" ]
154 | ]
155 | }
156 | ```
157 |
158 | ## Server config
159 | Config file has been updated from json to yaml file.
160 | A skeleton of the config is:
161 | ```
162 | -
163 | name :
164 | arguments :
165 | -
166 | name :
167 | fixed :
168 | type :
169 | value :
170 | command :
171 | -
172 | output :
173 | type :
174 | sep :
175 | ```
176 |
177 |
178 | Each element in the config is described below.
179 |
180 | ### name
181 | Since a server can host many services, the first step is to define the service
182 | name. Requests will use the `service` URL query attribute to the name of the
183 | service. The server will return an exception for any requests that do not have
184 | service specified:
185 | ```
186 | $ curl "http://127.0.0.1:8080/?chromosome=chr1&start=10000&end=20000"
187 | {"exception": "No service specified", "success": 0}
188 | ```
189 |
190 | Here the name is `rmsk`:
191 | ```
192 | "name" : "rmsk"
193 | ```
194 |
195 | ### arguments
196 |
197 | This command has five arguments:
198 | 1. path to the executable (`tabix`)
199 | 2. file of interest (`rmsk.bed.gz`)
200 | 3. chromosome (`chr1`)
201 | 4. start (`10000`)
202 | 5. end (`20000`)
203 |
204 | Each of these attributes is specified in a `arguments` array. Attributes can
205 | be fixed (`"fixed" : "true"`) or variable ("fixed" : "false)". The value of
206 | the variable attributes will be defined in a users' query, and the fixed
207 | attributes are defined by the `value` field. Each attribute has a type that is
208 | checked by the server before executing any commands. Currently `string`,
209 | `integer`, and `float` are supported.
210 |
211 | The arguments array for this service in raw yaml is:
212 |
213 | ```
214 | arguments :
215 | -
216 | name : file
217 | fixed : 'true'
218 | type : string
219 | value : /data/rmsk.bed.gz
220 | -
221 | name : chromosome
222 | fixed : 'false'
223 | type : string
224 | -
225 | name : start
226 | fixed : 'false'
227 | type : integer
228 | -
229 | name : end
230 | fixed : 'false'
231 | type : integer
232 | ```
233 |
234 |
235 | When a user requests this service, the server fills a variable table with both
236 | fixed and variable attributes. The server will return an exception for requests
237 | that do not provide precisely the set of variable arguments.
238 | ```
239 | $ curl "http://127.0.0.1:8080/?service=rmsk&chromosome=chr1&start=10000"
240 | {"exception": "Argument mismatch", "success": 0}
241 | ```
242 | The server will also return an exception for requests with type mismatches.
243 | ```
244 | $ curl "http://127.0.0.1:8080/?service=rmsk&chromosome=chr1&start=10000&end=not_int"
245 | {"exception": "Type mismatch for argument end. Expected integer", "success": 0}
246 | ```
247 |
248 | ### command
249 | After the variable table is filled, the server will construct the command by
250 | replaced variables names with value in the variable table by the same name.
251 | Note that variables in the command start with '$', but the names of the
252 | attributes do not. To improve security, it is highly recommended to split the
253 | command into individual strings.
254 | ```
255 | "command":
256 | [
257 | "/usr/bin/tabix",
258 | "$file",
259 | "$chromosome:$start-$end"
260 | ],
261 | ```
262 |
263 | The constructed command is then executed locally on the server. While it is
264 | beyond the scope of this example, we highly recommend running commands through
265 | a virtual machine such as docker.
266 |
267 | The server will return an exception for any command that does not return with a
268 | zero exit code. Commands also have a maximum runtime that is specified by the
269 | `--timeout` option when starting the server. The server will return an
270 | exception if a command exceeds this limit.
271 |
272 | ### output
273 |
274 | The last step is to define the output type. Current `text_stream` and `file`
275 | are supported.
276 | ```
277 | "output" :
278 | {
279 | "type" : "text_stream",
280 | "sep" : "\t"
281 | }
282 | ```
283 |
284 | For `text_stream` output, the server returns a JSON array or arrays. Output is split
285 | by line then by the value given in the `sep` field.
286 |
287 | ## staring the server
288 |
289 | ```
290 | python server.py --config tabix_config.yaml
291 | ```
292 |
293 | ```
294 | usage: server.py [-h] --config CONFIG [--port PORT] [--host HOST]
295 | [--timeout TIMEOUT]
296 |
297 | command to web server.
298 |
299 | optional arguments:
300 | -h, --help show this help message and exit
301 | --config CONFIG Configuration file.
302 | --port PORT Port to run on (default 8080)
303 | --host HOST Server hos (default 127.0.0.1)
304 | --timeout TIMEOUT Max runtime (sec) for a command (default 10)
305 | ```
306 |
307 | In addition to serving requests, the server also advertises the services it
308 | supports along with input and output requirements. This information allows for
309 | the development of more general clients interfaces and can be accessed at the
310 | `\info` endpoint.
311 |
312 | ```
313 | $ curl "http://127.0.0.1:8080/info"
314 | {
315 | "rmsk": {
316 | "name": "rmsk",
317 | "output": { "type": "text_stream" },
318 | "inputs": [
319 | { "name": "chromosome", "type": "string" },
320 | { "name": "start", "type": "integer" },
321 | { "name": "end", "type": "integer" }
322 | ]
323 | }
324 | }
325 | ```
326 |
327 | # Client
328 |
329 | Any method that can make web request can be a client. For example, `curl` works
330 | great.
331 | ```
332 | $ curl "http://127.0.0.1:8080/?service=rmsk&chromosome=chr1&start=10000&end=20000"
333 | { "success": 1,
334 | "result": [
335 | [ "chr1", "10000", "10468", "(CCCTAA)n", "Simple_repeat", "Simple_repeat" ],
336 | [ "chr1", "10468", "11447", "TAR1", "Satellite", "telo" ],
337 | [ "chr1", "11503", "11675", "L1MC", "LINE", "L1" ],
338 | [ "chr1", "11677", "11780", "MER5B", "DNA", "hAT-Charlie" ],
339 | [ "chr1", "15264", "15355", "MIR3", "SINE", "MIR" ],
340 | [ "chr1", "16712", "16749", "(TGG)n", "Simple_repeat", "Simple_repeat" ],
341 | [ "chr1", "18906", "19048", "L2a", "LINE", "L2" ],
342 | [ "chr1", "19947", "20405", "L3", "LINE", "CR1" ]
343 | ]
344 | }
345 | ```
346 |
347 | This package also provides a python API that is tightly coupled with the
348 | server. For example, exceptions returned by the server are then raised as an
349 | exception by the API. The client will also perform local type checking on all
350 | service requests before submitting them to the server.
351 |
352 | The client has two steps
353 | 1. connecting to the server with `cmd2web.Client.connect(host, port)`
354 | 2. running a query with `run(service_name, **kwargs)` where the `kwargs` map to
355 | the services variable arguments
356 |
357 | To use the service defined above:
358 | ```
359 | import cmd2web
360 | s = cmd2web.Client.connect('127.0.0.1','8080')
361 | R = R = s.run('rmsk', chromosome="chr1", start=10000, end=20000)
362 | for r in R:
363 | print('\t'.join(r))
364 | ```
365 |
366 | # Installation
367 |
368 | The easiest way to install `cmd2web` is with `virtualenv`:
369 | ```
370 | virtualenv -p /usr/local/bin/python3.6 cmd2web_env
371 | source cmd2web_env/bin/activate
372 | pip install flask requests numpy Cython cyvcf2 pyyaml pyopenssl flask-cors mod_wsgi werkzeug pandas
373 | ```
374 |
375 | ### Apache Setup
376 |
377 | To Install Apache:-
378 | ```
379 | sudo apt-get update
380 | sudo apt-get install apache2
381 | ```
382 |
383 | To Add new site we need to add new configuration for our website in /etc/apache/sites-available:
384 |
385 | sudo nano /etc/apache/sites-available/myweb.conf
386 | ```
387 |
388 | # Add machine's IP address (use ifconfig command)
389 | ServerName localhost
390 | # Give an alias to to start your website url with
391 | # Using cmd2web, it means in URL you have to write localhost to access the application. The path after that is path to your wsgi file. Change it accordingly.
392 | WSGIScriptAlias / somepath/flaskapp.wsgi
393 | # Mention the directory which should be accessible by your application. This will be directory which has all the files.
394 |
395 | # set permissions as per apache2.conf file
396 | Options FollowSymLinks
397 | AllowOverride None
398 | Require all granted
399 |
400 | ErrorLog ${APACHE_LOG_DIR}/error.log
401 | LogLevel warn
402 | CustomLog ${APACHE_LOG_DIR}/access.log combined
403 |
404 |
405 | ```
406 |
407 | create your flaskapp.wsgi file at your preferred location:
408 | ```
409 | nano flaskapp.wsgi
410 | ```
411 | ```
412 | #!/usr/bin/python
413 | import sys,os
414 | import logging
415 | #Path to your virtualenv
416 | activate_this = 'PATH_TO_VIRTUAL_ENV/activate_this.py'
417 | with open(activate_this) as file_:
418 | exec(file_.read(), dict(__file__=activate_this))
419 | logging.basicConfig(stream=sys.stderr)
420 | #Location where your server.py file is present.
421 | sys.path.insert(0,"PATH_TO_SRC_DIRECTORY")
422 |
423 | from server import app as application
424 | ```
425 |
426 | Enable site:
427 | ```
428 | sudo a2ensite flaskapp
429 | ```
430 | Add the site to https:
431 |
432 | For encrypting a web connection we need certificate from CA (certificate authority) or we can use self signed certificates. Let's create a self signed certificate using the following command.
433 |
434 | ```
435 | openssl req -x509 -newkey rsa:2048 -keyout mykey.key -out mycert.pem -days 365 -nodes
436 | sudo cp mycert.pem /etc/ssl/certs
437 | sudo cp mykey.key /etc/ssl/private
438 | ```
439 | Enable ssl on the server:
440 | ```
441 | sudo a2enmod ssl
442 | ```
443 |
444 | Once we create key, we have to add our site and the key to the /etc/apache2/sites-available/default-ssl.conf
445 |
446 | ```
447 | sudo nano /etc/apache2/sites-available/default-ssl.conf
448 | ```
449 |
450 | Add directory access and path to your website :
451 | ```
452 | # Give an alias to to start your website url with
453 | # Using cmd2web, it means in URL you have to write localhost to access the application. The path after that is path to your wsgi file. Change it accordingly.
454 | WSGIScriptAlias / PATH_TO_WSGI/flaskapp.wsgi
455 | # Mention the directory which should be accessible by your application. This will be directory which has all the files.
456 |
457 | # set permissions as per apache2.conf file
458 | Options FollowSymLinks
459 | AllowOverride None
460 | Require all granted
461 |
462 | ```
463 |
464 | Locate SSLCertificateFile & SSLCertificateKeyFile and replace the path with the key and certificate file:
465 | ```
466 | SSLCertificateFile /etc/ssl/certs/cmd2web.pem
467 | SSLCertificateKeyFile /etc/ssl/private/cmd2web.key
468 | ```
469 |
470 | Enable the SSL site:
471 | ```
472 | sudo a2ensite default-ssl.conf
473 | ```
474 |
475 | Restart the apache server:
476 | ```
477 | sudo service apache2 restart
478 | ```
479 |
480 | To access site:
481 | ```
482 | HTTP:
483 | http://localhost/?service=rmsk&chromosome=chr1&start=10000
484 |
485 | HTTPS:
486 | https://localhost/?service=rmsk&chromosome=chr1&start=10000
487 |
488 | Server address:
489 | http://localhost/
490 | ```
491 |
492 | # Setting Server:
493 | Currently if there is apache_conf.yaml file, then apache server will be the default server. If on some system that file is not present, then a normal python server can be used.
494 |
495 | # DB Setup
496 |
497 | Tables
498 | ```
499 | 1. Groups - It has a list of all the groups with the following fields:
500 | Name Type Primary Key Description
501 | - GroupID Integer Yes Group ID of the group
502 | - GroupName Text No Group Name of the group
503 | - GroupType Text No Type of the group
504 | - RestrictedGroup Integer No Boolean indicating if group is restricted (1 means restricted)
505 |
506 | 2. Keys - It has a list of all the keys belonging to a particular user associated to a group.
507 | Name Type Foreign Key Description
508 | - GroupID Integer Yes Group ID of the group
509 | - Token Text No Token for the user
510 | - Expiry Text No Expiry date of token. Format mm-dd-yyyy
511 | - UserEmail Text No Email ID of the user
512 | ```
513 |
514 | Every Service has a group associated to it. It can either have a value or can be blank. A group if mentioned is a restricted group. If a user calls a service which is restricted, the user needs to pass a token associated with that group provided by the admin. The results are displayed on passing the correct token otherwise an error is displayed.
515 |
516 | # Command Line Database application for the Admin
517 |
518 | The admin has following methods available (DBCommandLineTool.py):
519 |
520 | To get a list of all the commands available:
521 | ```
522 | Go to the directory having file DBCommandLineTool.py
523 | Run the following command:
524 | python DBCommandLineTool.py --help
525 |
526 | Output-
527 | Usage: DBCommandLineTool.py [OPTIONS] COMMAND [ARGS]...
528 |
529 | Command line interface for database interaction.
530 |
531 | Options:
532 | --help Show this message and exit.
533 |
534 | Commands:
535 | creategroup Create new group.
536 | createkeybygroupid Create new token by group id.
537 | createkeybygroupname Create new token by group name.
538 | deletegroup Delete group by name.
539 | deletekeybygroup Delete key by group name.
540 | deletekeybyuser Delete key by group user.
541 | getkeybygroupname Get keys by Group.
542 | getkeybyuser Get Keys by User.
543 |
544 | ```
545 |
546 | Click and pandas python library is used to create the command line application and to display the results.
547 | All the commands require a user to pass the input parameters. A user can use the help command to find all input parameters required:
548 | ```
549 | 1. CreateGroup Command
550 |
551 | Input- python DBCommandLineTool.py creategroup --help
552 |
553 | Output-
554 | Usage: DBCommandLineTool.py creategroup [OPTIONS]
555 | For eg: python DBCommandLineTool.py creategroup --gname=DummyGroup --gtype=Test --restricted=1
556 |
557 | Description:Create a new group.
558 |
559 | Input parameters required:
560 |
561 | - gname - Group Name
562 |
563 | - gytpe - Group Type
564 |
565 | - restricted - Boolean indicating whether group is restricted
566 |
567 | Options:
568 | --gname TEXT The group name.
569 | --gtype TEXT Type of the group.
570 | --restricted TEXT If the group is restricted group. 1 if group is
571 | restricted ,0 if not restricted.
572 | --help Show this message and exit.
573 |
574 |
575 |
576 | 2. CreateKeyByGroupID Command
577 |
578 | Input- python DBCommandLineTool.py createkeybygroupid --help
579 |
580 | Output-
581 | Usage: DBCommandLineTool.py createkeybygroupid [OPTIONS]
582 | For eg: python DBCommandLineTool.py createkeybygroupid --gid=9 --token=122344434 --expiry=04-27-2019 --email=ro@colorado.edu
583 |
584 | Description:Create new token by group id.
585 |
586 | Input parameters required:
587 |
588 | - gid - Group ID
589 |
590 | - token - Token for the user
591 |
592 | - expiry - Token expiry date
593 |
594 | - email - Email id of the user
595 |
596 | Options:
597 | --gid TEXT The group id.
598 | --token TEXT Token for the user associated to a group.Format (mm-dd-yyyy).
599 | --expiry TEXT Expiry date for the token.
600 | --email TEXT Email id of the user.
601 | --help Show this message and exit.
602 |
603 | Note: The expiry and token command is optional. If not passed random token will be generated and a new date with expiry after a year will be generated.
604 |
605 | 3. CreateKeyByGroupName Command
606 |
607 | Input-python DBCommandLineTool.py createkeybygroupname --help
608 |
609 | Output-
610 | Usage: DBCommandLineTool.py createkeybygroupname [OPTIONS]
611 | Foe eg: python DBCommandLineTool.py createkeybygroupname --gname=DummyGroup --token=122344435 --expiry=05-27-2019 --email=rom@colorado.edu
612 |
613 | Description:Create new token by group name.
614 |
615 | Input parameters required:
616 |
617 | - gname - Group Name
618 |
619 | - token - Token for the user
620 |
621 | - expiry - Token expiry date
622 |
623 | - email - Email id of the user
624 |
625 | Options:
626 | --gname TEXT The group name.
627 | --token TEXT Token for the user associated to a group.
628 | --expiry TEXT Expiry date for the token. Format (mm-dd-yyyy).
629 | --email TEXT Email id of the user.
630 | --help Show this message and exit.
631 |
632 | Note: The expiry and token command is optional. If not passed random token will be generated and a new date with expiry after a year will be generated.
633 |
634 | 4. DeleteGroup Command
635 |
636 | Input-python DBCommandLineTool.py deletegroup --help
637 |
638 | Output-
639 | Usage: DBCommandLineTool.py deletegroup [OPTIONS]
640 | For eg: python DBCommandLineTool.py deletegroup --gname=DummyGroup
641 |
642 | Description:Delete group by name.
643 |
644 | Input parameters required:
645 |
646 | - gname - Group Name
647 |
648 | Options:
649 | --gname TEXT The group name.
650 | --help Show this message and exit.
651 |
652 |
653 | 5. DeleteKeyByGroup Command
654 |
655 | Input- python DBCommandLineTool.py deletekeybygroup --help
656 |
657 | Output-
658 | Usage: DBCommandLineTool.py deletekeybygroup [OPTIONS]
659 | For eg:python DBCommandLineTool.py deletekeybygroup --gname=DummyGroup
660 |
661 | Description:Delete key by group name.
662 |
663 | Input parameters required:
664 |
665 | - gname - Group Name
666 |
667 | Options:
668 | --gname TEXT The group name.
669 | --help Show this message and exit.
670 |
671 |
672 | 6. DeleteKeyByUser Command
673 |
674 | Input-python DBCommandLineTool.py deletekeybyuser --help
675 |
676 | Output-
677 | Usage: DBCommandLineTool.py deletekeybyuser [OPTIONS]
678 | For eg: python DBCommandLineTool.py deletekeybyuser --email=rom@colorado.edu
679 |
680 | Description:Delete key by group user.
681 |
682 | Input parameters required:
683 |
684 | - email - email id of the user
685 |
686 | Options:
687 | --email TEXT The user email.
688 | --help Show this message and exit.
689 |
690 |
691 | 7. GetKeyByGroupName Command
692 |
693 | Input- python DBCommandLineTool.py getkeybygroupname --help
694 |
695 | Output-
696 | Usage: DBCommandLineTool.py getkeybygroupname [OPTIONS]
697 | For eg: python DBCommandLineTool.py getkeybygroupname --gname=DummyGroup
698 |
699 | Description:Get keys by Group.
700 |
701 | Input parameters required:
702 |
703 | - gname - Group name
704 |
705 | Options:
706 | --gname TEXT The Group name.
707 | --help Show this message and exit.
708 |
709 | 8. GetKeyByUser Command
710 |
711 | Input-python DBCommandLineTool.py getkeybyuser --help
712 |
713 | Output-
714 | Usage: DBCommandLineTool.py getkeybyuser [OPTIONS]
715 | For eg:python DBCommandLineTool.py getkeybyuser --email=rom2@colorado.edu
716 |
717 | Description:Get Keys by User.
718 |
719 | Input parameters required:
720 |
721 | - email - email id of the user
722 |
723 | Options:
724 | --email TEXT The user email.
725 | --help Show this message and exit.
726 |
727 | 9. GetGroupList Command
728 |
729 | Input- python DBCommandLineTool.py getgrouplist --help
730 |
731 | Output-
732 | Usage: DBCommandLineTool.py getgrouplist [OPTIONS]
733 | For eg:python DBCommandLineTool.py getgrouplist
734 |
735 | Description:Get all the groups.
736 |
737 | Input parameters required:
738 |
739 | None
740 |
741 | Options:
742 | --help Show this message and exit.
743 |
744 | 10. GetKeyList Command
745 |
746 | Input- python DBCommandLineTool.py getgrouplist --help
747 |
748 | Output-
749 | Usage: DBCommandLineTool.py getkeylist [OPTIONS]
750 | For eg:python DBCommandLineTool.py getkeylist
751 |
752 | Description:Get all the keys.
753 |
754 | Input parameters required:
755 |
756 | None
757 |
758 |
759 | Options:
760 | --help Show this message and exit.
761 |
762 |
763 |
764 | ```
765 | # File Upload Service
766 | We need to add the service to the config file. There is a separate endpoint created for the fileupload with "/f" endpoint.
767 | File fixed attribute is set to false for this service.
768 | For eg:
769 |
770 | ```
771 | name : simpleFileGrep
772 | arguments :
773 | -
774 | name : file
775 | fixed : 'false'
776 | type : string
777 | -
778 | name : pattern
779 | fixed : 'false'
780 | type : string
781 | command :
782 | - /bin/grep
783 | - $pattern
784 | - $file
785 | output :
786 | type : text_stream
787 | sep : \t
788 | ```
789 |
790 | The file will be uploaded to the tmp folder and will be deleted once processing is complete.
791 | I have implemented it in 3 ways:
792 |
793 | ## 1. Curl Command
794 |
795 | For eg: If a user wants to call simpleFileGrep service and wants to upload test1.txt file.
796 |
797 | Apache
798 | curl -X POST -F file=@"test1.txt" "http://localhost/f?service=simpleFileGrep&pattern=zip"
799 |
800 | Python
801 | curl -X POST -F file=@"test1.txt" "http://127.0.0.1:8080/f?service=simpleFileGrep&pattern=zip"
802 |
803 | -----------------------------------------------------------------------------
804 | ## 2. File Upload Command Line Application
805 |
806 | The admin has following methods available (DBCommandLineTool.py):
807 |
808 | To get a list of all the commands available:
809 | ```
810 | Go to the directory having file UploadFileTool.py
811 | Run the following command:
812 | python UploadFileTool.py --help
813 |
814 | Usage: UploadFileTool.py [OPTIONS] COMMAND [ARGS]...
815 |
816 | Command line interface for database interaction.
817 |
818 | Options:
819 | --help Show this message and exit.
820 |
821 | Commands:
822 | uploadruncommand Description: Pass your own input file to a service.
823 |
824 | ```
825 |
826 | A user can use the help command to find all input parameters required:
827 | ```
828 | 1. uploadruncommand Command
829 |
830 | Input- python UploadFileTool.py uploadruncommand --help
831 |
832 | Output-
833 | Usage: UploadFileTool.py uploadruncommand [OPTIONS]
834 |
835 | Description: Pass your own input file to a service.
836 |
837 | Input parameters required:
838 |
839 | - url - URL with the parameters
840 |
841 | - filepath - Path of the input file
842 |
843 | Example Usage: python UploadFileTool.py uploadRunCommand
844 | --url='http://127.0.0.1:8080/f?service=simpleFileGrep&pattern=zip'
845 | --filepath=/home/rohit/test3.txt
846 |
847 | Options:
848 | --url TEXT The url with parameters
849 | --filepath TEXT Path of the input file.
850 | --help Show this message and exit.
851 | ```
852 |
853 | -----------------------------------------------------------------------------
854 | ## 3. Web Version
855 |
856 | Apache
857 | https://localhost/webapp
858 |
859 | Python
860 | http://localhost:8080/webapp
861 |
862 | If the file fixed is set to false for the service selected, then the file upload box will appear and user can upload any file from the system.
863 |
864 |
865 |
866 |
--------------------------------------------------------------------------------
/docs/cmd2web.js:
--------------------------------------------------------------------------------
1 | var server_url = '';
2 | var server_info = null;
3 | var server_result = null;
4 | var selectedService = null;
5 |
6 | $.urlParam = function(name){
7 | var results = new RegExp('[\?&]' +
8 | name +
9 | '=([^]*)').exec(window.location.href);
10 | if (results==null){
11 | return null;
12 | } else {
13 | return results[1] || 0;
14 | }
15 | }
16 |
17 | $(document).ready(function() {
18 | server_param = $.urlParam('server');
19 |
20 | if (server_param){
21 | server_url = decodeURIComponent(server_param);
22 | $('#server_text').val(server_url);
23 | connect_to_server();
24 | }
25 |
26 | })
27 |
28 | function setServer() {
29 |
30 | server_url = $('#server_text').val();
31 |
32 | if (server_url.length == 0) {
33 | return
34 | }
35 |
36 | connect_to_server();
37 | }
38 |
39 |
40 | function connect_to_server() {
41 |
42 | var get_server_info_promise = get_server_info(server_url + '/info').then(function(data) {
43 | server_info = data
44 | });
45 |
46 | Promise.all([get_server_info_promise]).then(
47 | function(values) {
48 | setInputForm();
49 | }
50 | );
51 | }
52 |
53 | function get_server_info(url) {
54 | return new Promise( function(resolve, reject) {
55 | $.get(url,
56 | function (data) {
57 | resolve( JSON.parse(data) );
58 | }
59 | );
60 | });
61 | }
62 |
63 | function setInputForm(){
64 |
65 | $('#services').empty();
66 |
67 | $('#services').append('');
68 | var serviceSelect = document.getElementById('service-select');
69 |
70 |
71 | for (var service in server_info) {
72 | serviceSelect.options[serviceSelect.options.length] = new Option(service, service);
73 | }
74 |
75 | $('#services').append('');
76 |
77 |
78 | service_param = $.urlParam('service');
79 |
80 | if (service_param) {
81 | if ( service_param in server_info) {
82 | selectedService = decodeURIComponent(service_param);
83 | $("#set-service").val(selectedService).change();
84 | load_service();
85 | }
86 | }
87 |
88 | }
89 |
90 | function setService() {
91 |
92 | $('#input').empty();
93 | $('#output').empty();
94 |
95 | var serviceSelect = document.getElementById('service-select');
96 | selectedService = serviceSelect.options[serviceSelect.selectedIndex].value;
97 |
98 | load_service();
99 | }
100 |
101 |
102 | function load_service() {
103 | //console.log(selectedService);
104 | var all_vals = true;
105 | for (var i = 0; i < server_info[selectedService].inputs.length; ++i){
106 | //console.log(server_info[selectedService].inputs[i]);
107 | input_str = '';
111 | $('#input').append(input_str);
112 |
113 | var this_input = $.urlParam(server_info[selectedService].inputs[i].name);
114 | if (this_input) {
115 | var this_val = decodeURIComponent(this_input);
116 | $('#' + server_info[selectedService].inputs[i].name ).val(this_val);
117 | } else {
118 | all_vals = false;
119 | }
120 | }
121 |
122 | $('#input').append('');
123 |
124 | if (all_vals) {
125 | getData();
126 | }
127 | }
128 |
129 | function getData() {
130 |
131 | var serviceSelect = document.getElementById('service-select');
132 | var selectedService = serviceSelect.options[serviceSelect.selectedIndex].value;
133 |
134 | $('#loading').append('loading...');
135 |
136 | $('#output').empty();
137 |
138 | url_params = "?service=" + selectedService;
139 |
140 | console.log(server_info[selectedService]);
141 | for (var i = 0; i < server_info[selectedService].inputs.length; ++i){
142 | var inputName = server_info[selectedService].inputs[i].name;
143 | var inputValue = document.getElementById(inputName).value;
144 | url_params += '&' + inputName + '=' + inputValue
145 | }
146 |
147 | var get_data_promise = get_data(server_url + url_params).then(function(data) {
148 | server_result = data;
149 | });
150 |
151 | Promise.all([get_data_promise]).then(
152 | function(values) {
153 | showData();
154 | console.log('DONE 1');
155 | }
156 | );
157 | }
158 |
159 | function get_data(url) {
160 | return new Promise( function(resolve, reject) {
161 | $.get(url,
162 | function (data) {
163 | console.log(data);
164 | resolve( JSON.parse(data) );
165 | console.log('DONE');
166 | }
167 | );
168 | });
169 | }
170 |
171 | function showData() {
172 | if (server_result.success != 1) {
173 | $('#loading').empty();
174 | $('#output').append('Command did not complete successfully');
175 | } else {
176 | console.log('0');
177 | $('#loading').empty();
178 | var result = server_result.result;
179 | $('#output').append('
');
180 | for (var i = 0; i < result.length; ++i){
181 | row = '