Compare commits

..

8 commits

Author SHA1 Message Date
b3yond 8c778927ee fixing import error 2019-05-17 20:42:13 +02:00
b3yond 079166e74c
Merge pull request #86 from ticketfrei/masto502
don't log Mastodon 502 errors.
2019-05-04 12:04:51 +02:00
b3yond fb15771cf2
Merge pull request #93 from ticketfrei/images
Notify that telegram image reports are not supported. #90
2019-05-04 10:23:34 +02:00
sid d1b11fe932
Update active_bots/telegrambot.py
Co-Authored-By: b3yond <b3yond@riseup.net>
2019-05-04 10:22:03 +02:00
b3yond c30f9d8eaa
Merge pull request #87 from ticketfrei/fix-none-error
fixed wrong exception
2019-05-03 17:11:25 +02:00
b3yond 7a7e8f0a30 Notify that telegram image reports are not supported. #90 2019-05-03 14:35:06 +02:00
b3yond e18244e149 don't log Mastodon 502 errors. 2019-05-03 10:07:16 +02:00
b3yond cd3c8be2dc fixed wrong exception 2019-02-19 16:16:21 +01:00
72 changed files with 214 additions and 348 deletions

3
.gitignore vendored
View file

@ -1,7 +1,5 @@
*.swp
*.pyc
*.egg-info/
*.eggs
.idea/
__pycache__/
last_mention
@ -19,3 +17,4 @@ include/
lib/
share/
local/
venv/

View file

@ -32,15 +32,13 @@ 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.
In version 3, this repository contains a web application. On this website,
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, which run in parallel. This way, you do not have to
host it yourself, if you lack the know-how. But it is easily possible to do so
with docker: http://github.com/ticketfrei/docker-ticketfrei/
bots for multiple citys. This way, you do not have to host it yourself.
In https://github.com/ticketfrei/promotion, 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!
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

View file

@ -2,7 +2,7 @@
from bot import Bot
import logging
from mastodon import Mastodon
import mastodon
import re
from report import Report
@ -19,14 +19,14 @@ class MastodonBot(Bot):
"""
mentions = []
try:
m = Mastodon(*user.get_masto_credentials())
m = mastodon.Mastodon(*user.get_masto_credentials())
except TypeError:
# logger.error("No Mastodon Credentials in database.", exc_info=True)
return mentions
try:
notifications = m.notifications()
except Exception:
logger.error("Unknown Mastodon API Error.", exc_info=True)
except mastodon.MastodonServerError:
logger.error("Unknown Mastodon API Error: 502")
return mentions
for status in notifications:
if (status['type'] == 'mention' and
@ -54,7 +54,7 @@ class MastodonBot(Bot):
def post(self, user, report):
try:
m = Mastodon(*user.get_masto_credentials())
m = mastodon.Mastodon(*user.get_masto_credentials())
except TypeError:
return # no mastodon account for this user.
if report.source == self:

View file

@ -32,6 +32,12 @@ class TelegramBot(Bot):
logger.error("Unknown Telegram error code: " + str(update))
return reports
user.save_seen_tg(update.update_id)
if update.message.photo:
tb.send_message(
update.message.sender.id,
"Sending Photos is not supported 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(

View file

@ -73,7 +73,7 @@ class TwitterBot(Bot):
def post(self, user, report):
try:
api = self.get_api(user)
except IndexError:
except TypeError:
return # no twitter account for this user.
try:
if report.source == self:

View file

@ -17,7 +17,7 @@ def shutdown():
if __name__ == '__main__':
logger = logging.getLogger()
fh = logging.FileHandler(config["log"]["log_backend"])
fh = logging.FileHandler('/var/log/ticketfrei/backend.log')
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)

View file

@ -1,10 +1,6 @@
import pytoml as toml
import os
ROOT_DIR = os.path.dirname(os.path.realpath(__file__))
TEMPLATE_DIR = os.path.join(ROOT_DIR, 'template', '')
STATIC_DIR = os.path.join(ROOT_DIR, 'static', '')
BOT_DIR = os.path.join(ROOT_DIR, 'bots')
def load_env():
"""
@ -13,7 +9,7 @@ def load_env():
:return: config dictionary of dictionaries.
"""
with open(os.path.join(ROOT_DIR, 'config.toml.example')) as defaultconf:
with open('config.toml.example') as defaultconf:
configdict = toml.load(defaultconf)
try:
@ -58,24 +54,12 @@ def load_env():
except KeyError:
pass
try:
if os.environ['LOG_FRONTEND'] != "":
configdict['log']['log_frontend'] = os.environ['LOG_FRONTEND']
except KeyError:
pass
try:
if os.environ['LOG_BACKEND'] != "":
configdict['log']['log_backend'] = os.environ['LOG_BACKEND']
except KeyError:
pass
return configdict
# read config in TOML format (https://github.com/toml-lang/toml#toml)
try:
with open(os.path.join(ROOT_DIR, 'config.toml')) as configfile:
with open('config.toml') as configfile:
config = toml.load(configfile)
except FileNotFoundError:
config = load_env()

View file

@ -11,11 +11,6 @@ contact = "b3yond@riseup.net"
[mail]
mbox_user = "root"
aliases_path = "/etc/aliases"
[database]
db_path = "/var/ticketfrei/db.sqlite"
[log]
log_frontend = "/var/ticketfrei/frontend.log"
log_backend = "/var/log/ticketfrei/backend.log"

View file

@ -243,7 +243,7 @@ u\d\d?"""
(uid, "bastard"))
else:
uid = json['uid']
with open(config['mail']['aliases_path'], "a+") as f:
with open("/etc/aliases", "a+") as f:
f.write(city + ": " + config["mail"]["mbox_user"] + "\n")
self.execute("INSERT INTO email (user_id, email) VALUES(?, ?);",
(uid, json['email']))

