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

243 lines
7.4 KiB
Python
Raw Normal View History

2018-09-10 09:55:26 -07:00
import datetime
2018-11-13 08:07:09 -08:00
from typing import List
2018-09-10 09:55:26 -07:00
from grant.comment.models import Comment
from grant.extensions import ma, db
from grant.utils.misc import dt_to_unix
2018-11-13 08:07:09 -08:00
from grant.utils.exceptions import ValidationException
DRAFT = 'DRAFT'
PENDING = 'PENDING'
LIVE = 'LIVE'
DELETED = 'DELETED'
STATUSES = [DRAFT, PENDING, LIVE, DELETED]
2018-09-10 09:55:26 -07:00
FUNDING_REQUIRED = 'FUNDING_REQUIRED'
COMPLETED = 'COMPLETED'
PROPOSAL_STAGES = [FUNDING_REQUIRED, COMPLETED]
DAPP = "DAPP"
DEV_TOOL = "DEV_TOOL"
CORE_DEV = "CORE_DEV"
COMMUNITY = "COMMUNITY"
DOCUMENTATION = "DOCUMENTATION"
ACCESSIBILITY = "ACCESSIBILITY"
CATEGORIES = [DAPP, DEV_TOOL, CORE_DEV, COMMUNITY, DOCUMENTATION, ACCESSIBILITY]
proposal_team = db.Table(
'proposal_team', db.Model.metadata,
db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
db.Column('proposal_id', db.Integer, db.ForeignKey('proposal.id'))
)
class ProposalUpdate(db.Model):
__tablename__ = "proposal_update"
id = db.Column(db.Integer(), primary_key=True)
date_created = db.Column(db.DateTime)
proposal_id = db.Column(db.Integer, db.ForeignKey("proposal.id"), nullable=False)
title = db.Column(db.String(255), nullable=False)
content = db.Column(db.Text, nullable=False)
def __init__(self, proposal_id: int, title: str, content: str):
self.proposal_id = proposal_id
self.title = title
self.content = content
self.date_created = datetime.datetime.now()
2018-09-10 09:55:26 -07:00
class Proposal(db.Model):
__tablename__ = "proposal"
id = db.Column(db.Integer(), primary_key=True)
date_created = db.Column(db.DateTime)
2018-11-13 08:07:09 -08:00
# Database info
status = db.Column(db.String(255), nullable=False)
2018-09-10 09:55:26 -07:00
title = db.Column(db.String(255), nullable=False)
2018-11-13 08:07:09 -08:00
brief = db.Column(db.String(255), nullable=False)
2018-09-10 09:55:26 -07:00
stage = db.Column(db.String(255), nullable=False)
content = db.Column(db.Text, nullable=False)
category = db.Column(db.String(255), nullable=False)
2018-11-13 08:07:09 -08:00
# Contract info
2018-11-14 09:27:40 -08:00
target = db.Column(db.String(255), nullable=False)
2018-11-13 08:07:09 -08:00
payout_address = db.Column(db.String(255), nullable=False)
trustees = db.Column(db.String(1024), nullable=False)
deadline_duration = db.Column(db.Integer(), nullable=False)
vote_duration = db.Column(db.Integer(), nullable=False)
proposal_address = db.Column(db.String(255), unique=True, nullable=True)
# Relations
team = db.relationship("User", secondary=proposal_team)
2018-11-15 08:02:16 -08:00
comments = db.relationship(Comment, backref="proposal", lazy=True, cascade="all, delete-orphan")
updates = db.relationship(ProposalUpdate, backref="proposal", lazy=True, cascade="all, delete-orphan")
milestones = db.relationship("Milestone", backref="proposal", lazy=True, cascade="all, delete-orphan")
2018-09-10 09:55:26 -07:00
def __init__(
self,
2018-11-13 08:07:09 -08:00
status: str = 'DRAFT',
title: str = '',
brief: str = '',
content: str = '',
stage: str = '',
target: str = '0',
payout_address: str = '',
trustees: List[str] = [],
deadline_duration: int = 5184000, # 60 days
vote_duration: int = 604800, # 7 days
proposal_address: str = None,
category: str = ''
2018-09-10 09:55:26 -07:00
):
2018-11-13 08:07:09 -08:00
self.date_created = datetime.datetime.now()
self.status = status
2018-09-10 09:55:26 -07:00
self.title = title
2018-11-13 08:07:09 -08:00
self.brief = brief
2018-09-10 09:55:26 -07:00
self.content = content
self.category = category
2018-11-13 08:07:09 -08:00
self.target = target
self.payout_address = payout_address
self.trustees = ','.join(trustees)
self.proposal_address = proposal_address
self.deadline_duration = deadline_duration
self.vote_duration = vote_duration
self.stage = stage
2018-09-10 09:55:26 -07:00
@staticmethod
2018-11-13 08:07:09 -08:00
def validate(proposal):
title = proposal.get('title')
stage = proposal.get('stage')
category = proposal.get('category')
if title and len(title) > 60:
raise ValidationException("Proposal title cannot be longer than 60 characters")
if stage and stage not in PROPOSAL_STAGES:
raise ValidationException("Proposal stage {} not in {}".format(stage, PROPOSAL_STAGES))
if category and category not in CATEGORIES:
raise ValidationException("Category {} not in {}".format(category, CATEGORIES))
2018-09-10 09:55:26 -07:00
@staticmethod
def create(**kwargs):
2018-11-13 08:07:09 -08:00
Proposal.validate(kwargs)
2018-09-10 09:55:26 -07:00
return Proposal(
**kwargs
)
def update(
self,
title: str = '',
brief: str = '',
category: str = '',
2018-11-14 09:27:40 -08:00
content: str = '',
target: str = '0',
payout_address: str = '',
trustees: List[str] = [],
deadline_duration: int = 5184000, # 60 days
vote_duration: int = 604800 # 7 days
):
self.title = title
self.brief = brief
self.category = category
2018-11-14 09:27:40 -08:00
self.content = content
self.target = target
self.payout_address = payout_address
self.trustees = ','.join(trustees)
self.deadline_duration = deadline_duration
self.vote_duration = vote_duration
Proposal.validate(vars(self))
2018-09-10 09:55:26 -07:00
2018-11-13 08:07:09 -08:00
def publish(self):
# Require certain fields
if not self.title:
raise ValidationException("Proposal must have a title")
if not self.content:
raise ValidationException("Proposal must have content")
if not self.proposal_address:
raise ValidationException("Proposal must a contract address")
# Then run through regular validation
Proposal.validate(vars(self))
self.status = 'LIVE'
2018-09-10 09:55:26 -07:00
class ProposalSchema(ma.Schema):
class Meta:
model = Proposal
# Fields to expose
fields = (
"stage",
"date_created",
"title",
"brief",
2018-09-10 09:55:26 -07:00
"proposal_id",
"proposal_address",
"target",
"content",
2018-09-10 09:55:26 -07:00
"comments",
"updates",
2018-09-10 09:55:26 -07:00
"milestones",
"category",
"team",
"trustees",
"payout_address",
"deadline_duration",
"vote_duration"
2018-09-10 09:55:26 -07:00
)
date_created = ma.Method("get_date_created")
proposal_id = ma.Method("get_proposal_id")
trustees = ma.Method("get_trustees")
2018-09-10 09:55:26 -07:00
comments = ma.Nested("CommentSchema", many=True)
updates = ma.Nested("ProposalUpdateSchema", many=True)
team = ma.Nested("UserSchema", many=True)
2018-09-10 09:55:26 -07:00
milestones = ma.Nested("MilestoneSchema", many=True)
def get_proposal_id(self, obj):
return obj.id
2018-09-10 09:55:26 -07:00
def get_date_created(self, obj):
return dt_to_unix(obj.date_created)
def get_trustees(self, obj):
2018-11-14 09:27:40 -08:00
return [i for i in obj.trustees.split(',') if i != '']
2018-09-10 09:55:26 -07:00
proposal_schema = ProposalSchema()
proposals_schema = ProposalSchema(many=True)
class ProposalUpdateSchema(ma.Schema):
class Meta:
model = ProposalUpdate
# Fields to expose
fields = (
"update_id",
"date_created",
"proposal_id",
"title",
"content"
)
date_created = ma.Method("get_date_created")
proposal_id = ma.Method("get_proposal_id")
update_id = ma.Method("get_update_id")
def get_update_id(self, obj):
return obj.id
def get_proposal_id(self, obj):
return obj.proposal_id
def get_date_created(self, obj):
return dt_to_unix(obj.date_created)
proposal_update_schema = ProposalUpdateSchema()
proposals_update_schema = ProposalUpdateSchema(many=True)