diff --git a/funding/api.py b/funding/api.py
index 95ee6b7..d898199 100644
--- a/funding/api.py
+++ b/funding/api.py
@@ -5,7 +5,7 @@ from flask_yoloapi import endpoint, parameter
import settings
from funding.bin.utils import get_ip
from funding.bin.qr import QrCodeGenerator
-from funding.factory import app, db_session
+from funding.factory import app, db
from funding.orm.orm import Proposal, User
diff --git a/funding/bin/qr.py b/funding/bin/qr.py
index 4d7a1f4..e369ce2 100644
--- a/funding/bin/qr.py
+++ b/funding/bin/qr.py
@@ -34,8 +34,8 @@ class QrCodeGenerator:
:param color_to: gradient to color
:return:
"""
- if len(address) != settings.COIN_ADDRESS_LENGTH:
- raise Exception('faulty address length')
+ if len(address) not in settings.COIN_ADDRESS_LENGTH:
+ raise Exception(f'faulty address length, should be: {" or ".join(map(str, settings.COIN_ADDRESS_LENGTH))}')
if not dest:
dest = os.path.join(self.base, '%s.png' % address)
diff --git a/funding/bin/utils.py b/funding/bin/utils.py
index 0602b91..4caf0b4 100644
--- a/funding/bin/utils.py
+++ b/funding/bin/utils.py
@@ -8,6 +8,7 @@ from flask import g, request
from flask.json import JSONEncoder
import settings
+from funding.factory import cache
def json_encoder(obj):
@@ -18,62 +19,50 @@ def json_encoder(obj):
class Summary:
@staticmethod
+ @cache.cached(timeout=300, key_prefix="fetch_prices")
def fetch_prices():
- if hasattr(g, 'funding_prices') and g.coin_prices:
- return g.coin_prices
- from funding.factory import cache
- cache_key = 'funding_prices'
- data = cache.get(cache_key)
- if data:
- return data
- data = {
+ return {
'coin-btc': coin_btc_value(),
'btc-usd': price_cmc_btc_usd()
}
- cache.set(cache_key, data=data, expiry=1200)
- g.coin_prices = data
- return data
@staticmethod
- def fetch_stats(purge=False):
- from funding.factory import db_session
+ @cache.cached(timeout=300, key_prefix="funding_stats")
+ def fetch_stats():
+ from funding.factory import db
from funding.orm.orm import Proposal, User, Comment
- from funding.factory import cache
- cache_key = 'funding_stats'
- data = cache.get(cache_key)
- if data and not purge:
- return data
+ data = {}
categories = settings.FUNDING_CATEGORIES
statuses = settings.FUNDING_STATUSES.keys()
for cat in categories:
- q = db_session.query(Proposal)
+ q = db.session.query(Proposal)
q = q.filter(Proposal.category == cat)
res = q.count()
data.setdefault('cats', {})
data['cats'][cat] = res
for status in statuses:
- q = db_session.query(Proposal)
+ q = db.session.query(Proposal)
q = q.filter(Proposal.status == status)
res = q.count()
data.setdefault('statuses', {})
data['statuses'][status] = res
data.setdefault('users', {})
- data['users']['count'] = db_session.query(User.id).count()
- cache.set(cache_key, data=data, expiry=300)
+ data['users']['count'] = db.session.query(User.id).count()
return data
def price_cmc_btc_usd():
headers = {'User-Agent': 'Mozilla/5.0 (Android 4.4; Mobile; rv:41.0) Gecko/41.0 Firefox/41.0'}
try:
- print('request coinmarketcap')
- r = requests.get('https://api.coinmarketcap.com/v2/ticker/1/?convert=USD', headers=headers)
+ r = requests.get('https://api.coingecko.com/api/v3/coins/markets?vs_currency=usd', headers=headers)
r.raise_for_status()
- return r.json().get('data', {}).get('quotes', {}).get('USD', {}).get('price')
+ data = r.json()
+ btc = next(c for c in data if c['symbol'] == 'btc')
+ return btc['current_price']
except:
return
@@ -81,7 +70,6 @@ def price_cmc_btc_usd():
def coin_btc_value():
headers = {'User-Agent': 'Mozilla/5.0 (Android 4.4; Mobile; rv:41.0) Gecko/41.0 Firefox/41.0'}
try:
- print('request TO')
r = requests.get('https://tradeogre.com/api/v1/ticker/BTC-WOW', headers=headers)
r.raise_for_status()
return float(r.json().get('high'))
diff --git a/funding/bin/utils_request.py b/funding/bin/utils_request.py
index 26f1dab..f285e8c 100644
--- a/funding/bin/utils_request.py
+++ b/funding/bin/utils_request.py
@@ -2,16 +2,16 @@ from datetime import datetime
from flask import session, g, request
import settings
from funding.bin.utils import Summary
-from funding.factory import app, db_session
+from funding.factory import app, db
from funding.orm.orm import Proposal, User, Comment
@app.context_processor
def templating():
- from flask.ext.login import current_user
- recent_comments = db_session.query(Comment).filter(Comment.automated == False).order_by(Comment.date_added.desc()).limit(8).all()
+ from flask_login import current_user
+ recent_comments = db.session.query(Comment).filter(Comment.automated == False).order_by(Comment.date_added.desc()).limit(8).all()
summary_data = Summary.fetch_stats()
- newest_users = db_session.query(User).filter(User.admin == False).order_by(User.registered_on.desc()).limit(5).all()
+ newest_users = db.session.query(User).filter(User.admin == False).order_by(User.registered_on.desc()).limit(5).all()
return dict(logged_in=current_user.is_authenticated,
current_user=current_user,
funding_categories=settings.FUNDING_CATEGORIES,
@@ -28,8 +28,6 @@ def before_request():
@app.after_request
def after_request(res):
- if hasattr(g, 'funding_prices'):
- delattr(g, 'funding_prices')
res.headers.add('Accept-Ranges', 'bytes')
if request.full_path.startswith('/api/'):
@@ -45,7 +43,7 @@ def after_request(res):
@app.teardown_appcontext
def shutdown_session(**kwargs):
- db_session.remove()
+ db.session.remove()
@app.errorhandler(404)
diff --git a/funding/cache.py b/funding/cache.py
index b5c308f..e303c2e 100644
--- a/funding/cache.py
+++ b/funding/cache.py
@@ -45,17 +45,3 @@ class JsonRedis(RedisSessionInterface):
redis=redis.Redis(**redis_args()),
key_prefix=key_prefix,
use_signer=use_signer)
-
-
-class WowCache:
- def __init__(self):
- self._cache = redis.StrictRedis(**redis_args())
-
- def get(self, key):
- try:
- return json.loads(self._cache.get(key))
- except:
- return {}
-
- def set(self, key: str, data: dict, expiry=300):
- self._cache.set(key, json.dumps(data, default=json_encoder), ex=expiry)
diff --git a/funding/factory.py b/funding/factory.py
index 9fa6fa9..fffce45 100644
--- a/funding/factory.py
+++ b/funding/factory.py
@@ -1,40 +1,79 @@
# -*- coding: utf-8 -*-
import settings
-from werkzeug.contrib.fixers import ProxyFix
from flask import Flask
+from flask_caching import Cache
+from flask_session import Session
+from flask_sqlalchemy import SQLAlchemy
app = None
-sentry = None
cache = None
-db_session = None
+db = None
bcrypt = None
+def _setup_cache(app: Flask):
+ global cache
+
+ cache_config = {
+ "CACHE_TYPE": "redis",
+ "CACHE_DEFAULT_TIMEOUT": 60,
+ "CACHE_KEY_PREFIX": "wow_cache_"
+ }
+
+ app.config.from_mapping(cache_config)
+ cache = Cache(app)
+
+
+def _setup_session(app: Flask):
+ app.config['SESSION_TYPE'] = 'redis'
+ app.config['SESSION_COOKIE_NAME'] = 'bar'
+ Session(app) # defaults to timedelta(days=31)
+
+
+def _setup_db(app: Flask):
+ global db
+
+ DB_URL = 'postgresql+psycopg2://{user}:{pw}@{url}/{db}'.format(
+ user=settings.PSQL_USER,
+ pw=settings.PSQL_PASS,
+ url=settings.PSQL_HOST,
+ db=settings.PSQL_DB)
+ app.config['SQLALCHEMY_DATABASE_URI'] = DB_URL
+ db = SQLAlchemy(app)
+
+ import funding.orm
+
+ with app.app_context():
+ db.create_all()
+ db.session.commit()
+
+
def create_app():
global app
- global db_session
- global sentry
+ global db
global cache
global bcrypt
- from funding.orm.connect import create_session
- db_session = create_session()
-
- app = Flask(__name__)
- app.wsgi_app = ProxyFix(app.wsgi_app)
+ app = Flask(import_name=__name__,
+ static_folder='static',
+ template_folder='templates')
app.config.from_object(settings)
app.config['PERMANENT_SESSION_LIFETIME'] = 2678400
app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 30
app.secret_key = settings.SECRET
+ _setup_cache(app)
+ _setup_session(app)
+ _setup_db(app)
+
# flask-login
- from flask.ext.login import LoginManager
+ from flask_login import LoginManager
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
- from flask.ext.bcrypt import Bcrypt
+ from flask_bcrypt import Bcrypt
bcrypt = Bcrypt(app)
@login_manager.user_loader
@@ -42,15 +81,10 @@ def create_app():
from funding.orm.orm import User
return User.query.get(int(_id))
- # session init
- from funding.cache import JsonRedis, WowCache
- app.session_interface = JsonRedis(key_prefix=app.config['SESSION_PREFIX'], use_signer=False)
- cache = WowCache()
-
# import routes
from funding import routes
from funding import api
from funding.bin import utils_request
app.app_context().push()
- return app
\ No newline at end of file
+ return app
diff --git a/funding/orm/connect.py b/funding/orm/connect.py
deleted file mode 100644
index 842eaca..0000000
--- a/funding/orm/connect.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from datetime import datetime
-
-import sqlalchemy as sa
-from sqlalchemy.orm import scoped_session, sessionmaker, relationship
-from sqlalchemy.ext.declarative import declarative_base
-
-import settings
-
-
-def create_session():
- from funding.orm.orm import base
- engine = sa.create_engine(settings.SQLALCHEMY_DATABASE_URI, echo=False, encoding="latin")
- session = scoped_session(sessionmaker(autocommit=False,
- autoflush=False,
- bind=engine))
- base.query = session.query_property()
- base.metadata.create_all(bind=engine)
- return session
\ No newline at end of file
diff --git a/funding/orm/orm.py b/funding/orm/orm.py
index 7d7b5e1..86ec16e 100644
--- a/funding/orm/orm.py
+++ b/funding/orm/orm.py
@@ -1,19 +1,29 @@
from datetime import datetime
+import string
+import random
+
+import requests
+from sqlalchemy.orm import relationship, backref
import sqlalchemy as sa
from sqlalchemy.orm import scoped_session, sessionmaker, relationship
from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy.types import Float
+from sqlalchemy_json import MutableJson
+
import settings
+from funding.factory import db
base = declarative_base(name="Model")
-class User(base):
+
+class User(db.Model):
__tablename__ = "users"
- id = sa.Column('user_id', sa.Integer, primary_key=True)
- username = sa.Column(sa.String(20), unique=True, index=True)
- password = sa.Column(sa.String(60))
- email = sa.Column(sa.String(50), unique=True, index=True)
- registered_on = sa.Column(sa.DateTime)
- admin = sa.Column(sa.Boolean, default=False)
+ id = db.Column('user_id', db.Integer, primary_key=True)
+ username = db.Column(db.String(20), unique=True, index=True)
+ password = db.Column(db.String(60))
+ email = db.Column(db.String(50), unique=True, index=True)
+ registered_on = db.Column(db.DateTime)
+ admin = db.Column(db.Boolean, default=False)
proposals = relationship('Proposal', back_populates="user")
comments = relationship("Comment", back_populates="user")
@@ -48,7 +58,7 @@ class User(base):
@classmethod
def add(cls, username, password, email):
- from funding.factory import db_session
+ from funding.factory import db
from funding.validation import val_username, val_email
try:
@@ -57,37 +67,39 @@ class User(base):
val_email(email)
user = User(username, password, email)
- db_session.add(user)
- db_session.commit()
- db_session.flush()
+ db.session.add(user)
+ db.session.commit()
+ db.session.flush()
return user
except Exception as ex:
- db_session.rollback()
+ db.session.rollback()
raise
-class Proposal(base):
+class Proposal(db.Model):
__tablename__ = "proposals"
- id = sa.Column(sa.Integer, primary_key=True)
- headline = sa.Column(sa.VARCHAR, nullable=False)
- content = sa.Column(sa.VARCHAR, nullable=False)
- category = sa.Column(sa.VARCHAR, nullable=False)
- date_added = sa.Column(sa.TIMESTAMP, default=datetime.now)
- html = sa.Column(sa.VARCHAR)
- last_edited = sa.Column(sa.TIMESTAMP)
+ id = db.Column(db.Integer, primary_key=True)
+ archived = db.Column(db.Boolean, default=False)
+ headline = db.Column(db.VARCHAR, nullable=False)
+ content = db.Column(db.VARCHAR, nullable=False)
+ category = db.Column(db.VARCHAR, nullable=False)
+ date_added = db.Column(db.TIMESTAMP, default=datetime.now)
+ html = db.Column(db.VARCHAR)
+ last_edited = db.Column(db.TIMESTAMP)
# the FFS target
- funds_target = sa.Column(sa.Float, nullable=False)
+ funds_target = db.Column(db.Float, nullable=False)
# the FFS progress (cached)
- funds_progress = sa.Column(sa.Float, nullable=False, default=0)
+ funds_progress = db.Column(db.Float, nullable=False, default=0)
# the FFS withdrawal amount (paid to the author)
- funds_withdrew = sa.Column(sa.Float, nullable=False, default=0)
+ funds_withdrew = db.Column(db.Float, nullable=False, default=0)
# the FFS receiving and withdrawal addresses
- addr_donation = sa.Column(sa.VARCHAR)
- addr_receiving = sa.Column(sa.VARCHAR)
+ addr_donation = db.Column(db.VARCHAR)
+ addr_receiving = db.Column(db.VARCHAR)
+ payment_id = db.Column(db.VARCHAR)
# proposal status:
# 0: disabled
@@ -95,9 +107,9 @@ class Proposal(base):
# 2: funding required
# 3: wip
# 4: completed
- status = sa.Column(sa.INTEGER, default=1)
+ status = db.Column(db.INTEGER, default=1)
- user_id = sa.Column(sa.Integer, sa.ForeignKey('users.user_id'))
+ user_id = db.Column(db.Integer, db.ForeignKey('users.user_id'))
user = relationship("User", back_populates="proposals")
payouts = relationship("Payout", back_populates="proposal")
@@ -131,17 +143,12 @@ class Proposal(base):
@classmethod
def find_by_id(cls, pid: int):
- from funding.factory import db_session
+ from funding.factory import db
q = cls.query
q = q.filter(Proposal.id == pid)
result = q.first()
if not result:
return
-
- # check if we have a valid addr_donation generated. if not, make one.
- if not result.addr_donation and result.status == 2:
- from funding.bin.daemon import Daemon
- Proposal.generate_donation_addr(result)
return result
@property
@@ -154,21 +161,21 @@ class Proposal(base):
@property
def comment_count(self):
- from funding.factory import db_session
- q = db_session.query(sa.func.count(Comment.id))
+ from funding.factory import db
+ q = db.session.query(db.func.count(Comment.id))
q = q.filter(Comment.proposal_id == self.id)
return q.scalar()
def get_comments(self):
- from funding.factory import db_session
- q = db_session.query(Comment)
+ from funding.factory import db
+ q = db.session.query(Comment)
q = q.filter(Comment.proposal_id == self.id)
- q = q.filter(Comment.replied_to == None)
+ q = q.filter(Comment.replied_to.is_(None))
q = q.order_by(Comment.date_added.desc())
comments = q.all()
for c in comments:
- q = db_session.query(Comment)
+ q = db.session.query(Comment)
q = q.filter(Comment.proposal_id == self.id)
q = q.filter(Comment.replied_to == c.id)
_c = q.all()
@@ -177,6 +184,12 @@ class Proposal(base):
setattr(self, '_comments', comments)
return self
+ @property
+ def spends(self):
+ amount = sum([p.amount for p in self.payouts])
+ pct = amount / 100 * self.balance['sum']
+ return {"amount": amount, "pct": pct}
+
@property
def balance(self):
"""This property retrieves the current funding status
@@ -184,28 +197,49 @@ class Proposal(base):
daemon too much. Returns a nice dictionary containing
all relevant proposal funding info"""
from funding.bin.utils import Summary, coin_to_usd
- from funding.factory import cache, db_session
- rtn = {'sum': 0.0, 'txs': [], 'pct': 0.0}
+ from funding.factory import cache, db
+ rtn = {'sum': 0.0, 'txs': [], 'pct': 0.0, 'available': 0}
- cache_key = 'coin_balance_pid_%d' % self.id
- data = cache.get(cache_key)
- if not data:
- from funding.bin.daemon import Daemon
- try:
- data = Daemon().get_transfers_in(proposal=self)
- if not isinstance(data, dict):
- print('error; get_transfers_in; %d' % self.id)
- return rtn
- cache.set(cache_key, data=data, expiry=60)
- except Exception as ex:
- print('error; get_transfers_in; %d' % self.id)
- return rtn
+ if self.archived:
+ return rtn
+
+ try:
+ r = requests.get(f'http://{settings.RPC_HOST}:{settings.RPC_PORT}/json_rpc', json={
+ "jsonrpc": "2.0",
+ "id": "0",
+ "method": "get_payments",
+ "params": {
+ "payment_id": self.payment_id
+ }
+ })
+ r.raise_for_status()
+ blob = r.json()
+
+ assert 'result' in blob
+ assert 'payments' in blob['result']
+ assert isinstance(blob['result']['payments'], list)
+ except Exception as ex:
+ return rtn
+
+ txs = blob['result']['payments']
+ for tx in txs:
+ tx['amount_human'] = float(tx['amount'])/1e11
+ tx['txid'] = tx['tx_hash']
+ tx['type'] = 'in'
+
+ data = {
+ 'sum': sum([float(z['amount']) / 1e11 for z in txs]),
+ 'txs': txs
+ }
+
+ if not isinstance(data, dict):
+ print('error; get_transfers_in; %d' % self.id)
+ return rtn
prices = Summary.fetch_prices()
for tx in data['txs']:
if prices:
tx['amount_usd'] = coin_to_usd(amt=tx['amount_human'], btc_per_coin=prices['coin-btc'], usd_per_btc=prices['btc-usd'])
- tx['datetime'] = datetime.fromtimestamp(tx['timestamp'])
if data.get('sum', 0.0):
data['pct'] = 100 / float(self.funds_target / data.get('sum', 0.0))
@@ -216,8 +250,8 @@ class Proposal(base):
if data['pct'] != self.funds_progress:
self.funds_progress = data['pct']
- db_session.commit()
- db_session.flush()
+ db.session.commit()
+ db.session.flush()
if data['available']:
data['remaining_pct'] = 100 / float(data['sum'] / data['available'])
@@ -226,74 +260,9 @@ class Proposal(base):
return data
- @property
- def spends(self):
- from funding.bin.utils import Summary, coin_to_usd
- from funding.factory import cache, db_session
- rtn = {'sum': 0.0, 'txs': [], 'pct': 0.0}
-
- cache_key = 'coin_spends_pid_%d' % self.id
- data = cache.get(cache_key)
- if not data:
- from funding.bin.daemon import Daemon
- try:
- data = Daemon().get_transfers_out(proposal=self)
- if not isinstance(data, dict):
- print('error; get_transfers_out; %d' % self.id)
- return rtn
- cache.set(cache_key, data=data, expiry=60)
- except:
- print('error; get_transfers_out; %d' % self.id)
- return rtn
-
- data['remaining_pct'] = 0.0
- prices = Summary.fetch_prices()
-
- for tx in data['txs']:
- if prices:
- tx['amount_usd'] = coin_to_usd(amt=tx['amount_human'], btc_per_coin=prices['coin-btc'], usd_per_btc=prices['btc-usd'])
- tx['datetime'] = datetime.fromtimestamp(tx['timestamp'])
-
- if data.get('sum', 0.0):
- data['pct'] = 100 / float(self.funds_target / data.get('sum', 0.0))
- data['spent'] = data['sum']
- else:
- data['pct'] = 0.0
- data['spent'] = 0.0
-
- cache_key_in = 'coin_balance_pid_%d' % self.id
- data_in = cache.get(cache_key_in)
- if data_in and data['spent']:
- data['remaining_pct'] = 100 / float(data_in['sum'] / data['spent'])
-
- return data
-
- @staticmethod
- def generate_donation_addr(cls):
- from funding.factory import db_session
- from funding.bin.daemon import Daemon
- if cls.addr_donation:
- return cls.addr_donation
-
- # check if the current user has an account in the wallet
- account = Daemon().get_accounts(cls.id)
- if not account:
- account = Daemon().create_account(cls.id)
- index = account['account_index']
-
- address = account.get('address') or account.get('base_address')
- if not address:
- raise Exception('Cannot generate account/address for pid %d' % cls.id)
-
- # assign donation address, commit to db
- cls.addr_donation = address
- db_session.commit()
- db_session.flush()
- return address
-
@classmethod
def find_by_args(cls, status: int = None, cat: str = None, limit: int = 20, offset=0):
- from funding.factory import db_session
+ from funding.factory import db
if isinstance(status, int) and status not in settings.FUNDING_STATUSES.keys():
raise NotImplementedError('invalid status')
if isinstance(cat, str) and cat not in settings.FUNDING_CATEGORIES:
@@ -313,71 +282,82 @@ class Proposal(base):
@classmethod
def search(cls, key: str):
- key_ilike = '%' + key.replace('%', '') + '%'
+ key_ilike = f"%{key.replace('%', '')}%"
q = Proposal.query
- q = q.filter(sa.or_(
+ q = q.filter(db.or_(
Proposal.headline.ilike(key_ilike),
Proposal.content.ilike(key_ilike)))
return q.all()
-class Payout(base):
+class Payout(db.Model):
__tablename__ = "payouts"
- id = sa.Column(sa.Integer, primary_key=True)
+ id = db.Column(db.Integer, primary_key=True)
- proposal_id = sa.Column(sa.Integer, sa.ForeignKey('proposals.id'))
+ proposal_id = db.Column(db.Integer, db.ForeignKey('proposals.id'))
proposal = relationship("Proposal", back_populates="payouts")
- amount = sa.Column(sa.Integer, nullable=False)
- to_address = sa.Column(sa.VARCHAR, nullable=False)
+ amount = db.Column(db.Integer, nullable=False)
+ to_address = db.Column(db.VARCHAR, nullable=False)
+
+ date_sent = db.Column(db.TIMESTAMP, default=datetime.now)
- ix_proposal_id = sa.Index("ix_proposal_id", proposal_id)
+ ix_proposal_id = db.Index("ix_proposal_id", proposal_id)
@classmethod
def add(cls, proposal_id, amount, to_address):
# @TODO: validate that we can make this payout; check previous payouts
- from flask.ext.login import current_user
+ from flask_login import current_user
if not current_user.admin:
raise Exception("user must be admin to add a payout")
- from funding.factory import db_session
+ from funding.factory import db
try:
payout = Payout(propsal_id=proposal_id, amount=amount, to_address=to_address)
- db_session.add(payout)
- db_session.commit()
- db_session.flush()
+ db.session.add(payout)
+ db.session.commit()
+ db.session.flush()
return payout
except Exception as ex:
- db_session.rollback()
+ db.session.rollback()
raise
@staticmethod
def get_payouts(proposal_id):
- from funding.factory import db_session
- return db_session.query(Payout).filter(Payout.proposal_id == proposal_id).all()
+ from funding.factory import db
+ return db.session.query(Payout).filter(Payout.proposal_id == proposal_id).all()
+
+ @property
+ def as_tx(self):
+ return {
+ "block_height": "-",
+ "type": "out",
+ "amount_human": self.amount,
+ "amount": self.amount
+ }
-class Comment(base):
+class Comment(db.Model):
__tablename__ = "comments"
- id = sa.Column(sa.Integer, primary_key=True)
+ id = db.Column(db.Integer, primary_key=True)
- proposal_id = sa.Column(sa.Integer, sa.ForeignKey('proposals.id'))
+ proposal_id = db.Column(db.Integer, db.ForeignKey('proposals.id'))
proposal = relationship("Proposal", back_populates="comments")
- user_id = sa.Column(sa.Integer, sa.ForeignKey('users.user_id'), nullable=False)
+ user_id = db.Column(db.Integer, db.ForeignKey('users.user_id'), nullable=False)
user = relationship("User", back_populates="comments")
- date_added = sa.Column(sa.TIMESTAMP, default=datetime.now)
+ date_added = db.Column(db.TIMESTAMP, default=datetime.now)
- message = sa.Column(sa.VARCHAR, nullable=False)
- replied_to = sa.Column(sa.ForeignKey("comments.id"))
+ message = db.Column(db.VARCHAR, nullable=False)
+ replied_to = db.Column(db.ForeignKey("comments.id"))
- locked = sa.Column(sa.Boolean, default=False)
+ locked = db.Column(db.Boolean, default=False)
- automated = sa.Column(sa.Boolean, default=False)
+ automated = db.Column(db.Boolean, default=False)
- ix_comment_replied_to = sa.Index("ix_comment_replied_to", replied_to)
- ix_comment_proposal_id = sa.Index("ix_comment_proposal_id", proposal_id)
+ ix_comment_replied_to = db.Index("ix_comment_replied_to", replied_to)
+ ix_comment_proposal_id = db.Index("ix_comment_proposal_id", proposal_id)
@property
def message_html(self):
@@ -390,28 +370,30 @@ class Comment(base):
@staticmethod
def find_by_id(cid: int):
- from funding.factory import db_session
- return db_session.query(Comment).filter(Comment.id == cid).first()
+ from funding.factory import db
+ return db.session.query(Comment).filter(Comment.id == cid).first()
@staticmethod
def remove(cid: int):
- from funding.factory import db_session
- from flask.ext.login import current_user
- if current_user.id != user_id and not current_user.admin:
- raise Exception("no rights to remove this comment")
+ from funding.factory import db
+ from flask_login import current_user
comment = Comment.get(cid=cid)
+
+ if current_user.id != comment.user_id and not current_user.admin:
+ raise Exception("no rights to remove this comment")
+
try:
comment.delete()
- db_session.commit()
- db_session.flush()
+ db.session.commit()
+ db.session.flush()
except:
- db_session.rollback()
+ db.session.rollback()
raise
@staticmethod
def lock(cid: int):
- from funding.factory import db_session
- from flask.ext.login import current_user
+ from funding.factory import db
+ from flask_login import current_user
if not current_user.admin:
raise Exception("admin required")
comment = Comment.find_by_id(cid=cid)
@@ -419,17 +401,17 @@ class Comment(base):
raise Exception("comment by that id not found")
comment.locked = True
try:
- db_session.commit()
- db_session.flush()
+ db.session.commit()
+ db.session.flush()
return comment
except:
- db_session.rollback()
+ db.session.rollback()
raise
@classmethod
def add_comment(cls, pid: int, user_id: int, message: str, cid: int = None, message_id: int = None, automated=False):
- from flask.ext.login import current_user
- from funding.factory import db_session
+ from flask_login import current_user
+ from funding.factory import db
if not message:
raise Exception("empty message")
@@ -448,7 +430,7 @@ class Comment(base):
comment.replied_to = parent.id
else:
try:
- user = db_session.query(User).filter(User.id == user_id).first()
+ user = db.session.query(User).filter(User.id == user_id).first()
if not user:
raise Exception("no user by that id")
comment = next(c for c in user.comments if c.id == message_id)
@@ -460,10 +442,10 @@ class Comment(base):
raise Exception("unknown error")
try:
comment.message = message
- db_session.add(comment)
- db_session.commit()
- db_session.flush()
+ db.session.add(comment)
+ db.session.commit()
+ db.session.flush()
except Exception as ex:
- db_session.rollback()
+ db.session.rollback()
raise Exception(str(ex))
- return comment
\ No newline at end of file
+ return comment
diff --git a/funding/routes.py b/funding/routes.py
index 26e7a87..93580b3 100644
--- a/funding/routes.py
+++ b/funding/routes.py
@@ -1,12 +1,14 @@
from datetime import datetime
+import requests
from flask import request, redirect, Response, abort, render_template, url_for, flash, make_response, send_from_directory, jsonify
-from flask.ext.login import login_user , logout_user , current_user, login_required, current_user
+from flask_login import login_user , logout_user , current_user, login_required, current_user
from dateutil.parser import parse as dateutil_parse
from flask_yoloapi import endpoint, parameter
import settings
-from funding.factory import app, db_session
+from funding.bin.utils import Summary
+from funding.factory import app, db, cache
from funding.orm.orm import Proposal, User, Comment
@@ -27,7 +29,7 @@ def api():
@app.route('/proposal/add/disclaimer')
def proposal_add_disclaimer():
- return make_response(render_template(('proposal/disclaimer.html')))
+ return make_response(render_template('proposal/disclaimer.html'))
@app.route('/proposal/add')
@@ -79,9 +81,9 @@ def propsal_comment_reply(cid, pid):
@app.route('/proposal/
- AEON (camthegeek) has contributed commits to upstream; WOW is grateful. + AEON (camthegeek) has contributed commits upstream; WOW is grateful.
diff --git a/funding/templates/base.html b/funding/templates/base.html index 6d57fe7..91885c7 100644 --- a/funding/templates/base.html +++ b/funding/templates/base.html @@ -64,7 +64,7 @@ diff --git a/funding/templates/login.html b/funding/templates/login.html index 8f23a0f..9f4866c 100644 --- a/funding/templates/login.html +++ b/funding/templates/login.html @@ -27,7 +27,7 @@