Commit e7445ffa authored by Jogi Hofmüller's avatar Jogi Hofmüller

Release Candidate

parent 79e04513
......@@ -12,11 +12,18 @@ def logmsg(msg):
print('{}: {}'.format(strftime('%c'), msg))
# location of the gdb json file
gdbfile = '/app/data/gdb/gdb.json'
# dir for static html files; mainly needed for letsencrypt's certbot
basedir = '/app/data/www'
# url of frontend
frontendurl = 'https://plagi.at/geruecht'
# cookiesecret
cookiesecret = 'place-a-random-value-here';
class SessionList(list):
def __init__(self, userlist):
self.userlist = userlist
......@@ -56,6 +63,11 @@ sessionlist = SessionList(gdb.ulist)
# a handler for static files
class FileHandler(tornado.web.RequestHandler):
def set_default_headers(self):
# while testing leave this open to anyone
self.set_header('Access-Control-Allow-Origin', '*')
self.set_header('Access-Control-Allow-Methods', 'GET')
@tornado.web.asynchronous
def get(self, path):
print('path={}'.format(path))
......@@ -75,14 +87,21 @@ class RestHandler(tornado.web.RequestHandler):
def set_default_headers(self):
# while testing leave this open to anyone
self.set_header('Access-Control-Allow-Origin', '*')
self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE, PUT')
self.set_header("Access-Control-Allow-Headers", 'content-type')
@tornado.web.asynchronous
def post(self, *args):
pass
class GeruechtHandler(RestHandler):
def set_default_headers(self):
# while testing leave this open to anyone
self.set_header('Access-Control-Allow-Origin', '*')
self.set_header('Access-Control-Allow-Methods', 'GET')
@tornado.web.asynchronous
def get(self, *args):
def get(self):
geruecht = gdb.getNextGeruecht()
if not geruecht:
data = {'status': 'error'}
......@@ -93,40 +112,70 @@ class GeruechtHandler(RestHandler):
data = json.dumps(data)
self.finish(data)
class AddHandler(RestHandler):
def set_default_headers(self):
# while testing leave this open to anyone
self.set_header('Access-Control-Allow-Origin', frontendurl)
self.set_header('Access-Control-Allow-Credentials', 'true')
self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE, PUT')
@tornado.web.asynchronous
def post(self):
logmsg('AddHandler')
data = tornado.escape.json_decode(self.request.body)
logmsg(data['type'])
self.finish(json.dumps({'status': 'success', 'message': 'not implemented yet'}))
class LoginHandler(RestHandler):
def set_default_headers(self):
# while testing leave this open to anyone
self.set_header('Access-Control-Allow-Origin', frontendurl)
self.set_header('Access-Control-Allow-Credentials', 'true')
@tornado.web.asynchronous
def post(self, name, password):
user = sessionlist.authenticate(name, password)
if not user:
logmsg('LoginHandler: authentication error for user={}, password={}'.format(name, password))
self.finish(json.dumps({'status': 'error'}))
logmsg('LoginHandler: authentication error for user={}, password={}'.format(name, password))
else:
logmsg('LoginHandler: user={} logged in'.format(user.name))
# here we will send the entire gdb.json + samples for geruechte
self.set_secure_cookie('name', user.name)
self.finish(json.dumps({'status': 'success'}))
self.finish(json.dumps({'status': 'success', 'message': 'Hello {}!'.format(user.name)}))
logmsg('LoginHandler: user={} logged in'.format(user.name))
class ListHandler(RestHandler):
def set_default_headers(self):
# while testing leave this open to anyone
self.set_header('Access-Control-Allow-Origin', frontendurl)
self.set_header('Access-Control-Allow-Credentials', 'true')
self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE, PUT')
@tornado.web.asynchronous
def get(self, listobject):
data = {'status': 'error',}
user = sessionlist.validate(self.get_secure_cookie('name'))
if not user:
self.finish(json.dumps(data))
self.finish(json.dumps({'status': 'error', 'message': 'unauthorized access'}))
logmsg('ListHandler: unauthorized access')
return
payload = gdb.getdict(listobject)
if not payload:
self.finish(json.dumps(data))
self.finish(json.dumps({'status': 'error', 'message': 'unknown getlist type'}))
logmsg('ListHandler: unknown getlist type {}'.format(listobject))
return
data['status'] = 'success'
data['payload'] = payload
data = {'status': 'success', 'payload': payload,'message': len(payload), }
logmsg('ListHandler: list type={}, user={}'.format(listobject, user.name))
self.finish(json.dumps(data))
class SaveHandler(RestHandler):
def set_default_headers(self):
# while testing leave this open to anyone
self.set_header('Access-Control-Allow-Origin', frontendurl)
self.set_header('Access-Control-Allow-Credentials', 'true')
self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE, PUT')
@tornado.web.asynchronous
def post(self, saveobject, data):
user = sessionlist.validate(self.get_secure_cookie('name'))
......@@ -154,13 +203,14 @@ def run():
handlers = [
tornado.web.url(r'/get', GeruechtHandler),
tornado.web.url(r'/add', AddHandler),
tornado.web.url(r'/login/user/([A-Za-z0-9]+)/password/([A-Za-z0-9]+)', LoginHandler),
tornado.web.url(r'/listobject/([a-z]+)', ListHandler),
tornado.web.url(r'/saveobject/([a-z]+)/data/(.*)', SaveHandler),
tornado.web.url(r'/(.*)', FileHandler),
]
settings = dict(
cookie_secret = '946e0f11a8997bf41dbafca1f6f5a4bedf46746c91801ca4f2e90dd0172f06b6',
cookie_secret = cookiesecret,
login_url = '/login/user/anon/password/none',
)
......
......@@ -78,17 +78,23 @@ class GeruechtList(list):
List of objects of class Geruecht
'''
def __init__(self, *args):
list.__init__(self, args)
self.key = 0
def getRandomGeruecht(self):
g = random.choice(self)
while g.state != itemstate.active:
while g.state != itemstate.public:
g = random.choice(self)
g.names = self.nlist.getUniqueNames(g.num_names)
if len(g.names) != g.num_names:
return 'This is an error, seriously'
return ''
return g.render()
def importGeruecht(self, data):
self.append(Geruecht(data))
if data['key'] > self.key:
self.key = data['key']
def importName(self, data):
self.nl.importName(data)
......@@ -120,6 +126,10 @@ class NameList(list):
List of objects of class Name
'''
def __init__(self, *args):
list.__init__(self, args)
self.key = 0
def getUniqueNames(self, number):
if number > len(self):
return []
......@@ -128,13 +138,15 @@ class NameList(list):
i = 0
while i < number:
name = random.choice(self)
if name not in names:
if name not in names and name.state == itemstate.public:
names.append(name)
i += 1
return names
def importName(self, data):
self.append(Name(data))
if data['key'] > self.key:
self.key = data['key']
class User(object):
'''
......@@ -153,9 +165,13 @@ class User(object):
'passwordhash': self.passwordhash,
'lastseen': self.lastseen,
}
class UserList(list):
'''
'''
def __init__(self, *args):
list.__init__(self, args)
self.key = 0
def authenticate(self, name, password):
passwordhash = hashlib.sha256(password.encode('utf8')).hexdigest()
......@@ -166,6 +182,8 @@ class UserList(list):
def importUser(self, data):
self.append(User(data))
if data['key'] > self.key:
self.key = data['key']
class Gdb:
'''
......@@ -222,7 +240,11 @@ class Gdb:
data = {}
for item in l:
data[item.key] = item.export()
d = item.export()
if type == 'geruecht':
item.names = self.glist.nlist.getUniqueNames(item.num_names)
d['example'] = item.render()
data[item.key] = d
return data
def backup(self):
......@@ -262,8 +284,8 @@ class Gdb:
class ItemState:
def __init__(self):
self.pending = 0
self.active = 1
self.private = 0
self.public = 1
self.deleted = 2
itemstate = ItemState()
......
This source diff could not be displayed because it is too large. You can view the blob instead.
/* GLOBAL STYLES
-------------------------------------------------- */
/* Padding below the footer and lighter body text */
body {
padding-top: 3rem;
padding-bottom: 3rem;
color: #5a5a5a;
}
/* CUSTOMIZE THE CAROUSEL
-------------------------------------------------- */
/* Carousel base class */
.carousel {
margin-bottom: 4rem;
}
/* Since positioning the image, we need to help out the caption */
.carousel-caption {
bottom: 3rem;
z-index: 10;
}
/* Declare heights because of positioning of img element */
.carousel-item {
height: 32rem;
}
.carousel-item > img {
position: absolute;
top: 0;
left: 0;
min-width: 100%;
height: 32rem;
}
/* MARKETING CONTENT
-------------------------------------------------- */
/* Center align the text within the three columns below the carousel */
.marketing .col-lg-4 {
margin-bottom: 1.5rem;
text-align: center;
}
.marketing h2 {
font-weight: 400;
}
.marketing .col-lg-4 p {
margin-right: .75rem;
margin-left: .75rem;
}
/* Featurettes
------------------------- */
.featurette-divider {
margin: 5rem 0; /* Space out the Bootstrap <hr> more */
}
/* Thin out the marketing headings */
.featurette-heading {
font-weight: 300;
line-height: 1;
letter-spacing: -.05rem;
}
/* RESPONSIVE CSS
-------------------------------------------------- */
@media (min-width: 40em) {
/* Bump up size of carousel content */
.carousel-caption p {
margin-bottom: 1.25rem;
font-size: 1.25rem;
line-height: 1.4;
}
.featurette-heading {
font-size: 50px;
}
}
@media (min-width: 62em) {
.featurette-heading {
margin-top: 7rem;
}
}
console.log('GG3 frontend loaded');
function next() {
$.ajax({
type: 'GET',
datatype: 'json',
url: 'https://localhost:8887/get',
success: function(data, status, jqXHR) {
result = JSON.parse(data);
$('#geruecht').html(result.geruecht);
},
error: function(jqXHR, status) {
$('#alert').html('Error');
console.log('Error');
}
})
return false;
}
$('#next').on('submit', next);
$(document).ready(next);
<!doctype html>
<html lang="de">
<head>
<title>Gerücht</title>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<title>Gerüchtegenerator 3.0</title>
<!-- <link rel="canonical" href="https://getbootstrap.com/docs/4.3/examples/carousel/"> -->
<!-- Bootstrap core CSS -->
<!-- <link href="/docs/4.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> -->
<style>
#geruecht {
font-size: 120%;
text-align: center;
margin: 20px 25% 20px 25%;
}
#next {
text-align: center;
margin: 32px auto 32px auto;
}
#alert {
color: red;
background-color: gray;
}
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
</style>
</head>
<body>
<form id="next">
<button type="submit">
Noch eins bitte
</button>
</form>
<div id="geruecht">
...
<!-- Custom styles for this template -->
<link href="css/carousel.css" rel="stylesheet">
</head>
<body>
<header>
<nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
<a class="navbar-brand" href="#">Home</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<!-- <div class="collapse navbar-collapse" id="navbarCollapse">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#">Disabled</a>
</li>
</ul>
</div> -->
</nav>
</header>
<main role="main">
<div id="myCarousel" class="carousel slide" data-ride="carousel">
<!-- <ol class="carousel-indicators">
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
<li data-target="#myCarousel" data-slide-to="1"></li>
<li data-target="#myCarousel" data-slide-to="2"></li>
</ol> -->
<div class="carousel-inner">
<div class="carousel-item active">
<svg class="bd-placeholder-img" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice" focusable="false" role="img"><rect width="100%" height="100%" fill="#777"/></svg>
<div class="carousel-caption">
<div class="container">
<h1 id="geruecht">Kein Gerücht, echt nicht!</h1>
<p><a class="btn btn-lg btn-primary" id="next" role="button">Nächstes Gerücht</a></p>
</div>
</div>
</div>
<!-- <div class="carousel-item">
<svg class="bd-placeholder-img" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice" focusable="false" role="img"><rect width="100%" height="100%" fill="#777"/></svg>
<div class="container">
<div class="carousel-caption">
<h1>Another example headline.</h1>
<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
<p><a class="btn btn-lg btn-primary" href="#" role="button">Learn more</a></p>
</div>
</div>
</div>
<div class="carousel-item">
<svg class="bd-placeholder-img" width="100%" height="100%" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice" focusable="false" role="img"><rect width="100%" height="100%" fill="#777"/></svg>
<div class="container">
<div class="carousel-caption text-right">
<h1>One more for good measure.</h1>
<p>Cras justo odio, dapibus ac facilisis in, egestas eget quam. Donec id elit non mi porta gravida at eget metus. Nullam id dolor id nibh ultricies vehicula ut id elit.</p>
<p><a class="btn btn-lg btn-primary" href="#" role="button">Browse gallery</a></p>
</div>
</div>
</div> -->
</div>
<div id='#alert'>
<!-- <a class="carousel-control-prev" href="#myCarousel" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#myCarousel" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a> -->
</div>
<!-- Marketing messaging and featurettes
================================================== -->
<!-- Wrap the rest of the page in another container to center all the content. -->
<div class="container marketing">
<!-- START THE FEATURETTES -->
<hr class="featurette-divider">
<div class="row featurette">
<div class="col-md-7">
<h2 class="featurette-heading">Gerüchtegenerator 3.0. <span class="text-muted">Schneller und schöner denn je!</span></h2>
<p class="lead">
Im 18. Jahr seines Bestehens erfuhr der Gerüchtegnerator eine tiefgreiefende Überarbeitung
inklusive dieses neuen Interfaces. Hinzufügen von neuen Gerüchten und Namen folgt demnächst.
Sourcecode auf <a href="https://gitlab.com/thesix/geruechtegenerator">Gitlab</a>.
</p>
</div>
<div class="col-md-5">
<!-- <svg class="bd-placeholder-img bd-placeholder-img-lg featurette-image img-fluid mx-auto" width="500" height="500" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice" focusable="false" role="img" aria-label="Placeholder: 500x500"><title>Placeholder</title><rect width="100%" height="100%" fill="#eee"/><text x="50%" y="50%" fill="#aaa" dy=".3em">500x500</text></svg> -->
<img class="bd-placeholder-img bd-placeholder-img-lg featurette-image img-fluid mx-auto" width="500" height="500" src="images/hofos-reni.jpg">
</div>
</div>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="gg3frontend.js"></script>
<!-- <hr class="featurette-divider">
<div class="row featurette">
<div class="col-md-7 order-md-2">
<h2 class="featurette-heading">Oh yeah, it’s that good. <span class="text-muted">See for yourself.</span></h2>
<p class="lead">Donec ullamcorper nulla non metus auctor fringilla. Vestibulum id ligula porta felis euismod semper. Praesent commodo cursus magna, vel scelerisque nisl consectetur. Fusce dapibus, tellus ac cursus commodo.</p>
</div>
<div class="col-md-5 order-md-1">
<svg class="bd-placeholder-img bd-placeholder-img-lg featurette-image img-fluid mx-auto" width="500" height="500" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice" focusable="false" role="img" aria-label="Placeholder: 500x500"><title>Placeholder</title><rect width="100%" height="100%" fill="#eee"/><text x="50%" y="50%" fill="#aaa" dy=".3em">500x500</text></svg>
</div>
</div>
<hr class="featurette-divider">
<div class="row featurette">
<div class="col-md-7">
<h2 class="featurette-heading">And lastly, this one. <span class="text-muted">Checkmate.</span></h2>
<p class="lead">Donec ullamcorper nulla non metus auctor fringilla. Vestibulum id ligula porta felis euismod semper. Praesent commodo cursus magna, vel scelerisque nisl consectetur. Fusce dapibus, tellus ac cursus commodo.</p>
</div>
<div class="col-md-5">
<svg class="bd-placeholder-img bd-placeholder-img-lg featurette-image img-fluid mx-auto" width="500" height="500" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice" focusable="false" role="img" aria-label="Placeholder: 500x500"><title>Placeholder</title><rect width="100%" height="100%" fill="#eee"/><text x="50%" y="50%" fill="#aaa" dy=".3em">500x500</text></svg>
</div>
</div> -->
<hr class="featurette-divider">
<!-- /END THE FEATURETTES -->
</div><!-- /.container -->
<!-- FOOTER -->
<footer class="container">
<p class="float-right"><a href="#">Zum Seitenanfang</a></p>
<p>
&copy; CC by SA 4.0 - 2019 <a href="https://hofos.at/">institut hofos</a> &middot;
powerd by <a href="https://mur.at/">mur.at</a> &plus;
<a href="https://docker.io/">docker</a> &plus;
<a href="https://tornadoweb.org/">tornado</a> &plus;
<a href="https://getbootstrap.com/">bootstrap</a>
</p>
</footer>
</main>
<!-- <script>window.jQuery || document.write('<script src="/docs/4.3/assets/js/vendor/jquery-slim.min.js"><\/script>')</script> -->
<link rel="stylesheet" href="css/bootstrap.min.css">
<script type="text/javascript" src="js/jquery.min.js"></script>
<script src="js/bootstrap.bundle.min.js" ></script>
<script type="text/javascript" src="js/gg3frontend.js"></script>
</body>
</html>
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
console.log('GG3 frontend loaded');
function next() {
$.ajax({
type: 'GET',
datatype: 'json',
url: 'https://localhost:8888/get',
success: function(data, status, jqXHR) {
result = JSON.parse(data);
$('#geruecht').html(result.payload);
console.log('Debug: viewing geruecht')
},
error: function(jqXHR, status) {
$('#geruecht').html('Sorry, ein Fehler, kein Gerücht');
console.log('error');
}
})
return false;
}
// function addgeruecht() {
// var obj = new Object();
// obj.value = $('#newgeruecht').val();
// obj.state = 0;
// obj.type = 'geruecht';
// $.ajax({
// type: 'POST',
// datatype: 'json',
// url: 'https://localhost:8888/add',
// data: JSON.stringify(obj),
// contentType: 'application/json; charset=utf-8',
// crossdomain: true,
// success: function(response, status, jqXHR) {
// result = JSON.parse(response);
// $('#geruecht').removeClass('alert-danger').addClass('alert-success');
// $('#geruecht').html(result.message);
// console.log('Debug: added something')
// },
// error: function(jqXHR, status) {
// $('#geruecht').removeClass('alert-success').addClass('alert-danger');
// $('#geruecht').html('an error occured');
// console.log('error');
// }
// })
// return false;
// }
$('#geruecht').on('click', next);
$('#next').on('click', next);
// $('#addgeruecht').on('submit', addgeruecht);
$(document).ready(next);
jquery-3.3.1.min.js
\ No newline at end of file
jquery-3.3.1.min.map
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment