コード例 #1
0
def reject_permanently_proposal(proposal_id, reject_reason):
    proposal = Proposal.query.get(proposal_id)

    if not proposal:
        return {"message": "No proposal found."}, 404

    reject_permanently_statuses = [
        ProposalStatus.REJECTED, ProposalStatus.PENDING
    ]

    if proposal.status not in reject_permanently_statuses:
        return {"message": "Proposal status is not REJECTED or PENDING."}, 401

    proposal.status = ProposalStatus.REJECTED_PERMANENTLY
    proposal.reject_reason = reject_reason

    db.session.add(proposal)
    db.session.commit()

    for user in proposal.team:
        send_email(
            user.email_address, 'proposal_rejected_permanently', {
                'user': user,
                'proposal': proposal,
                'proposal_url': make_url(f'/proposals/{proposal.id}'),
                'admin_note': reject_reason,
                'profile_rejected_url': make_url('/profile?tab=rejected'),
            })

    return proposal_schema.dump(proposal)
コード例 #2
0
ファイル: views.py プロジェクト: urbit/grants
def paid_milestone_payout_request(id, mid):
    proposal = Proposal.query.filter_by(id=id).first()
    if not proposal:
        return {"message": "No proposal matching id"}, 404
    if not proposal.status == ProposalStatus.LIVE:
        return {"message": "Proposal is not live"}, 400
    for ms in proposal.milestones:
        if ms.id == int(mid):
            ms.mark_paid()
            admin.admin_log("MILESTONE_PAID", f"Paid milestone #{ms.index + 1} ({ms.title}) for proposal {proposal.id} ({proposal.title})")
            db.session.add(ms)
            db.session.flush()
            # check if this is the final ms, and update proposal.stage
            num_paid = reduce(lambda a, x: a + (1 if x.stage == MilestoneStage.PAID else 0), proposal.milestones, 0)
            if num_paid == len(proposal.milestones):
                proposal.stage = ProposalStage.COMPLETED  # WIP -> COMPLETED
                db.session.add(proposal)
                db.session.flush()
            db.session.commit()
            # email TEAM that payout request was PAID
            for member in proposal.team:
                send_email(member.email_address, 'milestone_paid', {
                    'proposal': proposal,
                    'milestone': ms,
                    'amount': ms.payout_amount,
                    'proposal_milestones_url': make_url(f'/proposals/{proposal.id}?tab=milestones'),
                })
            # email FOLLOWERS that milestone was accepted
            proposal.send_follower_email('followed_proposal_milestone', email_args={'milestone':ms}, url_suffix='?tab=milestones')
            return proposal_schema.dump(proposal), 200

    return {"message": "No milestone matching id"}, 404
コード例 #3
0
def cancel_proposal(id):
    proposal = Proposal.query.filter_by(id=id).first()
    if not proposal:
        return {"message": "No proposal found."}, 404

    proposal.cancel()
    db.session.add(proposal)
    db.session.commit()
    return proposal_schema.dump(proposal)
コード例 #4
0
def resolve_changes_discussion(proposal_id):
    proposal = Proposal.query.get(proposal_id)
    if not proposal:
        return {"message": "No proposal found"}, 404

    proposal.resolve_changes_discussion()

    db.session.add(proposal)
    db.session.commit()
    return proposal_schema.dump(proposal)
コード例 #5
0
def open_proposal_for_discussion(proposal_id,
                                 is_open_for_discussion,
                                 reject_reason=None):
    proposal = Proposal.query.get(proposal_id)
    if not proposal:
        return {"message": "No Proposal found."}, 404

    proposal.approve_discussion(is_open_for_discussion, reject_reason)
    db.session.commit()
    return proposal_schema.dump(proposal)
コード例 #6
0
ファイル: views.py プロジェクト: urbit/grants
def cancel_proposal(id):
    proposal = Proposal.query.filter_by(id=id).first()
    if not proposal:
        return {"message": "No proposal found."}, 404

    proposal.cancel()
    admin.admin_log("PROPOSAL_CANCEL", f"Canceled proposal {proposal.id} ({proposal.title})")
    db.session.add(proposal)
    db.session.commit()
    return proposal_schema.dump(proposal)