View file

@ -1,8 +1,7 @@
#!/usr/bin/env python3
import bottle
from os import listdir, path
from bottle import get, post, redirect, request, response, view
from config import config, STATIC_DIR, TEMPLATE_DIR
from config import config
from db import db
import logging
import tweepy
@ -19,13 +18,13 @@ def url(route):
@get('/')
@view('propaganda.tpl')
@view('template/propaganda.tpl')
def propaganda():
pass
@post('/register')
@view('register.tpl')
@view('template/register.tpl')
def register_post():
try:
email = request.forms['email']
@ -55,7 +54,7 @@ def register_post():
@get('/confirm/<city>/<token>')
@view('propaganda.tpl')
@view('template/propaganda.tpl')
def confirm(city, token):
# check whether city already exists
if db.by_city(city):
@ -76,7 +75,7 @@ def version():
@post('/login')
@view('login.tpl')
@view('template/login.tpl')
def login_post():
# check login
try:
@ -95,14 +94,14 @@ def city_page(city, info=None):
citydict = db.user_facing_properties(city)
if citydict is not None:
citydict['info'] = info
return bottle.template('city.tpl', **citydict)
return bottle.template('propaganda.tpl',
return bottle.template('template/city.tpl', **citydict)
return bottle.template('template/propaganda.tpl',
**dict(info='There is no Ticketfrei bot in your city'
' yet. Create one yourself!'))
@get('/city/mail/<city>')
@view('mail.tpl')
@view('template/mail.tpl')
def display_mail_page(city):
user = db.by_city(city)
return user.state()
@ -139,34 +138,34 @@ def unsubscribe(token):
@get('/settings')
@view('settings.tpl')
@view('template/settings.tpl')
def settings(user):
return user.state()
@post('/settings/markdown')
@view('settings.tpl')
@view('template/settings.tpl')
def update_markdown(user):
user.set_markdown(request.forms['markdown'])
return user.state()
@post('/settings/mail_md')
@view('settings.tpl')
@view('template/settings.tpl')
def update_mail_md(user):
user.set_mail_md(request.forms['mail_md'])
return user.state()
@post('/settings/goodlist')
@view('settings.tpl')
@view('template/settings.tpl')
def update_trigger_patterns(user):
user.set_trigger_words(request.forms['goodlist'])
return user.state()
@post('/settings/blocklist')
@view('settings.tpl')
@view('template/settings.tpl')
def update_badwords(user):
user.set_badwords(request.forms['blocklist'])
return user.state()
@ -187,12 +186,12 @@ def register_telegram(user):
@get('/static/<filename:path>')
def static(filename):
return bottle.static_file(filename, root=STATIC_DIR)
return bottle.static_file(filename, root='static')
# IS THIS USED?
#@get('/guides/<filename:path>')
#def guides(filename):
# return bottle.static_file(filename, root='guides')
@get('/guides/<filename:path>')
def guides(filename):
return bottle.static_file(filename, root='guides')
@get('/logout/')
@ -265,12 +264,10 @@ def login_mastodon(user):
logger = logging.getLogger()
fh = logging.FileHandler(config['log']['log_frontend'])
fh = logging.FileHandler('/var/log/ticketfrei/error.log')
fh.setLevel(logging.DEBUG)
logger.addHandler(fh)
# TODO change TEMPLATE_PATH to BOTS_DIR after refactoring
bottle.TEMPLATE_PATH.insert(0, TEMPLATE_DIR)
application = bottle.default_app()
bottle.install(SessionPlugin('/'))

View file

@ -1,2 +0,0 @@
[aliases]
test=pytest

View file

@ -1,37 +0,0 @@
from setuptools import setup
import sys
import os
PACKAGE_NAME = "ticketfrei"
sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), PACKAGE_NAME))
setup(
name=PACKAGE_NAME,
version='',
packages=[
PACKAGE_NAME
],
url='https://github.com/ticketfrei/ticketfrei',
license='ISC',
author='',
author_email='',
description='',
setup_requires=[
'pytest-runner',
],
install_requires=[
'bottle',
'gitpython',
'pyjwt',
'Markdown',
'Mastodon.py',
'pylibscrypt',
'pytoml',
'tweepy',
'twx',
],
tests_require=[
'pytest',
],
)

