read and create generic strategy
This commit is contained in:
parent
0122e9ed54
commit
1c22fb7b34
|
|
@ -1,11 +1,13 @@
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass, fields
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Strategy():
|
class Strategy():
|
||||||
id: str
|
id: str
|
||||||
enabled: bool
|
enabled: bool
|
||||||
fulfilled: bool
|
fulfilled: bool
|
||||||
created: str
|
createdAt: Optional[str]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_table_name(cls):
|
def get_table_name(cls):
|
||||||
|
|
@ -13,4 +15,31 @@ class Strategy():
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_route_prefix(cls):
|
def get_route_prefix(cls):
|
||||||
return "/strategies/" + cls.__name__.lower()
|
return "/strategies/" + cls.__name__.lower()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_computed_properties():
|
||||||
|
return ["id", "createdAt"]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def compute_properties():
|
||||||
|
return {
|
||||||
|
"createdAt": datetime.utcnow().isoformat() + "Z"
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_order(cls):
|
||||||
|
return [field.name for field in fields(cls)]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def format(cls, fields):
|
||||||
|
for key, value in fields.items():
|
||||||
|
if key in cls.get_formatters():
|
||||||
|
fields[key] = cls.get_formatters()[key](value)
|
||||||
|
return fields
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_formatters():
|
||||||
|
return {
|
||||||
|
"createdAt": lambda str: datetime.fromisoformat(str).strftime('%Y-%m-%d %H:%M')
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
from db import get_connection, getRethinkDB
|
from db import get_connection, getRethinkDB
|
||||||
from dataclasses import fields
|
from dataclasses import fields
|
||||||
|
from typing import List, Type
|
||||||
from flask import jsonify, request, redirect, render_template
|
from flask import jsonify, request, redirect, render_template
|
||||||
r = getRethinkDB()
|
r = getRethinkDB()
|
||||||
|
|
||||||
|
def get_bool_attribute_names(cls: Type) -> List[str]:
|
||||||
|
return [field.name for field in fields(cls) if field.type == bool]
|
||||||
|
|
||||||
def create_routes(cls, app):
|
def create_routes(cls, app):
|
||||||
print("creating routes for " + cls.__name__)
|
print("creating routes for " + cls.__name__)
|
||||||
|
|
||||||
|
|
@ -15,11 +19,34 @@ def create_routes(cls, app):
|
||||||
@app.route(cls.get_route_prefix() + "/", methods=['GET'])
|
@app.route(cls.get_route_prefix() + "/", methods=['GET'])
|
||||||
def get():
|
def get():
|
||||||
cursor = r.table(table_name).run(get_connection())
|
cursor = r.table(table_name).run(get_connection())
|
||||||
items = list(cursor)
|
fields = list(cursor)
|
||||||
|
|
||||||
return render_template(cls.get_route_prefix() + "/index.html", data={
|
return render_template(cls.get_route_prefix() + "/index.html", data={
|
||||||
"title": cls.__name__,
|
"title": cls.__name__,
|
||||||
"headers": [field.name for field in fields(cls)],
|
"fields": [cls.format(field) for field in fields],
|
||||||
"items": items,
|
"prefix": cls.get_route_prefix(),
|
||||||
"prefix": cls.get_route_prefix()
|
"order": cls.get_order()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@app.route(cls.get_route_prefix() + "/create", methods=['GET'])
|
||||||
|
def get_create():
|
||||||
|
return render_template(cls.get_route_prefix() + "/create.html", data={
|
||||||
|
"name": cls.__name__,
|
||||||
|
"prefix": cls.get_route_prefix(),
|
||||||
|
"computed": cls.get_computed_properties(),
|
||||||
|
"fields": {field.name: field.type.__name__ for field in fields(cls)}
|
||||||
|
})
|
||||||
|
|
||||||
|
@app.route(cls.get_route_prefix() + "/create", methods=['POST'])
|
||||||
|
def post_create():
|
||||||
|
if request.headers['Content-Type'] == 'application/x-www-form-urlencoded':
|
||||||
|
data = request.form.to_dict()
|
||||||
|
data.update(cls.compute_properties())
|
||||||
|
|
||||||
|
for key in get_bool_attribute_names(cls):
|
||||||
|
data[key] = key in request.form
|
||||||
|
|
||||||
|
r.table(table_name).insert(data).run(get_connection())
|
||||||
|
return 201
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/styles.css') }}">
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: white;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h2>Create a {{ data.name }}</h2>
|
||||||
|
<form method="POST" action="{{ data.prefix }}/create?submitted">
|
||||||
|
<fieldset>
|
||||||
|
{% for key, value in data.fields.items() %}
|
||||||
|
{% if key is not in data.computed %}
|
||||||
|
<label for="{{ key }}">{{ key }}</label>
|
||||||
|
{% if value == "str" %}
|
||||||
|
<input type="text" name="{{ key }}">
|
||||||
|
{% elif value == "float" %}
|
||||||
|
<input type="number" step="any" name="{{ key }}">
|
||||||
|
{% elif value == "bool" %}
|
||||||
|
<input type="checkbox" name="{{ key }}">
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<button value="cancel" formmethod="dialog" onclick="window.top.postMessage('close', '*')">Cancel</button>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
@ -1,51 +1,57 @@
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Trading Zone Website</title>
|
<title>Trading Zone Website</title>
|
||||||
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/styles.css') }}">
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/styles.css') }}">
|
||||||
<script type="text/javascript" src="{{ url_for('static', filename='js/main.js') }}" ></script>
|
<script type="text/javascript" src="{{ url_for('static', filename='js/main.js') }}"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<table id="conditionTable">
|
<dialog>
|
||||||
<thead>
|
<iframe frameborder="0"></iframe>
|
||||||
<tr>
|
</dialog>
|
||||||
<td colspan="{{ data.headers | length }}"><h2>{{ data.title }}</h2></td>
|
<table>
|
||||||
</tr>
|
<thead>
|
||||||
{% if data.items %}
|
<tr>
|
||||||
<tr>
|
<td colspan="{{ data.order | length }}">
|
||||||
{% for header in data.headers %}
|
<h2>{{ data.title }}</h2>
|
||||||
<th>{{ header }}</th>
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% if data.fields %}
|
||||||
|
<tr>
|
||||||
|
{% for key in data.order %}
|
||||||
|
<th>{{ key }}</th>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<th class="nodata">No Data</th>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for field in data.fields %}
|
||||||
|
<tr onclick="onOpenDialog('{{ data.prefix }}/{{ field.id }}')">
|
||||||
|
{% for key in data.order%}
|
||||||
|
<td>{{ field[key] }}</td>
|
||||||
|
{% endfor %}
|
||||||
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tbody>
|
||||||
{% else %}
|
<tfoot>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="nodata">No Data</th>
|
<td colspan="{{ data.order | length }}" style="text-align: right;">
|
||||||
</tr>
|
<button onclick="onOpenDialog('{{ data.prefix }}/create')">Add Item</button>
|
||||||
{% endif %}
|
</td>
|
||||||
</thead>
|
</tr>
|
||||||
<tbody>
|
</tfoot>
|
||||||
{% for item in data["items"] %}
|
</table>
|
||||||
<tr onclick="onOpenDialog('{{ data.prefix }}/{{ item.id }}')">
|
</div>
|
||||||
<td>{{ item }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
<tfoot>
|
|
||||||
<tr>
|
|
||||||
<td colspan="{{ data.headers | length }}" style="text-align: right;"> <!-- Adjust colspan as per your total columns -->
|
|
||||||
<button onclick="onOpenDialog('{{ data.prefix }}/create')">Add Item</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tfoot>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
Loading…
Reference in New Issue