コード例 #7
0
def paid_milestone_payout_request(id, mid, tx_id):
    proposal = Proposal.query.filter_by(id=id).first()
    if not proposal:
        return {"message": "No proposal matching id"}, 404
    if not proposal.is_funded:
        return {"message": "Proposal is not fully funded"}, 400
    for ms in proposal.milestones:
        if ms.id == int(mid):
            is_final_milestone = False
            ms.mark_paid(tx_id)
            db.session.add(ms)
            db.session.flush()
            # check if this is the final ms, and update proposal.stage
            num_paid = reduce(
                lambda a, x: a + (1 if x.stage == MilestoneStage.PAID else 0),
                proposal.milestones, 0)
            if num_paid == len(proposal.milestones):
                is_final_milestone = True
                proposal.stage = ProposalStage.COMPLETED  # WIP -> COMPLETED
                db.session.add(proposal)
                db.session.flush()
            db.session.commit()
            # email TEAM that payout request was PAID
            amount = Decimal(ms.payout_percent) * Decimal(
                proposal.target) / 100
            for member in proposal.team:
                send_email(
                    member.email_address, 'milestone_paid', {
                        'proposal':
                        proposal,
                        'milestone':
                        ms,
                        'amount':
                        amount,
                        'tx_explorer_url':
                        make_explore_url(tx_id),
                        'proposal_milestones_url':
                        make_url(f'/proposals/{proposal.id}?tab=milestones'),
                    })

            # email FOLLOWERS that milestone was accepted
            proposal.send_follower_email(
                "followed_proposal_milestone",
                email_args={"milestone": ms},
                url_suffix="?tab=milestones",
            )

            if not is_final_milestone:
                Milestone.set_v2_date_estimates(proposal)
                db.session.commit()

            return proposal_schema.dump(proposal), 200

    return {"message": "No milestone matching id"}, 404
コード例 #8
0
ファイル: views.py プロジェクト: urbit/grants
def approve_proposal(id, is_approve, reject_reason=None):
    proposal = Proposal.query.filter_by(id=id).first()
    if proposal:
        proposal.approve_pending(is_approve, reject_reason)
        if is_approve:
            admin.admin_log("PROPOSAL_APPROVE", f"Approved proposal {proposal.id} ({proposal.title})")
        else:
            admin.admin_log("PROPOSAL_REJECT", f"Rejected proposal {proposal.id} ({proposal.title}) for reason '{reject_reason}'")
        db.session.commit()
        return proposal_schema.dump(proposal)

    return {"message": "No proposal found."}, 404
コード例 #9
0
ファイル: views.py プロジェクト: urbit/grants
def update_proposal(id, private):
    proposal = Proposal.query.filter(Proposal.id == id).first()
    if not proposal:
        return {"message": f"Could not find proposal with id {id}"}, 404

    if private != None:
        proposal.private = private

    db.session.add(proposal)
    db.session.commit()

    return proposal_schema.dump(proposal)
コード例 #10
0
ファイル: views.py プロジェクト: urbit/grants
def accept_milestone_payout_request(proposal_id, milestone_id):
    proposal = Proposal.query.filter_by(id=proposal_id).first()
    if not proposal:
        return {"message": "No proposal matching id"}, 404
    for ms in proposal.milestones:
        if ms.id == int(milestone_id):
            ms.accept_request()
            admin.admin_log("MILESTONE_APPROVE", f"Approved milestone #{ms.index + 1} ({ms.title}) for proposal {proposal.id} ({proposal.title})")
            db.session.commit()
            # NOTE - no notification here, do it on PAID
            return proposal_schema.dump(proposal), 200

    return {"message": "No milestone matching id"}, 404
コード例 #11
0
def accept_proposal(id, is_accepted, with_funding, changes_requested_reason):
    proposal = Proposal.query.get(id)
    if not proposal:
        return {"message": "No proposal found."}, 404

    if is_accepted:
        proposal.accept_proposal(with_funding)

        if with_funding:
            Milestone.set_v2_date_estimates(proposal)
    else:
        proposal.request_changes_discussion(changes_requested_reason)

    db.session.add(proposal)
    db.session.commit()
    return proposal_schema.dump(proposal)
