2018-09-10 09:55:26 -07:00
import datetime
2019-11-20 13:37:26 -08:00
from typing import Optional
2019-04-16 13:08:13 -07:00
from decimal import Decimal , ROUND_DOWN
2019-01-09 11:45:16 -08:00
from functools import reduce
2019-03-14 13:29:02 -07:00
from marshmallow import post_dump
2019-10-23 14:34:10 -07:00
from sqlalchemy import func , or_ , select
2019-01-30 09:59:15 -08:00
from sqlalchemy . ext . hybrid import hybrid_property
2019-10-23 14:34:10 -07:00
from sqlalchemy . orm import column_property
2018-09-10 09:55:26 -07:00
from grant . comment . models import Comment
2019-03-14 09:46:09 -07:00
from grant . email . send import send_email
2018-09-10 09:55:26 -07:00
from grant . extensions import ma , db
2019-03-18 11:35:08 -07:00
from grant . settings import PROPOSAL_STAKING_AMOUNT , PROPOSAL_TARGET_MAX
2019-03-14 13:29:02 -07:00
from grant . task . jobs import ContributionExpired
2019-02-11 14:51:31 -08:00
from grant . utils . enums import (
ProposalStatus ,
ProposalStage ,
Category ,
ContributionStatus ,
ProposalArbiterStatus ,
MilestoneStage
)
2019-03-14 13:29:02 -07:00
from grant . utils . exceptions import ValidationException
2019-04-16 10:38:14 -07:00
from grant . utils . misc import dt_to_unix , make_url , make_admin_url , gen_random_id
2019-03-14 13:29:02 -07:00
from grant . utils . requests import blockchain_get
2019-02-23 12:31:07 -08:00
from grant . utils . stubs import anonymous_user
2018-11-13 08:07:09 -08:00
2018-09-25 13:09:25 -07:00
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 ' ) )
)
2019-10-23 14:34:10 -07:00
proposal_follower = db . Table (
" proposal_follower " ,
db . Model . metadata ,
db . Column ( " user_id " , db . Integer , db . ForeignKey ( " user.id " ) ) ,
db . Column ( " proposal_id " , db . Integer , db . ForeignKey ( " proposal.id " ) ) ,
)
2018-11-30 15:52:00 -08:00
2019-10-24 10:32:00 -07:00
proposal_liker = db . Table (
" proposal_liker " ,
db . Model . metadata ,
db . Column ( " user_id " , db . Integer , db . ForeignKey ( " user.id " ) ) ,
db . Column ( " proposal_id " , db . Integer , db . ForeignKey ( " proposal.id " ) ) ,
)
2018-11-15 13:51:32 -08:00
class ProposalTeamInvite ( db . Model ) :
__tablename__ = " proposal_team_invite "
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 )
address = db . Column ( db . String ( 255 ) , nullable = False )
accepted = db . Column ( db . Boolean )
def __init__ ( self , proposal_id : int , address : str , accepted : bool = None ) :
self . proposal_id = proposal_id
2019-03-18 12:03:01 -07:00
self . address = address [ : 255 ]
2018-11-15 13:51:32 -08:00
self . accepted = accepted
self . date_created = datetime . datetime . now ( )
2018-11-16 10:50:47 -08:00
@staticmethod
def get_pending_for_user ( user ) :
return ProposalTeamInvite . query . filter (
ProposalTeamInvite . accepted == None ,
2018-11-16 11:17:09 -08:00
( func . lower ( user . email_address ) == func . lower ( ProposalTeamInvite . address ) )
2018-11-16 10:50:47 -08:00
) . all ( )
2018-11-07 09:33:19 -08:00
2018-11-02 09:24:28 -07:00
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 ) :
2019-03-04 13:47:52 -08:00
self . id = gen_random_id ( ProposalUpdate )
2018-11-02 09:24:28 -07:00
self . proposal_id = proposal_id
2019-03-18 12:03:01 -07:00
self . title = title [ : 255 ]
2018-11-02 09:24:28 -07:00
self . content = content
self . date_created = datetime . datetime . now ( )
2018-09-25 13:09:25 -07:00
2018-11-21 19:18:22 -08:00
class ProposalContribution ( db . Model ) :
__tablename__ = " proposal_contribution "
2019-01-08 09:44:54 -08:00
id = db . Column ( db . Integer ( ) , primary_key = True )
2018-11-21 19:18:22 -08:00
date_created = db . Column ( db . DateTime , nullable = False )
proposal_id = db . Column ( db . Integer , db . ForeignKey ( " proposal.id " ) , nullable = False )
user_id = db . Column ( db . Integer , db . ForeignKey ( " user.id " ) , nullable = True )
2019-01-06 14:48:07 -08:00
status = db . Column ( db . String ( 255 ) , nullable = False )
amount = db . Column ( db . String ( 255 ) , nullable = False )
2019-02-17 08:52:35 -08:00
tx_id = db . Column ( db . String ( 255 ) , nullable = True )
refund_tx_id = db . Column ( db . String ( 255 ) , nullable = True )
2019-02-21 10:02:29 -08:00
staking = db . Column ( db . Boolean , nullable = False )
2019-06-11 19:49:14 -07:00
private = db . Column ( db . Boolean , nullable = False , default = False , server_default = ' true ' )
2018-11-21 19:18:22 -08:00
2019-01-09 12:48:41 -08:00
user = db . relationship ( " User " )
2018-11-21 19:18:22 -08:00
def __init__ (
2019-01-22 21:35:22 -08:00
self ,
proposal_id : int ,
2019-02-21 10:02:29 -08:00
amount : str ,
2019-02-23 12:31:07 -08:00
user_id : int = None ,
2019-02-21 10:02:29 -08:00
staking : bool = False ,
2019-06-11 19:49:14 -07:00
private : bool = True ,
2018-11-21 19:18:22 -08:00
) :
self . proposal_id = proposal_id
self . amount = amount
2019-02-23 12:31:07 -08:00
self . user_id = user_id
2019-02-21 10:02:29 -08:00
self . staking = staking
2019-06-11 19:49:14 -07:00
self . private = private
2018-11-21 19:18:22 -08:00
self . date_created = datetime . datetime . now ( )
2019-01-30 09:59:15 -08:00
self . status = ContributionStatus . PENDING
2019-01-06 14:48:07 -08:00
2019-01-06 22:58:33 -08:00
@staticmethod
2019-06-11 19:49:14 -07:00
def get_existing_contribution ( user_id : int , proposal_id : int , amount : str , private : bool = False ) :
2019-01-09 11:35:37 -08:00
return ProposalContribution . query . filter_by (
user_id = user_id ,
proposal_id = proposal_id ,
amount = amount ,
2019-06-11 19:49:14 -07:00
private = private ,
2019-01-30 09:59:15 -08:00
status = ContributionStatus . PENDING ,
2019-01-09 11:35:37 -08:00
) . first ( )
2019-01-16 14:26:45 -08:00
2019-01-09 11:07:50 -08:00
@staticmethod
def get_by_userid ( user_id ) :
2019-01-09 11:35:37 -08:00
return ProposalContribution . query \
2019-01-09 13:32:51 -08:00
. filter ( ProposalContribution . user_id == user_id ) \
2019-01-30 09:59:15 -08:00
. filter ( ProposalContribution . status != ContributionStatus . DELETED ) \
2019-02-21 10:07:11 -08:00
. filter ( ProposalContribution . staking == False ) \
2019-01-09 11:35:37 -08:00
. order_by ( ProposalContribution . date_created . desc ( ) ) \
. all ( )
2019-01-06 22:58:33 -08:00
2019-02-06 11:01:46 -08:00
@staticmethod
def validate ( contribution ) :
proposal_id = contribution . get ( ' proposal_id ' )
user_id = contribution . get ( ' user_id ' )
status = contribution . get ( ' status ' )
amount = contribution . get ( ' amount ' )
tx_id = contribution . get ( ' tx_id ' )
# Proposal ID (must belong to an existing proposal)
if proposal_id :
proposal = Proposal . query . filter ( Proposal . id == proposal_id ) . first ( )
if not proposal :
raise ValidationException ( ' No proposal matching that ID ' )
contribution . proposal_id = proposal_id
else :
raise ValidationException ( ' Proposal ID is required ' )
# User ID (must belong to an existing user)
if user_id :
2019-10-24 10:32:00 -07:00
from grant . user . models import User
2019-02-06 11:01:46 -08:00
user = User . query . filter ( User . id == user_id ) . first ( )
if not user :
raise ValidationException ( ' No user matching that ID ' )
contribution . user_id = user_id
else :
raise ValidationException ( ' User ID is required ' )
# Status (must be in list of statuses)
if status :
if not ContributionStatus . includes ( status ) :
raise ValidationException ( ' Invalid status ' )
contribution . status = status
else :
raise ValidationException ( ' Status is required ' )
# Amount (must be a Decimal parseable)
if amount :
try :
2019-02-06 14:24:07 -08:00
contribution . amount = str ( Decimal ( amount ) )
2019-02-06 11:01:46 -08:00
except :
raise ValidationException ( ' Amount must be a number ' )
else :
raise ValidationException ( ' Amount is required ' )
2019-01-06 14:48:07 -08:00
def confirm ( self , tx_id : str , amount : str ) :
2019-01-30 09:59:15 -08:00
self . status = ContributionStatus . CONFIRMED
2019-01-06 14:48:07 -08:00
self . tx_id = tx_id
self . amount = amount
2019-02-25 08:41:00 -08:00
2019-02-17 08:52:35 -08:00
@hybrid_property
def refund_address ( self ) :
2019-02-23 12:31:07 -08:00
return self . user . settings . refund_address if self . user else None
2018-11-21 19:18:22 -08:00
2019-02-09 18:58:40 -08:00
class ProposalArbiter ( db . Model ) :
__tablename__ = " proposal_arbiter "
id = db . Column ( db . Integer ( ) , primary_key = True )
proposal_id = db . Column ( db . Integer , db . ForeignKey ( " proposal.id " ) , nullable = False )
user_id = db . Column ( db . Integer , db . ForeignKey ( " user.id " ) , nullable = True )
status = db . Column ( db . String ( 255 ) , nullable = False )
proposal = db . relationship ( " Proposal " , lazy = True , back_populates = " arbiter " )
user = db . relationship ( " User " , uselist = False , lazy = True , back_populates = " arbiter_proposals " )
def __init__ ( self , proposal_id : int , user_id : int = None , status : str = ProposalArbiterStatus . MISSING ) :
2019-03-04 13:47:52 -08:00
self . id = gen_random_id ( ProposalArbiter )
2019-02-09 18:58:40 -08:00
self . proposal_id = proposal_id
self . user_id = user_id
self . status = status
def accept_nomination ( self , user_id : int ) :
if self . user_id == user_id :
self . status = ProposalArbiterStatus . ACCEPTED
db . session . add ( self )
db . session . commit ( )
return
raise ValidationException ( ' User not nominated for arbiter ' )
def reject_nomination ( self , user_id : int ) :
if self . user_id == user_id :
self . status = ProposalArbiterStatus . MISSING
self . user = None
db . session . add ( self )
db . session . commit ( )
return
raise ValidationException ( ' User is not arbiter ' )
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
def default_proposal_content ( ) :
2019-12-10 13:32:12 -08:00
return """ # Applicant background
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
2019-12-10 13:32:12 -08:00
Summarize you and / or your team ’ s background and experience . Demonstrate that you have the skills and expertise necessary for the project that you ’ re proposing . Institutional bona fides are not required , but we want to hear about your track record .
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
2019-12-10 13:32:12 -08:00
# Motivation and overview
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
2019-12-10 13:32:12 -08:00
What are your high - level goals ? Why are they important ? How is your project connected to [ ZF ’ s mission ] ( https : / / www . zfnd . org / about / #mission) and priorities? Whose needs will it serve?
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
2019-12-10 13:32:12 -08:00
# Technical approach
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
2019-12-10 13:32:12 -08:00
Dive into the _how_ of your project . Describe your approaches , components , workflows , methodology , etc . Bullet points and diagrams are appreciated !
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
2019-12-10 13:32:12 -08:00
# Execution risks
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
2019-12-10 13:32:12 -08:00
What obstacles do you expect ? What is most likely to go wrong ? Which unknown factors or dependencies could jeopardize success ? What are your contingency plans ? Will subsequent activities be required to maximize impact ?
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
2019-12-10 13:32:12 -08:00
# Downsides
What are the negative ramifications if your project is successful ? Consider usability , stability , privacy , integrity , availability , decentralization , interoperability , maintainability , technical debt , requisite education , etc .
# Evaluation plan
What will your project look like if successful ? How will we be able to tell ? Include quantifiable metrics if possible .
# Tasks and schedule
What is your timeline for the project ? Include concrete milestones and the major tasks required to complete each milestone .
# Budget and justification
How much funding do you need , and how will it be allocated ( e . g . , compensation for your effort , specific equipment , specific external services ) ? Specify a total cost , break it up into budget items , and explain the rationale for each . Feel free to present multiple options in terms of scope and cost .
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
"""
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 )
2019-02-01 11:13:30 -08:00
rfp_id = db . Column ( db . Integer ( ) , db . ForeignKey ( ' rfp.id ' ) , nullable = True )
2019-10-11 12:51:10 -07:00
version = db . Column ( db . String ( 255 ) , nullable = True )
2018-09-10 09:55:26 -07:00
2018-12-19 13:27:58 -08:00
# Content info
2018-11-13 08:07:09 -08:00
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 )
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
content = db . Column ( db . Text , nullable = False , default = default_proposal_content ( ) )
2019-11-13 15:23:36 -08:00
category = db . Column ( db . String ( 255 ) , nullable = True )
2019-01-09 10:23:08 -08:00
date_approved = db . Column ( db . DateTime )
date_published = db . Column ( db . DateTime )
2019-02-25 08:41:00 -08:00
reject_reason = db . Column ( db . String ( ) )
2019-10-16 20:43:20 -07:00
accepted_with_funding = db . Column ( db . Boolean ( ) , nullable = True )
2018-09-10 09:55:26 -07:00
2018-12-19 13:27:58 -08:00
# Payment 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 )
2019-10-11 12:52:52 -07:00
deadline_duration = db . Column ( db . Integer ( ) , nullable = True )
2019-01-29 15:50:27 -08:00
contribution_matching = db . Column ( db . Float ( ) , nullable = False , default = 0 , server_default = db . text ( " 0 " ) )
2019-03-06 12:25:58 -08:00
contribution_bounty = db . Column ( db . String ( 255 ) , nullable = False , default = ' 0 ' , server_default = db . text ( " ' 0 ' " ) )
rfp_opt_in = db . Column ( db . Boolean ( ) , nullable = True )
2019-01-29 15:50:27 -08:00
contributed = db . column_property ( )
2019-11-20 13:37:26 -08:00
tip_jar_address = db . Column ( db . String ( 255 ) , nullable = True )
tip_jar_view_key = db . Column ( db . String ( 255 ) , nullable = True )
2018-11-13 08:07:09 -08:00
# Relations
2018-09-25 13:09:25 -07:00
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 " )
2018-11-26 15:47:24 -08:00
contributions = db . relationship ( ProposalContribution , backref = " proposal " , lazy = True , cascade = " all, delete-orphan " )
2019-02-13 08:54:46 -08:00
milestones = db . relationship ( " Milestone " , backref = " proposal " ,
order_by = " asc(Milestone.index) " , lazy = True , cascade = " all, delete-orphan " )
2018-11-15 13:51:32 -08:00
invites = db . relationship ( ProposalTeamInvite , backref = " proposal " , lazy = True , cascade = " all, delete-orphan " )
2019-02-09 18:58:40 -08:00
arbiter = db . relationship ( ProposalArbiter , uselist = False , back_populates = " proposal " , cascade = " all, delete-orphan " )
2019-10-23 14:34:10 -07:00
followers = db . relationship (
" User " , secondary = proposal_follower , back_populates = " followed_proposals "
)
followers_count = column_property (
select ( [ func . count ( proposal_follower . c . proposal_id ) ] )
. where ( proposal_follower . c . proposal_id == id )
. correlate_except ( proposal_follower )
)
2019-10-24 10:32:00 -07:00
likes = db . relationship (
" User " , secondary = proposal_liker , back_populates = " liked_proposals "
)
likes_count = column_property (
select ( [ func . count ( proposal_liker . c . proposal_id ) ] )
. where ( proposal_liker . c . proposal_id == id )
. correlate_except ( proposal_liker )
)
2018-09-10 09:55:26 -07:00
def __init__ (
self ,
2019-01-30 09:59:15 -08:00
status : str = ProposalStatus . DRAFT ,
2018-11-13 08:07:09 -08:00
title : str = ' ' ,
brief : str = ' ' ,
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
content : str = default_proposal_content ( ) ,
2019-02-13 08:54:46 -08:00
stage : str = ProposalStage . PREVIEW ,
2018-11-13 08:07:09 -08:00
target : str = ' 0 ' ,
payout_address : str = ' ' ,
2018-11-30 15:52:00 -08:00
deadline_duration : int = 5184000 , # 60 days
2018-11-13 08:07:09 -08:00
category : str = ' '
2018-09-10 09:55:26 -07:00
) :
2019-03-04 13:47:52 -08:00
self . id = gen_random_id ( Proposal )
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 . deadline_duration = deadline_duration
self . stage = stage
2019-10-11 12:51:10 -07:00
self . version = ' 2 '
2018-09-10 09:55:26 -07:00
@staticmethod
2019-03-14 13:29:02 -07:00
def simple_validate ( proposal ) :
2019-03-18 11:35:08 -07:00
# Validate fields to be database save-able.
# Stricter validation is done in validate_publishable.
2018-11-13 08:07:09 -08:00
stage = proposal . get ( ' stage ' )
2019-03-14 13:29:02 -07:00
2019-01-30 09:59:15 -08:00
if stage and not ProposalStage . includes ( stage ) :
raise ValidationException ( " Proposal stage {} is not a valid stage " . format ( stage ) )
2018-09-10 09:55:26 -07:00
2019-03-14 13:29:02 -07:00
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 :
2019-03-18 11:35:08 -07:00
raise ValidationException ( " Milestone title cannot be longer than 60 chars " )
2019-03-14 13:29:02 -07:00
if len ( milestone . content ) > 200 :
2019-03-18 11:35:08 -07:00
raise ValidationException ( " Milestone content cannot be longer than 200 chars " )
2019-03-14 13:29:02 -07:00
2019-03-15 16:17:55 -07:00
try :
p = float ( milestone . payout_percent )
2019-03-18 11:53:15 -07:00
if not p . is_integer ( ) :
raise ValidationException ( " Milestone payout percents must be whole numbers, no decimals " )
if p < = 0 or p > 100 :
2019-03-15 16:17:55 -07:00
raise ValidationException ( " Milestone payout percent must be greater than zero " )
except ValueError :
raise ValidationException ( " Milestone payout percent must be a number " )
payout_total + = p
2019-03-14 13:29:02 -07:00
if payout_total != 100.0 :
2019-03-18 11:35:08 -07:00
raise ValidationException ( " Payout percentages of milestones must add up to exactly 100 % " )
2019-03-14 13:29:02 -07:00
2019-01-28 14:46:04 -08:00
def validate_publishable ( self ) :
2019-03-14 13:29:02 -07:00
self . validate_publishable_milestones ( )
2019-01-09 10:23:08 -08:00
# Require certain fields
2019-11-13 15:23:36 -08:00
required_fields = [ ' title ' , ' content ' , ' brief ' , ' target ' , ' payout_address ' ]
2019-01-27 18:51:05 -08:00
for field in required_fields :
if not hasattr ( self , field ) :
raise ValidationException ( " Proposal must have a {} " . format ( field ) )
2019-01-27 18:04:11 -08:00
2019-03-18 11:35:08 -07:00
# Stricter limits on certain fields
2019-03-19 10:01:11 -07:00
if len ( self . title ) > 60 :
2019-03-18 11:35:08 -07:00
raise ValidationException ( " Proposal title cannot be longer than 60 characters " )
2019-03-19 10:01:11 -07:00
if len ( self . brief ) > 140 :
2019-03-18 11:35:08 -07:00
raise ValidationException ( " Brief cannot be longer than 140 characters " )
2019-03-19 10:01:11 -07:00
if len ( self . content ) > 250000 :
2019-03-18 11:35:08 -07:00
raise ValidationException ( " Content cannot be longer than 250,000 characters " )
2019-03-19 10:01:11 -07:00
if Decimal ( self . target ) > PROPOSAL_TARGET_MAX :
2019-12-03 16:02:39 -08:00
raise ValidationException ( " Target cannot be more than {} USD " . format ( PROPOSAL_TARGET_MAX ) )
if Decimal ( self . target ) < 0 :
raise ValidationException ( " Target cannot be less than 0 " )
if not self . target . isdigit ( ) :
raise ValidationException ( " Target must be a whole number " )
2019-03-19 10:01:11 -07:00
if self . deadline_duration > 7776000 :
2019-03-18 11:35:08 -07:00
raise ValidationException ( " Deadline duration cannot be more than 90 days " )
2019-11-20 13:37:26 -08:00
# Check with node that the payout address is kosher
2019-03-12 10:10:56 -07:00
try :
res = blockchain_get ( ' /validate/address ' , { ' address ' : self . payout_address } )
except :
2019-03-12 18:14:51 -07:00
raise ValidationException (
" Could not validate your payout address due to an internal server error, please try again later " )
2019-02-05 12:26:37 -08:00
if not res [ ' valid ' ] :
raise ValidationException ( " Payout address is not a valid Zcash address " )
2019-11-20 13:37:26 -08:00
if self . tip_jar_address :
# Check with node that the tip jar address is kosher
try :
res = blockchain_get ( ' /validate/address ' , { ' address ' : self . tip_jar_address } )
except :
raise ValidationException (
" Could not validate your tipping address due to an internal server error, please try again later " )
if not res [ ' valid ' ] :
raise ValidationException ( " Tipping address is not a valid Zcash address " )
2019-01-09 10:23:08 -08:00
# Then run through regular validation
2019-03-14 13:29:02 -07:00
Proposal . simple_validate ( vars ( self ) )
2019-01-09 10:23:08 -08:00
2019-11-13 14:38:17 -08:00
def validate_milestone_days ( self ) :
2019-07-24 11:29:11 -07:00
for milestone in self . milestones :
2019-11-13 14:38:17 -08:00
if milestone . immediate_payout :
continue
try :
p = float ( milestone . days_estimated )
if not p . is_integer ( ) :
raise ValidationException ( " Milestone days estimated must be whole numbers, no decimals " )
if p < = 0 :
raise ValidationException ( " Milestone days estimated must be greater than zero " )
if p > 365 :
raise ValidationException ( " Milestone days estimated must be less than 365 " )
except ValueError :
raise ValidationException ( " Milestone days estimated must be a number " )
return
2019-07-24 11:29:11 -07:00
2018-09-10 09:55:26 -07:00
@staticmethod
def create ( * * kwargs ) :
2019-03-14 13:29:02 -07:00
Proposal . simple_validate ( kwargs )
2019-02-09 18:58:40 -08:00
proposal = Proposal (
2018-09-10 09:55:26 -07:00
* * kwargs
)
2018-11-30 15:52:00 -08:00
2019-02-09 18:58:40 -08:00
# arbiter needs proposal.id
db . session . add ( proposal )
2019-02-11 13:59:29 -08:00
db . session . flush ( )
2019-02-09 18:58:40 -08:00
arbiter = ProposalArbiter ( proposal_id = proposal . id )
db . session . add ( arbiter )
return proposal
2018-11-30 15:52:00 -08:00
@staticmethod
2019-01-30 09:59:15 -08:00
def get_by_user ( user , statuses = [ ProposalStatus . LIVE ] ) :
2019-01-09 10:23:08 -08:00
status_filter = or_ ( Proposal . status == v for v in statuses )
2018-11-30 15:52:00 -08:00
return Proposal . query \
. join ( proposal_team ) \
. filter ( proposal_team . c . user_id == user . id ) \
2019-01-09 10:23:08 -08:00
. filter ( status_filter ) \
2018-11-30 15:52:00 -08:00
. all ( )
@staticmethod
def get_by_user_contribution ( user ) :
return Proposal . query \
. join ( ProposalContribution ) \
. filter ( ProposalContribution . user_id == user . id ) \
. order_by ( ProposalContribution . date_created . desc ( ) ) \
. all ( )
2018-11-14 08:43:00 -08:00
def update (
2019-01-22 21:35:22 -08:00
self ,
title : str = ' ' ,
brief : str = ' ' ,
category : str = ' ' ,
content : str = ' ' ,
target : str = ' 0 ' ,
payout_address : str = ' ' ,
2019-11-20 13:37:26 -08:00
tip_jar_address : Optional [ str ] = None ,
2019-01-22 21:35:22 -08:00
deadline_duration : int = 5184000 # 60 days
2018-11-14 08:43:00 -08:00
) :
2019-03-18 11:35:08 -07:00
self . title = title [ : 255 ]
self . brief = brief [ : 255 ]
2018-11-14 08:43:00 -08:00
self . category = category
2019-03-18 11:35:08 -07:00
self . content = content [ : 300000 ]
2019-03-28 10:25:34 -07:00
self . target = target [ : 255 ] if target != ' ' else ' 0 '
2019-03-18 11:35:08 -07:00
self . payout_address = payout_address [ : 255 ]
2019-11-20 13:37:26 -08:00
self . tip_jar_address = tip_jar_address [ : 255 ] if tip_jar_address is not None else None
2018-11-14 08:43:00 -08:00
self . deadline_duration = deadline_duration
2019-03-14 13:29:02 -07:00
Proposal . simple_validate ( vars ( self ) )
2018-11-14 08:43:00 -08:00
2019-03-06 12:25:58 -08:00
def update_rfp_opt_in ( self , opt_in : bool ) :
self . rfp_opt_in = opt_in
2019-03-13 16:36:24 -07:00
def create_contribution (
self ,
amount ,
user_id : int = None ,
staking : bool = False ,
2019-06-11 19:49:14 -07:00
private : bool = True ,
2019-03-13 16:36:24 -07:00
) :
2019-01-31 14:56:16 -08:00
contribution = ProposalContribution (
proposal_id = self . id ,
2019-02-21 10:02:29 -08:00
amount = amount ,
2019-02-23 12:31:07 -08:00
user_id = user_id ,
2019-02-21 10:02:29 -08:00
staking = staking ,
2019-06-11 19:49:14 -07:00
private = private
2019-01-31 14:56:16 -08:00
)
db . session . add ( contribution )
2019-03-06 12:33:09 -08:00
db . session . flush ( )
2019-03-06 13:39:30 -08:00
if user_id :
task = ContributionExpired ( contribution )
task . make_task ( )
db . session . commit ( )
2019-01-31 14:56:16 -08:00
return contribution
def get_staking_contribution ( self , user_id : int ) :
contribution = None
2019-03-13 14:39:50 -07:00
remaining = PROPOSAL_STAKING_AMOUNT - Decimal ( self . amount_staked )
2019-01-31 14:56:16 -08:00
# check funding
if remaining > 0 :
2019-02-05 17:45:57 -08:00
# find pending contribution for any user of remaining amount
2019-01-31 14:56:16 -08:00
contribution = ProposalContribution . query . filter_by (
proposal_id = self . id ,
2019-02-05 09:01:57 -08:00
status = ProposalStatus . PENDING ,
2019-03-13 14:39:50 -07:00
staking = True ,
2019-01-31 14:56:16 -08:00
) . first ( )
if not contribution :
2019-02-21 10:02:29 -08:00
contribution = self . create_contribution (
user_id = user_id ,
amount = str ( remaining . normalize ( ) ) ,
staking = True ,
)
2019-01-31 14:56:16 -08:00
return contribution
2019-04-16 10:38:14 -07:00
def send_admin_email ( self , type : str ) :
from grant . user . models import User
admins = User . get_admins ( )
for a in admins :
send_email ( a . email_address , type , {
' user ' : a ,
' proposal ' : self ,
' proposal_url ' : make_admin_url ( f ' /proposals/ { self . id } ' ) ,
} )
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
# state: status (DRAFT || REJECTED) -> (PENDING)
2019-01-28 14:46:04 -08:00
def submit_for_approval ( self ) :
self . validate_publishable ( )
2019-11-13 14:38:17 -08:00
self . validate_milestone_days ( )
2019-01-30 09:59:15 -08:00
allowed_statuses = [ ProposalStatus . DRAFT , ProposalStatus . REJECTED ]
2019-01-09 10:23:08 -08:00
# specific validation
if self . status not in allowed_statuses :
2019-01-30 09:59:15 -08:00
raise ValidationException ( f " Proposal status must be draft or rejected to submit for approval " )
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
self . set_pending ( )
2019-01-09 10:23:08 -08:00
2019-02-15 19:35:25 -08:00
def set_pending_when_ready ( self ) :
if self . status == ProposalStatus . STAKING and self . is_staked :
self . set_pending ( )
# state: status STAKING -> PENDING
def set_pending ( self ) :
2019-04-16 10:38:14 -07:00
self . send_admin_email ( ' admin_approval ' )
2019-02-15 19:35:25 -08:00
self . status = ProposalStatus . PENDING
db . session . add ( self )
db . session . flush ( )
2019-10-17 15:25:12 -07:00
# state: status PENDING -> (LIVE || REJECTED)
2019-10-16 20:43:20 -07:00
def approve_pending ( self , is_approve , with_funding , reject_reason = None ) :
2019-01-09 10:23:08 -08:00
self . validate_publishable ( )
# specific validation
2019-01-30 09:59:15 -08:00
if not self . status == ProposalStatus . PENDING :
raise ValidationException ( f " Proposal must be pending to approve or reject " )
2019-01-09 10:23:08 -08:00
if is_approve :
2019-10-17 15:25:12 -07:00
self . status = ProposalStatus . LIVE
2019-01-09 10:23:08 -08:00
self . date_approved = datetime . datetime . now ( )
2019-10-16 20:43:20 -07:00
self . accepted_with_funding = with_funding
2019-11-13 14:38:17 -08:00
# also update date_published and stage since publish() is no longer called by user
self . date_published = datetime . datetime . now ( )
self . stage = ProposalStage . WIP
2019-10-16 20:43:20 -07:00
if with_funding :
self . fully_fund_contibution_bounty ( )
2019-01-16 14:26:45 -08:00
for t in self . team :
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
admin_note = ' '
if with_funding :
admin_note = ' Congratulations! Your proposal has been accepted with funding from the Zcash Foundation. '
else :
admin_note = '''
We ' ve chosen to list your proposal on ZF Grants, but we won ' t be funding your proposal at this time .
Your proposal can still receive funding from the community in the form of tips if you have set a tip address for your proposal .
If you have not yet done so , you can do this from the actions dropdown at your proposal .
'''
2019-01-16 14:26:45 -08:00
send_email ( t . email_address , ' proposal_approved ' , {
' user ' : t ,
' proposal ' : self ,
' proposal_url ' : make_url ( f ' /proposals/ { self . id } ' ) ,
CCRs (#86)
* CCRs API / Models boilerplate
* start on frontend
* backendy things
* Create CCR redux module, integrate API endpoints, create types
* Fix/Cleanup API
* Wire up CreateRequestDraftList
* bounty->target
* Add 'Create Request Flow' MVP
* cleanup
* Tweak filenames
* Simplify migrations
* fix migrations
* CCR Staking MVP
* tslint
* Get Pending Requests into Profile
* Remove staking requirement
* more staking related removals
* MVP Admin integration
* Make RFP when CCR is accepted
* Add pagination to CCRs in Admin
Improve styles for Proposals
* Hookup notifications
Adjust copy
* Simplify ccr->rfp relationship
Add admin approval email
Fixup copy
* Show Message on RFP Detail
Make Header CTAs change based on draft status
Adjust proposal card style
* Bugfix: Show header for non signed in users
* Add 'create a request' to intro
* Profile Created CCRs
RFP CCR attribution
* ignore
* CCR Price in USD (#85)
* init profile tipjar backend
* init profile tipjar frontend
* fix lint
* implement tip jar block
* fix wrapping, hide tip block on self
* init backend proposal tipjar
* init frontend proposal tipjar
* add hide title, fix bug
* uncomment rate limit
* rename vars, use null check
* allow address and view key to be unset
* add api tests
* fix tsc errors
* fix lint
* fix CopyInput styling
* fix migrations
* hide tipping in proposal if address not set
* add tip address to create flow
* redesign campaign block
* fix typo
* init backend changes
* init admin changes
* init frontend changes
* fix backend tests
* update campaign block
* be - init rfp usd changes
* admin - init rfp usd changes
* fe - fully adapt api util functions to usd
* fe - init rfp usd changes
* adapt profile created to usd
* misc usd changes
* add tip jar to dedicated card
* fix tipjar bug
* use zf light logo
* switch to zf grants logo
* hide profile tip jar if address not set
* add comment, run prettier
* conditionally add info icon and tooltip to funding line
* admin - disallow decimals in RFPs
* fe - cover usd string edge case
* add Usd as rfp bounty type
* fix migration order
* fix email bug
* adapt CCRs to USD
* implement CCR preview
* fix tsc
* Copy Updates and UX Tweaks (#87)
* Add default structure to proposal content
* Landing page copy
* Hide contributors tab for v2 proposals
* Minor UX tweaks for Liking/Following/Tipping
* Copy for Tipping Tooltip, proposal explainer for review, and milestone day estimate notice.
* Fix header styles bug and remove commented out styles.
* Revert "like" / "unfollow" hyphenication
* Comment out unused tests related to staking
Increase PROPOSAL_TARGET_MAX in .env.example
* Comment out ccr approval email send until ready
* Adjust styles, copy.
* fix proposal prune test (#88)
* fix USD display in preview, fix non-unique key (#90)
* Pre-stepper explainer for CCRs.
* Tweak styles
* Default content for CCRs
* fix tsc
* CCR approval and rejection emails
* add back admin_approval_ccr email templates
* Link ccr author name to profile in RFPs
* copy tweaks
* copy tweak
* hookup mangle user command
* Fix/add endif in jinja
* fix tests
* review
* fix review
2019-12-05 17:01:02 -08:00
' admin_note ' : admin_note
2019-01-16 14:26:45 -08:00
} )
2019-01-09 10:23:08 -08:00
else :
if not reject_reason :
raise ValidationException ( " Please provide a reason for rejecting the proposal " )
2019-01-30 09:59:15 -08:00
self . status = ProposalStatus . REJECTED
2019-01-09 10:23:08 -08:00
self . reject_reason = reject_reason
2019-01-16 14:26:45 -08:00
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
} )
2019-01-09 10:23:08 -08:00
2019-10-23 14:44:19 -07:00
def update_proposal_with_funding ( self ) :
self . accepted_with_funding = True
self . fully_fund_contibution_bounty ( )
2019-02-15 19:35:25 -08:00
# state: status APPROVE -> LIVE, stage PREVIEW -> FUNDING_REQUIRED
2018-11-13 08:07:09 -08:00
def publish ( self ) :
2019-01-09 10:23:08 -08:00
self . validate_publishable ( )
# specific validation
2019-01-30 09:59:15 -08:00
if not self . status == ProposalStatus . APPROVED :
raise ValidationException ( f " Proposal status must be approved " )
2019-01-09 10:23:08 -08:00
self . date_published = datetime . datetime . now ( )
2019-01-30 09:59:15 -08:00
self . status = ProposalStatus . LIVE
2019-02-15 19:35:25 -08:00
self . stage = ProposalStage . WIP
2019-03-06 12:25:58 -08:00
def set_contribution_bounty ( self , bounty : str ) :
# do not allow changes on funded/WIP proposals
if self . is_funded :
raise ValidationException ( " Cannot change contribution bounty on fully-funded proposal " )
# wrap in Decimal so it throws for non-decimal strings
self . contribution_bounty = str ( Decimal ( bounty ) )
db . session . add ( self )
db . session . flush ( )
2019-10-16 20:43:20 -07:00
def fully_fund_contibution_bounty ( self ) :
self . set_contribution_bounty ( self . target )
2019-02-15 19:35:25 -08:00
2019-02-23 13:38:06 -08:00
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 ( )
2019-03-12 18:12:07 -07:00
2019-02-23 13:38:06 -08:00
# Send emails to team & contributors
for u in self . team :
2019-03-14 09:46:09 -07:00
send_email ( u . email_address , ' proposal_canceled ' , {
2019-02-23 13:38:06 -08:00
' proposal ' : self ,
' support_url ' : make_url ( ' /contact ' ) ,
} )
2019-03-14 09:46:09 -07:00
for u in self . contributors :
send_email ( u . email_address , ' contribution_proposal_canceled ' , {
' proposal ' : self ,
' refund_address ' : u . settings . refund_address ,
' account_settings_url ' : make_url ( ' /profile/settings?tab=account ' )
} )
2019-02-23 13:38:06 -08:00
2019-10-23 14:34:10 -07:00
def follow ( self , user , is_follow ) :
if is_follow :
self . followers . append ( user )
else :
self . followers . remove ( user )
db . session . flush ( )
2019-10-24 10:32:00 -07:00
def like ( self , user , is_liked ) :
if is_liked :
self . likes . append ( user )
else :
self . likes . remove ( user )
db . session . flush ( )
2019-10-23 14:34:10 -07:00
def send_follower_email ( self , type : str , email_args = { } , url_suffix = " " ) :
for u in self . followers :
send_email (
u . email_address ,
type ,
{
" user " : u ,
" proposal " : self ,
" proposal_url " : make_url ( f " /proposals/ { self . id } { url_suffix } " ) ,
* * email_args ,
} ,
)
2019-01-29 15:50:27 -08:00
@hybrid_property
def contributed ( self ) :
2019-01-16 14:26:45 -08:00
contributions = ProposalContribution . query \
2019-02-21 10:07:11 -08:00
. filter_by ( proposal_id = self . id , status = ContributionStatus . CONFIRMED , staking = False ) \
2019-01-16 14:26:45 -08:00
. all ( )
2019-02-05 17:45:57 -08:00
funded = reduce ( lambda prev , c : prev + Decimal ( c . amount ) , contributions , 0 )
2019-01-16 14:26:45 -08:00
return str ( funded )
2019-03-13 14:39:50 -07:00
@hybrid_property
def amount_staked ( self ) :
contributions = ProposalContribution . query \
. filter_by ( proposal_id = self . id , status = ContributionStatus . CONFIRMED , staking = True ) \
. all ( )
amount = reduce ( lambda prev , c : prev + Decimal ( c . amount ) , contributions , 0 )
return str ( amount )
2019-01-29 15:50:27 -08:00
@hybrid_property
def funded ( self ) :
2019-02-05 17:45:57 -08:00
target = Decimal ( self . target )
2019-01-29 15:50:27 -08:00
# apply matching multiplier
2019-02-05 17:45:57 -08:00
funded = Decimal ( self . contributed ) * Decimal ( 1 + self . contribution_matching )
2019-03-06 12:25:58 -08:00
# apply bounty
if self . contribution_bounty :
funded = funded + Decimal ( self . contribution_bounty )
2019-01-29 15:50:27 -08:00
# if funded > target, just set as target
if funded > target :
2019-04-16 13:08:13 -07:00
return str ( target . quantize ( Decimal ( ' .001 ' ) , rounding = ROUND_DOWN ) )
2019-01-29 15:50:27 -08:00
2019-04-16 13:08:13 -07:00
return str ( funded . quantize ( Decimal ( ' .001 ' ) , rounding = ROUND_DOWN ) )
2019-01-29 15:50:27 -08:00
2019-01-31 14:56:16 -08:00
@hybrid_property
def is_staked ( self ) :
2019-12-09 14:00:01 -08:00
return True
2019-01-31 14:56:16 -08:00
2019-02-11 21:10:09 -08:00
@hybrid_property
def is_funded ( self ) :
2019-02-21 10:21:46 -08:00
return self . is_staked and Decimal ( self . funded ) > = Decimal ( self . target )
2019-02-15 19:35:25 -08:00
@hybrid_property
def is_failed ( self ) :
if not self . status == ProposalStatus . LIVE or not self . date_published :
return False
2019-02-23 13:38:06 -08:00
if self . stage == ProposalStage . FAILED or self . stage == ProposalStage . CANCELED :
return True
2019-02-15 19:35:25 -08:00
deadline = self . date_published + datetime . timedelta ( seconds = self . deadline_duration )
passed = deadline < datetime . datetime . now ( )
return passed and not self . is_funded
2019-02-11 21:10:09 -08:00
2019-02-11 13:08:51 -08:00
@hybrid_property
def current_milestone ( self ) :
if self . milestones :
for ms in self . milestones :
if ms . stage != MilestoneStage . PAID :
return ms
2019-02-13 08:54:46 -08:00
return self . milestones [ - 1 ] # return last one if all PAID
2019-02-11 13:08:51 -08:00
return None
2019-03-14 09:46:09 -07:00
@hybrid_property
def contributors ( self ) :
d = { c . user . id : c . user for c in self . contributions if c . user and c . status == ContributionStatus . CONFIRMED }
return d . values ( )
2019-10-23 14:34:10 -07:00
@hybrid_property
def authed_follows ( self ) :
from grant . utils . auth import get_authed_user
authed = get_authed_user ( )
if not authed :
return False
res = (
db . session . query ( proposal_follower )
. filter_by ( user_id = authed . id , proposal_id = self . id )
. count ( )
)
if res :
return True
return False
2019-10-24 10:32:00 -07:00
@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 ( proposal_liker )
. filter_by ( user_id = authed . id , proposal_id = self . id )
. count ( )
)
if res :
return True
return False
2019-11-20 13:37:26 -08:00
@hybrid_property
def get_tip_jar_view_key ( self ) :
from grant . utils . auth import get_authed_user
authed = get_authed_user ( )
if authed not in self . team :
return None
else :
return self . tip_jar_view_key
2018-09-10 09:55:26 -07:00
class ProposalSchema ( ma . Schema ) :
class Meta :
model = Proposal
# Fields to expose
fields = (
" stage " ,
2019-01-09 10:23:08 -08:00
" status " ,
2018-09-10 09:55:26 -07:00
" date_created " ,
2019-01-09 10:23:08 -08:00
" date_approved " ,
" date_published " ,
" reject_reason " ,
2018-09-10 09:55:26 -07:00
" title " ,
2018-11-14 08:43:00 -08:00
" brief " ,
2018-09-10 09:55:26 -07:00
" proposal_id " ,
2018-11-14 13:18:40 -08:00
" target " ,
2019-01-29 15:50:27 -08:00
" contributed " ,
2019-01-31 14:56:16 -08:00
" is_staked " ,
2019-02-15 19:35:25 -08:00
" is_failed " ,
2018-12-27 10:00:04 -08:00
" funded " ,
2018-11-14 08:43:00 -08:00
" content " ,
2018-11-02 09:24:28 -07:00
" updates " ,
2018-09-10 09:55:26 -07:00
" milestones " ,
2019-02-11 13:08:51 -08:00
" current_milestone " ,
2018-11-14 08:43:00 -08:00
" team " ,
" payout_address " ,
" deadline_duration " ,
2019-01-29 15:50:27 -08:00
" contribution_matching " ,
2019-03-06 12:25:58 -08:00
" contribution_bounty " ,
2019-02-01 11:13:30 -08:00
" invites " ,
2019-02-05 12:45:26 -08:00
" rfp " ,
2019-03-06 12:25:58 -08:00
" rfp_opt_in " ,
2019-10-11 12:51:10 -07:00
" arbiter " ,
2019-10-16 20:43:20 -07:00
" accepted_with_funding " ,
2019-10-23 14:34:10 -07:00
" is_version_two " ,
" authed_follows " ,
2019-10-24 10:32:00 -07:00
" followers_count " ,
" authed_liked " ,
2019-11-20 13:37:26 -08:00
" likes_count " ,
" tip_jar_address " ,
" tip_jar_view_key "
2018-09-10 09:55:26 -07:00
)
date_created = ma . Method ( " get_date_created " )
2019-01-09 10:23:08 -08:00
date_approved = ma . Method ( " get_date_approved " )
date_published = ma . Method ( " get_date_published " )
2018-09-10 09:55:26 -07:00
proposal_id = ma . Method ( " get_proposal_id " )
2019-10-11 12:51:10 -07:00
is_version_two = ma . Method ( " get_is_version_two " )
2019-11-20 13:37:26 -08:00
tip_jar_view_key = ma . Method ( " get_tip_jar_view_key " )
2018-09-10 09:55:26 -07:00
2018-11-02 09:24:28 -07:00
updates = ma . Nested ( " ProposalUpdateSchema " , many = True )
2018-09-25 13:09:25 -07:00
team = ma . Nested ( " UserSchema " , many = True )
2018-09-10 09:55:26 -07:00
milestones = ma . Nested ( " MilestoneSchema " , many = True )
2019-02-11 13:08:51 -08:00
current_milestone = ma . Nested ( " MilestoneSchema " )
2018-11-15 13:51:32 -08:00
invites = ma . Nested ( " ProposalTeamInviteSchema " , many = True )
2019-02-01 11:13:30 -08:00
rfp = ma . Nested ( " RFPSchema " , exclude = [ " accepted_proposals " ] )
2019-02-09 18:58:40 -08:00
arbiter = ma . Nested ( " ProposalArbiterSchema " , exclude = [ " proposal " ] )
2018-09-10 09:55:26 -07:00
def get_proposal_id ( self , obj ) :
2018-11-07 09:33:19 -08:00
return obj . id
2018-09-10 09:55:26 -07:00
def get_date_created ( self , obj ) :
return dt_to_unix ( obj . date_created )
2019-01-09 10:23:08 -08:00
def get_date_approved ( self , obj ) :
return dt_to_unix ( obj . date_approved ) if obj . date_approved else None
def get_date_published ( self , obj ) :
return dt_to_unix ( obj . date_published ) if obj . date_published else None
2019-10-11 12:51:10 -07:00
def get_is_version_two ( self , obj ) :
return True if obj . version == ' 2 ' else False
2018-09-10 09:55:26 -07:00
2019-11-20 13:37:26 -08:00
def get_tip_jar_view_key ( self , obj ) :
return obj . get_tip_jar_view_key
2018-09-10 09:55:26 -07:00
proposal_schema = ProposalSchema ( )
proposals_schema = ProposalSchema ( many = True )
2019-01-09 13:57:15 -08:00
user_fields = [
" proposal_id " ,
" status " ,
" title " ,
" brief " ,
" target " ,
2019-01-31 14:56:16 -08:00
" is_staked " ,
2019-01-09 13:57:15 -08:00
" funded " ,
2019-01-29 15:50:27 -08:00
" contribution_matching " ,
2019-01-09 13:57:15 -08:00
" date_created " ,
" date_approved " ,
" date_published " ,
" reject_reason " ,
" team " ,
2019-12-03 16:02:39 -08:00
" accepted_with_funding " ,
2019-10-23 14:34:10 -07:00
" is_version_two " ,
2019-10-24 10:32:00 -07:00
" authed_follows " ,
" authed_liked "
2019-01-09 13:57:15 -08:00
]
user_proposal_schema = ProposalSchema ( only = user_fields )
user_proposals_schema = ProposalSchema ( many = True , only = user_fields )
2018-11-02 09:24:28 -07:00
2019-01-16 14:26:45 -08:00
2018-11-02 09:24:28 -07:00
class ProposalUpdateSchema ( ma . Schema ) :
class Meta :
model = ProposalUpdate
# Fields to expose
fields = (
2018-11-07 09:33:19 -08:00
" update_id " ,
2018-11-02 09:24:28 -07:00
" date_created " ,
" proposal_id " ,
" title " ,
" content "
)
date_created = ma . Method ( " get_date_created " )
proposal_id = ma . Method ( " get_proposal_id " )
2018-11-07 09:33:19 -08:00
update_id = ma . Method ( " get_update_id " )
def get_update_id ( self , obj ) :
return obj . id
2018-11-02 09:24:28 -07:00
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 ( )
2018-11-07 09:33:19 -08:00
proposals_update_schema = ProposalUpdateSchema ( many = True )
2018-11-15 13:51:32 -08:00
class ProposalTeamInviteSchema ( ma . Schema ) :
class Meta :
model = ProposalTeamInvite
fields = (
" id " ,
" date_created " ,
" address " ,
" accepted "
)
date_created = ma . Method ( " get_date_created " )
def get_date_created ( self , obj ) :
return dt_to_unix ( obj . date_created )
2018-11-30 15:52:00 -08:00
2018-11-15 13:51:32 -08:00
proposal_team_invite_schema = ProposalTeamInviteSchema ( )
proposal_team_invites_schema = ProposalTeamInviteSchema ( many = True )
2018-11-16 10:50:47 -08:00
2019-01-22 21:35:22 -08:00
2018-11-16 10:50:47 -08:00
class InviteWithProposalSchema ( ma . Schema ) :
class Meta :
model = ProposalTeamInvite
fields = (
" id " ,
" date_created " ,
" address " ,
" accepted " ,
" proposal "
)
date_created = ma . Method ( " get_date_created " )
proposal = ma . Nested ( " ProposalSchema " )
def get_date_created ( self , obj ) :
return dt_to_unix ( obj . date_created )
2018-11-30 15:52:00 -08:00
2018-11-16 10:50:47 -08:00
invite_with_proposal_schema = InviteWithProposalSchema ( )
2018-11-26 17:14:00 -08:00
invites_with_proposal_schema = InviteWithProposalSchema ( many = True )
2018-11-21 19:18:22 -08:00
class ProposalContributionSchema ( ma . Schema ) :
class Meta :
model = ProposalContribution
# Fields to expose
fields = (
" id " ,
2019-01-06 14:48:07 -08:00
" proposal " ,
" user " ,
2019-01-08 09:44:54 -08:00
" status " ,
2018-11-21 19:18:22 -08:00
" tx_id " ,
" amount " ,
" date_created " ,
2019-01-06 22:58:33 -08:00
" addresses " ,
2019-02-25 11:46:47 -08:00
" is_anonymous " ,
2019-06-11 19:49:14 -07:00
" private "
2018-11-21 19:18:22 -08:00
)
2019-01-06 14:48:07 -08:00
proposal = ma . Nested ( " ProposalSchema " )
2019-02-23 12:31:07 -08:00
user = ma . Nested ( " UserSchema " , default = anonymous_user )
2019-01-06 14:48:07 -08:00
date_created = ma . Method ( " get_date_created " )
2019-01-06 22:58:33 -08:00
addresses = ma . Method ( " get_addresses " )
2019-02-25 11:46:47 -08:00
is_anonymous = ma . Method ( " get_is_anonymous " )
2018-11-21 19:18:22 -08:00
def get_date_created ( self , obj ) :
return dt_to_unix ( obj . date_created )
2019-01-06 22:58:33 -08:00
def get_addresses ( self , obj ) :
2019-02-23 12:19:33 -08:00
# Omit 'memo' and 'sprout' for now
2019-03-13 14:39:50 -07:00
# NOTE: Add back in 'sapling' when ready
2019-02-23 12:19:33 -08:00
addresses = blockchain_get ( ' /contribution/addresses ' , { ' contributionId ' : obj . id } )
return {
' transparent ' : addresses [ ' transparent ' ] ,
}
2019-03-06 12:25:58 -08:00
2019-02-25 11:46:47 -08:00
def get_is_anonymous ( self , obj ) :
2019-06-11 19:49:14 -07:00
return not obj . user_id or obj . private
2019-01-06 22:58:33 -08:00
2019-02-23 12:31:07 -08:00
@post_dump
def stub_anonymous_user ( self , data ) :
2019-06-11 19:49:14 -07:00
if ' user ' in data and data [ ' user ' ] is None or data [ ' private ' ] :
2019-02-23 12:31:07 -08:00
data [ ' user ' ] = anonymous_user
return data
2018-11-30 15:52:00 -08:00
2018-11-21 19:18:22 -08:00
proposal_contribution_schema = ProposalContributionSchema ( )
2019-01-09 11:07:50 -08:00
proposal_contributions_schema = ProposalContributionSchema ( many = True )
2019-01-09 12:48:41 -08:00
user_proposal_contribution_schema = ProposalContributionSchema ( exclude = [ ' user ' , ' addresses ' ] )
user_proposal_contributions_schema = ProposalContributionSchema ( many = True , exclude = [ ' user ' , ' addresses ' ] )
proposal_proposal_contribution_schema = ProposalContributionSchema ( exclude = [ ' proposal ' , ' addresses ' ] )
proposal_proposal_contributions_schema = ProposalContributionSchema ( many = True , exclude = [ ' proposal ' , ' addresses ' ] )
2019-02-09 18:58:40 -08:00
2019-02-17 08:52:35 -08:00
class AdminProposalContributionSchema ( ma . Schema ) :
class Meta :
model = ProposalContribution
# Fields to expose
fields = (
" id " ,
" proposal " ,
" user " ,
" status " ,
" tx_id " ,
" amount " ,
" date_created " ,
" addresses " ,
" refund_address " ,
" refund_tx_id " ,
2019-03-13 16:36:24 -07:00
" staking " ,
2019-06-11 19:49:14 -07:00
" private " ,
2019-02-17 08:52:35 -08:00
)
proposal = ma . Nested ( " ProposalSchema " )
user = ma . Nested ( " UserSchema " )
date_created = ma . Method ( " get_date_created " )
addresses = ma . Method ( " get_addresses " )
def get_date_created ( self , obj ) :
return dt_to_unix ( obj . date_created )
def get_addresses ( self , obj ) :
return blockchain_get ( ' /contribution/addresses ' , { ' contributionId ' : obj . id } )
admin_proposal_contribution_schema = AdminProposalContributionSchema ( )
admin_proposal_contributions_schema = AdminProposalContributionSchema ( many = True )
2019-02-09 18:58:40 -08:00
class ProposalArbiterSchema ( ma . Schema ) :
class Meta :
model = ProposalArbiter
fields = (
" id " ,
" user " ,
" proposal " ,
" status "
)
user = ma . Nested ( " UserSchema " ) # , exclude=['arbiter_proposals'] (if UserSchema ever includes it)
proposal = ma . Nested ( " ProposalSchema " , exclude = [ ' arbiter ' ] )
user_proposal_arbiter_schema = ProposalArbiterSchema ( exclude = [ ' user ' ] )
user_proposal_arbiters_schema = ProposalArbiterSchema ( many = True , exclude = [ ' user ' ] )