├── .force_git_push ├── .gitignore ├── .gitlab-ci.yml ├── .gitmodules ├── Dockerfile ├── LICENSE ├── README.md ├── __init__.py ├── app ├── __init__.py ├── static │ ├── .DS_Store │ ├── README.md │ ├── SBOL │ │ ├── assembly-scar.png │ │ ├── blunt-restriction-site.png │ │ ├── cds.png │ │ ├── five-prime-overhang.png │ │ ├── five-prime-sticky-restriction-site.png │ │ ├── insulator.png │ │ ├── operator.png │ │ ├── origin-of-replication.png │ │ ├── primer-binding-site.png │ │ ├── promoter.png │ │ ├── protease-site.png │ │ ├── protein-stability-element.png │ │ ├── restriction-enzyme-recognition-site.png │ │ ├── ribonuclease-site.png │ │ ├── ribosome-entry-site.png │ │ ├── rna-stability-element.png │ │ ├── signature.png │ │ ├── terminator.png │ │ ├── three-prime-overhang.png │ │ ├── three-prime-sticky-restriction-site.png │ │ └── user-defined.png │ ├── abacus.html │ ├── biobrick.html │ ├── blast_form.html │ ├── css │ │ ├── custom.css │ │ ├── home.css │ │ ├── material-1.2.0.min.css │ │ ├── material-icons.css │ │ ├── material-icons.woff2 │ │ ├── material-lite.css │ │ ├── material.min.css │ │ ├── materialize.css │ │ ├── materialize.min.css │ │ ├── style.css │ │ └── timeline.css │ ├── data │ │ ├── biobrick.json │ │ ├── data.json │ │ ├── plugins.json │ │ └── simu_data.json │ ├── dev-avatar │ │ ├── azy.jpg │ │ ├── pjer.jpg │ │ ├── wzb.JPG │ │ ├── zzh.JPG │ │ ├── zzr.JPG │ │ └── zzzz.jpg │ ├── developers.html │ ├── document │ │ ├── PANO_README.md │ │ └── ball.txt │ ├── favicon.ico │ ├── fonts │ │ ├── MaterialIcons-Regular.eot │ │ ├── MaterialIcons-Regular.ijmap │ │ ├── MaterialIcons-Regular.svg │ │ ├── MaterialIcons-Regular.ttf │ │ ├── MaterialIcons-Regular.woff │ │ ├── MaterialIcons-Regular.woff2 │ │ └── roboto │ │ │ ├── Roboto-Bold.eot │ │ │ ├── Roboto-Bold.ttf │ │ │ ├── Roboto-Bold.woff │ │ │ ├── Roboto-Bold.woff2 │ │ │ ├── Roboto-Light.eot │ │ │ ├── Roboto-Light.ttf │ │ │ ├── Roboto-Light.woff │ │ │ ├── Roboto-Light.woff2 │ │ │ ├── Roboto-Medium.eot │ │ │ ├── Roboto-Medium.ttf │ │ │ ├── Roboto-Medium.woff │ │ │ ├── Roboto-Medium.woff2 │ │ │ ├── Roboto-Regular.eot │ │ │ ├── Roboto-Regular.ttf │ │ │ ├── Roboto-Regular.woff │ │ │ ├── Roboto-Regular.woff2 │ │ │ ├── Roboto-Thin.eot │ │ │ ├── Roboto-Thin.ttf │ │ │ ├── Roboto-Thin.woff │ │ │ └── Roboto-Thin.woff2 │ ├── forum-api.txt │ ├── forums.html │ ├── home.html │ ├── images │ │ ├── background.jpeg │ │ ├── bg.png │ │ ├── bg_blur.png │ │ ├── logo.ico │ │ └── logo.png │ ├── img │ │ ├── bg.jpg │ │ ├── developer.png │ │ ├── emoj.ico │ │ ├── favicon.ico │ │ ├── github.png │ │ ├── link_from.svg │ │ ├── link_to.svg │ │ ├── loading.gif │ │ ├── logo.ico │ │ ├── logo.png │ │ ├── pjer.jpg │ │ └── user-a.png │ ├── js │ │ ├── abacus.js │ │ ├── blast.js │ │ ├── d3.v3.min.js │ │ ├── forum.js │ │ ├── jquery-1.11.3.min.js │ │ ├── jquery-2.1.1.min.js │ │ ├── latexit.js │ │ ├── material-1.2.0.js │ │ ├── material.min.js │ │ ├── material.min.js.map │ │ ├── materialize.js │ │ ├── materialize.min.js │ │ ├── otherdata.js │ │ ├── pano.js │ │ ├── post-form.js │ │ ├── profile-api.txt │ │ ├── profile.js │ │ ├── profile_edit.js │ │ ├── project.js │ │ ├── scripts.js │ │ ├── simulation.js │ │ ├── tether.min.js │ │ ├── user.js │ │ └── velocity.min.js │ ├── login.html │ ├── pano.html │ ├── personal_center.html │ ├── plugins.html │ ├── profile.html │ ├── profile_edit.html │ ├── project-api.txt │ ├── projects.html │ ├── signup.html │ ├── simulation_form.html │ ├── user_data.html │ ├── wksps_frame.html │ └── wksps_pjer.html └── views │ ├── __init__.py │ ├── home.py │ └── plugin.py ├── config.docker.py ├── config.py.example ├── database.py ├── models ├── __init__.py ├── document.py ├── link.py ├── list.config ├── node.py ├── plugin_document.py └── user.py ├── ncbi_562.sql ├── ncbiuploader.py ├── plugin.py ├── plugins ├── ABACUS │ ├── __init__.py │ ├── abacus.py │ ├── callabacus.py │ ├── design.py │ ├── singleMutationScan.py │ └── suspiciousSites.py ├── BLAST.py ├── README.md ├── __init__.py ├── biobrick_manager │ ├── Biobrick.py │ ├── BiobrickOfficial.py │ ├── BiobrickUser.py │ ├── Feature.py │ ├── FeatureOfficial.py │ ├── FeatureUser.py │ └── __init__.py ├── dbupload │ ├── __init__.py │ ├── dbprofile.py │ ├── linkgene.py │ ├── progressbar.py │ └── uploaddb.py ├── example_plugin.py ├── googlescholar.py ├── igemdata.json ├── pano.py ├── path_finder.py ├── path_finder_new.py ├── plugins │ ├── __init__.py │ ├── auto_load_list │ └── plugins.py ├── relationship.py ├── simulation.py ├── test.py ├── user_model.py └── version.py ├── requirements.txt ├── run.py ├── run_tests.py ├── scripts └── import_old_database.py ├── test_sample ├── MyDict.py ├── __init__.py └── function_as_sample.py └── tests ├── .gitkeep ├── __init__.py ├── test_astar.py ├── test_flask_sample.py ├── test_function_sample.py └── test_mydict_sample.py /.force_git_push: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/.force_git_push -------------------------------------------------------------------------------- /.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 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | 91 | # PyCharm 92 | .idea 93 | 94 | # Config File 95 | config.py 96 | #ABACUS 97 | plugins/ABACUS/ABACUS/ 98 | app/static/downloads/ 99 | 100 | # JetBrains Rider 101 | 102 | .idea/ 103 | 104 | *.sln.iml 105 | 106 | # Python Tools for Visual Studio (PTVS) 107 | 108 | __pycache__/ 109 | 110 | *.pyc 111 | 112 | # Visual Studio profiler 113 | 114 | *.psess 115 | 116 | *.vsp 117 | 118 | *.vspx 119 | 120 | *.sap 121 | 122 | # User-specific files 123 | 124 | *.suo 125 | 126 | *.user 127 | 128 | *.userosscache 129 | 130 | *.sln.docstates 131 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | build_linux: 2 | script: 3 | - cd app/static 4 | - git submodule init 5 | - git submodule update 6 | - cd ../.. 7 | - cp config.py.example config.py 8 | - coverage run run_tests.py 9 | lint: 10 | allow_failure: true 11 | script: 12 | - pylint -f parseable -rn models plugins -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "app/static"] 2 | path = app/static 3 | url = git@git.ustclug.org:igem2016/USTC-software-UI.git 4 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian 2 | MAINTAINER USTC-Software, developers@biohub.tech 3 | EXPOSE 5000 4 | 5 | WORKDIR /root 6 | RUN apt update && apt install -y \ 7 | git \ 8 | python3 \ 9 | python3-pip \ 10 | python3-biopython \ 11 | python3-flask \ 12 | python3-sqlalchemy \ 13 | python3-scipy \ 14 | libmysqlclient-dev \ 15 | mysql-client \ 16 | wget \ 17 | && pip3 install \ 18 | flask_login \ 19 | mysqlclient \ 20 | pymysql 21 | ADD . . 22 | RUN mv config.docker.py config.py 23 | 24 | ENTRYPOINT ./run.py 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Welcome to BioHub! 2 | ================== 3 | BioHub is a software tool for synthetic biologists developed by USTC-Software. It aims at helping synthetic biologists to deal with data from different types such as regulatory proteins, regulatory elements in gene expression. 4 | 5 | BioHub is done using an extensive plug-in system with some handy utility such as pathway-finding, one key blast and quick query. Users can have their own personalized Biohub according to their need. 6 | 7 | [Learn more about us](http://2016.igem.org/Team:USTC-Software) 8 | 9 | **If you just want to try it, please visit our example website [biohub.tech](http://biohub.tech/).** 10 | 11 | We strongly recommend you to use **Chrome** web browser, since other browsers are not fully supported. 12 | 13 | How to install BioHub on your lab server 14 | ---------------------------------------- 15 | We suggest users use [Docker](https://www.docker.com/) to deploy BioHub. It just needs two steps: 16 | 17 | docker run -d --name biohubdb -e MYSQL_ROOT_PASSWORD=password mysql 18 | docker run -d --name biohub --link biohubdb:db -p 80:5000 biohubtech/biohub 19 | 20 | You can also use `-e BIOHUB_DB_HOST=` and/or `-e BIOHUB_DB_USER= -e BIOHUB_DB_PASSWORD=` to connect to other databases. 21 | 22 | Also, you can clone the repo and run it manually. We've tested this on Debian 8: 23 | 24 | sudo apt update 25 | sudo apt install git python3 python3-pip python3-biopython python3-flask python3-sqlalchemy python3-scipy libmysqlclient-dev mysql-server mysql-client wget 26 | git clone https://github.com/igemsoftware2016/USTC-Software-2016.git 27 | cd USTC-Software-2016 28 | sudo pip3 install flask_login mysqlclient pymysql 29 | echo CREATE DATABASE biohub | mysql -u -p # please fill in the blanks 30 | wget http://parts.igem.org/partsdb/download.cgi?type=parts_sql -O biobricks.sql.gz 31 | gunzip biobricks.sql.gz 32 | mysql -u -p biohub < biobricks.sql # please fill in the blanks 33 | mysql -u -p biohub < ncbi_562.sql 34 | echo "DATABASE_URI = 'mysql://:@localhost/biohub'" >config.py # please fill in the blanks 35 | echo "SECRET_KEY = ''" >>config.py # please fill in the blanks 36 | ./run.py 37 | # then the server will start on port 5000 38 | 39 | After the installation, only one of the species databases is imported for demo. You can download databases from NCBI and import them manually by our script. 40 | 41 | How to install ABACUS plugin 42 | -------------- 43 | 44 | Copy and run the code below to install ABACUS: 45 | 46 | We assume that USTC-Software-2016 is the path to our git repo. 47 | 48 | wget http://download.biohub.tech/ABACUS.tar.gz 49 | wget http://download.biohub.tech/ABACUS.db.tar.gz 50 | tar -xvzf ABACUS.tar.gz 51 | tar -xvzf ABACUS.db.tar.gz 52 | mv ABACUS $BioHubPath/USTC-Software-2016/plugins/ABACUS/ 53 | # $BioHubPath is the path you install BioHub 54 | cd $BioHubPath/USTC-Software-2016/plugins/ABACUS/ABACUS/ 55 | sh setup.sh 56 | # You will get a message like set ABACUSPATH=$BioHubPath/USTC-Software-2016/plugins/ABACUS/ABACUS 57 | export ABACUSPATH=$BioHubPath/USTC-Software-2016/plugins/ABACUS/ABACUS/ 58 | # Don’t forget the last slash 59 | cd bin 60 | mkdir pdbs 61 | # If you are on Intel platform, please do the following steps 62 | rm psdSTRIDE 63 | wget http://download.biohub.tech/psdSTRIDE 64 | # All done! 65 | 66 | Upload Data File From NCBI 67 | -------------------------- 68 | 69 | Goto root direction, open ncbiuploader.py. Change filepath to the path you store NCBI data file, and change column_num to the number of columns in data file. 70 | 71 | It’s recommended to download file from following url: 72 | 73 | ftp://ftp.ncbi.nlm.nih.gov/gene/DATA/GENE_INFO/All_Data.gene_info.gz, column_num=15. 74 | ftp://ftp.ncbi.nlm.nih.gov/pub/biosystems/biosystems.20161008/biosystems_gene_all.gz, column_num=3 75 | 76 | Add index for tables: 77 | 78 | alter table biosystems add index all_index (gene_id, bsid); 79 | alter table allgeneinfo_all add index all_index (gene_id, tax_id, Symbol); 80 | alter table allgeneinfo_all add fulltext('Symbol'); 81 | 82 | To create database for pathfinder, execute the following SQL statement: 83 | 84 | create table biosys_562 ( 85 | id int primary key AUTO_INCREMENT, 86 | gene_id char(10), 87 | tax_id char(10), 88 | bsid int, 89 | Symbol char(64)); 90 | 91 | alter table biosys_562 add index all_index(gene_id, bsid); 92 | 93 | insert into biosys_562 (gene_id, tax_id, bsid, Symbol) 94 | select a.gene_id, a.tax_id, b.bsid, a.Symbol 95 | from allgeneinfo_all a, biosystems b 96 | where a.gene_id = b.gene_id and a.tax_id='%tax_id%'; 97 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/__init__.py -------------------------------------------------------------------------------- /app/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # encoding: utf-8 3 | 4 | from flask import Flask 5 | from flask_login import LoginManager, current_user 6 | import os 7 | import sys 8 | 9 | app = Flask(__name__) 10 | app.config.from_object('config') 11 | if os.getenv('FLASK_TESTING'): 12 | app.config['DATABASE_URI'] = 'sqlite://' # in memory 13 | print('Using temp database in memory', file=sys.stderr) 14 | login_manager = LoginManager() 15 | login_manager.init_app(app) 16 | login_manager.login_view = 'user.login' 17 | 18 | from models import User 19 | from database import session, TableBase, engine 20 | 21 | 22 | @login_manager.user_loader 23 | def load_user(user_id): 24 | return session.query(User).get(user_id) 25 | 26 | 27 | from app.views import * 28 | 29 | app.register_blueprint(home, url_prefix='') 30 | app.register_blueprint(plugin, url_prefix='/plugin') 31 | 32 | TableBase.metadata.create_all(engine) 33 | 34 | from plugin import plugin_manager 35 | 36 | with app.app_context(): 37 | plugin_manager.load_plugin('plugins') 38 | -------------------------------------------------------------------------------- /app/static/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/.DS_Store -------------------------------------------------------------------------------- /app/static/README.md: -------------------------------------------------------------------------------- 1 | # User interface 2 | ## 登陆页面 3 | form:登陆名(邮箱) 密码 4 | ## 注册页面 5 | form:用户名(昵称) 登录名(邮箱) 密码 6 | 7 | ## error code: 8 | ### (登陆) 9 | a1:账号或密码错误 10 | ### (注册) 11 | b1:账号已经注册 12 | 13 | ## 调试 14 | debug-fake-backend 是调试用的伪后端,flask写的,模拟后端接受post做客户验证并返回信息,前端可以根据自己的需要来定制自己的url响应内容,注意不要冲突,当前有的登陆和注册的url 15 | 16 | eg: 17 | 在登陆不成功的时候返回 18 | ``` 19 | {'error','a1'} 20 | ``` 21 | 22 | 23 | ## 所用到的轮子 24 | D3.js v3 25 | material.min.css v1.1.3 26 | materialize 0.97.7 27 | jquery v2.1.1 28 | 29 | 30 | # 接口文档 31 | ### plugin:user_module 32 | 用户模型-属性 33 | face:base64 34 | name:str 35 | email:str(key) 36 | education:str 37 | major:str 38 | description:str 39 | 40 | 用户模型-url post 41 | 42 | ### abstract 43 | 关于用户退登陆的接口在user.js里面, 44 | logout_form()向服务器发出退出登陆的请求并在前端重定向到login界面, 45 | get_user_info()向服务器请求用户数据,用于侧边栏的头像和id的展示。 46 | 47 | ### 登陆 48 | location : login-1.html 49 | POST : /plugin/ 50 | data : JSON.parse("{"plugin":"user_model","action":"create_user","email":"sam@gmail.com","password":"123456","username":"Big Sam"}") 51 | 如果成功 :跳转到home页面 52 | 如果失败 :后端返回错误原因 弹出提示信息 53 | 54 | 55 | 56 | ### 修改头像 57 | location : profile_edit.html 58 | POST : /plugin/ 59 | data : JSON.parse("[{"plugin":"user_model"},{"action":"head_change"},{"data":"data:image/png;base64,iVBORw0KGg..........mCPQ73/mO/e63v/CC"}]") 60 | 如果成功 :弹出提示修改成功的信息 61 | 如果失败 :弹出提示修改失败的信息 62 | 63 | 64 | ### 退出登陆 65 | location : anywhere 66 | POST : /plugin/ 67 | data : JSON.parse("{"plugin":"user_model","action":"logout"}") 68 | 重定向到login页面 69 | 70 | 71 | ### 注册 72 | location : signup.html 73 | POST : /plugin/ 74 | data : JSON.parse("{"plugin":"user_model","action":"create_user","email":"sam@gmail.com","password":"123456","username":"uncle sam"}") 75 | 如果注册成功,跳转到注册页面 76 | 如果注册失败,后端返回错误原因,弹出提示信息 77 | 78 | 79 | ### 获取用户信息 80 | location : anywhere 81 | POST : /plugin/ 82 | data : JSON.parse("{"plugin":"user_model","action":"get_user_data") 83 | res : 84 | email *(string) 85 | username *(string) 86 | avatar (string(base64)) 87 | description (long string) 88 | education (long string) 89 | major (long string) 90 | 91 | 如果成功,没有提示 92 | 如果失败,后端返回错误原因,弹出提示信息 93 | 94 | 95 | ### 修改用户信息 96 | location : profile_edit.html 97 | POST : /plugin/ 98 | data : JSON.parse("{"plugin":"user_model","action":"edit_profile","username":"sam J","education":"ustc","major":"hook","description":"nothing"}") 99 | 如果成功,返回home界面 100 | 失败 : 登录信息过期之类的(返回login-1) 101 | 用于把各种数据分发到各个位置 102 | 103 | ## BLAST 104 | 105 | ### data example 106 | 前端向后端提供一段基因序列例如: 107 | agagaatataaaaagccagattattaatccggcttttttattattt 108 | 后端经过BLAST得到处理结果示例如下 109 | 110 | ``` javascript 111 | {"q_length":46,"blast_result":[{'index':0,'ID':'gi|688010384|gb|KM018299.1|', 112 | 'description':'Synthetic fluorescent protein expression cassette cat-J23101-mTagBFP2, complete sequence', 113 | 'E-value':7.8e-14, 114 | 'score':84.24, 115 | 'span':46, 116 | 'query_start':0, 117 | 'query_end':46, 118 | 'hit_start':21, 119 | 'hit_end':67 120 | }, 121 | {'index':0,'ID':'gi|688010384|gb|KM018299.1|', 122 | 'description':'Synthetic fluorescent protein expression cassette cat-J23101-mTagBFP2, complete sequence', 123 | 'E-value':7.8e-14, 124 | 'score':84.24, 125 | 'span':46, 126 | 'query_start':0, 127 | 'query_end':46, 128 | 'hit_start':21, 129 | 'hit_end':67, 130 | },{'index':0,'ID':'gi|688010384|gb|KM018299.1|', 131 | 'description':'Synthetic fluorescent protein expression cassette cat-J23101-mTagBFP2, complete sequence', 132 | 'E-value':7.8e-14, 133 | 'score':84.24, 134 | 'span':46, 135 | 'query_start':0, 136 | 'query_end':46, 137 | 'hit_start':21, 138 | 'hit_end':67, 139 | },{'index':0,'ID':'gi|688010384|gb|KM018299.1|', 140 | 'description':'Synthetic fluorescent protein expression cassette cat-J23101-mTagBFP2, complete sequence', 141 | 'E-value':7.8e-14, 142 | 'score':84.24, 143 | 'span':46, 144 | 'query_start':0, 145 | 'query_end':46, 146 | 'hit_start':21, 147 | 'hit_end':67 148 | }]}; 149 | ``` 150 | 151 | ## simulation 152 | 153 | #### upload data example: 154 | location : profile_edit.html 155 | POST : /plugin/ 156 | plugin : simulation 157 | action : run_sim 158 | data : 159 | ``` javascript 160 | [ 161 | { 162 | "index":0,//index of equation starts from 0 163 | "name_dydx":"dy0dx" //name of equation (not important) 164 | "function":"0.05*y[1]+0.0005*y[1]" //function important 165 | "initial_value":0.1 166 | }, 167 | { 168 | "index":1,//index of equation starts from 0 169 | "name_dydx":"dy1dx" //name of equation (not important) 170 | "function":"0.05*y[1]+0.0005*y[1]" //function important 171 | "initial_value":0.1 172 | }, 173 | { 174 | "index":2,//index of equation starts from 0 175 | "name_dydx":"dy2dx" //name of equation (not important) 176 | "function":"0.05*y[1]+0.0005*y[1]" //function important 177 | "initial_value":0.1 178 | } 179 | 180 | ``` 181 | 182 | 183 | response : 184 | ``` javascript 185 | 186 | { 187 | "index":0,//corespond to the query index 188 | "t" :[2.1,2.2,2.3,......] 189 | "data":[2,3,4,.......]//calculate result 190 | } 191 | ``` 192 | 193 | 194 | 195 | 196 | http://localhost:5000/plugin/?plugin=biobrick_manager&action=search&key=abc 197 | 198 | 199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /app/static/SBOL/assembly-scar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/assembly-scar.png -------------------------------------------------------------------------------- /app/static/SBOL/blunt-restriction-site.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/blunt-restriction-site.png -------------------------------------------------------------------------------- /app/static/SBOL/cds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/cds.png -------------------------------------------------------------------------------- /app/static/SBOL/five-prime-overhang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/five-prime-overhang.png -------------------------------------------------------------------------------- /app/static/SBOL/five-prime-sticky-restriction-site.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/five-prime-sticky-restriction-site.png -------------------------------------------------------------------------------- /app/static/SBOL/insulator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/insulator.png -------------------------------------------------------------------------------- /app/static/SBOL/operator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/operator.png -------------------------------------------------------------------------------- /app/static/SBOL/origin-of-replication.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/origin-of-replication.png -------------------------------------------------------------------------------- /app/static/SBOL/primer-binding-site.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/primer-binding-site.png -------------------------------------------------------------------------------- /app/static/SBOL/promoter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/promoter.png -------------------------------------------------------------------------------- /app/static/SBOL/protease-site.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/protease-site.png -------------------------------------------------------------------------------- /app/static/SBOL/protein-stability-element.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/protein-stability-element.png -------------------------------------------------------------------------------- /app/static/SBOL/restriction-enzyme-recognition-site.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/restriction-enzyme-recognition-site.png -------------------------------------------------------------------------------- /app/static/SBOL/ribonuclease-site.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/ribonuclease-site.png -------------------------------------------------------------------------------- /app/static/SBOL/ribosome-entry-site.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/ribosome-entry-site.png -------------------------------------------------------------------------------- /app/static/SBOL/rna-stability-element.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/rna-stability-element.png -------------------------------------------------------------------------------- /app/static/SBOL/signature.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/signature.png -------------------------------------------------------------------------------- /app/static/SBOL/terminator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/terminator.png -------------------------------------------------------------------------------- /app/static/SBOL/three-prime-overhang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/three-prime-overhang.png -------------------------------------------------------------------------------- /app/static/SBOL/three-prime-sticky-restriction-site.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/three-prime-sticky-restriction-site.png -------------------------------------------------------------------------------- /app/static/SBOL/user-defined.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/SBOL/user-defined.png -------------------------------------------------------------------------------- /app/static/blast_form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | BLAST 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 93 | 94 | 95 |
96 | 101 |
102 |
103 |

