delay pledge notifications until payment becomes possible
This commit is contained in:
parent
1ce6f0bb75
commit
ae098df9b8
@ -118,19 +118,21 @@ elif env.clean_assets:
|
||||
|
||||
conf = website.app_conf
|
||||
if conf:
|
||||
intervals = conf.cron_intervals
|
||||
cron = Cron(website)
|
||||
cron(conf.check_db_every, website.db.self_check, True)
|
||||
cron(conf.dequeue_emails_every, Participant.dequeue_emails, True)
|
||||
cron(conf.send_newsletters_every, Participant.send_newsletters, True)
|
||||
cron(conf.refetch_elsewhere_data_every, refetch_elsewhere_data, True)
|
||||
cron(conf.refetch_repos_every, refetch_repos, True)
|
||||
cron(intervals['check_db'], website.db.self_check, True)
|
||||
cron(intervals['dequeue_emails'], Participant.dequeue_emails, True)
|
||||
cron(intervals['send_newsletters'], Participant.send_newsletters, True)
|
||||
cron(intervals['refetch_elsewhere_data'], refetch_elsewhere_data, True)
|
||||
cron(intervals['refetch_repos'], refetch_repos, True)
|
||||
cron(Weekly(weekday=3, hour=2), create_payday_issue, True)
|
||||
cron(conf.clean_up_counters_every, website.db.clean_up_counters, True)
|
||||
cron(intervals['clean_up_counters'], website.db.clean_up_counters, True)
|
||||
cron(Daily(hour=16), lambda: fetch_currency_exchange_rates(website.db), True)
|
||||
cron(Daily(hour=17), Payday.update_cached_amounts, True)
|
||||
cron(Daily(hour=8), clean_up_closed_accounts, True)
|
||||
cron(intervals['notify_patrons'], Participant.notify_patrons, True)
|
||||
if conf.ses_feedback_queue_url:
|
||||
cron(conf.fetch_email_bounces_every, handle_email_bounces, True)
|
||||
cron(intervals['fetch_email_bounces'], handle_email_bounces, True)
|
||||
|
||||
cron('once', website.cryptograph.rotate_stored_data, True)
|
||||
|
||||
|
@ -12,6 +12,7 @@ import uuid
|
||||
|
||||
import aspen_jinja2_renderer
|
||||
from cached_property import cached_property
|
||||
from dateutil.parser import parse as parse_date
|
||||
from html2text import html2text
|
||||
import mangopay
|
||||
from markupsafe import escape as htmlescape
|
||||
@ -1144,7 +1145,7 @@ class Participant(Model, MixinTeam):
|
||||
# Notifications
|
||||
# =============
|
||||
|
||||
def notify(self, event, force_email=False, email=True, web=True, **context):
|
||||
def notify(self, event, force_email=False, email=True, web=True, idem_key=None, **context):
|
||||
if email and not force_email:
|
||||
bit = EVENTS.get(event.split('~', 1)[0]).bit
|
||||
email = self.email_notif_bits & bit > 0
|
||||
@ -1152,8 +1153,8 @@ class Participant(Model, MixinTeam):
|
||||
context = serialize(context)
|
||||
n_id = self.db.one("""
|
||||
INSERT INTO notifications
|
||||
(participant, event, context, web, email)
|
||||
VALUES (%(p_id)s, %(event)s, %(context)s, %(web)s, %(email)s)
|
||||
(participant, event, context, web, email, idem_key)
|
||||
VALUES (%(p_id)s, %(event)s, %(context)s, %(web)s, %(email)s, %(idem_key)s)
|
||||
RETURNING id;
|
||||
""", locals())
|
||||
if not web:
|
||||
@ -1280,14 +1281,50 @@ class Participant(Model, MixinTeam):
|
||||
website.tell_sentry(e, state)
|
||||
return r
|
||||
|
||||
def notify_patrons(self, elsewhere, tips):
|
||||
@classmethod
|
||||
def notify_patrons(cls):
|
||||
grouped_tips = cls.db.all("""
|
||||
SELECT event.payload AS takeover, json_agg(tip) AS tips
|
||||
FROM current_tips tip
|
||||
JOIN participants tippee ON tippee.id = tip.tippee
|
||||
JOIN events event ON event.participant = tip.tippee
|
||||
AND event.type = 'take-over'
|
||||
WHERE tip.renewal_mode > 0
|
||||
AND tip.paid_in_advance IS NULL
|
||||
AND tippee.payment_providers > 0
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM tips old_tip
|
||||
WHERE old_tip.tipper = tip.tipper
|
||||
AND old_tip.tippee = (event.payload->>'owner')::int
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM notifications n
|
||||
WHERE n.participant = tip.tipper
|
||||
AND n.event = 'pledgee_joined~v2'
|
||||
AND n.idem_key = event.payload->>'owner'
|
||||
)
|
||||
GROUP BY event.payload
|
||||
""")
|
||||
for takeover, tips in grouped_tips:
|
||||
elsewhere = AccountElsewhere._from_thing(
|
||||
'user_id',
|
||||
takeover['platform'], takeover['user_id'], takeover['domain']
|
||||
)
|
||||
cls._notify_patrons(elsewhere, tips)
|
||||
|
||||
@classmethod
|
||||
def _notify_patrons(cls, elsewhere, tips):
|
||||
assert elsewhere.participant.payment_providers > 0
|
||||
for t in tips:
|
||||
Participant.from_id(t.tipper).notify(
|
||||
Participant.from_id(t['tipper']).notify(
|
||||
'pledgee_joined~v2',
|
||||
idem_key=str(elsewhere.participant.id),
|
||||
user_name=elsewhere.user_name,
|
||||
platform=elsewhere.platform_data.display_name,
|
||||
pledge_date=t.ctime.date(),
|
||||
periodic_amount=t.periodic_amount,
|
||||
pledge_date=parse_date(t['ctime']).date(),
|
||||
periodic_amount=Money(**t['periodic_amount']),
|
||||
elsewhere_profile_url=elsewhere.html_url,
|
||||
join_time=elsewhere.participant.join_time,
|
||||
liberapay_profile_url=elsewhere.participant.url(),
|
||||
@ -2487,9 +2524,6 @@ class Participant(Model, MixinTeam):
|
||||
platform=platform, domain=domain, user_id=user_id, owner=other.id
|
||||
))
|
||||
|
||||
if old_tips:
|
||||
self.notify_patrons(elsewhere, tips=old_tips)
|
||||
|
||||
self.update_avatar()
|
||||
|
||||
# Note: the order matters here, receiving needs to be updated before giving
|
||||
|
@ -207,14 +207,11 @@ class AppConf(object):
|
||||
bountysource_callback=str,
|
||||
bountysource_id=None.__class__,
|
||||
bountysource_secret=str,
|
||||
check_db_every=int,
|
||||
check_email_domains=bool,
|
||||
clean_up_counters_every=int,
|
||||
dequeue_emails_every=int,
|
||||
cron_intervals=dict,
|
||||
facebook_callback=str,
|
||||
facebook_id=str,
|
||||
facebook_secret=str,
|
||||
fetch_email_bounces_every=int,
|
||||
github_callback=str,
|
||||
github_id=str,
|
||||
github_secret=str,
|
||||
@ -243,8 +240,6 @@ class AppConf(object):
|
||||
paypal_domain=str,
|
||||
paypal_id=str,
|
||||
paypal_secret=str,
|
||||
refetch_elsewhere_data_every=int,
|
||||
refetch_repos_every=int,
|
||||
s3_endpoint=str,
|
||||
s3_public_access_key=str,
|
||||
s3_secret_key=str,
|
||||
@ -252,7 +247,6 @@ class AppConf(object):
|
||||
s3_payday_logs_bucket=str,
|
||||
ses_feedback_queue_url=str,
|
||||
ses_region=str,
|
||||
send_newsletters_every=int,
|
||||
sepa_creditor_identifier=str,
|
||||
show_sandbox_warning=bool,
|
||||
socket_timeout=float,
|
||||
|
@ -22,6 +22,11 @@ echo "Applying sql/recreate-schema.sql ... "
|
||||
echo
|
||||
psql "$DATABASE_URL" < sql/recreate-schema.sql
|
||||
|
||||
echo "=============================================================================="
|
||||
echo "Applying sql/app-conf-defaults.sql ... "
|
||||
echo
|
||||
psql "$DATABASE_URL" < sql/app-conf-defaults.sql
|
||||
|
||||
echo "=============================================================================="
|
||||
echo "Looking for sql/branch.sql ..."
|
||||
echo
|
||||
@ -33,11 +38,6 @@ else
|
||||
echo "include schema changes with your pull request."
|
||||
fi
|
||||
|
||||
echo "=============================================================================="
|
||||
echo "Applying sql/app-conf-defaults.sql ... "
|
||||
echo
|
||||
psql "$DATABASE_URL" < sql/app-conf-defaults.sql
|
||||
|
||||
if [ "${1-}" = "test" ]; then
|
||||
echo "=============================================================================="
|
||||
echo "Applying sql/app-conf-tests.sql ... "
|
||||
|
@ -10,14 +10,21 @@ INSERT INTO app_conf (key, value) VALUES
|
||||
('bountysource_callback', '"http://127.0.0.1:8339/on/bountysource/associate"'::jsonb),
|
||||
('bountysource_id', 'null'::jsonb),
|
||||
('bountysource_secret', '""'::jsonb),
|
||||
('check_db_every', '600'::jsonb),
|
||||
('check_email_domains', 'true'::jsonb),
|
||||
('clean_up_counters_every', '3600'::jsonb),
|
||||
('dequeue_emails_every', '60'::jsonb),
|
||||
('cron_intervals', jsonb_build_object(
|
||||
'check_db', 600,
|
||||
'clean_up_counters', 3600,
|
||||
'dequeue_emails', 60,
|
||||
'fetch_email_bounces', 60,
|
||||
'notify_patrons', 120,
|
||||
'refetch_elsewhere_data', 120,
|
||||
'refetch_repos', 60,
|
||||
'send_newsletters', 60
|
||||
)),
|
||||
('facebook_callback', '"http://localhost:8339/on/facebook/associate"'::jsonb),
|
||||
('facebook_id', '"1418954898427187"'::jsonb),
|
||||
('facebook_secret', '"3bcb5dc6ce821e5202870c1e6ef5bbc4"'::jsonb),
|
||||
('fetch_email_bounces_every', '60'::jsonb),
|
||||
('github_callback', '"http://127.0.0.1:8339/on/github/associate"'::jsonb),
|
||||
('github_id', '"18891d01e40e5aef93b8"'::jsonb),
|
||||
('github_secret', '"46f75669895e96029d57b64832d6f2c8e6291a0e"'::jsonb),
|
||||
@ -46,14 +53,11 @@ INSERT INTO app_conf (key, value) VALUES
|
||||
('paypal_domain', '"sandbox.paypal.com"'::jsonb),
|
||||
('paypal_id', '"ASTH9rn8IosjJcEwNYqV2KeHadB6O8MKVP7fL7kXeSuOml0ei77FRYU5E1thEF-1cT3Wp3Ibo0jXIbul"'::jsonb),
|
||||
('paypal_secret', '"EAStyBaGBZk9MVBGrI_eb4O4iEVFPZcRoIsbKDwv28wxLzroLDKYwCnjZfr_jDoZyDB5epQVrjZraoFY"'::jsonb),
|
||||
('refetch_elsewhere_data_every', '120'::jsonb),
|
||||
('refetch_repos_every', '60'::jsonb),
|
||||
('s3_endpoint', '""'::jsonb),
|
||||
('s3_payday_logs_bucket', '""'::jsonb),
|
||||
('s3_public_access_key', '""'::jsonb),
|
||||
('s3_secret_key', '""'::jsonb),
|
||||
('s3_region', '"eu-west-1"'::jsonb),
|
||||
('send_newsletters_every', '60'::jsonb),
|
||||
('sepa_creditor_identifier', '"FR65ZZZ858BF1"'::jsonb),
|
||||
('ses_feedback_queue_url', '""'::jsonb),
|
||||
('show_sandbox_warning', 'true'::jsonb),
|
||||
|
22
sql/branch.sql
Normal file
22
sql/branch.sql
Normal file
@ -0,0 +1,22 @@
|
||||
ALTER TABLE notifications ADD COLUMN idem_key text;
|
||||
|
||||
INSERT INTO app_conf (key, value) VALUES
|
||||
('cron_intervals', jsonb_build_object(
|
||||
'check_db', (SELECT value::text::int FROM app_conf WHERE key = 'check_db_every'),
|
||||
'clean_up_counters', (SELECT value::text::int FROM app_conf WHERE key = 'clean_up_counters_every'),
|
||||
'dequeue_emails', (SELECT value::text::int FROM app_conf WHERE key = 'dequeue_emails_every'),
|
||||
'fetch_email_bounces', (SELECT value::text::int FROM app_conf WHERE key = 'fetch_email_bounces_every'),
|
||||
'notify_patrons', 120,
|
||||
'refetch_elsewhere_data', (SELECT value::text::int FROM app_conf WHERE key = 'refetch_elsewhere_data_every'),
|
||||
'refetch_repos', (SELECT value::text::int FROM app_conf WHERE key = 'refetch_repos_every'),
|
||||
'send_newsletters', (SELECT value::text::int FROM app_conf WHERE key = 'send_newsletters_every')
|
||||
))
|
||||
ON CONFLICT (key) DO UPDATE SET value = excluded.value;
|
||||
|
||||
SELECT 'after deployment';
|
||||
|
||||
DELETE FROM app_conf WHERE key IN (
|
||||
'check_db_every', 'clean_up_counters_every', 'dequeue_emails_every',
|
||||
'fetch_email_bounces_every', 'refetch_elsewhere_data_every',
|
||||
'refetch_repos_every', 'send_newsletters_every'
|
||||
);
|
Loading…
x
Reference in New Issue
Block a user