Compare commits

...

20 commits

Author SHA1 Message Date
b3yond 833be826e9 fixed a bug with the docker deployment 2019-06-09 11:56:10 +02:00
cookietime--yay 7ef8c3e197 Fix more path issues and add aliases file path to config. 2019-03-06 19:40:02 +01:00
cookietime--yay 768a4350bd Add .eggs to gitignore 2019-03-06 15:40:15 +01:00
cookietime--yay 9906346691 Add ROOT_DIR, TEMPLATE_DIR to config.py. Make paths platform-independent. Add template/ to bottle TEMPLATE_PATH (you can add bots/ this way after complete refactoring). Rename tests to work with pytests. Change setup.py to run pytests. 2019-03-06 15:39:08 +01:00
cookietime--yay f5f741a5c2 Add more test stubs for frontend. 2019-03-04 22:46:42 +01:00
cookietime--yay eabc43cdba Add setup.py file for pip module. 2019-03-04 19:50:00 +01:00
cookietime--yay e4d0fc3b89 Fix reverse assertion in Tests. 2019-03-04 19:49:29 +01:00
cookietime--yay 5c844157ce Cleaning and refactor file structure to work as pip package. 2019-03-04 19:04:18 +01:00
cookietime--yay 050e641bb0 Add initial tests for Web Interface. 2019-03-04 18:55:39 +01:00
cookietime--yay fa3dda1c60 Remove duplicate entry from gitignore and add entries for egg-info. 2019-03-04 18:55:17 +01:00
cookietime--yay 5535d3535f Split log into frontend and backend log. 2019-03-04 15:43:17 +01:00
cookietime--yay 668157c552 Remove hardcoded paths for logs and frontend host. Add log path option to sample config.toml file. 2019-03-04 15:43:17 +01:00
b3yond 39cf3bd070 Merge branch 'templates' into stable3 2019-01-27 23:41:37 +01:00
b3yond 382532cf5c remove redundant import stuff 2019-01-27 23:35:55 +01:00
b3yond cfb9eabee9
Merge pull request #85 from ticketfrei/templates
Templates
2019-01-27 23:17:30 +01:00
b3yond a27d47eb8b templates from bots/*/ are correctly imported 2019-01-27 23:09:25 +01:00
b3yond e34944fcaa started splitting up the templates, wondering how to include them 2019-01-27 22:44:23 +01:00
b3yond d6db1879f9
Merge pull request #84 from ticketfrei/master
Added CSRF protection
2019-01-27 17:59:01 +01:00
b3yond 02f117a864
Merge pull request #82 from ticketfrei/csrf
Building in CSRF prevention
2019-01-27 17:56:53 +01:00
b3yond 4882930516 adjusted the README to the version 3 branch 2019-01-12 10:02:27 +01:00
72 changed files with 342 additions and 202 deletions

3
.gitignore vendored
View file

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

View file

@ -32,13 +32,15 @@ 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 2, this repository contains a web application. On this website,
In version 3, 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.
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/
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!
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!
Website (our flagship instance): https://ticketfrei.links-tech.org

2
setup.cfg Normal file
View file

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

37
setup.py Normal file
View file

@ -0,0 +1,37 @@
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

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

View file

@ -1,164 +0,0 @@
% 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>

0
ticketfrei/__init__.py Normal file
View file

View file

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

View file

@ -0,0 +1,19 @@
<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

@ -0,0 +1,51 @@
<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

@ -0,0 +1,23 @@
<%
# 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

@ -0,0 +1,10 @@
<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

View file

@ -1,6 +1,10 @@
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():
"""
@ -9,7 +13,7 @@ def load_env():
:return: config dictionary of dictionaries.
"""
with open('config.toml.example') as defaultconf:
with open(os.path.join(ROOT_DIR, 'config.toml.example')) as defaultconf:
configdict = toml.load(defaultconf)
try:
@ -54,12 +58,24 @@ 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('config.toml') as configfile:
with open(os.path.join(ROOT_DIR, 'config.toml')) as configfile:
config = toml.load(configfile)
except FileNotFoundError:
config = load_env()

View file

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

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('template/wrapper.tpl')
% rebase('wrapper.tpl')
<%
import markdown as md

View file

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

View file

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

View file

@ -1,4 +1,4 @@
% rebase('template/wrapper.tpl')
% rebase('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('template/login-plain.tpl')
% include('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('template/register-plain.tpl')
% include('register-plain.tpl')
<h2>Our Mission</h2>
<p>
Public transportation is meant to provide an easy and

View file

@ -1,4 +1,4 @@
% rebase('template/wrapper.tpl', title='Register')
% rebase('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('template/register-plain.tpl')
% include('register-plain.tpl')
% end

View file

@ -0,0 +1,76 @@
% 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

@ -0,0 +1,20 @@
[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

@ -0,0 +1,23 @@
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

@ -0,0 +1,16 @@
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)