V40-V43: band umur vote (BARU/VALID/KADALUARSA, scan simpan semua umur) → REVOTE = VALID langsung (V42) → tag mint 1-hari + badge VOTE ULANG SEGERA (V43) ; klaim recovery jendela lewat + parse respons dict rows (B7/B8) ; backend mysql test_mariadb ; oracle test_dashboard/distribute/get_voters/mariadb ; images web/scan/dist/claim rebuild + push
This commit is contained in:
1 parent
af9a0291b9
commit
81ec6bdfe7
17 files changed
+914
-148
No files matched your search
+58
-8
@@ -12,7 +12,7 @@ import sqlite3
|
||||
import sys
|
||||
import tempfile
|
||||
from contextlib import redirect_stdout
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from decimal import Decimal
|
||||
|
||||
import db
|
||||
@@ -55,6 +55,20 @@ def make_voters_db(path, rows):
|
||||
'VALUES (?, ?, ?, ?, ?)',
|
||||
rows,
|
||||
)
|
||||
# V42: distribusi LEFT JOIN voter_first_seen — tabel harus ada.
|
||||
conn.execute('CREATE TABLE IF NOT EXISTS voter_first_seen ('
|
||||
'owner TEXT PRIMARY KEY, first_seen_at TEXT NOT NULL)')
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
def make_first_seen(path, rows):
|
||||
"""V42: isi tabel voter_first_seen (owner, first_seen_at)."""
|
||||
conn = sqlite3.connect(path)
|
||||
conn.execute('CREATE TABLE IF NOT EXISTS voter_first_seen ('
|
||||
'owner TEXT PRIMARY KEY, first_seen_at TEXT NOT NULL)')
|
||||
conn.executemany('INSERT OR IGNORE INTO voter_first_seen '
|
||||
'(owner, first_seen_at) VALUES (?, ?)', rows)
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
@@ -68,6 +82,9 @@ def main():
|
||||
tmp = tempfile.mkdtemp()
|
||||
db.DB_PATH = os.path.join(tmp, 'test.db')
|
||||
_orig_query = db.query
|
||||
# V40: stempel last_vote SEJAK SEKARANG (relatif) agar umur jatuh di band
|
||||
# VALID (3..28 hari) — stempel hardcode berumur <3 hari justru dibuang.
|
||||
fresh = (datetime.now() - timedelta(days=5)).isoformat(timespec='seconds')
|
||||
|
||||
# Oracle: Telegram ⊥ boleh mengirim nyata — nonaktifkan dulu, dipakai lagi §V30
|
||||
_tg_token = telegram.TELEGRAM_BOT_TOKEN
|
||||
@@ -109,7 +126,7 @@ def main():
|
||||
|
||||
# ————— V26: dry-run — rencana tanpa tanda tangan / tanpa tulis DB —————
|
||||
make_voters_db(db.DB_PATH, [('aaa1', '1.0', 1200.0, '2026-08-05T00:00:00',
|
||||
'2026-08-05T00:00:00')])
|
||||
fresh)])
|
||||
dist.fetch_balance = lambda: Decimal('100.0000')
|
||||
dist.BP_PRIVATE_KEY = ''
|
||||
buf = io.StringIO()
|
||||
@@ -133,7 +150,7 @@ def main():
|
||||
check('V25 pemilih kosong → no-op', rc == 0 and 'no-op' in buf.getvalue())
|
||||
|
||||
make_voters_db(db.DB_PATH, [('aaa1', '1.0', 1200.0, '2026-08-05T00:00:00',
|
||||
'2026-08-05T00:00:00')])
|
||||
fresh)])
|
||||
dist.fetch_balance = lambda: Decimal('0.0000')
|
||||
db.query = _orig_query
|
||||
buf = io.StringIO()
|
||||
@@ -152,9 +169,9 @@ def main():
|
||||
|
||||
# ————— V21/V23/V24: run nyata — pending→sent, memo per run —————
|
||||
make_voters_db(db.DB_PATH, [('aaa1', '1.0', 300.0, '2026-08-05T00:00:00',
|
||||
'2026-08-05T00:00:00'),
|
||||
fresh),
|
||||
('bbb2', '1.0', 700.0, '2026-08-05T00:00:00',
|
||||
'2026-08-05T00:00:00')])
|
||||
fresh)])
|
||||
dist.fetch_balance = lambda: Decimal('100.0000')
|
||||
dist.BP_PRIVATE_KEY = '5Ktest'
|
||||
dist.DISTRIBUTE_MAX_ATTEMPTS = 3
|
||||
@@ -231,7 +248,7 @@ def main():
|
||||
|
||||
# ————— V35: kill-switch DISTRIBUTE_ENABLED=false → no-op —————
|
||||
make_voters_db(db.DB_PATH, [('aaa1', '1.0', 1200.0, '2026-08-05T00:00:00',
|
||||
'2026-08-05T00:00:00')])
|
||||
fresh)])
|
||||
db.query = _orig_query
|
||||
dist.fetch_balance = lambda: Decimal('100.0000')
|
||||
_orig_record_run = db.record_run
|
||||
@@ -260,6 +277,39 @@ def main():
|
||||
db.record_run = _orig_record_run
|
||||
dist.build_signed_transfer = _orig_build
|
||||
|
||||
# ————— V40/V42: reward utk vote matang+segar; REVOTE langsung VALID —————
|
||||
def _iso(days_ago):
|
||||
return (datetime.now() - timedelta(days=days_ago)).isoformat(timespec='seconds')
|
||||
|
||||
make_voters_db(db.DB_PATH, [
|
||||
('new1', '1.0', 1200.0, fresh, _iso(1)), # BARU — belum matang
|
||||
('mid5', '1.0', 1200.0, fresh, _iso(5)), # VALID — matang+segar
|
||||
('rev7', '1.0', 1200.0, fresh, _iso(1)), # REVOTE — pemilih lama revote
|
||||
('old9', '1.0', 1200.0, fresh, _iso(40)), # basi — lewat 28 hari
|
||||
])
|
||||
# V42: first_seen — new1 baru (umur 1 hr), rev7 lama (first_seen 60 hr lalu).
|
||||
make_first_seen(db.DB_PATH, [('new1', _iso(1)), ('rev7', _iso(60))])
|
||||
db.query = _orig_query
|
||||
dist.fetch_balance = lambda: Decimal('300.0000')
|
||||
dist.BP_PRIVATE_KEY = '5Ktest'
|
||||
dist.DISTRIBUTE_MAX_ATTEMPTS = 3
|
||||
signed_to = []
|
||||
dist.build_signed_transfer = (lambda to, amount, memo:
|
||||
signed_to.append(to) or FakeSigned('txV' + to))
|
||||
calls['runs'] = []
|
||||
db.record_run = lambda *a, **k: calls['runs'].append(a) or 7
|
||||
with redirect_stdout(io.StringIO()):
|
||||
dist.run_distribution(dry_run=False)
|
||||
check('V42 REVOTE (umur 1 hr, first_seen lama) LANGSUNG dibayar',
|
||||
'rev7' in signed_to)
|
||||
check('V40 pemilih baru (umur 1 hr) ⊥ dibayar', 'new1' not in signed_to)
|
||||
check('V40 basi (umur 40 hr) ⊥ dibayar', 'old9' not in signed_to)
|
||||
check('V40 matang+segar (umur 5 hr) dibayar', 'mid5' in signed_to)
|
||||
check('V40/V42 tepat 2 terkirim (mid5 + rev7)',
|
||||
sorted(signed_to) == ['mid5', 'rev7'])
|
||||
db.record_run = _orig_record_run
|
||||
dist.build_signed_transfer = _orig_build
|
||||
|
||||
# ————— V30: notifikasi Telegram — dua kanal, komunitas brief/internal detail —————
|
||||
tg = {'posts': []}
|
||||
|
||||
@@ -281,9 +331,9 @@ def main():
|
||||
|
||||
# dry-run → ⊥ notif Telegram
|
||||
make_voters_db(db.DB_PATH, [('aaa1', '1.0', 300.0, '2026-08-05T00:00:00',
|
||||
'2026-08-05T00:00:00'),
|
||||
fresh),
|
||||
('bbb2', '1.0', 700.0, '2026-08-05T00:00:00',
|
||||
'2026-08-05T00:00:00')])
|
||||
fresh)])
|
||||
db.query = _orig_query
|
||||
dist.fetch_balance = lambda: Decimal('100.0000')
|
||||
dist.BP_PRIVATE_KEY = '5Ktest'
|
||||
|
||||
Reference in new issue
Block a user