View file

Before

Width:  |  Height:  |  Size: 628 KiB

After

Width:  |  Height:  |  Size: 628 KiB

View file

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View file

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View file

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

View file

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View file

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

View file

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View file

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

View file

@ -1,4 +1,4 @@
% rebase('wrapper.tpl')
% rebase('template/wrapper.tpl')
<%
import markdown as md

2
template/login.tpl Normal file
View file

@ -0,0 +1,2 @@
% rebase('template/wrapper.tpl', title='Login')
% include('template/login-plain.tpl')

View file

@ -1,4 +1,4 @@
% rebase('wrapper.tpl')
% rebase('template/wrapper.tpl')
<%
import markdown as md

View file

@ -1,4 +1,4 @@
% rebase('wrapper.tpl')
% rebase('template/wrapper.tpl')
% if defined('info'):
<div class="ui-widget">
<div class="ui-state-highlight ui-corner-all" style="padding: 0.7em;">
@ -7,7 +7,7 @@
</div>
<br>
% end
% include('login-plain.tpl')
% include('template/login-plain.tpl')
<h1>Features</h1>
<p>
Don't pay for public transport. Instead, warn each other
@ -45,7 +45,7 @@
share it with us, so others can use it, too!</li>
</ul></li>
</ul>
% include('register-plain.tpl')
% include('template/register-plain.tpl')
<h2>Our Mission</h2>
<p>
Public transportation is meant to provide an easy and

View file

@ -1,4 +1,4 @@
% rebase('wrapper.tpl', title='Register')
% rebase('template/wrapper.tpl', title='Register')
% if defined('info'):
<div class="ui-widget">
<div class="ui-state-highlight ui-corner-all" style="padding: 0.7em;">
@ -6,5 +6,5 @@
</div>
</div>
% else:
% include('register-plain.tpl')
% include('template/register-plain.tpl')
% end

