added upload and messages

geo
Alexander Roidl 2 years ago
parent 83dc392cac
commit 389f9b71cb

BIN
.DS_Store vendored

Binary file not shown.

@ -0,0 +1,7 @@
FROM tiangolo/uwsgi-nginx-flask:python3.8-alpine
RUN apk --update add bash nano
ENV STATIC_URL /static
ENV STATIC_PATH /var/www/app/static
COPY ./requirements.txt /var/www/requirements.txt
RUN pip install -r /var/www/requirements.txt

BIN
app/.DS_Store vendored

Binary file not shown.

@ -6,33 +6,26 @@ from wtforms import Form as NoCsrfForm
from wtforms.fields import StringField, FormField, SubmitField, SelectField, RadioField from wtforms.fields import StringField, FormField, SubmitField, SelectField, RadioField
from app.models import Location, LocationSchema from app.models import Location, LocationSchema
from wtforms.fields import DecimalRangeField from wtforms.fields import DecimalRangeField
from wtforms.widgets import TextArea
# - - - Forms - - - # - - - Forms - - -
# class AuthorForm(NoCsrfForm): # class AuthorForm(NoCsrfForm):
# # this forms is never exposed so we can user the non CSRF version # # this forms is never exposed so we can use the non CSRF version
# author_name = StringField('Author Name', validators=[DataRequired()]) # author_name = StringField('Author Name', validators=[DataRequired()])
# class UploadForm(FlaskForm): class UploadText(FlaskForm):
# title = StringField('title', validators=[InputRequired()]) message = StringField('message', widget=TextArea(), default=None)
# author = FieldList(FormField(AuthorForm, default=lambda: Author()), min_entries=1) longitude = DecimalRangeField('longitude', default=0)
# category = StringField('category', validators=[InputRequired()]) latitude = DecimalRangeField('latitude', default=0)
# year_published = StringField('year published', [validators.Length(max=4)],default=None)
# file = FileField()
# upload = SubmitField(label='Upload') class UploadAudio(FlaskForm):
# wish = SubmitField(label='''I don't have the file, but wish I did.''') message = StringField('message', widget=TextArea(), default=None)
# message = StringField('message', default=None) audio = FileField()
# sameness = DecimalRangeField('sameness', default=0) longitude = DecimalRangeField('longitude', default=0)
# diversity = DecimalRangeField('diversity', default=0) latitude = DecimalRangeField('latitude', default=0)
# gender = DecimalRangeField('gender', default=50)
# choices = [('Student', 'Student'),
# ('Librarian', 'Librarian'),
# ('Pirate', 'Pirate'),
# ('Teacher', 'Teacher'),
# ('Institution', 'Institution'),
# ('All of the above', 'All of the above'),
# ('None of the above', 'None of the above')]
# who = SelectField('', choices=choices, default='Student')
# class EditForm(FlaskForm): # class EditForm(FlaskForm):

@ -25,6 +25,9 @@ class Location(db.Model):
id = db.Column(db.Integer, primary_key = True) id = db.Column(db.Integer, primary_key = True)
longitude = db.Column(db.Numeric(10,8)) longitude = db.Column(db.Numeric(10,8))
latitude = db.Column(db.Numeric(10,8)) latitude = db.Column(db.Numeric(10,8))
loc_type = db.Column(db.String(200))
message = db.Column(db.String(4000))
audio = db.Column(db.String(255))
# title = db.Column(db.String(255)) # title = db.Column(db.String(255))
# file = db.Column(db.String(255)) # file = db.Column(db.String(255))
@ -50,9 +53,12 @@ class Location(db.Model):
# who = db.Column(db.String(255)) # who = db.Column(db.String(255))
def __init__(self, longitude, latitude): def __init__(self, longitude, latitude, loc_type, message, audio):
self.longitude = longitude self.longitude = longitude
self.latitude = latitude self.latitude = latitude
self.loc_type = loc_type
self.message = message
self.audio = audio
# def __repr__(self): # def __repr__(self):
# return '<Title %r>' % self.title # return '<Title %r>' % self.title
@ -66,6 +72,9 @@ class LocationSchema(Schema):
id = fields.Int(dump_only=True) id = fields.Int(dump_only=True)
longitude = fields.Float() longitude = fields.Float()
latitude = fields.Float() latitude = fields.Float()
loc_type = fields.String()
message = fields.String()
audio = fields.String()
def must_not_be_blank(data): def must_not_be_blank(data):

