Skip to content

Commit 7ff23ce

Browse files
committed
tests running
1 parent 636ddd4 commit 7ff23ce

21 files changed

+307
-83
lines changed

.flaskenv

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
YOURAPPLICATION_SETTINGS=/home/marcidy/projects/noisebridge/donate2/donate.cfg
2-
FLASK_APP=donate
1+
APPLICATION_SETTINGS=/home/marcidy/projects/noisebridge/new_donate/donate.cfg
2+
FLASK_APP=/home/marcidy/projects/noisebridge/new_donate/autoapp.py
33
FLASK_ENV=development
4+
FLASK_DEBUG=1

autoapp.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from flask.helpers import get_debug_flag
2+
from donate.appp import create_app
3+
from donate.setting import DevConfig, ProdConfig
4+
5+
CONFIG = DevConfig if get_debug_flag() else ProdConfig
6+
7+
app = create_app(CONFIG)

donate.cfg

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ FLASK_ENV = 'development'
33
# FLASK_ENV = 'production'
44

55
SQLALCHEMY_TRACK_MODIFICATIONS = False
6-
SQLALCHEMY_DATABASE_URI='sqlite:////home/marcidy/projects/noisebridge/donate2/donate.db'
6+
SQLALCHEMY_DATABASE_URI='sqlite:////home/marcidy/projects/noisebridge/new_donate/donate.db'
77
SECRET_KEY = 'dev'
88

donate/__init__.py

-38
Original file line numberDiff line numberDiff line change
@@ -1,38 +0,0 @@
1-
import os
2-
from flask import Flask
3-
from flask_sqlalchemy import SQLAlchemy
4-
from flask_migrate import Migrate
5-
from donate.database import db
6-
7-
8-
def load_models():
9-
from donate import models
10-
11-
12-
load_models()
13-
14-
15-
def create_app(test_config=None):
16-
17-
app = Flask(__name__, instance_relative_config=True)
18-
app.config.from_envvar('YOURAPPLICATION_SETTINGS')
19-
20-
db.init_app(app)
21-
db.app = app
22-
Migrate(app, db)
23-
24-
if test_config is None:
25-
app.config.from_pyfile('config.py', silent=True)
26-
else:
27-
app.config.from_mapping(test_config)
28-
29-
try:
30-
os.makedirs(app.instance_path)
31-
except OSError:
32-
pass
33-
34-
@app.route('/home')
35-
def hello():
36-
return('donate2')
37-
38-
return(app)

donate/app.py

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import os
2+
from flask import Flask
3+
from donate.extensions import db, migrate
4+
from donate.settings import ProdConfig
5+
from donate.models import (
6+
User,
7+
Account,
8+
Project,
9+
Currency,
10+
Transaction,
11+
)
12+
13+
14+
def create_app(config_object=ProdConfig):
15+
16+
app = Flask(__name__.split('.')[0])
17+
app.url_map.strict_slashes = False
18+
app.config.from_object(config_object)
19+
20+
register_extensions(app)
21+
register_shellcontext(app)
22+
23+
return(app)
24+
25+
26+
def register_extensions(app):
27+
db.init_app(app)
28+
migrate.init_app(app, db)
29+
30+
31+
def register_shellcontext(app):
32+
def shell_context():
33+
return{
34+
'db': db,
35+
'user': User,
36+
'account': Account,
37+
'project': Project,
38+
'ccy': Currency,
39+
'tx': Transaction
40+
}
41+
42+
app.shell_context_processor(shell_context)

donate/database.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
from flask_sqlalchemy import SQLAlchemy
1+
from sqlalchemy.orm import relationship
2+
from .extensions import db
23

3-
4-
db = SQLAlchemy()
4+
Column = db.Column
5+
relationship = relationship
6+
Model = db.Model

donate/extensions.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from flask_sqlalchemy import SQLAlchemy, Model
2+
from flask_migrate import Migrate
3+
4+
5+
db = SQLAlchemy()
6+
migrate = Migrate()

donate/models.py

+91-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,24 @@
1-
from donate.database import db
1+
from donate.extensions import db
22
from datetime import datetime
3+
from flask_validator import (
4+
ValidateInteger,
5+
ValidateString,
6+
ValidateEmail,
7+
ValidateNumeric,
8+
)
39

410

