diff --git a/README.md b/README.md index 7b4603d..2bdc8d7 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ virtualenv -p python3 . Install the dependencies: ```shell -pip install tweepy pytoml Mastodon.py bottle pyjwt pylibscrypt +pip install tweepy pytoml Mastodon.py bottle pyjwt pylibscrypt Markdown ``` Configure the bot: diff --git a/db.py b/db.py index ac4999d..0259a85 100644 --- a/db.py +++ b/db.py @@ -42,13 +42,13 @@ class DB(object): CREATE TABLE IF NOT EXISTS triggerpatterns ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, user_id INTEGER, - pattern TEXT, + patterns TEXT, FOREIGN KEY(user_id) REFERENCES user(id) ); CREATE TABLE IF NOT EXISTS badwords ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, user_id INTEGER, - word TEXT, + words TEXT, FOREIGN KEY(user_id) REFERENCES user(id) ); CREATE TABLE IF NOT EXISTS mastodon_instances ( @@ -146,10 +146,29 @@ class DB(object): self.execute("INSERT INTO user (passhash) VALUES(?);", (json['passhash'], )) uid = self.cur.lastrowid - self.execute(""" - INSERT INTO triggerpatterns (user_id, pattern) - VALUES(?, ?); - """, (uid, '.*')) + default_triggerpatterns = """ +kontroll?e +konti +db +vgn +vag +zivil +sicherheit +uniform +station +bus +bahn +tram +linie +nuernberg +nürnberg +s\d +u\d\d? + """ + self.execute("""INSERT INTO triggerpatterns (user_id, patterns) + VALUES(?, ?); """, (uid, default_triggerpatterns)) + self.execute("INSERT INTO badwords (user_id, words) VALUES(?, ?);", + (uid, "")) else: uid = json['uid'] self.execute("INSERT INTO email (user_id, email) VALUES(?, ?);", diff --git a/frontend.py b/frontend.py index 43ca54d..07aff7f 100755 --- a/frontend.py +++ b/frontend.py @@ -38,7 +38,7 @@ def register_post(): return dict(error='Email address already in use.') # send confirmation mail try: - # print(url('confirm/' + city + '/%s' % db.user_token(email, password))) # only for local testing + print(url('confirm/' + city + '/%s' % db.user_token(email, password))) # only for local testing sendmail( email, "Confirm your account", @@ -93,6 +93,20 @@ def settings(user): return user.state() +@post('/settings/goodlist') +@view('template/settings.tpl') +def update_trigger_patterns(user): + user.set_trigger_words(request.forms['goodlist']) + return user.state() + + +@post('/settings/blacklist') +@view('template/settings.tpl') +def update_badwords(user): + user.set_badwords(request.forms['blacklist']) + return user.state() + + @get('/api/state') def api_enable(user): return user.state() diff --git a/template/city.tpl b/template/city.tpl index d102660..dddac8d 100644 --- a/template/city.tpl +++ b/template/city.tpl @@ -1,4 +1,9 @@ % rebase('template/wrapper.tpl') -$markdown.render() +<% +import markdown as md +html = md.markdown(markdown) +%> + +{{html}} diff --git a/template/settings.tpl b/template/settings.tpl index 32ab147..ea9c35d 100644 --- a/template/settings.tpl +++ b/template/settings.tpl @@ -1,7 +1,11 @@ % rebase('template/wrapper.tpl') -
asdf
+% if enabled: +
Disable
+% else: +
Enable
+% end @@ -72,7 +76,7 @@ suggest:

- +
@@ -86,7 +90,7 @@

- +
@@ -100,7 +104,7 @@

- +
diff --git a/user.py b/user.py index 08fd505..96d88b8 100644 --- a/user.py +++ b/user.py @@ -27,7 +27,7 @@ class User(object): @property def enabled(self): - db.execute("SELECT enabled FROM user WHERE user_id=?;", (self.uid, )) + db.execute("SELECT enabled FROM user WHERE id=?;", (self.uid, )) return bool(db.cur.fetchone()[0]) @enabled.setter @@ -59,16 +59,35 @@ class User(object): def is_appropriate(self, report): db.execute("SELECT pattern FROM triggerpatterns WHERE user_id=?;", (self.uid, )) - for pattern, in db.cur.fetchall(): + patterns = db.cur.fetchone() + for pattern in patterns.splitlines(): if pattern.search(report.text) is not None: break else: # no pattern matched return False + default_badwords = """ +bastard +bitch +whore +hitler +slut +hure +jude +schwuchtel +fag +faggot +nigger +neger +schlitz + """ db.execute("SELECT word FROM badwords WHERE user_id=?;", (self.uid, )) - badwords = [word.lower() for word, in db.cur.fetchall()] - for word in report.text.lower().split(): + badwords = db.cur.fetchone() + for word in report.text.lower().splitlines(): + if word in badwords: + return False + for word in default_badwords.splitlines(): if word in badwords: return False return True @@ -129,8 +148,22 @@ class User(object): db.execute("UPDATE seen_mail SET mail_date = ? WHERE user_id = ?;", (mail_date, self.uid)) - def get_trigger_words(self, table): - db.execute("SELECT words FROM ? WHERE user_id = ?;", (table, self.uid,)) + def set_trigger_words(self, patterns): + db.execute("UPDATE triggerpatterns SET patterns = ? WHERE user_id = ?;", + (patterns, self.uid)) + + def get_trigger_words(self): + db.execute("SELECT patterns FROM triggerpatterns WHERE user_id = ?;", + (self.uid,)) + return db.cur.fetchone()[0] + + def set_badwords(self, words): + db.execute("UPDATE badwords SET words = ? WHERE user_id = ?;", + (words, self.uid)) + + def get_badwords(self): + db.execute("SELECT words FROM badwords WHERE user_id = ?;", + (self.uid,)) return db.cur.fetchone()[0] def state(self): @@ -142,7 +175,12 @@ class User(object): # - logged in with twitter? # - logged in with mastodon? # - enabled? - return dict(foo='bar') + citydict = db.user_facing_properties(self.get_city()) + return dict(city=citydict['city'], + markdown=citydict['markdown'], + triggerwords=self.get_trigger_words(), + badwords=self.get_badwords(), + enabled=self.enabled) def save_request_token(self, token): db.execute("INSERT INTO twitter_request_tokens(user_id, request_token, request_token_secret) VALUES(?, ?, ?);", @@ -191,99 +229,99 @@ class User(object): db.commit() def get_city(self): - db.execute("SELECT city FROM user WHERE id == ?;", (self.uid, )) + db.execute("SELECT city FROM cities WHERE user_id == ?;", (self.uid, )) return db.cur.fetchone()[0] def set_city(self, city): - masto_link = "masto.social/@" + city # get masto_link - twit_link = "twitter.com/" + city # get twit_link + masto_link = "example.mastodon.social/@" + city # get masto_link + twit_link = "example.twitter.com/" + city # get twit_link mailinglist = city + "@" + config['web']['host'] markdown = """ - = Wie funktioniert Ticketfrei? = - - Willst du mithelfen, Ticketkontrolleure zu überwachen? - Willst du einen Fahrscheinfreien ÖPNV erkämpfen? - - == Ist es gerade sicher, schwarz zu fahren? == - - Schau einfach auf das Profil unseres Bots: """ + twit_link + """ - - Hat jemand vor kurzem etwas über Kontrolleur*innen gepostet? - * Wenn ja, dann kauf dir vllt lieber ein Ticket. In Nürnberg - haben wir die Erfahrung gemacht, dass Kontis normalerweile - ungefähr ne Woche aktiv sind, ein paar Stunden am Tag. Wenn es - also in den letzten Stunden einen Bericht gab, pass lieber - auf. - * Wenn nicht, ist es wahrscheinlich kein Problem :) - - Wir können natürlich nicht garantieren, dass es sicher ist, - also pass trotzdem auf, wer auf dem Bahnsteig steht. - Aber je mehr Leute mitmachen, desto eher kannst du dir sicher - sein, dass wir sie finden, bevor sie uns finden. - - Also, wenn du weniger Glück hast, und der erste bist, der einen - Kontrolleur sieht: - - == Was mache ich, wenn ich Kontis sehe? == - - Ganz einfach, du schreibst es den anderen. Das geht entweder - - - - * Oder per Mail an """ + mailinglist + """, wenn ihr kein - Social Media benutzen wollt. - - Schreibe einfach einen Toot oder einen Tweet, der den Bot - mentioned, und gib an - * Wo du die Kontis gesehen hast - * Welche Linie sie benutzen und in welche Richtung sie fahren. - - Zum Beispiel so: - - [[https://github.com/b3yond/ticketfrei/blob/master/guides/tooting_screenshot.png|Screenshot of writing a toot]] - - [[https://github.com/b3yond/ticketfrei/blob/master/guides/toot_screenshot.png|A toot ready to be boosted]] - - Der Bot wird die Nachricht dann weiterverbreiten, auch zu den - anderen Netzwerken. - Dann können andere Leute das lesen und sicher vor Kontis sein. - - Danke, dass du mithilfst, öffentlichen Verkehr für alle - sicherzustellen! - - == Kann ich darauf vertrauen, was random stranger from the - Internet mir da erzählen? == - - Aber natürlich! Wir haben Katzenbilder! - - [[https://lorempixel.com/550/300/cats|Katzenbilder...]] - - Glaubt besser nicht, wenn jemand postet, dass die Luft da und - da gerade rein ist. - Das ist vielleicht sogar gut gemeint - aber klar könnte die - VAG sich hinsetzen und einfach lauter Falschmeldungen posten. - - Aber Falschmeldungen darüber, dass gerade Kontis i-wo unterwegs - sind? - Das macht keinen Sinn. - Im schlimmsten Fall kauft jmd mal eine Fahrkarte mehr - aber - kann sonst immer schwarz fahren. - - Also ja - es macht Sinn, uns zu vertrauen, wenn wir sagen, wo - gerade Kontis sind. - - == Was ist Mastodon und warum sollte ich es benutzen? == - - Mastodon ist ein dezentrales soziales Netzwerk - so wie - Twitter, nur ohne Monopol und Zentralismus. - Ihr könnt Kurznachrichten (Toots) über alles mögliche - schreiben, und euch mit anderen austauschen. - - Mastodon ist Open Source, Privatsphäre-freundlich und relativ - sicher vor Zensur. - - Um Mastodon zu benutzen, besucht diese Seite: - https://joinmastodon.org/ +# Wie funktioniert Ticketfrei? + +Willst du mithelfen, Ticketkontrolleure zu überwachen? +Willst du einen Fahrscheinfreien ÖPNV erkämpfen? + +## Ist es gerade sicher, schwarz zu fahren? + +Schau einfach auf das Profil unseres Bots: """ + twit_link + """ + +Hat jemand vor kurzem etwas über Kontrolleur*innen gepostet? +* Wenn ja, dann kauf dir vllt lieber ein Ticket. In Nürnberg + haben wir die Erfahrung gemacht, dass Kontis normalerweile + ungefähr ne Woche aktiv sind, ein paar Stunden am Tag. Wenn es + also in den letzten Stunden einen Bericht gab, pass lieber + auf. +* Wenn nicht, ist es wahrscheinlich kein Problem :) + +Wir können natürlich nicht garantieren, dass es sicher ist, +also pass trotzdem auf, wer auf dem Bahnsteig steht. +Aber je mehr Leute mitmachen, desto eher kannst du dir sicher +sein, dass wir sie finden, bevor sie uns finden. + +Also, wenn du weniger Glück hast, und der erste bist, der einen +Kontrolleur sieht: + +## Was mache ich, wenn ich Kontis sehe? + +Ganz einfach, du schreibst es den anderen. Das geht entweder + + + +* Oder per Mail an """ + mailinglist + """, wenn ihr kein + Social Media benutzen wollt. + +Schreibe einfach einen Toot oder einen Tweet, der den Bot +mentioned, und gib an +* Wo du die Kontis gesehen hast +* Welche Linie sie benutzen und in welche Richtung sie fahren. + +Zum Beispiel so: + +[[https://github.com/b3yond/ticketfrei/blob/master/guides/tooting_screenshot.png|Screenshot of writing a toot]] + +[[https://github.com/b3yond/ticketfrei/blob/master/guides/toot_screenshot.png|A toot ready to be boosted]] + +Der Bot wird die Nachricht dann weiterverbreiten, auch zu den +anderen Netzwerken. +Dann können andere Leute das lesen und sicher vor Kontis sein. + +Danke, dass du mithilfst, öffentlichen Verkehr für alle +sicherzustellen! + +## Kann ich darauf vertrauen, was random stranger from the +Internet mir da erzählen? + +Aber natürlich! Wir haben Katzenbilder! + +[[https://lorempixel.com/550/300/cats|Katzenbilder...]] + +Glaubt besser nicht, wenn jemand postet, dass die Luft da und +da gerade rein ist. +Das ist vielleicht sogar gut gemeint - aber klar könnte die +VAG sich hinsetzen und einfach lauter Falschmeldungen posten. + +Aber Falschmeldungen darüber, dass gerade Kontis i-wo unterwegs +sind? +Das macht keinen Sinn. +Im schlimmsten Fall kauft jmd mal eine Fahrkarte mehr - aber +kann sonst immer schwarz fahren. + +Also ja - es macht Sinn, uns zu vertrauen, wenn wir sagen, wo +gerade Kontis sind. + +## Was ist Mastodon und warum sollte ich es benutzen? + +Mastodon ist ein dezentrales soziales Netzwerk - so wie +Twitter, nur ohne Monopol und Zentralismus. +Ihr könnt Kurznachrichten (Toots) über alles mögliche +schreiben, und euch mit anderen austauschen. + +Mastodon ist Open Source, Privatsphäre-freundlich und relativ +sicher vor Zensur. + +Um Mastodon zu benutzen, besucht diese Seite: +https://joinmastodon.org/ """ db.execute("""INSERT INTO cities(user_id, city, markdown, masto_link, twit_link) VALUES(?,?,?,?,?)""",