first go about
This commit is contained in:
commit
c8d4d9a660
|
@ -0,0 +1,136 @@
|
||||||
|
from flask import Flask, \
|
||||||
|
render_template as Render,\
|
||||||
|
redirect as Redirect, \
|
||||||
|
url_for as MethodUri, \
|
||||||
|
abort as Abort
|
||||||
|
|
||||||
|
from flask_sqlalchemy import SQLAlchemy as DBM
|
||||||
|
from enum import Enum
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
# Init
|
||||||
|
app=Flask(__name__)
|
||||||
|
app.config['SQLALCHEMY_DATABASE_URI']="sqlite:///app.db"
|
||||||
|
DB=DBM(app)
|
||||||
|
|
||||||
|
#Enums
|
||||||
|
class WorkState(Enum):
|
||||||
|
OTHER = 0
|
||||||
|
IDEA = 1
|
||||||
|
CONFIRMED = 2
|
||||||
|
PAID = 3
|
||||||
|
INPROGRESS = 4
|
||||||
|
FINISHED = 5
|
||||||
|
class TxProcessor(Enum):
|
||||||
|
OTHER = 0
|
||||||
|
PAYPAL = 1
|
||||||
|
class TxType(Enum):
|
||||||
|
OTHER = 0
|
||||||
|
NORMAL = 1
|
||||||
|
YCH = 2
|
||||||
|
YCHAUCTION = 3
|
||||||
|
class Currency(Enum):
|
||||||
|
OTHER = 0
|
||||||
|
GBP = 1
|
||||||
|
USD = 2
|
||||||
|
EUR = 3
|
||||||
|
CAD = 4
|
||||||
|
class LinkType(Enum):
|
||||||
|
OTHER = 0
|
||||||
|
WIPSKETCH = 1
|
||||||
|
WIPLINES = 2
|
||||||
|
WIPCOLOUR = 3
|
||||||
|
WIPSHADING = 4
|
||||||
|
WIPOTHER = 5
|
||||||
|
DELIVERABLE = 6
|
||||||
|
FINAL = 7
|
||||||
|
|
||||||
|
#Database stuff
|
||||||
|
class Artist(DB.Model):
|
||||||
|
artist_id = DB.Column(DB.Integer, primary_key=True, nullable=False, unique=True)
|
||||||
|
name = DB.Column(DB.String, nullable=False)
|
||||||
|
social_twitter = DB.Column(DB.String)
|
||||||
|
social_telegram = DB.Column(DB.String)
|
||||||
|
social_mastodon = DB.Column(DB.String)
|
||||||
|
social_furaffinity = DB.Column(DB.String)
|
||||||
|
social_weasyl = DB.Column(DB.String)
|
||||||
|
social_inkbunny = DB.Column(DB.String)
|
||||||
|
social_sofurry = DB.Column(DB.String)
|
||||||
|
social_furrynetwork = DB.Column(DB.String)
|
||||||
|
class Work(DB.Model):
|
||||||
|
work_id = DB.Column(DB.Integer, primary_key=True, nullable=False, unique=True)
|
||||||
|
artist_id = DB.Column(DB.Integer, DB.ForeignKey('artist.artist_id'), nullable=False)
|
||||||
|
state = DB.Column(DB.Enum(WorkState), nullable=False)
|
||||||
|
purchase_type = DB.Column(DB.Enum(TxType),nullable=False)
|
||||||
|
work_desc = DB.Column(DB.String)
|
||||||
|
date_proposed = DB.Column(DB.DateTime)
|
||||||
|
date_accepted = DB.Column(DB.DateTime)
|
||||||
|
date_paid = DB.Column(DB.DateTime)
|
||||||
|
date_inprogress = DB.Column(DB.DateTime)
|
||||||
|
date_completed = DB.Column(DB.DateTime)
|
||||||
|
class WorkLink(DB.Model):
|
||||||
|
link_id = DB.Column(DB.Integer, primary_key=True, nullable=False, unique=True)
|
||||||
|
work_id = DB.Column(DB.Integer, DB.ForeignKey('work.work_id'), nullable=False)
|
||||||
|
linktype = DB.Column(DB.Enum(LinkType), nullable=False)
|
||||||
|
descr = DB.Column(DB.String, nullable=False)
|
||||||
|
uri = DB.Column(DB.String, nullable=False)
|
||||||
|
datetime = DB.Column(DB.DateTime, nullable=False)
|
||||||
|
class Transaction(DB.Model):
|
||||||
|
transaction_id = DB.Column(DB.Integer, primary_key=True, nullable=False, unique=True)
|
||||||
|
artist_id = DB.Column(DB.Integer, DB.ForeignKey('artist.artist_id'), nullable=False)
|
||||||
|
work_id = DB.Column(DB.Integer, DB.ForeignKey('work.work_id'), nullable=False)
|
||||||
|
processor = DB.Column(DB.Enum(TxProcessor), nullable=False)
|
||||||
|
processor_txid = DB.Column(DB.String, unique=True, nullable=False)
|
||||||
|
currency = DB.Column(DB.Enum(Currency), nullable=False)
|
||||||
|
amount = DB.Column(DB.Float, nullable=False)
|
||||||
|
datetime = DB.Column(DB.DateTime, nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
#Debugging stuff
|
||||||
|
def RecreateDB():
|
||||||
|
DB.drop_all()
|
||||||
|
DB.create_all()
|
||||||
|
def PopulateTestData():
|
||||||
|
RecreateDB()
|
||||||
|
tArtist=Artist(name="test artist 1")
|
||||||
|
DB.session.add(tArtist)
|
||||||
|
DB.session.commit()
|
||||||
|
tWork=Work(artist_id=tArtist.artist_id,
|
||||||
|
state=WorkState.FINISHED, purchase_type=TxType.NORMAL)
|
||||||
|
tWorkTwo=Work(artist_id=tArtist.artist_id,
|
||||||
|
state=WorkState.INPROGRESS, purchase_type=TxType.YCHAUCTION)
|
||||||
|
DB.session.add_all((tWork, tWorkTwo))
|
||||||
|
DB.session.commit()
|
||||||
|
|
||||||
|
#Routes
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
_idea=Work.query.filter_by(state=WorkState.IDEA).join(Artist)
|
||||||
|
_conf=Work.query.filter(
|
||||||
|
(Work.state==WorkState.CONFIRMED) |
|
||||||
|
(Work.state==WorkState.PAID)).join(Artist)
|
||||||
|
_inp=Work.query.filter_by(state=WorkState.INPROGRESS).join(Artist)
|
||||||
|
_cmp=Work.query.filter_by(state=WorkState.FINISHED).join(Artist)
|
||||||
|
|
||||||
|
return Render("index.html.j2", ideas=_idea, cnfpaid=_conf, inprog=_inp, done=_cmp)
|
||||||
|
|
||||||
|
@app.route('/list/<listname>')
|
||||||
|
def list(listname=None):
|
||||||
|
_p=Work.query.filter_by(state=WorkState.FINISHED)
|
||||||
|
return Render("list.html.j2", workslist=listname, works=_p.all())
|
||||||
|
|
||||||
|
@app.route('/add')
|
||||||
|
def add(): return Render("add.html.j2")
|
||||||
|
|
||||||
|
@app.route('/update', methods=['POST'])
|
||||||
|
def update(): return Redirect(MethodUri('index'))
|
||||||
|
|
||||||
|
@app.route('/work/<id>')
|
||||||
|
def view_work(id=None): return True
|
||||||
|
|
||||||
|
@app.route('/artist/<id>')
|
||||||
|
def view_artist(id=None):
|
||||||
|
_a=Artist.query.filter_by(artist_id=id).first()
|
||||||
|
_w=Work.query.filter_by(artist_id=id).all()
|
||||||
|
_t=Transaction.query.filter_by(artist_id=id).all()
|
||||||
|
return Render("artist.html.j2", ainfo=_a, works=_w, txes=_t)
|
|
@ -0,0 +1,4 @@
|
||||||
|
pup.cloud Commissions
|
||||||
|
components
|
||||||
|
- web frontend (Flask)
|
||||||
|
- storage (SQLite, PG, Maria)
|
|
@ -0,0 +1,3 @@
|
||||||
|
Flask~=1.1.2
|
||||||
|
Flask-SQLAlchemy~=2.4.4
|
||||||
|
Jinja2~=2.11.2
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en-GB">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="handheldfriendly" content="true" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
|
<meta name="description" content="Furry art commission tracker, written in Flask" />
|
||||||
|
|
||||||
|
<link rel="stylesheet" type="text/css" href="https://assets.pup.cloud/css/chota.min.css" />
|
||||||
|
<style>
|
||||||
|
:root {
|
||||||
|
--colour-lightpurple: #b58dc5;
|
||||||
|
--colour-lightblue: #94b9e6;
|
||||||
|
--colour-green: #6dca81;
|
||||||
|
--grid-maxWidth: 98%;
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
height: 0;
|
||||||
|
background-color: unset;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
width: inherit;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
div.lanes:nth-child(1 of div.lane) {
|
||||||
|
margin-left: inherit;
|
||||||
|
}
|
||||||
|
div.lanes:nth-child(-1 of div.lane) {
|
||||||
|
margin-right: inherit;
|
||||||
|
}
|
||||||
|
.lane {
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid var(--color-darkGrey);
|
||||||
|
}
|
||||||
|
.lane > header {
|
||||||
|
background-color: var(--color-darkGrey);
|
||||||
|
color: white;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding: 0.4rem 1rem;
|
||||||
|
}
|
||||||
|
.status-confirming {
|
||||||
|
--card-outline-colour: var(--color-darkGrey);
|
||||||
|
--card-header-colour: var(--card-outline-colour);
|
||||||
|
--card-header-text-colour: white;
|
||||||
|
}
|
||||||
|
.status-confirmed {
|
||||||
|
--card-outline-colour: var(--colour-lightpurple);
|
||||||
|
--card-header-colour: var(--card-outline-colour);
|
||||||
|
--card-header-text-colour: white;
|
||||||
|
}
|
||||||
|
.status-inprogress {
|
||||||
|
--card-outline-colour: var(--colour-lightblue);
|
||||||
|
--card-header-colour: var(--card-outline-colour);
|
||||||
|
--card-header-text-colour: white;
|
||||||
|
}
|
||||||
|
.status-completed {
|
||||||
|
--card-outline-colour: var(--colour-green);
|
||||||
|
--card-header-colour: var(--card-outline-colour);
|
||||||
|
--card-header-text-colour: white;
|
||||||
|
}
|
||||||
|
.lane > .card {
|
||||||
|
margin: 1rem;
|
||||||
|
box-shadow: 0 1px 0 2px var(--card-outline-colour);
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.lane > .card > header {
|
||||||
|
background-color: var(--card-header-colour);
|
||||||
|
color: var(--card-header-text-colour);
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
padding: 0.4rem 1rem;
|
||||||
|
}
|
||||||
|
.lane > .card > section {
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<title>p.c Commissions :: {% block title %}{% endblock %}</title>
|
||||||
|
|
||||||
|
{% block head_more %}{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
{% include "navigation-bar.html.j2" %}
|
||||||
|
{% block page_body %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,48 @@
|
||||||
|
{% extends 'base.html.j2' %}
|
||||||
|
|
||||||
|
{% block title %}Home{% endblock %}
|
||||||
|
{% block head_more %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block page_body %}
|
||||||
|
<hr/>
|
||||||
|
<div class="container">
|
||||||
|
<div class="row lanes">
|
||||||
|
<div class="col-3 lane status-confirming">
|
||||||
|
<header>Ideas</header>
|
||||||
|
{% for work in ideas %}
|
||||||
|
<div class="card">
|
||||||
|
<header>{{ work.work_desc }}</header>
|
||||||
|
<section>status {{ work.state.name|title }} and artist {{ work.artist.name }}</section>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="col-3 lane status-confirmed">
|
||||||
|
<header>Confirmed/Paid</header>
|
||||||
|
{% for work in cnfpaid %}
|
||||||
|
<div class="card">
|
||||||
|
<header>{{ work.work_desc }}</header>
|
||||||
|
<section>status {{ work.state.name|title }} and artist {{ work.artist.name }}</section>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="col-3 lane status-inprogress">
|
||||||
|
<header>In-Progress</header>
|
||||||
|
{% for work in inprog %}
|
||||||
|
<div class="card">
|
||||||
|
<header>{{ work.work_desc }}</header>
|
||||||
|
<section>status {{ work.state.name|title }} and artist {{ work.artist.name }}</section>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
<div class="col-3 lane status-completed">
|
||||||
|
<header>Completed</header>
|
||||||
|
{% for work in done %}
|
||||||
|
<div class="card">
|
||||||
|
<header>{{ work.work_desc }}</header>
|
||||||
|
<section>status {{ work.state.name|title }} and artist {{ work.artist.name }}</section>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,15 @@
|
||||||
|
{% block nav %}
|
||||||
|
<nav class="nav">
|
||||||
|
<div class="nav-left">
|
||||||
|
<a class="brand" href="/">
|
||||||
|
<img src="https://assets.pup.cloud/img/maffsie_awoo.svg" height=150 alt="" />
|
||||||
|
p.c Commissions
|
||||||
|
</a>
|
||||||
|
<div class="tabs">
|
||||||
|
<a href="/">Home</a>
|
||||||
|
<a href="/add">➕ Add</a>
|
||||||
|
<a href="/completed">Completed</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue