finished #23 code. rw city page info display. Unsubscribe = Delete
This commit is contained in:
parent
c7aa87cb3b
commit
96329e968e
|
@ -27,13 +27,11 @@ class Mailbot(Bot):
|
||||||
# post/boost Report object
|
# post/boost Report object
|
||||||
def post(self, user, report):
|
def post(self, user, report):
|
||||||
recipients = user.get_mailinglist()
|
recipients = user.get_mailinglist()
|
||||||
print(recipients) # debug
|
|
||||||
for rec in recipients:
|
for rec in recipients:
|
||||||
rec = rec[0]
|
rec = rec[0]
|
||||||
unsubscribe_text = "\n_______\nYou don't want to receive those messages? Unsubscribe with this link: "
|
unsubscribe_text = "\n_______\nYou don't want to receive those messages? Unsubscribe with this link: "
|
||||||
body = report.text + unsubscribe_text + config['web']['host'] + "/city/mail/unsubscribe/" \
|
body = report.text + unsubscribe_text + config['web']['host'] + "/city/mail/unsubscribe/" \
|
||||||
+ db.mail_subscription_token(rec, user.get_city())
|
+ db.mail_subscription_token(rec, user.get_city())
|
||||||
print(body) # debug
|
|
||||||
if report.author != rec:
|
if report.author != rec:
|
||||||
try:
|
try:
|
||||||
sendmail.sendmail(rec, "Ticketfrei " + user.get_city() +
|
sendmail.sendmail(rec, "Ticketfrei " + user.get_city() +
|
||||||
|
|
7
db.py
7
db.py
|
@ -119,7 +119,6 @@ class DB(object):
|
||||||
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
|
||||||
user_id INTEGER,
|
user_id INTEGER,
|
||||||
email TEXT,
|
email TEXT,
|
||||||
active INTEGER,
|
|
||||||
FOREIGN KEY(user_id) REFERENCES user(id)
|
FOREIGN KEY(user_id) REFERENCES user(id)
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS seen_mail (
|
CREATE TABLE IF NOT EXISTS seen_mail (
|
||||||
|
@ -133,6 +132,7 @@ class DB(object):
|
||||||
user_id INTEGER,
|
user_id INTEGER,
|
||||||
city TEXT,
|
city TEXT,
|
||||||
markdown TEXT,
|
markdown TEXT,
|
||||||
|
mail_md TEXT,
|
||||||
masto_link TEXT,
|
masto_link TEXT,
|
||||||
twit_link TEXT,
|
twit_link TEXT,
|
||||||
FOREIGN KEY(user_id) REFERENCES user(id),
|
FOREIGN KEY(user_id) REFERENCES user(id),
|
||||||
|
@ -264,13 +264,14 @@ u\d\d?
|
||||||
return User(uid)
|
return User(uid)
|
||||||
|
|
||||||
def user_facing_properties(self, city):
|
def user_facing_properties(self, city):
|
||||||
self.execute("""SELECT city, markdown, masto_link, twit_link
|
self.execute("""SELECT city, markdown, mail_md, masto_link, twit_link
|
||||||
FROM cities
|
FROM cities
|
||||||
WHERE city=?;""", (city, ))
|
WHERE city=?;""", (city, ))
|
||||||
try:
|
try:
|
||||||
city, markdown, masto_link, twit_link = self.cur.fetchone()
|
city, markdown, mail_md, masto_link, twit_link = self.cur.fetchone()
|
||||||
return dict(city=city,
|
return dict(city=city,
|
||||||
markdown=markdown,
|
markdown=markdown,
|
||||||
|
mail_md=mail_md,
|
||||||
masto_link=masto_link,
|
masto_link=masto_link,
|
||||||
twit_link=twit_link,
|
twit_link=twit_link,
|
||||||
mailinglist=city + "@" + config["web"]["host"])
|
mailinglist=city + "@" + config["web"]["host"])
|
||||||
|
|
29
frontend.py
29
frontend.py
|
@ -9,6 +9,7 @@ from sendmail import sendmail
|
||||||
from session import SessionPlugin
|
from session import SessionPlugin
|
||||||
from mastodon import Mastodon
|
from mastodon import Mastodon
|
||||||
|
|
||||||
|
|
||||||
def url(route):
|
def url(route):
|
||||||
return '%s://%s/%s' % (
|
return '%s://%s/%s' % (
|
||||||
request.urlparts.scheme,
|
request.urlparts.scheme,
|
||||||
|
@ -78,13 +79,14 @@ def login_post():
|
||||||
|
|
||||||
|
|
||||||
@get('/city/<city>')
|
@get('/city/<city>')
|
||||||
@view('template/city.tpl')
|
def city_page(city, info=None):
|
||||||
def city_page(city):
|
|
||||||
citydict = db.user_facing_properties(city)
|
citydict = db.user_facing_properties(city)
|
||||||
if citydict is not None:
|
if citydict is not None:
|
||||||
return citydict
|
citydict['info'] = info
|
||||||
redirect('/')
|
return bottle.template('template/city.tpl', **citydict)
|
||||||
return dict(info='There is no Ticketfrei bot in your city yet. Create one yourself!')
|
return bottle.template('template/propaganda.tpl',
|
||||||
|
**dict(info='There is no Ticketfrei bot in your city'
|
||||||
|
' yet. Create one yourself!'))
|
||||||
|
|
||||||
|
|
||||||
@get('/city/mail/<city>')
|
@get('/city/mail/<city>')
|
||||||
|
@ -102,25 +104,26 @@ def subscribe_mail(city):
|
||||||
print(confirm_link) # only for local testing
|
print(confirm_link) # only for local testing
|
||||||
# send mail with code to email
|
# send mail with code to email
|
||||||
sendmail(email, "Subscribe to Ticketfrei " + city + " Mail Notifications",
|
sendmail(email, "Subscribe to Ticketfrei " + city + " Mail Notifications",
|
||||||
body="To subscribe to the mail notifications for Ticketfrei " + city + ", click on this link: " + token)
|
body="To subscribe to the mail notifications for Ticketfrei " +
|
||||||
|
city + ", click on this link: " + token)
|
||||||
|
return city_page(city, info="Thanks! You will receive a confirmation mail.")
|
||||||
|
|
||||||
|
|
||||||
@get('/city/mail/confirm/<token>')
|
@get('/city/mail/confirm/<token>')
|
||||||
@view('template/city.tpl')
|
|
||||||
def confirm_subscribe(token):
|
def confirm_subscribe(token):
|
||||||
email, city = db.confirm_subscription(token)
|
email, city = db.confirm_subscription(token)
|
||||||
user = db.by_city(city)
|
user = db.by_city(city)
|
||||||
user.add_subscriber(email)
|
user.add_subscriber(email)
|
||||||
redirect('/city/' + city)
|
return city_page(city, info="Thanks for subscribing to mail notifications!")
|
||||||
|
|
||||||
|
|
||||||
@get('/city/mail/unsubscribe/<token>')
|
@get('/city/mail/unsubscribe/<token>')
|
||||||
@view('template/mail.tpl')
|
|
||||||
def unsubscribe(token):
|
def unsubscribe(token):
|
||||||
email, city = db.confirm_subscription(token)
|
email, city = db.confirm_subscription(token)
|
||||||
user = db.by_city(city)
|
user = db.by_city(city)
|
||||||
user.remove_subscriber(email)
|
user.remove_subscriber(email)
|
||||||
redirect('/city/' + city)
|
return city_page(city, info="You successfully unsubscribed " + email +
|
||||||
|
" from the mail notifications.")
|
||||||
|
|
||||||
|
|
||||||
@get('/settings')
|
@get('/settings')
|
||||||
|
@ -136,6 +139,12 @@ def update_markdown(user):
|
||||||
return user.state()
|
return user.state()
|
||||||
|
|
||||||
|
|
||||||
|
@post('/settings/mail_md')
|
||||||
|
@view('template/settings.tpl')
|
||||||
|
def update_mail_md(user):
|
||||||
|
user.set_mail_md(request.forms['mail_md'])
|
||||||
|
return user.state()
|
||||||
|
|
||||||
@post('/settings/goodlist')
|
@post('/settings/goodlist')
|
||||||
@view('template/settings.tpl')
|
@view('template/settings.tpl')
|
||||||
def update_trigger_patterns(user):
|
def update_trigger_patterns(user):
|
||||||
|
|
|
@ -6,4 +6,12 @@ import markdown as md
|
||||||
html = md.markdown(markdown)
|
html = md.markdown(markdown)
|
||||||
%>
|
%>
|
||||||
|
|
||||||
|
% if info is not None:
|
||||||
|
<div class="ui-widget">
|
||||||
|
<div class="ui-state-highlight ui-corner-all" style="padding: 0.7em;">
|
||||||
|
<p><span class="ui-icon ui-icon-info" style="float: left; margin-right: .3em;"></span>{{!info}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
% end
|
||||||
|
|
||||||
{{!html}}
|
{{!html}}
|
||||||
|
|
|
@ -3,13 +3,14 @@
|
||||||
<%
|
<%
|
||||||
import markdown as md
|
import markdown as md
|
||||||
|
|
||||||
html = md.markdown(markdown)
|
html = md.markdown(mail_md)
|
||||||
%>
|
%>
|
||||||
|
|
||||||
|
{{!html}}
|
||||||
|
|
||||||
<form action="/city/mail/submit/{{!city}}" method="post">
|
<form action="/city/mail/submit/{{!city}}" method="post">
|
||||||
<input type="text" name="mailaddress" placeholder="E-Mail address" id="mailaddress">
|
<input type="text" name="mailaddress" placeholder="E-Mail address" id="mailaddress">
|
||||||
<input name='confirm' value='Subscribe to E-Mail notifications' type='submit'/>
|
<input name='confirm' value='Subscribe to E-Mail notifications' type='submit'/>
|
||||||
</form>
|
</form>
|
||||||
|
<br>
|
||||||
|
<p style="text-align: center;"><a href="/city/{{!city}}">Back to Ticketfrei {{!city}} overview</a></p>
|
||||||
{{!html}}
|
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
% rebase('template/wrapper.tpl')
|
% rebase('template/wrapper.tpl')
|
||||||
|
% if defined('info'):
|
||||||
|
<div class="ui-widget">
|
||||||
|
<div class="ui-state-highlight ui-corner-all" style="padding: 0.7em;">
|
||||||
|
<p><span class="ui-icon ui-icon-info" style="float: left; margin-right: .3em;"></span>{{!info}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br>
|
||||||
|
% end
|
||||||
% include('template/login-plain.tpl')
|
% include('template/login-plain.tpl')
|
||||||
<h1>Features</h1>
|
<h1>Features</h1>
|
||||||
<p>
|
<p>
|
||||||
|
@ -42,17 +50,17 @@
|
||||||
reclaim public transportation.
|
reclaim public transportation.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
On short term we want to do this by helping users to avoid
|
On short term we want to do this by helping users to avoid
|
||||||
controllers and fines - on long term by pressuring public
|
controllers and fines - on long term by pressuring public
|
||||||
transportation companies to offer their services free of
|
transportation companies to offer their services free of
|
||||||
charge, financed by the public.
|
charge, financed by the public.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Because with Ticketfrei you're able to use trains and
|
Because with Ticketfrei you're able to use trains and
|
||||||
subways for free anyway. Take part and create a new
|
subways for free anyway. Take part and create a new
|
||||||
understanding of what public transportation should look
|
understanding of what public transportation should look
|
||||||
like!
|
like!
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -87,14 +87,16 @@
|
||||||
<div>
|
<div>
|
||||||
<h2>Edit your city page</h2>
|
<h2>Edit your city page</h2>
|
||||||
<p>
|
<p>
|
||||||
With your bot, we generated you a page, which you can use for promotion: <a href="/city/{{city}}"
|
With your bot, we generated you a page, which you can use for promotion:
|
||||||
target="_blank">Ticketfrei {{city}}</a> You can change what your users will read there, and adjust it to your
|
<a href="/city/{{city}}" target="_blank">Ticketfrei {{city}}</a> You
|
||||||
|
can change what your users will read there, and adjust it to your
|
||||||
needs.
|
needs.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<b>You should definitely adjust the Social Media profile links.</b>
|
<b>You should definitely adjust the Social Media profile links.</b>
|
||||||
Also consider adding this link to the text: <a href="/city/mail/{{city}}" target="_blank">Link to the mail subscription page</a>.
|
Also consider adding this link to the text: <a href="/city/mail/{{city}}"
|
||||||
Your readers can use this to subscribe to mail notifications.
|
target="_blank">Link to the mail subscription page</a>. Your readers
|
||||||
|
can use this to subscribe to mail notifications.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
So this is the default text we suggest:
|
So this is the default text we suggest:
|
||||||
|
@ -105,12 +107,30 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2>Edit your mail subscription page</h2>
|
||||||
|
<p>
|
||||||
|
There is also a page where users can subscribe to mail notifications:
|
||||||
|
<a href="/city/mail/{{city}}" target="_blank">Ticketfrei {{city}}</a>.
|
||||||
|
You can change what your users will read there, and adjust it to your
|
||||||
|
needs.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
So this is the default text we suggest:
|
||||||
|
</p>
|
||||||
|
<form action="/settings/mail_md" method="post">
|
||||||
|
<textarea id="mail_md" rows="20" cols="70" name="mail_md" wrap="physical">{{mail_md}}</textarea>
|
||||||
|
<input name='confirm' value='Save' type='submit'/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h2>Edit your trigger patterns</h2>
|
<h2>Edit your trigger patterns</h2>
|
||||||
<p>
|
<p>
|
||||||
These words have to be contained in a report.
|
These words have to be contained in a report. If none of these
|
||||||
If none of these expressions is in the report, it will be ignored by the bot.
|
expressions is in the report, it will be ignored by the bot. You can
|
||||||
You can use the defaults, or enter some expressions specific to your city and language.
|
use the defaults, or enter some expressions specific to your city and
|
||||||
|
language.
|
||||||
</p>
|
</p>
|
||||||
<form action="/settings/goodlist" method="post">
|
<form action="/settings/goodlist" method="post">
|
||||||
<!-- find a way to display current good list. js which reads from a cookie? template? -->
|
<!-- find a way to display current good list. js which reads from a cookie? template? -->
|
||||||
|
@ -122,9 +142,9 @@
|
||||||
<div>
|
<div>
|
||||||
<h2>Edit the blacklist</h2>
|
<h2>Edit the blacklist</h2>
|
||||||
<p>
|
<p>
|
||||||
These words are not allowed in reports.
|
These words are not allowed in reports. If you encounter spam, you can
|
||||||
If you encounter spam, you can add more here - the bot will ignore reports which use such words.
|
add more here - the bot will ignore reports which use such words.
|
||||||
<!-- There are words which you can't exclude from the blacklist, e.g. certain racist, sexist, or antisemitic slurs. (to be implemented) -->
|
<!-- There are words which you can't exclude from the blacklist, e.g. certain racist, sexist, or antisemitic slurs.
|
||||||
</p>
|
</p>
|
||||||
<form action="/settings/blacklist" method="post">
|
<form action="/settings/blacklist" method="post">
|
||||||
<!-- find a way to display current blacklist. js which reads from a cookie? template? -->
|
<!-- find a way to display current blacklist. js which reads from a cookie? template? -->
|
||||||
|
|
37
user.py
37
user.py
|
@ -140,7 +140,7 @@ schlitz
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
def get_mailinglist(self):
|
def get_mailinglist(self):
|
||||||
db.execute("SELECT email FROM mailinglist WHERE user_id = ? AND active = 1;", (self.uid, ))
|
db.execute("SELECT email FROM mailinglist WHERE user_id = ?;", (self.uid, ))
|
||||||
return db.cur.fetchall()
|
return db.cur.fetchall()
|
||||||
|
|
||||||
def get_seen_mail(self):
|
def get_seen_mail(self):
|
||||||
|
@ -163,11 +163,11 @@ schlitz
|
||||||
return db.cur.fetchone()[0]
|
return db.cur.fetchone()[0]
|
||||||
|
|
||||||
def add_subscriber(self, email):
|
def add_subscriber(self, email):
|
||||||
db.execute("INSERT INTO mailinglist(user_id, email, active) VALUES(?, ?, ?);", (self.uid, email, 1))
|
db.execute("INSERT INTO mailinglist(user_id, email) VALUES(?, ?);", (self.uid, email))
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
def remove_subscriber(self, email):
|
def remove_subscriber(self, email):
|
||||||
db.execute("UPDATE mailinglist SET active = 0 WHERE email = ? AND user_id = ?;", (email, self.uid))
|
db.execute("DELETE FROM mailinglist WHERE email = ? AND user_id = ?;", (email, self.uid))
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
def set_badwords(self, words):
|
def set_badwords(self, words):
|
||||||
|
@ -184,6 +184,7 @@ schlitz
|
||||||
# necessary:
|
# necessary:
|
||||||
# - city
|
# - city
|
||||||
# - markdown
|
# - markdown
|
||||||
|
# - mail_md
|
||||||
# - goodlist
|
# - goodlist
|
||||||
# - blacklist
|
# - blacklist
|
||||||
# - logged in with twitter?
|
# - logged in with twitter?
|
||||||
|
@ -192,6 +193,7 @@ schlitz
|
||||||
citydict = db.user_facing_properties(self.get_city())
|
citydict = db.user_facing_properties(self.get_city())
|
||||||
return dict(city=citydict['city'],
|
return dict(city=citydict['city'],
|
||||||
markdown=citydict['markdown'],
|
markdown=citydict['markdown'],
|
||||||
|
mail_md=citydict['mail_md'],
|
||||||
triggerwords=self.get_trigger_words(),
|
triggerwords=self.get_trigger_words(),
|
||||||
badwords=self.get_badwords(),
|
badwords=self.get_badwords(),
|
||||||
enabled=self.enabled)
|
enabled=self.enabled)
|
||||||
|
@ -251,6 +253,11 @@ schlitz
|
||||||
(markdown, self.uid))
|
(markdown, self.uid))
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
def set_mail_md(self, mail_md):
|
||||||
|
db.execute("UPDATE cities SET mail_md = ? WHERE user_id = ?;",
|
||||||
|
(mail_md, self.uid))
|
||||||
|
db.commit()
|
||||||
|
|
||||||
def get_city(self):
|
def get_city(self):
|
||||||
db.execute("SELECT city FROM cities WHERE user_id == ?;", (self.uid, ))
|
db.execute("SELECT city FROM cities WHERE user_id == ?;", (self.uid, ))
|
||||||
return db.cur.fetchone()[0]
|
return db.cur.fetchone()[0]
|
||||||
|
@ -351,7 +358,25 @@ sicher vor Zensur.
|
||||||
Um Mastodon zu benutzen, besucht diese Seite:
|
Um Mastodon zu benutzen, besucht diese Seite:
|
||||||
[https://joinmastodon.org/](https://joinmastodon.org/)
|
[https://joinmastodon.org/](https://joinmastodon.org/)
|
||||||
"""
|
"""
|
||||||
db.execute("""INSERT INTO cities(user_id, city, markdown, masto_link,
|
mail_md = """# Immer up-to-date
|
||||||
twit_link) VALUES(?,?,?,?,?)""",
|
|
||||||
(self.uid, city, markdown, masto_link, twit_link))
|
Du bist viel unterwegs und hast keine Lust, jedes Mal auf das Profil des Bots
|
||||||
|
zu schauen? Kein Problem. Unsere Mail Notifications benachrichtigen dich, wenn
|
||||||
|
irgendwo Kontis gesehen werden.
|
||||||
|
|
||||||
|
Wenn du uns deine E-Mail-Adresse gibst, kriegst du bei jedem Konti-Report eine
|
||||||
|
Mail. Wenn du eine Mail-App auf dem Handy hast, so wie
|
||||||
|
[K9Mail](https://k9mail.github.io/), kriegst du sogar eine Push Notification. So
|
||||||
|
bist du immer Up-to-date über alles, was im Verkehrsnetz passiert.
|
||||||
|
|
||||||
|
## Keine Sorge
|
||||||
|
|
||||||
|
Wir benutzen deine E-Mail-Adresse selbstverständlich für nichts anderes. Du
|
||||||
|
kannst die Benachrichtigungen jederzeit deaktivieren, mit jeder Mail wird ein
|
||||||
|
unsubscribe-link mitgeschickt.
|
||||||
|
"""
|
||||||
|
db.execute("""INSERT INTO cities(user_id, city, markdown, mail_md,
|
||||||
|
masto_link, twit_link) VALUES(?,?,?,?,?,?)""",
|
||||||
|
(self.uid, city, markdown, mail_md, masto_link, twit_link))
|
||||||
db.commit()
|
db.commit()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue