Skip to content

Commit

Permalink
Merge pull request #459 from ZcashFoundation/develop
Browse files Browse the repository at this point in the history
Release 1.4.0
  • Loading branch information
dternyak authored Jun 12, 2019
2 parents b34ee97 + 8819ee3 commit dd966ae
Show file tree
Hide file tree
Showing 21 changed files with 257 additions and 132 deletions.
2 changes: 1 addition & 1 deletion admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
"react-copy-to-clipboard": "^5.0.1",
"react-dev-utils": "^5.0.2",
"react-dom": "16.5.2",
"react-easy-state": "^6.0.4",
"react-easy-state": "^6.1.3",
"react-hot-loader": "^4.3.8",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",
Expand Down
61 changes: 35 additions & 26 deletions admin/src/components/ContributionDetail/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,27 @@ class ContributionDetail extends React.Component<Props, State> {

const renderDeetItem = (label: string, val: React.ReactNode) => (
<div className="ContributionDetail-deet">
<div className="ContributionDetail-deet-value">
{val}
</div>
<div className="ContributionDetail-deet-label">
{label}
</div>
<div className="ContributionDetail-deet-value">{val}</div>
<div className="ContributionDetail-deet-label">{label}</div>
</div>
);

const renderSendRefund = () => {
if (c.staking || !c.refundAddress || c.refundTxId || !c.proposal.isFailed || !c.user) {
if (
c.staking ||
!c.refundAddress ||
c.refundTxId ||
!c.proposal.isFailed ||
!c.user
) {
return;
}
const percent = c.proposal.milestones.reduce((prev, m) => {
return m.datePaid ? prev - parseFloat(m.payoutPercent) : prev;
}, 100);
const amount = toZat(c.amount).muln(percent).divn(100);
const amount = toZat(c.amount)
.muln(percent)
.divn(100);
return (
<Alert
className="ContributionDetail-alert"
Expand All @@ -62,15 +66,15 @@ class ContributionDetail extends React.Component<Props, State> {
description={
<div>
<p>
The proposal this contribution was made towards has failed, and
is ready to be refunded to <strong>{c.user.displayName}</strong>
{' '}for <strong>{percent}%</strong> of the contribution amount.
Please Make a payment of <strong>{fromZat(amount)} ZEC</strong> to:
The proposal this contribution was made towards has failed, and is ready
to be refunded to <strong>{c.user.displayName}</strong> for{' '}
<strong>{percent}%</strong> of the contribution amount. Please Make a
payment of <strong>{fromZat(amount)} ZEC</strong> to:
</p>
<pre>{c.refundAddress}</pre>
<p>
They will be sent an email notifying them of the refund when you
enter the txid below.
They will be sent an email notifying them of the refund when you enter the
txid below.
</p>
<Input.Search
placeholder="Enter payment txid"
Expand Down Expand Up @@ -98,10 +102,9 @@ class ContributionDetail extends React.Component<Props, State> {
<pre>{JSON.stringify(c.addresses, null, 4)}</pre>
</Collapse.Panel>


<Collapse.Panel key="user" header="user">
{c.user ? <UserItem {...c.user} /> : <em>Anonymous contribution</em>}
</Collapse.Panel>
<Collapse.Panel key="user" header="user">
{c.user ? <UserItem {...c.user} /> : <em>Anonymous contribution</em>}
</Collapse.Panel>

<Collapse.Panel key="proposal" header="proposal">
<ProposalItem {...c.proposal} />
Expand All @@ -118,7 +121,9 @@ class ContributionDetail extends React.Component<Props, State> {
{/* ACTIONS */}
<Card size="small" className="ContributionDetail-controls">
<Link to={`/contributions/${id}/edit`}>
<Button type="primary" block>Edit</Button>
<Button type="primary" block>
Edit
</Button>
</Link>
</Card>

Expand All @@ -128,16 +133,20 @@ class ContributionDetail extends React.Component<Props, State> {
{renderDeetItem('created', formatDateSeconds(c.dateCreated))}
{renderDeetItem('status', c.status)}
{renderDeetItem('amount', c.amount)}
{renderDeetItem('txid', c.txId
? <Input size="small" value={c.txId} readOnly />
: <em>N/A</em>
{renderDeetItem(
'txid',
c.txId ? <Input size="small" value={c.txId} readOnly /> : <em>N/A</em>,
)}
{renderDeetItem('refund txid', c.refundTxId
? <Input size="small" value={c.refundTxId} readOnly />
: <em>N/A</em>
{renderDeetItem(
'refund txid',
c.refundTxId ? (
<Input size="small" value={c.refundTxId} readOnly />
) : (
<em>N/A</em>
),
)}
{renderDeetItem('staking tx', JSON.stringify(c.staking))}
{renderDeetItem('no refund', JSON.stringify(c.noRefund))}
{renderDeetItem('private', JSON.stringify(c.private))}
</Card>
</Col>
</Row>
Expand Down
2 changes: 1 addition & 1 deletion admin/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export interface Contribution {
memo: string;
};
staking: boolean;
noRefund: boolean;
private: boolean;
refundAddress?: string;
refundTxId?: string;
}
Expand Down
16 changes: 9 additions & 7 deletions admin/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -792,9 +792,10 @@
reflect-metadata "^0.1.12"
tslib "^1.8.1"

"@nx-js/observer-util@^4.1.1":
version "4.2.0"
resolved "https://registry.yarnpkg.com/@nx-js/observer-util/-/observer-util-4.2.0.tgz#ec9e2f903dda94cc3d8ac077617bc369f2ad2d6e"
"@nx-js/observer-util@^4.2.2":
version "4.2.2"
resolved "https://registry.yarnpkg.com/@nx-js/observer-util/-/observer-util-4.2.2.tgz#faea1bc61936653486d1b5dec7485220991e628d"
integrity sha512-9OayX1xkdGjdnsDiO2YdaYJ6aMyCF7/NY4QWVgIgjSAZJ4OX2fD766Ts79hEzBscenQy2DCaSoY8VkguIMB1ZA==

"@samverschueren/stream-to-observable@^0.3.0":
version "0.3.0"
Expand Down Expand Up @@ -6616,11 +6617,12 @@ [email protected]:
prop-types "^15.6.2"
schedule "^0.5.0"

react-easy-state@^6.0.4:
version "6.0.4"
resolved "https://registry.yarnpkg.com/react-easy-state/-/react-easy-state-6.0.4.tgz#94a124fe69723abcb922c15059dd444b2e3499f3"
react-easy-state@^6.1.3:
version "6.1.3"
resolved "https://registry.yarnpkg.com/react-easy-state/-/react-easy-state-6.1.3.tgz#f9db4e8d842b5acfb73b6899aaf49a26900f7d26"
integrity sha512-uWQ7ittvJylwn/Xgz7Ub1jjsbpthQ9Ad1KDLxXfbXCb2OPnov4porVdnOJU2PKeRezcam3ZgfPUtf9L9rjtyWg==
dependencies:
"@nx-js/observer-util" "^4.1.1"
"@nx-js/observer-util" "^4.2.2"

react-error-overlay@^4.0.1:
version "4.0.1"
Expand Down
31 changes: 26 additions & 5 deletions backend/grant/admin/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ def stats():
contribution_refundable_count = db.session.query(func.count(ProposalContribution.id)) \
.filter(ProposalContribution.refund_tx_id == None) \
.filter(ProposalContribution.staking == False) \
.filter(ProposalContribution.no_refund == False) \
.filter(ProposalContribution.status == ContributionStatus.CONFIRMED) \
.join(Proposal) \
.filter(or_(
Expand Down Expand Up @@ -609,7 +608,7 @@ def get_contribution(contribution_id):
@body({
"proposalId": fields.Int(required=False, missing=None),
"userId": fields.Int(required=False, missing=None),
"status": fields.Str(required=True, validate=validate.OneOf(choices=ContributionStatus.list())),
"status": fields.Str(required=False, missing=None, validate=validate.OneOf(choices=ContributionStatus.list())),
"amount": fields.Str(required=False, missing=None),
"txId": fields.Str(required=False, missing=None),
"refundTxId": fields.Str(required=False, allow_none=True, missing=None),
Expand Down Expand Up @@ -723,6 +722,8 @@ def sql_pc_p(where: str):
SELECT SUM(TO_NUMBER(amount, '{nfmt}'))
FROM proposal_contribution as pc
INNER JOIN proposal as p ON pc.proposal_id = p.id
LEFT OUTER JOIN "user" as u ON pc.user_id = u.id
LEFT OUTER JOIN user_settings as us ON u.id = us.user_id
WHERE {where}
'''

Expand All @@ -743,14 +744,34 @@ def ex(sql: str):
'staking': str(ex(sql_pc("status = 'CONFIRMED' AND staking = TRUE"))),
'funding': str(ex(sql_pc_p("pc.status = 'CONFIRMED' AND pc.staking = FALSE AND p.stage = 'FUNDING_REQUIRED'"))),
'funded': str(ex(sql_pc_p("pc.status = 'CONFIRMED' AND pc.staking = FALSE AND p.stage in ('WIP', 'COMPLETED')"))),
# should have a refund_address
'refunding': str(ex(sql_pc_p(
"pc.status = 'CONFIRMED' AND pc.staking = FALSE AND pc.no_refund = FALSE AND pc.refund_tx_id IS NULL AND p.stage IN ('CANCELED', 'FAILED')"
'''
pc.status = 'CONFIRMED' AND
pc.staking = FALSE AND
pc.refund_tx_id IS NULL AND
p.stage IN ('CANCELED', 'FAILED') AND
us.refund_address IS NOT NULL
'''
))),
# here we don't care about current refund_address of user, just that there has been a refund_tx_id
'refunded': str(ex(sql_pc_p(
"pc.status = 'CONFIRMED' AND pc.staking = FALSE AND pc.no_refund = FALSE AND pc.refund_tx_id IS NOT NULL AND p.stage IN ('CANCELED', 'FAILED')"
'''
pc.status = 'CONFIRMED' AND
pc.staking = FALSE AND
pc.refund_tx_id IS NOT NULL AND
p.stage IN ('CANCELED', 'FAILED')
'''
))),
# if there is no user, or the user hasn't any refund_address
'donations': str(ex(sql_pc_p(
"(pc.status = 'CONFIRMED' AND pc.staking = FALSE AND pc.refund_tx_id IS NULL) AND (pc.no_refund = TRUE OR pc.user_id IS NULL) AND p.stage IN ('CANCELED', 'FAILED')"
'''
pc.status = 'CONFIRMED' AND
pc.staking = FALSE AND
pc.refund_tx_id IS NULL AND
(pc.user_id IS NULL OR us.refund_address IS NULL) AND
p.stage IN ('CANCELED', 'FAILED')
'''
))),
'gross': str(ex(sql_pc_p("pc.status = 'CONFIRMED' AND pc.refund_tx_id IS NULL"))),
}
Expand Down
2 changes: 1 addition & 1 deletion backend/grant/comment/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def __init__(self, proposal_id, user_id, parent_comment_id, content):
self.proposal_id = proposal_id
self.user_id = user_id
self.parent_comment_id = parent_comment_id
self.content = content[:1000]
self.content = content[:5000]
self.date_created = datetime.datetime.now()

@staticmethod
Expand Down
21 changes: 11 additions & 10 deletions backend/grant/proposal/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class ProposalContribution(db.Model):
tx_id = db.Column(db.String(255), nullable=True)
refund_tx_id = db.Column(db.String(255), nullable=True)
staking = db.Column(db.Boolean, nullable=False)
no_refund = db.Column(db.Boolean, nullable=False)
private = db.Column(db.Boolean, nullable=False, default=False, server_default='true')

user = db.relationship("User")

Expand All @@ -98,23 +98,23 @@ def __init__(
amount: str,
user_id: int = None,
staking: bool = False,
no_refund: bool = False,
private: bool = True,
):
self.proposal_id = proposal_id
self.amount = amount
self.user_id = user_id
self.staking = staking
self.no_refund = no_refund
self.private = private
self.date_created = datetime.datetime.now()
self.status = ContributionStatus.PENDING

@staticmethod
def get_existing_contribution(user_id: int, proposal_id: int, amount: str, no_refund: bool = False):
def get_existing_contribution(user_id: int, proposal_id: int, amount: str, private: bool = False):
return ProposalContribution.query.filter_by(
user_id=user_id,
proposal_id=proposal_id,
amount=amount,
no_refund=no_refund,
private=private,
status=ContributionStatus.PENDING,
).first()

Expand Down Expand Up @@ -425,14 +425,14 @@ def create_contribution(
amount,
user_id: int = None,
staking: bool = False,
no_refund: bool = False,
private: bool = True,
):
contribution = ProposalContribution(
proposal_id=self.id,
amount=amount,
user_id=user_id,
staking=staking,
no_refund=no_refund,
private=private
)
db.session.add(contribution)
db.session.flush()
Expand Down Expand Up @@ -841,6 +841,7 @@ class Meta:
"date_created",
"addresses",
"is_anonymous",
"private"
)

proposal = ma.Nested("ProposalSchema")
Expand All @@ -861,11 +862,11 @@ def get_addresses(self, obj):
}

def get_is_anonymous(self, obj):
return not obj.user_id
return not obj.user_id or obj.private

@post_dump
def stub_anonymous_user(self, data):
if 'user' in data and data['user'] is None:
if 'user' in data and data['user'] is None or data['private']:
data['user'] = anonymous_user
return data

Expand Down Expand Up @@ -894,7 +895,7 @@ class Meta:
"refund_address",
"refund_tx_id",
"staking",
"no_refund",
"private",
)

proposal = ma.Nested("ProposalSchema")
Expand Down
16 changes: 6 additions & 10 deletions backend/grant/proposal/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def report_proposal_comment(proposal_id, comment_id):
@limiter.limit("30/hour;2/minute")
@requires_email_verified_auth
@body({
"comment": fields.Str(required=True, validate=validate.Length(max=1000)),
"comment": fields.Str(required=True, validate=validate.Length(max=5000)),
"parentCommentId": fields.Int(required=False, missing=None),
})
def post_proposal_comments(proposal_id, comment, parent_comment_id):
Expand Down Expand Up @@ -478,30 +478,26 @@ def get_proposal_contribution(proposal_id, contribution_id):
@limiter.limit("30/day;10/hour;2/minute")
@body({
"amount": fields.Str(required=True, validate=lambda p: 0.0001 <= float(p) <= 1000000),
"anonymous": fields.Bool(required=False, missing=None),
"noRefund": fields.Bool(required=False, missing=False),
"private": fields.Bool(required=False, missing=True)
})
def post_proposal_contribution(proposal_id, amount, anonymous, no_refund):
def post_proposal_contribution(proposal_id, amount, private):
proposal = Proposal.query.filter_by(id=proposal_id).first()
if not proposal:
return {"message": "No proposal matching id"}, 404

code = 200
user = None
user = get_authed_user()
contribution = None

if not anonymous:
user = get_authed_user()

if user:
contribution = ProposalContribution \
.get_existing_contribution(user.id, proposal_id, amount, no_refund)
.get_existing_contribution(user.id, proposal_id, amount, private)

if not contribution:
code = 201
contribution = proposal.create_contribution(
amount=amount,
no_refund=no_refund,
private=private,
user_id=user.id if user else None,
)

Expand Down
1 change: 1 addition & 0 deletions backend/grant/user/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ def get_user(user_id, with_proposals, with_comments, with_funded, with_pending,
contributions = ProposalContribution.get_by_userid(user_id)
if not authed_user or user.id != authed_user.id:
contributions = [c for c in contributions if c.status == ContributionStatus.CONFIRMED]
contributions = [c for c in contributions if not c.private]
contributions = [c for c in contributions if c.proposal.status == ProposalStatus.LIVE]
contributions_dump = user_proposal_contributions_schema.dump(contributions)
result["contributions"] = contributions_dump
Expand Down
10 changes: 4 additions & 6 deletions backend/grant/utils/pagination.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ def paginate(
if 'REFUNDABLE' in filters:
query = query.filter(ProposalContribution.refund_tx_id == None) \
.filter(ProposalContribution.staking == False) \
.filter(ProposalContribution.no_refund == False) \
.filter(ProposalContribution.status == ContributionStatus.CONFIRMED) \
.join(Proposal) \
.filter(or_(
Expand All @@ -173,15 +172,14 @@ def paginate(
if 'DONATION' in filters:
query = query.filter(ProposalContribution.refund_tx_id == None) \
.filter(ProposalContribution.status == ContributionStatus.CONFIRMED) \
.filter(or_(
ProposalContribution.no_refund == True,
ProposalContribution.user_id == None,
)) \
.join(Proposal) \
.filter(or_(
Proposal.stage == ProposalStage.FAILED,
Proposal.stage == ProposalStage.CANCELED,
))
)) \
.join(ProposalContribution.user, isouter=True) \
.join(UserSettings, isouter=True) \
.filter(UserSettings.refund_address == None)

# SORT (see self.SORT_MAP)
if sort:
Expand Down
Loading

0 comments on commit dd966ae

Please sign in to comment.