@ -0,0 +1,12 @@
{% macro render_field(field) %}
<dt>{{ field.label }}
<dd>{{ field(**kwargs)|safe }}
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</dd>
{% endmacro %}

@ -1,129 +0,0 @@
{% extends 'base.html' %}
{% block main %}
{% from "_formhelpers.html" import render_field %}
<head>
<script>
function outputUpdate(sameness) {
document.querySelector('#selected-sameness').value = sameness;
}
function outputUpdate2(diversity) {
document.querySelector('#selected-diversity').value = diversity;
}
function outputUpdate3(gender) {
document.querySelector('#selected-gender').value = gender;
}
</script>
</head>
<div class="container" style="float: left; width:50%;">
<div style="width: 98%; border-right: dashed; border-width: 1px;">
<h1 class="page-header">Add Book</h1>
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="alert alert-danger">
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% endwith %}
<form method="POST" action="{{ url_for('add_book') }}" enctype=multipart/form-data>
{{ form.csrf_token }}
<div class="form-group">Title:* <br> {{ form.title (size=50, class="form-control") }}</div>
<br>
<div data-toggle="fieldset" id="phone-fieldset">
Author(s):* <button type="button" data-toggle="fieldset-add-row" data-target="#phone-fieldset">+</button>
<table>
<tr>
<th></th>
<th></th>
</tr>
{% for author in form.author %}
<tr data-toggle="fieldset-entry">
<td>{{ author.author_name (size=50)}}</td>
<td><button type="button" data-toggle="fieldset-remove-row" id="phone-{{loop.index0}}-remove">-</button></td>
</tr>
{% endfor %}
</table>
</div>
<br>
Category:* <br> {{ form.category(size=50, class="form-control") }} <br><br>
Year published: <br> {{ form.year_published(size=8, class="form-control") }} <br><br>
How different is this item to the rest of the collection?
Or is it more of the same? <br>
{{ form.sameness(min=0, max=100, oninput="outputUpdate(value)") }} &nbsp;
<span style="color: #d3d3d3;"><output for="sameness" id="selected-sameness">{{ form.sameness.data }} </output> % different</span>
<br><hr align="left" style="width:96%;"><br>
Check the bibliography. How diverse are the references in this book? <br>
{{ form.diversity(min=0, max=100, oninput="outputUpdate2(value)") }} &nbsp;
<span style="color: #d3d3d3;"><output for="diversity" id="selected-diversity">{{ form.diversity.data }} </output> % diverse</span>
<br><hr align="left" style="width:96%;"><br>
Check the writing. Who is speaking? Is the voice more often male or female? <br>
{{ form.gender(min=1, max=100, oninput="outputUpdate3(value)") }} &nbsp;
<span style="color: #d3d3d3;"><output for="diversity" id="selected-gender">{{ form.gender.data }} </output> % female</span>
<br><hr align="left" style="width:96%;"><br>
Who are you? {{ render_field(form.who) }}
<br><hr align="left" style="width:96%;"><br>
<div style="width: 40%;">
Add a message for future readers: {{ form.message(size=90, class="form-control") }}
<br></div>
<br>
{{ form.file }}
{{ form.upload }}
{{ form.wish }}
</div>
</form>
</div>
<div>
<table class="library_table" id="table" style="width:30% padding:10px; padding-bottom: 400px;" >
<thead>
<tr id="header" style="height:15px;">
<th style="width: 10%;"> <h5> Currently in the library </h5></th>
<th style="width: 20%;"></th>
</tr>
</thead>
<tbody>
<tr>
<td> Titles: </td>
<td> {{ books_all }}</td>
</tr>
<tr>
<td> Authors: </td>
<td> {{ authors_all }} </td>
</tr>
<tr>
<td> Categories: </td>
<td> {{ categories|replace('[', '')|replace(']', '') }}</td>
</tr>
<tr>
<td> Stacks: </td>
<td> {{ stacks_all|replace('[', '')|replace(']', '') }}</td>
</tr>
<tr>
<td> From the years: </td>
<td> {{earliest}} {{latest}}</td>
</tr>
<tr>
<td> Gaps in the collection: </td>
<td> At least {{ books_potential }} potential books missing</td>
</tr>
</tbody>
</table>
</div>
</div>
<clear>
{% endblock %}

