Member spamming implementation

master
informatic 2017-05-05 23:17:22 +02:00
parent 06e25b3ad0
commit 5d3a14b8b2
6 changed files with 129 additions and 14 deletions

View File

@ -104,6 +104,18 @@ import webapp.api
def unauthorized():
return redirect('/login')
@app.template_filter('inflect')
def inflect(v, one, two, five):
num = abs(v)
if num == 0:
return '%d %s' % (v, five)
elif num == 1:
return '%d %s' % (v, one)
elif num <= 4:
return '%d %s' % (v, two)
else:
return '%d %s' % (v, five)
def init():
pass

View File

@ -23,6 +23,7 @@
# POSSIBILITY OF SUCH DAMAGE.
from wtforms import Form, BooleanField, TextField, PasswordField, SelectMultipleField, FormField, validators, widgets
from flask_wtf import Form as FlaskForm
class MultiCheckboxField(SelectMultipleField):
widget = widgets.ListWidget(prefix_label=False)
@ -43,3 +44,6 @@ class LDAPSyncForm(Form):
starving_to_add = MultiCheckboxField("Starving to add", choices=[])
starving_to_remove = MultiCheckboxField("Starving to remove", choices=[])
class SpamForm(FlaskForm):
dry_run = BooleanField("Dry run")
members = MultiCheckboxField("Members to spam", coerce=int)

View File

@ -226,7 +226,13 @@ class Member(db.Model):
previous_scalar = self._yearmonth_scalar(previous_transfer)
unpaid_months += (now - previous_scalar)
fees = {
'starving': 50,
'fatty': 100,
}
status['months_due'] = unpaid_months
status['money_due'] = fees.get(self.type, 0) * unpaid_months
status['payment_status'] = PaymentStatus.okay.value if unpaid_months < 4 else PaymentStatus.unpaid.value
status['last_paid'] = most_recent_transfer
status['left'] = not active_payment
@ -333,6 +339,9 @@ class Member(db.Model):
self.join_month = now_date.month
self.payment_policy = PaymentPolicy.normal.value
def __unicode__(self):
return self.username
class Transfer(db.Model):
id = db.Column(db.Integer, primary_key=True)

View File

@ -0,0 +1,19 @@
{% extends "root.html" %}
{% set active_page = "admin" %}
{% block title %}Admin LDAP Sync{% endblock %}
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-12">
<form method="post" action="/admin/spam/">
<button>Spam</button>
{{ form.dry_run() }} {{ form.dry_run.label }}
{{ form.hidden_tag() }}
{{ form.members() }}
</form>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,35 @@
Siemasz {{ member.username }},
automatycznie wygenerowałem raport ze stanu składek dla Twojego konta.
Oto stan na dzień {{ now.strftime('%d/%m/%Y') }}:
{% if status['months_due'] > 0 -%}
Jesteś {{ status['months_due']|inflect('składkę', 'składki', 'składek') }}
{%- if status['money_due'] %} ({{ status['money_due'] / 100 }} PLN){% endif %} do tyłu. Kiepsko.
{% elif status['months_due'] == 0 -%}
Jesteś na bieżąco ze składkami. Hura!
{% else -%}
Jesteś do przodu ze składkami. Świetnie!
{% endif -%}
{% if status['months_due'] > 2 %}
Zgodnie z regulaminem HS, trzymiesięczna zaległość w składkach oznacza
automatyczne wykreślenie z listy członków i usunięcie karty z zamka.
Masz tydzień na uregulowanie składki od daty wysłania tego emaila.
{% endif %}
Oto szczegółowe informacje o Twoich ostatnich wpłatach:
{% for t in transfers %}
- opłata za {{ t.month }}/{{ t.year }}, pokryta przelewem za {{
'%.02f'|format(t.transfer.amount/100) }} PLN w dniu {{ t.transfer.date.strftime('%d/%m/%Y') }}
{% endfor %}
Jeśli coś się nie zgadza, odpisz na tego mejla z pretensjami - wiadomość trafi
do naszego białkowego skarbnika który postara się ustalić, co poszło źle.
Jednocześnie przypominam, że trzymiesięczna zaległość w płaceniu oznacza
wykreślenie z listy członków - automatyczną!
xoxoxoxo,
Hackerspace'owy Kasownik
--
„100 linii pythona!” - enki o skrypcie do składek

View File

@ -104,20 +104,6 @@ def admin_index():
inactive_members=inactive_members)
@app.route("/admin/spam", methods=["POST", "GET"])
@admin_required
@login_required
def admin_spam():
#members = [m.get_status() for m in models.Member.get_members(True)]
form = forms.SPAMForm(request.form)
form.process(request.form)
if request.method == "POST" and form.validate():
pass
return render_template("admin_spam.html", form=form)
@app.route("/admin/ldapsync", methods=["POST", "GET"])
@admin_required
@login_required
@ -304,6 +290,56 @@ def match_user_transfer():
return render_template("match_user_transfer.html", member=member, transfer=transfer)
@app.route("/admin/spam/", methods=["GET", "POST"])
@login_required
@admin_required
def sendspam():
now = datetime.datetime.now()
members = models.Member.query.filter_by(
active=True, payment_policy=models.PaymentPolicy.normal.value).all()
form = forms.SpamForm()
form.members.choices = [(member.id, member) for member in members]
form.members.default = [member.id for member in members]
form.process(request.form)
if request.method == 'POST' and form.validate():
spam = []
for member in members:
if member.id not in form.members.data:
continue
content = render_template(
'mailing/due.txt',
member=member,
status=member.get_status(),
transfers=member.transfers[:5],
now=now)
# Just ignore empty messages
if not content.strip():
continue
msg = MIMEText(content, "plain", "utf-8")
msg["From"] = "Faszysta Hackerspace'owy <fascist@hackerspace.pl>"
msg["Subject"] = "Stan składek na dzień %s" % now.strftime("%d/%m/%Y")
msg["To"] = member.get_contact_email()
spam.append(msg)
if form.dry_run.data:
readable = [
msg.as_string().split('\n\n')[0] + '\n\n' + msg.get_payload(decode=True) for msg in spam]
return Response('\n====\n'.join(readable), mimetype='text/text')
for msg in spam:
p = Popen(["/usr/sbin/sendmail", "-t"], stdin=PIPE)
p.communicate(msg.as_string())
flash('%d messages sent!' % len(spam))
return redirect(url_for('admin_index'))
return render_template('admin_spam.html', form=form)
@app.route("/login", methods=["POST", "GET"])
def login():
form = forms.LoginForm(request.form)