164
template/settings.tpl Normal file
View file

@ -0,0 +1,164 @@
% rebase('template/wrapper.tpl')
<a href="/logout/"><button>Logout</button></a>
% if enabled:
<div id="enablebutton" style="float: right; padding: 2em;">Disable</div>
% else:
<div id="enablebutton" style="float: right; padding: 2em;" color="red">Enable</div>
% end
<a class='button' style="padding: 1.5em;" href="/login/twitter">
<picture>
<source type='image/webp' sizes='20px' srcset="/static-cb/1517673283/twitter-20.webp 20w,/static-cb/1517673283/twitter-40.webp 40w,/static-cb/1517673283/twitter-80.webp 80w,"/>
<source type='image/png' sizes='20px' srcset="/static-cb/1517673283/twitter-20.png 20w,/static-cb/1517673283/twitter-40.png 40w,/static-cb/1517673283/twitter-80.png 80w,"/>
<img src="https://patriciaannbridewell.files.wordpress.com/2014/04/official-twitter-logo-tile.png" alt="" />
</picture>
Log in with Twitter
</a>
<section>
<h2>Log in with Mastodon</h2>
<form action="/login/mastodon" method='post'>
<label for="email">E-Mail of your Mastodon-Account</label>
<input type="text" placeholder="Enter Email" name="email" id="email" required>
<label for="pass">Mastodon Password</label>
<input type="password" placeholder="Enter Password" name="pass" id="pass" required>
<label>Mastodon instance:
<input type='text' name='instance_url' list='instances' placeholder='social.example.net'/>
</label>
<datalist id='instances'>
<option value=''>
<option value='anticapitalist.party'>
<option value='awoo.space'>
<option value='cybre.space'>
<option value='mastodon.social'>
<option value='glitch.social'>
<option value='botsin.space'>
<option value='witches.town'>
<option value='social.wxcafe.net'>
<option value='monsterpit.net'>
<option value='mastodon.xyz'>
<option value='a.weirder.earth'>
<option value='chitter.xyz'>
<option value='sins.center'>
<option value='dev.glitch.social'>
<option value='computerfairi.es'>
<option value='niu.moe'>
<option value='icosahedron.website'>
<option value='hostux.social'>
<option value='hyenas.space'>
<option value='instance.business'>
<option value='mastodon.sdf.org'>
<option value='pawoo.net'>
<option value='pouet.it'>
<option value='scalie.business'>
<option value='sleeping.town'>
<option value='social.koyu.space'>
<option value='sunshinegardens.org'>
<option value='vcity.network'>
<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>
<%
# todo: hide this part, if there is already a telegram bot connected.
%>
<div>
<h2>Connect with Telegram</h2>
<p>
If you have a Telegram account, you can register a bot there. Just
write to @botfather. There are detailed instructions on
<a href="https://botsfortelegram.com/project/the-bot-father/" target="_blank">
Bots for Telegram</a>.
</p>
<p>
The botfather will give you an API key - with the API key, Ticketfrei
can use the Telegram bot. Enter it here:
</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>
<div>
<h2>Edit your city page</h2>
<p>
With your bot, we generated you a page, which you can use for promotion:
<a href="/city/{{city}}" target="_blank">Ticketfrei {{city}}</a> You
can change what your users will read there, and adjust it to your
needs.
</p>
<p>
<b>You should definitely adjust the Social Media, E-Mail, and Telegram
profile links.</b>
Also consider adding this link to the text: <a href="/city/mail/{{city}}"
target="_blank">Link to the mail subscription page</a>. Your readers
can use this to subscribe to mail notifications.
</p>
<p>
So this is the default text we suggest:
</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>
<div>
<h2>Edit your mail subscription page</h2>
<p>
There is also a page where users can subscribe to mail notifications:
<a href="/city/mail/{{city}}" target="_blank">Ticketfrei {{city}}</a>.
You can change what your users will read there, and adjust it to your
needs.
</p>
<p>
So this is the default text we suggest:
</p>
<form action="/settings/mail_md" method="post">
<textarea id="mail_md" rows="20" cols="70" name="mail_md" wrap="physical">{{mail_md}}</textarea>
<input name='csrf' value='{{csrf}}' type='hidden' />
<input name='confirm' value='Save' type='submit'/>
</form>
</div>
<div>
<h2>Edit your trigger patterns</h2>
<p>
These words have to be contained in a report. If none of these
expressions is in the report, it will be ignored by the bot. You can
use the defaults, or enter some expressions specific to your city and
language.
</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>
<div>
<h2>Edit the blocklist</h2>
<p>
These words are not allowed in reports. If you encounter spam, you can
add more here - the bot will ignore reports which use such words.
There are words which you can't exclude from the blocklist, e.g.
certain racist, sexist, or antisemitic slurs.
</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>