@ -0,0 +1,108 @@
{% extends 'base.html' %}
{% block main %}
{% from "_formhelpers.html" import render_field %}
<h1 class="page-header">Add Message</h1>
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="alert alert-danger">
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% endwith %}
<form method="POST" action="{{ url_for('addaudio') }}" enctype=multipart/form-data>
{{ form.csrf_token }}
<input type="hidden" name="longitude" value="{{ longitude }}" />
<input type="hidden" name="latitude" value="{{ latitude }}" />
<div style="width: 40%;">
message: {{ form.message(cols="45", rows="10", class="form-control") }}
</div>
<div id="audio">
<a onclick="record_audio()" href="#">record</a>
<a onclick="stop_audio()" href="#">stop</a>
<span id="seconds_rec"></span><span> seconds</span>
<div id="audio-player-container"></div>
</div>
<input type="file" name="file" id="uploadedFile" accept="audio/*"><br>
<button type="submit">Submit</button>
</form>
<clear>
{% endblock main %}
{% block js%}
<script>
var mediaRecorder;
var seconds_rec = 0;
var seconds_int;
function record_audio(){
seconds_int = setInterval(
function () {
document.getElementById("seconds_rec").innerHTML = seconds_rec;
seconds_rec += 1;
}, 1000);
navigator.mediaDevices.getUserMedia({ audio: true })
.then(stream => {
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.start();
const audioChunks = [];
mediaRecorder.addEventListener("dataavailable", event => {
audioChunks.push(event.data);
});
mediaRecorder.addEventListener("stop", () => {
const audioBlob = new Blob(audioChunks);
const audioUrl = URL.createObjectURL(audioBlob);
var sound = document.createElement('audio');
sound.id = 'audio-player';
sound.controls = 'controls';
sound.src = audioUrl;
console.log(audioUrl)
sound.type = 'audio/ogg';
document.getElementById("audio-player-container").innerHTML = sound.outerHTML;
const audio = new Audio(audioUrl);
//audio.play();
let file = new File([audioBlob], "audio.ogg",{type:"audio/ogg"});
let container = new DataTransfer();
container.items.add(file);
document.getElementById("uploadedFile").files = container.files;
//const audio = new Audio(audioUrl);
//audio.play();
});
setTimeout(() => {
stop_audio()
}, 1000 * 60);
});
}
function stop_audio(){
clearInterval(seconds_int);
mediaRecorder.stop();
}
</script>
{% endblock js%}

@ -0,0 +1,33 @@
{% extends 'base.html' %}
{% block main %}
{% from "_formhelpers.html" import render_field %}
<h1 class="page-header">Add Message</h1>
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="alert alert-danger">
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% endwith %}
<form method="POST" action="{{ url_for('addtext') }}" enctype=multipart/form-data>
{{ form.csrf_token }}
<input type="hidden" name="longitude" value="{{ longitude }}" />
<input type="hidden" name="latitude" value="{{ latitude }}" />
<div style="width: 40%;">
message: {{ form.message(cols="45", rows="10", class="form-control") }}
</div>
<button type="submit">Submit</button>
</form>
<clear>
{% endblock main %}

