zcash-grant-system/backend/grant/milestone/models.py

158 lines
5.7 KiB
Python
Raw Normal View History

2018-09-10 09:55:26 -07:00
import datetime
from grant.extensions import ma, db
2019-03-14 13:29:02 -07:00
from grant.utils.enums import MilestoneStage
2018-11-13 08:07:09 -08:00
from grant.utils.exceptions import ValidationException
2019-02-11 13:08:51 -08:00
from grant.utils.ma_fields import UnixDate
from grant.utils.misc import gen_random_id
2018-09-10 09:55:26 -07:00
2019-02-11 13:08:51 -08:00
class MilestoneException(Exception):
pass
2018-09-10 09:55:26 -07:00
class Milestone(db.Model):
__tablename__ = "milestone"
id = db.Column(db.Integer(), primary_key=True)
2019-02-11 13:08:51 -08:00
index = db.Column(db.Integer(), nullable=False)
2018-09-10 09:55:26 -07:00
date_created = db.Column(db.DateTime, nullable=False)
title = db.Column(db.String(255), nullable=False)
content = db.Column(db.Text, nullable=False)
payout_percent = db.Column(db.String(255), nullable=False)
immediate_payout = db.Column(db.Boolean)
date_estimated = db.Column(db.DateTime, nullable=False)
2019-02-11 13:08:51 -08:00
stage = db.Column(db.String(255), nullable=False)
date_requested = db.Column(db.DateTime, nullable=True)
requested_user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True)
date_rejected = db.Column(db.DateTime, nullable=True)
reject_reason = db.Column(db.String(255))
reject_arbiter_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True)
date_accepted = db.Column(db.DateTime, nullable=True)
accept_arbiter_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=True)
date_paid = db.Column(db.DateTime, nullable=True)
paid_tx_id = db.Column(db.String(255))
2018-09-10 09:55:26 -07:00
proposal_id = db.Column(db.Integer, db.ForeignKey("proposal.id"), nullable=False)
def __init__(
self,
2019-02-11 13:08:51 -08:00
index: int,
2018-09-10 09:55:26 -07:00
title: str,
content: str,
date_estimated: datetime,
payout_percent: str,
immediate_payout: bool,
2019-02-11 13:08:51 -08:00
stage: str = MilestoneStage.IDLE,
proposal_id=int,
2018-09-10 09:55:26 -07:00
):
self.id = gen_random_id(Milestone)
2018-09-10 09:55:26 -07:00
self.title = title
self.content = content
self.stage = stage
self.date_estimated = date_estimated
self.payout_percent = payout_percent
self.immediate_payout = immediate_payout
self.proposal_id = proposal_id
self.date_created = datetime.datetime.now()
2019-02-11 13:08:51 -08:00
self.index = index
2019-01-23 07:00:30 -08:00
2019-03-14 13:29:02 -07:00
@staticmethod
def make(milestones_data, proposal):
if milestones_data:
# Delete & re-add milestones
[db.session.delete(x) for x in proposal.milestones]
for i, milestone_data in enumerate(milestones_data):
m = Milestone(
title=milestone_data["title"],
content=milestone_data["content"],
date_estimated=datetime.datetime.fromtimestamp(milestone_data["date_estimated"]),
payout_percent=str(milestone_data["payout_percent"]),
immediate_payout=milestone_data["immediate_payout"],
proposal_id=proposal.id,
index=i
)
db.session.add(m)
2018-11-13 08:07:09 -08:00
@staticmethod
def validate(milestone):
if len(milestone.title) > 60:
raise ValidationException("Milestone title must be no more than 60 chars")
2018-09-10 09:55:26 -07:00
2019-02-11 13:08:51 -08:00
def request_payout(self, user_id: int):
if self.stage not in [MilestoneStage.IDLE, MilestoneStage.REJECTED]:
2019-02-11 13:08:51 -08:00
raise MilestoneException(f'Cannot request payout for milestone at {self.stage} stage')
self.stage = MilestoneStage.REQUESTED
self.date_requested = datetime.datetime.now()
self.requested_user_id = user_id
def reject_request(self, arbiter_id: int, reason: str):
if self.stage != MilestoneStage.REQUESTED:
raise MilestoneException(f'Cannot reject payout request for milestone at {self.stage} stage')
self.stage = MilestoneStage.REJECTED
self.date_rejected = datetime.datetime.now()
self.reject_reason = reason
self.reject_arbiter_id = arbiter_id
def accept_immediate(self):
if self.immediate_payout and self.index == 0:
self.date_requested = datetime.datetime.now()
self.stage = MilestoneStage.ACCEPTED
self.date_accepted = datetime.datetime.now()
db.session.add(self)
db.session.flush()
2019-02-11 13:08:51 -08:00
def accept_request(self, arbiter_id: int):
if self.stage != MilestoneStage.REQUESTED:
raise MilestoneException(f'Cannot accept payout request for milestone at {self.stage} stage')
2019-02-13 08:54:46 -08:00
self.stage = MilestoneStage.ACCEPTED
2019-02-11 13:08:51 -08:00
self.date_accepted = datetime.datetime.now()
self.accept_arbiter_id = arbiter_id
def mark_paid(self, tx_id: str):
if self.stage != MilestoneStage.ACCEPTED:
raise MilestoneException(f'Cannot pay a milestone at {self.stage} stage')
self.stage = MilestoneStage.PAID
self.date_paid = datetime.datetime.now()
self.paid_tx_id = tx_id
2018-09-10 09:55:26 -07:00
class MilestoneSchema(ma.Schema):
class Meta:
model = Milestone
# Fields to expose
fields = (
"title",
2019-02-11 13:08:51 -08:00
"index",
"id",
2018-09-10 09:55:26 -07:00
"content",
"stage",
"payout_percent",
"immediate_payout",
2019-02-11 13:08:51 -08:00
"reject_reason",
"paid_tx_id",
2018-09-10 09:55:26 -07:00
"date_created",
2019-02-11 13:08:51 -08:00
"date_estimated",
"date_requested",
"date_rejected",
"date_accepted",
"date_paid",
2018-09-10 09:55:26 -07:00
)
2019-02-11 13:08:51 -08:00
date_created = UnixDate(attribute='date_created')
date_estimated = UnixDate(attribute='date_estimated')
date_requested = UnixDate(attribute='date_requested')
date_rejected = UnixDate(attribute='date_rejected')
date_accepted = UnixDate(attribute='date_accepted')
date_paid = UnixDate(attribute='date_paid')
2018-09-10 09:55:26 -07:00
milestone_schema = MilestoneSchema()
milestones_schema = MilestoneSchema(many=True)