View file

View file

@ -1,19 +0,0 @@
<div>
<h2>Edit your mail subscription page</h2>
<p>
There is also a page where users can subscribe to mail notifications:
<a href="/city/mail/{{city}}" target="_blank">Ticketfrei {{city}}</a>.
You can change what your users will read there, and adjust it to your
needs.
</p>
<p>
So this is the default text we suggest:
</p>
<form action="/settings/mail_md" method="post">
<textarea id="mail_md" rows="20" cols="70" name="mail_md" wrap="physical">{{mail_md}}</textarea>
<input name='csrf' value='{{csrf}}' type='hidden' />
<input name='confirm' value='Save' type='submit'/>
</form>
</div>

View file

@ -1,51 +0,0 @@
<section>
<h2>Log in with Mastodon</h2>
<form action="/login/mastodon" method='post'>
<label for="email">E-Mail of your Mastodon-Account</label>
<input type="text" placeholder="Enter Email" name="email" id="email" required>
<label for="pass">Mastodon Password</label>
<input type="password" placeholder="Enter Password" name="pass" id="pass" required>
<label>Mastodon instance:
<input type='text' name='instance_url' list='instances' placeholder='social.example.net'/>
</label>
<datalist id='instances'>
<option value=''>
<option value='anticapitalist.party'>
<option value='awoo.space'>
<option value='cybre.space'>
<option value='mastodon.social'>
<option value='glitch.social'>
<option value='botsin.space'>
<option value='witches.town'>
<option value='social.wxcafe.net'>
<option value='monsterpit.net'>
<option value='mastodon.xyz'>
<option value='a.weirder.earth'>
<option value='chitter.xyz'>
<option value='sins.center'>
<option value='dev.glitch.social'>
<option value='computerfairi.es'>
<option value='niu.moe'>
<option value='icosahedron.website'>
<option value='hostux.social'>
<option value='hyenas.space'>
<option value='instance.business'>
<option value='mastodon.sdf.org'>
<option value='pawoo.net'>
<option value='pouet.it'>
<option value='scalie.business'>
<option value='sleeping.town'>
<option value='social.koyu.space'>
<option value='sunshinegardens.org'>
<option value='vcity.network'>
<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>

View file

@ -1,23 +0,0 @@
<%
# todo: hide this part, if there is already a telegram bot connected.
%>
<div>
<h2>Connect with Telegram</h2>
<p>
If you have a Telegram account, you can register a bot there. Just
write to @botfather. There are detailed instructions on
<a href="https://botsfortelegram.com/project/the-bot-father/" target="_blank">
Bots for Telegram</a>.
</p>
<p>
The botfather will give you an API key - with the API key, Ticketfrei
can use the Telegram bot. Enter it here:
</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>

View file

@ -1,10 +0,0 @@
<a class='button' style="padding: 1.5em;" href="/login/twitter">
<picture>
<source type='image/webp' sizes='20px' srcset="/static-cb/1517673283/twitter-20.webp 20w,/static-cb/1517673283/twitter-40.webp 40w,/static-cb/1517673283/twitter-80.webp 80w,"/>
<source type='image/png' sizes='20px' srcset="/static-cb/1517673283/twitter-20.png 20w,/static-cb/1517673283/twitter-40.png 40w,/static-cb/1517673283/twitter-80.png 80w,"/>
<img src="https://patriciaannbridewell.files.wordpress.com/2014/04/official-twitter-logo-tile.png" alt="" />
</picture>
Log in with Twitter
</a>

