Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
mwang87 authored Apr 13, 2023
0 parents commit 38b122a
Show file tree
Hide file tree
Showing 15 changed files with 298 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*~
*__pycache__*
Empty file added .gitignore
Empty file.
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM continuumio/miniconda3:4.10.3
MAINTAINER Mingxun Wang "mwang87@gmail.com"

RUN apt-get update && apt-get install -y build-essential

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . /app
WORKDIR /app
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
server-compose-build-nocache:
docker-compose --compatibility build --no-cache

server-compose-interactive:
docker-compose --compatibility build
docker-compose --compatibility up

server-compose:
docker-compose --compatibility build
docker-compose --compatibility up -d

attach:
docker exec -i -t gnpslcms-dash /bin/bash
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## Wang Lab Flask Basic Template

This is a minimally viable template for Wang Lab

### Editing Template

1. Replace all references to template to your own name
1. Change the external port in docker-compose.yml
1. Make new repo
1. Bring up the server with ```make server-compose-interactive```

30 changes: 30 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# app.py
import os

from flask import Flask
from peewee import SqliteDatabase

APP_ROOT = os.path.dirname(os.path.realpath(__file__))
DATABASE = os.path.join(APP_ROOT, './database/database.db')

class CustomFlask(Flask):
jinja_options = Flask.jinja_options.copy()
jinja_options.update(dict(
block_start_string='(%',
block_end_string='%)',
variable_start_string='((',
variable_end_string='))',
comment_start_string='(#',
comment_end_string='#)',
))

app = CustomFlask(__name__)
app.config.from_object(__name__)
db = SqliteDatabase(app.config['DATABASE'], pragmas=[('journal_mode', 'wal')])

app.config['UPLOAD_FOLDER'] = './tempuploads'

try:
os.mkdir(app.config['UPLOAD_FOLDER'])
except:
print("Cannot Create", app.config['UPLOAD_FOLDER'])
28 changes: 28 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
version: '3'
services:
template-dash:
build:
context: .
dockerfile: Dockerfile
container_name: template-dash
volumes:
- ./logs:/app/logs:rw
- ./database:/app/database:rw
ports:
- "5000:5000"
networks:
- default
- nginx-net
restart: unless-stopped
command: /app/run_server.sh
environment:
VIRTUAL_HOST: template.ucsd.edu
VIRTUAL_PORT: 5000
LETSENCRYPT_HOST: template.ucsd.edu
LETSENCRYPT_EMAIL: miw023@ucsd.edu


networks:
nginx-net:
external:
name: nginx-net
Empty file added logs/access.log
Empty file.
8 changes: 8 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# main.py
from app import app
from models import *
import views

if __name__ == '__main__':
Filename.create_table(True)
app.run(host='0.0.0.0', port=5000)
10 changes: 10 additions & 0 deletions models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# models.py

from peewee import *
from app import db

class Filename(Model):
filepath = TextField(primary_key=True)

class Meta:
database = db
9 changes: 9 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Flask
gunicorn
plotly
pandas
requests
tqdm
Werkzeug
Flask-Caching
peewee
4 changes: 4 additions & 0 deletions run_server.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/bin/bash

#python ./main.py
gunicorn -w 6 --threads=12 --worker-class=gthread -b 0.0.0.0:5000 --timeout 120 --max-requests 500 --max-requests-jitter 100 --graceful-timeout 120 main:app --access-logfile /app/logs/access.log
91 changes: 91 additions & 0 deletions templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
(% extends "layout.html" %)

(% block content %)

<!-- This portion is for drag and drop files -->

<script src="https://rawgit.com/enyo/dropzone/master/dist/dropzone.js"></script>
<link rel="stylesheet" href="https://rawgit.com/enyo/dropzone/master/dist/dropzone.css">

<style>
.dropzone { border: 2px dashed #0087F7; border-radius: 5px; background: white; margin: 20px}
.dropzone .dz-message { font-weight: 400; }
.dropzone .dz-message .note { font-size: 0.8em; font-weight: 200; display: block; margin-top: 1.4rem; }
.container-fluid { min-height: 100%; height: 100%;}
</style>

<div>
<div class="container-fluid">
<br>
<br>
<div class="row">
<div class="col-sm"></div>
<div class="col-sm text-center">
<h2>Upload Files</h2>
</div>
<div class="col-sm"></div>
</div>

<br>
<div class="row">
<div class="col-sm-2"></div>
<div class="col-sm-8">
<p>
Upload Files
</p>
</div>
<div class="col-sm-2"></div>
</div>

<br>

<div class="row">
<div class="col-md-2" id=""></div>
<div class="dropzone col-md-8" id="upload">
<div class="dz-message">Drop files here!</div>
</div>
<div class="col-md-2" id=""></div>
</div>

<div id="app-4" class="container-fluid">
<br>
<h3 class="text-center">Upload Summary</h3>
<br>
<table class="table table-sm table-striped">
<thead>
<tr>
<th>Category</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr v-for="stat in stats">
<td>{{stat.type}}</td>
<td>{{stat.value}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>

<script>
validatedropzone = new Dropzone("#upload", { url: "upload", maxFilesize: 200, parallelUploads:1});
validatedropzone.on("success", function(file, response) {
response_json = JSON.parse(response)
app4._data.stats = response_json["stats"]
});
validatedropzone.on("error", function(file) {
});
var app4 = new Vue({
el: '#app-4',
methods: {
},
data: {
stats: []
}
})
</script>


(% endblock %)
40 changes: 40 additions & 0 deletions templates/layout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html>

<head>
<title>Ming Flask Template</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" integrity="sha384-gfdkjb5BdAXd+lj+gudLWI+BXq4IuLW5IT+brZEZsLFm++aCMlF1V92rMkPaX4PP" crossorigin="anonymous">

<!-- Umami Analytics -->
<script async defer data-website-id="ENTER YOUR TOKEN HERE" src="https://analytics.gnps2.org/umami.js"></script>
</head>

<body>
<!-- A grey horizontal navbar that becomes vertical on small screens -->
<nav class="navbar navbar-expand-sm bg-light navbar-light">
<a class="navbar-brand" href="https://gnps.ucsd.edu/">
<img src="https://ccms-ucsd.github.io/GNPSDocumentation/img/GNPS_logo_original.png" alt="Logo" style="width:120px;">
</a>

<!-- Links -->
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/">Homepage</a>
</li>
</ul>

</nav>


<div id="content">
(% block content %)(% endblock %)
</div>


</body>

</html>
42 changes: 42 additions & 0 deletions views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# views.py
from flask import abort, jsonify, render_template, request, redirect, url_for, send_file, make_response

from app import app
from models import *

import os
import csv
import json
import uuid
import requests

@app.route('/', methods=['GET'])
def renderhomepage():
return render_template('index.html')

@app.route('/upload', methods=['POST'])
def validate():
request_file = request.files['file']

local_filename = os.path.join(app.config['UPLOAD_FOLDER'], str(uuid.uuid4()))
request_file.save(local_filename)


response_dict = {}
response_dict["stats"] = []
num_lines = sum(1 for line in open(local_filename))
response_dict["stats"].append({"type":"total_rows", "value":num_lines})

try:
os.remove(local_filename)
except:
print("Cannot Remove File")

return json.dumps(response_dict)


@app.route('/heartbeat', methods=['GET'])
def testapi():
return_obj = {}
return_obj["status"] = "success"
return json.dumps(return_obj)

0 comments on commit 38b122a

Please sign in to comment.