BLAST

104 | 105 | 106 |
107 |
108 |

Description

109 |
110 |

BioHub provide users with convenient one-key BLAST. In graphical interface ,the user select the components which he or she wants to align the sequence, and by just pressing one build-in button, BioHub will read the sequence and align it with sequences in online databases using BLAST interface provided by NCBI, and show the outcome simply and elegantly to the users.

111 |

Tips: BLAST is available only online. When using NCBI BLAST API, any user should obey their usage guidelines.

112 | 113 |
115 |
116 | 117 |
118 |
119 | 120 | 121 |

Blast

122 |
123 |
124 | 125 |
126 |
Sequence:
127 |
128 |
129 | 130 | 131 |
132 |
133 |
134 | 135 |
136 | 137 |
138 |
Blast 139 |
140 |
141 |
142 |

Result

143 |
144 | 145 |
146 | 147 |
148 |
149 | 150 |
151 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /app/static/css/custom.css: -------------------------------------------------------------------------------- 1 | @import url(https://fonts.googleapis.com/css?family=Merriweather+Sans:400,300,700); 2 | html { height: 100%; } 3 | body { width: 100%; font-family: 'Merriweather Sans', sans-serif; background-color: #f9f9f9; background-image: url("../images/bg_blur.png"); background-size: cover; background-repeat: no-repeat; background-position: center center; -webkit-font-smoothing: antialiased; } 4 | 5 | body .custom-container { max-width: 390px; margin-top: 8vw; } 6 | body .custom-container form.form { margin: 0 20px 20px; } 7 | body .custom-container .panel-default { box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2); box-shadow: 0 0px 5px 0 rgba(0, 0, 0, 0.1), 0 16px 20px -8px rgba(0, 0, 0, 0.3); box-shadow: 0 3px 9px 0 rgba(0, 0, 0, 0.1), 0 24px 38px -16px rgba(0, 0, 0, 0.2); background-color: white; border: none; padding: 14px; padding-top: 40px; border-radius: 2px; } 8 | body .custom-container .panel-default h3 { color: #3F51B5; font-weight: 400; } 9 | body .custom-container .panel-default h3 i.fa { color: #ddd; } 10 | body .custom-container .panel-default p a { transition: all 200ms ease-in-out; color: #3F51B5; } 11 | body .custom-container .panel-default p a:hover { text-decoration: none; opacity: 0.5; } 12 | body .custom-container .panel-default .form-group { position: relative; } 13 | body .custom-container .panel-default .form-group .material-input { box-shadow: none; border: none; border-bottom: 1px solid #ddd; font-size: 16px; height: 60px; font-weight: 400; border-radius: 0px; color: #333; transition: all 0.2s ease; padding-top: 19px; padding-left: 6px; background-color: transparent; } 14 | body .custom-container .panel-default .form-group .material-input:focus { border-color: #3F51B5; color: #333; } 15 | body .custom-container .panel-default .form-group:last-child { margin-bottom: 0; } 16 | body .custom-container .panel-default .form-group .placeholder { position: absolute; top: 27px; left: 5px; transition: all 0.1s ease-in-out; color: #ddd; transform: translate3d(0, 0, 0); font-size: 16px; pointer-events: none; font-weight: 400; } 17 | body .custom-container .panel-default .form-group .placeholder.focus { font-size: 12px; top: 2px; left: 5px; color: #3F51B5; } 18 | body .custom-container .panel-default .form-group .bottom-liner { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; margin: 0 auto; width: 0%; background-color: #3F51B5; transition: all 0.2s ease-in-out; } 19 | body .custom-container .panel-default .form-group .bottom-liner.lined { width: 100%; } 20 | body .custom-container .panel-default .form-group .highlight { height: 21px; background-color: #3F51B5; position: absolute; left: 5px; bottom: 13px; transition: all 0.15s ease-in-out; opacity: 0; width: 70%; pointer-events: none; background: -moz-linear-gradient(left, #3F51B5 0%, rgba(255, 255, 255, 0) 100%); background: -webkit-gradient(linear, left top, right top, color-stop(0%, #3F51B5), color-stop(100%, rgba(255, 255, 255, 0))); background: -webkit-linear-gradient(left, #3F51B5 0%, rgba(255, 255, 255, 0) 100%); background: -o-linear-gradient(left, #3F51B5 0%, rgba(255, 255, 255, 0) 100%); background: -ms-linear-gradient(left, #3F51B5 0%, rgba(255, 255, 255, 0) 100%); background: linear-gradient(to right, #3F51B5 0%, rgba(255, 255, 255, 0) 100%); } 21 | body .custom-container .panel-default .form-group .highlight.light { width: 0%; opacity: .3; } 22 | body .custom-container .panel-default .form-group .highlight.no-light { opacity: 0 !important; width: 0 !important; } 23 | body .custom-container .btn-custom { background-color: #3F51B5; border: none; color: white; transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); transition-delay: 0.2s; box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26); border-radius: 2px; padding: 10px 0px; font-size: 16px; font-weight: 700; letter-spacing: 0.3px; margin: 0 auto; outline: none !important; position: relative; overflow: hidden; } 24 | body .custom-container .btn-custom.not-visible { opacity: 0; transform: translateY(10px); color: transparent; } 25 | body .custom-container .btn-custom:hover { transition-delay: 0s; box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2); background-color: #4d5ec1; border-color: #4d5ec1; } 26 | body .custom-container .btn-custom:active { transform: scale(0.98); } 27 | body .custom-container .btn-custom .ripple-svg { position: absolute; left: 0; top: 0; } 28 | body .custom-container .btn-custom .ripple-svg .circle { opacity: 0.3; transform: traslateZ(0); } 29 | input.material-input[type=password] { font: large Verdana, sans-serif; } 30 | .material-icons { vertical-align: bottom; } 31 | 32 | 33 | 34 | 35 | a.download-button { font-weight: 700; color: #3f51b5; position: absolute; top: 20px; right: 20px; text-decoration: none; transition: all 200ms ease-in-out; } 36 | 37 | a.download-button:hover { color: rgba(63, 81, 181, 0.43); } 38 | -------------------------------------------------------------------------------- /app/static/css/home.css: -------------------------------------------------------------------------------- 1 | .demo-content { 2 | min-height: 437px; 3 | padding: 0px 8px 0px 8px; 4 | } 5 | .mdl-list__item-avatar { 6 | color: black !important; 7 | background-color: white !important; 8 | } 9 | html, body { 10 | font-family: 'Roboto', 'Helvetica'; 11 | } 12 | a { 13 | text-decoration: none; 14 | color: black; 15 | } 16 | .demo-avatar { 17 | width: 64px; 18 | height: 64px; 19 | border-radius: 32px; 20 | } 21 | .mdl-layout__drawer .avatar { 22 | margin-bottom: 16px; 23 | } 24 | .demo-drawer { 25 | border: none; 26 | } 27 | .demo-drawer .mdl-menu__container { 28 | z-index: -1; 29 | } 30 | .demo-drawer .demo-navigation { 31 | z-index: -2; 32 | } 33 | .demo-drawer .mdl-menu .mdl-menu__item { 34 | display: -webkit-flex; 35 | display: -ms-flexbox; 36 | display: flex; 37 | -webkit-align-items: center; 38 | -ms-flex-align: center; 39 | align-items: center; 40 | } 41 | .demo-drawer-header { 42 | box-sizing: border-box; 43 | display: -webkit-flex; 44 | display: -ms-flexbox; 45 | display: flex; 46 | -webkit-box-pack: end; 47 | -ms-flex-pack: end; 48 | -webkit-justify-content: flex-end; 49 | justify-content: flex-end; 50 | -webkit-box-orient: vertical; 51 | -webkit-flex-direction: column; 52 | -ms-flex-direction: column; 53 | flex-direction: column; 54 | padding: 16px; 55 | height: 160px; 56 | } 57 | .demo-avatar-dropdown { 58 | display: -webkit-flex; 59 | display: -ms-flexbox; 60 | display: flex; 61 | position: relative; 62 | -webkit-box-orient: horizontal; 63 | -webkit-flex-direction: row; 64 | -ms-flex-direction: row; 65 | flex-direction: row; 66 | -webkit-align-items: center; 67 | -ms-flex-align: center; 68 | align-items: center; 69 | width: 100%; 70 | } 71 | .demo-navigation { 72 | -webkit-box-flex: 1; 73 | -webkit-flex-grow: 1; 74 | -ms-flex-positive: 1; 75 | flex-grow: 1; 76 | } 77 | .demo-layout .demo-navigation .mdl-navigation__link { 78 | display: -webkit-flex !important; 79 | display: -ms-flexbox !important; 80 | display: flex !important; 81 | -webkit-box-orient: horizontal; 82 | -webkit-flex-direction: row; 83 | -ms-flex-direction: row; 84 | flex-direction: row; 85 | -webkit-align-items: center; 86 | -ms-flex-align: center; 87 | align-items: center; 88 | color: rgba(255, 255, 255, 0.56); 89 | font-weight: 500; 90 | } 91 | .demo-layout .demo-navigation .mdl-navigation__link:hover { 92 | background-color: #00C853; 93 | } 94 | .demo-navigation .mdl-navigation__link .material-icons { 95 | font-size: 24px; 96 | color: rgba(255, 255, 255, 0.56); 97 | margin-right: 24px; 98 | } 99 | .mdl-mini-footer { 100 | padding-left: 32px; 101 | padding-right: 32px; 102 | } 103 | .mdl-mini-footer { 104 | -webkit-box-flex: 1; 105 | -webkit-flex-grow: 1; 106 | -ms-flex-positive: 1; 107 | flex-grow: 1; 108 | } 109 | .demo-copyright { 110 | display: -webkit-flex !important; 111 | display: -ms-flexbox !important; 112 | display: flex !important; 113 | -webkit-box-orient: horizontal; 114 | -webkit-flex-direction: row; 115 | -ms-flex-direction: row; 116 | flex-direction: row; 117 | -webkit-align-items: center; 118 | -ms-flex-align: center; 119 | align-items: center; 120 | } 121 | .demo-spacer { 122 | height: 16px; 123 | } 124 | 125 | 126 | 127 | .demo-group-list { 128 | max-width: 1080px; 129 | } 130 | .demo-content { 131 | min-height: 437px; 132 | padding: 0px 8px 0px 8px; 133 | } 134 | .mdl-list__item-secondary-content { 135 | display: -webkit-flex !important; 136 | display: -ms-flexbox !important; 137 | display: flex !important; 138 | -webkit-flex-flow: row !important; 139 | -ms-flex-flow: row !important; 140 | flex-flow: row !important; 141 | -webkit-align-items: flex-end !important; 142 | -ms-flex-align: end !important; 143 | align-items: flex-end !important; 144 | } -------------------------------------------------------------------------------- /app/static/css/material-icons.css: -------------------------------------------------------------------------------- 1 | /* fallback */ 2 | @font-face { 3 | font-family: 'Material Icons'; 4 | font-style: normal; 5 | font-weight: 400; 6 | src: local('Material Icons'), 7 | local('MaterialIcons-Regular'), 8 | url('material-icons.woff2') format('woff2'); 9 | } 10 | 11 | .material-icons { 12 | font-family: 'Material Icons'; 13 | font-weight: normal; 14 | font-style: normal; 15 | font-size: 24px; 16 | line-height: 1; 17 | letter-spacing: normal; 18 | text-transform: none; 19 | display: inline-block; 20 | white-space: nowrap; 21 | word-wrap: normal; 22 | direction: ltr; 23 | -webkit-font-feature-settings: 'liga'; 24 | -webkit-font-smoothing: antialiased; 25 | } 26 | -------------------------------------------------------------------------------- /app/static/css/material-icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/css/material-icons.woff2 -------------------------------------------------------------------------------- /app/static/css/material-lite.css: -------------------------------------------------------------------------------- 1 | 2 | html, body { 3 | font-family: 'Roboto', 'Helvetica', sans-serif; 4 | } 5 | .demo-avatar { 6 | width: 48px; 7 | height: 48px; 8 | border-radius: 24px; 9 | } 10 | .demo-layout .demo-header .mdl-textfield { 11 | padding-top: 27px; 12 | } 13 | .demo-layout .mdl-layout__header .mdl-layout__drawer-button { 14 | color: rgba(0, 0, 0, 0.54); 15 | } 16 | .mdl-layout__drawer .avatar { 17 | margin-bottom: 16px; 18 | } 19 | .demo-drawer { 20 | border: none; 21 | } 22 | /* iOS Safari specific workaround */ 23 | .demo-drawer .mdl-menu__container { 24 | z-index: -1; 25 | } 26 | .demo-drawer .demo-navigation { 27 | z-index: -2; 28 | } 29 | /* END iOS Safari specific workaround */ 30 | .demo-drawer .mdl-menu .mdl-menu__item { 31 | display: -webkit-box; 32 | display: -webkit-flex; 33 | display: -ms-flexbox; 34 | display: flex; 35 | -webkit-box-align: center; 36 | -webkit-align-items: center; 37 | -ms-flex-align: center; 38 | align-items: center; 39 | } 40 | .demo-drawer-header { 41 | box-sizing: border-box; 42 | display: -webkit-box; 43 | display: -webkit-flex; 44 | display: -ms-flexbox; 45 | display: flex; 46 | -webkit-box-orient: vertical; 47 | -webkit-box-direction: normal; 48 | -webkit-flex-direction: column; 49 | -ms-flex-direction: column; 50 | flex-direction: column; 51 | -webkit-box-pack: end; 52 | -webkit-justify-content: flex-end; 53 | -ms-flex-pack: end; 54 | justify-content: flex-end; 55 | padding: 16px; 56 | height: 151px; 57 | } 58 | .demo-avatar-dropdown { 59 | display: -webkit-box; 60 | display: -webkit-flex; 61 | display: -ms-flexbox; 62 | display: flex; 63 | position: relative; 64 | -webkit-box-orient: horizontal; 65 | -webkit-box-direction: normal; 66 | -webkit-flex-direction: row; 67 | -ms-flex-direction: row; 68 | flex-direction: row; 69 | -webkit-box-align: center; 70 | -webkit-align-items: center; 71 | -ms-flex-align: center; 72 | align-items: center; 73 | width: 100%; 74 | } 75 | 76 | .demo-navigation { 77 | -webkit-box-flex: 1; 78 | -webkit-flex-grow: 1; 79 | -ms-flex-positive: 1; 80 | flex-grow: 1; 81 | } 82 | .demo-layout .demo-navigation .mdl-navigation__link { 83 | display: -webkit-box !important; 84 | display: -webkit-flex !important; 85 | display: -ms-flexbox !important; 86 | display: flex !important; 87 | -webkit-box-orient: horizontal; 88 | -webkit-box-direction: normal; 89 | -webkit-flex-direction: row; 90 | -ms-flex-direction: row; 91 | flex-direction: row; 92 | -webkit-box-align: center; 93 | -webkit-align-items: center; 94 | -ms-flex-align: center; 95 | align-items: center; 96 | color: rgba(255, 255, 255, 0.56); 97 | font-weight: 500; 98 | } 99 | .demo-layout .demo-navigation .mdl-navigation__link:hover { 100 | background-color: #00BCD4; 101 | color: #37474F; 102 | } 103 | .demo-navigation .mdl-navigation__link .material-icons { 104 | font-size: 24px; 105 | color: rgba(255, 255, 255, 0.56); 106 | margin-right: 32px; 107 | } 108 | 109 | .demo-content { 110 | max-width: 1080px; 111 | } 112 | 113 | .demo-charts { 114 | -webkit-box-align: center; 115 | -webkit-align-items: center; 116 | -ms-flex-align: center; 117 | align-items: center; 118 | } 119 | .demo-chart:nth-child(1) { 120 | color: #ACEC00; 121 | } 122 | .demo-chart:nth-child(2) { 123 | color: #00BBD6; 124 | } 125 | .demo-chart:nth-child(3) { 126 | color: #BA65C9; 127 | } 128 | .demo-chart:nth-child(4) { 129 | color: #EF3C79; 130 | } 131 | .demo-graphs { 132 | padding: 16px 32px; 133 | display: -webkit-box; 134 | display: -webkit-flex; 135 | display: -ms-flexbox; 136 | display: flex; 137 | -webkit-box-orient: vertical; 138 | -webkit-box-direction: normal; 139 | -webkit-flex-direction: column; 140 | -ms-flex-direction: column; 141 | flex-direction: column; 142 | -webkit-box-align: stretch; 143 | -webkit-align-items: stretch; 144 | -ms-flex-align: stretch; 145 | align-items: stretch; 146 | } 147 | /* TODO: Find a proper solution to have the graphs 148 | * not float around outside their container in IE10/11. 149 | * Using a browserhacks.com solution for now. 150 | */ 151 | _:-ms-input-placeholder, :root .demo-graphs { 152 | min-height: 664px; 153 | } 154 | _:-ms-input-placeholder, :root .demo-graph { 155 | max-height: 300px; 156 | } 157 | /* TODO end */ 158 | .demo-graph:nth-child(1) { 159 | color: #00b9d8; 160 | } 161 | .demo-graph:nth-child(2) { 162 | color: #d9006e; 163 | } 164 | 165 | .demo-cards { 166 | -webkit-box-align: start; 167 | -webkit-align-items: flex-start; 168 | -ms-flex-align: start; 169 | align-items: flex-start; 170 | -webkit-align-content: flex-start; 171 | -ms-flex-line-pack: start; 172 | align-content: flex-start; 173 | } 174 | .demo-cards .demo-separator { 175 | height: 32px; 176 | } 177 | .demo-cards .mdl-card__title.mdl-card__title { 178 | color: white; 179 | font-size: 24px; 180 | font-weight: 400; 181 | } 182 | .demo-cards ul { 183 | padding: 0; 184 | } 185 | .demo-cards h3 { 186 | font-size: 1em; 187 | } 188 | .demo-updates .mdl-card__title { 189 | min-height: 200px; 190 | background-image: url('images/dog.png'); 191 | background-position: 90% 100%; 192 | background-repeat: no-repeat; 193 | } 194 | .demo-cards .mdl-card__actions a { 195 | color: #00BCD4; 196 | text-decoration: none; 197 | } 198 | 199 | .demo-options h3 { 200 | margin: 0; 201 | } 202 | .demo-options .mdl-checkbox__box-outline { 203 | border-color: rgba(255, 255, 255, 0.89); 204 | } 205 | .demo-options ul { 206 | margin: 0; 207 | list-style-type: none; 208 | } 209 | .demo-options li { 210 | margin: 4px 0; 211 | } 212 | .demo-options .material-icons { 213 | color: rgba(255, 255, 255, 0.89); 214 | } 215 | .demo-options .mdl-card__actions { 216 | height: 64px; 217 | display: -webkit-box; 218 | display: -webkit-flex; 219 | display: -ms-flexbox; 220 | display: flex; 221 | box-sizing: border-box; 222 | -webkit-box-align: center; 223 | -webkit-align-items: center; 224 | -ms-flex-align: center; 225 | align-items: center; 226 | } -------------------------------------------------------------------------------- /app/static/css/timeline.css: -------------------------------------------------------------------------------- 1 | @import url(//fonts.googleapis.com/css?family=Open+Sans); 2 | 3 | 4 | h2 { 5 | margin-bottom: 30px; 6 | color: #4679bd; 7 | font-weight: 400; 8 | text-align: center; 9 | } 10 | 11 | p.footer { 12 | margin-bottom: 20px; 13 | color: #999999; 14 | font-size: 18px; 15 | text-align: center; 16 | } 17 | 18 | /* ----------------------------------------------- 19 | * Timeline 20 | * --------------------------------------------- */ 21 | .timeline { 22 | list-style: none; 23 | padding: 10px 0; 24 | position: relative; 25 | font-weight: 300; 26 | } 27 | .timeline:before { 28 | top: 0; 29 | bottom: 0; 30 | position: absolute; 31 | content:" "; 32 | width: 2px; 33 | background: #ffffff; 34 | left: 50%; 35 | margin-left: -1.5px; 36 | } 37 | .timeline > li { 38 | margin-bottom: 20px; 39 | position: relative; 40 | width: 50%; 41 | float: left; 42 | clear: left; 43 | } 44 | .timeline > li:before, .timeline > li:after { 45 | content:" "; 46 | display: table; 47 | } 48 | .timeline > li:after { 49 | clear: both; 50 | } 51 | .timeline > li:before, .timeline > li:after { 52 | content:" "; 53 | display: table; 54 | } 55 | .timeline > li:after { 56 | clear: both; 57 | } 58 | .timeline > li > .timeline-panel { 59 | width: calc(100% - 25px); 60 | width: -moz-calc(100% - 25px); 61 | width: -webkit-calc(100% - 25px); 62 | float: left; 63 | border: 1px solid #dcdcdc; 64 | background: #ffffff; 65 | position: relative; 66 | } 67 | .timeline > li > .timeline-panel:before { 68 | position: absolute; 69 | top: 26px; 70 | right: -15px; 71 | display: inline-block; 72 | border-top: 15px solid transparent; 73 | border-left: 15px solid #dcdcdc; 74 | border-right: 0 solid #dcdcdc; 75 | border-bottom: 15px solid transparent; 76 | content:" "; 77 | } 78 | .timeline > li > .timeline-panel:after { 79 | position: absolute; 80 | top: 27px; 81 | right: -14px; 82 | display: inline-block; 83 | border-top: 14px solid transparent; 84 | border-left: 14px solid #ffffff; 85 | border-right: 0 solid #ffffff; 86 | border-bottom: 14px solid transparent; 87 | content:" "; 88 | } 89 | .timeline > li > .timeline-badge { 90 | color: #ffffff; 91 | width: 28px; 92 | height: 28px; 93 | line-height: 50px; 94 | text-align: center; 95 | position: absolute; 96 | top: 16px; 97 | right: -12px; 98 | z-index: 100; 99 | } 100 | .timeline > li.timeline-inverted > .timeline-panel { 101 | float: right; 102 | } 103 | .timeline > li.timeline-inverted > .timeline-panel:before { 104 | border-left-width: 0; 105 | border-right-width: 15px; 106 | left: -15px; 107 | right: auto; 108 | } 109 | .timeline > li.timeline-inverted > .timeline-panel:after { 110 | border-left-width: 0; 111 | border-right-width: 14px; 112 | left: -14px; 113 | right: auto; 114 | } 115 | .timeline-badge > a { 116 | color: #ffffff !important; 117 | } 118 | .timeline-badge a:hover { 119 | color: #dcdcdc !important; 120 | } 121 | .timeline-title { 122 | margin-top: 0; 123 | color: inherit; 124 | } 125 | .timeline-heading h4 { 126 | font-weight: 400; 127 | padding: 0 15px; 128 | color: #4679bd; 129 | } 130 | .timeline-body > p, .timeline-body > ul { 131 | padding: 10px 15px; 132 | margin-bottom: 0; 133 | } 134 | .timeline-footer { 135 | padding: 5px 15px; 136 | background-color:#f4f4f4; 137 | } 138 | .timeline-footer p { margin-bottom: 0; } 139 | .timeline-footer > a { 140 | cursor: pointer; 141 | text-decoration: none; 142 | } 143 | .timeline > li.timeline-inverted { 144 | float: right; 145 | clear: right; 146 | } 147 | .timeline > li:nth-child(2) { 148 | margin-top: 60px; 149 | } 150 | .timeline > li.timeline-inverted > .timeline-badge { 151 | left: -12px; 152 | } 153 | .no-float { 154 | float: none !important; 155 | } 156 | @media (max-width: 767px) { 157 | ul.timeline:before { 158 | left: 40px; 159 | } 160 | ul.timeline > li { 161 | margin-bottom: 0px; 162 | position: relative; 163 | width:100%; 164 | float: left; 165 | clear: left; 166 | } 167 | ul.timeline > li > .timeline-panel { 168 | width: calc(100% - 65px); 169 | width: -moz-calc(100% - 65px); 170 | width: -webkit-calc(100% - 65px); 171 | } 172 | ul.timeline > li > .timeline-badge { 173 | left: 28px; 174 | margin-left: 0; 175 | top: 16px; 176 | } 177 | ul.timeline > li > .timeline-panel { 178 | float: right; 179 | } 180 | ul.timeline > li > .timeline-panel:before { 181 | border-left-width: 0; 182 | border-right-width: 15px; 183 | left: -15px; 184 | right: auto; 185 | } 186 | ul.timeline > li > .timeline-panel:after { 187 | border-left-width: 0; 188 | border-right-width: 14px; 189 | left: -14px; 190 | right: auto; 191 | } 192 | .timeline > li.timeline-inverted { 193 | float: left; 194 | clear: left; 195 | margin-top: 30px; 196 | margin-bottom: 30px; 197 | } 198 | .timeline > li.timeline-inverted > .timeline-badge { 199 | left: 28px; 200 | } 201 | } -------------------------------------------------------------------------------- /app/static/data/biobrick.json: -------------------------------------------------------------------------------- 1 | { 2 | "brick_data":[ 3 | {"id":1 ,"type":3, "u_name":"pSC101QC F1", "data1":{"description":"to remove BglII site on pSC101"},"data2":{"detail":"5'- gaatttacagatacccagatcAcccgggaaaagg-3'"},"data3":{"attention":"do not burn it"} }, 4 | {"id":2 ,"type":2, "u_name":"pSC101QC F1", "data1":{"description":"to remove BglII site on pSC101"},"data2":{"detail":"5'- gaatttacagatacccagatcAcccgggaaaagg-3'"},"data3":{"attention":"do not burn it"} }, 5 | {"id":6 ,"type":3, "u_name":"pSC101QC F1", "data1":{"description":"to remove BglII site on pSC101"},"data2":{"detail":"5'- gaatttacagatacccagatcAcccgggaaaagg-3'"}, "data3":{"attention":"do not burn it"} }, 6 | {"id":7 ,"type":3, "u_name":"pSC101QC F1", "data1":{"description":"to remove BglII site on pSC101"},"data2":{"detail":"5'- gaatttacagatacccagatcAcccgggaaaagg-3'"}, "data3":{"attention":"do not burn it"} }, 7 | {"id":12 ,"type":4, "u_name":"pSC101QC F1", "data1":{"description":"to remove BglII site on pSC101"},"data2":{"detail":"5'- gaatttacagatacccagatcAcccgggaaaagg-3'"}, "data3":{"attention":"do not burn it"} } 8 | ] 9 | } -------------------------------------------------------------------------------- /app/static/data/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "nodes":[ 3 | {"id":1 ,"type":3, "u_name":"gene1","title":"gene1", "x":540, "y":350}, 4 | {"id":2 ,"type":2, "u_name":"gRNA2","title":"gRNA2", "x":600, "y":300}, 5 | {"id":3 ,"type":2, "u_name":"gRNA1","title":"gRNA1", "x":480, "y":330}, 6 | {"id":4 ,"type":2, "u_name":"gene4","title":"gene4", "x":510, "y":300}, 7 | {"id":5 ,"type":3, "u_name":"gene3","title":"gene3", "x":480, "y":300}, 8 | {"id":6 ,"type":3, "u_name":"gene2","title":"gene2", "x":540, "y":380}, 9 | {"id":7 ,"type":3, "u_name":"gRNA3","title":"gRNA3", "x":580, "y":380}, 10 | {"id":8 ,"type":2, "u_name":"DNA2", "title":"DNA2", "x":500, "y":360}, 11 | {"id":9 ,"type":3, "u_name":"DNA1", "title":"DNA1", "x":480, "y":400}, 12 | {"id":10 ,"type":1, "u_name":"DNA3", "title":"DNA3", "x":500, "y":390}, 13 | {"id":11 ,"type":1, "u_name":"DNA4", "title":"DNA4", "x":560, "y":400}, 14 | {"id":12 ,"type":4, "u_name":"DNA4", "title":"DNA4", "x":560, "y":310}, 15 | {"id":14 ,"type":4, "u_name":"DNA4", "title":"DNA4", "x":600, "y":400} 16 | ], 17 | "links":[ 18 | {"lid":0, "source":1 ,"target":2 ,"weight":1}, 19 | {"lid":0, "source":1 ,"target":4 ,"weight":1}, 20 | {"lid":0, "source":3 ,"target":4 ,"weight":1}, 21 | {"lid":0, "source":1 ,"target":8 ,"weight":1}, 22 | {"lid":0, "source":3 ,"target":8 ,"weight":1}, 23 | {"lid":0, "source":9 ,"target":8 ,"weight":1} 24 | ] 25 | } 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/static/data/plugins.json: -------------------------------------------------------------------------------- 1 | { 2 | "auto": ["user_model", "pano", "path_finder", "simulation", "BLAST", "ABACUS", "version"], 3 | "description": 4 | { 5 | "user_model": "This plugin has no description.", 6 | "path_finder": "This plugin has no description.", 7 | "version": "This plugin has no description.", 8 | "plugins": "This plugin has no description.", 9 | "ABACUS":"This plugin has no description.", 10 | "BLAST": "This plugin has no description.", 11 | "pano": "This plugin has no description.", 12 | "simulation": "This plugin has no description." 13 | }, 14 | "success": true, 15 | "list": 16 | { 17 | "user_model": true, 18 | "path_finder": true, 19 | "version": true, 20 | "plugins": true, 21 | "BLAST": true, 22 | "example_plugin": false, 23 | "pano": true, 24 | "test": false, 25 | "googlescholar": false, 26 | "simulation": true, 27 | "relationship": false 28 | } 29 | } -------------------------------------------------------------------------------- /app/static/data/simu_data.json: -------------------------------------------------------------------------------- 1 | { 2 | "nodes":[ 3 | {"id":0 ,"type":3, "u_name":"gene1", "name":"node 1","title":"BBa_I10000","x":540, "y":350}, 4 | {"id":1 ,"type":2, "u_name":"gRNA2", "name":"node 2","title":"BBa_I19827","x":600, "y":300}, 5 | {"id":2 ,"type":3, "u_name":"gRNA2", "name":"node 3","title":"BBa_K87512","x":600, "y":300} 6 | ] 7 | } -------------------------------------------------------------------------------- /app/static/dev-avatar/azy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/dev-avatar/azy.jpg -------------------------------------------------------------------------------- /app/static/dev-avatar/pjer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/dev-avatar/pjer.jpg -------------------------------------------------------------------------------- /app/static/dev-avatar/wzb.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/dev-avatar/wzb.JPG -------------------------------------------------------------------------------- /app/static/dev-avatar/zzh.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/dev-avatar/zzh.JPG -------------------------------------------------------------------------------- /app/static/dev-avatar/zzr.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/dev-avatar/zzr.JPG -------------------------------------------------------------------------------- /app/static/dev-avatar/zzzz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/dev-avatar/zzzz.jpg -------------------------------------------------------------------------------- /app/static/document/PANO_README.md: -------------------------------------------------------------------------------- 1 | # Pano Document 2 | ## Data 3 | 数据格式编程json格式 有两个变量域 nodes(节点信息) linkes(有向连接关系) 示例数据: 4 | ``` 5 | nodes = [ 6 | {"id":1 ,"type":3, "u_name":"gene1","title":"gene1", "x":1400, "y":500}, 7 | {"id":2 ,"type":2, "u_name":"gRNA2","title":"gRNA2", "x":200, "y":100}, 8 | {"id":3 ,"type":2, "u_name":"gRNA1","title":"gRNA1", "x":800, "y":300}, 9 | {"id":4 ,"type":2, "u_name":"gene4","title":"gene4", "x":1100, "y":100}, 10 | {"id":5 ,"type":3, "u_name":"gene3","title":"gene3", "x":800, "y":100}, 11 | {"id":6 ,"type":3, "u_name":"gene2","title":"gene2", "x":1400, "y":800}, 12 | {"id":7 ,"type":3, "u_name":"gRNA3","title":"gRNA3", "x":1800, "y":800}, 13 | {"id":8 ,"type":2, "u_name":"DNA2", "title":"DNA2", "x":1000, "y":600}, 14 | {"id":9 ,"type":3, "u_name":"DNA1", "title":"DNA1", "x":500, "y":300}, 15 | {"id":10 ,"type":1, "u_name":"DNA3", "title":"DNA3", "x":1000, "y":900}, 16 | {"id":11 ,"type":1, "u_name":"DNA4", "title":"DNA4", "x":1600, "y":1000}, 17 | {"id":12 ,"type":4, "u_name":"DNA4", "title":"DNA4", "x":1600, "y":100}, 18 | {"id":14 ,"type":4, "u_name":"DNA4", "title":"DNA4", "x":2000, "y":1000} 19 | ]; 20 | 21 | edges = [ 22 | {"lid":0, "source":nodes[1] ,"target":nodes[8] ,"weight":1}, 23 | {"lid":0, "source":nodes[3] ,"target":nodes[8] ,"weight":1}, 24 | {"lid":0, "source":nodes[9] ,"target":nodes[8] ,"weight":1} 25 | ]; 26 | 27 | ``` 28 | 29 | ## variable 30 | r_click_gene (global) 表示邮件刚点过的点的信息,在on("contextmenu",function..)中被赋值,也就是右键node的时候会给这个全局变量赋值。这个变量包含点的位置和id以及type等信息可以在自定义右键的弹出菜单中使用 31 | 32 | ## Function 33 | #### redraw_lines(uid_num) 34 | uid_num:接受的变量是一个数字字符串,代表一个节点的id 35 | 功能:查询和点相连的线并更新线的位置使点之间的连线随着端点改变而改变 36 | 37 | #### print_gra(data_graph) 38 | data_graph:像示例数据一样的完整数据,包含节点和连线数据 39 | 功能:根据json画出图片上的点,之所以独立出来一个函数是为了后边更新svg方便 40 | 41 | #### about_modal() 42 | 不接收参数 43 | 只负责弹出和渲染 【about this gene】页面 44 | 45 | #### get_link_by_uid(uid_num) 46 | uid_num:接受的变量是一个数字字符串,代表一个节点的id 47 | 功能:查询和点相连的点,返回一个json,包含node_in和node_out两个字段,分别是发出指向这个点向量的node和这个点发出的向量指向的node 48 | 49 | #### back_to_center(data_graph) 50 | 通过考察data_graph里的点的位置信息,让图像回到点聚集的地方 51 | 52 | #### get_xy_range(json_data) 53 | 给出点分布的区域为 back_to_center提供参考 54 | 55 | ## attention 56 | node上的标签是对应node的id 57 | pano上的自定义右键只有node上的第一个可以用 58 | 59 | 60 | # 接口文档 61 | 62 | [{"plugin":"pano"},{"action":"update_data"},{"node-data":nodeData},{"edge-data":e\}]; 63 | 数据格式见上文 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/static/document/ball.txt: -------------------------------------------------------------------------------- 1 | PANO 部分: 2 | 获取匹配的名称: 3 | REQ(名称的一部分): 4 | POST /plugin 5 | plugin: "pano" 6 | action: "match_node" 7 | s: String() // 不完整的节点名称字符串(希望支持通配符,不支持就算了) 8 | RES(全名和简要信息): 9 | { 10 | "success": true, 11 | "nodes": [ 12 | { // 第一个推荐的节点,如果有完全匹配的名称,应该作为第一个 13 | "u_name": String(), // 节点的正式的,被补全的名称 14 | "info": String(), // 节点的简要信息 15 | }, 16 | { // 第二个推荐的节点 17 | "u_name": String(), // 节点的正式的,被补全的名称 18 | "info": String(), // 节点的简要信息 19 | }, 20 | { // 第三个推荐的节点 21 | "u_name": String(), // 节点的正式的,被补全的名称 22 | "info": String(), // 节点的简要信息 23 | }, 24 | ... 25 | ] 26 | } 27 | 28 | 节点信息: 29 | REQ(全部的名称): 30 | POST /plugin 31 | plugin: "pano" 32 | action: "node_info" 33 | u_name: String() // 节点名称 34 | RES(节点的简要和详细信息): 35 | { 36 | success: true, 37 | node: { 38 | info: String(), // 简要信息 39 | detailed_info: String() // 详细信息 40 | } 41 | } 42 | 43 | 寻路: 44 | REQ(data包括所有的数据): 45 | POST /plugin 46 | plugin: "path_finder" 47 | action: "path_finder" 48 | s: String() // 源节点名称 49 | t: String() // 目标节点名称 50 | k: Number() // 想要得到几条路 51 | maxlen: Number() // 路长度的最大值 52 | RES(返回所有**寻路**的节点和边的数据): 53 | { 54 | "success": true, 55 | "paths": [ 56 | [ 57 | String(), // 源节点名称 58 | String(), // 第二个节点名称 59 | String(), // 第三个节点名称 60 | String(), // 第四个节点名称 61 | String(), // 第五个节点名称 62 | ... 63 | String(), // 倒数第三个节点名称 64 | String(), // 倒数第二个节点名称 65 | String(), // 目标 66 | ], 67 | ... 68 | ] 69 | } 70 | 71 | @Deprecated 72 | { 73 | 获取ID: 74 | REQ: 75 | POST /plugin 76 | plugin: "pano" 77 | action: "find_project_id" 78 | RES: 79 | { project_id: Number() } 80 | 81 | 获取PANO: 82 | REQ: 83 | POST /plugin 84 | plugin: "pano" 85 | action: "load_pano" 86 | project_id: Number() 87 | RES(存在PANO): 88 | { 89 | nodes: [ 90 | {"id": Number(), "type": Number(), "u_name": String(), "title": String(), "x": Number(), "y": Number()}, 91 | {"id": Number(), "type": Number(), "u_name": String(), "title": String(), "x": Number(), "y": Number()}, 92 | ... 93 | ], edges: [ 94 | {"source": Number(), "target": Number(), "weight": Number()}, 95 | {"source": Number(), "target": Number(), "weight": Number()}, 96 | ... 97 | ] 98 | } 99 | RES(不存在PANO返回空): 100 | { 101 | nodes: [], edges: [] 102 | } 103 | 104 | 保存PANO: 105 | REQ: 106 | POST /plugin 107 | plugin: "pano" 108 | action: "save_pano" 109 | project_id: Number() 110 | data: "{ 111 | nodes: [ 112 | ...(同上) 113 | ], edges: [ 114 | ...(同上) 115 | ] 116 | }" 117 | RES(若存在PANO直接覆盖数据,若不存在PANO新建数据): 118 | { 119 | nodes: [ 120 | {"id": Number(), "type": Number(), "u_name": String(), "title": String(), "x": Number(), "y": Number()}, 121 | {"id": Number(), "type": Number(), "u_name": String(), "title": String(), "x": Number(), "y": Number()}, 122 | ... 123 | ], edges: [ 124 | {"source": Number(), "target": Number(), "weight": Number()}, 125 | {"source": Number(), "target": Number(), "weight": Number()}, 126 | ... 127 | ] 128 | } 129 | 130 | } -------------------------------------------------------------------------------- /app/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/favicon.ico -------------------------------------------------------------------------------- /app/static/fonts/MaterialIcons-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/MaterialIcons-Regular.eot -------------------------------------------------------------------------------- /app/static/fonts/MaterialIcons-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/MaterialIcons-Regular.ttf -------------------------------------------------------------------------------- /app/static/fonts/MaterialIcons-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/MaterialIcons-Regular.woff -------------------------------------------------------------------------------- /app/static/fonts/MaterialIcons-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/MaterialIcons-Regular.woff2 -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Bold.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Bold.eot -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Bold.ttf -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Bold.woff -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Bold.woff2 -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Light.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Light.eot -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Light.ttf -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Light.woff -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Light.woff2 -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Medium.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Medium.eot -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Medium.ttf -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Medium.woff -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Medium.woff2 -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Regular.eot -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Regular.ttf -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Regular.woff -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Regular.woff2 -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Thin.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Thin.eot -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Thin.ttf -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Thin.woff -------------------------------------------------------------------------------- /app/static/fonts/roboto/Roboto-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/fonts/roboto/Roboto-Thin.woff2 -------------------------------------------------------------------------------- /app/static/forum-api.txt: -------------------------------------------------------------------------------- 1 | 获得forum数据: 2 | data:{ 3 | "plugin":"pano", 4 | "action":"get_event_data" 5 | } 6 | type:POST 7 | url:"/plugin/" 8 | 9 | 返回值: 10 | '{"event": ---这个event的值是一个数组,数组长度不定,包含最近7天的所有好友的public event 11 | [ 12 | { 13 | "project_id":string, ---project的唯一标记值 14 | //"avt_src":string or null, ---完成事件的用户的头像链接 15 | //"user_name":string, ---完成事件的用户的username 16 | user_id 17 | "time":string, ---服务器端相应事件发生的时间 18 | "img_src":base64, ---事件相应的project的缩略图base64 19 | "state":"Create" or "Update", ---事件相应的project的最后一次更改的属性,如果是创建project则为Create,更改project则为Update 20 | "project_name":string, ---project的project name 21 | //"private":"Public" or "Private", ---project的权限属性,Public为对好友公开,反之为私有 22 | "last_update_time":string, ---事件相应的project最近一次更新的时间 23 | "praise":true or false, ---当前用户有没有赞过这个event 24 | "comment": ---这个comment的值是一个数组,数组里包含project的所有评论的数据 25 | [ 26 | { 27 | "user_id":string, ---作出评论的用户的userid 28 | "content":string ---评论的内容 29 | "time":string ---评论的时间 30 | } 31 | ] 32 | } 33 | ] 34 | }' 35 | 36 | 提交评论 37 | data:{ 38 | "plugin":"pano", 39 | "action":"submit_comment", 40 | "comment":string, ---评论内容 41 | "event_id":string, ---被评论的事件的id 42 | } 43 | type:POST 44 | url:"/plugin/" 45 | 46 | response:{ 47 | "success":true or false 48 | "error":错误信息 49 | 其它什么随便... 50 | } 51 | 52 | 提交赞 53 | data:{ 54 | "plugin":"pano", 55 | "action":"submit_praise", 56 | "modify":boolean, ---若点赞 则为true 若取消赞 则为false 57 | "event_id":string, ---被赞的事件id 58 | } 59 | type:POST 60 | url:"/plugin/" 61 | 62 | response:{ 63 | "success":true or false 64 | "error":错误信息 65 | 其它什么还是随便... 66 | } -------------------------------------------------------------------------------- /app/static/images/background.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/images/background.jpeg -------------------------------------------------------------------------------- /app/static/images/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/images/bg.png -------------------------------------------------------------------------------- /app/static/images/bg_blur.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/images/bg_blur.png -------------------------------------------------------------------------------- /app/static/images/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/images/logo.ico -------------------------------------------------------------------------------- /app/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/images/logo.png -------------------------------------------------------------------------------- /app/static/img/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/img/bg.jpg -------------------------------------------------------------------------------- /app/static/img/developer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/img/developer.png -------------------------------------------------------------------------------- /app/static/img/emoj.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/img/emoj.ico -------------------------------------------------------------------------------- /app/static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/img/favicon.ico -------------------------------------------------------------------------------- /app/static/img/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/img/github.png -------------------------------------------------------------------------------- /app/static/img/link_from.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 51 | 56 | 61 | 62 | -------------------------------------------------------------------------------- /app/static/img/link_to.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 20 | 22 | image/svg+xml 23 | 25 | 26 | 27 | 28 | 29 | 31 | 51 | 56 | 61 | 62 | -------------------------------------------------------------------------------- /app/static/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/img/loading.gif -------------------------------------------------------------------------------- /app/static/img/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/img/logo.ico -------------------------------------------------------------------------------- /app/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/img/logo.png -------------------------------------------------------------------------------- /app/static/img/pjer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/img/pjer.jpg -------------------------------------------------------------------------------- /app/static/img/user-a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/app/static/img/user-a.png -------------------------------------------------------------------------------- /app/static/js/abacus.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Pjer1 on 10/5/2016. 3 | */ 4 | 5 | var demo="F"; 6 | 7 | 8 | function demo_it() { 9 | if (demo == "F"){ 10 | demo = "True"; 11 | $('#demo_btn')[0].innerHTML = "cancel Demo"; 12 | $('#amount')[0].value = 3; 13 | $('div.file-field').addClass(" hide"); 14 | $('#tag')[0].value = "my first seq Design"; 15 | alert('Demo mode Sample pdb file has been in server click "UPLOAD AND CALCULATE" to start design'); 16 | Materialize.updateTextFields(); 17 | } 18 | else { 19 | demo = "F"; 20 | $('div.file-field').removeClass("hide"); 21 | $('#demo_btn')[0].innerHTML = "sample Demo"; 22 | $('#amount')[0].value = ""; 23 | $('#tag')[0].value = ""; 24 | Materialize.updateTextFields(); 25 | } 26 | } 27 | 28 | 29 | function upload_file(){ 30 | 31 | alert("Caution ! Previous .pdb file will be overwritten by this upload"); 32 | var waiting=jQuery('#loading'); 33 | waiting.removeClass("hide"); 34 | var btn = jQuery('#upload_btn'); 35 | var f_upload = new FormData(); 36 | f_upload.append('file', $('#pdb-file')[0].files[0]); 37 | f_upload.append('plugin','ABACUS'); 38 | f_upload.append('demo',demo); 39 | f_upload.append('amount',$('#amount')[0].value); 40 | f_upload.append('tag',$('#tag')[0].value); 41 | f_upload.append('action','design'); 42 | //console.log(f_upload); 43 | $.ajax({ 44 | type: "POST", 45 | url: "/plugin/", 46 | responseTime: 2000, 47 | data:f_upload, 48 | processData: false, 49 | contentType: false, 50 | success: function(response){ 51 | var Jr = JSON.parse(response); 52 | if(Jr['success']==Jr['success']){//true) { 53 | alert('The file has been accepted by server and being processed,it may take some time,we will email to inform you when finished', 3000, 'rounded'); 54 | waiting.addClass(" hide"); 55 | btn.addClass(" disabled"); 56 | btn.onclick=function () {} 57 | } 58 | else { 59 | Materialize.toast('Error : '+Jr['error'], 3000, 'rounded'); 60 | waiting.addClass(" hide"); 61 | } 62 | } 63 | }); 64 | //.done(L.addClass("hide")); 65 | //console.log("haha") 66 | } 67 | 68 | 69 | function get_status() { 70 | 71 | var data={"plugin":"ABACUS","action":"getstatus"}; 72 | $.ajax({ 73 | type:"POST", 74 | url:"/plugin/", 75 | data:data, 76 | success:function (response) { 77 | if (response.length>0){ 78 | var Jr = JSON.parse(response); 79 | if(Jr.status == "Clear"){ 80 | alert("Ready to design") 81 | } 82 | if(Jr.status == "Failed"){ 83 | alert("reason : "+Jr.reason) 84 | } 85 | if(Jr.status == "Running"){ 86 | alert("Designing....(be patient)") 87 | } 88 | if(Jr.status == "Empty"){ 89 | alert("ABACUS is not properly installed,Please contact administration for help") 90 | } 91 | if(Jr.status == "Success"){ 92 | var sel_s = $('#get_status')[0]; 93 | sel_s.innerHTML = "Download File"; 94 | sel_s.href = Jr.url; 95 | } 96 | } 97 | else {alert("please contact administration for help")} 98 | } 99 | }) 100 | } 101 | -------------------------------------------------------------------------------- /app/static/js/latexit.js: -------------------------------------------------------------------------------- 1 | /* 2 | * LaTeX IT - JavaScript to Convert Latex within an HTML page into Equations 3 | * Copyright (C) 2009 William Bateman, 2008 Waipot Ngamsaad 4 | 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | var LatexIT = { 20 | mode : 'gif', 21 | imgnum : 0, 22 | isFirefox:false, 23 | init : function() { 24 | // We need to review the support for SVG. Latest released versions are not supporting this as they should 25 | // if(document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1")) 26 | // this.mode='svg'; 27 | 28 | // browser name 29 | // svg support in FireFox is not allowing two images to occur currently on the same line. 30 | 31 | var ua = navigator.userAgent.toLowerCase(); 32 | if(ua.indexOf("firefox")!=-1) 33 | { 34 | // this.isFirefox = true; 35 | } 36 | }, 37 | 38 | pre : function(txt) { 39 | if ( !txt.match(//i) ) 40 | { 41 | //Clean code 42 | txt=txt.replace(/
/mgi,""); 43 | txt=txt.replace(/
/mgi,""); 44 | //Create img tag 45 | // txt = " "; 46 | // txt = " "; 47 | 48 | if(this.mode=='svg') 49 | { 50 | // Best for Firefox 51 | if(this.isFirefox) 52 | txt = " "; 53 | else // Best for Chrome 54 | // txt = " "; 55 | txt = " \""+ "; 56 | } 57 | else 58 | txt = " \""+txt+"\" "; 59 | } 60 | return txt; 61 | }, 62 | 63 | latex : function(txt) { 64 | var html, htmlinline; 65 | if(this.isFirefox) { 66 | html=" "; 67 | htmlinline=" "; 68 | } 69 | else { 70 | html=" "; 71 | htmlinline=" "; 72 | } 73 | 74 | 75 | txt=txt.replace(/(^\$|[^\\]\$)(.*?[^\\])\$/gm, htmlinline); 76 | txt=txt.replace(/(^\\|[^\\]\\)\[(.*?[^\\])\\\]/mg,"
"+html+"
"); 77 | txt=txt.replace(/\\\$/mg,"\$"); 78 | txt=txt.replace(/\\\\(\[|\])/mg,"$1"); 79 | 80 | return txt; 81 | }, 82 | 83 | render : function(tag, latexmode) { 84 | var eqn = window.document.getElementsByTagName(tag); 85 | for (var i=0; i0){ 27 | document.getElementById('this_is_a_user_name').innerHTML=Jr.username 28 | } 29 | } 30 | //this is for the current user name 31 | } 32 | }); 33 | } 34 | function get_others_info() { 35 | var url = window.location.hash; 36 | console.log(url); 37 | var loc=url.substring(url.lastIndexOf('#')+1, url.length); 38 | console.log(loc); 39 | var dictPost = {"plugin":"user_model","action":"get_user_data_by_id","user_id":parseInt(loc)}; 40 | console.log(dictPost); 41 | var Jr=[]; 42 | $.ajax({ 43 | type: "POST", 44 | url: "/plugin/", 45 | data: dictPost, 46 | success: function(response){ 47 | console.log(response); 48 | Jr = JSON.parse(response); 49 | if(Jr['success']==true) { 50 | // load info 51 | if(Jr.avt_src==null){ 52 | document.getElementById('user-head').setAttribute( 'src', 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAIAAgMAAACJFjxpAAAADFBMVEXFxcX////p6enW1tbAmiBwAAAFiElEQVR4AezAgQAAAACAoP2pF6kAAAAAAAAAAAAAAIDbu2MkvY0jiuMWWQoUmI50BB+BgRTpCAz4G6C8CJDrC3AEXGKPoMTlYA/gAJfwETawI8cuBs5Nk2KtvfiLW+gLfK9m+r3X82G653+JP/zjF8afP1S//y+An4/i51//AsB4aH+/QPD6EQAY/zwZwN8BAP50bh786KP4+VT+3fs4/noigEc+jnHeJrzxX+NWMDDh4g8+EXcnLcC9T8U5S/CdT8bcUeBEIrwBOiI8ki7Ba5+NrePgWUy89/nYyxQ8Iw3f+pWY4h1gb3eAW7sDTPEOsLc7wK1TIeDuDB+I/OA1QOUHv/dFsZQkhKkh4QlEfOULYz2nGj2/Nn1LmwR/86VxlCoAW6kCsHRGANx1RgCMo5Qh2EsZgrXNQZZShp5Liv7Il8eIc5C91EHY2hxk6bwYmNscZIReDBwtCdhbErC1JGBpScBcOgFMLQsZMQs5Whayd+UQsLYsZGlZyNyykKllISNmIUfAwifw8NXvTojAjGFrdYi11SGWVoeYWx1i6lmQCiEjFkKOVgjZ+xxIhZCtFULWHkCqxCw9gNQKmP9vNHzipdEPrRcxtVbAeDkAvve0iM2QozVD9hfjhp4YP/UrkJYDbD2AtBxgfSkAvvHEeNcDSAsilgtAWxIy91J8AXgZAJ5e33+4tuACcAG4AFwALgBXRXQB6AFcB5MXAuA6nl9/0Vx/011/1V5/1/dfTPJvRtdnu/zL6beeFO/7r+fXBYbrEkt/j+i6ytXfpuvvE/ZXOnsA/a3a/l5xf7O6v1t+Xe/vOyz6HpO8yyboM8o7rfJes77bru83THk48p7TvOs27zvOO6/73vO++z7l4cgnMPQzKPopHC0N9noSSz6LJp/Gk88jyicy5TOp6qlc+VyyfDJbPpuuns6XzyfMJzTmMyrrKZ35nNJ8Ums+q7af1tvPK+4nNodEnPKp3fnc8npyez67/qVP7+/fL8hfcMjfsOhf8cjfMclfcnn9+BkOnLECP8Q58OYeyJ40eoyF6Ee/En/JHlP6mIlRVXprF4BxtAvArV0AxtEuALd2ARhHuwDc2gVgHPX/hFv9fMBddjIGeKg/WCxlCsI46u+Ga5mCcJd+sIG9UkGAW32ZbApFAHhod4Bb3eo04h3god0BbiUHYApVCNjbHeBW+QDAXT4a7qg7r7e214057vg0QhkEHkoSwq0kIdydXw4/Q3H8hjYJ3vL0WConBJhCHQaOToeBrU0BljYFmEoVgHGUKgAPnREAt84IgLuqFgAYSUEOAHszDwuAtSkHAZhLGYIpdCLgKGUIHtocZG1zkLmUIRhxDnJU1RDA1uYga5uDzKUOwhTnIEfnxcDe5iBrcyQAYGlzkKkUYhhxDrKXQgxbSwLWUohhbknA1JKAEZOAvSUBW0sC1pYEzC0JmFoSMMJyCDhaFrK3JGDtyiFgaVnI3LKQqWUhI2YhR8tC9paFrC0LWVoWMrcsZGpZyIhZyNGykL2rSIGtlQHWVgZYWhlgbmWAqZUBRiwDHK0MsLcywNbKAGsOoNUhllaHmFsdYmp1iBHrEEerQ+w5gFYI2VodYm11iKXVIeYcQCuETK0QMmIh5MgBtELI3gohWyuErDmAVolZWiFkzgG0SszUKjGjfj6gVmKOVonZcwCtFbB9HQC+ozWDbz1bvGu9iKW1AuYcQOtFTLEX1GbIaFegN0OOHEBrhuw5gNYM2XIArRuz5gDacoB3bTnAEktxXQ4wfw0AvveM8b4tiJjSJOwLIsbXsAKeNeKCiOO3D+AVbUl0AfjGs8ZPbUnIdgFoa1LWC0BblfMuB9AeC1j6gqQE0J9LmC8AOYD2ZMb7i4bt2ZTpWoHfPoB7Tj2fXzT8N1X41vkq/QHOAAAAAElFTkSuQmCC' ); 53 | } 54 | else { 55 | document.getElementById('user-head').setAttribute( 'src', Jr.avt_src ); 56 | } 57 | document.getElementById('user_edu').innerHTML=Jr.education; 58 | document.getElementById('user_name').innerHTML=Jr.user_name; 59 | document.getElementById("mdl-title").innerHTML=Jr.user_name; 60 | document.getElementById('description').innerHTML=Jr.description; 61 | document.getElementById('major').innerHTML=Jr.major; 62 | document.getElementById('user_email').innerHTML=Jr.user_email; 63 | } 64 | else { 65 | alert(Jr['error']); 66 | } 67 | } 68 | }); 69 | } 70 | function get_all(){ 71 | get_user_info(); 72 | get_others_info(); 73 | } -------------------------------------------------------------------------------- /app/static/js/post-form.js: -------------------------------------------------------------------------------- 1 | 2 | $.fn.serializeObject = function() 3 | { 4 | var o = {}; 5 | var a = this.serializeArray(); 6 | $.each(a, function() { 7 | if (o[this.name] !== undefined) { 8 | if (!o[this.name].push) { 9 | o[this.name] = [o[this.name]]; 10 | } 11 | o[this.name].push(this.value || ''); 12 | } else { 13 | o[this.name] = this.value || ''; 14 | } 15 | }); 16 | return o; 17 | }; 18 | 19 | function postForm(){ 20 | var formData = ($('form').serializeObject()); 21 | console.log(formData); 22 | var dictPost = {"plugin":"user_model","action":"validate_login","email":formData["email"],"password":formData["password"],"remember":formData["remember"]}; 23 | console.log(dictPost); 24 | $.ajax({ 25 | type: "POST", 26 | url: "/plugin/", 27 | data: (dictPost), 28 | success: function(response){ 29 | var Jr = JSON.parse(response); 30 | if(Jr['success']==true) { 31 | window.location="projects.html" 32 | } 33 | else { 34 | Materialize.toast(Jr['error'], 3000, 'rounded'); 35 | } 36 | } 37 | }); 38 | } 39 | 40 | function postForm_sign_up(){ 41 | var FormData = ($('form').serializeObject()); 42 | 43 | if (FormData["passwd"]==FormData["passwd_2"]){ 44 | var dictPost = {"plugin":"user_model","action":"create_user","email":FormData["email"],"password":FormData["passwd"],"username":FormData["username"]}; 45 | console.log(dictPost); 46 | $.ajax({ 47 | type: "POST", 48 | url: "/plugin/", 49 | data: dictPost, 50 | success: function(response){ 51 | var Jr = JSON.parse(response); 52 | if(Jr['success']==true) { 53 | window.location="projects.html" 54 | } 55 | else { 56 | Materialize.toast(Jr['error'], 3000, 'rounded'); 57 | } 58 | } 59 | }); 60 | }else {alert("Make sure the two passwords are the same")} 61 | } 62 | 63 | function logout_form(){ 64 | var dictPost = {"plugin":"user_model","action":"logout"}; 65 | console.log(dictPost); 66 | $.ajax({ 67 | type: "POST", 68 | url: "/plugin/", 69 | data: dictPost, 70 | success: function(response){ 71 | var Jr = JSON.parse(response); 72 | if(Jr['success']==true) { 73 | window.location="login.html" 74 | } 75 | else { 76 | Materialize.toast(Jr['error'], 3000, 'rounded'); 77 | } 78 | } 79 | }); 80 | } 81 | 82 | function postForm_enter(e) { 83 | if (e.keyCode == 13) { 84 | if (event.which == 13 || event.keyCode == 13) { 85 | postForm(); 86 | return false; 87 | } 88 | return true; 89 | } 90 | } -------------------------------------------------------------------------------- /app/static/js/profile-api.txt: -------------------------------------------------------------------------------- 1 | 获得当前用户的最近30条信息: 2 | data:{ 3 | "plugin":"user_model" 4 | "action":"get_message_data" 5 | } 6 | 7 | type:POST 8 | url:"/plugin/" 9 | 10 | 返回值: 11 | { 12 | "message": 13 | [ 14 | { 15 | "user_id":string ---发信息的用户的id 16 | "message":string ---信息的概述,只可能是"Comment"和"Apply for friend" 17 | "detail":string ---信息的具体内容,若是"Comment"则为评论内容,若是"Apply for friend"则为null 18 | } 19 | ] 20 | "success":string 21 | "error":string 22 | } 23 | 24 | 25 | 26 | 获得当前用户的所有好友: 27 | data:{ 28 | "plugin":"user_model" 29 | "action":"get_friend_data" 30 | } 31 | 32 | type:POST 33 | url:"/plugin/" 34 | 返回值: 35 | { 36 | "friend": 37 | [ 38 | { 39 | "user_id":string ---好友的id 40 | } 41 | ] 42 | "success":string 43 | "error":string 44 | } 45 | 46 | 47 | 48 | 通过id查询用户信息: 49 | data:{ 50 | "plugin":"user_model" 51 | "action":"get_user_data_by_id" 52 | "user_id":string 53 | } 54 | 55 | type:POST 56 | url:"/plugin/" 57 | 返回值: 58 | { 59 | "user_name":string ---用户名 60 | "user_email":string ---邮箱 61 | "avt_src":string ---头像的链接 62 | "description":string ---用户描述 63 | "major":string ---专业 64 | "education":string ---教育情况 65 | "is_friend":boolean ---当前用户与被查询的用户是否是好友 66 | 67 | "success":string 68 | "error":string 69 | } 70 | 71 | 72 | 发送好友请求: 73 | data:{ 74 | "plugin":"user_model" 75 | "action":"apply_friend" 76 | "user_id":string ---若A向B发送好友请求,则此处为B的id 77 | } 78 | type:POST 79 | url:"/plugin/" 80 | 81 | 返回值: 82 | { 83 | "success":string 84 | "error":string 85 | } 86 | 87 | 88 | 89 | 处理好友请求: 90 | data:{ 91 | "plugin":"user_model" 92 | "action":"response_friend" 93 | "user_id":string ---若B处理A向B发送的好友请求,则此处为A的id 94 | "modify":boolean ---拒绝好友请求为false 反之为true 95 | } 96 | type:POST 97 | url:"/plugin/" 98 | 99 | 返回值: 100 | { 101 | "success":string 102 | "error":string 103 | } 104 | 105 | 106 | 发送信息: 107 | data:{ 108 | "plugin":"user_model" 109 | "action":"message" 110 | "user_id":string ---若A向B发送信息,则此处为B的id 111 | "response":string ---消息内容 112 | } 113 | type:POST 114 | url:"/plugin/" 115 | 116 | 返回值: 117 | { 118 | "success":string 119 | "error":string 120 | } -------------------------------------------------------------------------------- /app/static/js/profile.js: -------------------------------------------------------------------------------- 1 | function getMessageData(){ 2 | var dictPost={"plugin":"user_model","action":"get_message_data"}; 3 | //console.log(dictPost); 4 | var jsonResp=[]; 5 | $.ajax({ 6 | type:"POST", 7 | url:"/plugin/", 8 | data:dictPost, 9 | success:function(response){ 10 | //console.log(response); 11 | jsonResp=JSON.parse(response); 12 | if(jsonResp['success']==true){ 13 | for (var i=1;i<=jsonResp.message.length;i++){ 14 | var res=get_user_info_by_id(jsonResp.message[i-1].user_id); 15 | jsonResp.message[i-1].user_name=res.user_name; 16 | jsonResp.message[i-1].avt_src=res.avt_src; 17 | } 18 | } 19 | else{ 20 | alert(jsonResp['error']); 21 | } 22 | } 23 | }); 24 | return jsonResp; 25 | } 26 | 27 | function get_user_info_by_id(id) { 28 | var dictPost = {"plugin":"user_model","action":"get_user_data_by_id","user_id":id}; 29 | //console.log(dictPost); 30 | var jsonResp=[]; 31 | $.ajax({ 32 | type: "POST", 33 | url: "/plugin/", 34 | data: dictPost, 35 | success: function(response){ 36 | //console.log(response); 37 | jsonResp = JSON.parse(response); 38 | if(jsonResp['success']==true) { 39 | } 40 | else { 41 | alert(jsonResp['error']); 42 | } 43 | } 44 | }); 45 | return jsonResp; 46 | } 47 | 48 | function getFriendData(){ 49 | var dictPost={"plugin":"user_model","action":"get_friend_data"}; 50 | console.log(dictPost); 51 | var jsonResp=[]; 52 | $.ajax({ 53 | type:"POST", 54 | url:"/plugin/", 55 | data:dictPost, 56 | success:function(response){ 57 | //console.log(response); 58 | jsonResp=JSON.parse(response); 59 | if(jsonResp['success']==true){ 60 | for (var i=1;i<=jsonResp.friend.length;i++){ 61 | var res=get_user_info_by_id(jsonResp.friend[i-1].user_id); 62 | jsonResp.friend[i-1].user_name=res.user_name; 63 | jsonResp.friend[i-1].avt_src=res.avt_src; 64 | jsonResp.friend[i-1].user_email=res.user_email; 65 | } 66 | } 67 | else{ 68 | alert(jsonResp['error']); 69 | } 70 | } 71 | }); 72 | return jsonResp; 73 | } 74 | 75 | function prepareMsgData(i,obj){ 76 | return function(){ 77 | var id=obj.message[i-1].user_name; 78 | var hr="user_name?user_id="+obj.message[i-1].user_id; 79 | var msg=obj.message[i-1].detail; 80 | document.getElementById("usr_hr").innerHTML=id; 81 | document.getElementById("usr_hr").href=hr; 82 | document.getElementById("usr_msg").innerHTML=msg; 83 | } 84 | } 85 | 86 | function sendAgree(i,obj,bool){ 87 | return function(){ 88 | var friend_id=obj.message[i-1].user_id; 89 | var dictPost={"plugin":"user_model","action":"response_friend","user_id":friend_id,"modify":bool}; 90 | //console.log(dictPost); 91 | var jsonResp=[]; 92 | $.ajax({ 93 | type:"POST", 94 | url:"/plugin/", 95 | data:dictPost, 96 | success:function(response){ 97 | //console.log(response); 98 | jsonResp=JSON.parse(response); 99 | if(jsonResp['success']==true){ 100 | alert("Successfully submitted!"); 101 | window.location.reload(); 102 | } 103 | else{ 104 | alert(jsonResp['error']); 105 | } 106 | } 107 | }); 108 | } 109 | } 110 | 111 | function sendResponse(i,obj){ 112 | return function(){ 113 | var user_id=document.getElementById("this_is_a_user_name").innerHTML; 114 | var friend_id=obj.message[i-1].user_id; 115 | var res_content=document.getElementById("msg-res").value; 116 | if(res_content==null||res_content.length==0){ 117 | alert("Empty response!"); 118 | return; 119 | } 120 | var dictPost={"plugin":"user_model","action":"message","user_id":friend_id,"response":res_content}; 121 | //console.log(dictPost); 122 | var jsonResp=[]; 123 | $.ajax({ 124 | type:"POST", 125 | url:"/plugin/", 126 | data:dictPost, 127 | success:function(response){ 128 | console.log(response); 129 | jsonResp=JSON.parse(response); 130 | if(jsonResp['success']==true){ 131 | alert("Successfully submitted!"); 132 | } 133 | else{ 134 | alert(jsonResp['error']); 135 | } 136 | } 137 | }); 138 | } 139 | } -------------------------------------------------------------------------------- /app/static/js/scripts.js: -------------------------------------------------------------------------------- 1 | // Focus function for input 2 | _focus = function(elem) { 3 | var _this = $(elem); 4 | _this.siblings('.placeholder').addClass('focus'); 5 | _this.siblings('.bottom-liner').addClass('lined'); 6 | _this.siblings('.highlight').addClass('light'); 7 | }; 8 | 9 | // Blur function for input 10 | _blur = function(elem) { 11 | var _this = $(elem); 12 | 13 | // Reset hightlight for input 14 | _this.siblings('.highlight').addClass('no-light'); 15 | setTimeout(function() { 16 | _this.siblings('.highlight').removeClass('no-light'); 17 | _this.siblings('.highlight').removeClass('light'); 18 | }, 200); 19 | 20 | // If input is empty return to normal 21 | if (_this.val() == 0) { 22 | _this.siblings('.placeholder').removeClass('focus'); 23 | _this.siblings('.bottom-liner').removeClass('lined'); 24 | } 25 | }; 26 | 27 | $(function() { 28 | // input On focus 29 | $('.material-input').on('focus', function() { 30 | _focus(this); 31 | $(this).select(); 32 | }); 33 | 34 | // input On blur 35 | $('.material-input').on('blur', function() { 36 | _blur(this); 37 | }); 38 | 39 | // Enter fake credentials and show button 40 | $('input#password').on('keyup', function() { 41 | if (!$('#username').val() <= 0) { 42 | if ($('input#password').val().length >= 5) { 43 | $('.btn-custom').removeClass("not-visible"); 44 | } 45 | } 46 | if ($('input#password').val().length <= 5) { 47 | $('.btn-custom').addClass("not-visible"); 48 | } 49 | }); 50 | 51 | // Ripple effect 52 | $('#flow-button').on("click", function(event) { 53 | // Get mouse coordinates 54 | var offset = $(this).offset(); 55 | var MousePosX = (event.pageX - offset.left); 56 | var MousePosY = (event.pageY - offset.top); 57 | 58 | // Append svg with coordinates in circle element 59 | $('#flow-button').append(''); 60 | 61 | // Animate the circle radius and opacity with velocity 62 | $('.ripple-svg:last .circle').velocity({ 63 | r: 300, 64 | opacity: 0 65 | }, 600); 66 | 67 | // If there are more than 5, delete all of them but the last one - Wait 600ms (animation time) 68 | if ($('.ripple-svg').length > 5) { 69 | setTimeout(function() { 70 | $('.ripple-svg:not(:last-child)').remove(); 71 | }, 600); 72 | } 73 | }); 74 | 75 | }); 76 | -------------------------------------------------------------------------------- /app/static/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | BioHub Login 9 | 10 | 11 | 12 | 13 | 14 | 81 | 82 | 83 |
84 |
85 |
86 |
87 | 88 | 90 |

 BioHub