コード例 #12
0
def set_arbiter(proposal_id, user_id):
    proposal = Proposal.query.filter(Proposal.id == proposal_id).first()
    if not proposal:
        return {"message": "Proposal not found"}, 404

    for member in proposal.team:
        if member.id == user_id:
            return {
                "message": "Cannot set proposal team member as arbiter"
            }, 400

    if proposal.is_failed:
        return {"message": "Cannot set arbiter on failed proposal"}, 400

    if proposal.version == '2' and not proposal.accepted_with_funding:
        return {
            "message":
            "Cannot set arbiter, proposal has not been accepted with funding"
        }, 400

    user = User.query.filter(User.id == user_id).first()
    if not user:
        return {"message": "User not found"}, 404

    # send email
    code = user.email_verification.code
    send_email(
        user.email_address, 'proposal_arbiter', {
            'proposal':
            proposal,
            'proposal_url':
            make_url(f'/proposals/{proposal.id}'),
            'accept_url':
            make_url(f'/email/arbiter?code={code}&proposalId={proposal.id}'),
        })
    proposal.arbiter.user = user
    proposal.arbiter.status = ProposalArbiterStatus.NOMINATED
    db.session.add(proposal.arbiter)
    db.session.commit()

    return {
        'proposal': proposal_schema.dump(proposal),
        'user': admin_user_schema.dump(user)
    }, 200
コード例 #13
0
ファイル: views.py プロジェクト: urbit/grants
def reject_milestone_payout_request(proposal_id, milestone_id, reason):
    proposal = Proposal.query.filter_by(id=proposal_id).first()
    if not proposal:
        return {"message": "No proposal matching id"}, 404
    for ms in proposal.milestones:
        if ms.id == int(milestone_id):
            ms.reject_request(reason)
            admin.admin_log("MILESTONE_REJECT", f"Rejected milestone #{ms.index + 1} ({ms.title}) for proposal {proposal.id} ({proposal.title}) with reason '{reason}'")
            db.session.add(ms)
            db.session.commit()
            # email TEAM that payout request was rejected
            for member in proposal.team:
                send_email(member.email_address, 'milestone_reject', {
                    'proposal': proposal,
                    'admin_note': reason,
                    'proposal_milestones_url': make_url(f'/proposals/{proposal.id}?tab=milestones'),
                })
            return proposal_schema.dump(proposal), 200

    return {"message": "No milestone matching id"}, 404
コード例 #14
0
def change_proposal_to_accepted_with_funding(id):
    proposal = Proposal.query.filter_by(id=id).first()
    if not proposal:
        return {"message": "No proposal found."}, 404
    if proposal.accepted_with_funding:
        return {"message": "Proposal already accepted with funding."}, 404
    if proposal.version != '2':
        return {
            "message":
            "Only version two proposals can be accepted with funding"
        }, 404
    if proposal.status != ProposalStatus.LIVE and proposal.status != ProposalStatus.APPROVED:
        return {
            "message":
            "Only live or approved proposals can be modified by this endpoint"
        }, 404

    proposal.update_proposal_with_funding()
    Milestone.set_v2_date_estimates(proposal)
    db.session.add(proposal)
    db.session.commit()

    return proposal_schema.dump(proposal)
コード例 #15
0
    def init_proposal(self, proposal_data):
        self.login_default_user()
        resp = self.app.post("/api/v1/proposals/drafts")
        self.assertStatus(resp, 201)
        proposal_id = resp.json["proposalId"]

        resp = self.app.put(f"/api/v1/proposals/{proposal_id}",
                            data=json.dumps(proposal_data),
                            content_type='application/json')
        self.assert200(resp)

        proposal = Proposal.query.get(proposal_id)
        proposal.status = ProposalStatus.DISCUSSION

        # accept with funding
        proposal.accept_proposal(True)
        Milestone.set_v2_date_estimates(proposal)

        db.session.add(proposal)
        db.session.commit()

        print(proposal_schema.dump(proposal))
        return proposal
コード例 #16
0
def get_proposal(id):
    proposal = Proposal.query.filter(Proposal.id == id).first()
    if proposal:
        return proposal_schema.dump(proposal)
    return {"message": f"Could not find proposal with id {id}"}, 404