Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various #2277

Merged
merged 5 commits into from
Sep 23, 2023
Merged

Various #2277

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions liberapay/billing/payday.py
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,7 @@ def update_stats(cls, payday_id):
FROM participants p
WHERE p.kind IN ('individual', 'organization')
AND p.join_time < %(ts_start)s
AND p.is_suspended IS NOT true
AND COALESCE((
SELECT payload::text
FROM events e
Expand Down
4 changes: 3 additions & 1 deletion liberapay/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
from liberapay.models.account_elsewhere import refetch_elsewhere_data
from liberapay.models.community import Community
from liberapay.models.participant import (
Participant, clean_up_closed_accounts, send_account_disabled_notifications,
Participant, clean_up_closed_accounts, free_up_usernames,
send_account_disabled_notifications,
generate_profile_description_missing_notifications
)
from liberapay.models.repository import refetch_repos
Expand Down Expand Up @@ -185,6 +186,7 @@ def default_body_parser(body_bytes, headers):
cron(Daily(hour=17), paypal.sync_all_pending_payments, True)
cron(Daily(hour=18), Payday.update_cached_amounts, True)
cron(Daily(hour=19), Participant.delete_old_feedback, True)
cron(Daily(hour=20), free_up_usernames, True)
cron(intervals.get('notify_patrons', 1200), Participant.notify_patrons, True)
if conf.ses_feedback_queue_url:
cron(intervals.get('fetch_email_bounces', 60), handle_email_bounces, True)
Expand Down
31 changes: 30 additions & 1 deletion liberapay/models/participant.py
Original file line number Diff line number Diff line change
Expand Up @@ -3199,10 +3199,17 @@ def get_tips_awaiting_payment(self, weeks_early=3, exclude_recipients_of=None):
SELECT t.*, p AS tippee_p
FROM current_tips t
JOIN participants p ON p.id = t.tippee
LEFT JOIN scheduled_payins sp ON sp.payer = t.tipper
AND sp.payin IS NULL
AND t.tippee::text IN (
SELECT tr->>'tippee_id'
FROM json_array_elements(sp.transfers) tr
)
WHERE t.tipper = %(tipper_id)s
AND t.renewal_mode > 0
AND ( t.paid_in_advance IS NULL OR
t.paid_in_advance < (t.amount * %(weeks_early)s)
t.paid_in_advance < (t.amount * %(weeks_early)s) OR
sp.execution_date <= (current_date + interval '%(weeks_early)s weeks')
)
AND p.status = 'active'
AND ( p.goal IS NULL OR p.goal >= 0 )
Expand Down Expand Up @@ -3747,6 +3754,28 @@ def clean_up_closed_accounts():
return len(participants)


def free_up_usernames():
n = website.db.one("""
WITH updated AS (
UPDATE participants
SET username = '~' || id::text
WHERE username NOT LIKE '~%'
AND marked_as IN ('fraud', 'spam')
AND kind IN ('individual', 'organization')
AND (
SELECT e.ts
FROM events e
WHERE e.participant = participants.id
AND e.type = 'flags_changed'
ORDER BY e.ts DESC
LIMIT 1
) < (current_timestamp - interval '3 weeks')
RETURNING id
) SELECT count(*) FROM updated;
""")
print(f"Freed up {n} username{'s' if n > 1 else ''}.")


def send_account_disabled_notifications():
"""Notify the owners of accounts that have been flagged as fraud or spam.

Expand Down
19 changes: 13 additions & 6 deletions liberapay/payin/stripe.py
Original file line number Diff line number Diff line change
Expand Up @@ -739,12 +739,19 @@
tr = stripe.Transfer.retrieve(charge.transfer)
update_transfer_metadata(tr, pt)
if tr.amount_reversed < bt.fee:
tr.reversals.create(
amount=bt.fee,
description="Stripe fee",
metadata={'payin_id': payin.id},
idempotency_key='payin_fee_%i' % payin.id,
)
try:
tr.reversals.create(

Check warning on line 743 in liberapay/payin/stripe.py

View check run for this annotation

Codecov / codecov/patch

liberapay/payin/stripe.py#L742-L743

Added lines #L742 - L743 were not covered by tests
amount=bt.fee,
description="Stripe fee",
metadata={'payin_id': payin.id},
idempotency_key='payin_fee_%i' % payin.id,
)
except stripe.error.StripeError as e:

Check warning on line 749 in liberapay/payin/stripe.py

View check run for this annotation

Codecov / codecov/patch

liberapay/payin/stripe.py#L749

Added line #L749 was not covered by tests
# In some cases Stripe can refuse to create a reversal. This is
# a serious problem, it means that Liberapay is losing money,
# but it can't be properly resolved automatically, so here the
# error is merely sent to Sentry.
website.tell_sentry(e)

Check warning on line 754 in liberapay/payin/stripe.py

View check run for this annotation

Codecov / codecov/patch

liberapay/payin/stripe.py#L754

Added line #L754 was not covered by tests
elif tr.amount_reversed > bt.fee:
reversed_amount = int_to_Money(tr.amount_reversed, tr.currency) - fee
record_reversals(db, pt, tr)
Expand Down
2 changes: 1 addition & 1 deletion www/%username/giving/pay/%payment_id.spt
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ elif payin_id:
raise response.error(404, "unknown payin ID in URL path")
response.redirect(payer.path('giving/pay/stripe/%i' % payin.id))

weeks_early = request.qs.get_int('weeks_early', default=3)
weeks_early = request.qs.get_int('weeks_early', default=3, minimum=1, maximum=520)
donation_groups, n_fundable = payer.get_tips_awaiting_payment(weeks_early)
donations_not_fundable = (
donation_groups['no_provider'] +
Expand Down