Compare commits

..

327 Commits

Author SHA1 Message Date
b3yond 0b862e35c8 changed promotion repo link #21 2018-10-07 19:15:18 +02:00
b3yond 13fcb41148 Merge branch 'multi-deployment' of https://github.com/b3yond/ticketfrei into multi-deployment 2018-10-07 19:13:50 +02:00
b3yond d3d7bd098d moved promotion to own repository: https://github.com/ticketfrei/promotion #21 2018-10-07 19:13:23 +02:00
b3yond 8a4cc17575 moved promotion to own repository: https://github.com/ticketfrei/promotion 2018-10-07 19:12:44 +02:00
b3yond 3d669e6caf fixing #42 - excepting more Telegram error codes 2018-10-07 19:09:02 +02:00
b3yond e032ecbcc3 Merge remote-tracking branch 'origin/multi-deployment' into multi-deployment 2018-10-07 18:48:05 +02:00
b3yond 30f1f8a21c fixing #40 - treating different message MIMEtypes 2018-10-07 18:47:37 +02:00
b3yond 942f19fefe comments, because the use of this file is not obvious. 2018-10-06 11:58:08 +02:00
b3yond 5119c6bfbb globals are in a separate python file now #39 #45 2018-10-06 10:44:07 +02:00
b3yond 2068b99b87 fixing #44 - refactoring how mails are sent 2018-10-06 10:20:37 +02:00
b3yond 4851fc0b63 manually merging multi-deployment with master 2018-10-06 09:29:34 +02:00
b3yond b9a4899981 fixing #38: putting the city into the From address of report mails 2018-10-06 02:46:54 +02:00
b3yond 304d83ffad fixing #39 - saving last request in global var, not db. 2018-10-06 00:56:12 +02:00
b3yond 9b3efd7bd2 fixed #41 - mention has to be in status text now 2018-10-05 23:40:41 +02:00
b3yond 24598f0b87 crawl only mentions, no replies 2018-10-05 11:02:12 +02:00
b3yond dc8f51c632 payload is extracted later, we need the message object here 2018-10-05 10:56:34 +02:00
b3yond 34d43f1911 get text of email, not message object 2018-09-25 11:06:08 +02:00
b3yond 2a4d517f1d only save newer tweets, don't override with older 2018-09-24 23:16:05 +02:00
b3yond 2d12aa7107 save the newest id, not the current 2018-09-24 23:08:29 +02:00
b3yond 47a7452eb4 excepting and logging Twitter Errors to prevent crashes 2018-09-24 23:02:10 +02:00
b3yond 234ed59049 don't require correctly cased mail addresses 2018-09-24 22:40:29 +02:00
b3yond 5efea773b8 get text from db, not rows 2018-09-24 22:27:11 +02:00
b3yond 3b19278774 repaired seen_tweets, this time 4 real 2018-09-24 22:14:17 +02:00
b3yond 03033d26d7 repaired seen_tweets 2018-09-24 22:10:23 +02:00
b3yond b35e885ae2 bug in pattern matching 2018-09-24 21:11:28 +02:00
b3yond d61d5750bb fuck sql 2018-09-24 21:02:10 +02:00
b3yond aa9267e8d1 1 comma too much 2018-09-24 21:00:55 +02:00
b3yond 732ac1c5d3 changed toot logic 2018-09-24 20:54:57 +02:00
b3yond b94ead7041 weird log logic 2018-09-24 19:58:17 +02:00
b3yond b20a080129 transmitted wrong variable 2018-09-24 19:51:23 +02:00
b3yond 1412dbc54c simple var name error 2018-09-24 19:46:21 +02:00
b3yond f28df3ce3e logging reports for debugging 2018-09-24 19:41:48 +02:00
b3yond 0cf1d8b603 sqlite3 syntax error because of trailing " 2018-09-24 17:14:23 +02:00
b3yond 244bde51b6 added email routing with exim4 via /etc/aliases 2018-09-23 18:53:46 +02:00
b3yond 36c21dbfbb style guides ftw 2018-09-15 19:30:37 +02:00
b3yond f360c4f8fd Merge remote-tracking branch 'origin/multi-deployment' into multi-deployment
# Conflicts:
#	template/settings.tpl
2018-09-15 19:20:25 +02:00
b3yond fcab07246b blacklist -> blocklist #31 to honor zuckerimtank@twitter.com 2018-09-15 19:01:58 +02:00
b3yond 11f3c5713b
Merge pull request #36 from git-sid/multi-deployment
merge small stylechanges
2018-09-15 18:58:08 +02:00
b3yond 1a793657af
right of = should be right of = 2018-09-15 18:50:37 +02:00
b3yond e9ac7286d9
peak readability 2018-09-15 18:47:43 +02:00
b3yond 823df7b04a fix TypeError when updates == None 2018-09-14 19:59:45 +02:00
git-sid 1703eb3802 Make code even more PEP8 compliant
It could be made even more compliant, but that would actually decrease
readability imo.
2018-09-14 12:45:49 +02:00
git-sid 72d6798022 WIP: #31 fix: blacklist -> blocklist.
Replace all relevant instances of "blacklist" with blocklist.
Untested due to OS restricitions. Please check before merge.
2018-09-14 09:44:21 +02:00
git-sid c2ed73bafc Make code more pep8 compliant 2018-09-13 17:33:33 +02:00
git-sid c576888da5 small fix 2018-09-13 17:24:19 +02:00
b3yond 25bfe8e838 Merge branch 'multi-deployment' of github:b3yond/ticketfrei into multi-deployment 2018-09-09 21:38:22 +02:00
b3yond eae077cb9b Merge branch 'multi-deployment' of github:git-sid/ticketfrei into multi-deployment 2018-09-09 21:37:30 +02:00
b3yond 91181e1cf8 added telegram to default city page text. 2018-09-09 21:36:27 +02:00
b3yond 6757e62242 those error messages are a bit universal. 2018-09-09 21:36:01 +02:00
b3yond c37a447392
Merge pull request #20 from git-sid/multi-deployment
added basic telegram backend support & smaller changes
2018-09-09 21:26:57 +02:00
b3yond 3e83ba95da those error messages are a bit universal. 2018-09-09 20:32:10 +02:00
b3yond faaf8ac5f4 default values are bad practice 2018-09-09 20:28:13 +02:00
b3yond a54538bcea fixed seen_toot problem 2018-09-09 20:22:41 +02:00
b3yond 6f3c953736 fixed telegram spam problem!!111 2018-09-09 18:06:12 +02:00
b3yond 0624bcb378 Merge branch 'multi-deployment' of github:git-sid/ticketfrei into multi-deployment
# Conflicts:
#	active_bots/telegrambot.py
2018-09-09 17:52:23 +02:00
b3yond 6cac81e444 fixing more telegram bugs 2018-09-09 17:51:07 +02:00
git-sid f68a869309 added message type filtering -> only text messages get crawled 2018-09-09 17:47:38 +02:00
b3yond a0bd5e69e1 Merge remote-tracking branch 'origin/multi-deployment' into multi-deployment 2018-09-09 17:29:29 +02:00
b3yond 4b953f54e5 Making Twitter Rate Limiting intelligent #35 2018-09-09 17:29:06 +02:00
git-sid 8acbfb4569 added offset to telegram message polling to prevent duplicated responses 2018-09-09 17:22:00 +02:00
b3yond 439dbeb1fa telegram troubleshooting and fine-tuning 2018-09-09 16:58:07 +02:00
b3yond fd8b29c55f appropriate success message 2018-09-09 15:45:25 +02:00
b3yond f1d7215eba debug level was not enough 2018-09-09 15:09:40 +02:00
b3yond 4586e14ee4 Merge remote-tracking branch 'origin/multi-deployment' into multi-deployment 2018-09-09 14:58:12 +02:00
b3yond 40c834020a logging confirmation links for debug purposes 2018-09-09 14:57:40 +02:00
git-sid b85360b0a8 added twx dependency to README.md instruction 2018-09-09 14:26:46 +02:00
git-sid 185014a452 fixed telegram api bug (from -> sender) 2018-09-09 13:25:42 +02:00
b3yond b5f6854a1c host is configurable now 2018-09-08 16:31:02 +02:00
b3yond 7ca904564c Port is configurable now 2018-09-08 16:06:25 +02:00
b3yond b80b80dc43
Merge pull request #32 from b3yond/mailbot
Rewriting the Mailbot, included subscription mechanism
2018-09-08 11:14:57 +02:00
b3yond 96329e968e finished #23 code. rw city page info display. Unsubscribe = Delete 2018-09-08 11:14:00 +02:00
b3yond c7aa87cb3b BE & FE store secret in DB. Unsubscribing works 2018-09-08 09:33:40 +02:00
b3yond ad4e65e0fa Merge branch 'multi-deployment' of github:b3yond/ticketfrei into multi-deployment 2018-09-01 14:01:18 +02:00
b3yond 9c599cec37 wait on rate limit option for twitter APIs 2018-09-01 14:01:03 +02:00
b3yond 848b7b1cb5
Merge pull request #30 from jorgesumle/multi-deployment
HTML fixes
2018-08-11 17:28:00 +02:00
Jorge Maldonado Ventura 0ffe4daac8 HTML fixes 2018-08-11 17:19:12 +02:00
b3yond 372e0612a6 wrote unsubscribe function, but BE & FE have different secrets 2018-08-09 15:01:51 +02:00
b3yond 57a2e4dcb1 the mailbot can now receive messages from /var/mail/test 2018-08-08 17:09:26 +02:00
b3yond ec399db2eb started to build a mailbot implementing bot.py 2018-08-08 14:04:31 +02:00
b3yond ef0ce8f9f1 Advertising mail notifications on the city page 2018-08-08 10:55:51 +02:00
b3yond 27b63d9f8f Merge remote-tracking branch 'origin/multi-deployment' into multi-deployment 2018-08-08 10:42:08 +02:00
b3yond cc0b3378a9 you can now subscribe to mail notifications! Also db bugfixes. 2018-08-08 10:24:20 +02:00
b3yond d002969377 mail subscription confirm functions;
confirmation code & mail template still missing
2018-08-07 15:10:28 +02:00
b3yond 1f0583da74 debugging the backend, adding mail subscribe page, finished VAG zeitung 2018-08-02 22:30:57 +02:00
b3yond e1eb737ad0 markus s. 2018-08-02 22:04:26 +02:00
b3yond 9beb864a2f added mail subscriber function, confirm missing 2018-07-22 13:56:15 +02:00
b3yond a05205289f added mail template callback functions 2018-07-22 13:47:56 +02:00
b3yond 89fce872f3 added template for subscribing to mail notifications (untested) 2018-07-21 15:07:47 +02:00
b3yond d7eba3d233 replaced illegal flyer parts 2018-07-17 23:41:33 +02:00
b3yond 10b3550ad6 fixed backend deployment with systemd 2018-07-14 17:17:36 +02:00
b3yond 2d879383d4 took out mailbot for now. development of mailbot continues on the mailbot branch. 2018-07-14 16:49:11 +02:00
b3yond 4343be7e06 bots are safely imported in the backend, except twitterDMs 2018-07-14 16:39:53 +02:00
b3yond 55a804f0d6 removing redundant p tags 2018-07-13 15:55:40 +02:00
b3yond cae74a5715 fixing missing /form tag #28 2018-07-13 15:55:14 +02:00
b3yond 3d23b47a6e included aktionsschwarzfahren in promotion newspaper 2018-07-13 15:12:48 +02:00
sid 57a4a50254 modified telegram bot subscribe implementation 2018-06-30 22:11:41 +02:00
sid a8504971ea
completed telegram subscriber list functionality 2018-06-30 21:32:22 +02:00
b3yond 9db71e485d fixing settings issue with required forms 2018-06-25 21:14:22 +02:00
b3yond 8dfffffe76 Merge branch 'multi-deployment' of https://github.com/b3yond/ticketfrei into multi-deployment 2018-06-25 21:13:47 +02:00
b3yond 4fb2930c6c small changes to default markdown 2018-06-25 21:13:43 +02:00
b3yond fd8f236cdd you need to checkout the multi-deployment branch, if you're actively developing 2018-06-24 00:26:00 +02:00
b3yond 44cd1308ba added development instructions to README 2018-06-24 00:24:01 +02:00
b3yond 4c6ab2d3ae css fixes 2018-06-24 00:12:39 +02:00
b3yond 0719b094f8 added telegram to frontend 2018-06-24 00:00:48 +02:00
sid a48ba9ebf8 added /start, /stop, /help command check & small fixes 2018-05-29 07:07:15 +02:00
sid 4b37c0df3d Merge branch 'multi-deployment' of https://github.com/b3yond/ticketfrei into multi-deployment 2018-05-29 00:10:22 +02:00
b3yond 83d8700e30 updated install instructions & gitignore 2018-05-28 22:26:07 +02:00
sid 86d63fe9a0
Merge branch 'multi-deployment' into multi-deployment 2018-05-28 21:18:22 +02:00
b3yond bfd9a2d5fe only markdown shit still missing, is displaying äöü on production server. 2018-05-25 19:21:30 +02:00
b3yond 7543bf3e6e last markdown fixes, I swear! 2018-05-25 17:12:41 +02:00
b3yond cd5eeb3917 You can now edit markdown in settings. #18 2018-05-25 16:50:02 +02:00
b3yond f4736c91dd fixed markdiown render issues. Closing #22 2018-05-25 16:31:08 +02:00
b3yond 559b709b8f more markdown fixes 2018-05-25 16:27:30 +02:00
b3yond 628fcb4f95 small markdown fixes 2018-05-25 16:15:44 +02:00
b3yond 2a9c5c657f you can now set goodlist & blacklist in settings. render city page #18. fixed #24 and #25. 2018-05-25 15:57:20 +02:00
b3yond c9dfb6611a Merge branch 'multi-deployment' of https://github.com/b3yond/ticketfrei into multi-deployment 2018-05-25 14:45:07 +02:00
b3yond 04a6b82c1b You can now set data for the city page. #22 2018-05-25 14:44:45 +02:00
sid 29a577508f added basic telegram backend support 2018-05-25 02:38:27 +02:00
b3yond d4d58daf40 backported the typo fixes by @git-sid in #19 2018-05-24 21:59:58 +02:00
b3yond 48d44cf698 backported the typo fixes by @git-sid in #19 2018-05-24 21:58:20 +02:00
b3yond 9274dfdecb Add API to get content of the user facing page 2018-04-27 01:20:37 +02:00
b3yond 5ec4d1aab0 displaying city or other titles on various pages. still ugly. 2018-04-26 23:48:26 +02:00
b3yond 62eb588b28 BETTER cat images!!11 2018-04-26 22:30:34 +02:00
b3yond 9885e39d68 added cat pictures <3333 2018-04-26 22:28:51 +02:00
b3yond 01b3657c8e fixing file not found 500 error 2018-04-26 22:23:58 +02:00
Tech 6996cbfc09 merrrrge 2018-04-26 22:07:00 +02:00
b3yond 591020f8cc Merge branch 'multi-deployment' of dl6tom.de:public/ticketfrei into multi-deployment 2018-04-26 21:50:56 +02:00
b3yond d706c4f1cc created a user-facing page 2018-04-26 21:50:52 +02:00
Thomas L 642cf429e5 serve jquery from own server 2018-04-26 21:00:29 +02:00
b3yond dd24a2b265 fixing import error 2018-04-16 09:38:55 +02:00
b3yond 3afa73ccaf removed outdated images 2018-04-15 22:42:20 +02:00
b3yond 1a76cba4fb changed background image to jpg & more beautiful 2018-04-15 22:41:33 +02:00
b3yond 84746a6d01 better log messages 2018-04-15 12:11:49 +02:00
b3yond 064ca181c0 Merge branch 'multi-deployment' of dl6tom.de:public/ticketfrei into multi-deployment 2018-04-15 11:59:50 +02:00
b3yond 16580f3181 implemented twitter DMs 2018-04-15 11:58:19 +02:00
b3yond 7f8697947c twitter & masto sign limit 2018-04-15 11:42:34 +02:00
b3yond 758ff1db46 implemented mastodon DMs, city, and backend.shutdown function 2018-04-15 11:26:48 +02:00
b3yond 9b01ac7eac save db in a persistent folder, /var/run is not persistent in every OS 2018-04-15 09:41:27 +02:00
b3yond 898f229145 Twitter OAuth dance works now!!1111 wuuuuhhuuuu 2018-04-14 18:16:05 +02:00
b3yond 0b41b43421 fixed db scheme error 2018-04-14 18:12:55 +02:00
b3yond 24beedf467 fixed several id typos 2018-04-14 17:56:48 +02:00
Thomas L fd2a389d12 add error message for empty form. 2018-04-14 17:53:08 +02:00
b3yond 25c57039ea fixed small, but nasty bug 2018-04-14 17:49:19 +02:00
b3yond 20cfe159e9 query is a dict, not a function 2018-04-14 17:38:49 +02:00
Thomas L 57cf3bd7d6 no return needed, redirect throws 2018-04-14 17:34:43 +02:00
Thomas L 1af14a5db4 Merge branch 'multi-deployment' of dl6tom.de:public/ticketfrei into multi-deployment 2018-04-14 17:32:15 +02:00
Thomas L 22de5e7e4e add default triggerpattern 2018-04-14 17:31:53 +02:00
b3yond 4d556ec595 don't do except all -.- rather repair the fcking logging. 2018-04-14 17:31:01 +02:00
b3yond bf7c21c113 request token is a dict, not a string 2018-04-14 17:19:20 +02:00
b3yond 45d4cd2062 fixed url() call 2018-04-14 17:00:30 +02:00
b3yond 034513718f generate url with dedicated function 2018-04-14 16:36:57 +02:00
b3yond 261496c097 fixed config key error 2018-04-14 16:34:02 +02:00
b3yond 19cc64d00d added logging for unstable functions 2018-04-14 16:31:45 +02:00
b3yond 27497e7129 log python errors to extra file 2018-04-14 15:22:05 +02:00
Thomas L d280130b29 fix login and registration. 2018-03-29 21:58:55 +02:00
Thomas L 78331212e6 improve sendmail function. 2018-03-29 02:40:22 +02:00
b3yond 10fb150c21 merge 2018-03-29 02:00:28 +02:00
b3yond 29c35be8a5 reworked mailbot to implement bot.py 2018-03-29 01:50:05 +02:00
Thomas L bfc311b6c9 omit bare except. 2018-03-29 01:25:17 +02:00
Thomas L 4981223ee8 catch some error cases. 2018-03-29 01:13:53 +02:00
Thomas L 9339015101 fix account confirmation. 2018-03-29 00:59:13 +02:00
Thomas L 4850860f82 use local mail daemon for confirmation links 2018-03-29 00:57:17 +02:00
b3yond c9fd91de74 getting logging stuff 2018-03-29 00:39:45 +02:00
b3yond affd209a3b changed logging to new scheme in sendmail.py 2018-03-29 00:33:29 +02:00
b3yond ca55223be9 Merge branch 'multi-deployment' of dl6tom.de:public/ticketfrei into multi-deployment 2018-03-29 00:31:38 +02:00
b3yond 5670c92d33 added logging to sendmail.py 2018-03-29 00:31:21 +02:00
Thomas L 2b6b3a2263 log to stderr 2018-03-29 00:24:56 +02:00
b3yond 0aa1d79621 changed default config after deployment learnings 2018-03-29 00:21:14 +02:00
b3yond 788f55860b Merge branch 'multi-deployment' of dl6tom.de:public/ticketfrei into multi-deployment 2018-03-29 00:13:11 +02:00
b3yond ba6e13a2be started mail rewrite 2018-03-29 00:13:00 +02:00
Thomas L 8e08eb9c2e fix recursive import 2018-03-29 00:12:19 +02:00
b3yond c71bc8574a solved loop bug 2018-03-28 23:50:55 +02:00
b3yond bc41d7460c Merge branch 'multi-deployment' of dl6tom.de:public/ticketfrei into multi-deployment 2018-03-28 23:47:02 +02:00
b3yond 9425fde917 clean up 2018-03-28 23:46:06 +02:00
Thomas L 88afab1270 cleanup 2018-03-28 23:40:26 +02:00
Tech 5db529702c Merge branch 'multi-deployment' of https://github.com/b3yond/ticketfrei into multi-deployment 2018-03-28 23:33:43 +02:00
b3yond 66bb1f86a3 reworked twitterbot according to new scheme 2018-03-28 23:33:04 +02:00
b3yond 49bd00fba3 clean up after refactor 2018-03-28 22:12:57 +02:00
b3yond ec3053a0ab small bugfixes 2018-03-28 20:24:21 +02:00
Tech 036c742f34 Merge branch 'multi-deployment' of https://github.com/b3yond/ticketfrei into multi-deployment 2018-03-28 18:47:44 +02:00
Thomas L 1dd75c10d5 Refactoring. 2018-03-28 17:36:35 +02:00
Thomas L 890e720c91 Merge branch 'multi-deployment' of dl6tom.de:public/ticketfrei into multi-deployment 2018-03-27 23:37:19 +02:00
Tech a3e33c36c6 added deployment instructions and fixed some deployment issues. 2018-03-27 20:02:47 +02:00
Tech 670a1a6d8f Merge branch 'multi-deployment' of https://github.com/b3yond/ticketfrei into multi-deployment 2018-03-27 19:21:47 +02:00
b3yond 51dec7e072 tested deployment and brought learnings to README. added nginx config. 2018-03-27 01:04:07 +02:00
Tech c3f9f86d3f Merge branch 'multi-deployment' of https://github.com/b3yond/ticketfrei into multi-deployment 2018-03-26 22:24:06 +02:00
b3yond 2d7b222c21 removed attribution of author in bridged reports. #2 2018-03-26 21:21:51 +02:00
Tech dde4e6af7b Merge branch 'multi-deployment' of https://github.com/b3yond/ticketfrei into multi-deployment 2018-03-26 20:55:23 +02:00
Thomas L cb764f2ec3 Merge branch 'multi-deployment' of dl6tom.de:public/ticketfrei into multi-deployment 2018-03-25 23:42:45 +02:00
b3yond d207d4e960
Merge pull request #16 from d24phant/multi-deployment
propaganda - added our mission-draft
2018-03-25 22:57:40 +02:00
b3yond 5d2ffbd935
more paragraphs, some typos 2018-03-25 22:49:14 +02:00
d24phant ce79b37b38
fixed some fails_pt2
Hopefully.... :)
2018-03-25 22:32:15 +02:00
d24phant 2fdc6f1f28
Delete propaganda.tpl 2018-03-25 22:31:00 +02:00
d24phant f99b44d815
Fixed some fails
:)
2018-03-25 22:30:17 +02:00
d24phant c980e7abb5
Added "our_mission"-draft 2018-03-25 22:06:31 +02:00
b3yond 95ada7ba62 Lorem Ipsum -> actual promotion text 2018-03-25 18:23:42 +02:00
b3yond 9ac7ab3b70 config format changed 2018-03-25 17:50:28 +02:00
b3yond 64f1fff275 don't even dare to try it out. I already changed it. :P 2018-03-25 17:31:51 +02:00
Thomas L 3ea06d1e93 Add .editorconfig 2018-03-24 16:35:16 +01:00
Thomas L daf6fe831f cleanup 2018-03-24 16:26:35 +01:00
Thomas L 751f9154cc Add files for deployment. Make testing use memory-DB. 2018-03-24 15:02:11 +01:00
b3yond 061fb62bdc started reworking the README 2018-03-24 11:58:15 +01:00
Tech 305fb8e06a Merge branch 'multi-deployment' of https://github.com/b3yond/ticketfrei into multi-deployment 2018-03-24 11:33:32 +01:00
b3yond ba9b28f254 removed a lot of unnecessary clutter 2018-03-24 11:32:59 +01:00
b3yond a8efcd7825 removed a lot of unnecessary clutter 2018-03-24 11:30:12 +01:00
b3yond 17d044ec20 changed config.toml layout for ticketfrei 2.0 #12 2018-03-24 11:25:14 +01:00
b3yond be118fb4bd renamed retweetbot & retootbot (wtf, those names) 2018-03-23 18:06:59 +01:00
b3yond aa5669b019 changed trigger to work with db 2018-03-23 18:00:05 +01:00
b3yond 5f55eb88ff changed twitter to work with db 2018-03-23 17:35:04 +01:00
b3yond c548a81272 removed waste 2018-03-23 17:07:00 +01:00
b3yond a65d410e4f changing mail to use db, part 1; seen mails 2018-03-23 17:00:52 +01:00
b3yond 570792ba37 reworked mastodon to work with frontend. user, config, logging -> new files. 2018-03-23 15:51:52 +01:00
b3yond c612a9dee0 rename to frontend.py & backend.py 2018-03-23 13:19:39 +01:00
b3yond bd2599c91a tested Mastodon OAuth Login - works now. 2018-03-23 13:14:06 +01:00
b3yond 81e2357e2f merging toms commits 2018-03-23 11:21:10 +01:00
b3yond a3b74dcfff initializing logger is also done by ticketfrei now 2018-03-23 11:18:00 +01:00
b3yond 32e86a3c0e ticketfrei can be imported now, takes care of loading config & logging 2018-03-23 11:05:24 +01:00
b3yond b9613a60de added twitter & masto OAuth to new web.py - untested, take care! 2018-03-23 02:28:00 +01:00
Thomas L 404be47d1b Use IF NOT EXISTS instead of sqlite specific hack. Clean up formating. Other minor fixes. 2018-03-22 21:15:15 +01:00
b3yond 235b8524f8 db is persistent now 2018-03-22 11:32:43 +01:00
b3yond 9e09dcea84 fixed db init, fixed confirmation mails, added logout button 2018-03-22 11:22:28 +01:00
b3yond c48704ea73 modified gitignore 2018-03-22 10:37:53 +01:00
b3yond cdc88e3ee3 this file should have been ignored, I guess 2018-03-22 10:35:51 +01:00
b3yond ee8040893e fixed login error, db is now saved between different test runs 2018-03-22 10:34:53 +01:00
b3yond 390f4dc76e if table "user" doesn't exist, db is created 2018-03-22 10:25:00 +01:00
b3yond a176f856d8 unified formatting of db_init SQL 2018-03-22 10:05:49 +01:00
b3yond 529270a396 complete db create statement 2018-03-22 09:51:50 +01:00
Thomas L 3f4ec83abe start refactoring web-frontend. 2018-03-22 02:23:31 +01:00
b3yond f9033a009f added mastodon oauth dance 2018-03-20 21:24:20 +01:00
b3yond eb0252f235 added twitter OAuth dance. 2018-03-20 20:00:19 +01:00
b3yond 9cc2bf4228 typo 2018-03-18 21:37:34 +01:00
b3yond 28891d5069 outline for masto oauth 2018-03-18 21:36:46 +01:00
b3yond 9e70ff6866 removed debug messages, small layout changes 2018-03-17 15:57:56 +01:00
b3yond 87302faf9e good- and blacklist configuration works now! <3 2018-03-16 18:59:40 +01:00
b3yond 8a7c2f0110 writing good/blacklist to db. Cookies don't work yet 2018-03-16 17:55:27 +01:00
b3yond 7bbcbe1ab1 writing goodlist & blacklist -> db 2018-03-16 15:17:12 +01:00
b3yond 4b21dddddf created twitter/masto OAuth login stub 2018-03-16 14:21:15 +01:00
b3yond 26d1282413 implemented the enable button 2018-03-16 12:41:34 +01:00
b3yond 79f301d823 added OpenGraph data, started enable button 2018-03-16 09:51:10 +01:00
b3yond 2ce2a45f7b fixed bg image on some browsers. fixed invalid email error. 2018-02-17 15:51:33 +01:00
b3yond 52c2d1e341 fixed FPD for bot.html 2018-02-17 12:31:49 +01:00
b3yond 1f01938a8c This time I really fixed the css. almost. 2018-02-17 12:30:06 +01:00
b3yond a7bae0aed9 login check with cookies works now. fixed some layout stuff 2018-02-16 17:46:43 +01:00
b3yond 1b75e03fc5 check if user already exists on registering 2018-02-16 14:16:50 +01:00
b3yond 7ccf6917c8 create db manually 2018-02-16 12:02:58 +01:00
b3yond 2e89f9bf2d It's unfortunate, but apparently it is impossible to keep this file in the repo. >.< 2018-02-16 11:59:58 +01:00
b3yond fb36221a40 readded db stub 2018-02-16 11:51:58 +01:00
b3yond 0c04ce4b70 delete db file 2018-02-16 11:50:23 +01:00
b3yond 1e0a8a09ed gitignore readd. how do I prevent ticketfrei.sqlite from updating the stub in the repo? 2018-02-16 11:46:10 +01:00
b3yond 27902954e8 fixed wallpaper after confirmation mail 2018-02-16 11:39:31 +01:00
b3yond 821f201454 confirmation emails work now, accounts can be created. 2018-02-16 11:33:27 +01:00
b3yond 9e221ed290 Excepted IMAP connection Error 2018-01-30 16:10:33 +01:00
b3yond 3bc1010edf small steps... 2018-01-26 17:54:11 +01:00
b3yond 0ba2438541 fix sqlite commands, rename to website.py 2018-01-26 15:19:03 +01:00
b3yond 0acb89ebf0 excepted IMAP4 error with unknown cause 2018-01-23 09:18:59 +01:00
b3yond c9d5f7441a excepted IMAP4 error with unknown cause 2018-01-23 09:17:26 +01:00
b3yond ace28ee25a summary: what is ticketfrei? 2018-01-19 16:42:43 +01:00
b3yond 63cf134ffa merged ticketfrei 1.0 into multi-deployment #3 2018-01-19 16:33:46 +01:00
b3yond c0328be3a4 one \ to much lol 2018-01-19 16:27:30 +01:00
b3yond c9e6a35372 updated README to version 1.0. you can disable accounts now 2018-01-19 16:00:36 +01:00
b3yond 04e05ee8ca excepted Mastodon API Error with a too broad exception 2018-01-19 00:17:09 +01:00
b3yond 37b2706a3b excepted TweepError that was raised without an explanation further than 503 2018-01-18 21:48:36 +01:00
b3yond 9305a32eb7 added more save_last(), schadet nicht 2018-01-18 20:15:41 +01:00
b3yond 12fbbde79c bots don't own trigger anymore 2018-01-18 15:18:20 +01:00
b3yond 21e4af6fa9 twitter accidentially crawled too many tweets 2018-01-18 15:14:04 +01:00
b3yond c8e67d1937 better error handling of FileExistsError, fixed regex for mastobot 2018-01-18 15:10:05 +01:00
b3yond 10de40549c added regex magic so twitter & masto don't mention themselves by accident 2018-01-18 14:48:53 +01:00
b3yond ee61ba19e6 mailbot doesn't crawl mails which it wrote itself anymore 2018-01-18 14:23:11 +01:00
b3yond 72d0acb20a bugfix: gave Report.__init__() twitter User object, not screen_name 2018-01-18 13:59:37 +01:00
b3yond b174db3cfe twitterbot.crawl() returns reports now, not statuses 2018-01-18 13:54:32 +01:00
b3yond 048bad181b only send one status at a time 2018-01-18 13:42:23 +01:00
b3yond b5288f341c bugfix: FileExistsError 2018-01-18 13:40:07 +01:00
b3yond 75e1ff902c function needs to take an argument 2018-01-18 13:19:11 +01:00
b3yond d6a0c6d377 changed ticketfrei flow logic, integrated mailbot!!! #11 2018-01-18 13:06:53 +01:00
b3yond cde5494de3 mailbot uses reports now, and doesn't need to own trigger 2018-01-18 12:42:37 +01:00
b3yond ff73c5dc21 Standardized reports; moved flow() logic to crawl(), repost(), & post(); bots don't own Trigger anymore 2018-01-18 11:41:08 +01:00
b3yond 9ef0b27970 Tried to make confirm link work (WIP) 2018-01-18 09:39:06 +01:00
b3yond 9f060b405e added nice slogan! 2018-01-09 23:01:01 +01:00
b3yond 5feb6cf5be check hashes at login (not tested) 2018-01-09 23:00:00 +01:00
b3yond da421769e9 generating confirmation links 2018-01-08 22:56:05 +01:00
b3yond 89ce129b38 first attempt at confirmation mails 2018-01-08 01:16:34 +01:00
b3yond 2f74791dd6 renamed promotion directory on master, too 2018-01-08 00:17:19 +01:00
b3yond 2e80d10222 renamed promotion directory 2018-01-08 00:16:29 +01:00
b3yond 2b4d8650c9 Merge branch 'master' of https://github.com/b3yond/ticketfrei into multi-deployment 2018-01-08 00:14:38 +01:00
b3yond 7689eb25f8 Started with the index page, worked on login & register. 2018-01-08 00:09:25 +01:00
Thomas L f2a0cf18b4 replace logger class with standard python loggin 2018-01-07 20:22:32 +01:00
Thomas L f0aaa4dc54 remove our api-keys m( 2018-01-07 18:48:35 +01:00
b3yond b9e1b38963 blacklisted certain racist slurs 2018-01-07 01:33:10 +01:00
b3yond 409f9e80f8 exchanged link & QR-Code 2018-01-07 00:52:03 +01:00
b3yond 851992803f created a flyer for autonomous centers 2018-01-06 22:20:36 +01:00
b3yond 79a8965d1c wrote 3 articles for a false-flag-flyer :D 2018-01-06 21:31:23 +01:00
b3yond a0ca940008 wrote fully fleshed out mailbot. has to be connected to ticketfrei.py #11 2018-01-05 17:13:41 +01:00
b3yond 5c98aa7677 started an IMAP listener to implement a 3rd bot: the Mailbot. #11 2018-01-05 14:16:24 +01:00
b3yond 01ad0e1c40 attach logfiles to shutdown mails 2018-01-05 11:20:07 +01:00
b3yond e962bbbe85 removed unused shutdown contact, renamed variable 2018-01-05 11:02:45 +01:00
b3yond 0b89a52da3 log traceback of all unexpected Exceptions 2018-01-05 10:52:15 +01:00
b3yond 31a54fc19f documented log config 2018-01-05 10:43:38 +01:00
b3yond 654af44534 reworked logger class - also handles bot crashes and tbs now. added configline for log directory. 2018-01-05 10:42:31 +01:00
b3yond 8357be7f7d typo 2018-01-04 12:23:41 +01:00
b3yond 98dd5e4212 improved the traceback messages 2018-01-04 12:20:59 +01:00
b3yond aa45a8e814 small fix 2018-01-04 11:05:36 +01:00
b3yond 0f6fc60b5e crash reports are now sent via mail. documented config.toml.example 2018-01-04 11:02:42 +01:00
b3yond df32f3c614 added class to write mails to users 2018-01-01 11:23:50 +01:00
b3yond d7dea7df00 finished changes to class structure 2017-12-30 16:33:34 +01:00
b3yond 96ef5e2a3f typo 2017-12-30 16:23:53 +01:00
b3yond e64e3702f6 moved log to own class 2017-12-30 16:20:25 +01:00
Thomas L 594b3fb5de fix fd mode 2017-12-30 11:31:16 +01:00
b3yond d22c85da1b Renamed config file to config.toml #6 2017-12-30 10:32:20 +01:00
b3yond 4aa4846527 optimized install docs 2017-12-30 01:21:57 +01:00
b3yond 7a1a857ab4 added documentation -> python3 #7 2017-12-30 01:17:13 +01:00
b3yond cbf16b8f74 changed ticketfrei.py to python3 #7 2017-12-30 01:15:22 +01:00
b3yond fb24c758a8 changed twitterbot to python3 + tweepy #7 2017-12-30 01:11:28 +01:00
b3yond 15d2c75b5a Merge branch 'master' of https://github.com/b3yond/ticketfrei 2017-12-10 20:20:39 +01:00
b3yond 2c21fb09ca added todo 2017-12-10 20:20:30 +01:00
b3yond 42aa60a968 wrote documentation 2017-11-28 15:11:09 +01:00
b3yond a4eef4b086 updated gitignore 2017-11-24 18:16:38 +01:00
b3yond 9e38906898 new image 2017-11-24 18:15:56 +01:00
b3yond b1348e5578 Merge branch 'master' of https://github.com/b3yond/ticketfrei 2017-11-24 18:13:52 +01:00
b3yond 1ee464cf97 patc designed a more readable sticker :D 2017-11-01 23:10:40 +01:00
b3yond 3ee52532d2 added nbg_ticketfrei logo 2017-10-18 19:15:16 +02:00
b3yond 357d6c4fc2 would be a nice feature 2017-10-17 15:29:09 +02:00
b3yond 36f919826f Merge branch 'master' of https://github.com/b3yond/ticketfrei 2017-10-17 15:27:56 +02:00
b3yond 694a930d73 Merge branch 'master' of dl6tom.de:public/ticketfrei 2017-10-17 00:16:51 +02:00
b3yond d6a94432c8 added another todo point 2017-10-17 00:15:56 +02:00
Thomas L aefe78eb50 add license 2017-10-17 00:14:57 +02:00
b3yond 150e3579b7 added 2 todo points 2017-10-17 00:04:21 +02:00
ng0 f4b8300ac1
minor correction to ticketfrei.cfg.example 2017-10-14 19:54:57 +00:00
34 changed files with 402 additions and 674 deletions

View File

@ -1,27 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
**Expected behavior**
A clear and concise description of what you expected to happen.
**Actual Behavior**
A clear and concise description of what happens.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Ticketfrei Version**
See the commit on which Ticketfrei is running at example.org/version.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.

View File

@ -1,17 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@ -1,7 +0,0 @@
---
name: Something else
about: Other ideas?
---
*If your suggestion is neither a bug report nor a feature request, this is the right place. Just describe what you have in mind.*

View File

@ -1,6 +1,6 @@
Copyright (c) 2017 Thomas L <tom@dl6tom.de>
Copyright (c) 2017 b3yond <b3yond@riseup.net>
Copyright (c) 2018 sid <sid-sid@riseup.net>
Copyright (c) 2018 sid
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above

188
README.md
View File

@ -1,25 +1,10 @@
# Ticketfrei social bot
Version: 2.0beta
Ticketfrei is a mastodon/twitter/mail bot to dodge ticket controllers in public
transport systems.
## Mission
Public transportation is meant to provide an easy and time-saving way to move
within a region while being affordable for everybody. Unfortunately, this is
not yet the case. Ticketfrei's approach is to **enable people to reclaim public
transportation.**
On short term we want to do this by helping users to avoid controllers and
fines - on long term by **pressuring public transportation companies to offer
their services free of charge**, financed by the public.
Because with Ticketfrei you're able to use trains and subways for free anyway.
Take part and create a new understanding of what public transportation could
look like!
## How It Works
The functionality is simple: It retweets every tweet where it is mentioned.
This leads to a community which evolves around it. If you see ticket
@ -28,19 +13,19 @@ your tweet and others can read the info and think twice whether they want to
buy a ticket or not. If enough people, a critical mass, participate for the bot
to become reliable, you have positive self-reinforcing dynamics.
Today, you can use a Twitter, Mastodon, Telegram, and Mail with the account.
They will communicate with each other; if someone warns others via Mail,
Telegram, Twitter and Mastodon users will also see the message. And vice versa.
Today, you can use a Twitter, a Mastodon, and Mail with the account. They will
communicate with each other; if someone warns others via Mail, Twitter and
Mastodon users will also see the message. And vice versa.
In version 2, this repository contains a web application. On this website,
people can register an own bot for their city - the website manages multiple
bots for multiple citys. This way, you do not have to host it yourself.
In version 2, this bot has received a frontend website. On this website, people
can register an own bot for their city - the website manages multiple bots for
multiple citys. This way, you do not have to host it yourself.
In the promotion folder, you'll find some promotion material you can use to
build up such a community in your city. Unfortunately it is in german - but
it's editable, feel free to translate it!
Website (our flagship instance): https://ticketfrei.links-tech.org
Website: https://ticketfrei.links-tech.org
More information: https://wiki.links-tech.org/IT/Ticketfrei
@ -49,11 +34,9 @@ More information: https://wiki.links-tech.org/IT/Ticketfrei
Just go to https://ticketfrei.links-tech.org or another website where this software is
running.
* Register a twitter account
* Register a Mastodon account
* Register on the ticketfrei site
* Optionally: register bots:
* Register a Twitter account
* Register a Mastodon account
* Register a Telegram bot
* Configure account
* The hard part: do the promotion! You need a community.
@ -67,7 +50,7 @@ to check if something was retweeted in the last hour or something.
To this date, we have never heard of this happening though.
### Blocklisting
### blockisting
You also need to edit the goodlist and the blocklist. You can do this on the
website, in the settings of your bot.
@ -87,9 +70,9 @@ a GitHub issue or write to tech@lists.links-tech.org, we are happy to help and s
We wrote these installation notes, so you can set up the website easily:
### Install from the git repository
### Install
This guide assumes you are on a Debian 9 Server:
To Do:
```shell
sudo apt install python3 virtualenv uwsgi uwsgi-plugin-python3 nginx git exim4
@ -108,7 +91,7 @@ virtualenv -p python3 .
Install the dependencies:
```shell
pip install tweepy pytoml Mastodon.py bottle pyjwt pylibscrypt Markdown twx gitpython
pip install tweepy pytoml Mastodon.py bottle pyjwt pylibscrypt Markdown twx
```
Configure the bot:
@ -118,11 +101,10 @@ cp config.toml.example config.toml
vim config.toml
```
This configuration is only for the admin. Moderators can log into
This configuration is only for the admin. Users can log into
twitter/mastodon/mail and configure their personal bot on the settings page.
Set up LetsEncrypt:
```shell
sudo apt-get install python-certbot-nginx -t stretch-backports
sudo certbot --authenticator webroot --installer nginx --agree-tos --redirect --hsts
@ -152,19 +134,10 @@ echo "Enter your domain name into the following prompt:" && read DOMAIN
# configure nginx
sudo sed -r "s/example.org/$DOMAIN/g" deployment/example.org.conf > /etc/nginx/sites-enabled/$DOMAIN.conf
# create folder for database
# create folder for socket & database
sudo mkdir /var/ticketfrei
sudo chown www-data:www-data -R /var/ticketfrei
# create folder for socket
sudo mkdir /var/run/ticketfrei
sudo chown -R www-data:www-data /var/run/ticketfrei
sudo -s
echo "mkdir /var/run/ticketfrei" >> /etc/rc.local
echo "chown -R www-data:www-data /var/run/ticketfrei" >> /etc/rc.local
echo "service ticketfrei-web restart" >> /etc/rc.local
exit
# change /etc/aliases permissions to be able to receive reports per mail
sudo chown root:www-data /etc/aliases
sudo chmod 664 /etc/aliases
@ -187,17 +160,6 @@ sudo systemctl daemon-reload
sudo systemctl start ticketfrei-backend.service
```
### Backup
For automated backups, you need to backup these files:
* `/var/ticketfrei/db.sqlite`
* `/srv/ticketfrei/config.toml`
* `/etc/aliases`
You can find an example how to do this with borgbackup in the deployment
folder. Adjust it to your needs.
### Logs
There are several logfiles which you can look at:
@ -214,15 +176,11 @@ less /var/log/syslog
# for the nginx web server:
less /var/log/nginx/example.org_error.log
# for the mail server
less /var/log/exim4/mainlog
```
### Development Install
If you want to install it locally to develop on it, note that twitter and mail
will probably not work. You should test them on a server instead.
If you want to install it locally to develop on it:
```shell
sudo apt install python3 virtualenv uwsgi uwsgi-plugin-python3 nginx git
@ -267,113 +225,3 @@ sudo chown $USER:$USER -R /var/log/ticketfrei
./frontend.py & ./backend.py &
```
# Project History
## Version 1
- more of less hacked together during a mate-fueled weekend
- backend-only, twitter & mastodon
- just a script, which crawled & retweeted tweets, if they match a whitelist & blocklist
- whitelist & blocklist were just 2 files
## Version 2
Reasons for the rewrite:
- user management: Users should be able to run a Ticketfrei bot in their city
- without needing a server, without needing command line skills
- more networks; not only Twitter & Mastodon, also Email & Telegram
2 processes: backend & frontend.
The two Processes talk via a database.
The two Processes have separate log files.
Both processes take some config values from config.toml.
### Backend
The Backend takes care of crawling & spreading the reports.
backend.py:
- main loop which does the crawling & posting.
- loops through all cities in the database
- per city it tries all of the networks/bots:
- per network/bot it runs the crawl()-function to ask the social network for new reports
- then it checks whether the report is appropriate
- if yes, it posts the report via all networks/bots, which belong to the city.
config.py: imports config values
- Imports values from config.toml
- If there is no config file it tries to use environment variables,
- Apart from that it uses the default values.
bot.py: bot parent Class
- just the absolute minimum what a bot needs to be able to do: crawl + post
- is never instantiated, only inherited from
report.py: report Class
- defines how reports are supposed to look like
active_bots/mailbot.py as an example for how a network/bot works
- crawl():
- mails arrive at an mbox file through exim4
- the bot checks whether they are new
- the bot generates a report object from the mail and returns it to the backend.py-loop
- post():
- asks the database for the list of mails which want to receive reports for this city
- sends the report.text to those mail addresses
### Frontend
the architecture of the frontend is loosely oriented off [Model View
Controller](https://blog.codinghorror.com/understanding-model-view-controller/).
user.py (Model)
- high-level interface to talk to the database
- database calls; almost all values in the database are specific to a city/user
- user.py is also a Class for frontend web authentication
- user.py keeps the user-id, through which the frontend tracks authentication
db.py (Model)
- DB-Layout; creates the database if it doesn't exist yet.
- holds some database calls which are not city-specific.
frontend.py (Controller): bottle web application
- handles POST/GET requests
- talks to the database through user.py
- everyone can look at the pages, and register
- but only authenticated users can login and change settings
session.py: User Authentication
- takes care of session cookies and "403 unauthenticated" error messages
sendmail.py: helper script to send mails
- sends all mails the frontend, backend, and bots need to send
static/
- css, images, javascript for the login form etc.
template/ (view)
- base for the HTML generation, uses the bottle-template-framework
- wrapper.tpl is the base template for every other template
### active_bots: how to implement a new network
If you want to write a new bot, e.g. a Wire-Bot, you have to take these steps:
- look for a python-library which can talk to Wire
- the city/users have to provide authentication details; this needs a form in
the settings
- depending on the network either a password, a token, or an implementation
of the OAuth login flow
- the backend needs to crawl messages from the network, & post reports to the
network
Files you need to change:
1. active_bots/wire.py - crawl & post functions
2. settings.tpl - form to authenticate to the network & possible network specific settings.
3. frontend.py - routes for the forms you added to settings.tpl
4. db.py - database layout, to store the account credentials/tokens, and to save which message you have last seen
5. user.py - database calls to get or set values

View File

@ -10,7 +10,7 @@ from bot import Bot
from config import config
from db import db
logger = logging.getLogger("main")
logger = logging.getLogger(__name__)
class Mailbot(Bot):
@ -19,11 +19,7 @@ class Mailbot(Bot):
def crawl(self, user):
reports = []
# todo: adjust to actual mailbox
try:
mails = mailbox.mbox("/var/mail/" + config['mail']['mbox_user'])
except FileNotFoundError:
logger.error("No mbox file found.")
return reports
mails = mailbox.mbox("/var/mail/" + config['mail']['mbox_user'])
for msg in mails:
if get_date_from_header(msg['Date']) > user.get_seen_mail():
if user.get_city().lower() in msg['To'].lower():
@ -38,7 +34,7 @@ class Mailbot(Bot):
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/" \
+ db.mail_subscription_token(rec, user.get_city())
if rec not in report.author:
if report.author != rec:
try:
city = user.get_city()
sendmail(rec, "Ticketfrei " + city + " Report",
@ -58,16 +54,27 @@ def make_report(msg, user):
date = get_date_from_header(msg['Date'])
author = msg['From'] # get mail author from email header
for part in msg.walk():
if part.get_content_type() == 'text/plain':
text = part.get_payload()
elif part.get_content_type() == 'text/html':
text = re.sub(r'<[^>]*>', '', msg.get_payload())
try:
post = report.Report(author, "mail", text, None, date)
except UnboundLocalError:
logger.error('No suitable message body')
return
# :todo take only the part in between the < >
if msg.is_multipart():
text = []
for part in msg.get_payload():
if part.get_content_type() == "text":
text.append(part.get_payload())
elif part.get_content_type() == "multipart/mixed":
for p in part:
if p.get_content_type() == "text":
text.append(part.get_payload())
else:
logger.error("unknown MIMEtype: " +
p.get_content_type())
else:
logger.error("unknown MIMEtype: " +
part.get_content_type())
text = '\n'.join(text)
else:
text = msg.get_payload()
post = report.Report(author, "mail", text, None, date)
user.save_seen_mail(date)
return post

View File

@ -2,12 +2,12 @@
from bot import Bot
import logging
import mastodon
from mastodon import Mastodon
import re
from report import Report
logger = logging.getLogger("main")
logger = logging.getLogger(__name__)
class MastodonBot(Bot):
@ -19,93 +19,42 @@ class MastodonBot(Bot):
"""
mentions = []
try:
m = mastodon.Mastodon(*user.get_masto_credentials())
m = Mastodon(*user.get_masto_credentials())
except TypeError:
# No Mastodon Credentials in database.
# logger.error("No Mastodon Credentials in database.", exc_info=True)
return mentions
try:
notifications = m.notifications()
except mastodon.MastodonNetworkError:
logger.error("Mastodon Network Error.")
return mentions
except mastodon.MastodonAPIError:
try:
logger.error("Mastodon API Error: " + m.instance()['urls']['streaming_api'] + ", city: " + str(user.uid))
except mastodon.MastodonServerError:
logger.error("Mastodon Server Error 500, can't get instance.")
except mastodon.MastodonVersionError:
logger.error("Mastodon Server Error 500, server version too low.")
return mentions
except mastodon.MastodonInternalServerError:
try:
logger.error("Mastodon Error: 500. Server: " + m.instance()['urls']['streaming_api'])
except mastodon.MastodonServerError:
logger.error("Mastodon Server Error 500, can't get instance.")
except mastodon.MastodonVersionError:
logger.error("Mastodon Server Error 500, server version too low.")
return mentions
except mastodon.MastodonBadGatewayError:
try:
logger.error("Mastodon Error: 502. Server: " + m.instance()['urls']['streaming_api'])
except mastodon.MastodonServerError:
logger.error("Mastodon Server Error 502, can't get instance.")
except mastodon.MastodonVersionError:
logger.error("Mastodon Server Error 502, server version too low.")
return mentions
except mastodon.MastodonServiceUnavailableError:
try:
logger.error("Mastodon Error: 503. Server: " + m.instance()['urls']['streaming_api'])
except mastodon.MastodonServerError:
logger.error("Mastodon Server Error 503, can't get instance.")
except mastodon.MastodonVersionError:
logger.error("Mastodon Server Error 503, server version too low.")
return mentions
except mastodon.MastodonGatewayTimeoutError:
try:
logger.error("Mastodon Error: 504. Server: " + m.instance()['urls']['streaming_api'])
except mastodon.MastodonServerError:
logger.error("Mastodon Server Error 504, can't get instance.")
except mastodon.MastodonVersionError:
logger.error("Mastodon Server Error 504, server version too low.")
return mentions
except mastodon.MastodonServerError:
try:
logger.error("Unknown Mastodon Server Error. Server: " + m.instance()['urls']['streaming_api'], exc_info=True)
except mastodon.MastodonServerError:
logger.error("Unknown Mastodon Server Error.", exc_info=True)
except mastodon.MastodonVersionError:
logger.error("Unknown Mastodon Server Error.", exc_info=True)
except Exception:
logger.error("Unknown Mastodon API Error.", exc_info=True)
return mentions
for status in notifications:
try:
if (status['type'] == 'mention' and
if (status['type'] == 'mention' and
not user.toot_is_seen(status['status']['uri'])):
# save state
user.toot_witness(status['status']['uri'])
# add mention to mentions
text = re.sub(r'<[^>]*>', '', status['status']['content'])
text = re.sub(
"(?<=^|(?<=[^a-zA-Z0-9-_.]))@([A-Za-z]+[A-Za-z0-9-_]+)",
"", text)
if status['status']['visibility'] == 'public':
mentions.append(Report(status['account']['acct'],
self,
text,
status['status']['id'],
status['status']['created_at']))
else:
mentions.append(Report(status['account']['acct'],
'mastodonPrivate',
text,
status['status']['id'],
status['status']['created_at']))
except TypeError:
pass
# save state
user.toot_witness(status['status']['uri'])
# add mention to mentions
text = re.sub(r'<[^>]*>', '', status['status']['content'])
text = re.sub(
"(?<=^|(?<=[^a-zA-Z0-9-_.]))@([A-Za-z]+[A-Za-z0-9-_]+)",
"", text)
if status['status']['visibility'] == 'public':
mentions.append(Report(status['account']['acct'],
self,
text,
status['status']['id'],
status['status']['created_at']))
else:
mentions.append(Report(status['account']['acct'],
'mastodonPrivate',
text,
status['status']['id'],
status['status']['created_at']))
return mentions
def post(self, user, report):
try:
m = mastodon.Mastodon(*user.get_masto_credentials())
m = Mastodon(*user.get_masto_credentials())
except TypeError:
return # no mastodon account for this user.
if report.source == self:

View File

@ -3,7 +3,8 @@ import logging
from report import Report
from twx.botapi import TelegramBot as Telegram
logger = logging.getLogger("main")
logger = logging.getLogger(__name__)
class TelegramBot(Bot):
@ -12,45 +13,20 @@ class TelegramBot(Bot):
seen_tg = user.get_seen_tg()
try:
updates = tb.get_updates(offset=seen_tg + 1,
allowed_updates="message",
timeout=5).wait()
allowed_updates="message").wait()
except TypeError:
updates = tb.get_updates(timeout=5).wait()
updates = tb.get_updates().wait()
reports = []
if updates == None:
return reports
for update in updates:
# return when telegram returns an error code
if update in [303, 404, 420, 500, 502]:
if update in [303, 404, 420, 500]:
return reports
# log unusual telegram error messages
if isinstance(update, int):
try:
logger.error("City " + str(user.uid) +
": Unknown Telegram error code: " +
str(update) + " - " + str(updates[1]))
except TypeError:
logger.error("Unknown Telegram error code: " + str(update))
elif isinstance(update, int):
logger.error("Unknown Telegram error code: " + str(update))
return reports
# save the last message, so it doesn't get crawled again
user.save_seen_tg(update.update_id)
# skip if message is None
if update.message is None:
continue
# complain if message is a photo
if update.message.photo is not None:
tb.send_message(
update.message.sender.id,
"Sending Photos is not supported for privacy reasons. Can "
"you describe it as text instead?")
continue
# complain if message is a media file
if update.message.text is None:
tb.send_message(
update.message.sender.id,
"We only support text reporting for privacy reasons. Can "
"you describe it as text instead?")
continue
if update.message.text.lower() == "/start":
user.add_telegram_subscribers(update.message.sender.id)
tb.send_message(
@ -66,24 +42,19 @@ class TelegramBot(Bot):
elif update.message.text.lower() == "/help":
tb.send_message(
update.message.sender.id,
"Send reports here to share them with other users. "
"Use /start and /stop to get reports or not.")
"Send reports here to share them with other users. Use /start and /stop to get reports or not.")
# TODO: /help message should be set in frontend
else:
# set report.author to "" to avoid mailbot crash
sender_name = update.message.sender.username
if sender_name is None:
sender_name = ""
reports.append(Report(sender_name, self, update.message.text,
None, update.message.date))
reports.append(Report(update.message.sender.username, self,
update.message.text, None,
update.message.date))
return reports
def post(self, user, report):
tb = Telegram(user.get_telegram_credentials())
text = report.text
if len(text) > 4096:
text = text[:4096 - 2] + " \N{Horizontal ellipsis}"
text = text[:4096 - 4] + u' ...'
try:
for subscriber_id in user.get_telegram_subscribers():
tb.send_message(subscriber_id, text).wait()

67
active_bots/twitterDMs.py Normal file
View File

@ -0,0 +1,67 @@
#!/usr/bin/env python3
import logging
import tweepy
import re
import requests
import report
import tfglobals
from time import time
from bot import Bot
logger = logging.getLogger(__name__)
class TwitterBot(Bot):
def get_api(self, user):
keys = user.get_api_keys()
auth = tweepy.OAuthHandler(consumer_key=keys[0],
consumer_secret=keys[1])
auth.set_access_token(keys[2], # access_token_key
keys[3]) # access_token_secret
return tweepy.API(auth, wait_on_rate_limit=True)
def crawl(self, user):
"""
crawls all Tweets which mention the bot from the twitter rest API.
:return: reports: (list of report.Report objects)
"""
reports = []
if tfglobals.last_twitter_request + 60 > time():
return reports
try:
api = self.get_api(user)
except IndexError:
return reports # no twitter account for this user.
last_dm = user.get_seen_dm()
try:
if last_dm is None:
mentions = api.direct_messages()
else:
mentions = api.mentions_timeline(since_id=last_dm[0])
tfglobals.last_twitter_request = time()
for status in mentions:
text = re.sub(
"(?<=^|(?<=[^a-zA-Z0-9-_\.]))@([A-Za-z]+[A-Za-z0-9-_]+)",
"", status.text)
reports.append(report.Report(status.author.screen_name,
"twitterDM",
text,
status.id,
status.created_at))
user.save_seen_dm(last_dm)
return reports
except tweepy.RateLimitError:
logger.error("Twitter API Error: Rate Limit Exceeded",
exc_info=True)
# :todo implement rate limiting
except requests.exceptions.ConnectionError:
logger.error("Twitter API Error: Bad Connection", exc_info=True)
except tweepy.TweepError:
logger.error("Twitter API Error: General Error", exc_info=True)
return []
def post(self, user, report):
pass

View File

@ -7,9 +7,10 @@ import requests
from time import time
import report
from bot import Bot
import tfglobals
logger = logging.getLogger("main")
logger = logging.getLogger(__name__)
class TwitterBot(Bot):
@ -29,11 +30,9 @@ class TwitterBot(Bot):
:return: reports: (list of report.Report objects)
"""
reports = []
try:
if user.get_last_twitter_request() + 60 > time():
return reports
except TypeError:
user.set_last_twitter_request(time())
#global last_twitter_request
if tfglobals.last_twitter_request + 60 > time():
return reports
try:
api = self.get_api(user)
except TypeError:
@ -47,12 +46,13 @@ class TwitterBot(Bot):
mentions = api.mentions_timeline()
else:
mentions = api.mentions_timeline(since_id=last_mention)
user.set_last_twitter_request(time())
tfglobals.last_twitter_request = time()
for status in mentions:
if status._json['in_reply_to_status_id'] == None:
text = re.sub(
"(?<=^|(?<=[^a-zA-Z0-9-_\.]))@([A-Za-z]+[A-Za-z0-9-_]+)",
"", status.text)
text = re.sub(
"(?<=^|(?<=[^a-zA-Z0-9-_\.]))@([A-Za-z]+[A-Za-z0-9-_]+)",
"", status.text)
username = "@" + api.me().screen_name
if username in status.text:
reports.append(report.Report(status.author.screen_name,
self,
text,
@ -67,13 +67,13 @@ class TwitterBot(Bot):
except requests.exceptions.ConnectionError:
logger.error("Twitter API Error: Bad Connection", exc_info=True)
except tweepy.TweepError:
logger.error("Twitter API Error: General Error. User: " + str(user.uid), exc_info=True)
logger.error("Twitter API Error: General Error", exc_info=True)
return []
def post(self, user, report):
try:
api = self.get_api(user)
except TypeError:
except IndexError:
return # no twitter account for this user.
try:
if report.source == self:

View File

@ -5,7 +5,8 @@ from config import config
from db import db
import logging
from sendmail import sendmail
from time import sleep
from time import time
def shutdown():
try:
@ -15,15 +16,14 @@ def shutdown():
exit(1)
last_twitter_request = time()
if __name__ == '__main__':
logger = logging.getLogger("main")
logger.setLevel(logging.DEBUG)
logger = logging.getLogger()
fh = logging.FileHandler('/var/log/ticketfrei/backend.log')
formatter = logging.Formatter('%(asctime)s %(levelname)8s: %(message)s')
fh.setFormatter(formatter)
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)
logger.info("Backend Daemon was started...")
bots = []
for ActiveBot in active_bots.__dict__.values():
@ -34,14 +34,12 @@ if __name__ == '__main__':
while True:
for user in db.active_users:
for bot in bots:
sleep(1)
reports = bot.crawl(user)
for status in reports:
if not user.is_appropriate(status):
logger.info("Inaproppriate message: %d %s %s" % (user.uid, status.author, status.text))
continue
for bot2 in bots:
sleep(1)
bot2.post(user, status)
logger.info("Resent: %d %s %s" % (user.uid, status.author, status.text))
except Exception:

View File

@ -1,70 +1,5 @@
import pytoml as toml
import os
def load_env():
"""
load environment variables from the environment. If empty, use default
values from config.toml.example.
:return: config dictionary of dictionaries.
"""
with open('config.toml.example') as defaultconf:
configdict = toml.load(defaultconf)
try:
if os.environ['CONSUMER_KEY'] != "":
configdict['twitter']['consumer_key'] = os.environ['CONSUMER_KEY']
except KeyError:
pass
try:
if os.environ['CONSUMER_SECRET'] != "":
configdict['twitter']['consumer_secret'] = os.environ['CONSUMER_SECRET']
except KeyError:
pass
try:
if os.environ['HOST'] != "":
configdict['web']['host'] = os.environ['HOST']
except KeyError:
pass
try:
if os.environ['PORT'] != "":
configdict['web']['port'] = os.environ['PORT']
except KeyError:
pass
try:
if os.environ['CONTACT'] != "":
configdict['web']['contact'] = os.environ['CONTACT']
except KeyError:
pass
try:
if os.environ['MBOX_USER'] != "":
configdict['mail']['mbox_user'] = os.environ['MBOX_USER']
except KeyError:
pass
try:
if os.environ['DB_PATH'] != "":
configdict['database']['db_path'] = os.environ['DB_PATH']
except KeyError:
pass
return configdict
# read config in TOML format (https://github.com/toml-lang/toml#toml)
try:
with open('config.toml') as configfile:
config = toml.load(configfile)
except FileNotFoundError:
config = load_env()
if __name__ == "__main__":
for category in config:
for key in config[category]:
print(key + "=" + str(config[category][key]))
with open('config.toml') as configfile:
config = toml.load(configfile)

View File

@ -10,7 +10,10 @@ port = 80
contact = "b3yond@riseup.net"
[mail]
mbox_user = "root"
mailserver = "smtp.riseup.net"
user = "user"
passphrase = "sup3rs3cur3"
mbox = "root"
[database]
db_path = "/var/ticketfrei/db.sqlite"

58
db.py
View File

@ -1,13 +1,12 @@
from config import config
import jwt
import logging
from os import urandom, system
from os import urandom
from pylibscrypt import scrypt_mcf
import sqlite3
from time import sleep, time
logger = logging.getLogger("main")
logger = logging.getLogger(__name__)
class DB(object):
@ -15,25 +14,13 @@ class DB(object):
self.conn = sqlite3.connect(dbfile)
self.cur = self.conn.cursor()
self.create()
self.secret = self.get_secret()
def execute(self, *args, **kwargs):
return self.cur.execute(*args, **kwargs)
def commit(self):
start_time = time()
while 1:
try:
self.conn.commit()
break
except sqlite3.OperationalError as error:
# another thread may be writing, give it a chance to finish
sleep(0.5)
logger.exception()
if time() - start_time > 5:
# if it takes this long, something is wrong
system("rcctl restart frontend_daemon")
logger.warning("frontend_daemon is getting restarted")
self.conn.commit()
self.conn.commit()
def close(self):
self.conn.close()
@ -128,6 +115,13 @@ class DB(object):
FOREIGN KEY(twitter_accounts_id)
REFERENCES twitter_accounts(id)
);
CREATE TABLE IF NOT EXISTS telegram_accounts (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
user_id INTEGER,
api_token TEXT,
active INTEGER,
FOREIGN KEY(user_id) REFERENCES user(id)
);
CREATE TABLE IF NOT EXISTS telegram_subscribers (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
user_id INTEGER,
@ -147,12 +141,6 @@ class DB(object):
mail_date REAL,
FOREIGN KEY(user_id) REFERENCES user(id)
);
CREATE TABLE IF NOT EXISTS twitter_last_request (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
user_id INTEGER,
date INTEGER,
FOREIGN KEY(user_id) REFERENCES user(id)
);
CREATE TABLE IF NOT EXISTS cities (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
user_id INTEGER,
@ -202,7 +190,7 @@ class DB(object):
'passhash': scrypt_mcf(
password.encode('utf-8')
).decode('ascii')
}, self.get_secret()).decode('ascii')
}, self.secret).decode('ascii')
def mail_subscription_token(self, email, city):
"""
@ -216,17 +204,17 @@ class DB(object):
token = jwt.encode({
'email': email,
'city': city
}, self.get_secret()).decode('ascii')
}, self.secret).decode('ascii')
return token
def confirm_subscription(self, token):
json = jwt.decode(token, self.get_secret())
json = jwt.decode(token, self.secret)
return json['email'], json['city']
def confirm(self, token, city):
from user import User
try:
json = jwt.decode(token, self.get_secret())
json = jwt.decode(token, self.secret)
except jwt.DecodeError:
return None # invalid token
if 'passhash' in json.keys():
@ -258,19 +246,17 @@ u\d\d?"""
else:
uid = json['uid']
with open("/etc/aliases", "a+") as f:
f.write(city + ": " + config["mail"]["mbox_user"] + "\n")
try:
os.system("newaliases")
except:
logger.exception()
f.write(city + ": " + config["mail"]["mbox_user"])
self.execute("INSERT INTO email (user_id, email) VALUES(?, ?);",
(uid, json['email']))
self.execute("""INSERT INTO telegram_accounts (user_id, apikey,
active) VALUES(?, ?, ?);""", (uid, "", 1))
self.execute("INSERT INTO seen_telegrams (user_id, tg_id) VALUES (?, ?);", (uid, 0))
self.execute("INSERT INTO seen_mail (user_id, mail_date) VALUES (?, ?);", (uid, 0))
self.execute("INSERT INTO seen_tweets (user_id, tweet_id) VALUES (?, ?)", (uid, 0))
self.execute("INSERT INTO twitter_last_request (user_id, date) VALUES (?, ?)", (uid, 0))
self.execute(
"INSERT INTO seen_telegrams (user_id, tg_id) VALUES (?, ?);", (uid, 0))
self.execute(
"INSERT INTO seen_mail (user_id, mail_date) VALUES (?, ?);", (uid, 0))
self.execute("INSERT INTO seen_tweets (user_id, tweet_id) VALUES (?, ?)",
(uid, 0))
self.commit()
user = User(uid)
user.set_city(city)

View File

@ -1,15 +0,0 @@
#!/bin/ksh
daemon="/usr/local/bin/python3 /srv/ticketfrei/backend.py"
daemon_user="root"
. /etc/rc.d/rc.subr
rc_bg=YES
rc_reload=NO
rc_start() {
rc_exec "cd /srv/ticketfrei; /usr/bin/nice -n15 ${daemon} ${daemon_flags}"
}
rc_cmd $1

View File

@ -1,15 +0,0 @@
#!/bin/ksh
. /etc/borg-env
export BORG_REPO=nathan@nephilim:repositories-borg/ticketfrei
export BORG_RSH="ssh \
-o TCPKeepAlive=no \
-o ServerAliveInterval=15 \
-o ServerAliveCountMax=10 \
-o Compression=no"
rcctl stop backend_daemon
rcctl stop frontend_daemon
/usr/local/bin/borg create --stats ::'backup{now:%Y%m%d-%H%M}' /srv/ticketfrei /var/ticketfrei /etc
rcctl start backend_daemon
rcctl start frontend_daemon

View File

@ -0,0 +1,31 @@
server {
listen 443 ssl;
server_name example.org;
ssl_certificate /etc/letsencrypt/live/example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.org/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
access_log /var/log/nginx/example.org_access.log;
error_log /var/log/nginx/example.org_error.log;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
include uwsgi_params;
uwsgi_pass unix:///var/run/ticketfrei/ticketfrei.sock;
}
location /.well-known/acme-challenge {
root /var/www/acme;
}
}
server {
listen 80;
listen [::]:80;
server_name example.org;
return 301 https://$server_name$request_uri;
}

View File

@ -1,15 +0,0 @@
#!/bin/ksh
daemon="/usr/local/bin/python3 /srv/ticketfrei/frontend.py"
daemon_user="frontend"
. /etc/rc.d/rc.subr
rc_bg=YES
rc_reload=NO
rc_start() {
rc_exec "env > /tmp/envars; cd /srv/ticketfrei; ${daemon} ${daemon_flags}"
}
rc_cmd $1

View File

@ -0,0 +1,17 @@
[Unit]
Description=Ticketfrei Backend
After=syslog.target network.target
[Service]
WorkingDirectory=/srv/ticketfrei
ExecStart=/srv/ticketfrei/bin/python3 backend.py
# Requires systemd version 211 or newer
#RuntimeDirectory=uwsgi
Restart=always
KillSignal=SIGQUIT
Type=simple
StandardError=syslog
NotifyAccess=all
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,17 @@
[Unit]
Description=Ticketfrei Web Application
After=syslog.target network.target
[Service]
WorkingDirectory=/srv/ticketfrei
ExecStart=/usr/bin/uwsgi --ini /srv/ticketfrei/deployment/uwsgi.ini
# Requires systemd version 211 or newer
RuntimeDirectory=uwsgi
Restart=always
KillSignal=SIGQUIT
Type=notify
StandardError=syslog
NotifyAccess=all
[Install]
WantedBy=multi-user.target

View File

@ -45,7 +45,7 @@ def register_post():
sendmail(
email,
"Confirm your account",
body="Complete your registration here: %s" % (link)
"Complete your registration here: %s" % (link)
)
return dict(info='Confirmation mail sent.')
except Exception:
@ -56,22 +56,11 @@ def register_post():
@get('/confirm/<city>/<token>')
@view('template/propaganda.tpl')
def confirm(city, token):
# check whether city already exists
if db.by_city(city):
return dict(error='This Account was already confirmed, please try '
'signing in.')
# create db-entry
if db.confirm(token, city):
# :todo show info "Account creation successful."
redirect('/settings')
return dict(error='Account creation failed. Please try to register again.')
@get('/version')
def version():
import git
repo = git.Repo(search_parent_directories=True)
return repo.head.object.hexsha
return dict(error='Email confirmation failed.')
@post('/login')
@ -116,7 +105,7 @@ def subscribe_mail(city):
# send mail with code to email
sendmail(email, "Subscribe to Ticketfrei " + city + " Mail Notifications",
body="To subscribe to the mail notifications for Ticketfrei " +
city + ", click on this link: " + confirm_link, city=city)
city + ", click on this link: " + confirm_link)
return city_page(city, info="Thanks! You will receive a confirmation mail.")
@ -178,10 +167,9 @@ def register_telegram(user):
return city_page(user.get_city(), info="Thanks for registering Telegram!")
# unused afaik
#@get('/api/state')
#def api_enable(user):
# return user.state()
@get('/api/state')
def api_enable(user):
return user.state()
@get('/static/<filename:path>')
@ -198,7 +186,6 @@ def guides(filename):
def logout():
# clear auth cookie
response.set_cookie('uid', '', expires=0, path="/")
response.set_cookie('csrf', '', expires=0, path="/")
# :todo show info "Logout successful."
redirect('/')
@ -257,6 +244,11 @@ def login_mastodon(user):
try:
access_token = m.log_in(masto_email, masto_pass)
user.save_masto_token(access_token, instance_url)
# Trying to set the seen_toot to 0, thereby initializing it.
# It should work now, but has default values. Not sure if I need them.
user.init_seen_toot(instance_url)
return city_page(user.get_city(), info='Thanks for supporting decentralized social networks!')
except Exception:
logger.error('Login to Mastodon failed.', exc_info=True)
@ -272,6 +264,7 @@ application = bottle.default_app()
bottle.install(SessionPlugin('/'))
if __name__ == '__main__':
bottle.run(host="0.0.0.0", port=config["web"]["port"])
# testing only
bottle.run(host=config["web"]["host"], port=config["web"]["port"])
else:
application.catchall = False

BIN
guides/toot_screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

43
guides/use.md Normal file
View File

@ -0,0 +1,43 @@
# How to use Ticketfrei
Do you want to help sousveilling ticket controllers?
## Do you want to know if it's safe to ride without a ticket at the moment?
Just look at the profile of the bot: https://chaos.social/@nbg_ticketfrei
Do you see a toot, reporting ticket controllers?
* If yes, you should probably buy a ticket for now.
In Nuremberg we made the experience that ticket controllers are usually active for about a week, a few hours every day.
So if you see that there was a warning in the last days, watch out.
* If no, you are probably fine! Dare to ride without a ticket.
We can't guarantee that you will be safe though, so still watch out.
The more people participate, the more you can trust that controllers are reported before you run into them.
So, if you have bad luck and are the first one to see the controller:
## Do you want to help others, who ride public transport without a ticket?
That's easy. You only need an Mastodon account, for example at
* https://queer.party/about
* https://soc.ialis.me/about
* https://witches.town/about
* https://kitty.town/about
* https://social.coop/about
* https://awoo.space/about
Using a twitter account or sending a mail is also possible!
Just write a toot or a tweet, mentioning the bot, and tell it
* Where you saw the ticket controllers
* Which line they are using, into which direction
For example like this:
![Screenshot of tooting](tooting_screenshot.png)
![A toot ready to be boosted](toot_screenshot.png)
The bot will soon share your message, so other people will be able to look at it and be safe.
Thanks for helping to provide public transport for everyone!

4
logs/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View File

@ -1,9 +0,0 @@
tweepy
pytoml
Mastodon.py
bottle
pyjwt
pylibscrypt
Markdown
twx
gitpython

View File

@ -8,7 +8,7 @@ import smtplib
from socket import getfqdn
logger = logging.getLogger("main")
logger = logging.getLogger(__name__)
def sendmail(to, subject, city=None, body=''):
@ -27,5 +27,5 @@ def sendmail(to, subject, city=None, body=''):
# For testing:
if __name__ == '__main__':
sendmail(config['web']['contact'], "Test Mail",
sendmail(config['mail']['contact'], "Test Mail",
body="This is a test mail.")

View File

@ -1,4 +1,4 @@
from bottle import redirect, request, abort, response
from bottle import redirect, request
from db import db
from functools import wraps
from inspect import Signature
@ -17,14 +17,10 @@ class SessionPlugin(object):
if self.keyword in Signature.from_callable(route.callback).parameters:
@wraps(callback)
def wrapper(*args, **kwargs):
uid = request.get_cookie('uid', secret=db.get_secret())
uid = request.get_cookie('uid', secret=db.secret)
if uid is None:
return redirect(self.loginpage)
kwargs[self.keyword] = User(uid)
if request.method == 'POST':
if request.forms['csrf'] != request.get_cookie('csrf',
secret=db.get_secret()):
abort(400)
return callback(*args, **kwargs)
return wrapper

View File

@ -1,6 +1,6 @@
body {
background-image: url(/static/img/ticketfrei-og-image.jpg);
background-height: 100%;
background-size: 50%;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-size: 12pt;
line-height: 1.5em;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 628 KiB

After

Width:  |  Height:  |  Size: 570 KiB

View File

@ -15,14 +15,13 @@
your city into a paradise for fare dodgers.
</p>
<p>
Ticketfrei is a Twitter, Mastodon, Telegram, and E-Mail
bot. Users can help each other by tweeting, tooting,
messaging, or mailing, when and where they spot a ticket
controller.
Ticketfrei is a Twitter, Mastodon, and E-Mail bot. Users
can help each other by tweeting, tooting, or mailing,
when and where they spot a ticket controller.
</p>
<p>
Ticketfrei automatically spreads those controller reports
in the other networks, so others can see them. If there
Ticketfrei automatically retweets, boosts, and remails
those controller reports, so others can see them. If there
are ticket controllers around, they can still buy a ticket
- but if the coast is clear, they can save the money.
</p>
@ -32,26 +31,22 @@
to other citys. There are four basic steps:
</p>
<ul>
<li>Create a Twitter and/or a Mastodon account.</li>
<li>Register on this website to create a bot for your city.</li>
<li>Create a Twitter, a Telegram, and/or a Mastodon account.</li>
<li>Log in with the social media accounts you want to
use for Ticketfrei.</li>
<li>Promote the service! Ticketfrei only works if there is
a community for it. Fortunately, we prepared some material
you can edit, remix, use, and republish:
<a href="https://github.com/ticketfrei/promotion" target="_blank">https://github.com/ticketfrei/promotion</a>
<ul>
<li>If you build cool promotion material yourself, please
share it with us, so others can use it, too!</li>
</ul></li>
you can use:
<a href="https://github.com/ticketfrei/promotion" target="_blank">https://github.com/ticketfrei/promotion</a></li>
</ul>
% include('template/register-plain.tpl')
<h2>Our Mission</h2>
<p>
Public transportation is meant to provide an easy and
time-saving way to move within a region while being
affordable for everybody. Unfortunately, this is not yet
the case. Ticketfrei's approach is to enable people to
affordable for everybody. Unfortunately, this is not the
case. Ticketfrei's approach is to enable people to
reclaim public transportation.
</p>
<p>
@ -63,7 +58,7 @@
<p>
Because with Ticketfrei you're able to use trains and
subways for free anyway. Take part and create a new
understanding of what public transportation could look
understanding of what public transportation should look
like!
</p>

View File

@ -61,7 +61,6 @@
<option value='octodon.social'>
<option value='soc.ialis.me'>
</datalist>
<input name='csrf' value='{{csrf}}' type='hidden' />
<input name='confirm' value='Log in' type='submit'/>
</form>
</section>
@ -83,7 +82,6 @@
</p>
<form action="/settings/telegram" method="post">
<input type="text" name="apikey" placeholder="Telegram bot API key" id="apikey">
<input name='csrf' value='{{csrf}}' type='hidden' />
<input name='confirm' value='Login with Telegram' type='submit'/>
</form>
</div>
@ -108,7 +106,6 @@
</p>
<form action="/settings/markdown" method="post">
<textarea id="markdown" rows="20" cols="70" name="markdown" wrap="physical">{{markdown}}</textarea>
<input name='csrf' value='{{csrf}}' type='hidden' />
<input name='confirm' value='Save' type='submit'/>
</form>
</div>
@ -126,7 +123,6 @@
</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='csrf' value='{{csrf}}' type='hidden' />
<input name='confirm' value='Save' type='submit'/>
</form>
</div>
@ -141,7 +137,6 @@
</p>
<form action="/settings/goodlist" method="post">
<textarea id="goodlist" rows="8" cols="70" name="goodlist" wrap="physical">{{triggerwords}}</textarea>
<input name='csrf' value='{{csrf}}' type='hidden' />
<input name='confirm' value='Submit' type='submit'/>
</form>
</div>
@ -156,7 +151,6 @@
</p>
<form action="/settings/blocklist" method="post">
<textarea id="blocklist" rows="8" cols="70" name="blocklist" wrap="physical">{{badwords}}</textarea>
<input name='csrf' value='{{csrf}}' type='hidden' />
<input name='confirm' value='Submit' type='submit'/>
</form>
</div>

10
tfglobals.py Normal file
View File

@ -0,0 +1,10 @@
from time import time
"""
This file is for shared global variables. They only stay during runtime.
For reference:
https://stackoverflow.com/questions/15959534/visibility-of-global-variables-in-imported-modules
"""
last_twitter_request = time()

141
user.py
View File

@ -1,26 +1,16 @@
from config import config
from bottle import response, request
from bottle import response
from db import db
import jwt
from mastodon import Mastodon
from pylibscrypt import scrypt_mcf, scrypt_mcf_check
from os import urandom
import logging
logger = logging.getLogger("main")
class User(object):
def __init__(self, uid):
# set cookie
response.set_cookie('uid', uid, secret=db.get_secret(), path='/')
response.set_cookie('uid', uid, secret=db.secret, path='/')
self.uid = uid
response.set_cookie('csrf', self.get_csrf(), db.get_secret(), path='/')
def get_csrf(self):
csrf_token = request.get_cookie('csrf', secret=db.get_secret())
if not csrf_token:
csrf_token = str(urandom(32))
return csrf_token
def check_password(self, password):
db.execute("SELECT passhash FROM user WHERE id=?;", (self.uid,))
@ -65,7 +55,7 @@ class User(object):
return jwt.encode({
'email': email,
'uid': self.uid
}, db.get_secret()).decode('ascii')
}, db.secret).decode('ascii')
def is_appropriate(self, report):
db.execute("SELECT patterns FROM triggerpatterns WHERE user_id=?;",
@ -76,7 +66,6 @@ class User(object):
break
else:
# no pattern matched
logger.error("Message didn't trigger goodlist: " + report.text)
return False
default_badwords = """
bitch
@ -96,38 +85,25 @@ schlitz
db.execute("SELECT words FROM badwords WHERE user_id=?;",
(self.uid, ))
badwords = db.cur.fetchone()
for word in report.text.lower().split():
if word in badwords[0].splitlines():
logger.error("Word " + word + " triggered the spam filter on message: " + report.text)
for word in report.text.lower().splitlines():
if word in badwords:
return False
for word in report.text.lower().split():
if word in default_badwords.splitlines():
logger.error("Word " + word + " triggered the spam filter on message: " + report.text)
for word in default_badwords.splitlines():
if word in badwords:
return False
logger.info("Valid report: " + report.text + " | username: " + report.author)
return True
def get_last_twitter_request(self):
db.execute("SELECT date FROM twitter_last_request WHERE user_id = ?;",
(self.uid,))
return db.cur.fetchone()[0]
def set_last_twitter_request(self, date):
db.execute("UPDATE twitter_last_request SET date = ? WHERE user_id = ?;",
(date, self.uid))
db.commit()
def get_telegram_credentials(self):
db.execute("""SELECT apikey
FROM telegram_accounts
db.execute("""SELECT apikey
FROM telegram_accounts
WHERE user_id = ? AND active = 1;""",
(self.uid,))
row = db.cur.fetchone()
return row[0]
def get_telegram_subscribers(self):
db.execute("""SELECT subscriber_id
FROM telegram_subscribers
db.execute("""SELECT subscriber_id
FROM telegram_subscribers
WHERE user_id = ?;""",
(self.uid,))
rows = db.cur.fetchall()
@ -140,21 +116,21 @@ schlitz
db.commit()
def remove_telegram_subscribers(self, subscriber_id):
db.execute("""DELETE
FROM telegram_subscribers
db.execute("""DELETE
FROM telegram_subscribers
WHERE user_id = ?
AND subscriber_id = ?;""",
(self.uid, subscriber_id))
db.commit()
def get_masto_credentials(self):
db.execute("""SELECT access_token, instance_id
FROM mastodon_accounts
db.execute("""SELECT access_token, instance_id
FROM mastodon_accounts
WHERE user_id = ? AND active = 1;""",
(self.uid,))
row = db.cur.fetchone()
db.execute("""SELECT instance, client_id, client_secret
FROM mastodon_instances
db.execute("""SELECT instance, client_id, client_secret
FROM mastodon_instances
WHERE id = ?;""",
(row[1],))
instance = db.cur.fetchone()
@ -249,7 +225,6 @@ schlitz
# - mail_md
# - goodlist
# - blocklist
# - csrf
# - logged in with twitter?
# - logged in with mastodon?
# - enabled?
@ -259,8 +234,7 @@ schlitz
mail_md=citydict['mail_md'],
triggerwords=self.get_trigger_words(),
badwords=self.get_badwords(),
enabled=self.enabled,
csrf=self.get_csrf())
enabled=self.enabled)
def save_request_token(self, token):
db.execute("""INSERT INTO
@ -272,11 +246,11 @@ schlitz
db.commit()
def get_request_token(self):
db.execute("""SELECT request_token, request_token_secret
FROM twitter_request_tokens
db.execute("""SELECT request_token, request_token_secret
FROM twitter_request_tokens
WHERE user_id = ?;""", (self.uid,))
request_token = db.cur.fetchone()
db.execute("""DELETE FROM twitter_request_tokens
db.execute("""DELETE FROM twitter_request_tokens
WHERE user_id = ?;""", (self.uid,))
db.commit()
return {"oauth_token": request_token[0],
@ -287,8 +261,6 @@ schlitz
user_id, client_id, client_secret
) VALUES(?, ?, ?);""",
(self.uid, access_token, access_token_secret))
db.execute("""INSERT INTO seen_tweets(user_id, tweet_id) VALUES (?, ?);""",
(self.uid, 0))
db.commit()
def get_twitter_token(self):
@ -309,8 +281,8 @@ schlitz
db.commit()
def get_mastodon_app_keys(self, instance):
db.execute("""SELECT client_id, client_secret
FROM mastodon_instances
db.execute("""SELECT client_id, client_secret
FROM mastodon_instances
WHERE instance = ?;""", (instance,))
try:
row = db.cur.fetchone()
@ -318,7 +290,7 @@ schlitz
client_secret = row[1]
return client_id, client_secret
except TypeError:
app_name = "ticketfrei" + str(db.get_secret())[0:4]
app_name = "ticketfrei" + str(db.secret)[0:4]
client_id, client_secret \
= Mastodon.create_app(app_name, api_base_url=instance)
db.execute("""INSERT INTO mastodon_instances(
@ -329,8 +301,8 @@ schlitz
return client_id, client_secret
def save_masto_token(self, access_token, instance):
db.execute("""SELECT id
FROM mastodon_instances
db.execute("""SELECT id
FROM mastodon_instances
WHERE instance = ?;""", (instance,))
instance_id = db.cur.fetchone()[0]
db.execute("INSERT INTO mastodon_accounts(user_id, access_token, instance_id, active) "
@ -366,28 +338,25 @@ 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
* 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
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,
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
Aber je mehr Leute mitmachen, desto eher kannst du dir sicher
sein, dass wir sie finden, bevor sie uns finden.
Wenn du immer direkt gewarnt werden willst, kannst du auch die
Benachrichtigungen über E-Mail, Telegram, oder den Mastodon RSS
feed aktivieren. Entweder:
* Gibt hier [deine E-Mail-Adresse an](/city/mail/""" + city + """)
* Subscribe dem Telegram-Bot [@ticketfrei_""" + city + \
"_bot](https://t.me/ticketfrei_" + city + """_bot)
* oder subscribe dem RSS feed von [""" + city + """](""" + masto_link + \
""".atom?replies=false&boosts=true)
Benachrichtigungen über E-Mail oder Telegram aktivieren. Gib
einfach <a href="/city/mail/""" + city + """"/">hier</a> deine
E-Mail-Adresse an oder subscribe dem Telegram-Bot [@ticketfrei_""" + city + \
"_bot](https://t.me/ticketfrei_" + city + """_bot)
Also, wenn du weniger Glück hast, und der erste bist, der einen
Also, wenn du weniger Glück hast, und der erste bist, der einen
Kontrolleur sieht:
## Was mache ich, wenn ich Kontis sehe?
@ -398,10 +367,10 @@ Ganz einfach, du schreibst es den anderen. Das geht entweder
* über Twitter: [Link zu unserem Profil](""" + twit_link + """)
* über Telegram an [@ticketfrei_""" + city + "_bot](https://t.me/ticketfrei_" \
+ city + """_bot)
* Oder per Mail an [""" + mailinglist + "](mailto:" + mailinglist + """), wenn
* Oder per Mail an [""" + mailinglist + "](mailto:" + mailinglist + """), wenn
ihr kein Social Media benutzen wollt.
Schreibe einfach einen Toot oder einen Tweet, der den Bot
Schreibe einfach einen Toot oder einen Tweet, der den Bot
mentioned, und gib an
* Wo du die Kontis gesehen hast
@ -409,15 +378,15 @@ mentioned, und gib an
Zum Beispiel so:
![Screenshot of writing a Toot](https://github.com/b3yond/ticketfrei/raw/stable1/guides/tooting_screenshot.png)
![Screenshot of writing a Toot](https://github.com/b3yond/ticketfrei/raw/master/guides/tooting_screenshot.png)
![A toot ready to be shared](https://github.com/b3yond/ticketfrei/raw/stable1/guides/toot_screenshot.png)
![A toot ready to be shared](https://github.com/b3yond/ticketfrei/raw/master/guides/toot_screenshot.png)
Der Bot wird die Nachricht dann weiterverbreiten, auch zu den
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
Danke, dass du mithilfst, öffentlichen Verkehr für alle
sicherzustellen!
## Kann ich darauf vertrauen, was random stranger from the Internet mir da erzählen?
@ -426,31 +395,31 @@ Aber natürlich! Wir haben Katzenbilder!
![Katzenbilder!](https://lorempixel.com/550/300/cats)
Glaubt besser nicht, wenn jemand postet, dass die Luft da und
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
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
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
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
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
Mastodon ist ein dezentrales soziales Netzwerk - so wie
Twitter, nur ohne Monopol und Zentralismus.
Ihr könnt Kurznachrichten (Toots) über alles mögliche
Ihr könnt Kurznachrichten (Toots) über alles mögliche
schreiben, und euch mit anderen austauschen.
Mastodon ist Open Source, Privatsphäre-freundlich und relativ
Mastodon ist Open Source, Privatsphäre-freundlich und relativ
sicher vor Zensur.
Um Mastodon zu benutzen, besucht diese Seite:
Um Mastodon zu benutzen, besucht diese Seite:
[https://joinmastodon.org/](https://joinmastodon.org/)
"""
mail_md = """# Immer up-to-date
@ -460,15 +429,15 @@ 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
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
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.
unsubscribe-link mitgeschickt.
"""
db.execute("""INSERT INTO cities(user_id, city, markdown, mail_md,
masto_link, twit_link) VALUES(?,?,?,?,?,?)""",