Brandon Cornejo
7 years ago
commit
7825abf11c
13 changed files with 672 additions and 0 deletions
-
3config.py
-
BINdiscworld.db
-
9discworld/__init__.py
-
95discworld/models.py
-
97discworld/shop.py
-
BINdiscworld/static/favicon.ico
-
76discworld/templates/layout.html
-
205discworld/templates/shop_dashboard.html
-
17discworld/templates/shop_dataentry.html
-
119discworld/templates/shop_product_entries.html
-
36discworld/views.py
-
11uwsgi.ini
-
4wsgi.py
@ -0,0 +1,3 @@ |
|||
DEBUG = False |
|||
SQLALCHEMY_TRACK_MODIFICATIONS = False |
|||
SQLALCHEMY_DATABASE_URI = 'sqlite:///../discworld.db' |
@ -0,0 +1,9 @@ |
|||
from flask import Flask |
|||
from flask_sqlalchemy import SQLAlchemy |
|||
|
|||
app = Flask(__name__) |
|||
app.config.from_object('config') |
|||
|
|||
db = SQLAlchemy(app) |
|||
|
|||
from . import views |
@ -0,0 +1,95 @@ |
|||
from datetime import datetime |
|||
|
|||
from . import ( |
|||
db, |
|||
shop |
|||
) |
|||
|
|||
|
|||
class ShopProduct(db.Model): |
|||
id = db.Column(db.Integer, primary_key = True) |
|||
name = db.Column(db.String(100), unique=True, nullable=False) |
|||
total_listed = db.Column(db.Integer) |
|||
total_sold = db.Column(db.Integer) |
|||
entries = db.relationship('ShopEntry', backref='product', lazy=True, |
|||
order_by="desc(ShopEntry.date)") |
|||
|
|||
def __repr__(self): |
|||
return '<ShopProduct "{}">'.format(self.name) |
|||
|
|||
@property |
|||
def latest_entry(self): |
|||
return ShopEntry.query.filter_by( |
|||
product_id=self.id).order_by(ShopEntry.date.desc()).first() |
|||
|
|||
@property |
|||
def total_stocked(self): |
|||
entries = ShopEntry.query.filter_by(product_id=self.id).order_by( |
|||
ShopEntry.date.asc()) |
|||
|
|||
last_stock = 0 |
|||
stocked_count = 0 |
|||
for entry in entries: |
|||
diff = last_stock - entry.stock |
|||
if diff < 0: |
|||
stocked_count += abs(diff) |
|||
last_stock = entry.stock |
|||
return stocked_count |
|||
|
|||
@property |
|||
def total_sold(self): |
|||
entries = ShopEntry.query.filter_by(product_id=self.id).order_by( |
|||
ShopEntry.date.asc()) |
|||
|
|||
last_stock = 0 |
|||
sold_count = 0 |
|||
for entry in entries: |
|||
diff = last_stock - entry.stock |
|||
if diff > 0: |
|||
sold_count += diff |
|||
last_stock = entry.stock |
|||
return sold_count |
|||
|
|||
@property |
|||
def total_earned(self): |
|||
entries = ShopEntry.query.filter_by(product_id=self.id).order_by( |
|||
ShopEntry.date.asc()) |
|||
|
|||
last_stock = 0 |
|||
earned_count = 0.00 |
|||
for entry in entries: |
|||
diff = last_stock - entry.stock |
|||
if diff > 0: |
|||
earned_count += (entry.price * diff) |
|||
last_stock = entry.stock |
|||
return earned_count |
|||
|
|||
|
|||
class ShopEntry(db.Model): |
|||
id = db.Column(db.Integer, primary_key=True) |
|||
stock = db.Column(db.Integer, unique=False, nullable=False) |
|||
raw_price = db.Column(db.String(20), unique=False, nullable=False) |
|||
raw_stock = db.Column(db.String(2), unique=False, nullable=False) |
|||
date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) |
|||
product_id = db.Column(db.Integer, db.ForeignKey('shop_product.id'), |
|||
nullable=False) |
|||
|
|||
def __repr__(self): |
|||
return '<ShopEntry "{}" {}>'.format( |
|||
self.product.name, |
|||
self.id |
|||
) |
|||
|
|||
@property |
|||
def stock(self): |
|||
stock_map = { |
|||
'zero': 0, 'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, |
|||
'six': 6, 'seven': 7, 'eight': 8, 'nine': 9, 'ten': 10, |
|||
'eleven': 11, 'twelve': 12, 'thirteen': 13, 'fourteen': 14 |
|||
} |
|||
return stock_map[self.raw_stock] |
|||
|
|||
@property |
|||
def price(self): |
|||
brass = shop.convert_lancre_to_brass(self.raw_price) |
|||
return shop.convert_brass_to_am(brass) |
@ -0,0 +1,97 @@ |
|||
import re |
|||
|
|||
from . import ( |
|||
db, |
|||
models |
|||
) |
|||
|
|||
|
|||
def convert_lancre_to_brass(raw_price): |
|||
coins = { |
|||
'penny': 0, |
|||
'shilling': 0, |
|||
'crown': 0, |
|||
'sovereign': 0, |
|||
'hedgehog': 0 |
|||
} |
|||
|
|||
def noz(num): |
|||
if num and num is not '-': |
|||
return int(num) |
|||
return 0 |
|||
|
|||
# Figure out which special notation we have |
|||
if "LC" in raw_price: |
|||
pattern = r'^LC (\d+)\|(\d+|-)\|(\d+|-)$' |
|||
match = re.match(pattern, raw_price) |
|||
groups = match.groups() |
|||
|
|||
coins['penny'] = noz(groups[2]) |
|||
coins['shilling'] = noz(groups[1]) |
|||
coins['crown'] = noz(groups[0]) |
|||
elif "LSov" in raw_price: |
|||
pattern = r'^LSov (\d+)\|(\d+|-)\|(\d+|-)\|(\d+|-)$' |
|||
match = re.match(pattern, raw_price) |
|||
groups = match.groups() |
|||
|
|||
coins['penny'] = noz(groups[3]) |
|||
coins['shilling'] = noz(groups[2]) |
|||
coins['crown'] = noz(groups[1]) |
|||
coins['sovereign'] = noz(groups[0]) |
|||
elif "LH" in raw_price: |
|||
pattern = r'^LH (\d+)\|(\d+|-)\|(\d+|-)\|(\d+|-)\|(\d+|-)$' |
|||
match = re.match(pattern, raw_price) |
|||
groups = match.groups() |
|||
|
|||
coins['penny'] = noz(groups[4]) |
|||
coins['shilling'] = noz(groups[3]) |
|||
coins['crown'] = noz(groups[2]) |
|||
coins['sovereign'] = noz(groups[1]) |
|||
coins['hedgehog'] = noz(groups[0]) |
|||
|
|||
# Convert to brass |
|||
brass_coins = ( |
|||
(coins['hedgehog'] * 248832) + |
|||
(coins['sovereign'] * 20736) + |
|||
(coins['crown'] * 1728) + |
|||
(coins['shilling'] * 144) + |
|||
(coins['penny'] * 12) |
|||
) |
|||
return brass_coins |
|||
|
|||
def convert_brass_to_am(brass_price): |
|||
# 12 brass coins to am pennies |
|||
pennies = brass_price / 4 |
|||
return (pennies/100) |
|||
|
|||
def parse_shop_output(data): |
|||
pattern = r'^\s{3}?\w{2}\)\sAn*\s([\w\s-]+) for (L\w{1,3} [\d\-|]+);\s(\w+)\sleft\.$' |
|||
matches = [m.groups() for m in re.finditer(pattern, data, re.MULTILINE)] |
|||
|
|||
if not matches: |
|||
return |
|||
|
|||
# Iterate over each product line in the data |
|||
seen_products = [] |
|||
for m in matches: |
|||
product = models.ShopProduct.query.filter_by(name=m[0]).first() |
|||
if not product: |
|||
# If we didn't find a product, create it |
|||
product = models.ShopProduct(name=m[0]) |
|||
db.session.add(product) |
|||
# Add a ShopEntry for this row only if stock has changed |
|||
if not product.latest_entry or product.latest_entry.raw_stock != m[2]: |
|||
entry = models.ShopEntry(raw_price=m[1], raw_stock=m[2], product=product) |
|||
db.session.add(entry) |
|||
seen_products.append(product) |
|||
|
|||
# Check all products against seen, record sellouts |
|||
products = models.ShopProduct.query.all() |
|||
for product in products: |
|||
if product not in seen_products and product.latest_entry.stock != 0: |
|||
entry = models.ShopEntry( |
|||
raw_price=product.latest_entry.raw_price, |
|||
raw_stock='zero', product=product |
|||
) |
|||
db.session.add(entry) |
|||
db.session.commit() |
After Width: 16 | Height: 16 | Size: 785 B |
@ -0,0 +1,76 @@ |
|||
<!doctype html> |
|||
<html> |
|||
<head> |
|||
<title>Ramtops Remedies and Reagents</title> |
|||
|
|||
<meta charset="utf-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|||
|
|||
<!-- UIkit CSS --> |
|||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.35/css/uikit.min.css" /> |
|||
|
|||
<!-- UIkit JS --> |
|||
<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.35/js/uikit.min.js"></script> |
|||
<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/3.0.0-beta.35/js/uikit-icons.min.js"></script> |
|||
|
|||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}"> |
|||
<style> |
|||
</style> |
|||
</head> |
|||
<body> |
|||
<div class="uk-container uk-container-large"> |
|||
<!-- Title --> |
|||
<h3 class="uk-text-center uk-heading-line uk-margin-small-top"> |
|||
<a href="/" class="">Ramtops Remedies and Reagents</a> |
|||
</h3> |
|||
|
|||
<!-- Top Bar --> |
|||
<div class="" uk-grid> |
|||
<div class="uk-width-1-3"> {% block left_top_bar %} {% endblock %} </div> |
|||
<div class="uk-width-1-3 uk-text-center"> {% block center_top_bar %} {% endblock %} </div> |
|||
<div class="uk-width-1-3"> |
|||
<a href="/shop/data" class="uk-button uk-button-primary uk-button-small uk-align-right uk-border-rounded"> |
|||
Report Stock |
|||
</a> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Page Content --> |
|||
{% block content %} {% endblock %} |
|||
|
|||
<!-- Footer --> |
|||
<footer class="uk-text-center uk-margin-large-top uk-margin-small-bottom"> |
|||
© 2017 by <a href="http://binaryatrocity.name">Ruhsbaar</a> |
|||
| |
|||
Created for Ramtops Remedies and Reagents |
|||
| |
|||
<a href="http://discworld.starturtle.net">DiscworldMUD</a> |
|||
</footer> |
|||
</div> |
|||
</body> |
|||
{% block pagescripts %} {% endblock %} |
|||
<script> |
|||
function change_date_strings() { |
|||
var times = document.querySelectorAll('table > tbody > tr > td:last-child'); |
|||
for(var time of times) { |
|||
var local = new Date(time.textContent + 'Z'); |
|||
|
|||
var options = { |
|||
weekday: 'short', |
|||
year: 'numeric', |
|||
month: 'short', |
|||
day: 'numeric', |
|||
hour: 'numeric', |
|||
minute: 'numeric', |
|||
timeZoneName: 'short' |
|||
}; |
|||
time.innerText = local.toLocaleString('en-US', options); |
|||
} |
|||
} |
|||
|
|||
/* On Page Ready */ |
|||
document.addEventListener("DOMContentLoaded", function(event) { |
|||
change_date_strings(); |
|||
}); |
|||
</script> |
|||
</html> |
@ -0,0 +1,205 @@ |
|||
{% extends "layout.html" %} |
|||
|
|||
{% block left_top_bar %} |
|||
<button class="uk-button uk-button-default uk-button-small uk-border-rounded" |
|||
uk-toggle="target: #charts-container">Show/Hide Charts</button> |
|||
{% endblock %} |
|||
|
|||
{% block center_top_bar %} |
|||
Total Funds Earned: |
|||
<span id="total_funds_earned" class="uk-text-primary"></span> |
|||
{% endblock %} |
|||
|
|||
{% block content %} |
|||
<div id="charts-container" uk-grid hidden> |
|||
<div class="uk-width-1-2"> |
|||
<canvas id="sales-chart"></canvas> |
|||
</div> |
|||
<div class="uk-width-1-2"> |
|||
<canvas id="stock-chart"></canvas> |
|||
</div> |
|||
</div> |
|||
<table id="products" class="uk-table uk-table-small uk-table-striped uk-table-hover"> |
|||
<thead> |
|||
<tr> |
|||
<th class="uk-table-expand">Product Name</th> |
|||
<th>Current Stock</th> |
|||
<th>Total Stock</th> |
|||
<th>Total Sold</th> |
|||
<th>Total Earned</th> |
|||
<th>Latest Price</th> |
|||
<th>Last Update</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{% for product in products %} |
|||
{% if product.latest_entry != None %} |
|||
<tr> |
|||
<td class="uk-table-link"> |
|||
<a href="/shop/product/{{ product.id }}"> |
|||
{{ product.name }} |
|||
</a> |
|||
</td> |
|||
<td>{{ product.latest_entry.stock }}</td> |
|||
<td>{{ product.total_stocked }}</td> |
|||
<td>{{ product.total_sold }}</td> |
|||
<td>A${{ product.total_earned }}</td> |
|||
<td> |
|||
<span title="{{ product.latest_entry.raw_price}}"> |
|||
A${{ product.latest_entry.price }} |
|||
</span> |
|||
</td> |
|||
<td class="uk-text-nowrap">{{ product.latest_entry.date.isoformat() }}</td> |
|||
</tr> |
|||
{% endif %} |
|||
{% endfor %} |
|||
</tbody> |
|||
</table> |
|||
{% endblock %} |
|||
|
|||
{% block pagescripts %} |
|||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.js"></script> |
|||
<script> |
|||
function highlight_empty_stock() { |
|||
var rows = document.querySelectorAll('table#products > tbody > tr > td:nth-child(2)'); |
|||
for(var row of rows) { |
|||
if(parseInt(row.textContent) == 0) { |
|||
row.parentElement.classList.add('uk-text-danger'); |
|||
} |
|||
} |
|||
} |
|||
|
|||
function calculate_total_earnings() { |
|||
var total_earnings = 0.00; |
|||
var earnings = document.querySelectorAll('table#products > tbody > tr > td:nth-child(5)'); |
|||
for(var earning of earnings) { |
|||
total_earnings += parseFloat(earning.textContent.substring(2)) |
|||
} |
|||
document.getElementById('total_funds_earned').textContent = "A$" + total_earnings.toFixed(2); |
|||
} |
|||
|
|||
/* Chart.js */ |
|||
var item_labels = [ |
|||
{% for product in products %} |
|||
"{{ product.name }}", |
|||
{% endfor %} |
|||
]; |
|||
var sale_data = [ |
|||
{% for product in products %} |
|||
{{ product.total_sold }}, |
|||
{% endfor %} |
|||
]; |
|||
var earnings_data = [ |
|||
{% for product in products %} |
|||
{{ product.total_earned }}, |
|||
{% endfor %} |
|||
]; |
|||
var total_stock_data = [ |
|||
{% for product in products %} |
|||
{{ product.total_stocked }}, |
|||
{% endfor %} |
|||
]; |
|||
var current_stock_data = [ |
|||
{% for product in products %} |
|||
{{ product.latest_entry.stock }}, |
|||
{% endfor %} |
|||
]; |
|||
|
|||
function init_sales_chart(labels, sold_data, earned_data) { |
|||
var ctx = document.getElementById("sales-chart").getContext('2d'); |
|||
var chart = new Chart(ctx, { |
|||
type: 'horizontalBar', |
|||
data: { |
|||
labels: labels, |
|||
datasets: [ |
|||
{ |
|||
label: 'Sold', |
|||
backgroundColor: 'rgb(93, 173, 226)', |
|||
borderColor: 'rgb(89, 131, 227)', |
|||
data: sold_data, |
|||
xAxisID: 'quantity' |
|||
}, |
|||
{ |
|||
label: 'Earned', |
|||
backgroundColor: 'rgb(173, 93, 226)', |
|||
borderColor: 'rgb(131, 89, 227)', |
|||
data: earned_data, |
|||
xAxisID: 'currency' |
|||
} |
|||
], |
|||
}, |
|||
options: { |
|||
elements: { rectangle: { borderWidth: 2, } }, |
|||
responsive: true, |
|||
legend: { position: 'bottom', }, |
|||
title: { display: true, text: 'Sales & Earnings'}, |
|||
scales: { |
|||
xAxes: [ |
|||
{ |
|||
id: 'quantity', |
|||
type: 'linear', |
|||
position: 'top' |
|||
}, |
|||
{ |
|||
id: 'currency', |
|||
type: 'linear', |
|||
position: 'bottom' |
|||
} |
|||
] |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
function init_stock_chart(labels, total_data, current_data) { |
|||
var ctx = document.getElementById("stock-chart").getContext('2d'); |
|||
var chart = new Chart(ctx, { |
|||
type: 'horizontalBar', |
|||
data: { |
|||
labels: labels, |
|||
datasets: [ |
|||
{ |
|||
label: 'Total', |
|||
backgroundColor: 'rgb(54, 84, 126)', |
|||
data: total_data, |
|||
xAxisID: 'quantity' |
|||
}, |
|||
{ |
|||
label: 'Current', |
|||
backgroundColor: 'rgb(73, 133, 226)', |
|||
data: current_data, |
|||
xAxisID: 'big_quantity' |
|||
} |
|||
], |
|||
}, |
|||
options: { |
|||
responsive: true, |
|||
legend: { position: 'bottom', }, |
|||
title: { display: true, text: 'Total/Current Stock'}, |
|||
scales: { |
|||
xAxes: [ |
|||
{ |
|||
id: 'quantity', |
|||
type: 'linear', |
|||
position: 'top' |
|||
}, |
|||
{ |
|||
id: 'big_quantity', |
|||
type: 'linear', |
|||
position: 'bottom' |
|||
} |
|||
] |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/* On Page Ready */ |
|||
document.addEventListener("DOMContentLoaded", function(event) { |
|||
highlight_empty_stock(); |
|||
calculate_total_earnings(); |
|||
init_sales_chart(item_labels, sale_data, earnings_data); |
|||
init_stock_chart(item_labels, total_stock_data, current_stock_data); |
|||
}); |
|||
</script> |
|||
{% endblock %} |
@ -0,0 +1,17 @@ |
|||
{% extends "layout.html" %} |
|||
{% block content %} |
|||
<form id="mission-form" action="{{ url_for('shop_dataentry') }}" method="post" |
|||
class="uk-margin-large-left"> |
|||
<label for="mission-data">Enter shops "Mission Item" output:</label> <br/> |
|||
<textarea class="uk-textarea uk-form-small uk-form-width-large uk-margin-medium-bottom" |
|||
autofocus=true rows=15 name="mission-data"></textarea> |
|||
|
|||
<br/> |
|||
<label for="password">Password</label> |
|||
<input type="password" name="password" |
|||
class="uk-input uk-form-small uk-form-width-small uk-margin-medium-left"/> |
|||
<br/> |
|||
<input type="submit" value="Parse Entries" |
|||
class="uk-button uk-button-primary uk-margin-small-top uk-border-rounded"/> |
|||
</form> |
|||
{% endblock %} |
@ -0,0 +1,119 @@ |
|||
{% extends "layout.html" %} |
|||
|
|||
{% block left_top_bar %} |
|||
<button class="uk-button uk-button-default uk-button-small uk-border-rounded" |
|||
uk-toggle="target: #charts-container">Show/Hide Charts</button> |
|||
{% endblock %} |
|||
|
|||
{% block center_top_bar %} |
|||
<h4 class="uk-text-center">{{ product.name }}</h4> |
|||
{% endblock %} |
|||
|
|||
{% block content %} |
|||
<div id="charts-container" uk-grid hidden> |
|||
<div class="uk-width-1-1"> |
|||
<canvas id="time-chart"></canvas> |
|||
</div> |
|||
</div> |
|||
<table id="products" class="uk-table uk-table-small uk-table-striped uk-table-hover uk-margin-large-left"> |
|||
<thead> |
|||
<tr> |
|||
<th>Stock</th> |
|||
<th>Price (Raw)</th> |
|||
<th>Price (Cvt)</th> |
|||
<th>Update</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
{% for entry in product.entries %} |
|||
<tr> |
|||
<td>{{ entry.stock }}</td> |
|||
<td>{{ entry.raw_price }}</td> |
|||
<td>A${{ entry.price }}</td> |
|||
<td>{{ entry.date.isoformat() }}</td> |
|||
</tr> |
|||
{% endfor %} |
|||
</tbody> |
|||
<caption class="uk-margin-small-bottom">{{ product.entries | length }} total entries.</caption> |
|||
</table> |
|||
{% endblock %} |
|||
|
|||
{% block pagescripts %} |
|||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.3/moment.min.js"></script> |
|||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.js"></script> |
|||
<script> |
|||
/* Chart.js */ |
|||
var item_labels = [ |
|||
"{{ product.name }}", |
|||
]; |
|||
var time_data = [ |
|||
{% for entry in product.entries %} |
|||
{x: "{{ entry.date.isoformat() }}", y: {{ entry.stock }}}, |
|||
{% endfor %} |
|||
]; |
|||
|
|||
function init_time_chart(labels, timedata) { |
|||
var ctx = document.getElementById("time-chart").getContext('2d'); |
|||
var chart = new Chart(ctx, { |
|||
type: 'line', |
|||
data: { |
|||
labels: labels, |
|||
datasets: [ |
|||
{ |
|||
label: 'Entries', |
|||
backgroundColor: 'rgb(93, 173, 226)', |
|||
borderColor: 'rgb(89, 131, 227)', |
|||
fill: false, |
|||
data: timedata, |
|||
} |
|||
], |
|||
}, |
|||
options: { |
|||
responsive: true, |
|||
title: { display: true, text: 'Entries'}, |
|||
scales: { |
|||
xAxes: [ |
|||
{ |
|||
type: 'time', |
|||
distribution: 'series', |
|||
display: true, |
|||
scaleLabel: { |
|||
display: true, |
|||
labelString: 'Date' |
|||
}, |
|||
time: { |
|||
unit: 'day', |
|||
unitStepSize: 1, |
|||
displayFormats: { |
|||
day: 'MMM D YYYY h:mm a' |
|||
} |
|||
}, |
|||
ticks: { |
|||
major: { |
|||
fontStyle: "bold", |
|||
fontColor: "#FF0000" |
|||
}, |
|||
source: 'data' |
|||
} |
|||
} |
|||
], |
|||
yAxes: [ |
|||
{ |
|||
display: true, |
|||
scaleLabel: { |
|||
display: true, |
|||
labelString: 'Stock' |
|||
} |
|||
} |
|||
] |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/* On Page Ready */ |
|||
document.addEventListener("DOMContentLoaded", function(event) { |
|||
init_time_chart(item_labels, time_data); |
|||
}); |
|||
</script> |
|||
{% endblock %} |
@ -0,0 +1,36 @@ |
|||
import re |
|||
|
|||
from flask import ( |
|||
request, |
|||
url_for, |
|||
redirect, |
|||
render_template |
|||
) |
|||
|
|||
from . import ( |
|||
db, |
|||
app, |
|||
models, |
|||
shop |
|||
) |
|||
|
|||
|
|||
@app.route('/') |
|||
def shop_dashboard(): |
|||
return render_template('shop_dashboard.html', |
|||
products=models.ShopProduct.query.all()) |
|||
|
|||
@app.route('/shop/data', methods=['POST','GET']) |
|||
def shop_dataentry(): |
|||
if request.method == 'POST': |
|||
if request.form.get('password') == 'r3m3di3s' and request.form.get('mission-data'): |
|||
data = request.form['mission-data'] |
|||
clean_data = data.replace('\r\n', '\n') |
|||
shop.parse_shop_output(clean_data) |
|||
return redirect(url_for('shop_dashboard')) |
|||
return render_template('shop_dataentry.html') |
|||
|
|||
@app.route('/shop/product/<int:product_id>') |
|||
def shop_product_entries(product_id): |
|||
product = models.ShopProduct.query.filter_by(id=product_id).first_or_404() |
|||
return render_template('shop_product_entries.html', product=product) |
@ -0,0 +1,11 @@ |
|||
[uwsgi] |
|||
module = wsgi:application |
|||
|
|||
master = true |
|||
processes = 4 |
|||
|
|||
socket = discworld.sock |
|||
chmod-scoket = 660 |
|||
vacuum = true |
|||
|
|||
die-on-term = true |
@ -0,0 +1,4 @@ |
|||
from discworld import app as application |
|||
|
|||
if __name__ == "__main__": |
|||
application.run() |
Write
Preview
Loading…
Cancel
Save
Reference in new issue