Exemplo n.º 1
0
    def approve_pending(self, is_approve, reject_reason=None):
        self.validate_publishable()
        # specific validation
        if not self.status == ProposalStatus.PENDING:
            raise ValidationException(f"Proposal must be pending to approve or reject")

        if is_approve:
            self.status = ProposalStatus.APPROVED
            self.date_approved = datetime.datetime.now()
            for t in self.team:
                send_email(t.email_address, 'proposal_approved', {
                    'user': t,
                    'proposal': self,
                    'proposal_url': make_url(f'/proposals/{self.id}'),
                    'admin_note': 'Congratulations! Your proposal has been approved.'
                })
        else:
            if not reject_reason:
                raise ValidationException("Please provide a reason for rejecting the proposal")
            self.status = ProposalStatus.REJECTED
            self.reject_reason = reject_reason
            for t in self.team:
                send_email(t.email_address, 'proposal_rejected', {
                    'user': t,
                    'proposal': self,
                    'proposal_url': make_url(f'/proposals/{self.id}'),
                    'admin_note': reject_reason
                })
Exemplo n.º 2
0
def rfw_exists_check(id):
    rfw = RFW.query.get(id)
    if not rfw:
        raise ValidationException("No RFW matching id")
    if rfw.status in [RFWStatus.DRAFT]:
        raise ValidationException("RFW is not viewable")
    return rfw
Exemplo n.º 3
0
    def simple_validate(proposal):
        # Validate fields to be database save-able.
        # Stricter validation is done in validate_publishable.
        stage = proposal.get('stage')
        category = proposal.get('category')

        if stage and not ProposalStage.includes(stage):
            raise ValidationException("Proposal stage {} is not a valid stage".format(stage))
        if category and not Category.includes(category):
            raise ValidationException("Category {} not a valid category".format(category))
Exemplo n.º 4
0
    def validate_publishable(self):
        # Require certain fields
        required_fields = ['title', 'content', 'brief', 'target']
        for field in required_fields:
            if not hasattr(self, field):
                raise ValidationException("Proposal must have a {}".format(field))

        # Stricter limits on certain fields
        if len(self.title) > 60:
            raise ValidationException("Proposal title cannot be longer than 60 characters")
        if len(self.brief) > 140:
            raise ValidationException("Brief cannot be longer than 140 characters")
        if len(self.content) > 250000:
            raise ValidationException("Content cannot be longer than 250,000 characters")
Exemplo n.º 5
0
    def validate(user):
        em = user.get('email_address')
        if not em:
            raise ValidationException('Must have email address')
        if not is_email(em):
            raise ValidationException('Email address looks invalid')

        t = user.get('title')
        if t and len(t) > 255:
            raise ValidationException('Title is too long')

        dn = user.get('display_name')
        if dn and len(dn) > 255:
            raise ValidationException('Display name is too long')
Exemplo n.º 6
0
 def submit_for_approval(self):
     self.validate_publishable()
     allowed_statuses = [CCRStatus.DRAFT, CCRStatus.REJECTED]
     # specific validation
     if self.status not in allowed_statuses:
         raise ValidationException(f"CCR status must be draft or rejected to submit for approval")
     self.set_pending()
Exemplo n.º 7
0
 def publish(self):
     self.validate_publishable()
     # specific validation
     if not self.status == ProposalStatus.APPROVED:
         raise ValidationException(f"Proposal status must be approved")
     self.date_published = datetime.datetime.now()
     self.status = ProposalStatus.LIVE
     self.stage = ProposalStage.WIP
Exemplo n.º 8
0
    def approve_pending(self, is_approve, reject_reason=None):
        from grant.rfp.models import RFP
        self.validate_publishable()
        # specific validation
        if not self.status == CCRStatus.PENDING:
            raise ValidationException(f"CCR must be pending to approve or reject")

        if is_approve:
            self.status = CCRStatus.LIVE
            rfp = RFP(
                title=self.title,
                brief=self.brief,
                content=self.content,
                bounty=self._target,
                date_closes=datetime.now() + timedelta(days=90),
            )
            db.session.add(self)
            db.session.add(rfp)
            db.session.flush()
            self.rfp_id = rfp.id
            db.session.add(rfp)
            db.session.flush()

            # for emails
            db.session.commit()

            send_email(self.author.email_address, 'ccr_approved', {
                'user': self.author,
                'ccr': self,
                'admin_note': f'Congratulations! Your Request has been accepted. There may be a delay between acceptance and final posting as required by the Zcash Foundation.'
            })
            return rfp.id
        else:
            if not reject_reason:
                raise ValidationException("Please provide a reason for rejecting the ccr")
            self.status = CCRStatus.REJECTED
            self.reject_reason = reject_reason
            # for emails
            db.session.add(self)
            db.session.commit()
            send_email(self.author.email_address, 'ccr_rejected', {
                'user': self.author,
                'ccr': self,
                'admin_note': reject_reason
            })
            return None