91 |
92 |
93 |
94 | 95 |
96 |
97 |
98 | person 99 | 100 | 101 |
102 |
103 |
104 |
105 | lock 106 | 107 | 108 |
109 |
110 |
111 | 115 |
116 |
117 |
118 |
119 | 122 |
123 |
124 | 131 |
132 | 133 |
134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /app/static/plugins.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Plugins Status 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 37 | 38 | 39 |
40 | 45 |
46 |
47 |

Plugins Status

48 | 49 | 50 |
51 | 52 |
53 | 54 |
55 | 56 |
57 |
58 | 59 |
60 |
61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /app/static/project-api.txt: -------------------------------------------------------------------------------- 1 | 获得project数据: 2 | data:{ 3 | "plugin":"pano", 4 | "action":"get_project_data" 5 | } 6 | type:POST 7 | url:"/plugin/" 8 | 9 | 返回值: 10 | { 11 | "project": ---包含当前用户的所有project 12 | [ 13 | { 14 | "project_id":string 相应的project的唯一标记值 15 | "project_name":string project的标题 16 | "project_remark":string project的备注 17 | "user_id":string project作者的user id 18 | "private":string,"Public" or "Private" 仅有两个可能值,表示相应project的权限状态 19 | "create_time":string project创建时的服务器时间 20 | "last_update_time":string project最近一次被修改的服务器时间 21 | "img_src":base64 project的缩略图的base64 22 | } 23 | ] 24 | } 25 | 26 | 创建project: 27 | data:{ 28 | "plugin":"pano", 29 | "action":"new", 30 | "project_name":string, 31 | "project_remark":string, 32 | "private":string,"Public" or "Private" 33 | } 34 | type:POST 35 | url:"/plugin/" 36 | 37 | 返回值: 38 | { 39 | "project_id":string 40 | "success":boolean 41 | "error":错误信息 42 | } 43 | 44 | 删除project: 45 | data: 46 | { 47 | "plugin":"pano", 48 | "action":"delete", 49 | "project_id":string 50 | } 51 | type:POST 52 | url:"/plugin/" 53 | 54 | 返回值: 55 | { 56 | "success":boolean 57 | "error":错误信息 58 | } -------------------------------------------------------------------------------- /app/static/signup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | BioHub 9 | 10 | 11 | 12 | 13 | 79 | 82 | 83 | 84 |
85 |
86 |
87 |
88 | 89 | 90 |

 BioHub