@ -43,144 +43,12 @@
</div> </div>
</footer> </footer>
{% block js %} {% endblock%}
<script src="{{ url_for("static", filename="js/jquery-3.3.1.min.js") }}"></script> <script src="{{ url_for("static", filename="js/jquery-3.3.1.min.js") }}"></script>
<script src="{{ url_for("static", filename="js/app.js") }}"></script> <script src="{{ url_for("static", filename="js/app.js") }}"></script>
{% block js %} {% endblock%}
<script>
var locations;
function assign_data(data) {
console.log(data);
locations = data;
}
assign_data({{ data_locations|tojson }});
var map = L.map('map', {zoomControl:false,
attributionControl:false,
scrollWheelZoom: false,
zoom: 2000
}).setView([48.505, 1.09], 10);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
zoom:2,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
locations.forEach(function (item, index) {
var circle = L.circle([item.latitude, item.longitude], {
color: 'red',
fillColor: 'red',
fillOpacity: 1,
radius: 30
}).addTo(map);
});
var myPositionCircle = L.circle([48.172934, 9.01236], {
color: 'black',
fillColor: 'black',
fillOpacity: 1,
radius: 30
}).addTo(map);
var x = document.getElementById("position");
let id;
let target;
let options;
//first: latitude, second: longitude
target = {
latitude : 48.172934,
longitude: 9.01236
};
var my_location = {
latitude : 0,
longitude: 0
};
function success(pos) {
const crd = pos.coords;
my_location.longitude = crd.longitude;
my_location.latitude = crd.latitude;
map.setView([my_location.latitude, my_location.longitude], 16);
myPositionCircle.setLatLng([my_location.latitude, my_location.longitude])
console.log("updated")
x.innerHTML = "Latitude: " + crd.latitude +
"<br>Longitude: " + crd.longitude +
"<br>Distance: " + distance(target.longitude, target.latitude, crd.longitude, crd.latitude);
// if we want to clear the watch
// if (target.latitude === crd.latitude && target.longitude === crd.longitude) {
// console.log('Congratulations, you reached the target');
// navigator.geolocation.clearWatch(id);
// }
}
function error(err) {
console.error(`ERROR(${err.code}): ${err.message}`);
console.log("trying again")
id = navigator.geolocation.watchPosition(success, error, options);
}
options = {
enableHighAccuracy: false,
timeout: 5000,
maximumAge: 0
};
id = navigator.geolocation.watchPosition(success, error, options);
function distance(lon1, lat1, lon2, lat2) {
var R = 6371; // Radius of the earth in km
var dLat = (lat2-lat1).toRad(); // Javascript functions in radians
var dLon = (lon2-lon1).toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c; // Distance in km
return d;
}
/** Converts numeric degrees to radians */
if (typeof(Number.prototype.toRad) === "undefined") {
Number.prototype.toRad = function() {
return this * Math.PI / 180;
}
}
function store_location(){
console.log("storing location");
console.log(my_location)
var xhr = new XMLHttpRequest();
xhr.open("POST", "/addlocation", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
longitude: my_location.longitude,
latitude: my_location.latitude
}));
location.reload();
}
</script>
</body> </body>
</html> </html>