Exemplo n.º 9
0
    def validate_publishable_milestones(self):
        payout_total = 0.0
        for i, milestone in enumerate(self.milestones):

            if milestone.immediate_payout and i != 0:
                raise ValidationException("Only the first milestone can have an immediate payout")

            if len(milestone.title) > 60:
                raise ValidationException("Milestone title cannot be longer than 60 chars")

            if len(milestone.content) > 200:
                raise ValidationException("Milestone content cannot be longer than 200 chars")

            try:
                p = float(milestone.payout_amount)
                if not p.is_integer():
                    raise ValidationException("Milestone payout must be whole numbers, no decimals")
                if p <= 0:
                    raise ValidationException("Milestone payout must be greater than zero")
            except ValueError:
                raise ValidationException("Milestone payout percent must be a number")

            payout_total += p

        if payout_total != float(self.target):
            raise ValidationException("Payout of milestones must add up to proposal target")
Exemplo n.º 10
0
    def validate_publishable(self):
        self.validate_publishable_milestones()

        # Require certain fields
        required_fields = ['title', 'content', 'brief', 'category', 'target']
        for field in required_fields:
            if not hasattr(self, field):
                raise ValidationException("Proposal must have a {}".format(field))

        # Stricter limits on certain fields
        if len(self.title) > 60:
            raise ValidationException("Proposal title cannot be longer than 60 characters")
        if len(self.brief) > 140:
            raise ValidationException("Brief cannot be longer than 140 characters")
        if len(self.content) > 250000:
            raise ValidationException("Content cannot be longer than 250,000 characters")

        # Then run through regular validation
        Proposal.simple_validate(vars(self))
Exemplo n.º 11
0
def email_subscriptions_to_bits(subs: dict):
    validate_email_subscriptions(subs)
    settings = 0
    for s in EmailSubscription:
        sk = s.value['key']
        si = s.value['bit']
        if sk not in subs:
            raise ValidationException('Missing email_subscriptions key: {}'.format(sk))
        settings = set_bitmap_state(settings, si, subs[sk])
    return settings
Exemplo n.º 12
0
 def submit_for_approval(self):
     self.validate_publishable()
     self.validate_milestone_dates()
     allowed_statuses = [ProposalStatus.DRAFT, ProposalStatus.REJECTED]
     # specific validation
     if self.status not in allowed_statuses:
         raise ValidationException(f"Proposal status must be draft or rejected to submit for approval")
     self.send_admin_email('admin_approval')
     self.status = ProposalStatus.PENDING
     db.session.add(self)
     db.session.flush()
Exemplo n.º 13
0
    def cancel(self):
        if self.status != ProposalStatus.LIVE:
            raise ValidationException("Cannot cancel a proposal until it's live")

        self.stage = ProposalStage.CANCELED
        db.session.add(self)
        db.session.flush()

        # Send emails to team & contributors
        for u in self.team:
            send_email(u.email_address, 'proposal_canceled', {
                'proposal': self,
                'support_url': make_url('/contact'),
            })
Exemplo n.º 14
0
def update_ccr(ccr_id, **kwargs):
    try:
        if g.current_ccr.status not in [CCRStatus.DRAFT, CCRStatus.REJECTED]:
            raise ValidationException(
                f"CCR with status: {g.current_ccr.status} are not authorized for updates"
            )
        g.current_ccr.update(**kwargs)
    except ValidationException as e:
        return {"message": "{}".format(str(e))}, 400
    db.session.add(g.current_ccr)

    # Commit
    db.session.commit()
    return ccr_schema.dump(g.current_ccr), 200
Exemplo n.º 15
0
def update_proposal(milestones, proposal_id, **kwargs):
    # Update the base proposal fields
    try:
        if g.current_proposal.status not in [
                ProposalStatus.DRAFT, ProposalStatus.REJECTED
        ]:
            raise ValidationException(
                f"Proposal with status: {g.current_proposal.status} are not authorized for updates"
            )
        g.current_proposal.update(**kwargs)
    except ValidationException as e:
        return {"message": "{}".format(str(e))}, 400
    db.session.add(g.current_proposal)

    Milestone.make(milestones, g.current_proposal)

    # Commit
    db.session.commit()
    return proposal_schema.dump(g.current_proposal), 200
Exemplo n.º 16
0
def update_proposal(milestones, proposal_id, rfp_opt_in, **kwargs):
    # Update the base proposal fields
    try:
        if g.current_proposal.status not in [
                ProposalStatus.DRAFT, ProposalStatus.LIVE_DRAFT,
                ProposalStatus.REJECTED
        ]:
            raise ValidationException(
                f"Proposal with status: {g.current_proposal.status} are not authorized for updates"
            )
        g.current_proposal.update(**kwargs)
    except ValidationException as e:
        return {"message": "{}".format(str(e))}, 400
    db.session.add(g.current_proposal)

    # twiddle rfp opt-in (modifies proposal matching and/or bounty)
    if rfp_opt_in is not None:
        g.current_proposal.update_rfp_opt_in(rfp_opt_in)

    Milestone.make(milestones, g.current_proposal)

    # Commit
    db.session.commit()
    return proposal_schema.dump(g.current_proposal), 200
Exemplo n.º 17
0
def validate_email_subscriptions(subs: dict):
    for k in subs:
        if not is_email_sub_key(k):
            raise ValidationException('Invalid email_subcriptions key: {}'.format(k))
Exemplo n.º 18
0
 def validate_milestone_dates(self):
     present = datetime.datetime.today().replace(day=1, hour=0, minute=0, second=0, microsecond=0)
     for milestone in self.milestones:
         if present > milestone.date_estimated:
             raise ValidationException("Milestone date estimate must be in the future ")