91 |
92 |
93 |
94 | 95 |
96 |
97 |
98 | person 99 | 100 | 101 |
102 |
103 |
104 |
105 | email 106 | 107 | 108 |
109 |
110 |
111 |
112 | lock 113 | 114 | 115 |
116 |
117 |
118 |
119 | repeat 120 | 121 | 122 |
123 |
124 |
125 |
126 |
127 | Sign up now 128 |
129 |
130 | 131 |
132 |
133 |
134 |
135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /app/static/simulation_form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | simulation 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 73 | 74 | 75 |
76 | 77 | 82 | 83 | 84 |
85 |
86 |

Simulation Pool

87 | 88 | 89 |
90 |
91 |

Description

92 |
93 |

After you have run the module 'Pathway_finder', you may get some nodes. Here you can use this module to simulate the concentration of the substances involved in this reaction.

94 |

Simulation is a simulator designed to solve the concentration function with respect to time based on the differential equations given by the user. After the user has submitted control functions, this module will upload relative data to a high performance server, which will be able to return results in minutes or hours, based on the quantity of control functions and the width of time domain. The concentration of all nodes will be displayed visualized, meanwhile a proper notice will pop up if an instability is detected in order to warn the user to be cautious about the result after the critical point.

95 | 96 |
98 |
99 | 100 |
101 |
102 | 103 |

