remove obsolete kontor.py #61
@@ -0,0 +1,129 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
*.py,cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
db.sqlite3
|
||||||
|
db.sqlite3-journal
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# Jupyter Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# IPython
|
||||||
|
profile_default/
|
||||||
|
ipython_config.py
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||||
|
__pypackages__/
|
||||||
|
|
||||||
|
# Celery stuff
|
||||||
|
celerybeat-schedule
|
||||||
|
celerybeat.pid
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Environments
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
env/
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
env.bak/
|
||||||
|
venv.bak/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# kontor-bottle
|
||||||
|
Kontor with Python Bottle Framework
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# set base image (host OS)
|
||||||
|
FROM python:3.8
|
||||||
|
|
||||||
|
# set the working directory in the container
|
||||||
|
WORKDIR /code
|
||||||
|
|
||||||
|
# copy the dependencies file to the working directory
|
||||||
|
COPY requirements.txt /code/
|
||||||
|
|
||||||
|
# copy the content of the local src directory to the working directory
|
||||||
|
COPY src/ /code/
|
||||||
|
|
||||||
|
# install dependencies
|
||||||
|
RUN pip install --upgrade pip && pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
EXPOSE 9000
|
||||||
|
|
||||||
|
# command to run on container start
|
||||||
|
CMD [ "python", "./kontor.py" ]
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
pymongo
|
||||||
|
bottle
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
import pymongo
|
||||||
|
import comics.publisherDAO
|
||||||
|
import comics.artistDAO
|
||||||
|
import comics.comicDAO
|
||||||
|
import bottle
|
||||||
|
import cgi
|
||||||
|
|
||||||
|
|
||||||
|
__author__ = 'tpeetz'
|
||||||
|
|
||||||
|
|
||||||
|
class Plugin:
|
||||||
|
|
||||||
|
def __init__(self, app, database, sessions):
|
||||||
|
self.app = app
|
||||||
|
self.db = database
|
||||||
|
self.sessions = sessions
|
||||||
|
self.publishers = publisherDAO.PublisherDAO(database)
|
||||||
|
self.artists = artistDAO.ArtistDAO(database)
|
||||||
|
self.comics = comicDAO.ComicDAO(database)
|
||||||
|
self.routing()
|
||||||
|
|
||||||
|
|
||||||
|
def routing(self):
|
||||||
|
self.app.route('/comics/', 'GET', self.comic_index)
|
||||||
|
self.app.route('/comics/comic', 'GET', self.comic_list)
|
||||||
|
self.app.route('/comics/comic/<id>', 'GET', self.comic_details)
|
||||||
|
self.app.route('/comics/comic/create', 'GET', self.get_comic_create)
|
||||||
|
self.app.route('/comics/comic/create', 'POST', self.post_create_comic)
|
||||||
|
self.app.route('/comics/publisher', 'GET', self.publisher_list)
|
||||||
|
self.app.route('/comics/publisher/<id>', 'GET', self.publisher_details)
|
||||||
|
self.app.route('/comics/publisher/create', 'GET', self.get_publisher_create)
|
||||||
|
self.app.route('/comics/publisher/create', 'POST', self.post_create_publisher)
|
||||||
|
self.app.route('/comics/artist', 'GET', self.artist_list)
|
||||||
|
self.app.route('/comics/artist/<id>', 'GET', self.artist_details)
|
||||||
|
self.app.route('/comics/artist/create', 'GET', self.get_artist_create)
|
||||||
|
self.app.route('/comics/artist/create', 'POST', self.post_create_artist)
|
||||||
|
self.app.route('/comics/storyarc', 'GET', self.storyarc_list)
|
||||||
|
self.app.route('/comics/storyarc/<id>', 'GET', self.storyarc_details)
|
||||||
|
self.app.route('/comics/storyarc/create', 'GET', self.get_storyarc_create)
|
||||||
|
self.app.route('/comics/storyarc/create', 'POST', self.post_create_storyarc)
|
||||||
|
|
||||||
|
def comic_index(self):
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
username = self.sessions.get_username(cookie)
|
||||||
|
return bottle.template('comic_index', dict(username=username))
|
||||||
|
|
||||||
|
|
||||||
|
def comic_list(self):
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
username = self.sessions.get_username(cookie)
|
||||||
|
l = self.comics.get_comics()
|
||||||
|
return bottle.template('comic_list', dict(comics=l, username=username))
|
||||||
|
|
||||||
|
|
||||||
|
def comic_details(self, id):
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
username = self.sessions.get_username(cookie)
|
||||||
|
comic = self.comics.get_comic(id)
|
||||||
|
errors = ""
|
||||||
|
if comic == None:
|
||||||
|
errors = "Entry not found"
|
||||||
|
return bottle.template('comic_template', dict(title=comic['title'],
|
||||||
|
id=comic['_id'],
|
||||||
|
current_order=comic['current_order'],
|
||||||
|
completed=comic['completed'],
|
||||||
|
errors="",
|
||||||
|
username=username))
|
||||||
|
|
||||||
|
|
||||||
|
def get_comic_create(self):
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
username = self.sessions.get_username(cookie)
|
||||||
|
return bottle.template("comic_template", dict(title="",
|
||||||
|
id='newentry',
|
||||||
|
current_order=False,
|
||||||
|
completed=False,
|
||||||
|
errors="",
|
||||||
|
username=username))
|
||||||
|
|
||||||
|
|
||||||
|
def post_create_comic(self):
|
||||||
|
comic_id = bottle.request.forms.get("id")
|
||||||
|
comic_title = bottle.request.forms.get("title")
|
||||||
|
comic_order = bottle.request.forms.get("current_order")
|
||||||
|
comic_completed = bottle.request.forms.get("completed")
|
||||||
|
if comic_id == "newentry":
|
||||||
|
self.comics.insert_entry(comic_title, None, comic_order, comic_completed)
|
||||||
|
else:
|
||||||
|
self.comics.update_entry(comic_id, comic_title, None, comic_order, comic_completed)
|
||||||
|
bottle.redirect("/comics/comic")
|
||||||
|
|
||||||
|
|
||||||
|
def publisher_list(self):
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
username = self.sessions.get_username(cookie)
|
||||||
|
l = self.publishers.get_publishers()
|
||||||
|
return bottle.template('publisher_list', dict(publishers=l, username=username))
|
||||||
|
|
||||||
|
|
||||||
|
def publisher_details(self, id):
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
username = self.sessions.get_username(cookie)
|
||||||
|
publisher = self.publishers.get_publisher(id)
|
||||||
|
errors = ""
|
||||||
|
if publisher == None:
|
||||||
|
errors= "Entry not found"
|
||||||
|
return bottle.template('publisher_template', dict(name=publisher['name'], id=publisher['_id'], errors="", username=username))
|
||||||
|
|
||||||
|
|
||||||
|
def get_publisher_create(self):
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
username = self.sessions.get_username(cookie)
|
||||||
|
return bottle.template("publisher_template", dict(name="", id='newentry', errors="", username=username))
|
||||||
|
|
||||||
|
|
||||||
|
def post_create_publisher(self):
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
username = self.sessions.get_username(cookie)
|
||||||
|
publisher_id = bottle.request.forms.get("id")
|
||||||
|
publisher_name = bottle.request.forms.get("name")
|
||||||
|
if publisher_id == "newentry":
|
||||||
|
self.publishers.insert_entry(publisher_name)
|
||||||
|
else:
|
||||||
|
self.publishers.update_entry(publisher_id, publisher_name)
|
||||||
|
bottle.redirect("/comics/publisher")
|
||||||
|
|
||||||
|
|
||||||
|
def artist_list(self):
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
username = self.sessions.get_username(cookie)
|
||||||
|
l = self.artists.get_artists()
|
||||||
|
return bottle.template('artist_list', dict(artists=l, username=username))
|
||||||
|
|
||||||
|
|
||||||
|
def artist_details(self, id):
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
username = self.sessions.get_username(cookie)
|
||||||
|
artist = self.artists.get_artist(id)
|
||||||
|
errors = ""
|
||||||
|
if artist == None:
|
||||||
|
errors= "Entry not found"
|
||||||
|
return bottle.template('artist_template', dict(name=artist['name'], id=artist['_id'], errors="", username=username))
|
||||||
|
|
||||||
|
|
||||||
|
def get_artist_create(self):
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
username = self.sessions.get_username(cookie)
|
||||||
|
return bottle.template("artist_template", dict(name="", id='newentry', errors="", username=username))
|
||||||
|
|
||||||
|
|
||||||
|
def post_create_artist(self):
|
||||||
|
artist_id = bottle.request.forms.get("id")
|
||||||
|
artist_name = bottle.request.forms.get("name")
|
||||||
|
if artist_id == "newentry":
|
||||||
|
self.artists.insert_entry(artist_name)
|
||||||
|
else:
|
||||||
|
self.artists.update_entry(artist_id, artist_name)
|
||||||
|
bottle.redirect("/comics/artist")
|
||||||
|
|
||||||
|
|
||||||
|
def storyarc_list(self):
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
username = self.sessions.get_username(cookie)
|
||||||
|
l = self.storyarcs.get_storyarcs()
|
||||||
|
return bottle.template('storyarc_list', dict(storyarcs=l, username=username))
|
||||||
|
|
||||||
|
|
||||||
|
def storyarc_details(self, id):
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
username = self.sessions.get_username(cookie)
|
||||||
|
storyarc = self.storyarcs.get_storyarc(id)
|
||||||
|
errors = ""
|
||||||
|
if storyarc == None:
|
||||||
|
errors = "Entry not found"
|
||||||
|
return bottle.template('storyarc_template', dict(title=storyarc['title'], id=storyarc['_id'], errors="", username=username))
|
||||||
|
|
||||||
|
|
||||||
|
def get_storyarc_create(self):
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
username = self.sessions.get_username(cookie)
|
||||||
|
return bottle.template("storyarc_template", dict(title="", id='newentry', errors="", username=username))
|
||||||
|
|
||||||
|
|
||||||
|
def post_create_storyarc(self):
|
||||||
|
storyarc_id = bottle.request.forms.get("id")
|
||||||
|
storyarc_title = bottle.request.forms.get("title")
|
||||||
|
if storyarc_id == "newentry":
|
||||||
|
self.storyarcs.insert_entry(storyarc_title)
|
||||||
|
else:
|
||||||
|
self.storyarcs.update_entry(storyarc_id, storyarc_title)
|
||||||
|
bottle.redirect("/comics/storyarc")
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from bson.objectid import ObjectId
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class ArtistDAO:
|
||||||
|
|
||||||
|
# constructor for the class
|
||||||
|
def __init__(self, database):
|
||||||
|
self.db = database
|
||||||
|
self.artists = database.artists
|
||||||
|
|
||||||
|
def get_artists(self):
|
||||||
|
cursor = self.artists.find()
|
||||||
|
l = []
|
||||||
|
for artist in cursor:
|
||||||
|
l.append({'name':artist['name'], '_id':artist['_id']})
|
||||||
|
return l
|
||||||
|
|
||||||
|
def get_artist(self, artist_id):
|
||||||
|
artist = self.artists.find_one({"_id": ObjectId(artist_id)})
|
||||||
|
return artist
|
||||||
|
|
||||||
|
def insert_entry(self, artist_name):
|
||||||
|
print("inserting artist entry", artist_name)
|
||||||
|
|
||||||
|
artist = {"name": artist_name}
|
||||||
|
|
||||||
|
# now insert the post
|
||||||
|
try:
|
||||||
|
result = self.artists.insert_one(artist)
|
||||||
|
print("Matching artist: ", result.matched_count)
|
||||||
|
print("Modified artist: ", result.modified_count)
|
||||||
|
except:
|
||||||
|
print("Error inserting artist")
|
||||||
|
print("Unexpected error:", sys.exc_info())
|
||||||
|
|
||||||
|
def update_entry(self, artist_id, artist_name):
|
||||||
|
print("upserting artist entry", artist_name)
|
||||||
|
|
||||||
|
filter_doc = {"_id": ObjectId(artist_id)}
|
||||||
|
artist = { "$set": {"name": artist_name}}
|
||||||
|
|
||||||
|
# now insert the post
|
||||||
|
try:
|
||||||
|
result = self.artists.update_one(filter_doc, artist)
|
||||||
|
print("Modified artist: ", result.modified_count)
|
||||||
|
except:
|
||||||
|
print("Error inserting artist")
|
||||||
|
print("Unexpected error:", sys.exc_info())
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from bson.objectid import ObjectId
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class ComicDAO:
|
||||||
|
|
||||||
|
# constructor for the class
|
||||||
|
def __init__(self, database):
|
||||||
|
self.db = database
|
||||||
|
self.comics = database.comics
|
||||||
|
|
||||||
|
def get_comics(self):
|
||||||
|
cursor = self.comics.find()
|
||||||
|
l = []
|
||||||
|
for comic in cursor:
|
||||||
|
l.append({'title':comic['title'],
|
||||||
|
'_id':comic['_id'],
|
||||||
|
'current_order':comic['current_order'],
|
||||||
|
'completed':comic['completed']})
|
||||||
|
return l
|
||||||
|
|
||||||
|
def get_comic(self, comic_id):
|
||||||
|
comic = self.comics.find_one({"_id": ObjectId(comic_id)})
|
||||||
|
return comic
|
||||||
|
|
||||||
|
def insert_entry(self, comic_title, comic_publisher=None, comic_order=False, comic_completed=False):
|
||||||
|
print("inserting comic entry", comic_title)
|
||||||
|
|
||||||
|
comic = {"title": comic_title, "current_order": comic_order, "completed": comic_completed}
|
||||||
|
|
||||||
|
# now insert the comic
|
||||||
|
try:
|
||||||
|
result = self.comics.insert_one(comic)
|
||||||
|
print("Modified comic: ", result.modified_count)
|
||||||
|
except:
|
||||||
|
print("Error inserting comic")
|
||||||
|
print("Unexpected error:", sys.exc_info())
|
||||||
|
|
||||||
|
def update_entry(self, comic_id, comic_title, comic_publisher=None, comic_order=False, comic_completed=False):
|
||||||
|
print("upserting comic entry", comic_title)
|
||||||
|
|
||||||
|
filter_doc = {"_id": ObjectId(comic_id)}
|
||||||
|
comic = { "$set": {"title": comic_title, 'current_order': comic_order, 'completed': comic_completed}}
|
||||||
|
|
||||||
|
# now insert the post
|
||||||
|
try:
|
||||||
|
result = self.comics.update_one(filter_doc, comic)
|
||||||
|
print("Matching comic: ", result.matched_count)
|
||||||
|
print("Modified comic: ", result.modified_count)
|
||||||
|
except:
|
||||||
|
print("Error inserting comic")
|
||||||
|
print("Unexpected error:", sys.exc_info())
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from mongoengine import connect, Document
|
||||||
|
from mongoengine import StringField, BooleanField
|
||||||
|
from mongoengine import ListField, ReferenceField, GenericReferenceField
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
|
||||||
|
class Publisher(Document):
|
||||||
|
name = StringField(required=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = "Publisher(%s)" % self.name
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
class Artist(Document):
|
||||||
|
name = StringField(required=True)
|
||||||
|
className = StringField()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = "Artist(%s)" % self.name
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
class Issue(Document):
|
||||||
|
number = StringField()
|
||||||
|
comic = GenericReferenceField()
|
||||||
|
is_read = BooleanField(default=False)
|
||||||
|
is_stock = BooleanField(default=False)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = "Issue(%s # %s, %s)" % (self.comic.title, self.number, self.is_read)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
class StoryArc(Document):
|
||||||
|
name = StringField(required=True)
|
||||||
|
comic = GenericReferenceField()
|
||||||
|
issues = ListField(ReferenceField(Issue))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = "StoryArc(%s, %s)" % (self.name, self.comic.title)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
class Volume(Document):
|
||||||
|
name = StringField(required=True)
|
||||||
|
comic = GenericReferenceField()
|
||||||
|
issues = ListField(ReferenceField(Issue))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = "Volume(%s, %s, %s)" % (self.id, self.name, self.comic.title)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
class Comic(Document):
|
||||||
|
title = StringField(required=True)
|
||||||
|
publisher = ReferenceField(Publisher)
|
||||||
|
current_order = BooleanField()
|
||||||
|
completed = BooleanField()
|
||||||
|
issues = ListField(ReferenceField(Issue))
|
||||||
|
stories = ListField(ReferenceField(StoryArc))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.publisher is None:
|
||||||
|
s = "Comic(%s, %s, %s, %s)" % (self.title, self.publisher, self.current_order, self.completed)
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
s = "Comic(%s, %s, %s, %s)" % (
|
||||||
|
self.title, self.publisher.name, self.current_order, self.completed)
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
class TradePaperback(Document):
|
||||||
|
comic = ReferenceField(Comic)
|
||||||
|
issue_start = StringField()
|
||||||
|
issue_end = StringField()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
s = "TPB(%s)" % self.comic.title
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
def get_publisher(name):
|
||||||
|
publisher = Publisher.objects(name=name)
|
||||||
|
if publisher.count() > 0:
|
||||||
|
return publisher[0]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_comic(title):
|
||||||
|
comic = Comic.objects(title=title)
|
||||||
|
if comic.count() > 0:
|
||||||
|
return comic[0]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_issue(title, number):
|
||||||
|
comic = get_comic(title)
|
||||||
|
issues = Issue.objects(number=number, comic=comic)
|
||||||
|
if issues.count() > 0:
|
||||||
|
return issues[0]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
connect('comics')
|
||||||
|
for publisher in Publisher.objects:
|
||||||
|
pprint.pprint(publisher)
|
||||||
|
for artist in Artist.objects:
|
||||||
|
pprint.pprint(artist)
|
||||||
|
for comic in Comic.objects:
|
||||||
|
pprint.pprint(comic)
|
||||||
|
for issue in Issue.objects:
|
||||||
|
pprint.pprint(issue)
|
||||||
|
for story in StoryArc.objects:
|
||||||
|
pprint.pprint(story)
|
||||||
|
for tpb in TradePaperback.objects:
|
||||||
|
pprint.pprint(tpb)
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from bson.objectid import ObjectId
|
||||||
|
import sys
|
||||||
|
|
||||||
|
class PublisherDAO:
|
||||||
|
|
||||||
|
# constructor for the class
|
||||||
|
def __init__(self, database):
|
||||||
|
self.db = database
|
||||||
|
self.publishers = database.publishers
|
||||||
|
|
||||||
|
def get_publishers(self):
|
||||||
|
cursor = self.publishers.find()
|
||||||
|
l = []
|
||||||
|
for publisher in cursor:
|
||||||
|
l.append({'name':publisher['name'], '_id':publisher['_id']})
|
||||||
|
return l
|
||||||
|
|
||||||
|
def get_publisher(self, publisher_id):
|
||||||
|
publisher = self.publishers.find_one({"_id": ObjectId(publisher_id)})
|
||||||
|
return publisher
|
||||||
|
|
||||||
|
def insert_entry(self, publisher_name):
|
||||||
|
print("inserting publisher entry", publisher_name)
|
||||||
|
|
||||||
|
publisher = {"name": publisher_name}
|
||||||
|
|
||||||
|
# now insert the post
|
||||||
|
try:
|
||||||
|
result = self.publishers.insert_one(publisher)
|
||||||
|
print("Matching publisher: ", result.matched_count)
|
||||||
|
print("Modified publisher: ", result.modified_count)
|
||||||
|
except:
|
||||||
|
print("Error inserting publisher")
|
||||||
|
print("Unexpected error:", sys.exc_info())
|
||||||
|
|
||||||
|
def update_entry(self, publisher_id, publisher_name):
|
||||||
|
print("upserting publisher entry", publisher_name)
|
||||||
|
|
||||||
|
filter_doc = {"_id": ObjectId(publisher_id)}
|
||||||
|
publisher = { "$set": {"name": publisher_name}}
|
||||||
|
|
||||||
|
# now insert the post
|
||||||
|
try:
|
||||||
|
result = self.publishers.update_one(filter_doc, publisher)
|
||||||
|
print("Modified publisher: ", result.modified_count)
|
||||||
|
except:
|
||||||
|
print("Error inserting publisher")
|
||||||
|
print("Unexpected error:", sys.exc_info())
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from bson.objectid import ObjectId
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
class StoryArcDAO:
|
||||||
|
# constructor for the class
|
||||||
|
def __init__(self, database):
|
||||||
|
self.db = database
|
||||||
|
self.storyarcs = database.storyarcs
|
||||||
|
|
||||||
|
def get_storyarcs(self):
|
||||||
|
cursor = self.storyarcs.find()
|
||||||
|
l = []
|
||||||
|
for storyarc in cursor:
|
||||||
|
l.append({'title': storyarc['title'], '_id': storyarc['_id']})
|
||||||
|
return l
|
||||||
|
|
||||||
|
def get_storyarc(self, storyarc_id):
|
||||||
|
storyarc = self.storyarcs.find_one({"_id": ObjectId(storyarc_id)})
|
||||||
|
return storyarc
|
||||||
|
|
||||||
|
def insert_entry(self, storyarc_title):
|
||||||
|
print("inserting publisher entry", storyarc_title)
|
||||||
|
|
||||||
|
storyarc = {"name": storyarc_title}
|
||||||
|
|
||||||
|
# now insert the post
|
||||||
|
try:
|
||||||
|
result = self.storyarcs.insert_one(storyarc)
|
||||||
|
print("Matching storyarc: ", result.matched_count)
|
||||||
|
print("Modified storyarc: ", result.modified_count)
|
||||||
|
except:
|
||||||
|
print("Error inserting storyarc")
|
||||||
|
print("Unexpected error:", sys.exc_info())
|
||||||
|
|
||||||
|
def update_entry(self, storyarc_id, storyarc_title):
|
||||||
|
print("upserting storyarc entry", storyarc_title)
|
||||||
|
|
||||||
|
filter_doc = {"_id": ObjectId(storyarc_id)}
|
||||||
|
storyarc = {"$set": {"name": storyarc_title}}
|
||||||
|
|
||||||
|
# now insert the post
|
||||||
|
try:
|
||||||
|
result = self.storyarcs.update_one(filter_doc, storyarc)
|
||||||
|
print("Modified storyarc: ", result.modified_count)
|
||||||
|
except:
|
||||||
|
print("Error inserting storyarc")
|
||||||
|
print("Unexpected error:", sys.exc_info())
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
body {
|
||||||
|
font-family: sans-serif;
|
||||||
|
color: #333333;
|
||||||
|
padding:4em 0 4em;
|
||||||
|
}
|
||||||
|
body,
|
||||||
|
.wrapper {
|
||||||
|
margin: 10px auto;
|
||||||
|
/*max-width: 60em;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
header, nav, nav a, main, section, footer {
|
||||||
|
border-radius: 0px 0.5em 0.5em;
|
||||||
|
border: 1px solid;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
position:fixed;
|
||||||
|
top:0px;
|
||||||
|
left:0px;
|
||||||
|
right:0px;
|
||||||
|
text-align:center;
|
||||||
|
padding:10px;
|
||||||
|
background: lightgrey;
|
||||||
|
/*border-bottom: 1px solid #d5d5d5;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
nav {
|
||||||
|
position: fixed;
|
||||||
|
padding-top: 10em;
|
||||||
|
|
||||||
|
font-size: 0.91em;
|
||||||
|
float: left;
|
||||||
|
width: 15em;
|
||||||
|
padding: 0;
|
||||||
|
background: lightskyblue;
|
||||||
|
border-color: skyblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav ul {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav li {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a {
|
||||||
|
display: block;
|
||||||
|
padding: 0.2em 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-decoration: none;
|
||||||
|
background-color: skyblue;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav ul a:hover,
|
||||||
|
nav ul a:active {
|
||||||
|
color: #fffbf0;
|
||||||
|
background-color: #dfac20;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
display: block;
|
||||||
|
background: lightblue;
|
||||||
|
border-color: #8a9da8;
|
||||||
|
margin-left: 15em;
|
||||||
|
min-width: 16em; /* Mindestbreite (der Überschrift) verhindert Anzeigefehler in modernen Browsern */
|
||||||
|
}
|
||||||
|
|
||||||
|
footer {
|
||||||
|
position:fixed;
|
||||||
|
padding: 10px;
|
||||||
|
margin-top: 10px;
|
||||||
|
bottom:0;
|
||||||
|
left: 0;
|
||||||
|
right:0;
|
||||||
|
background: lightgrey;
|
||||||
|
border-color: grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer p {
|
||||||
|
float:right;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import pymongo
|
||||||
|
import sessionDAO
|
||||||
|
import userDAO
|
||||||
|
import comics
|
||||||
|
#import library
|
||||||
|
import bottle
|
||||||
|
import cgi
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
__author__ = 'tpeetz'
|
||||||
|
|
||||||
|
app = bottle.Bottle()
|
||||||
|
|
||||||
|
|
||||||
|
def index():
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
username = sessions.get_username(cookie)
|
||||||
|
return bottle.template('kontor', dict(username=username))
|
||||||
|
|
||||||
|
|
||||||
|
def show_signup():
|
||||||
|
return bottle.template("signup", dict(username="",
|
||||||
|
password="",
|
||||||
|
password_error="",
|
||||||
|
email="",
|
||||||
|
username_error="",
|
||||||
|
email_error="",
|
||||||
|
verify_error =""))
|
||||||
|
|
||||||
|
|
||||||
|
def process_signup():
|
||||||
|
email = bottle.request.forms.get("email")
|
||||||
|
username = bottle.request.forms.get("username")
|
||||||
|
password = bottle.request.forms.get("password")
|
||||||
|
verify = bottle.request.forms.get("verify")
|
||||||
|
|
||||||
|
# set these up in case we have an error case
|
||||||
|
errors = {'username': cgi.escape(username), 'email': cgi.escape(email)}
|
||||||
|
if validate_signup(username, password, verify, email, errors):
|
||||||
|
|
||||||
|
if not users.add_user(username, password, email):
|
||||||
|
# this was a duplicate
|
||||||
|
errors['username_error'] = "Username already in use. Please choose another"
|
||||||
|
return bottle.template("signup", errors)
|
||||||
|
|
||||||
|
session_id = sessions.start_session(username)
|
||||||
|
print(session_id)
|
||||||
|
bottle.response.set_cookie("session", session_id)
|
||||||
|
bottle.redirect("/welcome")
|
||||||
|
else:
|
||||||
|
print("user did not validate")
|
||||||
|
return bottle.template("signup", errors)
|
||||||
|
|
||||||
|
|
||||||
|
def show_login():
|
||||||
|
return bottle.template('login', dict(username="", password="", login_error=""))
|
||||||
|
|
||||||
|
def process_login():
|
||||||
|
username = bottle.request.forms.get("username")
|
||||||
|
password = bottle.request.forms.get("password")
|
||||||
|
|
||||||
|
print("user submitted ", username, "pass ", password)
|
||||||
|
|
||||||
|
user_record = users.validate_login(username, password)
|
||||||
|
if user_record:
|
||||||
|
# username is stored in the user collection in the _id key
|
||||||
|
session_id = sessions.start_session(user_record['_id'])
|
||||||
|
|
||||||
|
if session_id is None:
|
||||||
|
bottle.redirect("/internal_error")
|
||||||
|
|
||||||
|
cookie = session_id
|
||||||
|
|
||||||
|
# Warning, if you are running into a problem whereby the cookie being set here is
|
||||||
|
# not getting set on the redirect, you are probably using the experimental version of bottle (.12).
|
||||||
|
# revert to .11 to solve the problem.
|
||||||
|
bottle.response.set_cookie("session", cookie)
|
||||||
|
|
||||||
|
bottle.redirect("/")
|
||||||
|
|
||||||
|
else:
|
||||||
|
return bottle.template("login", dict(username=cgi.escape(username), password="", login_error="Invalid Login"))
|
||||||
|
|
||||||
|
|
||||||
|
def process_logout():
|
||||||
|
cookie = bottle.request.get_cookie("session")
|
||||||
|
sessions.end_session(cookie)
|
||||||
|
bottle.response.set_cookie("session", "")
|
||||||
|
bottle.redirect("/")
|
||||||
|
|
||||||
|
|
||||||
|
def send_stylesheet(filename):
|
||||||
|
return bottle.static_file(filename, root='.', mimetype='text/css')
|
||||||
|
|
||||||
|
|
||||||
|
def setup_routing(app):
|
||||||
|
app.route('/', 'GET', index)
|
||||||
|
app.route('/signup', 'GET', show_signup)
|
||||||
|
app.route('/signup', 'POST', process_signup)
|
||||||
|
app.route('/login', 'GET', show_login)
|
||||||
|
app.route('/login', 'POST', process_login)
|
||||||
|
app.route('/logout', 'GET', process_logout)
|
||||||
|
app.route('/css/<filename:re:.*\.css>', 'GET', send_stylesheet)
|
||||||
|
|
||||||
|
|
||||||
|
# validates that the user information is valid for new signup, return True of False
|
||||||
|
# and fills in the error string if there is an issue
|
||||||
|
def validate_signup(username, password, verify, email, errors):
|
||||||
|
USER_RE = re.compile(r"^[a-zA-Z0-9_-]{3,20}$")
|
||||||
|
PASS_RE = re.compile(r"^.{3,20}$")
|
||||||
|
EMAIL_RE = re.compile(r"^[\S]+@[\S]+\.[\S]+$")
|
||||||
|
|
||||||
|
errors['username_error'] = ""
|
||||||
|
errors['password_error'] = ""
|
||||||
|
errors['verify_error'] = ""
|
||||||
|
errors['email_error'] = ""
|
||||||
|
|
||||||
|
if not USER_RE.match(username):
|
||||||
|
errors['username_error'] = "invalid username. try just letters and numbers"
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not PASS_RE.match(password):
|
||||||
|
errors['password_error'] = "invalid password."
|
||||||
|
return False
|
||||||
|
if password != verify:
|
||||||
|
errors['verify_error'] = "password must match"
|
||||||
|
return False
|
||||||
|
if email != "":
|
||||||
|
if not EMAIL_RE.match(email):
|
||||||
|
errors['email_error'] = "invalid email address"
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
setup_routing(app)
|
||||||
|
|
||||||
|
connection = pymongo.MongoClient("mongodb://mongodb")
|
||||||
|
database = connection.kontor
|
||||||
|
|
||||||
|
users = userDAO.UserDAO(database)
|
||||||
|
sessions = sessionDAO.SessionDAO(database)
|
||||||
|
|
||||||
|
comics_plugin = comics.Plugin(app, database, sessions)
|
||||||
|
#library_plugin = library.Plugin(app, database, sessions)
|
||||||
|
print("starting app Kontor")
|
||||||
|
bottle.run(app, host="0.0.0.0", port=9000, debug=True)
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
|
||||||
|
|
||||||
|
# The session Data Access Object handles interactions with the sessions collection
|
||||||
|
|
||||||
|
class SessionDAO:
|
||||||
|
|
||||||
|
def __init__(self, database):
|
||||||
|
self.db = database
|
||||||
|
self.sessions = database.sessions
|
||||||
|
|
||||||
|
# will start a new session id by adding a new document to the sessions collection
|
||||||
|
# returns the sessionID or None
|
||||||
|
def start_session(self, username):
|
||||||
|
|
||||||
|
session_id = self.get_random_str(32)
|
||||||
|
session = {'username': username, '_id': session_id}
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.sessions.insert_one(session)
|
||||||
|
except:
|
||||||
|
print("Unexpected error on start_session:", sys.exc_info()[0])
|
||||||
|
return None
|
||||||
|
|
||||||
|
return str(session['_id'])
|
||||||
|
|
||||||
|
# will send a new user session by deleting from sessions table
|
||||||
|
def end_session(self, session_id):
|
||||||
|
|
||||||
|
if session_id is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.sessions.delete_one({'_id': session_id})
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
# if there is a valid session, it is returned
|
||||||
|
def get_session(self, session_id):
|
||||||
|
|
||||||
|
if session_id is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
session = self.sessions.find_one({'_id': session_id})
|
||||||
|
|
||||||
|
return session
|
||||||
|
|
||||||
|
# get the username of the current session, or None if the session is not valid
|
||||||
|
def get_username(self, session_id):
|
||||||
|
|
||||||
|
session = self.get_session(session_id)
|
||||||
|
if session is None:
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
return session['username']
|
||||||
|
|
||||||
|
def get_random_str(self, num_chars):
|
||||||
|
random_string = ""
|
||||||
|
for i in range(num_chars):
|
||||||
|
random_string = random_string + random.choice(string.ascii_letters)
|
||||||
|
return random_string
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import hmac
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
import hashlib
|
||||||
|
import pymongo
|
||||||
|
|
||||||
|
|
||||||
|
# The User Data Access Object handles all interactions with the User collection.
|
||||||
|
class UserDAO:
|
||||||
|
|
||||||
|
def __init__(self, db):
|
||||||
|
self.db = db
|
||||||
|
self.users = self.db.users
|
||||||
|
self.SECRET = 'verysecret'
|
||||||
|
|
||||||
|
# makes a little salt
|
||||||
|
def make_salt(self):
|
||||||
|
salt = ""
|
||||||
|
for i in range(5):
|
||||||
|
salt = salt + random.choice(string.ascii_letters)
|
||||||
|
return salt
|
||||||
|
|
||||||
|
# implement the function make_pw_hash(name, pw) that returns a hashed password
|
||||||
|
# of the format:
|
||||||
|
# HASH(pw + salt),salt
|
||||||
|
# use sha256
|
||||||
|
|
||||||
|
def make_pw_hash(self, pw,salt=None):
|
||||||
|
if salt == None:
|
||||||
|
salt = self.make_salt();
|
||||||
|
return hashlib.sha256(pw + salt).hexdigest()+","+ salt
|
||||||
|
|
||||||
|
# Validates a user login. Returns user record or None
|
||||||
|
def validate_login(self, username, password):
|
||||||
|
|
||||||
|
user = None
|
||||||
|
try:
|
||||||
|
user = self.users.find_one({'_id': username})
|
||||||
|
except:
|
||||||
|
print("Unable to query database for user")
|
||||||
|
|
||||||
|
if user is None:
|
||||||
|
print("User not in database")
|
||||||
|
return None
|
||||||
|
|
||||||
|
salt = user['password'].split(',')[1]
|
||||||
|
|
||||||
|
if user['password'] != self.make_pw_hash(password, salt):
|
||||||
|
print("user password is not a match")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Looks good
|
||||||
|
return user
|
||||||
|
|
||||||
|
|
||||||
|
# creates a new user in the users collection
|
||||||
|
def add_user(self, username, password, email):
|
||||||
|
password_hash = self.make_pw_hash(password)
|
||||||
|
|
||||||
|
user = {'_id': username, 'password': password_hash}
|
||||||
|
if email != "":
|
||||||
|
user['email'] = email
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.users.insert_one(user)
|
||||||
|
except pymongo.errors.OperationFailure:
|
||||||
|
print("oops, mongo error")
|
||||||
|
return False
|
||||||
|
except pymongo.errors.DuplicateKeyError as e:
|
||||||
|
print("oops, username is already taken")
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Kontor</title>
|
||||||
|
<link rel="stylesheet" href="/css/kontor.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>Kontor</header>
|
||||||
|
<nav><ul>
|
||||||
|
<li><a href="/">Kontor</a></li>
|
||||||
|
<li><a href="/comics">Comics</a></li>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/comics/artist">Artists</a></li>
|
||||||
|
<li><a href="/comics/publisher">Publishers</a></li>
|
||||||
|
</ul>
|
||||||
|
<li><a href="/library">Bücher</a></li>
|
||||||
|
<li><a href="/medien">Medien</a></li>
|
||||||
|
<li><a href="/tradingcards">Trading Cards</a></li>
|
||||||
|
</ul></nav>
|
||||||
|
<main role="main">
|
||||||
|
<details>
|
||||||
|
<ul>
|
||||||
|
%for artist in artists:
|
||||||
|
<li><a href="/comics/artist/{{artist['_id']}}">{{artist['name']}}</a></li>
|
||||||
|
%end
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
%if (username == None):
|
||||||
|
<a href="/login">Login</a>
|
||||||
|
%end
|
||||||
|
%if (username != None):
|
||||||
|
<a href="/logout">{{username}}</a>
|
||||||
|
%end
|
||||||
|
<p>Ingenieurbüro Thomas Peetz</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Kontor</title>
|
||||||
|
<link rel="stylesheet" href="/css/kontor.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>Kontor</header>
|
||||||
|
<nav><ul>
|
||||||
|
<li><a href="/">Kontor</a></li>
|
||||||
|
<li><a href="/comics">Comics</a></li>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/comics/artist">Artists</a></li>
|
||||||
|
<li><a href="/comics/publisher">Publishers</a></li>
|
||||||
|
</ul>
|
||||||
|
<li><a href="/library">Bücher</a></li>
|
||||||
|
<li><a href="/medien">Medien</a></li>
|
||||||
|
<li><a href="/tradingcards">Trading Cards</a></li>
|
||||||
|
</ul></nav>
|
||||||
|
<main role="main">
|
||||||
|
<details>
|
||||||
|
<form action="/comics/artist/create" method="POST">
|
||||||
|
{{errors}}
|
||||||
|
<h2>Title</h2>
|
||||||
|
<input type="hidden" name="id", value="{{id}}">
|
||||||
|
<input type="text" name="name" size="60" value="{{name}}"><br>
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</details>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
%if (username == None):
|
||||||
|
<a href="/login">Login</a>
|
||||||
|
%end
|
||||||
|
%if (username != None):
|
||||||
|
<a href="/logout">{{username}}</a>
|
||||||
|
%end
|
||||||
|
<p>Ingenieurbüro Thomas Peetz</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Kontor</title>
|
||||||
|
<link rel="stylesheet" href="/css/kontor.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>Kontor</header>
|
||||||
|
<nav><ul>
|
||||||
|
<li><a href="/">Kontor</a></li>
|
||||||
|
<li><a href="/comics">Comics</a></li>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/comics/artist">Artists</a></li>
|
||||||
|
<li><a href="/comics/publisher">Publishers</a></li>
|
||||||
|
</ul>
|
||||||
|
<li><a href="/library">Bücher</a></li>
|
||||||
|
<li><a href="/medien">Medien</a></li>
|
||||||
|
<li><a href="/tradingcards">Trading Cards</a></li>
|
||||||
|
</ul></nav>
|
||||||
|
<main role="main">
|
||||||
|
<details>
|
||||||
|
</details>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
%if (username == None):
|
||||||
|
<a href="/login">Login</a>
|
||||||
|
%end
|
||||||
|
%if (username != None):
|
||||||
|
<a href="/logout">{{username}}</a>
|
||||||
|
%end
|
||||||
|
<p>Ingenieurbüro Thomas Peetz</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Kontor</title>
|
||||||
|
<link rel="stylesheet" href="/css/kontor.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>Kontor</header>
|
||||||
|
<nav><ul>
|
||||||
|
<li><a href="/">Kontor</a></li>
|
||||||
|
<li><a href="/comics">Comics</a></li>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/comics/artist">Artists</a></li>
|
||||||
|
<li><a href="/comics/publisher">Publishers</a></li>
|
||||||
|
</ul>
|
||||||
|
<li><a href="/library">Bücher</a></li>
|
||||||
|
<li><a href="/medien">Medien</a></li>
|
||||||
|
<li><a href="/tradingcards">Trading Cards</a></li>
|
||||||
|
</ul></nav>
|
||||||
|
<main role="main">
|
||||||
|
<details>
|
||||||
|
<table border="1">
|
||||||
|
<tr><td>Title</td><td>Current Order</td><td>Completed</td></tr>
|
||||||
|
<tr>
|
||||||
|
%for comic in comics:
|
||||||
|
<td><a href="/comics/comic/{{comic['_id']}}">{{comic['title']}}</a></td>
|
||||||
|
<td>{{comic['current_order']}}</td>
|
||||||
|
<td>{{comic['completed']}}</td>
|
||||||
|
%end
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</details>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
%if (username == None):
|
||||||
|
<a href="/login">Login</a>
|
||||||
|
%end
|
||||||
|
%if (username != None):
|
||||||
|
<a href="/logout">{{username}}</a>
|
||||||
|
%end
|
||||||
|
<p>Ingenieurbüro Thomas Peetz</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Kontor</title>
|
||||||
|
<link rel="stylesheet" href="/css/kontor.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>Kontor</header>
|
||||||
|
<nav><ul>
|
||||||
|
<li><a href="/">Kontor</a></li>
|
||||||
|
<li><a href="/comics">Comics</a></li>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/comics/artist">Artists</a></li>
|
||||||
|
<li><a href="/comics/publisher">Publishers</a></li>
|
||||||
|
</ul>
|
||||||
|
<li><a href="/library">Bücher</a></li>
|
||||||
|
<li><a href="/medien">Medien</a></li>
|
||||||
|
<li><a href="/tradingcards">Trading Cards</a></li>
|
||||||
|
</ul></nav>
|
||||||
|
<main role="main">
|
||||||
|
<details>
|
||||||
|
<form action="/comics/comic/create" method="POST">
|
||||||
|
{{errors}}
|
||||||
|
<h2>Title</h2>
|
||||||
|
<input type="hidden" name="id", value="{{id}}">
|
||||||
|
<input type="text" name="title" size="60" value="{{title}}"><br>
|
||||||
|
<p>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="current_order" size="60" value="{{current_order}}">
|
||||||
|
Current Order
|
||||||
|
</label>
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="completed" size="60" value="{{completed}}">
|
||||||
|
Completed
|
||||||
|
</label>
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</details>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
%if (username == None):
|
||||||
|
<a href="/login">Login</a>
|
||||||
|
%end
|
||||||
|
%if (username != None):
|
||||||
|
<a href="/logout">{{username}}</a>
|
||||||
|
%end
|
||||||
|
<p>Ingenieurbüro Thomas Peetz</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Kontor</title>
|
||||||
|
<link rel="stylesheet" href="css/kontor.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>Kontor</header>
|
||||||
|
<nav><ul>
|
||||||
|
<li><a href="/">Kontor</a></li>
|
||||||
|
<li><a href="/comics">Comics</a></li>
|
||||||
|
<li><a href="/library">Bücher</a></li>
|
||||||
|
<li><a href="/medien">Medien</a></li>
|
||||||
|
<li><a href="/tradingcards">Trading Cards</a></li>
|
||||||
|
</ul></nav>
|
||||||
|
<main role="main">
|
||||||
|
<details>
|
||||||
|
</details>
|
||||||
|
</main>
|
||||||
|
%if (username == None):
|
||||||
|
<footer><a href="/login">Login</a><p>Ingenieurbüro Thomas Peetz</p></footer>
|
||||||
|
%end
|
||||||
|
%if (username != None):
|
||||||
|
<footer><a href="/logout">{{username}}</a><p>Ingenieurbüro Thomas Peetz</p></footer>
|
||||||
|
%end
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Kontor</title>
|
||||||
|
<link rel="stylesheet" href="/css/kontor.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>Kontor</header>
|
||||||
|
<nav><ul>
|
||||||
|
<li><a href="/">Kontor</a></li>
|
||||||
|
<li><a href="/comics">Comics</a></li>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/comics/artist">Artists</a></li>
|
||||||
|
<li><a href="/comics/publisher">Publishers</a></li>
|
||||||
|
</ul>
|
||||||
|
<li><a href="/library">Bücher</a></li>
|
||||||
|
<li><a href="/medien">Medien</a></li>
|
||||||
|
<li><a href="/tradingcards">Trading Cards</a></li>
|
||||||
|
</ul></nav>
|
||||||
|
<main role="main">
|
||||||
|
<details>
|
||||||
|
<form method="POST">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td class="label">Username</td>
|
||||||
|
<td><input type="text" name="username" value="{{username}}"></td>
|
||||||
|
<td class="error"></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="label">Password</td>
|
||||||
|
<td><input type="password" name="password" value=""></td>
|
||||||
|
<td class="error">{{login_error}}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</details>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
%if (username == None):
|
||||||
|
<a href="/login">Login</a>
|
||||||
|
%end
|
||||||
|
%if (username != None):
|
||||||
|
<a href="/logout">{{username}}</a>
|
||||||
|
%end
|
||||||
|
<p>Ingenieurbüro Thomas Peetz</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Kontor</title>
|
||||||
|
<link rel="stylesheet" href="/css/kontor.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>Kontor</header>
|
||||||
|
<nav><ul>
|
||||||
|
<li><a href="/">Kontor</a></li>
|
||||||
|
<li><a href="/comics">Comics</a></li>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/comics/artist">Artists</a></li>
|
||||||
|
<li><a href="/comics/publisher">Publishers</a></li>
|
||||||
|
</ul>
|
||||||
|
<li><a href="/library">Bücher</a></li>
|
||||||
|
<li><a href="/medien">Medien</a></li>
|
||||||
|
<li><a href="/tradingcards">Trading Cards</a></li>
|
||||||
|
</ul></nav>
|
||||||
|
<main role="main">
|
||||||
|
<details>
|
||||||
|
<ul>
|
||||||
|
%for publisher in publishers:
|
||||||
|
<li><a href="/comics/publisher/{{publisher['_id']}}">{{publisher['name']}}</a></li>
|
||||||
|
%end
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
%if (username == None):
|
||||||
|
<a href="/login">Login</a>
|
||||||
|
%end
|
||||||
|
%if (username != None):
|
||||||
|
<a href="/logout">{{username}}</a>
|
||||||
|
%end
|
||||||
|
<p>Ingenieurbüro Thomas Peetz</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Kontor</title>
|
||||||
|
<link rel="stylesheet" href="/css/kontor.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>Kontor</header>
|
||||||
|
<nav><ul>
|
||||||
|
<li><a href="/">Kontor</a></li>
|
||||||
|
<li><a href="/comics/comic">Comics</a></li>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/comics/artist">Artists</a></li>
|
||||||
|
<li><a href="/comics/publisher">Publishers</a></li>
|
||||||
|
</ul>
|
||||||
|
<li><a href="/library">Bücher</a></li>
|
||||||
|
<li><a href="/medien">Medien</a></li>
|
||||||
|
<li><a href="/tradingcards">Trading Cards</a></li>
|
||||||
|
</ul></nav>
|
||||||
|
<main role="main">
|
||||||
|
<details>
|
||||||
|
<form action="/comics/publisher/create" method="POST">
|
||||||
|
{{errors}}
|
||||||
|
<h2>Title</h2>
|
||||||
|
<input type="hidden" name="id", value="{{id}}">
|
||||||
|
<input type="text" name="name" size="60" value="{{name}}"><br>
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</details>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
%if (username == None):
|
||||||
|
<a href="/login">Login</a>
|
||||||
|
%end
|
||||||
|
%if (username != None):
|
||||||
|
<a href="/logout">{{username}}</a>
|
||||||
|
%end
|
||||||
|
<p>Ingenieurbüro Thomas Peetz</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Kontor</title>
|
||||||
|
<link rel="stylesheet" href="/css/kontor.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>Kontor</header>
|
||||||
|
<nav><ul>
|
||||||
|
<li><a href="/">Kontor</a></li>
|
||||||
|
<li><a href="/comics">Comics</a></li>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/comics/artist">Artists</a></li>
|
||||||
|
<li><a href="/comics/publisher">Publishers</a></li>
|
||||||
|
</ul>
|
||||||
|
<li><a href="/library">Bücher</a></li>
|
||||||
|
<li><a href="/medien">Medien</a></li>
|
||||||
|
<li><a href="/tradingcards">Trading Cards</a></li>
|
||||||
|
</ul></nav>
|
||||||
|
<main role="main">
|
||||||
|
<details>
|
||||||
|
<h2>Signup</h2>
|
||||||
|
<form method="post">
|
||||||
|
<table>
|
||||||
|
<tr><td class="label">Username</td>
|
||||||
|
<td><input type="text" name="username" value="{{username}}"></td>
|
||||||
|
<td class="error">{{username_error}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">Password</td>
|
||||||
|
<td><input type="password" name="password" value=""></td>
|
||||||
|
<td class="error">{{password_error}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">Verify Password</td>
|
||||||
|
<td><input type="password" name="verify" value=""></td>
|
||||||
|
<td class="error">{{verify_error}}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="label">Email (optional)</td>
|
||||||
|
<td><input type="text" name="email" value="{{email}}"></td>
|
||||||
|
<td class="error">{{email_error}}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<input type="submit">
|
||||||
|
</form>
|
||||||
|
</details>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
%if (username == None):
|
||||||
|
<a href="/login">Login</a>
|
||||||
|
%end
|
||||||
|
%if (username != None):
|
||||||
|
<a href="/logout">{{username}}</a>
|
||||||
|
%end
|
||||||
|
<p>Ingenieurbüro Thomas Peetz</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Kontor</title>
|
||||||
|
<link rel="stylesheet" href="/css/kontor.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>Kontor</header>
|
||||||
|
<nav><ul>
|
||||||
|
<li><a href="/">Kontor</a></li>
|
||||||
|
<li><a href="/comics/comic">Comics</a></li>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/comics/artist">Artists</a></li>
|
||||||
|
<li><a href="/comics/publisher">Publishers</a></li>
|
||||||
|
<li><a href="/comics/storyarc">StoryArcs</a></li>
|
||||||
|
</ul>
|
||||||
|
<li><a href="/library">Bücher</a></li>
|
||||||
|
<li><a href="/medien">Medien</a></li>
|
||||||
|
<li><a href="/tradingcards">Trading Cards</a></li>
|
||||||
|
</ul></nav>
|
||||||
|
<main role="main">
|
||||||
|
<details>
|
||||||
|
<ul>
|
||||||
|
%for storyarc in storyarcs:
|
||||||
|
<li><a href="/comics/storyarc/{{storyarc['_id']}}">{{storyarc['title']}}</a></li>
|
||||||
|
%end
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
%if (username == None):
|
||||||
|
<a href="/login">Login</a>
|
||||||
|
%end
|
||||||
|
%if (username != None):
|
||||||
|
<a href="/logout">{{username}}</a>
|
||||||
|
%end
|
||||||
|
<p>Ingenieurbüro Thomas Peetz</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Kontor</title>
|
||||||
|
<link rel="stylesheet" href="/css/kontor.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>Kontor</header>
|
||||||
|
<nav><ul>
|
||||||
|
<li><a href="/">Kontor</a></li>
|
||||||
|
<li><a href="/comics">Comics</a></li>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/comics/artist">Artists</a></li>
|
||||||
|
<li><a href="/comics/publisher">Publishers</a></li>
|
||||||
|
<li><a href="/comics/storyarc">StoryArcs</a></li>
|
||||||
|
</ul>
|
||||||
|
<li><a href="/library">Bücher</a></li>
|
||||||
|
<li><a href="/medien">Medien</a></li>
|
||||||
|
<li><a href="/tradingcards">Trading Cards</a></li>
|
||||||
|
</ul></nav>
|
||||||
|
<main role="main">
|
||||||
|
<details>
|
||||||
|
<form action="/comics/storyarc/create" method="POST">
|
||||||
|
{{errors}}
|
||||||
|
<h2>Title</h2>
|
||||||
|
<input type="hidden" name="id", value="{{id}}">
|
||||||
|
<input type="text" name="title" size="60" value="{{title}}"><br>
|
||||||
|
<p>
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</details>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
%if (username == None):
|
||||||
|
<a href="/login">Login</a>
|
||||||
|
%end
|
||||||
|
%if (username != None):
|
||||||
|
<a href="/logout">{{username}}</a>
|
||||||
|
%end
|
||||||
|
<p>Ingenieurbüro Thomas Peetz</p>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
services:
|
||||||
|
mongodb:
|
||||||
|
image: mongo
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- db-data:/var/lib/mongo
|
||||||
|
networks:
|
||||||
|
- backend-network
|
||||||
|
app:
|
||||||
|
build: app
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- 9000:9000
|
||||||
|
networks:
|
||||||
|
- backend-network
|
||||||
|
- frontend-network
|
||||||
|
nginx:
|
||||||
|
image: nginx
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ./nginx:/etc/nginx/conf.d
|
||||||
|
- ./front-end:/var/www/front-end
|
||||||
|
ports:
|
||||||
|
- 8070:80
|
||||||
|
networks:
|
||||||
|
- frontend-network
|
||||||
|
volumes:
|
||||||
|
db-data:
|
||||||
|
networks:
|
||||||
|
backend-network:
|
||||||
|
frontend-network:
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Hello!</title>
|
||||||
|
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||||
|
<meta content="utf-8" http-equiv="encoding">
|
||||||
|
<style>
|
||||||
|
*, ::after, ::before {
|
||||||
|
box-sizing: inherit;
|
||||||
|
background-color: #9eb5c2;
|
||||||
|
color: rgb(8, 8, 71);
|
||||||
|
}
|
||||||
|
.moby {
|
||||||
|
padding: 2rem 1rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
border-radius: .3rem;
|
||||||
|
border-bottom: 0;
|
||||||
|
text-align: center;
|
||||||
|
align-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4rem 2rem;
|
||||||
|
}
|
||||||
|
.moby button {
|
||||||
|
color: #fff;
|
||||||
|
background-color: rgb(6, 105, 138);
|
||||||
|
border-color: rgb(6, 105, 138);
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
.moby .query {
|
||||||
|
text-align: left;
|
||||||
|
border: 3px dotted #e9ecef;
|
||||||
|
padding: 1.5rem 1.2rem;
|
||||||
|
max-width: 800px;
|
||||||
|
min-height: 200px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
border-radius: .3rem;
|
||||||
|
}
|
||||||
|
.moby .query button:hover{
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #73abff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="moby">
|
||||||
|
<img src="https://www.docker.com/sites/default/files/Whale%20Logo332_5.png" />
|
||||||
|
<h1>Hello there!</h1>
|
||||||
|
<p>Simple DEV environment setup with Docker and Docker Compose</p>
|
||||||
|
<div class="query">
|
||||||
|
<p>Set url path(default is '/'), then query the app service.</p>
|
||||||
|
<div>
|
||||||
|
<button type="submit" onclick="queryServer()">GET</button>
|
||||||
|
<input id="path" type="text">
|
||||||
|
</div>
|
||||||
|
<h3>Server response</h3>
|
||||||
|
<div id="response">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function queryServer() {
|
||||||
|
const Http = new XMLHttpRequest();
|
||||||
|
const path = document.getElementById('path').value;
|
||||||
|
const url = "/";
|
||||||
|
Http.open("GET", url + path);
|
||||||
|
Http.send();
|
||||||
|
|
||||||
|
Http.onreadystatechange = (e) => {
|
||||||
|
document.getElementById('response').innerHTML = Http.responseText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost;
|
||||||
|
root /var/www/front-end;
|
||||||
|
|
||||||
|
location /api {
|
||||||
|
proxy_pass http://app:9000;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user