511
class User(db.Model):
12+
'''A user is someonme internal to Noisebridge who uses the system for
13+
reportinng purposes. This should include treasurers and priviledged
14+
users who may access sensitive user data for donations
15+
16+
id: unique ID of the user, e.g. primary key
17+
username: name internal to the system
18+
slack: slack handle
19+
email: email address of user
20+
'''
21+
622
id = db.Column(db.Integer, primary_key=True)
723
username = db.Column(db.String(80), unique=True, nullable=False)
824
slack = db.Column(db.String(80), unique=True, nullable=False)
@@ -11,16 +27,40 @@ class User(db.Model):
1127
def __repr__(self):
1228
return('<User {}>'.format(self.username))
1329

30+
@classmethod
31+
def __declare_last__(cls):
32+
ValidateString(User.username, False, True)
33+
ValidateString(User.slack, False, True)
34+
ValidateEmail(User.email,
35+
False,
36+
True,
37+
"not a valid email address")
38+
1439

1540
class Transaction(db.Model):
41+
''' A transaction moves amounts between accounts. When a transaction
42+
occurs, an account must be debited and an account must be credited.
43+
44+
id: unique ID of transaction
45+
amount: the quantity of the transaction, e.g. <X> USD or <Y> BTC.
46+
ccy: the denomiation of the transaction, e.g. 100 <CCY>
47+
datetime: the time of the transaction in epochs
48+
payer_id: The account which will be debited
49+
recvr_id: the account which will be credited
50+
requestor_id: The user who is requesting the transfer
51+
approver_id: The user approving the transfoer
52+
pay_from_acct: Account linked to the payer_id
53+
rec_to_acct: Account linked to recvr_id
54+
'''
55+
1656
id = db.Column(db.Integer, primary_key=True)
1757
amount = db.Column(db.Float, nullable=False)
1858
ccy = db.Column(db.Integer, db.ForeignKey('currency.id'))
1959
datetime = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
2060
payer_id = db.Column(db.Integer,
2161
db.ForeignKey('account.id'),
2262
nullable=False)
23-
recer_id = db.Column(db.Integer,
63+
recvr_id = db.Column(db.Integer,
2464
db.ForeignKey('account.id'),
2565
nullable=False)
2666
requestor_id = db.Column(db.Integer,
@@ -31,26 +71,74 @@ class Transaction(db.Model):
3171
nullable=False)
3272

3373
pay_from_acct = db.relationship('Account', foreign_keys=[payer_id])
34-
rec_to_acct = db.relationship('Account', foreign_keys=[recer_id])
74+
rec_to_acct = db.relationship('Account', foreign_keys=[recvr_id])
75+
76+
@classmethod
77+
def __declare_last__(cls):
78+
ValidateInteger(Transaction.ccy, False, True)
79+
ValidateNumeric(Transaction.amount, False, True)
80+
ValidateInteger(Transaction.payer_id, False, True)
81+
ValidateInteger(Transaction.recvr_id, False, True)
82+
ValidateInteger(Transaction.requestor_id, False, True)
83+
ValidateInteger(Transaction.approver_id, False, True)
3584

3685

3786
class Account(db.Model):
87+
''' Accounts aggregate transactions. They are associated with one and
88+
only one currenct. An account can increase or decrease based on the
89+
sum of the transactions.
90+
91+
id: unique Id
92+
name: name or nmenonic of account
93+
tx_ids: transactions associated with account. Must link to pay/rec to
94+
get debit or credit info
95+
ccy: account denomination e.g. USD or BTC.
96+
'''
97+
3898
id = db.Column(db.Integer, primary_key=True)
3999
name = db.Column(db.String(120), unique=True, nullable=False)
40100
tx_ids = db.Column(db.Integer, db.ForeignKey('transaction.id'))
41101
ccy = db.Column(db.Integer, db.ForeignKey('currency.id'))
42102

103+
@classmethod
104+
def __declare_last__(cls):
105+
ValidateString(Account.name, False, True)
106+
ValidateInteger(Account.tx_ids, False, True)
107+
ValidateInteger(Account.ccy, False, True)
108+
43109

44110
class Project(db.Model):
111+
''' A project has a specific goal, e.g. amount to be reached. It is
112+
linked to an account which provides information about how much has been
113+
donated towards the goal.
114+
115+
id: Unique ID
116+
name: Project name
117+
account_id: Accunt linked to project (might need multiple for multiple ccys
118+
goal: Amount required to read the goal of the project.
119+
(prob need ccy)
120+
'''
121+
45122
id = db.Column(db.Integer, primary_key=True)
46123
name = db.Column(db.String(120), unique=True, nullable=False)
47124
account_id = db.Column(db.Integer,
48125
db.ForeignKey('account.id'),
49126
nullable=False)
50127
goal = db.Column(db.Float, nullable=False, default=0)
51128

129+
@classmethod
130+
def __declare_last__(cls):
131+
ValidateString(Project.name, False, True)
132+
ValidateInteger(Project.account_id, False, True)
133+
ValidateNumeric(Project.goal, False, True)
134+
52135

53136
class Currency(db.Model):
54137
id = db.Column(db.Integer, primary_key=True)
55138
name = db.Column(db.String(120), unique=True, nullable=False)
56139
code = db.Column(db.String(3), unique=True, nullable=False)
140+
141+
@classmethod
142+
def __declare_last__(cls):
143+
ValidateString(Currency.name, False, True)
144+
ValidateString(Currency.code, False, True)

donate/settings.py

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import os
2+
from datetime import timedelta
3+
4+
5+
class Config:
6+
""" Base Configuration """
7+
8+
SECRET_KEY = os.environ.get('DONATE_SECRET', 'key')
9+
APP_DIR = os.path.abspath(os.path.dirname(__file__))
10+
PROJECT_ROOT = os.path.abspath(os.path.join(APP_DIR, os.pardir))
11+
DEBUG_TB_INTERCEPT_REDIRECTS = False
12+
CACHE_TYPE = 'simple'
13+
SQLALCHEMY_TRACK_MODIFICAITONS = False
14+
JWT_AUTH_USERNAME_KEY = 'email'
15+
JWT_AUTH_HEADERS_PREFIX = 'Token'
16+
CORS_ORIGIN_WHITELIST = []
17+
JWT_HEADER_TYPE = 'Token'
18+
19+
20+
class ProdConfig(Config):
21+
""" Production Configuration """
22+
23+
ENV = 'prod'
24+
DEBUG = False
25+
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL',
26+
'postresql://localhost/example')
27+
28+
29+
class DevConfig(Config):
30+
""" Development Configuration """
31+
32+
ENV = 'dev'
33+
DEBUG = True
34+
DB_NAME = 'dev.db'
35+
DB_PATH = os.path.join(Config.PROJECT_ROOT, DB_NAME)
36+
SQLALCHEMY_DATABASE_URI = 'sqlite:////{0}'.format(DB_PATH)
37+
CACHE_TYPE = 'simple'
38+
JWT_ACCESS_TOKEN_EXPIRES = timedelta(10**6)
39+
40+
41+
class TestConfig(Config):
42+
""" Testing Configuration """
43+
44+
TESTING = True
45+
DEBUG = True
46+
SQLALCHEMY_DATABASE_URI = 'sqlite://'
-2.35 KB
Binary file not shown.