Control functions

104 |
105 |
106 |
107 | 108 |
109 |
110 | 111 | 112 |
113 |
114 |
115 |
116 |
117 | 118 | 119 |
120 |
121 | 122 |
123 | 124 |

Result

125 |
126 |
127 |
128 |
129 |
130 | 131 |
132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /app/views/__init__.py: -------------------------------------------------------------------------------- 1 | from .home import home 2 | from .plugin import plugin 3 | -------------------------------------------------------------------------------- /app/views/home.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, redirect, url_for, request 2 | from flask_login import current_user, login_required, login_user, logout_user 3 | from models import User 4 | from database import session 5 | 6 | home = Blueprint('home', __name__) 7 | 8 | 9 | @home.route('/') 10 | def index(): 11 | if current_user.is_authenticated: 12 | return redirect(url_for('static', filename='projects.html')) 13 | return redirect(url_for('static', filename='login.html')) 14 | 15 | 16 | @home.route('/validateLogin', methods=['POST']) 17 | def login(): 18 | username = request.values['username'] 19 | password = request.values['password'] 20 | return username 21 | 22 | 23 | @home.route('/login/') 24 | def login_test(id): 25 | login_user(session.query(User).get(id)) 26 | return redirect(url_for('home.index')) 27 | 28 | 29 | @home.route('/logout') 30 | def logout_test(): 31 | logout_user() 32 | return redirect(url_for('home.index')) 33 | -------------------------------------------------------------------------------- /app/views/plugin.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, redirect, url_for, request 2 | from flask_login import current_user, login_required, login_user, logout_user 3 | from models import User 4 | from plugin import plugin_manager 5 | import json 6 | 7 | plugin = Blueprint('plugin', __name__) 8 | 9 | 10 | @plugin.route('/', methods=['GET', 'POST']) 11 | def plugin_request(): 12 | plugin_name = request.values['plugin'] if 'plugin' in request.values else '' 13 | req = {v: request.values[v] for v in request.values} 14 | if 'file' in request.files and request.files['file'].filename: 15 | req['file'] = request.files['file'] 16 | print('Got a file:', request.files['file'].filename) 17 | rtv = plugin_manager.send_request(plugin_name, req) 18 | return json.dumps(rtv) 19 | -------------------------------------------------------------------------------- /config.docker.py: -------------------------------------------------------------------------------- 1 | from os import getenv, system 2 | from os.path import exists 3 | from time import time 4 | 5 | if getenv('BIOHUB_DB_HOST'): 6 | dbhost = getenv('BIOHUB_DB_HOST') 7 | else: 8 | dbhost = 'db' 9 | if getenv('BIOHUB_DB_USER'): 10 | dbuser = getenv('BIOHUB_DB_USER') 11 | dbpassword = getenv('BIOHUB_DB_PASSWORD') 12 | else: 13 | dbuser = 'root' 14 | dbpassword = getenv(dbhost.upper() + '_ENV_MYSQL_ROOT_PASSWORD') 15 | 16 | if not exists('.not_first'): 17 | import MySQLdb 18 | c = MySQLdb.connect(dbhost, dbuser, dbpassword) 19 | c.send_query('CREATE DATABASE igem') 20 | try: c.commit() 21 | except: pass 22 | c.close() 23 | df = 'biobricks.sql.gz' 24 | bf = 'biobricks.sql' 25 | system('wget http://parts.igem.org/partsdb/download.cgi?type=parts_sql -O "%s"' % df) 26 | system('gunzip "%s"' % df) 27 | system('mysql "-h%s" "-u%s" "-p%s" "%s" <"%s"' % (dbhost, dbuser, dbpassword, 'igem', bf)) 28 | system('mysql "-h%s" "-u%s" "-p%s" "%s" < ncbi_562.sql' % (dbhost, dbuser, dbpassword, 'igem')) 29 | with open('.not_first', 'w') as f: 30 | pass 31 | 32 | DATABASE_URI = 'mysql://%s:%s@%s/igem' % (dbuser, dbpassword, dbhost) 33 | SECRET_KEY = str(time) 34 | -------------------------------------------------------------------------------- /config.py.example: -------------------------------------------------------------------------------- 1 | # cp config.py.example config.py 2 | # then replace the 'password' with the actual one. 3 | # DO NOT enter the password into config.py.example 4 | 5 | DATABASE_URI = 'mysql://igem:password@biohub.tech/igem' 6 | # ^^^^^^^^ 7 | 8 | SECRET_KEY = 'develop_key' 9 | -------------------------------------------------------------------------------- /database.py: -------------------------------------------------------------------------------- 1 | import app 2 | 3 | from sqlalchemy import * 4 | from sqlalchemy.dialects.mysql import * 5 | from sqlalchemy.orm import sessionmaker 6 | from sqlalchemy.ext.declarative import declarative_base 7 | import sys 8 | 9 | TableBase = declarative_base() 10 | engine = create_engine(app.app.config['DATABASE_URI']) 11 | DBSession = sessionmaker(bind=engine) 12 | 13 | if 'app' in sys.modules: 14 | print('database imported in flask') 15 | 16 | from flask import g 17 | from app import app 18 | 19 | 20 | def get_session(): 21 | s = getattr(g, '_dbsession', None) 22 | if s is None: 23 | s = g._dbsession = DBSession() 24 | print('new session') 25 | else: 26 | print('get session') 27 | return s 28 | 29 | 30 | @app.teardown_appcontext 31 | def teardown_session(exception): 32 | s = getattr(g, '_dbsession', None) 33 | if s is not None: 34 | s.close() 35 | print('close session') 36 | 37 | 38 | from werkzeug.local import LocalProxy 39 | 40 | session = LocalProxy(get_session) 41 | 42 | else: 43 | print('database imported outside flask') 44 | session = DBSession() 45 | -------------------------------------------------------------------------------- /models/__init__.py: -------------------------------------------------------------------------------- 1 | from .document import Document 2 | from .plugin_document import PluginDocument 3 | from .node import Node 4 | from .link import Link 5 | from .user import User 6 | from plugins.dbupload.dbprofile import * 7 | 8 | """Each table in the database and not belonged to a plugin has a model here, so that we can use SQLAlchemy to connect to the database.""" -------------------------------------------------------------------------------- /models/document.py: -------------------------------------------------------------------------------- 1 | from .plugin_document import PluginDocument 2 | from database import TableBase, Column, Integer, String, ForeignKey 3 | 4 | 5 | class Document(TableBase): 6 | """An object refer to an actual plugin-managed document. 7 | 8 | Every actual document is not only saved in plugins' table, but also has an entry here, so that we can easily get all documents belong to a specific user.""" 9 | 10 | __tablename__ = 'document' 11 | 12 | def __init__(self, plugin_name: str, doc: PluginDocument): 13 | super().__init__() 14 | self.owner = doc.owner 15 | self.plugin_name = plugin_name 16 | self.plugin_document_id = doc.id 17 | 18 | document_id = Column(Integer(), primary_key=True) 19 | owner = Column(Integer(), ForeignKey('user.id')) 20 | plugin_name = Column(String(256)) 21 | plugin_document_id = Column(Integer()) 22 | -------------------------------------------------------------------------------- /models/link.py: -------------------------------------------------------------------------------- 1 | from database import TableBase, Column, String, ForeignKey, Integer 2 | 3 | 4 | class Link(TableBase): 5 | """A link between two nodes, for path_finder.""" 6 | 7 | __tablename__ = 'link' 8 | link_id = Column(Integer, primary_key=True, autoincrement=True) 9 | tax_id = Column(String(10)) 10 | node_a_id = Column(String(10)) 11 | node_b_id = Column(String(10)) 12 | link_catalog = Column(String(256)) 13 | link_name = Column(String(256)) 14 | -------------------------------------------------------------------------------- /models/list.config: -------------------------------------------------------------------------------- 1 | 10710 2 | 10633 3 | 1423 4 | 155892 5 | 2097 6 | 668 7 | 1142 8 | 294 9 | 3055 10 | 44689 11 | 5911 12 | 2903 13 | 35128 14 | 33169 15 | 162425 16 | 5346 17 | 5207 18 | 4853 19 | 5141 20 | 4932 21 | 5334 22 | 4896 23 | 5270 24 | 3702 25 | 76872 26 | 88036 27 | 15368 28 | 4556 29 | 34305 30 | 4470 31 | 4577 32 | 3880 33 | 4155 34 | 4530 35 | 3218 36 | 3197 37 | 3689 38 | 6499 39 | 7739 40 | 6239 41 | 7014 42 | 64391 43 | 37639 44 | 7719 45 | 35529 46 | 169440 47 | 139644 48 | 7215 49 | 32281 50 | 6613 51 | 7137 52 | 6999 53 | 6083 54 | 1051067 55 | 282301 56 | 27923 57 | 45351 58 | 34765 59 | 386100 60 | 80999 61 | 317513 62 | 6359 63 | 109885 64 | 54126 65 | 95463 66 | 79327 67 | 7668 68 | 84072 69 | 7070 70 | 10228 71 | 6386 72 | 8344 73 | 28377 74 | 9685 75 | 9031 76 | 42414 77 | 9615 78 | 10036 79 | 10141 80 | 59463 81 | 8090 82 | 10088 83 | 10090 84 | 10181 85 | 105023 86 | 8930 87 | 8081 88 | 10116 89 | 9544 90 | 7757 91 | 31032 92 | 69293 93 | 481459 94 | 8364 95 | 8355 96 | 59729 97 | 7955 -------------------------------------------------------------------------------- /models/node.py: -------------------------------------------------------------------------------- 1 | from database import TableBase, Column, String 2 | 3 | 4 | class Node(TableBase): 5 | """A bio-part which can be added to biopano.""" 6 | 7 | __tablename__ = 'node' 8 | node_id = Column(String(256), primary_key=True) 9 | node_name = Column(String(256)) 10 | node_catalog = Column(String(256)) 11 | -------------------------------------------------------------------------------- /models/plugin_document.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.ext.declarative import declared_attr 2 | 3 | from database import Column, Integer, String, ForeignKey, Text 4 | 5 | 6 | class PluginDocument(object): 7 | """Abstract class for all plugins to make their own document type.""" 8 | 9 | def __init__(self): 10 | super().__init__() 11 | if self.__class__ is PluginDocument: 12 | raise NotImplementedError 13 | 14 | id = Column(Integer(), primary_key=True) 15 | @declared_attr 16 | def owner(cls): 17 | return Column(Integer(), ForeignKey('user.id')) 18 | title = Column(String(256)) 19 | last_modified = Column(Integer()) 20 | description = Column(Text()) 21 | -------------------------------------------------------------------------------- /models/user.py: -------------------------------------------------------------------------------- 1 | from database import TableBase, Column, Integer, String, session, Text, MEDIUMTEXT 2 | from flask_login import UserMixin 3 | import hashlib 4 | import random 5 | import string 6 | import os 7 | 8 | 9 | def random_string(N): 10 | return ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for i in range(N)) 11 | 12 | 13 | class User(TableBase, UserMixin): 14 | """A user.""" 15 | 16 | __tablename__ = 'user' 17 | id = Column(Integer, primary_key=True) 18 | email = Column(String(63), unique=True) 19 | passwordhash = Column(String(127), nullable=False) 20 | salt = Column(String(127), nullable=False) 21 | username = Column(String(127)) 22 | if os.getenv('FLASK_TESTING'): 23 | avatar = Column(String(16777215)) 24 | else: 25 | avatar = Column(MEDIUMTEXT()) 26 | description = Column(Text()) 27 | education = Column(Text()) 28 | major = Column(Text()) 29 | 30 | def __init__(self, email, password, username): 31 | self.email = email 32 | self.set_password(password) 33 | self.username = username 34 | 35 | def set_password(self, password): 36 | """hash and save the password""" 37 | self.salt = random_string(10) 38 | s = hashlib.sha256() 39 | s.update(password.encode('utf-8')) 40 | s.update(self.salt.encode('utf-8')) 41 | self.passwordhash = s.hexdigest() 42 | 43 | def check_password(self, password): 44 | """hash and check the password""" 45 | s = hashlib.sha256() 46 | s.update(password.encode('utf-8')) 47 | s.update(self.salt.encode('utf-8')) 48 | return self.passwordhash == s.hexdigest() 49 | 50 | @classmethod 51 | def get_user_by_email(cls, email): 52 | return session.query(cls).filter_by(email=email).first() 53 | 54 | @classmethod 55 | def get_user_by_id(cls, id): 56 | return session.query(cls).get(id) 57 | -------------------------------------------------------------------------------- /ncbiuploader.py: -------------------------------------------------------------------------------- 1 | from plugins.dbupload.uploaddb import upload 2 | from plugins.dbupload.dbprofile import * 3 | from config import DATABASE_URI 4 | 5 | ''' 6 | Change filepath = your data file from ncbi 7 | Change column_num = Column number of data file 8 | ''' 9 | 10 | filepath = r"" 11 | column_num = 0 12 | 13 | if not DATABASE_URI.startswith('mysql+pymysql://'): 14 | DATABASE_URI = 'mysql+pymysql://'+DATABASE_URI.split('://')[1] 15 | upload(DATABASE_URI, filepath, gene_commit, column_num, cache_size=100000, echo=True, log=True) 16 | -------------------------------------------------------------------------------- /plugin.py: -------------------------------------------------------------------------------- 1 | """Everything about plugins.""" 2 | 3 | import importlib 4 | 5 | import app 6 | from database import session, engine 7 | from models import Document, PluginDocument 8 | 9 | 10 | class Plugin: 11 | def __init__(self): 12 | self.documents = Documents(self) 13 | try: self.name 14 | except: self.name = self.__class__.__name__.lower() 15 | try: self.description 16 | except: self.description = 'This plugin has no description.' 17 | if self.__class__ is Plugin: 18 | raise NotImplementedError 19 | 20 | @property 21 | def user(self): 22 | return app.current_user 23 | 24 | def process(self, request): 25 | pass 26 | 27 | def unload(self): 28 | pass 29 | 30 | 31 | class PluginManager: 32 | plugin_directory = 'plugins' 33 | 34 | def __init__(self): 35 | self.plugins = {} 36 | self.modules = {} 37 | 38 | # now reload and unload are very unstable, do not use 39 | # FIXME: [wzb@07-31] if plugin is in a directory, reload can only reload the __init__.py 40 | 41 | def load_plugin(self, name, reload=False): 42 | if name in self.plugins: 43 | if reload: 44 | self.modules[name] = importlib.reload(self.modules[name]) 45 | self.plugins[name] = self.modules[name].__plugin__ 46 | return self.plugins[name] 47 | self.modules[name] = importlib.import_module(self.plugin_directory + '.' + name) 48 | self.plugins[name] = self.modules[name].__plugin__ 49 | return self.plugins[name] 50 | 51 | def get_plugins(self): 52 | return self.plugins 53 | 54 | def send_request(self, plugin, request): 55 | if plugin not in self.plugins: 56 | return {'success': False, 'reason': 'plugin not found'} 57 | try: 58 | rtv = self.plugins[plugin].process(request) 59 | if 'success' not in rtv: 60 | rtv['success'] = True 61 | except Exception as e: 62 | rtv = {'success': False, 'reason': type(e).__name__ + ': ' + str(e)} 63 | return rtv 64 | 65 | 66 | plugin_manager = PluginManager() 67 | 68 | 69 | class Documents: 70 | def __init__(self, plugin: Plugin): 71 | self.plugin = plugin 72 | self.type_name = None 73 | self.document_table = None 74 | 75 | def set_document_type(self, name: str): 76 | self.type_name = name 77 | 78 | def set_document_table(self, table): 79 | self.document_table = table 80 | try: 81 | table.__table__.create(engine) 82 | except: 83 | pass 84 | 85 | def get(self, pid): 86 | return session.query(self.document_table).get(pid) 87 | 88 | def list(self, owner): 89 | return session.query(self.document_table).filter(self.document_table.owner == owner).all() 90 | 91 | def create(self, pdoc: PluginDocument): 92 | session.add(pdoc) 93 | session.commit() 94 | doc = Document(self.plugin.name, pdoc) 95 | session.add(doc) 96 | session.commit() 97 | 98 | @staticmethod 99 | def update(pdoc: PluginDocument): 100 | session.add(pdoc) 101 | session.commit() 102 | 103 | def delete(self, pdoc: PluginDocument): 104 | # XXX: This can not be fixed. --Hypercube 105 | session.delete(pdoc) 106 | session.commit() 107 | -------------------------------------------------------------------------------- /plugins/ABACUS/__init__.py: -------------------------------------------------------------------------------- 1 | from .abacus import __plugin__ -------------------------------------------------------------------------------- /plugins/ABACUS/abacus.py: -------------------------------------------------------------------------------- 1 | """This is an ABACUS plugin. 2 | request = { 3 | "action": "design" or "singleMutationScan" 4 | "id": user_id 5 | "inpath": inputFilePath 6 | "filename": filename 7 | "amount": amount #optional 8 | "tag":tag 9 | "design": desginpath 10 | "mutationScan": scanpath 11 | "abacuspath": path 12 | } 13 | """ 14 | from time import ctime 15 | from subprocess import Popen 16 | from os import mkdir, listdir, getcwd, chdir, path 17 | import os 18 | from shutil import rmtree 19 | from plugin import Plugin 20 | from zipfile import ZipFile 21 | import re 22 | 23 | from .callabacus import InternalError, FileFormatError 24 | 25 | abacuspath = 'plugins/ABACUS/ABACUS/bin/' 26 | designpath = 'plugins/ABACUS/design.py' 27 | mutationpath = 'plugins/ABACUS/singleMutationScan.py' 28 | 29 | 30 | class ABACUS(Plugin): 31 | name = 'ABACUS' 32 | 33 | def process(self, request): 34 | print("ABACUS plugin got a request:" + str(request)) 35 | if not path.exists(abacuspath): 36 | return dict(status="Empty") 37 | 38 | filepath = abacuspath + 'pdbs/' + str(self.user.id) + '/' 39 | 40 | if request["action"] == "design": 41 | print("Cleaning!") 42 | try: 43 | rmtree(filepath) # Alert! Clean directory even it is existed 44 | except: 45 | pass 46 | mkdir(filepath) 47 | 48 | if request['demo'] == "True": 49 | print("demo!") 50 | Popen(['python3', designpath, filepath, str(self.user.id) + '.pdb', 51 | request['amount'], abacuspath, request['demo']]) 52 | return dict(status="Running", demo="True") 53 | 54 | print('Gonna save file') 55 | request['file'].save(filepath + str(self.user.id) + '.pdb') 56 | print("File saved") 57 | 58 | try: 59 | tag = request["tag"] 60 | except KeyError: 61 | Popen(['python3', designpath, filepath, str(self.user.id) + '.pdb', 62 | request['amount'], abacuspath, request['demo']]) 63 | else: 64 | Popen(['python3', designpath, filepath, str(self.user.id) + '.pdb', 65 | request['amount'], abacuspath, request['demo'], tag]) 66 | return dict(status="Running") 67 | 68 | elif request["action"] == 'getstatus': 69 | if not path.exists(filepath): 70 | return dict(status='Clean') 71 | 72 | ferr = open(filepath + 'err.log', 'r') 73 | f = open(filepath + 'status.log', 'r') 74 | flag = False 75 | 76 | while 1: 77 | log = ferr.read(9600) 78 | if log.find('Exception') != -1: 79 | return dict(status='Failed', reason=log) 80 | if not log: 81 | break 82 | 83 | while 1: 84 | log = f.read(9600) 85 | if log.find('Done') != -1: 86 | flag = True 87 | break 88 | elif log.find('Error') != -1: 89 | return dict(status='Failed', reason=log) 90 | if not log: 91 | break 92 | # Compress file 93 | if flag: 94 | cur_path = getcwd() 95 | if not path.exists('app/static/downloads'): 96 | mkdir('app/static/downloads') 97 | 98 | target = ZipFile('app/static/downloads/' + str(self.user.id) + '.zip', 'w') 99 | allfile = listdir(filepath) 100 | chdir(filepath) 101 | for file in allfile: 102 | if re.match(r'.*_design_.*\.pdb', file) or re.match(r'.*_design_.*\.fasta', file): 103 | target.write(file) 104 | target.close() 105 | chdir(cur_path) 106 | return dict(url='/static/downloads/' + str(self.user.id) + '.zip', status='Success') 107 | else: 108 | return dict(status='Running') 109 | else: 110 | return {"success": False, "reason": "unknown action: " + request["action"]} 111 | 112 | 113 | __plugin__ = ABACUS() 114 | -------------------------------------------------------------------------------- /plugins/ABACUS/callabacus.py: -------------------------------------------------------------------------------- 1 | from subprocess import Popen 2 | from os import getcwd 3 | 4 | 5 | class InternalError(Exception): 6 | pass 7 | 8 | 9 | class FileFormatError(Exception): 10 | pass 11 | 12 | 13 | def ABACUS_prepare(path, file, abacuspath): 14 | 15 | print(getcwd()) 16 | print(path+file) 17 | p = Popen(["ABACUS_prepare", path+file]) 18 | while p.poll() is None: 19 | pass 20 | if p.poll(): 21 | f = open(path+'err.log', 'r') 22 | exp = f.read(int(1E4)) 23 | if exp.find("no protein chain detected") != -1: 24 | raise FileFormatError("File format error! No protein chain detected!") 25 | else: 26 | raise InternalError("We are sorry, something wrong happened") 27 | 28 | return p.poll() 29 | 30 | 31 | def ABACUS_S1S2(path, file, abacuspath): 32 | 33 | print(getcwd()) 34 | print(path+file) 35 | p = Popen(["ABACUS_S1S2", path+file]) 36 | while p.poll() is None: 37 | pass 38 | if p.poll(): 39 | raise InternalError("We are sorry, something wrong happened") 40 | 41 | return p.poll() 42 | 43 | 44 | def ABACUS_vdwEtable(path, file, abacuspath): 45 | 46 | p = Popen(["ABACUS_vdwEtable", path+file]) 47 | while p.poll() is None: 48 | pass 49 | if p.poll(): 50 | raise InternalError("We are sorry, something wrong happened") 51 | 52 | return p.poll() 53 | 54 | 55 | def ABACUS_design(path, file, abacuspath, num, tag=None): 56 | 57 | if tag is None: 58 | p = Popen(["ABACUS_design", path + file, str(num)]) 59 | else: 60 | p = Popen(["ABACUS_design", path + file, str(num), tag]) 61 | 62 | while p.poll() is None: 63 | pass 64 | if p.poll(): 65 | raise InternalError("We are sorry, something wrong happened") 66 | 67 | return p.poll() 68 | 69 | 70 | def ABACUS_singleMutationScan(path, file, abacuspath, output, size=None): 71 | 72 | if size is None: 73 | p = Popen(["ABACUS_singleMutationScan", path+file, output]) 74 | else: 75 | p = Popen(["ABACUS_singleMutationScan", path + file, output, size]) 76 | 77 | while p.poll() is None: 78 | pass 79 | if p.poll(): 80 | raise InternalError("We are sorry, something wrong happened") 81 | 82 | return p.poll() 83 | -------------------------------------------------------------------------------- /plugins/ABACUS/design.py: -------------------------------------------------------------------------------- 1 | from callabacus import ABACUS_design, ABACUS_prepare, ABACUS_S1S2, ABACUS_singleMutationScan, ABACUS_vdwEtable 2 | from callabacus import InternalError, FileFormatError 3 | import sys 4 | from os import chdir, rename 5 | import time 6 | 7 | 8 | def design(path, file, amount, abacuspath, demo=False, tag=None): 9 | if demo == 'True': 10 | demo = True 11 | fp = open(path + 'err.log', 'w') 12 | fp.close() 13 | else: 14 | demo = False 15 | 16 | try: 17 | f = open(path + 'status.log', 'a') 18 | except: 19 | return -1; 20 | 21 | try: 22 | amount = int(amount) 23 | except ValueError: 24 | f.write("[Error]Invalid value\n") 25 | f.close() 26 | return -2 27 | 28 | try: 29 | f.write("[Info]Preparing\n") 30 | f.close() 31 | if not demo: 32 | ABACUS_prepare(path, file, abacuspath) 33 | f = open(path + 'status.log', 'a') 34 | f.write("[Info]Prepared\n") 35 | 36 | f.write("[Info]Processing...\n") 37 | f.close() 38 | if not demo: 39 | ABACUS_S1S2(path, file, abacuspath) 40 | f = open(path + 'status.log', 'a') 41 | f.write("[Info]Processed...\n") 42 | 43 | f.write("[Info]Generating energy table\n") 44 | f.close() 45 | if not demo: 46 | ABACUS_vdwEtable(path, file, abacuspath) 47 | f = open(path + 'status.log', 'a') 48 | f.write("[Info]Generate energy table\n") 49 | 50 | f.write("[Info]Designing\n") 51 | f.close() 52 | if not demo: 53 | if tag is None: 54 | ABACUS_design(path, file, abacuspath, amount) 55 | else: 56 | ABACUS_design(path, file, abacuspath, amount, tag) 57 | else: 58 | print("I am gonna sleep") 59 | time.sleep(10) 60 | fp = open(path + 'demo_design_demo.fasta', 'w') 61 | fp.close() 62 | fp = open(path + 'demo_design_demo.pdb', 'w') 63 | fp.close() 64 | 65 | f = open(path + 'status.log', 'a') 66 | f.write("[Info]Done!\n") 67 | 68 | except InternalError: 69 | f.write("[Error]Some internal error occured, we are sorry\n") 70 | except FileFormatError: 71 | f.write("[Error]File format error!\n") 72 | f.close() 73 | return "0" 74 | 75 | if __name__ == '__main__': 76 | if len(sys.argv) == 6: 77 | design(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]) 78 | elif len(sys.argv) == 7: 79 | design(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6]) 80 | else: 81 | print("Parameter error\n") -------------------------------------------------------------------------------- /plugins/ABACUS/singleMutationScan.py: -------------------------------------------------------------------------------- 1 | from subprocess import Popen 2 | from callabacus import ABACUS_design, ABACUS_prepare, ABACUS_S1S2, ABACUS_singleMutationScan, ABACUS_vdwEtable 3 | from callabacus import InternalError, FileFormatError 4 | import sys 5 | from os import chdir, rename 6 | from shutil import copyfile 7 | 8 | def singleMutationScan(path, file, abacuspath, output, size=None, demo=False): 9 | try: 10 | chdir(abacuspath) 11 | f = open(path + 'status.log', 'a') 12 | except: 13 | return -1; 14 | 15 | if size is not None: 16 | try: 17 | size = int(size) 18 | except ValueError: 19 | f.write("[Error]Invalid value\n") 20 | f.close() 21 | return -2 22 | 23 | try: 24 | f.write("[Info]Preparing\n") 25 | f.close() 26 | if not demo: 27 | ABACUS_prepare(path, file, abacuspath) 28 | f = open(path + 'status.log', 'a') 29 | f.write("[Info]Prepared\n") 30 | 31 | f.write("[Info]Processing...\n") 32 | f.close() 33 | if not demo: 34 | ABACUS_S1S2(path, file, abacuspath) 35 | f = open(path + 'status.log', 'a') 36 | f.write("[Info]Processed...\n") 37 | 38 | f.write("[Info]Single mutation scaning\n") 39 | f.close() 40 | if not demo: 41 | if size is None: 42 | ABACUS_design(path, file, abacuspath, output) 43 | else: 44 | ABACUS_design(path, file, abacuspath, output, size) 45 | f = open(path + 'status.log', 'a') 46 | f.write("[Info]Done!\n") 47 | 48 | 49 | except InternalError: 50 | f.write("[Error]Some internal error occured, we are sorry\n") 51 | except FileFormatError: 52 | f.write("[Error]File format error!\n") 53 | 54 | f.close() 55 | return "0" 56 | 57 | if __name__ == '__main__': 58 | if len(sys.argv) == 6: 59 | singleMutationScan(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5]) 60 | elif len(sys.argv) == 7: 61 | singleMutationScan(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], sys.argv[5], sys.argv[6]) 62 | else: 63 | print("Parameter error\n") -------------------------------------------------------------------------------- /plugins/ABACUS/suspiciousSites.py: -------------------------------------------------------------------------------- 1 | from subprocess import Popen 2 | 3 | 4 | def suspiciousSites(path, file, output): 5 | pass 6 | -------------------------------------------------------------------------------- /plugins/README.md: -------------------------------------------------------------------------------- 1 | # plugins README 2 | 3 | ## simulation 4 | input of the simulaiton should contain 3 parts 5 | 1. coefficient 6 | 2. equations (dy/dt = ....) 7 | 3. initial values 8 | 9 | there is a example_input of simlulation: 10 | 1. coefficient(string) 11 | ``` python 12 | str_coefs="start_t=0;end_t=200;step=0.005;" 13 | ``` 14 | 2. equations(string) 15 | ``` python 16 | str_eqs ="""# equations (one equation one line) 17 | dy0dt = 0.01*y[0] +0.005*y[1] 18 | dy1dt = 0.05*y[1]*(1-y[1]/2) 19 | # end line """ 20 | ``` 21 | the number of equations should the same as variables to make sure the ODE can be solved 22 | 3. init values(string) 23 | ``` python 24 | str_init = """# init values 25 | y0 = 0.2 26 | y1 = 0.1 27 | # end line""" 28 | ``` -------------------------------------------------------------------------------- /plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/plugins/__init__.py -------------------------------------------------------------------------------- /plugins/biobrick_manager/Biobrick.py: -------------------------------------------------------------------------------- 1 | from .BiobrickOfficial import BiobrickOfficial 2 | from .BiobrickUser import BiobrickUser 3 | 4 | 5 | class Biobrick: 6 | pass 7 | -------------------------------------------------------------------------------- /plugins/biobrick_manager/BiobrickOfficial.py: -------------------------------------------------------------------------------- 1 | from database import TableBase, Column, \ 2 | INTEGER, TINYINT, VARCHAR, LONGTEXT, DATE, DATETIME, TEXT, BINARY, DOUBLE 3 | from database import session 4 | 5 | #from .FeatureOfficial import FeatureOfficial 6 | 7 | 8 | class BiobrickOfficial(TableBase): 9 | __tablename__ = 'parts' 10 | 11 | part_id = Column(INTEGER(11), primary_key=True) 12 | ok = Column(TINYINT(1)) 13 | part_name = Column(VARCHAR(255)) 14 | short_desc = Column(VARCHAR(100)) 15 | description = Column(LONGTEXT) 16 | part_type = Column(VARCHAR(20)) 17 | author = Column(VARCHAR(200)) 18 | owning_group_id = Column(INTEGER(11)) 19 | status = Column(VARCHAR(20)) 20 | dominant = Column(TINYINT(1)) 21 | informational = Column(TINYINT(1)) 22 | discontinued = Column(INTEGER(11)) 23 | part_status = Column(VARCHAR(40)) 24 | sample_status = Column(VARCHAR(40)) 25 | p_status_cache = Column(VARCHAR(1000)) 26 | s_status_cache = Column(VARCHAR(1000)) 27 | creation_date = Column(DATE) 28 | m_datetime = Column(DATETIME) 29 | m_user_id = Column(INTEGER(11)) 30 | uses = Column(INTEGER(11)) 31 | doc_size = Column(INTEGER(11)) 32 | works = Column(VARCHAR(10)) 33 | favorite = Column(INTEGER(4)) 34 | specified_u_list = Column(LONGTEXT) 35 | deep_u_list = Column(LONGTEXT) 36 | deep_count = Column(INTEGER(11)) 37 | ps_string = Column(LONGTEXT) 38 | scars = Column(VARCHAR(20)) 39 | default_scars = Column(VARCHAR(20)) 40 | owner_id = Column(INTEGER(11)) 41 | group_u_list = Column(LONGTEXT) 42 | has_barcode = Column(TINYINT(1)) 43 | notes = Column(LONGTEXT) 44 | source = Column(TEXT) 45 | nickname = Column(VARCHAR(10)) 46 | categories = Column(VARCHAR(500)) 47 | sequence = Column(LONGTEXT) 48 | sequence_sha1 = Column(BINARY(20)) 49 | sequence_update = Column(INTEGER(11)) 50 | seq_edit_cache = Column(LONGTEXT) 51 | review_result = Column(DOUBLE(12, 0)) 52 | review_count = Column(INTEGER(4)) 53 | review_total = Column(INTEGER(4)) 54 | flag = Column(INTEGER(4)) 55 | sequence_length = Column(INTEGER(11)) 56 | temp_1 = Column(INTEGER(11)) 57 | temp_2 = Column(INTEGER(11)) 58 | temp_3 = Column(INTEGER(11)) 59 | temp4 = Column(INTEGER(11)) 60 | rating = Column(INTEGER(11)) 61 | 62 | def __set_by_kwargs__(self, **kwargs): 63 | for k, v in kwargs.items(): 64 | setattr(self, k, v) 65 | 66 | def __get_info__(self): 67 | values = {} 68 | for k in dir(self): 69 | if k.startswith('_'): 70 | continue 71 | if not k in ('part_id', 'part_name', 'short_desc', 'description', 'sequence'): 72 | continue 73 | values[k] = getattr(self, k) 74 | #features = [] 75 | #for feature in session.query(BioBrickFeature).filter(BioBrickFeature.part_id == self): 76 | # features.append({}) 77 | # for k in dir(feature): 78 | # if k.startswith('_'): 79 | # continue 80 | # features[-1][k] = getattr(feature, k) 81 | #values['features'] = features 82 | return values 83 | -------------------------------------------------------------------------------- /plugins/biobrick_manager/BiobrickUser.py: -------------------------------------------------------------------------------- 1 | from database import TableBase, Column, ForeignKey, \ 2 | Integer, INTEGER, TINYINT, VARCHAR, LONGTEXT, DATE, DATETIME, TEXT, BINARY, DOUBLE 3 | 4 | 5 | class BiobrickUser(TableBase): 6 | __tablename__ = 'parts_by_user' 7 | 8 | part_id = Column(INTEGER(11), primary_key=True) 9 | ok = Column(TINYINT(1)) 10 | part_name = Column(VARCHAR(255)) 11 | short_desc = Column(VARCHAR(100)) 12 | description = Column(LONGTEXT) 13 | part_type = Column(VARCHAR(20)) 14 | author = Column(VARCHAR(200)) 15 | owning_group_id = Column(INTEGER(11)) 16 | status = Column(VARCHAR(20)) 17 | dominant = Column(TINYINT(1)) 18 | informational = Column(TINYINT(1)) 19 | discontinued = Column(INTEGER(11)) 20 | part_status = Column(VARCHAR(40)) 21 | sample_status = Column(VARCHAR(40)) 22 | p_status_cache = Column(VARCHAR(1000)) 23 | s_status_cache = Column(VARCHAR(1000)) 24 | creation_date = Column(DATE) 25 | m_datetime = Column(DATETIME) 26 | m_user_id = Column(INTEGER(11)) 27 | uses = Column(INTEGER(11)) 28 | doc_size = Column(INTEGER(11)) 29 | works = Column(VARCHAR(10)) 30 | favorite = Column(INTEGER(4)) 31 | specified_u_list = Column(LONGTEXT) 32 | deep_u_list = Column(LONGTEXT) 33 | deep_count = Column(INTEGER(11)) 34 | ps_string = Column(LONGTEXT) 35 | scars = Column(VARCHAR(20)) 36 | default_scars = Column(VARCHAR(20)) 37 | owner_id = Column(INTEGER(11)) 38 | group_u_list = Column(LONGTEXT) 39 | has_barcode = Column(TINYINT(1)) 40 | notes = Column(LONGTEXT) 41 | sources = Column(TEXT) 42 | nickname = Column(VARCHAR(10)) 43 | categories = Column(VARCHAR(500)) 44 | sequence = Column(LONGTEXT) 45 | sequence_sha1 = Column(BINARY(20)) 46 | sequence_update = Column(INTEGER(11)) 47 | seq_edit_cache = Column(LONGTEXT) 48 | review_result = Column(DOUBLE(12, 0)) 49 | review_count = Column(INTEGER(4)) 50 | review_total = Column(INTEGER(4)) 51 | flag = Column(INTEGER(4)) 52 | sequence_length = Column(INTEGER(11)) 53 | temp_1 = Column(INTEGER(11)) 54 | temp_2 = Column(INTEGER(11)) 55 | temp_3 = Column(INTEGER(11)) 56 | temp4 = Column(INTEGER(11)) 57 | rating = Column(INTEGER(11)) 58 | 59 | owner = Column(Integer, ForeignKey('user.user_id')) 60 | 61 | def __set_by_kwargs__(self, **kwargs): 62 | for k, v in kwargs.items(): 63 | setattr(self, k, v) 64 | 65 | def __get_info__(self): 66 | values = {} 67 | for k in dir(self): 68 | if k.startswith('_'): 69 | continue 70 | values[k] = getattr(self, k) 71 | features = [] 72 | for feature in session.query(BioBrickFeature).filter(BioBrickFeature.part_id == self): 73 | features.append({}) 74 | for k in dir(feature): 75 | if k.startswith('_'): 76 | continue 77 | features[-1][k] = getattr(feature, k) 78 | values['features'] = features 79 | return values 80 | -------------------------------------------------------------------------------- /plugins/biobrick_manager/Feature.py: -------------------------------------------------------------------------------- 1 | from .FeatureOfficial import FeatureOfficial 2 | from .FeatureUser import FeatureUser 3 | 4 | 5 | class Feature: 6 | pass 7 | -------------------------------------------------------------------------------- /plugins/biobrick_manager/FeatureOfficial.py: -------------------------------------------------------------------------------- 1 | from database import TableBase, Column, ForeignKey, INTEGER, VARCHAR 2 | 3 | 4 | class FeatureOfficial(TableBase): 5 | __tablename__ = 'parts_seq_features' 6 | 7 | feature_id = Column(INTEGER(11), primary_key=True) 8 | feature_type = Column(VARCHAR(200)) 9 | start_pos = Column(INTEGER(11)) 10 | end_pos = Column(INTEGER(11)) 11 | label = Column(VARCHAR(200)) 12 | part_id = Column(INTEGER(11), ForeignKey('parts.part_id')) 13 | type = Column(VARCHAR(200)) 14 | label2 = Column(VARCHAR(200)) 15 | mark = Column(INTEGER(11)) 16 | old = Column(INTEGER(11)) 17 | reverse = Column(INTEGER(11)) 18 | 19 | def __set_by_kwargs__(self, **kwargs): 20 | for k, v in kwargs.items(): 21 | setattr(self, k, v) 22 | -------------------------------------------------------------------------------- /plugins/biobrick_manager/FeatureUser.py: -------------------------------------------------------------------------------- 1 | from database import TableBase, Column, ForeignKey, INTEGER, VARCHAR 2 | 3 | 4 | class FeatureUser(TableBase): 5 | __tablename__ = 'parts_seq_features_by_user' 6 | 7 | feature_id = Column(INTEGER(11), primary_key=True) 8 | feature_type = Column(VARCHAR(200)) 9 | start_pos = Column(INTEGER(11)) 10 | end_pos = Column(INTEGER(11)) 11 | label = Column(VARCHAR(200)) 12 | part_id = Column(INTEGER(11), ForeignKey('parts.part_id')) 13 | type = Column(VARCHAR(200)) 14 | label2 = Column(VARCHAR(200)) 15 | mark = Column(INTEGER(11)) 16 | old = Column(INTEGER(11)) 17 | reverse = Column(INTEGER(11)) 18 | 19 | def __set_by_kwargs__(self, **kwargs): 20 | for k, v in kwargs.items(): 21 | setattr(self, k, v) 22 | -------------------------------------------------------------------------------- /plugins/biobrick_manager/__init__.py: -------------------------------------------------------------------------------- 1 | from plugin import Plugin 2 | from database import session 3 | 4 | from .BiobrickOfficial import BiobrickOfficial 5 | #from .FeatureOfficial import FeatureOfficial 6 | 7 | 8 | class BiobrickManager(Plugin): 9 | def __init__(self): 10 | super().__init__() 11 | self.documents.set_document_type('biobrick') 12 | self.documents.set_document_table(BiobrickOfficial) 13 | self.name = 'biobrick_manager' 14 | 15 | def process(self, request): 16 | return getattr(self, request['action'])(**request) 17 | 18 | def search(self, key, **kwargs): 19 | filter_str = 'concat(part_name, short_desc, description, notes) like "%%%s%%"' % key 20 | q = session.query(BiobrickOfficial).filter(filter_str).limit(100) 21 | return dict(list=list(map(BiobrickOfficial.__get_info__, q))) 22 | ''' 23 | doc = Biobrick() 24 | doc.__set_by_kwargs__(**values) 25 | self.documents.create(doc) 26 | return {'id': doc.id} 27 | 28 | elif request['action'] == 'basic_edit': 29 | doc = self.documents.get(request['id']) 30 | doc.__set_by_kwargs__(**request['values']) 31 | self.documents.update(doc) 32 | return {} 33 | elif request['action'] == 'feature_edit': 34 | feature = session.query(BioBrickFeature).get(request['id']) 35 | feature.__set_by_kwargs__(**request['values']) 36 | session.add(feature) 37 | session.commit() 38 | return {} 39 | elif request['action'] == 'delete': 40 | # doc = self.documents.get(request['id']) 41 | # self.documents.delete(doc) 42 | raise NotImplementedError('delete not supported') 43 | elif request['action'] == 'get': 44 | doc = self.documents.get(request['id']) 45 | return {'values': repr(doc.__get_info__())} 46 | elif request['action'] == 'search': 47 | # FIXME: [wzb@08-04] 48 | filter_str = 'concat(part_name, short_desc, description, notes) like "%%%s%%"' % request['key'] 49 | q = session.query(Biobrick).filter(filter_str) 50 | return {'list': repr(list(map(Biobrick.__get_info__, q)))} 51 | else: 52 | raise ValueError('unknown action: ' + request['action']) 53 | ''' 54 | 55 | __plugin__ = BiobrickManager() 56 | -------------------------------------------------------------------------------- /plugins/dbupload/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/plugins/dbupload/__init__.py -------------------------------------------------------------------------------- /plugins/dbupload/dbprofile.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import Column, Text, Integer, Date, String 2 | from sqlalchemy.ext.declarative import declarative_base 3 | TableBase = declarative_base() 4 | 5 | 6 | # Define database file error exception 7 | class DataBaseSourceError(Exception): 8 | pass 9 | 10 | 11 | # define biosystems of certain taxonomy 12 | class biosys_single(TableBase): 13 | __tablename__ = 'biosys_562' 14 | id = Column(Integer, primary_key=True, autoincrement=True) 15 | tax_id = Column(String(10)) 16 | gene_id = Column(String(10)) 17 | bsid = Column(Integer) 18 | Symbol = Column(String(64)) 19 | 20 | 21 | # define Gene 22 | class Gene(TableBase): 23 | __tablename__ = 'allgeneinfo_all' 24 | tax_id = Column(String(10)) 25 | gene_id = Column(String(10), primary_key=True) 26 | Symbol = Column(String(64)) 27 | LocusTag = Column(Text) 28 | Synonyms = Column(Text) 29 | dbXrefs = Column(Text) 30 | chromosome = Column(Text) 31 | map_location = Column(Text) 32 | description = Column(Text) 33 | type_of_gene = Column(Text) 34 | Symbol_from_nomenclature_authority = Column(Text) 35 | Full_name_from_nomenclature_authority = Column(Text) 36 | Nomenclature_status = Column(Text) 37 | Other_designations = Column(Text) 38 | Modification_date = Column(Date) 39 | 40 | 41 | def gene_init(oneline): 42 | try: 43 | if len(oneline) != 15: 44 | raise DataBaseSourceError 45 | finally: 46 | pass 47 | 48 | day = ''.join(oneline[14]) 49 | day = day[0:4] + '-' + day[4:6] + '-' + day[6:8] 50 | new_gene = Gene( 51 | tax_id=''.join(oneline[0]), 52 | gene_id=''.join(oneline[1]), 53 | Symbol=''.join(oneline[2]), 54 | LocusTag=''.join(oneline[3]), 55 | Synonyms=''.join(oneline[4]), 56 | dbXrefs=''.join(oneline[5]), 57 | chromosome=''.join(oneline[6]), 58 | map_location=''.join(oneline[7]), 59 | description=''.join(oneline[8]), 60 | type_of_gene=''.join(oneline[9]), 61 | Symbol_from_nomenclature_authority=''.join(oneline[10]), 62 | Full_name_from_nomenclature_authority=''.join(oneline[11]), 63 | Nomenclature_status=''.join(oneline[12]), 64 | Other_designations=''.join(oneline[13]), 65 | Modification_date=day) 66 | 67 | return new_gene 68 | 69 | 70 | def gene_commit(e_e, res, num): 71 | if len(res) == 0: 72 | return None 73 | 74 | date = [] 75 | for oneline in res: 76 | try: 77 | date.append(oneline[14][0:4] + '-' + oneline[14][4:6] + '-' + oneline[14][6:8]) 78 | except IndexError as e: 79 | print(e) 80 | continue 81 | 82 | e_e( 83 | Gene.__table__.insert(), 84 | [dict(tax_id=res[i][0], 85 | gene_id=res[i][1], 86 | Symbol=res[i][2], 87 | LocusTag=res[i][3], 88 | Synonyms=res[i][4], 89 | dbXrefs=res[i][5], 90 | chromosome=res[i][6], 91 | map_location=res[i][7], 92 | description=res[i][8], 93 | type_of_gene=res[i][9], 94 | Symbol_from_nomenclature_authority=res[i][10], 95 | Full_name_from_nomenclature_authority=res[i][11], 96 | Nomenclature_status=res[i][12], 97 | Other_designations=res[i][13], 98 | Modification_date=date[i]) 99 | for i in range(len(res))] 100 | ) 101 | 102 | 103 | # ===========================BioSystems==================================== 104 | class BioSys(TableBase): 105 | __tablename__ = 'biosystems' 106 | 107 | id = Column(Integer, primary_key=True, autoincrement=True) 108 | bsid = Column(Integer) 109 | gene_id = Column(String(10)) 110 | score = Column(Integer) 111 | 112 | 113 | def biosys_init(oneline): 114 | try: 115 | if len(oneline) != 3: 116 | raise DataBaseSourceError 117 | finally: 118 | pass 119 | 120 | try: 121 | score_int = int(oneline[2]) 122 | except ValueError: 123 | return None 124 | 125 | return BioSys( 126 | bsid=''.join(oneline[0]), 127 | gene_id=''.join(oneline[1]), 128 | score=score_int) 129 | 130 | 131 | def biosys_commit(e_e, res, num): 132 | if len(res) == 0: 133 | return None 134 | 135 | error_pos = [] 136 | score_int = [] 137 | bs_id_int = [] 138 | for i in range(0, len(res)): 139 | try: 140 | temp1 = int(res[i][2]) 141 | temp2 = int(res[i][0]) 142 | except ValueError as e: 143 | print('\nIn row', str(num - len(res) + i + 1) + ',', e) 144 | error_pos.append(i) 145 | else: 146 | score_int.append(temp1) 147 | bs_id_int.append(temp2) 148 | 149 | for i in error_pos: 150 | del res[i] 151 | 152 | e_e( 153 | BioSys.__table__.insert(), 154 | [dict(bsid=bs_id_int[i], 155 | gene_id=res[i][1], 156 | score=score_int[i]) 157 | for i in range(len(res))] 158 | ) 159 | -------------------------------------------------------------------------------- /plugins/dbupload/linkgene.py: -------------------------------------------------------------------------------- 1 | from Bio import Entrez as ez 2 | from sqlalchemy.exc import IntegrityError, InvalidRequestError 3 | from database import * 4 | from progressbar import * 5 | from dbprofile import * 6 | import time 7 | 8 | 9 | def get_bsid(tax_name, log=False, flog=None): 10 | handle = ez.esearch(db='biosystems', term=tax_name, rettype='count') 11 | res = ez.read(handle) 12 | try: 13 | r_max = int(res['Count']) 14 | except ValueError as e: 15 | print(e) 16 | 17 | if r_max <= 0 and log: 18 | flog.write('[Alert]' + time.asctime(time.localtime(time.time())) + tax_name + "bsid not found!\n") 19 | return None 20 | 21 | handle = ez.esearch(db='biosystems', term=tax_name, retmax=r_max) 22 | res = ez.read(handle) 23 | res = res['IdList'] 24 | return res 25 | 26 | 27 | def get_taxid(tax_name, log=False, flog=False): 28 | handle = ez.esearch(db='taxonomy', term=tax_name, rettype='count') 29 | res = ez.read(handle) 30 | try: 31 | r_max = int(res['Count']) 32 | except ValueError as e: 33 | print(e) 34 | 35 | if r_max <= 0 and log: 36 | flog.write('[Alert]' + time.asctime(time.localtime(time.time())) + tax_name + 'tax_id not found') 37 | return None 38 | try: 39 | handle = ez.esearch(db='taxonomy', term=tax_name, retmax=r_max) 40 | res = ez.read(handle) 41 | res = res['IdList'] 42 | except RuntimeError as e: 43 | print(e) 44 | flog.write('[Error!]' + time.asctime(time.localtime(time.time())) + ' ' + e + ' tax_name:' + tax_name + '\n') 45 | 46 | return res 47 | 48 | 49 | def set_link(path, echo=False, log=False): 50 | ez.email = 'biohub@biohub.tech' 51 | l = 0 52 | 53 | if echo: 54 | total = count_lines(path) 55 | if total <= 0: 56 | echo = False 57 | 58 | if log: 59 | try: 60 | flog = open(r'linkgene_log.dat', 'w') 61 | except IOError as e: 62 | print(e, 'can\'t log!') 63 | log = False 64 | else: 65 | flog.write('[Info]Log date:' + time.asctime(time.localtime(time.time())) + ' Start.\nFile:' + path + '\n') 66 | 67 | # Open file 68 | try: 69 | f = open(path, 'r') 70 | except IOError as e: 71 | print(e) 72 | return -10 73 | except FileNotFoundError as e: 74 | print(e) 75 | return -11 76 | 77 | tax_list = [] 78 | while 1: 79 | temp = f.readline() 80 | if not temp: 81 | break 82 | 83 | if temp.startswith('#'): 84 | continue 85 | 86 | temp = temp.split('\n') 87 | if temp[0] == '': 88 | continue 89 | tax_list.append(temp[0]) 90 | 91 | f.close() 92 | 93 | if echo: 94 | i = 0 95 | 96 | for tax in tax_list: 97 | # Obtain tax_id from tax name 98 | if log: 99 | bsid_list = get_bsid(tax, log, flog) 100 | taxid_list = get_taxid(tax, log, flog) 101 | else: 102 | bsid_list = get_bsid(tax) 103 | taxid_list = get_taxid(tax) 104 | 105 | # Fail to fetch bsid or tax_id 106 | if not bsid_list or not taxid_list: 107 | if log: 108 | flog.write('[Alert]' + time.asctime( 109 | time.localtime(time.time())) + ': Cannot find ' + tax + '\'s tax_id or bsid.\n') 110 | if echo: 111 | i += 1 112 | continue 113 | 114 | j = 0 115 | for bsid in bsid_list: 116 | if echo: 117 | l = print_2bar(i, total, j, len(bsid_list), tax, l, bsid) 118 | j += 1 119 | 120 | # Set command 121 | cmd = '''select a.gene_id, b.gene_id 122 | from biosystems a, biosystems b 123 | where a.bsid = '%s' 124 | and a.gene_id in( 125 | select gene_id 126 | from allgeneinfo 127 | where tax_id = '%s' 128 | ) 129 | and b.gene_id in ( 130 | select gene_id 131 | from allgeneinfo 132 | where tax_id = '%s' 133 | ) 134 | and a.bsid = b.bsid 135 | and a.gene_id > b.gene_id;''' % (bsid, taxid_list[0], taxid_list[0]) 136 | 137 | # Send command to sql server 138 | with engine.connect() as con: 139 | res = con.execute(cmd) 140 | res = list(res) 141 | 142 | # Result is empty 143 | if len(res) == 0: 144 | if log: 145 | flog.write('[Alert]' + time.asctime(time.localtime(time.time())) + ': tax_id:' + taxid_list[0] + 146 | ':bsid:' + bsid + ', not exist!\n') 147 | continue 148 | 149 | # Insert result to server 150 | try: 151 | link_commit(engine.execute, res, taxid_list[0]) 152 | except ValueError as e: 153 | print(e) 154 | if log: 155 | flog.write('[Error!]' + time.asctime(time.localtime(time.time())) + ':' + str(e) + '\n') 156 | flog.close() 157 | return -3 158 | except IntegrityError as e: 159 | print(e.orig.args) 160 | if log: 161 | flog.write('[Error!]' + time.asctime(time.localtime(time.time())) + ':' + str(e) + '\n') 162 | flog.close() 163 | return -4 164 | except InvalidRequestError as e: 165 | print(e) 166 | if log: 167 | flog.write('[Error!]' + time.asctime(time.localtime(time.time())) + ':' + str(e) + '\n') 168 | flog.close() 169 | return -5 170 | 171 | if echo: 172 | i += 1 173 | if log: 174 | flog.write('[Info]' + time.asctime(time.localtime(time.time())) + ':' + tax + '(' + tax_list[0] + ')' 175 | + ' Done.\n') 176 | 177 | if echo: 178 | print_2bar(100, 100, 100, 100, '--Done--', l, '------') 179 | 180 | if log: 181 | flog.close() 182 | -------------------------------------------------------------------------------- /plugins/dbupload/progressbar.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from time import * 3 | 4 | 5 | def count_lines(path): 6 | try: 7 | fp = open(path, 'r') 8 | except IOError as e: 9 | print(e) 10 | return -1 11 | 12 | count = 0 13 | 14 | while 1: 15 | try: 16 | buffer = fp.read(4*1024*1024) 17 | except UnicodeDecodeError as e: 18 | print(e) 19 | continue 20 | 21 | if not buffer: 22 | break 23 | 24 | count += buffer.count('\n') 25 | fp.close() 26 | 27 | return count 28 | 29 | 30 | def print_bar(num, lines_num): 31 | printnum = int(100 * num / lines_num) 32 | ratio = int(100 * num / lines_num) 33 | strs = '' 34 | for i in range(0, printnum): 35 | strs += '#' 36 | for i in range(printnum, 100): 37 | strs += ' ' 38 | 39 | sys.stdout.write('\r' + str(ratio) + '% [' + strs + ']') 40 | sys.stdout.flush() 41 | 42 | 43 | def print_2bar(num1, total1, num2, total2, name, size, bsid): 44 | ratio1 = int(100 * num1 / total1) 45 | ratio2 = int(100 * num2 / total2) 46 | 47 | strs1 = '' 48 | strs2 = '' 49 | 50 | for i in range(0, int(ratio1 / 2)): 51 | strs1 += '#' 52 | for i in range(int(ratio1 / 2), 50): 53 | strs1 += ' ' 54 | 55 | for i in range(0, int(ratio2 / 2)): 56 | strs2 += '#' 57 | for i in range(int(ratio2 / 2), 50): 58 | strs2 += ' ' 59 | 60 | str_end = str(ratio1) + '% [' + strs1 + ']' + ' ' + str(ratio2) + '% [' + strs2 + ']' + ' tax name:' + name + ' | bsid:' + bsid 61 | length = len(str_end) 62 | 63 | if length < size: 64 | for i in range(0, size - length): 65 | str_end += ' ' 66 | 67 | sys.stdout.write('\r' + str_end) 68 | sys.stdout.flush() 69 | 70 | return length 71 | -------------------------------------------------------------------------------- /plugins/dbupload/uploaddb.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.exc import IntegrityError, InvalidRequestError 2 | 3 | from .progressbar import * 4 | import time 5 | from sqlalchemy import * 6 | from sqlalchemy.orm import sessionmaker 7 | 8 | # return -1 IOError 9 | # return -2 FileNotFoundError 10 | # return -3 ValueError 11 | # return -4 IntegrityError 12 | # return -5 InvalidRequestError 13 | 14 | 15 | # Set echo to True to enable progress bar. 16 | # Set log to True to enable log function. 17 | def upload(DATABASE_URI, path, commit, column_num, cache_size=100000, echo=False, log=False): 18 | engine = create_engine(DATABASE_URI) 19 | DBSession = sessionmaker(bind=engine) 20 | session = DBSession() 21 | 22 | # Open file 23 | if echo: 24 | line_num = count_lines(path) 25 | if log: 26 | try: 27 | logf = open('log.dat', 'w+') 28 | except IOError as e: 29 | print(e, 'can\'t log!') 30 | log = False 31 | else: 32 | logf.write('Log date:' + time.asctime(time.localtime(time.time())) + ' Start.\nFile:' + path + '\n') 33 | 34 | try: 35 | f = open(path, 'r') 36 | except IOError as e: 37 | print(e) 38 | if log: 39 | logf.write(time.asctime(time.localtime(time.time())) + ':' + e) 40 | logf.close() 41 | return -1 42 | except FileNotFoundError as e: 43 | print(e) 44 | if log: 45 | logf.write(time.asctime(time.localtime(time.time())) + ':' + e) 46 | logf.close() 47 | return -2 48 | 49 | # Initialize 50 | num = 0 51 | flag = False 52 | while 1: 53 | res = [] 54 | # cache_size is import for a high speed upload 55 | for i in range(1, cache_size + 1): 56 | num += 1 57 | try: 58 | line = f.readline() 59 | except UnicodeDecodeError as e: 60 | print("In " + path + " row ", num + i, '.', end='') 61 | print(e) 62 | if log: 63 | logf.write(time.asctime(time.localtime(time.time())) + ':' + "In " + path + " row " + 64 | str(num + i) + '.' + str(e) + '\n') 65 | continue 66 | else: 67 | if not line: 68 | flag = True 69 | break 70 | 71 | # Filter and append 72 | if line.startswith('#'): 73 | continue 74 | if line == '': 75 | continue 76 | temp = line.split('\t') 77 | 78 | if len(temp) != column_num: 79 | print("In " + path + " row ", num, ", data missed or duplicated.") 80 | if log: 81 | logf.write(time.asctime(time.localtime(time.time())) + ':' + "In " + path + " row " + str(num) 82 | + ", data missed or duplicated." + '\n') 83 | else: 84 | res.append(temp) 85 | 86 | # Commit data 87 | try: 88 | commit(engine.execute, res, num) 89 | 90 | if echo: 91 | print_bar(num, line_num) 92 | 93 | except ValueError as e: 94 | print(e) 95 | if log: 96 | logf.write(time.asctime(time.localtime(time.time())) + ':' + str(e) + '\n') 97 | logf.close() 98 | return -3 99 | except IntegrityError as e: 100 | print(e.orig.args) 101 | if log: 102 | logf.write(time.asctime(time.localtime(time.time())) + ':' + str(e) + '\n') 103 | logf.close() 104 | return -4 105 | except InvalidRequestError as e: 106 | print(e) 107 | if log: 108 | logf.write(time.asctime(time.localtime(time.time())) + ':' + str(e) + '\n') 109 | logf.close() 110 | return -5 111 | 112 | if flag: 113 | break 114 | 115 | if log: 116 | logf.close() 117 | -------------------------------------------------------------------------------- /plugins/example_plugin.py: -------------------------------------------------------------------------------- 1 | """This is an example plugin for BioHub. It manages all text files, and print some debug messages.""" 2 | 3 | 4 | from plugin import Plugin, PluginDocument 5 | 6 | from database import TableBase, Column, Text 7 | from database import engine 8 | 9 | 10 | class TextFileDocument(TableBase, PluginDocument): 11 | 12 | __tablename__ = 'textfile' 13 | 14 | def __init__(self, owner, title='Untitled', text=''): 15 | super().__init__() 16 | self.owner = owner 17 | self.title = title 18 | self.text = text 19 | self.description = 'not support description' 20 | 21 | text = Column(Text()) 22 | 23 | 24 | class TextFile(Plugin): 25 | def __init__(self): 26 | super().__init__() 27 | print('example plugin loaded') 28 | self.documents.set_document_type('text') 29 | self.documents.set_document_table(TextFileDocument) 30 | self.name = 'example_plugin' 31 | try: 32 | TextFileDocument.__table__.create(engine) 33 | except: 34 | pass 35 | 36 | def process(self, request): 37 | print('example plugin got a request:' + str(request)) 38 | if request['action'] == 'new': 39 | doc = TextFileDocument(self.user.user_id) 40 | self.documents.create(doc) 41 | return {'id': doc.id} 42 | elif request['action'] == 'save': 43 | doc = self.documents.get(request['id']) 44 | doc.title = request['title'] 45 | doc.text = request['text'] 46 | self.documents.update(doc) 47 | return {} 48 | elif request['action'] == 'delete': 49 | doc = self.documents.get(request['id']) 50 | self.documents.delete(doc) 51 | return {} 52 | elif request['action'] == 'get': 53 | doc = self.documents.get(request['id']) 54 | return {'id': doc.id, 'owner': doc.owner, 'title': doc.title, 'text': doc.text, 55 | 'last_modified': doc.last_modified} 56 | else: 57 | return {'success': False, 'reason': 'unknown action: ' + request['action']} 58 | 59 | def unload(self): 60 | print('example plugin unloaded') 61 | 62 | __plugin__ = TextFile() 63 | -------------------------------------------------------------------------------- /plugins/googlescholar.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/python3 2 | # encoding=utf-8 3 | 4 | import urllib.parse 5 | import urllib.request 6 | 7 | import re 8 | 9 | from bs4 import BeautifulSoup 10 | 11 | 12 | keyword='fuck' 13 | 14 | url='https://scholar.google.com/scholar?&hl=en&q='+keyword+'&btnG=&lr=' 15 | header_dict={'Host': 'scholar.google.com', 16 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0', 17 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 18 | 'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 19 | 'Referer': 'https://scholar.google.com/schhp?hl=zh-CN', 20 | 'Connection': 'keep-alive'} 21 | req = urllib.request.Request(url=url,headers=header_dict) 22 | response = urllib.request.urlopen(req,timeout=120) 23 | 24 | 25 | soup = BeautifulSoup(response) 26 | 27 | i=0 28 | for k in soup.find(id='gs_res_bdy').find(id='gs_ccl').find_all(class_='gs_r'): 29 | i=i+1 30 | for l in k.find_all(class_='gs_ri'): 31 | for r in l.find_all(class_='gs_rt'): 32 | try: 33 | print(r.a.get('href')) 34 | except: 35 | ii=0 36 | try: 37 | print(r.a.text) 38 | except: 39 | ii=0 40 | for r in l.find_all(class_='gs_a'): 41 | try: 42 | print(r.text) 43 | except: 44 | print('none') 45 | for r in l.find_all(class_='gs_rs'): 46 | try: 47 | print(r.text) 48 | except: 49 | ii=0 50 | for r in l.find_all(class_='gs_fl'): 51 | try: 52 | print(r.a.text) 53 | except: 54 | ii=0 55 | 56 | 57 | 58 | start=0 59 | start+=10 60 | 61 | 62 | url='https://scholar.google.com/scholar?start='+str(start)+'&hl=en&q='+keyword+'234&btnG=&lr=' 63 | req = urllib.request.Request(url=url,headers=header_dict) 64 | response = urllib.request.urlopen(req,timeout=120) 65 | 66 | 67 | soup = BeautifulSoup(response) 68 | 69 | 70 | i = 0 71 | #print(soup.body) 72 | for m in soup.find_all(id='gs_res_bdy'): 73 | i=i+1 74 | #print(m) 75 | 76 | for n in m.find_all(id='gs_ccl'): 77 | i=i+1 78 | #print(n) 79 | 80 | i=0 81 | 82 | for k in n.find_all(class_='gs_r'): 83 | i=i+1 84 | for l in k.find_all(class_='gs_ri'): 85 | for r in l.find_all(class_='gs_rt'): 86 | try: 87 | print(r.a.get('href')) 88 | except: 89 | ii=0 90 | try: 91 | print(r.a.text) 92 | except: 93 | ii=0 94 | for r in l.find_all(class_='gs_a'): 95 | try: 96 | print(r.text) 97 | except: 98 | print('none') 99 | for r in l.find_all(class_='gs_rs'): 100 | try: 101 | print(r.text) 102 | except: 103 | ii=0 104 | for r in l.find_all(class_='gs_fl'): 105 | try: 106 | print(r.a.text) 107 | except: 108 | ii=0 109 | -------------------------------------------------------------------------------- /plugins/path_finder.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/python3 2 | # encoding=utf-8 3 | from queue import Queue, PriorityQueue 4 | from datetime import * 5 | from database import session 6 | # from models import Node, Link 7 | from plugin import Plugin 8 | from .dbupload.dbprofile import biosys_single, Gene 9 | 10 | inf = 20 11 | Graph = {} 12 | dis = {} 13 | node_count = 0 14 | 15 | 16 | class State: 17 | def __init__(self, f, g, cur, prepath): # f is the distance to src, g is the distance to dst 18 | self.f = f 19 | self.g = g 20 | self.cur = cur 21 | self.prepath = prepath 22 | 23 | def __lt__(self, x): 24 | if self.f == x.f: 25 | return self.g < x.g 26 | else: 27 | return self.f < x.f 28 | 29 | 30 | def calcu_dis(dst, n, maxlen): 31 | global dis 32 | visited = {} 33 | queue = Queue() 34 | 35 | dis[dst] = 0 36 | visited[dst] = True 37 | queue.put(dst) 38 | while not queue.empty(): 39 | u = queue.get() 40 | # visited[u] = False 41 | Graph[u] = [] 42 | for u_node in session.query(biosys_single).filter(biosys_single.gene_id == u): 43 | for node in session.query(biosys_single).filter(biosys_single.bsid == u_node.bsid): 44 | if node.gene_id not in Graph[u]: 45 | Graph[u].append(node.gene_id) 46 | for v in Graph[u]: 47 | if (v not in visited or dis[v] > dis[u] + 1) and dis[u] + 1 <= maxlen: 48 | dis[v] = dis[u] + 1 49 | visited[v] = True 50 | queue.put(v) 51 | 52 | 53 | def a_star(src, dst, pathnum): 54 | p_queue = PriorityQueue() 55 | global dis 56 | cnt = 0 57 | 58 | time_monitor = datetime.now() 59 | if dis[src] == inf: # if there's no path from src to dst 60 | yield "None" 61 | return 62 | p_queue.put(State(dis[src], 0, src, [src])) 63 | while not p_queue.empty(): 64 | s = p_queue.get() 65 | if s.cur == dst: 66 | yield s.prepath 67 | cnt += 1 68 | if cnt == pathnum: 69 | break 70 | for v in Graph[s.cur]: 71 | if v not in s.prepath: 72 | p_queue.put(State(s.g + 1 + dis[v], s.g + 1, v, s.prepath + [v])) 73 | 74 | if (datetime.now() - time_monitor).seconds > 5: 75 | yield "Timeout" 76 | return 77 | 78 | 79 | def path_finder(s, t, k, maxlen): # s:starting point, t:terminal point, k:number of paths required 80 | calcu_dis(t, node_count, maxlen) 81 | path_list = [] # contain the found paths 82 | node_pool = [] 83 | requested = {} 84 | for p in a_star(s, t, k): 85 | if p == "None" or p == "Timeout": 86 | break 87 | else: 88 | for gene_id in p: 89 | if gene_id not in requested: 90 | requested[gene_id] = True 91 | node = session.query(Gene).get(gene_id) 92 | result = {"gene_id": gene_id} 93 | result["tax_id"] = node.tax_id 94 | result["name"] = node.Symbol 95 | result["info"] = node.description 96 | node_pool.append(result) 97 | path_list.append(p) 98 | print(node_pool) 99 | return node_pool, path_list 100 | 101 | 102 | class Path_Finder(Plugin): 103 | def __init__(self): 104 | super().__init__() 105 | self.name = 'path_finder' 106 | # reload() 107 | 108 | def process(self, request): 109 | print(request) 110 | if request['action'] == 'path_finder': 111 | result = path_finder(request['s'], request['t'], int(request['k']), int(request['maxlen'])) 112 | return {'nodes': result[0], 'paths': result[1]} 113 | # if request['action'] == 'reload': 114 | # reload() 115 | # return {} 116 | else: 117 | return {'success': False, 'reason': 'unknown action: ' + request['action']} 118 | 119 | def unload(self): 120 | pass 121 | 122 | 123 | __plugin__ = Path_Finder() 124 | -------------------------------------------------------------------------------- /plugins/path_finder_new.py: -------------------------------------------------------------------------------- 1 | from queue import PriorityQueue, Queue 2 | from datetime import * 3 | import json 4 | from plugin import Plugin 5 | 6 | 7 | def MakeArray(n): 8 | return [0 for i in range(n + 1)] 9 | 10 | 11 | # class state is aimed at A*-state 12 | class state: 13 | def __init__(self, f, g, now, pre): 14 | self.f = f 15 | self.g = g 16 | self.now = now 17 | self.pre = pre 18 | 19 | def __lt__(self, x): 20 | if (x.f == self.f): 21 | return x.g > self.g 22 | return x.f > self.f 23 | 24 | 25 | q = Queue() 26 | pq = PriorityQueue() 27 | inf = 100000000 28 | 29 | edge = [] 30 | edge2 = [] 31 | next = [] 32 | next2 = [] 33 | 34 | ww = [] 35 | point = [] 36 | point2 = [] 37 | pre = [] 38 | dis = [] 39 | 40 | data = {} 41 | 42 | 43 | def AddEdge(u, v, w, ee): 44 | global edge, edge2, ww, next, next2, point, point2 45 | edge[ee] = v 46 | edge2[ee] = u 47 | ww[ee] = w 48 | next[ee] = point[u] 49 | point[u] = ee 50 | next2[ee] = point2[v] 51 | point2[v] = ee 52 | 53 | 54 | def Relax(u, v, c): 55 | global dis 56 | if dis[v] > dis[u] + c: 57 | dis[v] = dis[u] + c 58 | return True 59 | return False 60 | 61 | 62 | def SPFA(src, n): 63 | global dis, point2, next2, ww, inf 64 | global q 65 | 66 | vis = [False for i in range(n + 1)] 67 | dis[src] = 0 68 | q.put(src) 69 | while not q.empty(): 70 | u = q.get() 71 | vis[u] = False 72 | i = point2[u] 73 | while i != 0: 74 | v = edge2[i] 75 | if Relax(u, v, ww[i]) and not vis[v]: 76 | q.put(v) 77 | vis[v] = True 78 | i = next2[i] 79 | 80 | 81 | def Astar(src, to, k): 82 | global dis 83 | global pq 84 | 85 | cnt = 0 86 | if src == to: 87 | k += 1 88 | if dis[src] == inf: 89 | yield -1 90 | return 91 | pq.put(state(dis[src], 0, src, [src])) 92 | time_monitor = datetime.now() 93 | while not pq.empty(): 94 | b = pq.qsize() 95 | a = pq.get() 96 | if a.now == to: 97 | yield a.pre 98 | cnt += 1 99 | if cnt == k: 100 | break 101 | i = point[a.now] 102 | while i != 0: 103 | 104 | if not edge[i] in a.pre: 105 | pq.put(state(a.g + ww[i] + dis[edge[i]], a.g + ww[i], edge[i], a.pre + [edge[i]])) 106 | i = next[i] 107 | 108 | if (datetime.now() - time_monitor).seconds > 5: 109 | yield 0 110 | return 111 | 112 | 113 | def a_star(s_id, t_id, k): 114 | global edge, edge2, next, next2, ww, point, point2, dis, q, pq 115 | 116 | q = Queue() 117 | pq = PriorityQueue() 118 | node_pool = {} 119 | link_pool = [] 120 | search_pool = {} 121 | time_point = {} 122 | start_time = datetime.now() 123 | 124 | information = data['boost_store'][list(data['boost_store'])[0]] 125 | database_saving = datetime.now() 126 | time_point["database_saving"] = database_saving - start_time 127 | node_count = information["node_count"] 128 | link_count = information["link_count"] 129 | for id, node in data['node_pool'].items(): 130 | node_pool[node["node_id"]] = node["node_count"] 131 | search_pool[node["node_count"]] = node["node_id"] 132 | for id, link in data['link_pool'].items(): 133 | link_pool.append((link["id1"], link["id2"])) 134 | 135 | n_count_time = datetime.now() 136 | time_point["database reading"] = n_count_time - database_saving 137 | 138 | # initial vars 139 | edge = MakeArray(link_count * 2 + 1) 140 | edge2 = MakeArray(link_count * 2 + 1) 141 | next = MakeArray(link_count * 2 + 1) 142 | next2 = MakeArray(link_count * 2 + 1) 143 | ww = MakeArray(link_count * 2 + 1) 144 | point = MakeArray(node_count) 145 | point2 = MakeArray(node_count) 146 | dis = [inf for i in range(node_count + 1)] 147 | 148 | initial_time = datetime.now() 149 | time_point["initial"] = initial_time - n_count_time 150 | 151 | # add in edge 152 | link_count = 0 153 | for link in link_pool: 154 | id1 = link[0] 155 | id2 = link[1] 156 | # ObjectId to int 157 | link_count += 1 158 | num_id1 = node_pool[id1] 159 | num_id2 = node_pool[id2] 160 | AddEdge(num_id1, num_id2, 1, link_count) 161 | link_count += 1 162 | AddEdge(num_id2, num_id1, 1, link_count) 163 | if not s_id in node_pool or not t_id in node_pool: 164 | return {'success': False, 'reason': 'Node not found in database!'} 165 | 166 | s = node_pool[s_id] 167 | t = node_pool[t_id] 168 | 169 | convert_time = datetime.now() 170 | time_point["convert"] = convert_time - initial_time 171 | 172 | SPFA(t, node_count) 173 | 174 | SPFA_time = datetime.now() 175 | time_point["SPFA"] = SPFA_time - convert_time 176 | 177 | path_list = [] 178 | for j in Astar(s, t, k): 179 | # not founded 180 | if j == -1: 181 | break 182 | 183 | # overtime 184 | if j == 0: 185 | break 186 | 187 | path = [] 188 | for node in j: 189 | result = {"id": search_pool[node]} 190 | object_node = data['node'][result["id"]] 191 | result["NAME"] = object_node["NAME"] 192 | result["TYPE"] = object_node["TYPE"] 193 | path.append(result) 194 | del result 195 | # path.append(db.node.find_one({"_id": search_dict[node]})["NAME"]) 196 | path_list.append(path) 197 | 198 | Astar_time = datetime.now() 199 | time_point["Astar"] = Astar_time - SPFA_time 200 | return {'paths': path_list} 201 | 202 | 203 | class Path_Finder_New(Plugin): 204 | def __init__(self): 205 | super().__init__() 206 | self.name = 'path_finder_new' 207 | print('Loading json... Please wait...') 208 | with open('plugins/igemdata.json') as f: 209 | global data 210 | data = json.load(f) 211 | 212 | def process(self, request): 213 | print(request) 214 | if request['action'] == 'path_finder': 215 | return a_star(request['s'], request['t'], int(request['k'])) 216 | else: 217 | return {'success': False, 'reason': 'unknown action: ' + request['action']} 218 | 219 | def unload(self): 220 | pass 221 | 222 | 223 | __plugin__ = Path_Finder_New() 224 | -------------------------------------------------------------------------------- /plugins/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | from .plugins import Plugins 2 | 3 | 4 | __plugin__ = Plugins() 5 | 6 | print('__init__') 7 | -------------------------------------------------------------------------------- /plugins/plugins/auto_load_list: -------------------------------------------------------------------------------- 1 | [ 2 | #'example_plugin', 3 | 'user_model', 4 | 'biobrick_manager', 5 | 'pano', 6 | 'path_finder_new', 7 | 'path_finder', 8 | 'simulation', 9 | 'BLAST', 10 | 'ABACUS', 11 | 'version', 12 | ] 13 | -------------------------------------------------------------------------------- /plugins/plugins/plugins.py: -------------------------------------------------------------------------------- 1 | """This plugin can search other plugins, list them and auto-load some plugins.""" 2 | 3 | from os import listdir, path 4 | 5 | from plugin import Plugin, plugin_manager 6 | 7 | 8 | class Plugins(Plugin): 9 | auto_load_list_file = 'plugins/plugins/auto_load_list' 10 | 11 | def __init__(self): 12 | super().__init__() 13 | for p in self.auto_load_list: 14 | plugin_manager.load_plugin(p) 15 | 16 | @property 17 | def auto_load_list(self) -> list: 18 | with open(Plugins.auto_load_list_file) as f: 19 | return eval(f.read()) 20 | 21 | @auto_load_list.setter 22 | def auto_load_list(self, val): 23 | with open(Plugins.auto_load_list_file, 'w') as f: 24 | f.write(repr(val)) 25 | 26 | def process(self, request): 27 | return getattr(self, request['action'])(**request) 28 | 29 | def list(self, **_): 30 | result = {} 31 | ds = {} 32 | loaded = plugin_manager.get_plugins() 33 | for f in listdir(plugin_manager.plugin_directory): 34 | if path.isdir(f): 35 | name = f 36 | else: 37 | name, _, postfix = f.rpartition('.') 38 | if postfix not in ('py', 'pyc', 'pyd'): 39 | continue 40 | if name.startswith('_'): 41 | continue 42 | state = name in loaded 43 | if state: 44 | ds[name] = plugin_manager.get_plugins()[name].description 45 | result[name] = state 46 | return {'list': result, 'description': ds, 'auto': self.auto_load_list} 47 | 48 | @staticmethod 49 | def enable(name, **_): 50 | plugin_manager.load_plugin(name) 51 | return {} 52 | 53 | @staticmethod 54 | def disable(name, **_): 55 | plugin_manager.unload_plugin(name) 56 | return {} 57 | 58 | def auto_enable(self, name, **_): 59 | l = self.auto_load_list 60 | if name not in l: 61 | l.append(name) 62 | self.auto_load_list = l 63 | return {} 64 | 65 | def auto_disable(self, name, **_): 66 | l = self.auto_load_list 67 | if name in l: 68 | l.remove(name) 69 | self.auto_load_list = l 70 | return {} 71 | 72 | 73 | print('plugins') 74 | -------------------------------------------------------------------------------- /plugins/relationship.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env/python3 2 | # encoding=utf-8 3 | 4 | import urllib.parse 5 | import urllib.request 6 | 7 | import re 8 | 9 | from bs4 import BeautifulSoup 10 | 11 | 12 | keyword1=input("keywords1 is?\n") 13 | print(keyword1) 14 | 15 | keyword2=input("keywords2 is?\n") 16 | print(keyword2) 17 | 18 | 19 | url='https://scholar.google.com/scholar?&hl=en&q='+keyword1+'+'+keyword2+'&btnG=&lr=' 20 | header_dict={'Host': 'scholar.google.com', 21 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0', 22 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 23 | 'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3', 24 | 'Referer': 'https://scholar.google.com/schhp?hl=zh-CN', 25 | 'Connection': 'keep-alive'} 26 | req = urllib.request.Request(url=url,headers=header_dict) 27 | response = urllib.request.urlopen(req,timeout=120) 28 | 29 | 30 | soup = BeautifulSoup(response) 31 | 32 | 33 | i = 0 34 | #print(soup.body) 35 | for m in soup.find_all(id='gs_res_bdy'): 36 | i=i+1 37 | #print(m) 38 | 39 | for n in m.find_all(id='gs_ccl'): 40 | i=i+1 41 | #print(n) 42 | 43 | i=0 44 | 45 | for k in n.find_all(class_='gs_r'): 46 | i=i+1 47 | for l in k.find_all(class_='gs_ri'): 48 | for r in l.find_all(class_='gs_rt'): 49 | try: 50 | print(r.a.get('href')) 51 | except: 52 | ii=0 53 | try: 54 | print(r.a.text) 55 | except: 56 | ii=0 57 | for r in l.find_all(class_='gs_a'): 58 | try: 59 | print(r.text) 60 | except: 61 | print('none') 62 | for r in l.find_all(class_='gs_rs'): 63 | try: 64 | print(r.text) 65 | except: 66 | ii=0 67 | for r in l.find_all(class_='gs_fl'): 68 | try: 69 | print(r.a.text) 70 | except: 71 | ii=0 72 | 73 | 74 | 75 | start=0 76 | start+=10 77 | 78 | 79 | url='https://scholar.google.com/scholar?start='+str(start)+'&hl=en&q='+keyword1+'+'+keyword2+'234&btnG=&lr=' 80 | req = urllib.request.Request(url=url,headers=header_dict) 81 | response = urllib.request.urlopen(req,timeout=120) 82 | 83 | 84 | soup = BeautifulSoup(response) 85 | 86 | 87 | i = 0 88 | #print(soup.body) 89 | for m in soup.find_all(id='gs_res_bdy'): 90 | i=i+1 91 | #print(m) 92 | 93 | for n in m.find_all(id='gs_ccl'): 94 | i=i+1 95 | #print(n) 96 | 97 | i=0 98 | 99 | for k in n.find_all(class_='gs_r'): 100 | i=i+1 101 | for l in k.find_all(class_='gs_ri'): 102 | for r in l.find_all(class_='gs_rt'): 103 | try: 104 | print(r.a.get('href')) 105 | except: 106 | ii=0 107 | try: 108 | print(r.a.text) 109 | except: 110 | ii=0 111 | for r in l.find_all(class_='gs_a'): 112 | try: 113 | print(r.text) 114 | except: 115 | print('none') 116 | for r in l.find_all(class_='gs_rs'): 117 | try: 118 | print(r.text) 119 | except: 120 | ii=0 121 | for r in l.find_all(class_='gs_fl'): 122 | try: 123 | print(r.a.text) 124 | except: 125 | ii=0 126 | 127 | -------------------------------------------------------------------------------- /plugins/test.py: -------------------------------------------------------------------------------- 1 | print('loaded') -------------------------------------------------------------------------------- /plugins/version.py: -------------------------------------------------------------------------------- 1 | from os import popen 2 | 3 | from plugin import Plugin 4 | 5 | 6 | class Version(Plugin): 7 | name = 'version' 8 | 9 | def process(self, request): 10 | p = popen('git log -n 5') 11 | s = p.read() 12 | p.close() 13 | return dict(gitlog=s) 14 | 15 | __plugin__ = Version() 16 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | SQLAlchemy 2 | flask 3 | flask_login 4 | pylint 5 | mock 6 | -------------------------------------------------------------------------------- /run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # encoding: utf-8 3 | 4 | from app import app 5 | 6 | if __name__ == '__main__': 7 | app.run(host='0.0.0.0', port=5000, threaded=True) 8 | -------------------------------------------------------------------------------- /run_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | ''' 3 | Setup all tests files and run pylint 4 | ''' 5 | import unittest 6 | import subprocess 7 | from pylint import epylint as lint 8 | 9 | DIR_LIST = [ 10 | 'plugins', 11 | 'models' 12 | ] 13 | 14 | test = '123' 15 | 16 | 17 | def suite(): 18 | return unittest.TestLoader().discover('tests', 'test_*.py') 19 | 20 | 21 | if __name__ == '__main__': 22 | unittest.main(defaultTest='suite') 23 | # subprocess.call(['pylint','-rn','set_up.py']) 24 | # (pylint_stdout,pylint_stderr)=lint.py_run('test_sample/MyDict.py',return_std=True) 25 | # result_string=pylint_stdout.getvalue() 26 | # print(result_string) 27 | -------------------------------------------------------------------------------- /scripts/import_old_database.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # encoding: utf-8 3 | 4 | from pymongo import MongoClient 5 | import json 6 | from bson.json_util import dumps 7 | 8 | DATABASE = 'igemdata_new' 9 | 10 | tables = ['boost_store', 'count', 'link', 'link_pool', 'link_ref', 'node', 'node_pool', 'node_ref'] 11 | 12 | client = MongoClient('mongodb://localhost/igemdata_new') 13 | db = client[DATABASE] 14 | data = {} 15 | 16 | 17 | def fuck(d): 18 | if isinstance(d, list): 19 | if len(d) > 0 and isinstance(d[0], dict) and "_id" in d[0]: 20 | return {str(x['_id']): fuck(x) for x in d} 21 | else: 22 | return [fuck(x) for x in d] 23 | elif isinstance(d, dict): 24 | return {k: fuck(v) for k, v in d.items()} 25 | elif type(d).__name__ == 'ObjectId': 26 | return str(d) 27 | else: 28 | return d 29 | 30 | 31 | for t in tables: 32 | data[t] = fuck(list(db[t].find())) 33 | 34 | print(json.dumps(data)) 35 | -------------------------------------------------------------------------------- /test_sample/MyDict.py: -------------------------------------------------------------------------------- 1 | class Dict(dict): 2 | 3 | def __init__(self, **kw): 4 | super(Dict, self).__init__(**kw) 5 | 6 | def __getattr__(self, key): 7 | try: 8 | return self[key] 9 | except KeyError: 10 | raise AttributeError(r"'Dict' object has no attribute '%s'" % key) 11 | 12 | def __setattr__(self, key, value): 13 | self[key] = value -------------------------------------------------------------------------------- /test_sample/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/test_sample/__init__.py -------------------------------------------------------------------------------- /test_sample/function_as_sample.py: -------------------------------------------------------------------------------- 1 | def multiply(x, y): 2 | 3 | return x * y+3 4 | 5 | def add_and_multiply(x, y): 6 | 7 | addition = x + y 8 | multiple = multiply(x, y) 9 | 10 | return (addition, multiple) -------------------------------------------------------------------------------- /tests/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/tests/.gitkeep -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igemsoftware2016/USTC-Software-2016/8057b8503892435ecb05d80173bd5021c5f759e6/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_astar.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/test_flask_sample.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | import json 4 | import tempfile 5 | 6 | os.environ['FLASK_TESTING'] = '1' 7 | 8 | import app 9 | 10 | 11 | class FlaskTestCase(unittest.TestCase): 12 | def setUp(self): 13 | app.app.config['TESTING'] = True 14 | self.app = app.app.test_client() 15 | # with app.app.app_context(): 16 | # app.init_db() 17 | 18 | def tearDown(self): 19 | pass 20 | 21 | def post(self, url, data): 22 | return json.loads(self.app.post(url, data=data).data.decode("utf-8")) 23 | 24 | def call_plugin(self, **data): 25 | return self.post('/plugin/', data) 26 | 27 | def test_user(self): 28 | # root 29 | rv = self.app.get('/') 30 | assert b'redirect' in rv.data 31 | 32 | # register 33 | rv = self.call_plugin(plugin='user_model', action='create_user', email='e', password='123', username='u') 34 | assert rv['success'] 35 | 36 | # email already exists 37 | rv = self.call_plugin(plugin='user_model', action='create_user', email='e', password='123', username='u') 38 | assert not rv['success'] 39 | 40 | # wrong password 41 | rv = self.call_plugin(plugin='user_model', action='validate_login', email='e', password='1234') 42 | assert not rv['success'] 43 | 44 | # wrong email 45 | rv = self.call_plugin(plugin='user_model', action='validate_login', email='e2', password='123') 46 | assert not rv['success'] 47 | 48 | # successful login 49 | rv = self.call_plugin(plugin='user_model', action='validate_login', email='e', password='123') 50 | assert rv['success'] 51 | 52 | # edit profile 53 | rv = self.call_plugin(plugin='user_model', action='edit_profile', username='t1', description='t2', education='t3', major='t4') 54 | assert rv['success'] 55 | 56 | # get profile 57 | rv = self.call_plugin(plugin='user_model', action='get_user_data') 58 | assert rv['username'] == 't1' 59 | 60 | def test_version(self): 61 | rv = self.call_plugin(plugin='version') 62 | assert rv['success'] 63 | 64 | def test_biobrick(self): 65 | rv = self.call_plugin(plugin='biobrick_manager', action='search', key='a') 66 | assert rv['success'] and len(rv['list']) > 50 67 | 68 | def test_pano(self): 69 | self.call_plugin(plugin='user_model', action='create_user', email='pano1@test', password='x', username='pano1_test') 70 | self.call_plugin(plugin='user_model', action='create_user', email='pano2@test', password='x', username='pano2_test') 71 | self.call_plugin(plugin='user_model', action='validate_login', email='pano1@test', password='x') 72 | rv = self.call_plugin(plugin='pano', action='new', title='a_title', data='a_data', public='false', img='a_img') 73 | assert rv['success'] 74 | a = rv['id'] 75 | rv = self.call_plugin(plugin='pano', action='new', title='b_title', data='b_data', public='true', img='b_img') 76 | assert rv['success'] 77 | b = rv['id'] 78 | rv = self.call_plugin(plugin='pano', action='list') 79 | assert rv['success'] and set(rv['ids']) == {a, b} 80 | rv = self.call_plugin(plugin='pano', action='get_event_data') 81 | assert rv['success'] and len(rv['events']) == 1 and rv['events'][0]['project_id'] == b 82 | rv = self.call_plugin(plugin='pano', action='load', id=str(a)) 83 | assert rv['success'] and not rv['public'] 84 | rv = self.call_plugin(plugin='pano', action='save', id=str(a), title='a_new_title', data='a_data', img='a_img') 85 | assert rv['success'] 86 | rv = self.call_plugin(plugin='pano', action='load', id=str(a)) 87 | assert rv['success'] and rv['title'] == 'a_new_title' 88 | rv = self.call_plugin(plugin='pano', action='delete', id=str(a)) 89 | assert rv['success'] 90 | rv = self.call_plugin(plugin='pano', action='load', id=str(a)) 91 | assert not rv['success'] 92 | rv = self.call_plugin(plugin='pano', action='list') 93 | assert rv['success'] and set(rv['ids']) == {b} 94 | rv = self.call_plugin(plugin='pano', action='new', title='c_title', data='c_data', public='false', img='c_img') 95 | assert rv['success'] 96 | c = rv['id'] 97 | self.call_plugin(plugin='user_model', action='validate_login', email='pano2@test', password='x') 98 | rv = self.call_plugin(plugin='pano', action='get_event_data') 99 | assert rv['success'] and len(rv['events']) == 1 and rv['events'][0]['project_id'] == b 100 | # FIXME Hypercube 101 | 102 | 103 | if __name__ == '__main__': 104 | unittest.main() 105 | -------------------------------------------------------------------------------- /tests/test_function_sample.py: -------------------------------------------------------------------------------- 1 | from test_sample.function_as_sample import multiply,add_and_multiply 2 | import unittest 3 | import mock 4 | ''' 5 | 6 | ''' 7 | class TestFunctions(unittest.TestCase): 8 | # replace the function:multiply that we import 9 | # if not decorated,the function imported is used 10 | @mock.patch('test_sample.function_as_sample.multiply') 11 | def test_add_and_multiply(self,mock_multiply): 12 | 13 | x = 3 14 | y = 5 15 | mock_multiply.return_value = 15 16 | 17 | addition, multiple = add_and_multiply(x, y) 18 | mock_multiply.assert_called_once_with(3, 5) 19 | 20 | self.assertEqual(8, addition) 21 | self.assertEqual(15, multiple) 22 | 23 | if __name__ == '__main__': 24 | unittest.main() 25 | -------------------------------------------------------------------------------- /tests/test_mydict_sample.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from test_sample.MyDict import Dict 3 | 4 | 5 | class TestDict(unittest.TestCase): 6 | 7 | def test_init(self): 8 | d = Dict(a=1, b='test') 9 | self.assertEqual(d.a, 1) 10 | self.assertEqual(d.b, 'test') 11 | self.assertTrue(isinstance(d, dict)) 12 | 13 | def test_key(self): 14 | d = Dict() 15 | d['key'] = 'value' 16 | self.assertEqual(d.key, 'value') 17 | 18 | def test_attr(self): 19 | d = Dict() 20 | d.key = 'value' 21 | self.assertTrue('key' in d) 22 | self.assertEqual(d['key'], 'value') 23 | 24 | def test_keyerror(self): 25 | d = Dict() 26 | with self.assertRaises(KeyError): 27 | value = d['empty'] 28 | 29 | def test_attrerror(self): 30 | d = Dict() 31 | with self.assertRaises(AttributeError): 32 | value = d.empty 33 | 34 | if __name__ == '__main__': 35 | unittest.main() --------------------------------------------------------------------------------