@ -5,14 +5,186 @@
<h1 class="header" id="title">GEO</h1> <h1 class="header" id="title">GEO</h1>
<p id="position"></p> <p id="position"></p>
<button id="store_location" onclick="store_location()">store my position</button> <button id="store_location" onclick="store_location()">store my position</button>
<button id="add_text" onclick="add_text()">add message</button>
<button id="add_audio" onclick="add_audio()">add audio</button>
<br><br><br> <br><br><br>
{% for location in locations %} {% for location in locations %}
<div >{{location.id}}: {{location.longitude}}, {{location.latitude}} <a href="location/{{location.id}}/delete">delete</a></div> <div >{{location.id}}: {{location.longitude}}, {{location.latitude}} {{location.message if location.loc_type == "message"}}
{% if location.loc_type == "audio" %}
<audio id="audio-player" controls="" src="uploads/{{location.audio}}"></audio>
{% endif %}
<a href="location/{{location.id}}/delete">delete</a></div>
{% endfor %} {% endfor %}
</div> </div>
{% endblock %} {% endblock main %}
{% block js %}
<script>
var locations;
function assign_data(data) {
console.log(data);
locations = data;
}
assign_data({{ data_locations|tojson }});
var map = L.map('map', {zoomControl:false,
attributionControl:false,
scrollWheelZoom: false,
zoom: 2000
}).setView([48.505, 1.09], 10);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
zoom:2,
attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
locations.forEach(function (item, index) {
try {
var circle = L.circle([item.latitude, item.longitude], {
color: 'red',
fillColor: 'red',
fillOpacity: 1,
radius: 30
}).addTo(map);
} catch (error) {
console.error(error);
}
});
var myPositionCircle = L.circle([48.172934, 9.01236], {
color: 'black',
fillColor: 'black',
fillOpacity: 1,
radius: 30
}).addTo(map);
var x = document.getElementById("position");
let id;
let target;
let options;
//first: latitude, second: longitude
target = {
latitude : 48.172934,
longitude: 9.01236
};
var my_location = {
latitude : 0,
longitude: 0
};
function success(pos) {
const crd = pos.coords;
my_location.longitude = crd.longitude;
my_location.latitude = crd.latitude;
map.setView([my_location.latitude, my_location.longitude], 16);
myPositionCircle.setLatLng([my_location.latitude, my_location.longitude])
console.log("updated")
x.innerHTML = "Latitude: " + crd.latitude +
"<br>Longitude: " + crd.longitude +
"<br>Distance: " + distance(target.longitude, target.latitude, crd.longitude, crd.latitude);
// if we want to clear the watch
// if (target.latitude === crd.latitude && target.longitude === crd.longitude) {
// console.log('Congratulations, you reached the target');
// navigator.geolocation.clearWatch(id);
// }
}
function error(err) {
console.error(`ERROR(${err.code}): ${err.message}`);
console.log("trying again")
// id = navigator.geolocation.watchPosition(success, error, options);
}
options = {
enableHighAccuracy: true,
timeout: 1000,
maximumAge: 1000
};
id = navigator.geolocation.watchPosition(success, error, options);
function distance(lon1, lat1, lon2, lat2) {
var R = 6371; // Radius of the earth in km
var dLat = (lat2-lat1).toRad(); // Javascript functions in radians
var dLon = (lon2-lon1).toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c; // Distance in km
return d;
}
/** Converts numeric degrees to radians */
if (typeof(Number.prototype.toRad) === "undefined") {
Number.prototype.toRad = function() {
return this * Math.PI / 180;
}
}
function store_location(){
console.log("storing location");
console.log(my_location)
var xhr = new XMLHttpRequest();
xhr.open("POST", "./addlocation", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
longitude: my_location.longitude,
latitude: my_location.latitude
}));
xhr.onreadystatechange=function(){
if (xhr.readyState==4 && xhr.status==200){
location.reload();
}
}
}
function add_text(){
window.location.href = "addtext?longitude="+ my_location.longitude +"&latitude="+my_location.latitude;
}
function add_audio(){
window.location.href = "addaudio?longitude="+ my_location.longitude +"&latitude="+my_location.latitude;
}
</script>
{% endblock js %}

@ -14,6 +14,7 @@ from sqlalchemy.sql.expression import func, select
from sqlalchemy.sql import except_ from sqlalchemy.sql import except_
from sqlalchemy.ext.serializer import loads, dumps from sqlalchemy.ext.serializer import loads, dumps
# from app.forms import UploadForm, EditForm, SearchForm, ChatForm, StackForm, AddtoStackForm, EditStackForm # from app.forms import UploadForm, EditForm, SearchForm, ChatForm, StackForm, AddtoStackForm, EditStackForm
from app.forms import UploadText, UploadAudio
from app.models import Location, LocationSchema from app.models import Location, LocationSchema
from app.cover import get_cover from app.cover import get_cover
from app.getannot import get_annotations, get_annot_results, get_annot_book from app.getannot import get_annotations, get_annot_results, get_annot_book
@ -21,7 +22,7 @@ from urllib.parse import quote as urlquote
from app.extractText import extract_text from app.extractText import extract_text
from os import environ from os import environ
from flask_socketio import SocketIO, emit from flask_socketio import SocketIO, emit
import datetime from datetime import datetime
import time import time
from csv import DictWriter, DictReader from csv import DictWriter, DictReader
import io import io
@ -44,6 +45,11 @@ def allowed_file(filename):
# Routing for your application. # Routing for your application.
### ###
@app.route('/uploads/<filename>')
def uploaded_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'],
filename)
@app.route('/', methods= ['POST','GET']) @app.route('/', methods= ['POST','GET'])
def home(): def home():
@ -71,13 +77,69 @@ def hello(name):
def add_location(): def add_location():
if request.method == 'POST': if request.method == 'POST':
data = request.get_json() data = request.get_json()
print("UPDATING DATA")
print(data['longitude']) print(data['longitude'])
location = Location(data['longitude'],data['latitude']) location = Location(data['longitude'],data['latitude'], "mosquito", "", "")
db.session.add(location) db.session.add(location)
db.session.commit() db.session.commit()
return redirect(url_for('home')) return redirect(url_for('home'))
@app.route('/addtext', methods=['POST', 'GET'])
def addtext():
upload_form = UploadText()
longitude = request.args.get('longitude')
latitude = request.args.get('latitude')
print(longitude)
print(latitude)
if request.method == 'POST':
if upload_form.validate_on_submit():
#get data from form
message = upload_form.message.data
longitude = upload_form.longitude.data
latitude = upload_form.latitude.data
location = Location(longitude,latitude, "message", message, "");
db.session.add(location)
db.session.commit()
return redirect(url_for('home'))
return render_template('addtext.html', form=upload_form, longitude=longitude, latitude=latitude)
@app.route('/addaudio', methods=['POST', 'GET'])
def addaudio():
upload_form = UploadAudio()
if request.method == 'GET':
longitude = request.args.get('longitude')
latitude = request.args.get('latitude')
if request.method == 'POST':
if upload_form.validate_on_submit():
#get data from form
message = upload_form.message.data
longitude = upload_form.longitude.data
latitude = upload_form.latitude.data
file = request.files['file']
print(file.filename)
locations = db.session.query(Location).all()
id = len(locations)+1
# Getting the current date and time
dt = datetime.now()
# getting the timestamp
ts = datetime.timestamp(dt)
filename = str(id) + "_" + str(ts) +"_"+ secure_filename(file.filename)
fullpath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(fullpath)
#add to database
location = Location(longitude,latitude, "audio", message, filename);
db.session.add(location)
db.session.commit()
return redirect(url_for('home'))
return render_template('addaudio.html', form=upload_form, longitude=longitude, latitude=latitude)
@app.route('/location/<int:id>/delete', methods=['POST', 'GET']) @app.route('/location/<int:id>/delete', methods=['POST', 'GET'])
def delete_location(id): def delete_location(id):
if request.method == 'GET': if request.method == 'GET':

@ -0,0 +1 @@
from app import app

@ -0,0 +1,13 @@
click==8.1.3
Flask==2.2.2
Flask_SocketIO==5.3.1
flask_sqlalchemy==3.0.2
Flask_WTF==1.0.1
marshmallow==3.18.0
PyPDF2==2.11.1
python-dotenv==0.21.0
requests==2.28.1
SQLAlchemy==1.4.42
Wand==0.6.10
Werkzeug==2.2.2
WTForms==3.0.1

@ -1,3 +1,3 @@
#! /usr/bin/env python #! /usr/bin/env python
from app import app, socketio from app import app, socketio
socketio.run(app,host="0.0.0.0", port=8080, ssl_context='adhoc') socketio.run(app,host="0.0.0.0", port=8080)

@ -0,0 +1,6 @@
#!/bin/bash
app="geo.app"
docker build -t ${app} .
docker run --platform linux/amd64 -p 56733:80 \
--name=${app} \
-v $PWD:/app ${app}

@ -0,0 +1,5 @@
[uwsgi]
module = main
callable = app
master = true
Loading…
Cancel
Save