227 lines
6.5 KiB
Python
227 lines
6.5 KiB
Python
from datetime import datetime
|
|
from decimal import Decimal
|
|
from grant.extensions import ma, db
|
|
from sqlalchemy.ext.hybrid import hybrid_property
|
|
from sqlalchemy import func, select
|
|
from sqlalchemy.orm import column_property
|
|
from grant.utils.enums import RFPStatus
|
|
from grant.utils.misc import dt_to_unix, gen_random_id
|
|
from grant.utils.enums import Category
|
|
|
|
rfp_liker = db.Table(
|
|
"rfp_liker",
|
|
db.Model.metadata,
|
|
db.Column("user_id", db.Integer, db.ForeignKey("user.id")),
|
|
db.Column("rfp_id", db.Integer, db.ForeignKey("rfp.id")),
|
|
)
|
|
|
|
|
|
class RFP(db.Model):
|
|
__tablename__ = "rfp"
|
|
|
|
id = db.Column(db.Integer(), primary_key=True)
|
|
date_created = db.Column(db.DateTime)
|
|
|
|
title = db.Column(db.String(255), nullable=False)
|
|
brief = db.Column(db.String(255), nullable=False)
|
|
content = db.Column(db.Text, nullable=False)
|
|
category = db.Column(db.String(255), nullable=True)
|
|
status = db.Column(db.String(255), nullable=False)
|
|
matching = db.Column(db.Boolean, default=False, nullable=False)
|
|
_bounty = db.Column("bounty", db.String(255), nullable=True)
|
|
date_closes = db.Column(db.DateTime, nullable=True)
|
|
date_opened = db.Column(db.DateTime, nullable=True)
|
|
date_closed = db.Column(db.DateTime, nullable=True)
|
|
version = db.Column(db.String(255), nullable=True)
|
|
|
|
ccr = db.relationship("CCR", uselist=False, back_populates="rfp")
|
|
|
|
# Relationships
|
|
proposals = db.relationship(
|
|
"Proposal",
|
|
backref="rfp",
|
|
lazy=True,
|
|
cascade="all, delete-orphan",
|
|
)
|
|
accepted_proposals = db.relationship(
|
|
"Proposal",
|
|
lazy=True,
|
|
primaryjoin="and_(Proposal.rfp_id==RFP.id, Proposal.status=='LIVE')",
|
|
cascade="all, delete-orphan",
|
|
)
|
|
|
|
likes = db.relationship(
|
|
"User", secondary=rfp_liker, back_populates="liked_rfps"
|
|
)
|
|
likes_count = column_property(
|
|
select([func.count(rfp_liker.c.rfp_id)])
|
|
.where(rfp_liker.c.rfp_id == id)
|
|
.correlate_except(rfp_liker)
|
|
)
|
|
|
|
@hybrid_property
|
|
def bounty(self):
|
|
return self._bounty
|
|
|
|
@bounty.setter
|
|
def bounty(self, bounty: str):
|
|
if bounty and Decimal(bounty) > 0:
|
|
self._bounty = bounty
|
|
else:
|
|
self._bounty = None
|
|
|
|
@hybrid_property
|
|
def authed_liked(self):
|
|
from grant.utils.auth import get_authed_user
|
|
|
|
authed = get_authed_user()
|
|
if not authed:
|
|
return False
|
|
res = (
|
|
db.session.query(rfp_liker)
|
|
.filter_by(user_id=authed.id, rfp_id=self.id)
|
|
.count()
|
|
)
|
|
if res:
|
|
return True
|
|
return False
|
|
|
|
def like(self, user, is_liked):
|
|
if is_liked:
|
|
self.likes.append(user)
|
|
else:
|
|
self.likes.remove(user)
|
|
db.session.flush()
|
|
|
|
def __init__(
|
|
self,
|
|
title: str,
|
|
brief: str,
|
|
content: str,
|
|
bounty: str,
|
|
date_closes: datetime,
|
|
matching: bool = False,
|
|
status: str = RFPStatus.DRAFT,
|
|
):
|
|
assert RFPStatus.includes(status)
|
|
self.id = gen_random_id(RFP)
|
|
self.date_created = datetime.now()
|
|
self.title = title[:255]
|
|
self.brief = brief[:255]
|
|
self.content = content
|
|
self.bounty = bounty
|
|
self.date_closes = date_closes
|
|
self.matching = matching
|
|
self.status = status
|
|
self.version = '2'
|
|
|
|
|
|
class RFPSchema(ma.Schema):
|
|
class Meta:
|
|
model = RFP
|
|
# Fields to expose
|
|
fields = (
|
|
"id",
|
|
"title",
|
|
"brief",
|
|
"content",
|
|
"status",
|
|
"matching",
|
|
"bounty",
|
|
"date_created",
|
|
"date_closes",
|
|
"date_opened",
|
|
"date_closed",
|
|
"accepted_proposals",
|
|
"authed_liked",
|
|
"likes_count",
|
|
"is_version_two",
|
|
"ccr"
|
|
)
|
|
|
|
ccr = ma.Nested("CCRSchema", exclude=["rfp"])
|
|
status = ma.Method("get_status")
|
|
date_closes = ma.Method("get_date_closes")
|
|
date_opened = ma.Method("get_date_opened")
|
|
date_closed = ma.Method("get_date_closed")
|
|
accepted_proposals = ma.Nested("ProposalSchema", many=True, exclude=["rfp"])
|
|
is_version_two = ma.Method("get_is_version_two")
|
|
|
|
def get_status(self, obj):
|
|
# Force it into closed state if date_closes is in the past
|
|
if obj.date_closes and obj.date_closes <= datetime.today():
|
|
return RFPStatus.CLOSED
|
|
return obj.status
|
|
|
|
def get_date_closes(self, obj):
|
|
return dt_to_unix(obj.date_closes) if obj.date_closes else None
|
|
|
|
def get_date_opened(self, obj):
|
|
return dt_to_unix(obj.date_opened) if obj.date_opened else None
|
|
|
|
def get_date_closed(self, obj):
|
|
return dt_to_unix(obj.date_closed) if obj.date_closed else None
|
|
|
|
def get_is_version_two(self, obj):
|
|
return True if obj.version == '2' else False
|
|
|
|
|
|
rfp_schema = RFPSchema()
|
|
rfps_schema = RFPSchema(many=True)
|
|
|
|
|
|
class AdminRFPSchema(ma.Schema):
|
|
class Meta:
|
|
model = RFP
|
|
# Fields to expose
|
|
fields = (
|
|
"id",
|
|
"title",
|
|
"brief",
|
|
"content",
|
|
"status",
|
|
"matching",
|
|
"bounty",
|
|
"date_created",
|
|
"date_closes",
|
|
"date_opened",
|
|
"date_closed",
|
|
"proposals",
|
|
"is_version_two",
|
|
"ccr"
|
|
)
|
|
|
|
ccr = ma.Nested("CCRSchema", exclude=["rfp"])
|
|
status = ma.Method("get_status")
|
|
date_created = ma.Method("get_date_created")
|
|
date_closes = ma.Method("get_date_closes")
|
|
date_opened = ma.Method("get_date_opened")
|
|
date_closed = ma.Method("get_date_closed")
|
|
proposals = ma.Nested("ProposalSchema", many=True, exclude=["rfp"])
|
|
is_version_two = ma.Method("get_is_version_two")
|
|
|
|
def get_status(self, obj):
|
|
# Force it into closed state if date_closes is in the past
|
|
if obj.date_closes and obj.date_closes <= datetime.today():
|
|
return RFPStatus.CLOSED
|
|
return obj.status
|
|
|
|
def get_date_created(self, obj):
|
|
return dt_to_unix(obj.date_created)
|
|
|
|
def get_date_closes(self, obj):
|
|
return dt_to_unix(obj.date_closes) if obj.date_closes else None
|
|
|
|
def get_date_opened(self, obj):
|
|
return dt_to_unix(obj.date_opened) if obj.date_opened else None
|
|
|
|
def get_date_closed(self, obj):
|
|
return dt_to_unix(obj.date_closes) if obj.date_closes else None
|
|
|
|
def get_is_version_two(self, obj):
|
|
return True if obj.version == '2' else False
|
|
|
|
|
|
admin_rfp_schema = AdminRFPSchema()
|
|
admin_rfps_schema = AdminRFPSchema(many=True)
|