migrations/env.py

+13-10
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,6 @@
44
from logging.config import fileConfig
55
import logging
66

7-
from flask import current_app
8-
9-
from donate.database import db
10-
from donate import create_app
11-
127
# this is the Alembic Config object, which provides
138
# access to the values within the .ini file in use.
149
config = context.config
@@ -20,15 +15,21 @@
2015

2116
# add your model's MetaData object here
2217
# for 'autogenerate' support
23-
# from myapp import mymodel
24-
# target_metadata = mymodel.Base.metadata
18+
from donate.models import (
19+
User,
20+
Currency,
21+
Account,
22+
Project,
23+
Transaction,
24+
)
25+
from donate import db
2526

26-
app = create_app()
27+
target_metadata = db.Model.metadata
2728

29+
from flask import current_app
2830
config.set_main_option('sqlalchemy.url',
2931
current_app.config.get('SQLALCHEMY_DATABASE_URI'))
3032
# target_metadata = current_app.extensions['migrate'].db.metadata
31-
target_metadata = db.metadata
3233

3334
# other values from the config, defined by the needs of env.py,
3435
# can be acquired:
@@ -86,10 +87,12 @@ def process_revision_directives(context, revision, directives):
8687
try:
8788
with context.begin_transaction():
8889
context.run_migrations()
90+
except Exception as exception:
91+
logger.error(exception)
92+
raise exception
8993
finally:
9094
connection.close()
9195

92-
9396
if context.is_offline_mode():
9497
run_migrations_offline()
9598
else:

0 commit comments

Comments
 (0)