View file

@ -1,2 +0,0 @@
% rebase('wrapper.tpl', title='Login')
% include('login-plain.tpl')

View file

@ -1,76 +0,0 @@
% rebase('wrapper.tpl')
<a href="/logout/"><button>Logout</button></a>
% if enabled:
<div id="enablebutton" style="float: right; padding: 2em;">Disable</div>
% else:
<div id="enablebutton" style="float: right; padding: 2em;" color="red">Enable</div>
% end
<%
# import all the settings templates from bots/*/settings.tpl
from config import BOT_DIR
import os
bots = os.listdir(BOT_DIR)
for bot in bots:
include(os.path.join(BOT_DIR, bot, 'settings.tpl'), csrf=csrf, city=city)
end
%>
<div>
<h2>Edit your city page</h2>
<p>
With your bot, we generated you a page, which you can use for promotion:
<a href="/city/{{city}}" target="_blank">Ticketfrei {{city}}</a> You
can change what your users will read there, and adjust it to your
needs.
</p>
<p>
<b>You should definitely adjust the Social Media, E-Mail, and Telegram
profile links.</b>
Also consider adding this link to the text: <a href="/city/mail/{{city}}"
target="_blank">Link to the mail subscription page</a>. Your readers
can use this to subscribe to mail notifications.
</p>
<p>
So this is the default text we suggest:
</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>
<div>
<h2>Edit your trigger patterns</h2>
<p>
These words have to be contained in a report. If none of these
expressions is in the report, it will be ignored by the bot. You can
use the defaults, or enter some expressions specific to your city and
language.
</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>
<div>
<h2>Edit the blocklist</h2>
<p>
These words are not allowed in reports. If you encounter spam, you can
add more here - the bot will ignore reports which use such words.
There are words which you can't exclude from the blocklist, e.g.
certain racist, sexist, or antisemitic slurs.
</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>

View file

@ -1,20 +0,0 @@
[twitter]
# You get those keys when you follow these steps:
# https://developer.twitter.com/en/docs/basics/authentication/guides/access-tokens
consumer_key = "your_consumer_key"
consumer_secret = "your_consumer_secret"
[web]
host = "0.0.0.0" # will be used by bottle as a host.
port = 80
contact = "b3yond@riseup.net"
[mail]
mbox_user = "root"
[database]
db_path = "/var/ticketfrei/db.sqlite"
[log]
log_frontend = "/var/ticketfrei/frontend.log"
log_backend = "/var/log/ticketfrei/backend.log"

View file

@ -1,23 +0,0 @@
from webtest import TestApp
import unittest
import frontend
app = TestApp(frontend.application)
class TestLogin(unittest.TestCase):
def setUp(self):
pass
def tearDown(self):
pass
def test_login_not_registered(self):
request = app.post('/login', {'email': '', 'pass': ''}, expect_errors=True)
self.assertEqual(401, request.status_code)
def test_login_registered(self):
request = app.post('/register', {'email': 'foo@abc.de', 'pass': 'bar', 'pass-repeat': 'bar', 'city': 'testcity'}, expect_errors=True)
request = app.post('/login', {'email': 'foor@abc.de', 'pass': 'bar'}, expect_errors=False)
self.assertEqual(200, request.status_code)

View file

@ -1,16 +0,0 @@
from webtest import TestApp
import unittest
import frontend
app = TestApp(frontend.application)
class TestRegister(unittest.TestCase):
def test_register(self):
request = app.post('/register', {'email': 'foo@abc.de', 'pass': 'bar', 'pass-repeat': 'bar', 'city': 'testcity'}, expect_errors=True)
self.assertEqual(200, request.status_code)
def test_getRoot(self):
request = app.get('/')
self.assertEqual(200, request.status_code)