import from kontor-flask branch develop/0.1.0
This commit is contained in:
committed by
Thomas Peetz
parent
0d2f27f771
commit
28746adfbb
@@ -0,0 +1,2 @@
|
||||
__pycache__/
|
||||
.idea
|
||||
@@ -0,0 +1,2 @@
|
||||
# Kontor Flask
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
from kontor import create_app
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = create_app()
|
||||
app.run(host="0.0.0.0", port=8000, debug=True)
|
||||
@@ -1,47 +0,0 @@
|
||||
# config.py
|
||||
|
||||
|
||||
class Config(object):
|
||||
"""
|
||||
Common configurations
|
||||
"""
|
||||
|
||||
# Put any configurations here that are common across all environments
|
||||
host = '127.0.0.1'
|
||||
port = 8500
|
||||
database = 'kontor'
|
||||
|
||||
|
||||
class DevelopmentConfig(Config):
|
||||
"""
|
||||
Development configurations
|
||||
"""
|
||||
|
||||
DEBUG = True
|
||||
host = '0.0.0.0'
|
||||
database = 'kontor_dev'
|
||||
|
||||
|
||||
class ProductionConfig(Config):
|
||||
"""
|
||||
Production configurations
|
||||
"""
|
||||
|
||||
DEBUG = False
|
||||
|
||||
class TestingConfig(Config):
|
||||
"""
|
||||
Testing configurations
|
||||
"""
|
||||
|
||||
TESTING = True
|
||||
DEBUG = True
|
||||
port = 8600
|
||||
database = 'kontor_test'
|
||||
|
||||
app_config = {
|
||||
'development': DevelopmentConfig,
|
||||
'production': ProductionConfig,
|
||||
'testing': TestingConfig
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXPROJ = KontorFlask
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
@@ -1,200 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Kontor Flask documentation build configuration file, created by
|
||||
# sphinx-quickstart on Mon Nov 6 08:53:04 2017.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = ['sphinx.ext.autodoc',
|
||||
'sphinx.ext.doctest',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx.ext.coverage',
|
||||
'sphinx.ext.mathjax',
|
||||
'sphinx.ext.ifconfig',
|
||||
'sphinx.ext.viewcode']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'Kontor Flask'
|
||||
copyright = '2017, Thomas Peetz'
|
||||
author = 'Thomas Peetz'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.0.7'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = 'de'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'alabaster'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
#
|
||||
# This is required for the alabaster theme
|
||||
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
|
||||
html_sidebars = {
|
||||
'**': [
|
||||
'relations.html', # needs 'show_related': True theme option to display
|
||||
'searchbox.html',
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'KontorFlaskdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'KontorFlask.tex', 'Kontor Flask Documentation',
|
||||
'Thomas Peetz', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'kontorflask', 'Kontor Flask Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'KontorFlask', 'Kontor Flask Documentation',
|
||||
author, 'KontorFlask', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
|
||||
# -- Options for Epub output ----------------------------------------------
|
||||
|
||||
# Bibliographic Dublin Core info.
|
||||
epub_title = project
|
||||
epub_author = author
|
||||
epub_publisher = author
|
||||
epub_copyright = copyright
|
||||
|
||||
# The unique identifier of the text. This can be a ISBN number
|
||||
# or the project homepage.
|
||||
#
|
||||
# epub_identifier = ''
|
||||
|
||||
# A unique identification for the text.
|
||||
#
|
||||
# epub_uid = ''
|
||||
|
||||
# A list of files that should not be packed into the epub file.
|
||||
epub_exclude_files = ['search.html']
|
||||
|
||||
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'https://docs.python.org/': None}
|
||||
@@ -1,20 +0,0 @@
|
||||
.. Kontor Flask documentation master file, created by
|
||||
sphinx-quickstart on Mon Nov 6 08:53:04 2017.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
Welcome to Kontor Flask's documentation!
|
||||
========================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
+51
-64
@@ -1,74 +1,61 @@
|
||||
"""
|
||||
Module kontor implements Kontor application.
|
||||
"""
|
||||
from flask import Flask, render_template
|
||||
from flask_jwt_extended import JWTManager
|
||||
|
||||
from flask import Flask
|
||||
from flask_bootstrap import Bootstrap
|
||||
from flask_login import LoginManager
|
||||
from pymodm import connect
|
||||
from kontor import config
|
||||
from kontor.extensions import db, ma
|
||||
from logging.config import dictConfig
|
||||
|
||||
# local imports
|
||||
from config import app_config
|
||||
from .version import __version__
|
||||
dictConfig({
|
||||
'version': 1,
|
||||
'formatters': {'default': {
|
||||
'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
|
||||
}},
|
||||
'handlers': {'wsgi': {
|
||||
'class': 'logging.StreamHandler',
|
||||
'stream': 'ext://flask.logging.wsgi_errors_stream',
|
||||
'formatter': 'default'
|
||||
}},
|
||||
'root': {
|
||||
'level': 'INFO',
|
||||
'handlers': ['wsgi']
|
||||
}
|
||||
})
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
_LOGIN_MANAGER_ = LoginManager()
|
||||
def create_app(config_class=config.Config):
|
||||
app.config.from_object(config_class)
|
||||
|
||||
db.init_app(app)
|
||||
ma.init_app(app)
|
||||
# Initialize Flask extensions here
|
||||
app.config["JWT_SECRET_KEY"] = "super-secret" # Change this!
|
||||
jwt = JWTManager(app)
|
||||
|
||||
def get_host(config_name):
|
||||
"""
|
||||
Returns host address from configuration.
|
||||
:param config_name:
|
||||
:return: host address
|
||||
"""
|
||||
host = app_config[config_name].host
|
||||
return host
|
||||
with app.app_context():
|
||||
# db.create_all()
|
||||
db.reflect()
|
||||
|
||||
# Register blueprints here
|
||||
from kontor.main import bp as main_bp
|
||||
app.register_blueprint(main_bp)
|
||||
from kontor.comics import comics_bp
|
||||
app.register_blueprint(comics_bp, url_prefix='/comics')
|
||||
from kontor.api import api_bp
|
||||
app.register_blueprint(api_bp, url_prefix='/api/v1')
|
||||
from kontor.comics import comics_api
|
||||
app.register_blueprint(comics_api, url_prefix='/api/v1/comics')
|
||||
|
||||
def get_port(config_name):
|
||||
"""
|
||||
Returns port number from configuration.
|
||||
:param config_name:
|
||||
:return: port number
|
||||
"""
|
||||
port = app_config[config_name].port
|
||||
return port
|
||||
|
||||
|
||||
def create_app(config_name):
|
||||
"""
|
||||
Returns Flask application.
|
||||
:param config_name:
|
||||
:return: Flask application
|
||||
"""
|
||||
app = Flask(__name__, instance_relative_config=True)
|
||||
app.config.from_object(app_config[config_name])
|
||||
app.config.from_pyfile('config.py')
|
||||
|
||||
database = "mongodb://localhost:27017/{}".format(app_config[config_name].database)
|
||||
connect(database, alias="kontor")
|
||||
|
||||
Bootstrap(app)
|
||||
_LOGIN_MANAGER_.init_app(app)
|
||||
_LOGIN_MANAGER_.login_message = "You must be logged in to access this page."
|
||||
_LOGIN_MANAGER_.login_view = "auth.login"
|
||||
|
||||
from .admin.views import ADMIN as ADMIN_BLUEPRINT
|
||||
app.register_blueprint(ADMIN_BLUEPRINT, url_prefix='/admin')
|
||||
|
||||
from .auth.views import AUTH as AUTH_BLUEPRINT
|
||||
app.register_blueprint(AUTH_BLUEPRINT)
|
||||
|
||||
from .home.views import HOME as HOME_BLUEPRINT
|
||||
app.register_blueprint(HOME_BLUEPRINT)
|
||||
|
||||
from .comics.views import COMIC as COMIC_BLUEPRINT
|
||||
app.register_blueprint(COMIC_BLUEPRINT, url_prefix='/comics')
|
||||
|
||||
from .library.views import LIBRARY as LIBRARY_BLUEPRINT
|
||||
app.register_blueprint(LIBRARY_BLUEPRINT, url_prefix='/library')
|
||||
|
||||
from .tysc.views import TYSC as TYSC_BLUEPRINT
|
||||
app.register_blueprint(TYSC_BLUEPRINT, url_prefix='/tysc')
|
||||
from kontor.media import media_bp
|
||||
app.register_blueprint(media_bp, url_prefix='/media')
|
||||
from kontor.media import media_api
|
||||
app.register_blueprint(media_api, url_prefix='/api/v1/media')
|
||||
# from kontor.auth.auth import auth_bp
|
||||
# from kontor.cart.cart import cart_bp
|
||||
# from kontor.general.general import general_bp
|
||||
# app.register_blueprint(auth_bp)
|
||||
# app.register_blueprint(cart_bp, url_prefix='/cart')
|
||||
# app.register_blueprint(general_bp)
|
||||
|
||||
return app
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
"""
|
||||
Module admin implements administration functions.
|
||||
"""
|
||||
from . import views
|
||||
@@ -1,17 +0,0 @@
|
||||
"""
|
||||
Define form to edit users
|
||||
"""
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, SubmitField
|
||||
from wtforms.validators import DataRequired
|
||||
|
||||
|
||||
class UserEditForm(FlaskForm):
|
||||
"""
|
||||
Form for admin to edit users
|
||||
"""
|
||||
email = StringField('Email', validators=[DataRequired()])
|
||||
username = StringField('Username', validators=[DataRequired()])
|
||||
first_name = StringField('First Name', validators=[DataRequired()])
|
||||
last_name = StringField('Last Name', validators=[DataRequired()])
|
||||
submit = SubmitField('Submit')
|
||||
@@ -1,63 +0,0 @@
|
||||
"""
|
||||
Define routing rules for managing users
|
||||
"""
|
||||
from flask import abort, Blueprint, flash, redirect, render_template, url_for
|
||||
from flask_login import current_user, login_required
|
||||
|
||||
from .forms import UserEditForm
|
||||
from ..models import User
|
||||
|
||||
ADMIN = Blueprint('admin', __name__)
|
||||
|
||||
|
||||
def check_admin():
|
||||
"""
|
||||
Prevent non-admins from accessing the page
|
||||
"""
|
||||
if not current_user.is_admin:
|
||||
abort(403)
|
||||
|
||||
|
||||
# User Views
|
||||
@ADMIN.route('/users')
|
||||
@login_required
|
||||
def list_users():
|
||||
"""
|
||||
List all users
|
||||
"""
|
||||
check_admin()
|
||||
|
||||
users = User.objects.all()
|
||||
return render_template('admin/users/users.html',
|
||||
users=users, title='Users')
|
||||
|
||||
|
||||
@ADMIN.route('/users/edit/<user_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_user(user_id):
|
||||
"""
|
||||
Edit an user.
|
||||
"""
|
||||
check_admin()
|
||||
|
||||
user = User.objects.get({'username': user_id})
|
||||
|
||||
# prevent admin from being assigned a department or role
|
||||
if user.is_admin:
|
||||
abort(403)
|
||||
|
||||
form = UserEditForm(obj=user)
|
||||
if form.validate_on_submit():
|
||||
user.email = form.email.data
|
||||
user.username = form.username.data
|
||||
user.first_name = form.first_name.data
|
||||
user.last_name = form.last_name.data
|
||||
user.save()
|
||||
flash('You have successfully edited an user.')
|
||||
|
||||
# redirect to the roles page
|
||||
return redirect(url_for('admin.list_users'))
|
||||
|
||||
return render_template('admin/users/user.html',
|
||||
user=user, form=form,
|
||||
title='Edit User')
|
||||
@@ -0,0 +1,5 @@
|
||||
from flask import Blueprint
|
||||
|
||||
api_bp = Blueprint('api_bp', __name__)
|
||||
|
||||
from kontor.api import routes
|
||||
@@ -0,0 +1,30 @@
|
||||
from flask import jsonify, request
|
||||
from flask_jwt_extended import jwt_required, get_jwt_identity, create_access_token
|
||||
|
||||
from kontor.api import api_bp
|
||||
|
||||
|
||||
@api_bp.route('/')
|
||||
def index():
|
||||
modules = ['comics']
|
||||
return jsonify(modules)
|
||||
|
||||
|
||||
# Create a route to authenticate your users and return JWTs. The
|
||||
# create_access_token() function is used to actually generate the JWT.
|
||||
@api_bp.route("/login", methods=["POST"])
|
||||
def login():
|
||||
username = request.json.get("username", None)
|
||||
password = request.json.get("password", None)
|
||||
if username != "test" or password != "test":
|
||||
return jsonify({"msg": "Bad username or password"}), 401
|
||||
|
||||
access_token = create_access_token(identity=username)
|
||||
return jsonify(access_token=access_token)
|
||||
|
||||
|
||||
@api_bp.route('/protected', methods=['GET'])
|
||||
@jwt_required()
|
||||
def protected():
|
||||
current_user = get_jwt_identity()
|
||||
return {'message': f'Hello, {current_user}!'}
|
||||
@@ -1,4 +1,22 @@
|
||||
"""
|
||||
Module auth implements authentication functions.
|
||||
"""
|
||||
from . import views
|
||||
import bcrypt
|
||||
from flask import session
|
||||
from flask_httpauth import HTTPBasicAuth
|
||||
|
||||
from kontor import app
|
||||
from kontor.auth.models import User
|
||||
|
||||
auth = HTTPBasicAuth()
|
||||
|
||||
|
||||
@auth.verify_password
|
||||
def verify_password(username, password):
|
||||
if username is None:
|
||||
return False
|
||||
# Add your authentication logic here
|
||||
app.logger.info("login user %s", username)
|
||||
user = User.query.filter_by(user_name=username).first()
|
||||
app.logger.info("User: %s", user)
|
||||
app.logger.info("Stored Password: '%s' Hashed Password: '%s'", user.password, bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()))
|
||||
if 'user_name' in session and session['user_name'] == username:
|
||||
return True
|
||||
return False
|
||||
@@ -1,50 +0,0 @@
|
||||
"""
|
||||
Contains forms for authentication.
|
||||
"""
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import PasswordField, StringField, SubmitField, ValidationError
|
||||
from wtforms.validators import DataRequired, Email, EqualTo
|
||||
|
||||
from ..models import User
|
||||
|
||||
|
||||
class RegistrationForm(FlaskForm):
|
||||
"""
|
||||
Form for users to create new account
|
||||
"""
|
||||
email = StringField('Email', validators=[DataRequired(), Email()])
|
||||
username = StringField('Username', validators=[DataRequired()])
|
||||
first_name = StringField('First Name', validators=[DataRequired()])
|
||||
last_name = StringField('Last Name', validators=[DataRequired()])
|
||||
password = PasswordField('Password', validators=[DataRequired(),
|
||||
EqualTo('confirm_password')
|
||||
])
|
||||
confirm_password = PasswordField('Confirm Password')
|
||||
submit = SubmitField('Register')
|
||||
|
||||
def validate_email(self, field):
|
||||
"""
|
||||
Check if email is already in use.
|
||||
:param field:
|
||||
:return:
|
||||
"""
|
||||
if User.objects.raw({'email': field.data}).count() > 0:
|
||||
raise ValidationError('Email is already in use.')
|
||||
|
||||
def validate_username(self, field):
|
||||
"""
|
||||
check if username is already in use.
|
||||
:param field:
|
||||
:return:
|
||||
"""
|
||||
if User.objects.raw({'username': field.data}).count() > 0:
|
||||
raise ValidationError('Username is already in use.')
|
||||
|
||||
|
||||
class LoginForm(FlaskForm):
|
||||
"""
|
||||
Form for users to login
|
||||
"""
|
||||
email = StringField('Email', validators=[DataRequired(), Email()])
|
||||
password = PasswordField('Password', validators=[DataRequired()])
|
||||
submit = SubmitField('Login')
|
||||
@@ -0,0 +1,45 @@
|
||||
from kontor.extensions import db, ma
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
|
||||
class User(db.Model):
|
||||
# __table__ = db.metadata.tables["publisher"]
|
||||
__tablename__ = "user"
|
||||
__table_args__ = {'extend_existing': True}
|
||||
id = db.Column(db.String, primary_key=True)
|
||||
created_date = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
last_modified_date = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
version = db.Column(db.Integer)
|
||||
enabled = db.Column(db.SmallInteger)
|
||||
email = db.Column(db.String)
|
||||
first_name = db.Column(db.String)
|
||||
last_name = db.Column(db.String)
|
||||
user_name = db.Column(db.String)
|
||||
password = db.Column(db.String)
|
||||
token = db.Column(db.String)
|
||||
token_expired = db.Column(db.SmallInteger)
|
||||
|
||||
def is_token_valid(self):
|
||||
return self.review == 'b\x01'
|
||||
|
||||
def is_user_enabled(self):
|
||||
return self.should_download == 'b\x01'
|
||||
|
||||
class Role(db.Model):
|
||||
__tablename__ = "role"
|
||||
__table_args__ = {'extend_existing': True}
|
||||
id = db.Column(db.String, primary_key=True)
|
||||
created_date = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
last_modified_date = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
version = db.Column(db.Integer)
|
||||
name = db.Column(db.String)
|
||||
|
||||
class AuthorizationMatrix(db.Model):
|
||||
__tablename__ = "authorization_matrix"
|
||||
__table_args__ = {'extend_existing': True}
|
||||
id = db.Column(db.String, primary_key=True)
|
||||
created_date = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
last_modified_date = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
version = db.Column(db.Integer)
|
||||
role_id = db.Column(db.String, db.ForeignKey("role.id"))
|
||||
user_id = db.Column(db.String, db.ForeignKey("user.id"))
|
||||
@@ -1,79 +0,0 @@
|
||||
"""
|
||||
Define routing rules for registering users and login and logout.
|
||||
"""
|
||||
from flask import Blueprint, flash, redirect, render_template, url_for
|
||||
from flask_login import login_required, login_user, logout_user
|
||||
from .forms import LoginForm, RegistrationForm
|
||||
from ..models import User
|
||||
|
||||
AUTH = Blueprint('auth', __name__)
|
||||
|
||||
|
||||
@AUTH.route('/register', methods=['GET', 'POST'])
|
||||
def register():
|
||||
"""
|
||||
Handle requests to the /register route
|
||||
Add an employee to the database through the registration form
|
||||
"""
|
||||
form = RegistrationForm()
|
||||
if form.validate_on_submit():
|
||||
user = User()
|
||||
user.email = form.email.data
|
||||
user.username = form.username.data
|
||||
user.first_name = form.first_name.data
|
||||
user.last_name = form.last_name.data
|
||||
user.password = form.password.data
|
||||
# add employee to the database
|
||||
user.save()
|
||||
flash('You have successfully registered! You may now login.')
|
||||
|
||||
# redirect to the login page
|
||||
return redirect(url_for('auth.login'))
|
||||
|
||||
# load registration template
|
||||
return render_template('auth/register.html', form=form, title='Register')
|
||||
|
||||
|
||||
@AUTH.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
"""
|
||||
Handle requests to the /login route
|
||||
Validate given email with matching password
|
||||
:return:
|
||||
"""
|
||||
form = LoginForm()
|
||||
if form.validate_on_submit():
|
||||
|
||||
# check whether employee exists in the database and whether
|
||||
# the password entered matches the password in the database
|
||||
user = User.objects.get({'email': form.email.data})
|
||||
if user is not None and user.verify_password(
|
||||
form.password.data):
|
||||
# log employee in
|
||||
login_user(user)
|
||||
|
||||
# redirect to the appropriate dashboard page
|
||||
if user.is_admin:
|
||||
return redirect(url_for('home.admin_dashboard'))
|
||||
else:
|
||||
return redirect(url_for('home.dashboard'))
|
||||
|
||||
# when login details are incorrect
|
||||
else:
|
||||
flash('Invalid email or password.')
|
||||
|
||||
# load login template
|
||||
return render_template('auth/login.html', form=form, title='Login')
|
||||
|
||||
@AUTH.route('/logout')
|
||||
@login_required
|
||||
def logout():
|
||||
"""
|
||||
Handle requests to the /logout route
|
||||
Log an employee out through the logout link
|
||||
"""
|
||||
logout_user()
|
||||
flash('You have successfully been logged out.')
|
||||
|
||||
# redirect to the login page
|
||||
return redirect(url_for('auth.login'))
|
||||
@@ -1,3 +1,9 @@
|
||||
"""
|
||||
Define routing rules for comic related information
|
||||
"""
|
||||
from flask import Blueprint
|
||||
|
||||
comics_bp = Blueprint('comics_bp', __name__,
|
||||
template_folder='templates',
|
||||
static_folder='static', static_url_path='assets')
|
||||
comics_api = Blueprint('comics_api', __name__)
|
||||
|
||||
from kontor.comics import routes
|
||||
from kontor.comics import api
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
from flask import Blueprint, render_template, jsonify
|
||||
|
||||
from kontor.comics import comics_api
|
||||
from kontor.models import Comic, comics_schema, Publisher, comic_schema, publisher_schema, publishers_schema
|
||||
|
||||
|
||||
@comics_api.route('/')
|
||||
def index():
|
||||
comics = Comic.query.all()
|
||||
return comics_schema.dump(comics)
|
||||
|
||||
|
||||
@comics_api.route('/comic/<string:comic_id>')
|
||||
def view(comic_id):
|
||||
comic = Comic.query.get(comic_id)
|
||||
return comic_schema.dump(comic)
|
||||
|
||||
|
||||
@comics_api.route('/publisher/')
|
||||
def publisher_all():
|
||||
publishers = Publisher.query.all()
|
||||
return publishers_schema.dump(publishers)
|
||||
|
||||
|
||||
@comics_api.route('/publisher/<string:id>')
|
||||
def publisher_detail(publisher_id):
|
||||
publisher = Publisher.query.get(publisher_id)
|
||||
return publisher_schema.dump(publisher)
|
||||
@@ -1,31 +0,0 @@
|
||||
"""Define form to edit publisher, artists and comics"""
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, SubmitField, BooleanField, SelectField
|
||||
from wtforms.validators import DataRequired
|
||||
from bson import ObjectId
|
||||
|
||||
|
||||
class PublisherForm(FlaskForm):
|
||||
"""
|
||||
Form to add and edit a Comic publisher
|
||||
"""
|
||||
name = StringField('Name', validators=[DataRequired()])
|
||||
submit = SubmitField('Submit')
|
||||
|
||||
|
||||
class ArtistForm(FlaskForm):
|
||||
"""
|
||||
Form to add and edit a Comic publisher
|
||||
"""
|
||||
name = StringField('Name', validators=[DataRequired()])
|
||||
submit = SubmitField('Submit')
|
||||
|
||||
|
||||
class ComicForm(FlaskForm):
|
||||
"""
|
||||
Form to add and edit Comics
|
||||
"""
|
||||
title = StringField('Title', validators=[DataRequired()])
|
||||
publisher = SelectField('Publisher', coerce=ObjectId)
|
||||
current_order = BooleanField('Current Order')
|
||||
submit = SubmitField('Submit')
|
||||
@@ -1,51 +0,0 @@
|
||||
"""This modules declares the model for Comic related information."""
|
||||
|
||||
from flask import current_app
|
||||
from pymongo.write_concern import WriteConcern
|
||||
from pymodm import MongoModel, fields
|
||||
|
||||
|
||||
class Publisher(MongoModel):
|
||||
"""Class Publisher represents a publisher of a comic."""
|
||||
name = fields.CharField()
|
||||
|
||||
def __str__(self):
|
||||
return "Publisher({})".format(self.name)
|
||||
|
||||
@property
|
||||
def comics(self):
|
||||
"""
|
||||
Return list of comics which has reference to this publisher
|
||||
:return:
|
||||
"""
|
||||
comics = Comic.objects.raw({'publisher': self.pk})
|
||||
current_app.logger.debug(comics)
|
||||
return comics
|
||||
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
|
||||
|
||||
class Artist(MongoModel):
|
||||
"""Class Artist represents a comic artist."""
|
||||
name = fields.CharField()
|
||||
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
|
||||
|
||||
class Comic(MongoModel):
|
||||
"""Class Comic represents a comic."""
|
||||
title = fields.CharField()
|
||||
publisher = fields.ReferenceField(Publisher)
|
||||
current_order = fields.BooleanField(default=False)
|
||||
completed = fields.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
@@ -0,0 +1,16 @@
|
||||
from flask import Blueprint, render_template
|
||||
|
||||
from kontor.comics import comics_bp
|
||||
from kontor.models import Comic
|
||||
|
||||
|
||||
@comics_bp.route('/')
|
||||
def index():
|
||||
comics = Comic.query.all()
|
||||
return render_template('comics/list.html', comics=comics)
|
||||
|
||||
|
||||
@comics_bp.route('/comic/<string:comic_id>')
|
||||
def view(comic_id):
|
||||
comic = Comic.query.get(comic_id)
|
||||
return render_template('comics/view.html', comic=comic)
|
||||
@@ -0,0 +1,28 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<span class="title">
|
||||
<h1>{% block title %} Comics {% endblock %}</h1>
|
||||
</span>
|
||||
<div class="comics">
|
||||
<h2>Comics Blueprint</h2>
|
||||
{% for comic in comics %}
|
||||
<div class="comic">
|
||||
<b>
|
||||
<p class="name">
|
||||
<a href="{{ url_for('comics_bp.view', comic_id=comic.id)}}">{{ comic.title }}</a>
|
||||
</p>
|
||||
</b>
|
||||
<b><p class="identifier">{{ comic.publisher.name }}</p></b>
|
||||
<div class="date">
|
||||
<h4>Created</h4>
|
||||
<p>{{ comic.created_date }}</p>
|
||||
<h4>Modified</h4>
|
||||
<p>{{ comic.last_modified_date }}</p>
|
||||
</div>
|
||||
<p>Version: {{ comic.version }}</p>
|
||||
<p>Review: {{ comic.review }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,27 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<span class="title">
|
||||
<h1>{% block title %} Comics {% endblock %}</h1>
|
||||
</span>
|
||||
<div class="comics">
|
||||
<h2>Comics Blueprint</h2>
|
||||
<div class="comic">
|
||||
<b>
|
||||
<p class="name">
|
||||
<a href="{{ url_for('comics_bp.view', comic_id=comic.id)}}">{{ comic.title }}</a>
|
||||
</p>
|
||||
</b>
|
||||
<b>
|
||||
<p class="identifier">{{ comic.id }}</p>
|
||||
</b>
|
||||
<div class="date">
|
||||
<h4>Created</h4>
|
||||
<p>{{ comic.created_date }}</p>
|
||||
<h4>Modified</h4>
|
||||
<p>{{ comic.last_modified_date }}</p>
|
||||
</div>
|
||||
<p>Version: {{ comic.version }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,222 +0,0 @@
|
||||
"""
|
||||
Define routing rules for comics, publisher and artists
|
||||
"""
|
||||
from flask import Blueprint, flash, redirect, render_template, url_for
|
||||
from flask_login import login_required
|
||||
from bson import ObjectId
|
||||
from pymongo.errors import PyMongoError
|
||||
from .forms import ComicForm, PublisherForm, ArtistForm
|
||||
from .models import Comic, Publisher, Artist
|
||||
|
||||
|
||||
COMIC = Blueprint('comic', __name__)
|
||||
|
||||
|
||||
@COMIC.route('/artists')
|
||||
@login_required
|
||||
def list_artists():
|
||||
"""
|
||||
List all artists
|
||||
:return:
|
||||
"""
|
||||
artists = Artist.objects.all()
|
||||
return render_template('comics/artists.html',
|
||||
artists=artists, title="Artists")
|
||||
|
||||
|
||||
@COMIC.route('/artists/edit/<artist_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_artist(artist_id):
|
||||
"""
|
||||
Edit a comic artist
|
||||
"""
|
||||
artist = Artist.objects.get({'_id': ObjectId(artist_id)})
|
||||
form = ArtistForm(obj=artist)
|
||||
if form.validate_on_submit():
|
||||
artist.name = form.name.data
|
||||
artist.save()
|
||||
flash('You have successfully edited the artist.')
|
||||
return redirect(url_for('comic.list_artists'))
|
||||
form.name.data = artist.name
|
||||
return render_template('simpleform.html', action="Edit",
|
||||
form=form, title="Edit Artist")
|
||||
|
||||
|
||||
@COMIC.route('/artists/add', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_artist():
|
||||
"""
|
||||
Add a artist
|
||||
:return:
|
||||
"""
|
||||
form = ArtistForm()
|
||||
if form.validate_on_submit():
|
||||
artist = Artist()
|
||||
artist.name = form.name.data
|
||||
try:
|
||||
# add publisher to the database
|
||||
artist.save()
|
||||
flash('You have successfully added a new artist.')
|
||||
except PyMongoError:
|
||||
# in case publisher name already exists
|
||||
flash('Error: artist name already exists.')
|
||||
return redirect(url_for('comic.list_artists'))
|
||||
return render_template('simpleform.html', action="Add",
|
||||
form=form, title="Add Artist")
|
||||
|
||||
|
||||
@COMIC.route('/artists/delete/<artist_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def delete_artist(artist_id):
|
||||
"""
|
||||
Delete a comic artist
|
||||
:param artist_id:
|
||||
:return:
|
||||
"""
|
||||
artist = Artist.objects.raw({'_id': ObjectId(artist_id)})
|
||||
if artist:
|
||||
artist.delete()
|
||||
flash('You have successfully deleted the comic artist.')
|
||||
return redirect(url_for('comic.list_artists'))
|
||||
|
||||
|
||||
@COMIC.route('/publishers')
|
||||
@login_required
|
||||
def list_publishers():
|
||||
"""
|
||||
List all publishers
|
||||
:return:
|
||||
"""
|
||||
publishers = Publisher.objects.all()
|
||||
return render_template('comics/publishers.html',
|
||||
publishers=publishers, title="Publishers")
|
||||
|
||||
|
||||
@COMIC.route('/publishers/add', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_publisher():
|
||||
"""
|
||||
Add a publisher to the database
|
||||
:return:
|
||||
"""
|
||||
form = PublisherForm()
|
||||
if form.validate_on_submit():
|
||||
publisher = Publisher()
|
||||
publisher.name = form.name.data
|
||||
try:
|
||||
# add publisher to the database
|
||||
publisher.save()
|
||||
flash('You have successfully added a new publisher.')
|
||||
except PyMongoError:
|
||||
# in case publisher name already exists
|
||||
flash('Error: publisher name already exists.')
|
||||
return redirect(url_for('comic.list_publishers'))
|
||||
return render_template('simpleform.html', action="Add",
|
||||
form=form, title="Add Publisher")
|
||||
|
||||
|
||||
@COMIC.route('/publishers/edit/<publisher_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_publisher(publisher_id):
|
||||
"""
|
||||
Edit a publisher
|
||||
"""
|
||||
publisher = Publisher.objects.get({'_id': ObjectId(publisher_id)})
|
||||
form = PublisherForm(obj=publisher)
|
||||
if form.validate_on_submit():
|
||||
publisher.name = form.name.data
|
||||
publisher.save()
|
||||
flash('You have successfully edited the publisher.')
|
||||
return redirect(url_for('comic.list_publishers'))
|
||||
form.name.data = publisher.name
|
||||
return render_template('simpleform.html', action="Edit",
|
||||
form=form, title="Edit Publisher")
|
||||
|
||||
|
||||
@COMIC.route('/publishers/delete/<publisher_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def delete_publisher(publisher_id):
|
||||
"""
|
||||
Delete a publisher
|
||||
:param publisher_id: ObjectId of publisher
|
||||
:return:
|
||||
"""
|
||||
publisher = Publisher.objects.raw({'_id': ObjectId(publisher_id)})
|
||||
if publisher:
|
||||
publisher.delete()
|
||||
flash('You have successfully deleted the publisher.')
|
||||
return redirect(url_for('comic.list_publishers'))
|
||||
|
||||
|
||||
@COMIC.route('/comics')
|
||||
@login_required
|
||||
def list_comics():
|
||||
"""
|
||||
List all comics
|
||||
:return:
|
||||
"""
|
||||
comics = Comic.objects.all()
|
||||
return render_template('comics/comics.html',
|
||||
comics=comics, title="Comics")
|
||||
|
||||
|
||||
@COMIC.route('/comics/edit/<comic_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_comic(comic_id):
|
||||
"""
|
||||
Edit a comic
|
||||
"""
|
||||
comic = Comic.objects.get({'_id': ObjectId(comic_id)})
|
||||
form = ComicForm(obj=comic)
|
||||
form.publisher.choices = [(p.pk, p.name) for p in Publisher.objects.all()]
|
||||
form.publisher.default = comic.publisher.pk
|
||||
form.publisher.process_data(comic.publisher.pk)
|
||||
if form.validate_on_submit():
|
||||
comic.title = form.title.data
|
||||
comic.current_order = form.current_order.data
|
||||
comic.publisher = form.publisher.data
|
||||
comic.save()
|
||||
flash('You have successfully edited the comic.')
|
||||
return redirect(url_for('comic.list_comics'))
|
||||
form.title.data = comic.title
|
||||
form.current_order.data = comic.current_order
|
||||
return render_template('simpleform.html', action="Edit",
|
||||
form=form, title="Edit Comic")
|
||||
|
||||
|
||||
@COMIC.route('/comics/add', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_comic():
|
||||
"""
|
||||
Add a comic
|
||||
:return:
|
||||
"""
|
||||
form = ComicForm()
|
||||
form.publisher.choices = [(p.pk, p.name) for p in Publisher.objects.all()]
|
||||
if form.validate_on_submit():
|
||||
comic = Comic()
|
||||
comic.title = form.title.data
|
||||
comic.publisher = form.publisher.data
|
||||
try:
|
||||
comic.save()
|
||||
flash('You have successfully added a new comic.')
|
||||
except PyMongoError:
|
||||
flash('Error: comic title already exists.')
|
||||
return redirect(url_for('comic.list_comics'))
|
||||
return render_template('simpleform.html', action="Add",
|
||||
form=form, title="Add Comic")
|
||||
|
||||
|
||||
@COMIC.route('/comics/delete/<comic_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def delete_comic(comic_id):
|
||||
"""
|
||||
Delete a comic
|
||||
:param comic_id:
|
||||
:return:
|
||||
"""
|
||||
comic = Comic.objects.raw({'_id': ObjectId(comic_id)})
|
||||
if comic:
|
||||
comic.delete()
|
||||
flash('You have successfully deleted the comic.')
|
||||
return redirect(url_for('comic.list_comics'))
|
||||
@@ -0,0 +1,10 @@
|
||||
import os
|
||||
|
||||
basedir = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
|
||||
class Config:
|
||||
SECRET_KEY = os.environ.get('SECRET_KEY')
|
||||
# SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI') or 'sqlite:///' + os.path.join(basedir, 'kontor.db')
|
||||
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI') or 'mariadb+mariadbconnector://kontor:kontor@localhost/kontor'
|
||||
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
||||
@@ -0,0 +1,5 @@
|
||||
import flask_sqlalchemy
|
||||
from flask_marshmallow import Marshmallow
|
||||
|
||||
db = flask_sqlalchemy.SQLAlchemy()
|
||||
ma = Marshmallow()
|
||||
@@ -1,3 +0,0 @@
|
||||
"""
|
||||
Module for the Kontor homepage.
|
||||
"""
|
||||
@@ -1,39 +0,0 @@
|
||||
"""
|
||||
Define routing rules for homepage and dashboards
|
||||
"""
|
||||
|
||||
from flask import Blueprint, render_template, abort
|
||||
from flask_login import login_required, current_user
|
||||
|
||||
HOME = Blueprint('home', __name__)
|
||||
|
||||
|
||||
@HOME.route('/')
|
||||
def homepage():
|
||||
"""
|
||||
Render the homepage template on the / route
|
||||
"""
|
||||
return render_template('home/index.html', title="Welcome")
|
||||
|
||||
|
||||
@HOME.route('/dashboard')
|
||||
@login_required
|
||||
def dashboard():
|
||||
"""
|
||||
Render the dashboard template on the /dashboard route
|
||||
"""
|
||||
return render_template('home/dashboard.html', title="Dashboard")
|
||||
|
||||
|
||||
@HOME.route('/admin/dashboard')
|
||||
@login_required
|
||||
def admin_dashboard():
|
||||
"""
|
||||
Render the admin_dashboard template on the /admin/dashboard route
|
||||
:return:
|
||||
"""
|
||||
# prevent non-admins from accessing the page
|
||||
if not current_user.is_admin:
|
||||
abort(403)
|
||||
|
||||
return render_template('home/admin_dashboard.html', title="Dashboard")
|
||||
@@ -1,3 +0,0 @@
|
||||
"""
|
||||
Define routing rules for library related information
|
||||
"""
|
||||
@@ -1,35 +0,0 @@
|
||||
"""
|
||||
Define form to edit publisher, artists and books
|
||||
"""
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, SubmitField, SelectField, IntegerField
|
||||
from wtforms.validators import DataRequired, Optional, NumberRange
|
||||
from bson import ObjectId
|
||||
|
||||
|
||||
class PublisherForm(FlaskForm):
|
||||
"""
|
||||
Form to add and edit a Comic publisher
|
||||
"""
|
||||
name = StringField('Name', validators=[DataRequired()])
|
||||
submit = SubmitField('Submit')
|
||||
|
||||
|
||||
class AuthorForm(FlaskForm):
|
||||
"""
|
||||
Form to add and edit a Comic publisher
|
||||
"""
|
||||
name = StringField('Name', validators=[DataRequired()])
|
||||
submit = SubmitField('Submit')
|
||||
|
||||
|
||||
class BookForm(FlaskForm):
|
||||
"""
|
||||
Form to add and edit Comics
|
||||
"""
|
||||
title = StringField('Title', validators=[DataRequired()])
|
||||
author = SelectField('Author', coerce=ObjectId)
|
||||
publisher = SelectField('Publisher', coerce=ObjectId)
|
||||
isbn = StringField('ISBN', validators=[Optional()])
|
||||
year = IntegerField('Year', validators=[NumberRange(min=1970, max=2050)])
|
||||
submit = SubmitField('Submit')
|
||||
@@ -1,55 +0,0 @@
|
||||
"""
|
||||
This module declares the model for the library related information.
|
||||
"""
|
||||
from pymongo.write_concern import WriteConcern
|
||||
from pymodm import MongoModel, fields
|
||||
|
||||
|
||||
class Publisher(MongoModel):
|
||||
"""
|
||||
Class Publisher represents a publisher of a book.
|
||||
"""
|
||||
name = fields.CharField()
|
||||
|
||||
def __str__(self):
|
||||
return "Publisher({})".format(self.name)
|
||||
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
|
||||
|
||||
class Author(MongoModel):
|
||||
"""
|
||||
Class Author represents an author of a book.
|
||||
"""
|
||||
name = fields.CharField()
|
||||
|
||||
def __str__(self):
|
||||
return "Author({})".format(self.name)
|
||||
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
|
||||
|
||||
class Book(MongoModel):
|
||||
"""
|
||||
Class book represents a book.
|
||||
"""
|
||||
title = fields.CharField()
|
||||
author = fields.ReferenceField(Author)
|
||||
publisher = fields.ReferenceField(Publisher)
|
||||
isbn = fields.CharField(blank=True)
|
||||
year = fields.IntegerField(blank=True)
|
||||
edition = fields.CharField()
|
||||
|
||||
def __str__(self):
|
||||
return "Book({})".format(self.title)
|
||||
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
@@ -1,228 +0,0 @@
|
||||
"""Define routing rules for book publishers"""
|
||||
from flask import Blueprint, flash, redirect, render_template, url_for
|
||||
from flask_login import login_required
|
||||
from bson import ObjectId
|
||||
from pymongo.errors import PyMongoError
|
||||
from .forms import PublisherForm, AuthorForm, BookForm
|
||||
from .models import Publisher, Author, Book
|
||||
|
||||
|
||||
LIBRARY = Blueprint('library', __name__)
|
||||
|
||||
|
||||
@LIBRARY.route('/publishers')
|
||||
@login_required
|
||||
def list_publishers():
|
||||
"""
|
||||
List all publishers
|
||||
:return:
|
||||
"""
|
||||
publishers = Publisher.objects.all()
|
||||
return render_template('library/publishers.html',
|
||||
publishers=publishers, title="Publishers")
|
||||
|
||||
|
||||
@LIBRARY.route('/publishers/add', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_publisher():
|
||||
"""
|
||||
Add a publisher to the database
|
||||
:return:
|
||||
"""
|
||||
form = PublisherForm()
|
||||
if form.validate_on_submit():
|
||||
publisher = Publisher()
|
||||
publisher.name = form.name.data
|
||||
try:
|
||||
publisher.save()
|
||||
flash('You have successfully added a new publisher.')
|
||||
except PyMongoError:
|
||||
flash('Error: publisher name already exists.')
|
||||
return redirect(url_for('library.list_publishers'))
|
||||
return render_template('simpleform.html', action="Add",
|
||||
form=form, title="Add Publisher")
|
||||
|
||||
|
||||
@LIBRARY.route('/publishers/edit/<publisher_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_publisher(publisher_id):
|
||||
"""
|
||||
Edit a publisher
|
||||
"""
|
||||
publisher = Publisher.objects.get({'_id': ObjectId(publisher_id)})
|
||||
form = PublisherForm(obj=publisher)
|
||||
if form.validate_on_submit():
|
||||
publisher.name = form.name.data
|
||||
publisher.save()
|
||||
flash('You have successfully edited the publisher.')
|
||||
return redirect(url_for('library.list_publishers'))
|
||||
form.name.data = publisher.name
|
||||
return render_template('simpleform.html', action="Edit",
|
||||
form=form, publisher=publisher, title="Edit Publisher")
|
||||
|
||||
|
||||
@LIBRARY.route('/publishers/delete/<publisher_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def delete_publisher(publisher_id):
|
||||
"""
|
||||
Delete a publisher
|
||||
:param publisher_id: ObjectId of publisher
|
||||
:return:
|
||||
"""
|
||||
publisher = Publisher.objects.raw({'_id': ObjectId(publisher_id)})
|
||||
if publisher:
|
||||
publisher.delete()
|
||||
flash('You have successfully deleted the publisher.')
|
||||
return redirect(url_for('library.list_publishers'))
|
||||
|
||||
|
||||
@LIBRARY.route('/authors')
|
||||
@login_required
|
||||
def list_authors():
|
||||
"""
|
||||
List all authors
|
||||
:return:
|
||||
"""
|
||||
authors = Author.objects.all()
|
||||
return render_template('library/authors.html',
|
||||
authors=authors, title="Authors")
|
||||
|
||||
|
||||
@LIBRARY.route('/authors/edit/<author_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_author(author_id):
|
||||
"""
|
||||
Edit a book artist
|
||||
"""
|
||||
author = Author.objects.get({'_id': ObjectId(author_id)})
|
||||
form = AuthorForm(obj=author)
|
||||
if form.validate_on_submit():
|
||||
author.name = form.name.data
|
||||
author.save()
|
||||
flash('You have successfully edited the author.')
|
||||
return redirect(url_for('library.list_authors'))
|
||||
form.name.data = author.name
|
||||
return render_template('simpleform.html', action="Edit",
|
||||
form=form, author=author, title="Edit Author")
|
||||
|
||||
|
||||
@LIBRARY.route('/authors/add', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_author():
|
||||
"""
|
||||
Add a author
|
||||
:return:
|
||||
"""
|
||||
form = AuthorForm()
|
||||
if form.validate_on_submit():
|
||||
author = Author()
|
||||
author.name = form.name.data
|
||||
try:
|
||||
author.save()
|
||||
flash('You have successfully added a new author.')
|
||||
except PyMongoError:
|
||||
flash('Error: author name already exists.')
|
||||
return redirect(url_for('library.list_authors'))
|
||||
return render_template('simpleform.html', action="Add",
|
||||
form=form, title="Add Author")
|
||||
|
||||
|
||||
@LIBRARY.route('/authors/delete/<author_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def delete_author(author_id):
|
||||
"""
|
||||
Delete a author
|
||||
:param author_id:
|
||||
:return:
|
||||
"""
|
||||
author = Author.objects.raw({'_id': ObjectId(author_id)})
|
||||
if author:
|
||||
author.delete()
|
||||
flash('You have successfully deleted the author.')
|
||||
return redirect(url_for('library.list_authors'))
|
||||
|
||||
|
||||
@LIBRARY.route('/books')
|
||||
@login_required
|
||||
def list_books():
|
||||
"""
|
||||
List all comics
|
||||
:return:
|
||||
"""
|
||||
books = Book.objects.all()
|
||||
return render_template('library/books.html',
|
||||
books=books, title="Books")
|
||||
|
||||
|
||||
@LIBRARY.route('/books/edit/<book_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_book(book_id):
|
||||
"""
|
||||
Edit a book
|
||||
"""
|
||||
book = Book.objects.get({'_id': ObjectId(book_id)})
|
||||
form = BookForm(obj=book)
|
||||
form.publisher.choices = [(p.pk, p.name) for p in Publisher.objects.all()]
|
||||
if book.publisher:
|
||||
form.publisher.default = book.publisher.pk
|
||||
form.publisher.process_data(book.publisher.pk)
|
||||
form.author.choices = [(a.pk, a.name) for a in Author.objects.all()]
|
||||
if book.author:
|
||||
form.author.default = book.author.pk
|
||||
form.author.process_data(book.author.pk)
|
||||
if form.validate_on_submit():
|
||||
book.title = form.title.data
|
||||
book.publisher = form.publisher.data
|
||||
book.author = form.author.data
|
||||
if form.isbn.data:
|
||||
book.isbn = form.isbn.data
|
||||
else:
|
||||
book.isbn = None
|
||||
book.year = form.year.data
|
||||
book.save()
|
||||
flash('You have successfully edited the book.')
|
||||
return redirect(url_for('library.list_books'))
|
||||
form.title.data = book.title
|
||||
return render_template('simpleform.html', action="Edit",
|
||||
form=form, book=book, title="Edit Book")
|
||||
|
||||
|
||||
@LIBRARY.route('/books/add', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_book():
|
||||
"""
|
||||
Add a book
|
||||
:return:
|
||||
"""
|
||||
form = BookForm()
|
||||
form.publisher.choices = [(p.pk, p.name) for p in Publisher.objects.all()]
|
||||
form.author.choices = [(a.pk, a.name) for a in Author.objects.all()]
|
||||
if form.validate_on_submit():
|
||||
book = Book()
|
||||
book.title = form.title.data
|
||||
book.publisher = form.publisher.data
|
||||
book.author = form.author.data
|
||||
book.year = form.year.data
|
||||
try:
|
||||
book.save()
|
||||
flash('You have successfully added a new book.')
|
||||
except PyMongoError:
|
||||
flash('Error: book title already exists.')
|
||||
return redirect(url_for('library.list_books'))
|
||||
return render_template('simpleform.html', action="Add",
|
||||
form=form, title="Add Book")
|
||||
|
||||
|
||||
@LIBRARY.route('/books/delete/<book_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def delete_book(book_id):
|
||||
"""
|
||||
Delete a book
|
||||
:param book_id:
|
||||
:return:
|
||||
"""
|
||||
book = Book.objects.raw({'_id': ObjectId(book_id)})
|
||||
if book:
|
||||
book.delete()
|
||||
flash('You have successfully deleted the book.')
|
||||
return redirect(url_for('library.list_books'))
|
||||
@@ -0,0 +1,5 @@
|
||||
from flask import Blueprint
|
||||
|
||||
bp = Blueprint('main', __name__)
|
||||
|
||||
from kontor.main import routes
|
||||
@@ -0,0 +1,18 @@
|
||||
from flask import render_template, session
|
||||
|
||||
from kontor import app
|
||||
from kontor.main import bp
|
||||
from kontor.auth import auth
|
||||
|
||||
|
||||
@bp.route('/')
|
||||
@auth.login_required
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
|
||||
@bp.route('/logout')
|
||||
def logout():
|
||||
app.logger.info("logout")
|
||||
auth.current_user()
|
||||
session['user_name'] = None
|
||||
return render_template('index.html')
|
||||
@@ -0,0 +1,9 @@
|
||||
from flask import Blueprint
|
||||
|
||||
media_bp = Blueprint('media_bp', __name__,
|
||||
template_folder='templates',
|
||||
static_folder='static', static_url_path='assets')
|
||||
media_api = Blueprint('media_api', __name__)
|
||||
|
||||
from kontor.media import routes
|
||||
from kontor.media import api
|
||||
@@ -0,0 +1,18 @@
|
||||
from flask import Blueprint, render_template, jsonify
|
||||
|
||||
from kontor import app
|
||||
from kontor.media import media_api
|
||||
from kontor.media.models import MediaFile, mediafile_schema, mediafiles_schema
|
||||
|
||||
|
||||
@media_api.route('/')
|
||||
def mediafile_list():
|
||||
app.logger.info("get all media files")
|
||||
files = MediaFile.query.all()
|
||||
return mediafiles_schema.dump(files)
|
||||
|
||||
|
||||
@media_api.route('/mediafile/<string:mediafile_id>')
|
||||
def mediafile_detail(file_id):
|
||||
file = MediaFile.query.get(file_id)
|
||||
return mediafile_schema.dump(file)
|
||||
@@ -0,0 +1,43 @@
|
||||
from kontor.extensions import db, ma
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
|
||||
class MediaFile(db.Model):
|
||||
# __table__ = db.metadata.tables["publisher"]
|
||||
__tablename__ = "media_file"
|
||||
__table_args__ = {'extend_existing': True}
|
||||
id = db.Column(db.String, primary_key=True)
|
||||
created_date = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
last_modified_date = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
version = db.Column(db.Integer)
|
||||
title = db.Column(db.String)
|
||||
file_name = db.Column(db.String)
|
||||
url = db.Column(db.String)
|
||||
path = db.Column(db.String)
|
||||
cloud_link = db.Column(db.String)
|
||||
review = db.Column(db.SmallInteger)
|
||||
should_download = db.Column(db.Boolean)
|
||||
|
||||
def is_review(self):
|
||||
return self.review == 'b\x00'
|
||||
|
||||
def is_download(self):
|
||||
return self.should_download == 'b\x00'
|
||||
|
||||
|
||||
class MediaFileSchema(ma.SQLAlchemySchema):
|
||||
class Meta:
|
||||
model = MediaFile
|
||||
fields = ("id", "created_date", "last_modified_date", "version", "title", "file_name", "url", "path", "cloud_link", "review", "should_download", "_links")
|
||||
|
||||
# Smart hyperlinking
|
||||
_links = ma.Hyperlinks(
|
||||
{
|
||||
"self": ma.URLFor("media_api.mediafile_detail", values=dict(mediafile_id="<id>")),
|
||||
"collection": ma.URLFor("media_api.mediafile_list"),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
mediafile_schema = MediaFileSchema()
|
||||
mediafiles_schema = MediaFileSchema(many=True)
|
||||
@@ -0,0 +1,16 @@
|
||||
from flask import Blueprint, render_template
|
||||
|
||||
from kontor.media import media_bp
|
||||
from kontor.media.models import MediaFile
|
||||
|
||||
|
||||
@media_bp.route('/')
|
||||
def mediafile_list():
|
||||
files = MediaFile.query.all()
|
||||
return render_template('media/mediafile_list.html', mediafiles=files)
|
||||
|
||||
|
||||
@media_bp.route('/mediafile/<string:mediafile_id>')
|
||||
def mediafile_detail(mediafile_id):
|
||||
mediafile = MediaFile.query.get(mediafile_id)
|
||||
return render_template('media/mediafile_detail.html', mediafile=mediafile)
|
||||
@@ -0,0 +1,29 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<span class="title">
|
||||
<h1>{% block title %} MediaFile {% endblock %}</h1>
|
||||
</span>
|
||||
<div class="comics">
|
||||
<h2>MediaFile Blueprint</h2>
|
||||
<div class="comic">
|
||||
<b>
|
||||
<p class="name">
|
||||
<a href="{{ url_for('media_bp.mediafile_detail', mediafile_id=mediafile.id)}}">{{ mediafile.title }}</a>
|
||||
</p>
|
||||
</b>
|
||||
<b>
|
||||
<p class="identifier">{{ mediafile.id }}</p>
|
||||
</b>
|
||||
<div class="date">
|
||||
<h4>Created</h4>
|
||||
<p>{{ mediafile.created_date }}</p>
|
||||
<h4>Modified</h4>
|
||||
<p>{{ mediafile.last_modified_date }}</p>
|
||||
</div>
|
||||
<p>Version: {{ mediafile.version }}</p>
|
||||
<p>Review: {{ mediafile.is_review() }}</p>
|
||||
<p>Should Download: {{mediafile.is_download() }}</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,30 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<span class="title">
|
||||
<h1>{% block title %} MediaFile {% endblock %}</h1>
|
||||
</span>
|
||||
<div class="comic">
|
||||
<h2>MediaFile Blueprint</h2>
|
||||
{% for mediafile in mediafiles %}
|
||||
<div class="comic">
|
||||
<b>
|
||||
<p class="name">
|
||||
<a href="{{ url_for('media_bp.mediafile_detail', mediafile_id=mediafile.id)}}">{{ mediafile.title }}</a>
|
||||
</p>
|
||||
</b>
|
||||
<b><p class="identifier">{{ mediafile.id }}</p></b>
|
||||
<div class="date">
|
||||
<h4>Created</h4>
|
||||
<p>{{ mediafile.created_date }}</p>
|
||||
<h4>Modified</h4>
|
||||
<p>{{ mediafile.last_modified_date }}</p>
|
||||
</div>
|
||||
<p>Version: {{ mediafile.version }}</p>
|
||||
<p>Review: {{ mediafile.is_review() }}</p>
|
||||
<p>Should Download: {{ mediafile.is_download() }}</p>
|
||||
<p>Links: {{ mediafile._links }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
+42
-59
@@ -1,66 +1,49 @@
|
||||
"""
|
||||
This modules declares the model for Kontor users.
|
||||
"""
|
||||
from pymodm import MongoModel, fields
|
||||
from pymongo.write_concern import WriteConcern
|
||||
from flask_login import UserMixin
|
||||
from werkzeug.security import generate_password_hash, check_password_hash
|
||||
from kontor import _LOGIN_MANAGER_
|
||||
from kontor.extensions import db, ma
|
||||
from sqlalchemy.sql import func
|
||||
|
||||
|
||||
class User(UserMixin, MongoModel):
|
||||
"""
|
||||
This class represents an user for the Kontor application.
|
||||
"""
|
||||
email = fields.EmailField()
|
||||
username = fields.CharField(max_length=60)
|
||||
first_name = fields.CharField(max_length=60)
|
||||
last_name = fields.CharField(max_length=60)
|
||||
password_hash = fields.CharField(max_length=128)
|
||||
is_admin = fields.BooleanField(default=False)
|
||||
class Publisher(db.Model):
|
||||
# __table__ = db.metadata.tables["publisher"]
|
||||
__tablename__ = "publisher"
|
||||
__table_args__ = {'extend_existing': True}
|
||||
id = db.Column(db.String, primary_key=True)
|
||||
created_date = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
last_modified_date = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
version = db.Column(db.Integer)
|
||||
name = db.Column(db.String)
|
||||
comics = db.relationship('Comic', back_populates='publisher', lazy='dynamic')
|
||||
|
||||
@property
|
||||
def password(self):
|
||||
"""
|
||||
Prevent pasword from being accessed
|
||||
"""
|
||||
raise AttributeError('password is not a readable attribute.')
|
||||
|
||||
@password.setter
|
||||
def password(self, password):
|
||||
"""
|
||||
Set password to a hashed password
|
||||
"""
|
||||
self.password_hash = generate_password_hash(password)
|
||||
|
||||
def verify_password(self, password):
|
||||
"""
|
||||
Check if hashed password matches actual password
|
||||
"""
|
||||
return check_password_hash(self.password_hash, password)
|
||||
|
||||
def get_id(self):
|
||||
"""
|
||||
Get username as id
|
||||
:return:
|
||||
"""
|
||||
return self.username
|
||||
|
||||
def __repr__(self):
|
||||
return '<User: {}>'.format(self.username)
|
||||
|
||||
class PublisherSchema(ma.SQLAlchemySchema):
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
model = Publisher
|
||||
|
||||
comics = ma.List(ma.HyperlinkRelated("comics_api.index"))
|
||||
|
||||
|
||||
# Set up user_loader
|
||||
@_LOGIN_MANAGER_.user_loader
|
||||
def load_user(user_name):
|
||||
"""
|
||||
Get list of users from database
|
||||
:param user_name:
|
||||
:return:
|
||||
"""
|
||||
return User.objects.get({'username': user_name})
|
||||
publisher_schema = PublisherSchema()
|
||||
publishers_schema = PublisherSchema(many=True)
|
||||
|
||||
|
||||
class Comic(db.Model):
|
||||
# __table__ = db.metadata.tables["comic"]
|
||||
__tablename__ = "comic"
|
||||
__table_args__ = {'extend_existing': True}
|
||||
id = db.Column(db.String, primary_key=True)
|
||||
created_date = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
last_modified_date = db.Column(db.DateTime(timezone=True), server_default=func.now())
|
||||
version = db.Column(db.Integer)
|
||||
title = db.Column(db.String)
|
||||
publisher_id = db.Column(db.String, db.ForeignKey("publisher.id"))
|
||||
publisher = db.relationship("Publisher", back_populates="comics")
|
||||
|
||||
|
||||
class ComicSchema(ma.SQLAlchemyAutoSchema):
|
||||
class Meta:
|
||||
model = Comic
|
||||
include_fk = True
|
||||
publisher = ma.HyperlinkRelated("comics_api.publisher_detail")
|
||||
|
||||
|
||||
comic_schema = ComicSchema()
|
||||
comics_schema = ComicSchema(many=True)
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
"""
|
||||
Define routing rules for office related information
|
||||
"""
|
||||
@@ -1,126 +0,0 @@
|
||||
/* app/static/css/style.css */
|
||||
|
||||
body, html {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body, h1, h2, h3 {
|
||||
font-family: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
a, .navbar-default .navbar-brand, .navbar-default .navbar-nav>li>a {
|
||||
color: #aec251;
|
||||
}
|
||||
|
||||
a:hover, .navbar-default .navbar-brand:hover, .navbar-default .navbar-nav>li>a:hover {
|
||||
color: #687430;
|
||||
}
|
||||
|
||||
footer {
|
||||
padding: 50px 0;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
p.copyright {
|
||||
margin: 15px 0 0;
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
width: 50%;
|
||||
margin: auto;
|
||||
color: #687430;
|
||||
background-color: #e6ecca;
|
||||
border-color: #aec251;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
border-color: #aec251;
|
||||
color: #aec251;
|
||||
}
|
||||
|
||||
.btn-default:hover {
|
||||
background-color: #aec251;
|
||||
}
|
||||
|
||||
.center {
|
||||
margin: auto;
|
||||
width: 70%;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.content-section {
|
||||
padding: 50px 0;
|
||||
border-top: 1px solid #e7e7e7;
|
||||
}
|
||||
|
||||
.footer, .push {
|
||||
clear: both;
|
||||
height: 4em;
|
||||
}
|
||||
|
||||
.intro-divider {
|
||||
width: 400px;
|
||||
border-top: 1px solid #f8f8f8;
|
||||
border-bottom: 1px solid rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.intro-header {
|
||||
padding-top: 50px;
|
||||
padding-bottom: 50px;
|
||||
text-align: center;
|
||||
color: #f8f8f8;
|
||||
background: url(../img/intro-bg.jpg) no-repeat center center;
|
||||
background-size: cover;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.intro-message {
|
||||
position: relative;
|
||||
padding-top: 20%;
|
||||
padding-bottom: 20%;
|
||||
}
|
||||
|
||||
.intro-message > h1 {
|
||||
margin: 0;
|
||||
text-shadow: 2px 2px 3px rgba(0,0,0,0.6);
|
||||
font-size: 5em;
|
||||
}
|
||||
|
||||
.intro-message > h3 {
|
||||
text-shadow: 2px 2px 3px rgba(0,0,0,0.6);
|
||||
}
|
||||
|
||||
.lead {
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.topnav {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
min-height: 100%;
|
||||
height: auto !important;
|
||||
height: 100%;
|
||||
margin: 0 auto -4em;
|
||||
}
|
||||
|
||||
.outer {
|
||||
display: table;
|
||||
position: absolute;
|
||||
height: 70%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.middle {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.inner {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<!-- app/templates/admin/employees/employee.html -->
|
||||
|
||||
{% import "bootstrap/wtf.html" as wtf %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Edit User{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<div class="outer">
|
||||
<div class="middle">
|
||||
<div class="inner">
|
||||
<div class="center">
|
||||
<h1> Edit User </h1>
|
||||
<br/>
|
||||
<br/>
|
||||
{{ wtf.quick_form(form) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,58 +0,0 @@
|
||||
<!-- app/templates/admin/users/users.html -->
|
||||
|
||||
{% import "bootstrap/utils.html" as utils %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Users{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<div class="outer">
|
||||
<div class="middle">
|
||||
<div class="inner">
|
||||
<br/>
|
||||
{{ utils.flashed_messages() }}
|
||||
<br/>
|
||||
<h1 style="text-align:center;">Users</h1>
|
||||
{% if users %}
|
||||
<hr class="intro-divider">
|
||||
<div class="center">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="15%"> Name </th>
|
||||
<th width="30%"> Email </th>
|
||||
<th width="30%"> Username </th>
|
||||
<th width="15%"> Edit </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
{% if user.is_admin %}
|
||||
<tr style="background-color: #aec251; color: white;">
|
||||
<td> <i class="fa fa-key"></i> Admin </td>
|
||||
<td> N/A </td>
|
||||
<td> N/A </td>
|
||||
<td> N/A </td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td> {{ user.first_name }} {{ user.last_name }} </td>
|
||||
<td> {{ user.email }} </td>
|
||||
<td> {{ user.username }} </td>
|
||||
<td>
|
||||
<a href="{{ url_for('admin.edit_user', user_id=user.username) }}">
|
||||
<i class="fa fa-user-plus"></i> Edit
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,18 +0,0 @@
|
||||
<!-- app/templates/auth/login.html -->
|
||||
|
||||
{% import "bootstrap/utils.html" as utils %}
|
||||
{% import "bootstrap/wtf.html" as wtf %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Login{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<br/>
|
||||
{{ utils.flashed_messages() }}
|
||||
<br/>
|
||||
<div class="center">
|
||||
<h1>Login to your account</h1>
|
||||
<br/>
|
||||
{{ wtf.quick_form(form) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,14 +0,0 @@
|
||||
<!-- app/templates/auth/register.html -->
|
||||
|
||||
{% import "bootstrap/wtf.html" as wtf %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Register{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<div class="center">
|
||||
<h1>Register for an account</h1>
|
||||
<br/>
|
||||
{{ wtf.quick_form(form) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,107 +1,68 @@
|
||||
<!-- app/templates/base.html -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ title }} | Kontor</title>
|
||||
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
|
||||
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
|
||||
<link href="{{ url_for('static', filename='css/style.css') }}" rel="stylesheet">
|
||||
<link rel="shortcut icon" href="{{ url_for('static', filename='img/favicon.ico') }}">
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %} {% endblock %} - FlaskApp</title>
|
||||
<style>
|
||||
h2 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin: 5px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin: 5px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.comic {
|
||||
flex: 20%;
|
||||
padding: 10px;
|
||||
margin: 5px;
|
||||
background-color: #f3f3f3;
|
||||
inline-size: 100%;
|
||||
}
|
||||
|
||||
.identifier a {
|
||||
color: #00a36f;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.date {
|
||||
padding: 10px;
|
||||
margin: 5px;
|
||||
background-color: #ffffff;
|
||||
color: #004835;
|
||||
}
|
||||
|
||||
nav a {
|
||||
color: #d64161;
|
||||
font-size: 3em;
|
||||
margin-left: 50px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.title a {
|
||||
color: #00a36f;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-default navbar-fixed-top topnav" role="navigation">
|
||||
<div class="container topnav">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand topnav" href="{{ url_for('home.homepage') }}">Kontor</a>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
{% if current_user.is_authenticated %}
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button">Comics <span class="caret"></span> </a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{{ url_for('comic.list_comics') }}">Comics</a></li>
|
||||
<li><a href="{{ url_for('comic.list_artists') }}">Artists</a></li>
|
||||
<li><a href="{{ url_for('comic.list_publishers') }}">Publishers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button">Library <span class="caret"></span> </a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{{ url_for('library.list_books') }}">Books</a></li>
|
||||
<li><a href="{{ url_for('library.list_authors') }}">Authors</a></li>
|
||||
<li><a href="{{ url_for('library.list_publishers') }}">Publishers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button">HomeOffice <span class="caret"></span> </a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{{ url_for('home.homepage') }}">HomeOffice</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button">Trading Cards <span class="caret"></span> </a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{{ url_for('home.homepage') }}">Trading Cards</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button">TradeYourSportsCards <span class="caret"></span> </a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="{{ url_for('tysc.list_sports') }}">Sports</a></li>
|
||||
<li><a href="{{ url_for('tysc.list_positions') }}">Positions</a></li>
|
||||
<li><a href="{{ url_for('tysc.list_teams') }}">Teams</a></li>
|
||||
<li><a href="{{ url_for('tysc.list_players') }}">Players</a></li>
|
||||
<li><a href="{{ url_for('tysc.list_manufacturers') }}">Manufacturers</a></li>
|
||||
<li><a href="{{ url_for('tysc.list_card_sets') }}">Series</a></li>
|
||||
<li><a href="{{ url_for('tysc.list_parallel_sets') }}">Parallel Sets</a></li>
|
||||
<li><a href="{{ url_for('tysc.list_insert_sets') }}">Inserts</a></li>
|
||||
<li><a href="{{ url_for('tysc.list_cards') }}">Cards</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
{% if current_user.is_admin %}
|
||||
<li><a href="{{ url_for('home.admin_dashboard') }}">Dashboard</a></li>
|
||||
<li><a href="{{ url_for('admin.list_users') }}">Users</a></li>
|
||||
{% else %}
|
||||
<li><a href="{{ url_for('home.dashboard') }}">Dashboard</a></li>
|
||||
{% endif %}
|
||||
<li><a href="{{ url_for('auth.logout') }}">{{ current_user.username }}</a></li>
|
||||
{% else %}
|
||||
<li><a href="{{ url_for('home.homepage') }}">Home</a></li>
|
||||
<li><a href="{{ url_for('auth.register') }}">Register</a></li>
|
||||
<li><a href="{{ url_for('auth.login') }}">Login</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<nav>
|
||||
<a href="{{ url_for('main.index') }}">Kontor</a>
|
||||
<a href="{{ url_for('comics_bp.index') }}">Comics</a>
|
||||
<a href="{{ url_for('media_bp.mediafile_list') }}">Media</a>
|
||||
</nav>
|
||||
<div class="wrapper">
|
||||
{% block body %}
|
||||
{% endblock %}
|
||||
<div class="push"></div>
|
||||
<hr>
|
||||
<div class="content">
|
||||
{% block content %} {% endblock %}
|
||||
</div>
|
||||
<footer>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<p class="col-lg-12">
|
||||
<ul class="list-inline">
|
||||
<li><a href="{{ url_for('home.homepage') }}">Home</a></li>
|
||||
<li class="footer-menu-divider">⋅</li>
|
||||
<li><a href="{{ url_for('auth.register') }}">Register</a></li>
|
||||
<li class="footer-menu-divider">⋅</li>
|
||||
<li><a href="{{ url_for('auth.login') }}">Login</a></li>
|
||||
</ul>
|
||||
<p class="copyright text-muted small">Version {{ version }}. Copyright © 2017. All Rights Reserved</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
{% import "bootstrap/utils.html" as utils %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Comic Artists{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<div class="outer">
|
||||
<div class="middle">
|
||||
<div class="inner">
|
||||
<br/>
|
||||
{{ utils.flashed_messages() }}
|
||||
<br/>
|
||||
<h1 style="text-align:center;">Comic Artists</h1>
|
||||
{% if artists %}
|
||||
<hr class="intro-divider">
|
||||
<div class="center">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="15%"> Name </th>
|
||||
<th width="15%"> Edit </th>
|
||||
<th width="15%"> Delete </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for artist in artists %}
|
||||
<tr>
|
||||
<td> {{ artist.name }} </td>
|
||||
<td>
|
||||
<a href="{{ url_for('comic.edit_artist', artist_id=artist.pk) }}">
|
||||
<i class="fa fa-pencil"></i> Edit
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('comic.delete_artist', artist_id=artist.pk) }}">
|
||||
<i class="fa fa-trash"></i> Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="text-align: center">
|
||||
{% else %}
|
||||
<div style="text-align: center">
|
||||
<h3> No artists have been added. </h3>
|
||||
<hr class="intro-divider">
|
||||
{% endif %}
|
||||
<a href="{{ url_for('comic.add_artist') }}" class="btn btn-default btn-lg">
|
||||
<i class="fa fa-plus"></i>
|
||||
Add Artist
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,66 +0,0 @@
|
||||
{% import "bootstrap/utils.html" as utils %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Comics{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<div class="outer">
|
||||
<div class="middle">
|
||||
<div class="inner">
|
||||
<br/>
|
||||
{{ utils.flashed_messages() }}
|
||||
<br/>
|
||||
<h1 style="text-align:center;">Comics</h1>
|
||||
{% if comics %}
|
||||
<hr class="intro-divider">
|
||||
<div class="center">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="15%"> Title </th>
|
||||
<th width="40%"> Publisher </th>
|
||||
<th width="15%"> Current Order </th>
|
||||
<th width="15%"> Edit </th>
|
||||
<th width="15%"> Delete </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for comic in comics %}
|
||||
<tr>
|
||||
<td> {{ comic.title }} </td>
|
||||
<td>
|
||||
<a href="{{ url_for('comic.edit_publisher', publisher_id=comic.publisher.pk) }}">
|
||||
{{ comic.publisher.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td> {{ comic.current_order }} </td>
|
||||
<td>
|
||||
<a href="{{ url_for('comic.edit_comic', comic_id=comic.pk) }}">
|
||||
<i class="fa fa-pencil"></i> Edit
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('comic.delete_comic', comic_id=comic.pk) }}">
|
||||
<i class="fa fa-trash"></i> Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="text-align: center">
|
||||
{% else %}
|
||||
<div style="text-align: center">
|
||||
<h3> No comics have been added. </h3>
|
||||
<hr class="intro-divider">
|
||||
{% endif %}
|
||||
<a href="{{ url_for('comic.add_comic') }}" class="btn btn-default btn-lg">
|
||||
<i class="fa fa-plus"></i>
|
||||
Add Comic
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,58 +0,0 @@
|
||||
{% import "bootstrap/utils.html" as utils %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Comic Publishers{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<div class="outer">
|
||||
<div class="middle">
|
||||
<div class="inner">
|
||||
<br/>
|
||||
{{ utils.flashed_messages() }}
|
||||
<br/>
|
||||
<h1 style="text-align:center;">Comic Publishers</h1>
|
||||
{% if publishers %}
|
||||
<hr class="intro-divider">
|
||||
<div class="center">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="15%"> Name </th>
|
||||
<th width="15%"> Edit </th>
|
||||
<th width="15%"> Delete </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for publisher in publishers %}
|
||||
<tr>
|
||||
<td> {{ publisher.name }} </td>
|
||||
<td>
|
||||
<a href="{{ url_for('comic.edit_publisher', publisher_id=publisher.pk) }}">
|
||||
<i class="fa fa-pencil"></i> Edit
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('comic.delete_publisher', publisher_id=publisher.pk) }}">
|
||||
<i class="fa fa-trash"></i> Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="text-align: center">
|
||||
{% else %}
|
||||
<div style="text-align: center">
|
||||
<h3> No comics have been added. </h3>
|
||||
<hr class="intro-divider">
|
||||
{% endif %}
|
||||
<a href="{{ url_for('comic.add_publisher') }}" class="btn btn-default btn-lg">
|
||||
<i class="fa fa-plus"></i>
|
||||
Add Publisher
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,31 +0,0 @@
|
||||
<!-- app/templates/home/admin_dashboard.html -->
|
||||
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Admin Dashboard{% endblock %}
|
||||
{% block body %}
|
||||
<div class="intro-header">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="intro-message">
|
||||
<h2>Admin Dashboard</h2>
|
||||
<hr class="intro-divider">
|
||||
<ul>
|
||||
<li><a href="{{ url_for('comic.list_comics') }}">Comics</a></li>
|
||||
<ul>
|
||||
<li><a href="{{ url_for('comic.list_publishers') }}">Publishers</a> </li>
|
||||
<li><a href="{{ url_for('comic.list_artists') }}">Artists</a> </li>
|
||||
</ul>
|
||||
<li><a href="{{ url_for('library.list_books') }}">Library</a></li>
|
||||
<ul>
|
||||
<li><a href="{{ url_for('library.list_publishers') }}">Publishers</a> </li>
|
||||
<li><a href="{{ url_for('library.list_authors') }}">Authors</a> </li>
|
||||
</ul>
|
||||
<li><a href="{{ url_for('home.homepage') }}">Office</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,20 +0,0 @@
|
||||
<!-- app/templates/home/dashboard.html -->
|
||||
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Dashboard{% endblock %}
|
||||
{% block body %}
|
||||
<div class="intro-header">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="intro-message">
|
||||
<h1>The Dashboard</h1>
|
||||
<h3>We made it here!</h3>
|
||||
<hr class="intro-divider">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,20 +0,0 @@
|
||||
<!-- app/templates/home/index.html -->
|
||||
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Home{% endblock %}
|
||||
{% block body %}
|
||||
<div class="intro-header">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="intro-message">
|
||||
<h1>Project Kontor</h1>
|
||||
<h3>Store everything!</h3>
|
||||
<hr class="intro-divider">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,8 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<span class="title"><h1>{% block title %} The Home Page of Kontor {% endblock %}</h1></span>
|
||||
<div class="content">
|
||||
<h2>This is the main Flask blueprint</h2>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,58 +0,0 @@
|
||||
{% import "bootstrap/utils.html" as utils %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Library Authors{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<div class="outer">
|
||||
<div class="middle">
|
||||
<div class="inner">
|
||||
<br/>
|
||||
{{ utils.flashed_messages() }}
|
||||
<br/>
|
||||
<h1 style="text-align:center;">Library Authors</h1>
|
||||
{% if authors %}
|
||||
<hr class="intro-divider">
|
||||
<div class="center">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="15%"> Name </th>
|
||||
<th width="15%"> Edit </th>
|
||||
<th width="15%"> Delete </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for author in authors %}
|
||||
<tr>
|
||||
<td> {{ author.name }} </td>
|
||||
<td>
|
||||
<a href="{{ url_for('library.edit_author', author_id=author.pk) }}">
|
||||
<i class="fa fa-pencil"></i> Edit
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('library.delete_author', author_id=author.pk) }}">
|
||||
<i class="fa fa-trash"></i> Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="text-align: center">
|
||||
{% else %}
|
||||
<div style="text-align: center">
|
||||
<h3> No artists have been added. </h3>
|
||||
<hr class="intro-divider">
|
||||
{% endif %}
|
||||
<a href="{{ url_for('library.add_author') }}" class="btn btn-default btn-lg">
|
||||
<i class="fa fa-plus"></i>
|
||||
Add Author
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,74 +0,0 @@
|
||||
{% import "bootstrap/utils.html" as utils %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Books{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<div class="outer">
|
||||
<div class="middle">
|
||||
<div class="inner">
|
||||
<br/>
|
||||
{{ utils.flashed_messages() }}
|
||||
<br/>
|
||||
<h1 style="text-align:center;">Books</h1>
|
||||
{% if books %}
|
||||
<hr class="intro-divider">
|
||||
<div class="center">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="15%"> Title </th>
|
||||
<th width="25%"> Author </th>
|
||||
<th width="40%"> Publisher </th>
|
||||
<th width="5%"> ISBN </th>
|
||||
<th width="2%"> Year </th>
|
||||
<th width="15%"> Edit </th>
|
||||
<th width="15%"> Delete </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for book in books %}
|
||||
<tr>
|
||||
<td> {{ book.title }} </td>
|
||||
<td>
|
||||
<a href="{{ url_for('library.edit_author', author_id=book.author.pk) }}">
|
||||
{{ book.author.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('library.edit_publisher', publisher_id=book.publisher.pk) }}">
|
||||
{{ book.publisher.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td> {{ book.isbn }} </td>
|
||||
<td> {{ book.year }} </td>
|
||||
<td>
|
||||
<a href="{{ url_for('library.edit_book', book_id=book.pk) }}">
|
||||
<i class="fa fa-pencil"></i> Edit
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('library.delete_book', book_id=book.pk) }}">
|
||||
<i class="fa fa-trash"></i> Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="text-align: center">
|
||||
{% else %}
|
||||
<div style="text-align: center">
|
||||
<h3> No books have been added. </h3>
|
||||
<hr class="intro-divider">
|
||||
{% endif %}
|
||||
<a href="{{ url_for('library.add_book') }}" class="btn btn-default btn-lg">
|
||||
<i class="fa fa-plus"></i>
|
||||
Add Book
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,58 +0,0 @@
|
||||
{% import "bootstrap/utils.html" as utils %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Book Publishers{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<div class="outer">
|
||||
<div class="middle">
|
||||
<div class="inner">
|
||||
<br/>
|
||||
{{ utils.flashed_messages() }}
|
||||
<br/>
|
||||
<h1 style="text-align:center;">Book Publishers</h1>
|
||||
{% if publishers %}
|
||||
<hr class="intro-divider">
|
||||
<div class="center">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="15%"> Name </th>
|
||||
<th width="15%"> Edit </th>
|
||||
<th width="15%"> Delete </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for publisher in publishers %}
|
||||
<tr>
|
||||
<td> {{ publisher.name }} </td>
|
||||
<td>
|
||||
<a href="{{ url_for('library.edit_publisher', publisher_id=publisher.pk) }}">
|
||||
<i class="fa fa-pencil"></i> Edit
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('library.delete_publisher', publisher_id=publisher.pk) }}">
|
||||
<i class="fa fa-trash"></i> Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="text-align: center">
|
||||
{% else %}
|
||||
<div style="text-align: center">
|
||||
<h3> No publishers have been added. </h3>
|
||||
<hr class="intro-divider">
|
||||
{% endif %}
|
||||
<a href="{{ url_for('library.add_publisher') }}" class="btn btn-default btn-lg">
|
||||
<i class="fa fa-plus"></i>
|
||||
Add Publisher
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,21 +0,0 @@
|
||||
{% import "bootstrap/wtf.html" as wtf %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}{{ title }}{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<div class="outer">
|
||||
<div class="middle">
|
||||
<div class="inner">
|
||||
<div class="center">
|
||||
<h1> {{ title }} </h1>
|
||||
<br/>
|
||||
<br/>
|
||||
{{ wtf.quick_form(form) }}
|
||||
<br/>
|
||||
<hr class="intro-divider">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,58 +0,0 @@
|
||||
{% import "bootstrap/utils.html" as utils %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}{{ title }}{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<div class="outer">
|
||||
<div class="middle">
|
||||
<div class="inner">
|
||||
<br/>
|
||||
{{ utils.flashed_messages() }}
|
||||
<br/>
|
||||
<h1 style="text-align:center;">{{ title }}</h1>
|
||||
{% if manufacturers %}
|
||||
<hr class="intro-divider">
|
||||
<div class="center">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="15%"> Name </th>
|
||||
<th width="15%"> Edit </th>
|
||||
<th width="15%"> Delete </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for manufacturer in manufacturers %}
|
||||
<tr>
|
||||
<td> {{ manufacturer.name }} </td>
|
||||
<td>
|
||||
<a href="{{ url_for('tysc.edit_manufacturer', manufacturer_id=manufacturer.pk) }}">
|
||||
<i class="fa fa-pencil"></i> Edit
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('tysc.delete_manufacturer', manufacturer_id=manufacturer.pk) }}">
|
||||
<i class="fa fa-trash"></i> Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="text-align: center">
|
||||
{% else %}
|
||||
<div style="text-align: center">
|
||||
<h3> No manufacturers have been added. </h3>
|
||||
<hr class="intro-divider">
|
||||
{% endif %}
|
||||
<a href="{{ url_for('tysc.add_manufacturer') }}" class="btn btn-default btn-lg">
|
||||
<i class="fa fa-plus"></i>
|
||||
Add Manufacturer
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,60 +0,0 @@
|
||||
{% import "bootstrap/utils.html" as utils %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}{{ title }}{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<div class="outer">
|
||||
<div class="middle">
|
||||
<div class="inner">
|
||||
<br/>
|
||||
{{ utils.flashed_messages() }}
|
||||
<br/>
|
||||
<h1 style="text-align:center;">{{ title }}</h1>
|
||||
{% if players %}
|
||||
<hr class="intro-divider">
|
||||
<div class="center">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="15%"> First Name </th>
|
||||
<th width="15%"> Last Name </th>
|
||||
<th width="15%"> Edit </th>
|
||||
<th width="15%"> Delete </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for player in players %}
|
||||
<tr>
|
||||
<td> {{ player.first_name }} </td>
|
||||
<td> {{ player.last_name }} </td>
|
||||
<td>
|
||||
<a href="{{ url_for('tysc.edit_player', player_id=player.pk) }}">
|
||||
<i class="fa fa-pencil"></i> Edit
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('tysc.delete_player', player_id=player.pk) }}">
|
||||
<i class="fa fa-trash"></i> Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="text-align: center">
|
||||
{% else %}
|
||||
<div style="text-align: center">
|
||||
<h3> No players have been added. </h3>
|
||||
<hr class="intro-divider">
|
||||
{% endif %}
|
||||
<a href="{{ url_for('tysc.add_player') }}" class="btn btn-default btn-lg">
|
||||
<i class="fa fa-plus"></i>
|
||||
Add Player
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,62 +0,0 @@
|
||||
{% import "bootstrap/utils.html" as utils %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}{{ title }}{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<div class="outer">
|
||||
<div class="middle">
|
||||
<div class="inner">
|
||||
<br/>
|
||||
{{ utils.flashed_messages() }}
|
||||
<br/>
|
||||
<h1 style="text-align:center;">{{ title }}</h1>
|
||||
{% if positions %}
|
||||
<hr class="intro-divider">
|
||||
<div class="center">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="25%"> Name </th>
|
||||
<th width="15%"> Description </th>
|
||||
<th width="15%"> Sport </th>
|
||||
<th width="15%"> Edit </th>
|
||||
<th width="15%"> Delete </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for position in positions %}
|
||||
<tr>
|
||||
<td> {{ position.name }} </td>
|
||||
<td> {{ position.description }} </td>
|
||||
<td> {{ position.sport.name }} </td>
|
||||
<td>
|
||||
<a href="{{ url_for('tysc.edit_position', position_id=position.pk) }}">
|
||||
<i class="fa fa-pencil"></i> Edit
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('tysc.delete_position', position_id=position.pk) }}">
|
||||
<i class="fa fa-trash"></i> Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="text-align: center">
|
||||
{% else %}
|
||||
<div style="text-align: center">
|
||||
<h3> No positions have been added. </h3>
|
||||
<hr class="intro-divider">
|
||||
{% endif %}
|
||||
<a href="{{ url_for('tysc.add_position') }}" class="btn btn-default btn-lg">
|
||||
<i class="fa fa-plus"></i>
|
||||
Add Position
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,58 +0,0 @@
|
||||
{% import "bootstrap/utils.html" as utils %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Sports{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<div class="outer">
|
||||
<div class="middle">
|
||||
<div class="inner">
|
||||
<br/>
|
||||
{{ utils.flashed_messages() }}
|
||||
<br/>
|
||||
<h1 style="text-align:center;">Sports</h1>
|
||||
{% if sports %}
|
||||
<hr class="intro-divider">
|
||||
<div class="center">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="15%"> Name </th>
|
||||
<th width="15%"> Edit </th>
|
||||
<th width="15%"> Delete </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for sport in sports %}
|
||||
<tr>
|
||||
<td> {{ sport.name }} </td>
|
||||
<td>
|
||||
<a href="{{ url_for('tysc.edit_sport', sport_id=sport.pk) }}">
|
||||
<i class="fa fa-pencil"></i> Edit
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('tysc.delete_sport', sport_id=sport.pk) }}">
|
||||
<i class="fa fa-trash"></i> Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="text-align: center">
|
||||
{% else %}
|
||||
<div style="text-align: center">
|
||||
<h3> No sports have been added. </h3>
|
||||
<hr class="intro-divider">
|
||||
{% endif %}
|
||||
<a href="{{ url_for('tysc.add_sport') }}" class="btn btn-default btn-lg">
|
||||
<i class="fa fa-plus"></i>
|
||||
Add Sport
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,60 +0,0 @@
|
||||
{% import "bootstrap/utils.html" as utils %}
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Teams{% endblock %}
|
||||
{% block body %}
|
||||
<div class="content-section">
|
||||
<div class="outer">
|
||||
<div class="middle">
|
||||
<div class="inner">
|
||||
<br/>
|
||||
{{ utils.flashed_messages() }}
|
||||
<br/>
|
||||
<h1 style="text-align:center;">Teams</h1>
|
||||
{% if teams %}
|
||||
<hr class="intro-divider">
|
||||
<div class="center">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="25%"> Name </th>
|
||||
<th width="15%"> Shortname </th>
|
||||
<th width="15%"> Edit </th>
|
||||
<th width="15%"> Delete </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for team in teams %}
|
||||
<tr>
|
||||
<td> {{ team.name }} </td>
|
||||
<td> {{ team.shortname }} </td>
|
||||
<td>
|
||||
<a href="{{ url_for('tysc.edit_team', team_id=team.pk) }}">
|
||||
<i class="fa fa-pencil"></i> Edit
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{{ url_for('tysc.delete_team', team_id=team.pk) }}">
|
||||
<i class="fa fa-trash"></i> Delete
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="text-align: center">
|
||||
{% else %}
|
||||
<div style="text-align: center">
|
||||
<h3> No teams have been added. </h3>
|
||||
<hr class="intro-divider">
|
||||
{% endif %}
|
||||
<a href="{{ url_for('tysc.add_team') }}" class="btn btn-default btn-lg">
|
||||
<i class="fa fa-plus"></i>
|
||||
Add Team
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -1,377 +0,0 @@
|
||||
"""
|
||||
Define routing rules for TradeYourSportsCards related information
|
||||
"""
|
||||
from .models import Sport, Team, Position, Player
|
||||
from .models import Manufacturer, CardSet, ParallelSet, InsertSet, Card
|
||||
|
||||
|
||||
def initialize_model():
|
||||
"""
|
||||
Initialize collections for module TradeYourSportsCards.
|
||||
"""
|
||||
initialize_sport()
|
||||
initialize_position()
|
||||
initialize_teams()
|
||||
initialize_players()
|
||||
initialize_manufacturers()
|
||||
initialize_card_sets()
|
||||
initialize_parallel_sets()
|
||||
initialize_insert_sets()
|
||||
initialize_cards()
|
||||
|
||||
|
||||
def initialize_sport():
|
||||
"""
|
||||
Initialize collection Sport with american sports.
|
||||
"""
|
||||
for sport in Sport.objects.all():
|
||||
sport.delete()
|
||||
sports = ["Baseball", "Basketball", "Football", "Hockey"]
|
||||
for sport_name in sports:
|
||||
sport = Sport()
|
||||
sport.name = sport_name
|
||||
sport.save()
|
||||
|
||||
|
||||
def initialize_position():
|
||||
"""
|
||||
Initialize collection Position with data.
|
||||
"""
|
||||
for position in Position.objects.all():
|
||||
position.delete()
|
||||
positions = {
|
||||
'Quarterback': {'short': 'QB', 'sport': 'Football'},
|
||||
'Wide Receiver': {'short': 'WR', 'sport': 'Football'},
|
||||
'Runningback': {'short': 'RB', 'sport': 'Football'},
|
||||
'Linebacker': {'short': 'LB', 'sport': 'Football'},
|
||||
'Tight End': {'short': 'TE', 'sport': 'Football'},
|
||||
'Fullback': {'short': 'FB', 'sport': 'Football'},
|
||||
'Strong Safety': {'short': 'SS', 'sport': 'Football'},
|
||||
'Defensive End': {'short': 'DE', 'sport': 'Football'},
|
||||
'Kicker': {'short': 'K', 'sport': 'Football'},
|
||||
'Punter': {'short': 'P', 'sport': 'Football'},
|
||||
'Left Guard': {'short': 'LG', 'sport': 'Football'},
|
||||
'Right Guard': {'short': 'RG', 'sport': 'Football'},
|
||||
'Offensive Tackle': {'short': 'OT', 'sport': 'Football'},
|
||||
'Defensive Back': {'short': 'DB', 'sport': 'Football'},
|
||||
'Cornerback': {'short': 'CB', 'sport': 'Football'},
|
||||
'Catcher': {'short': 'C', 'sport': 'Baseball'},
|
||||
'First Base': {'short': '1B', 'sport': 'Baseball'},
|
||||
'Second Base': {'short': '2B', 'sport': 'Baseball'},
|
||||
'Third Base': {'short': '3B', 'sport': 'Baseball'},
|
||||
'Shortstop': {'short': 'SS', 'sport': 'Baseball'},
|
||||
'Left Field': {'short': 'LF', 'sport': 'Baseball'},
|
||||
'Center Field': {'short': 'CF', 'sport': 'Baseball'},
|
||||
'Right Field': {'short': 'RF', 'sport': 'Baseball'},
|
||||
'Designated Hitter': {'short': 'DH', 'sport': 'Baseball'},
|
||||
'Pitcher': {'short': 'P', 'sport': 'Baseball'}
|
||||
}
|
||||
for key in positions:
|
||||
sport = Sport.objects.get({'name': positions.get(key)['sport']})
|
||||
position = Position()
|
||||
position.description = key
|
||||
position.name = positions.get(key)['short']
|
||||
position.sport = sport
|
||||
position.save()
|
||||
|
||||
|
||||
def initialize_teams():
|
||||
"""
|
||||
Initialize collection Team with data.
|
||||
"""
|
||||
for team in Team.objects.all():
|
||||
team.delete()
|
||||
teams = {'Buffalo Bills': {'short': 'Bills', 'sport': 'Football'},
|
||||
'Indianapolis Colts': {'short': 'Colts', 'sport': 'Football'},
|
||||
'Miami Dolphins': {'short': 'Dolphins', 'sport': 'Football'},
|
||||
'New England Patriots': {'short': 'Patriots', 'sport': 'Football'},
|
||||
'New York Jets': {'short': 'Jets', 'sport': 'Football'},
|
||||
'Baltimore Ravens': {'short': 'Ravens', 'sport': 'Football'},
|
||||
'Cincinnati Bengals': {'short': 'Bengals', 'sport': 'Football'},
|
||||
'Cleveland Browns': {'short': 'Browns', 'sport': 'Football'},
|
||||
'Jacksonville Jaguars': {'short': 'Jaguars', 'sport': 'Football'},
|
||||
'Pittsburgh Steelers': {'short': 'Steelers', 'sport': 'Football'},
|
||||
'Tennessee Titans': {'short': 'Titans', 'sport': 'Football'},
|
||||
'Denver Broncos': {'short': 'Broncos', 'sport': 'Football'},
|
||||
'Kansas City Chiefs': {'short': 'Chiefs', 'sport': 'Football'},
|
||||
'Oakland Raiders': {'short': 'Raiders', 'sport': 'Football'},
|
||||
'San Diego Chargers': {'short': 'Chargers', 'sport': 'Football'},
|
||||
'Seattle Seahawks': {'short': 'Seahawks', 'sport': 'Football'},
|
||||
'Arizona Cardinals': {'short': 'Cardinals', 'sport': 'Football'},
|
||||
'Dallas Cowboys': {'short': 'Cowboys', 'sport': 'Football'},
|
||||
'New York Giants': {'short': 'Giants', 'sport': 'Football'},
|
||||
'Philadelphia Eagles': {'short': 'Eagles', 'sport': 'Football'},
|
||||
'Washington Redskins': {'short': 'Redskins', 'sport': 'Football'},
|
||||
'Chicago Bears': {'short': 'Bears', 'sport': 'Football'},
|
||||
'Detroit Lions': {'short': 'Lions', 'sport': 'Football'},
|
||||
'Green Bay Packers': {'short': 'Packers', 'sport': 'Football'},
|
||||
'Minnesota Vikings': {'short': 'Vikings', 'sport': 'Football'},
|
||||
'Tampa Bay Buccaneers': {'short': 'Buccaneers', 'sport': 'Football'},
|
||||
'Atlanta Falcons': {'short': 'Falcons', 'sport': 'Football'},
|
||||
'Carolina Panthers': {'short': 'Panthers', 'sport': 'Football'},
|
||||
'New Orleans Saints': {'short': 'Saints', 'sport': 'Football'},
|
||||
'St.Louis Rams': {'short': 'Rams', 'sport': 'Football'},
|
||||
'San Francisco 49ers': {'short': '49ers', 'sport': 'Football'},
|
||||
'Baltimore Orioles': {'short': 'Orioles', 'sport': 'Baseball'},
|
||||
'Boston Red Sox': {'short': 'Red Sox', 'sport': 'Baseball'},
|
||||
'New York Yankees': {'short': 'Yankees', 'sport': 'Baseball'},
|
||||
'Tampa Bay Devil Rays': {'short': 'Devil Rays', 'sport': 'Baseball'},
|
||||
'Toronto Blue Jays': {'short': 'Blue Jays', 'sport': 'Baseball'},
|
||||
'Chicago White Sox': {'short': 'White Sox', 'sport': 'Baseball'},
|
||||
'Cleveland Indians': {'short': 'Indians', 'sport': 'Baseball'},
|
||||
'Detroit Tigers': {'short': 'Tigers', 'sport': 'Baseball'},
|
||||
'Kansas City Royals': {'short': 'Royals', 'sport': 'Baseball'},
|
||||
'Minnesota Twins': {'short': 'Twins', 'sport': 'Baseball'},
|
||||
'Anaheim Angels': {'short': 'Angels', 'sport': 'Baseball'},
|
||||
'Oakland Athletics': {'short': 'Athletics', 'sport': 'Baseball'},
|
||||
'Seattle Mariners': {'short': 'Mariners', 'sport': 'Baseball'},
|
||||
'Texas Rangers': {'short': 'Rangers', 'sport': 'Baseball'},
|
||||
'Atlanta Braves': {'short': 'Braves', 'sport': 'Baseball'},
|
||||
'Florida Marlins': {'short': 'Marlins', 'sport': 'Baseball'},
|
||||
'Montreal Expos': {'short': 'Expos', 'sport': 'Baseball'},
|
||||
'New York Mets': {'short': 'Mets', 'sport': 'Baseball'},
|
||||
'Philadelphia Phillies': {'short': 'Phillies', 'sport': 'Baseball'},
|
||||
'Chicago Cubs': {'short': 'Cubs', 'sport': 'Baseball'},
|
||||
'Cincinnati Reds': {'short': 'Reds', 'sport': 'Baseball'},
|
||||
'Houston Astros': {'short': 'Astros', 'sport': 'Baseball'},
|
||||
'Milwaukee Brewers': {'short': 'Brewers', 'sport': 'Baseball'},
|
||||
'Pittsburgh Pirates': {'short': 'Pirates', 'sport': 'Baseball'},
|
||||
'St.Louis Cardinals': {'short': 'Cardinals', 'sport': 'Baseball'},
|
||||
'Arizona Diamondbacks': {'short': 'Diamondbacks', 'sport': 'Baseball'},
|
||||
'Colorado Rockies': {'short': 'Rockies', 'sport': 'Baseball'},
|
||||
'Los Angeles Dodgers': {'short': 'Dodgers', 'sport': 'Baseball'},
|
||||
'San Diego Padres': {'short': 'Padres', 'sport': 'Baseball'},
|
||||
'San Francisco Giants': {'short': 'Giants', 'sport': 'Baseball'},
|
||||
'Boston Celtics': {'short': 'Celtics', 'sport': 'Basketball'},
|
||||
'Miami Heat': {'short': 'Heat', 'sport': 'Basketball'},
|
||||
'New Jersey Nets': {'short': 'Mets', 'sport': 'Basketball'},
|
||||
'New York Knicks': {'short': 'Knicks', 'sport': 'Basketball'},
|
||||
'Orlando Magic': {'short': 'Magic', 'sport': 'Basketball'},
|
||||
'Philadelphia 76ers': {'short': '76ers', 'sport': 'Basketball'},
|
||||
'Washington Wizards': {'short': 'Wizards', 'sport': 'Basketball'},
|
||||
'Atlanta Hawks': {'short': 'Hawks', 'sport': 'Basketball'},
|
||||
'Charlotte Hornets': {'short': 'Hornets', 'sport': 'Basketball'},
|
||||
'Chicago Bulls': {'short': 'Bulls', 'sport': 'Basketball'},
|
||||
'Cleveland Cavaliers': {'short': 'Cavaliers', 'sport': 'Basketball'},
|
||||
'Detroit Pistons': {'short': 'Pistons', 'sport': 'Basketball'},
|
||||
'Indiana Pacers': {'short': 'Pacers', 'sport': 'Basketball'},
|
||||
'Milwaukee Bucks': {'short': 'Bucks', 'sport': 'Basketball'},
|
||||
'Toronto Raptors': {'short': 'Raptors', 'sport': 'Basketball'},
|
||||
'Dallas Mavericks': {'short': 'Mavericks', 'sport': 'Basketball'},
|
||||
'Denver Nuggets': {'short': 'Nuggets', 'sport': 'Basketball'},
|
||||
'Houston Rockets': {'short': 'Rockets', 'sport': 'Basketball'},
|
||||
'Minnesota Timberwolves': {'short': 'Timberwolves', 'sport': 'Basketball'},
|
||||
'San Antonio Spurs': {'short': 'Spurs', 'sport': 'Basketball'},
|
||||
'Utah Jazz': {'short': 'Jazz', 'sport': 'Basketball'},
|
||||
'Vancouver Grizzlies': {'short': 'Grizzlies', 'sport': 'Basketball'},
|
||||
'Golden State Warriors': {'short': 'Warriors', 'sport': 'Basketball'},
|
||||
'Los Angeles Clippers': {'short': 'Clippers', 'sport': 'Basketball'},
|
||||
'Los Angeles Lakers': {'short': 'Lakers', 'sport': 'Basketball'},
|
||||
'Phoenix Suns': {'short': 'Suns', 'sport': 'Basketball'},
|
||||
'Portland Trail Blazers': {'short': 'Blazers', 'sport': 'Basketball'},
|
||||
'Sacramento Kings': {'short': 'Kings', 'sport': 'Basketball'},
|
||||
'Seattle SuperSonics': {'short': 'SuperSonics', 'sport': 'Basketball'},
|
||||
'Boston Bruins': {'short': 'Bruins', 'sport': 'Hockey'},
|
||||
'Buffalo Sabres': {'short': 'Sabres', 'sport': 'Hockey'},
|
||||
'Montreal Canadiens': {'short': 'Canadiens', 'sport': 'Hockey'},
|
||||
'Ottawa Senators': {'short': 'Senators', 'sport': 'Hockey'},
|
||||
'Toronto Maple Leafs': {'short': 'Maple Leafs', 'sport': 'Hockey'},
|
||||
'New Jersey Devils': {'short': 'Devils', 'sport': 'Hockey'},
|
||||
'New York Islander': {'short': 'Islander', 'sport': 'Hockey'},
|
||||
'New York Rangers': {'short': 'Rangers', 'sport': 'Hockey'},
|
||||
'Philadelphia Flyers': {'short': 'Flyers', 'sport': 'Hockey'},
|
||||
'Pittsburgh Penguins': {'short': 'Penguins', 'sport': 'Hockey'},
|
||||
'Atlanta Trashers': {'short': 'Trashers', 'sport': 'Hockey'},
|
||||
'Carolina Hurricanes': {'short': 'Hurricanes', 'sport': 'Hockey'},
|
||||
'Florida Panthers': {'short': 'Panthers', 'sport': 'Hockey'},
|
||||
'Tampa Bay Lightnings': {'short': 'Lightnings', 'sport': 'Hockey'},
|
||||
'Washington Capitals': {'short': 'Capitals', 'sport': 'Hockey'},
|
||||
'Chicago Blackhawks': {'short': 'Blackhawks', 'sport': 'Hockey'},
|
||||
'Columbo Blue Jackets': {'short': 'Blue Jackets', 'sport': 'Hockey'},
|
||||
'Detroit Red Wings': {'short': 'Red Wings', 'sport': 'Hockey'},
|
||||
'Nashville Predators': {'short': 'Predators', 'sport': 'Hockey'},
|
||||
'St.Louis Blues': {'short': 'Blues', 'sport': 'Hockey'},
|
||||
'Calgary Flames': {'short': 'Flames', 'sport': 'Hockey'},
|
||||
'Colorado Avalanche': {'short': 'Avalanche', 'sport': 'Hockey'},
|
||||
'Edmonton Oilers': {'short': 'Oilers', 'sport': 'Hockey'},
|
||||
'Minnesota Wild': {'short': 'Wild', 'sport': 'Hockey'},
|
||||
'Vancouver Canucks': {'short': 'Canucks', 'sport': 'Hockey'},
|
||||
'Anaheim Mighty Ducks': {'short': 'Mighty Ducks', 'sport': 'Hockey'},
|
||||
'Dallas Stars': {'short': 'Stars', 'sport': 'Hockey'},
|
||||
'Los Angeles Kings': {'short': 'Kings', 'sport': 'Hockey'},
|
||||
'Phoenix Coyotes': {'short': 'Coyotes', 'sport': 'Hockey'},
|
||||
'San Jose Sharks': {'short': 'Sharks', 'sport': 'Hockey'},
|
||||
'Houston Texans': {'short': 'Texans', 'sport': 'Football'},
|
||||
'Houston Oilers': {'short': 'Oilers', 'sport': 'Football'}
|
||||
}
|
||||
for key in teams:
|
||||
sport = Sport.objects.get({'name': teams.get(key)['sport']})
|
||||
team = Team()
|
||||
team.name = key
|
||||
team.shortname = teams.get(key)['short']
|
||||
team.sport = sport
|
||||
team.save()
|
||||
|
||||
|
||||
def initialize_players():
|
||||
"""
|
||||
Initialize collection Manufacturer with data.
|
||||
"""
|
||||
for player in Player.objects.all():
|
||||
player.delete()
|
||||
players = ['Pathon, Jerome', 'Bruschi, Tedy', 'Couch, Tim', 'Shea, Aaron',
|
||||
'Lewis, Jamal', 'Lewis, Jermaine', 'Banks, Tony', 'Fuamatu-Ma\'Afala, Chris',
|
||||
'Bettis, Jerome', 'Stewart, Kordell', 'Moon, Warren', 'Lockett, Kevin',
|
||||
'Gannon, Rich', 'Jett, James', 'Strong, Mack', 'Huard, Brock',
|
||||
'Watters, Ricky', 'Aikman, Troy', 'LaFleur, David', 'Brazzell, Chris',
|
||||
'Dayne, Ron', 'Brown, Na', 'Small, Torrance', 'Lewis, Chad', 'Murrell, Adrian',
|
||||
'Smith, Maurice', 'Chandler, Chris', 'Kanell, Danny', 'Williams, Ricky',
|
||||
'Garcia, Jeff', 'Streets, Tai', 'Garner, Charlie', 'Rice, Jerry',
|
||||
'Owens, Terrell', 'Bruce, Isaac', 'Canidate, Trung']
|
||||
for player_name in players:
|
||||
player = Player()
|
||||
(last_name, first_name) = player_name.split(',')
|
||||
player.last_name = last_name.strip()
|
||||
player.first_name = first_name.strip()
|
||||
player.save()
|
||||
|
||||
|
||||
def initialize_manufacturers():
|
||||
"""
|
||||
Initialize collection Manufacturer with data.
|
||||
"""
|
||||
for manufacturer in Manufacturer.objects.all():
|
||||
manufacturer.delete()
|
||||
manufacturers = ['Pacific', 'Fleer', 'Bowman', 'Topps', 'Donruss',
|
||||
'Score', 'Flair', 'Upper Deck']
|
||||
for manufacturer_name in manufacturers:
|
||||
manufacturer = Manufacturer()
|
||||
manufacturer.name = manufacturer_name
|
||||
manufacturer.save()
|
||||
|
||||
|
||||
def initialize_card_sets():
|
||||
"""
|
||||
Initialize collection CardSet with data.
|
||||
"""
|
||||
for card_set in CardSet.objects.all():
|
||||
card_set.delete()
|
||||
card_sets = {'Pacific': 'Pacific',
|
||||
'Fleer': 'Fleer',
|
||||
'Bowman': 'Bowman',
|
||||
'Leaf': 'Topps',
|
||||
'Ultra': 'Fleer',
|
||||
'Mystique': 'Fleer',
|
||||
'Finest Hour': 'Pacific',
|
||||
'SP': 'Upper Deck',
|
||||
'SPx': 'Upper Deck',
|
||||
'SP Authentic': 'Upper Deck',
|
||||
'Black Diamond': 'Upper Deck'
|
||||
}
|
||||
for set_name in card_sets:
|
||||
card_set = CardSet()
|
||||
card_set.name = set_name
|
||||
card_set.manufacturer = Manufacturer.objects.get({'name': card_sets.get(set_name)})
|
||||
card_set.save()
|
||||
|
||||
|
||||
def initialize_parallel_sets():
|
||||
"""
|
||||
Initialize collection ParallelSet with data.
|
||||
"""
|
||||
for parallel_set in ParallelSet.objects.all():
|
||||
parallel_set.delete()
|
||||
parallel_sets = {'Mystique Gold': 'Fleer',
|
||||
'Pacific Copper': 'Pacific',
|
||||
'Pacific Gold': 'Pacific'
|
||||
}
|
||||
for key in parallel_sets:
|
||||
manufacturer = Manufacturer.objects.get({'name': parallel_sets.get(key)})
|
||||
parallel_set = ParallelSet()
|
||||
parallel_set.name = key
|
||||
parallel_set.manufacturer = manufacturer
|
||||
parallel_set.save()
|
||||
|
||||
|
||||
def initialize_insert_sets():
|
||||
"""
|
||||
Initialize collection InsertSet with data.
|
||||
"""
|
||||
for insert_set in InsertSet.objects.all():
|
||||
insert_set.delete()
|
||||
manufacturer = Manufacturer.objects.get({'name': 'Fleer'})
|
||||
insert_set = InsertSet()
|
||||
insert_set.name = 'Mystique Big Buzz'
|
||||
insert_set.manufacturer = manufacturer
|
||||
insert_set.save()
|
||||
|
||||
|
||||
def initialize_cards():
|
||||
"""
|
||||
Initialize collection Card with data.
|
||||
"""
|
||||
for card in Card.objects.all():
|
||||
card.delete()
|
||||
players = ['Pathon, Jerome', 'Bruschi, Tedy', 'Couch, Tim', 'Shea, Aaron',
|
||||
'Lewis, Jamal', 'Lewis, Jermaine', 'Banks, Tony', 'Fuamatu-Ma\'Afala, Chris',
|
||||
'Bettis, Jerome', 'Stewart, Kordell', 'Moon, Warren', 'Lockett, Kevin',
|
||||
'Gannon, Rich', 'Jett, James', 'Strong, Mack', 'Huard, Brock',
|
||||
'Watters, Ricky', 'Aikman, Troy', 'LaFleur, David', 'Brazzell, Chris',
|
||||
'Dayne, Ron', 'Brown, Na', 'Small, Torrance', 'Lewis, Chad', 'Murrell, Adrian',
|
||||
'Smith, Maurice', 'Chandler, Chris', 'Kanell, Danny', 'Williams, Ricky',
|
||||
'Garcia, Jeff', 'Streets, Tai', 'Garner, Charlie', 'Rice, Jerry',
|
||||
'Owens, Terrell', 'Bruce, Isaac', 'Canidate, Trung']
|
||||
cards = [
|
||||
[0, 'Indianapolis Colts', 'Pacific', 'Pacific', None, None, False, 2001, 185],
|
||||
[1, 'Indianapolis Colts', 'Pacific', 'Pacific', None, None, False, 2001, 250],
|
||||
[2, 'Cleveland Browns', 'Pacific', 'Pacific', None, None, False, 2001, 103],
|
||||
[3, 'Cleveland Browns', 'Pacific', 'Pacific', None, None, False, 2001, 112],
|
||||
[4, 'Baltimore Ravens', 'Pacific', 'Pacific', None, None, False, 2001, 37],
|
||||
[5, 'Baltimore Ravens', 'Pacific', 'Pacific', None, None, False, 2001, 38],
|
||||
[6, 'Baltimore Ravens', 'Pacific', 'Pacific', None, None, False, 2001, 31],
|
||||
[7, 'Pittsburgh Steelers', 'Pacific', 'Pacific', None, None, False, 2001, 338],
|
||||
[8, 'Pittsburgh Steelers', 'Pacific', 'Pacific', None, None, False, 2001, 335],
|
||||
[9, 'Pittsburgh Steelers', 'Pacific', 'Pacific', None, None, False, 2001, 345],
|
||||
[10, 'Kansas City Chiefs', 'Pacific', 'Pacific', None, None, False, 2001, 213],
|
||||
[11, 'Kansas City Chiefs', 'Pacific', 'Pacific', None, None, False, 2001, 212],
|
||||
[12, 'Oakland Raiders', 'Pacific', 'Pacific', None, None, False, 2001, 311],
|
||||
[13, 'Oakland Raiders', 'Pacific', 'Pacific', None, None, False, 2001, 312],
|
||||
[14, 'Seattle Seahawks', 'Pacific', 'Pacific', None, None, False, 2001, 403],
|
||||
[15, 'Seattle Seahawks', 'Pacific', 'Pacific', None, None, False, 2001, 397],
|
||||
[16, 'Seattle Seahawks', 'Pacific', 'Pacific', None, None, False, 2001, 404],
|
||||
[17, 'Dallas Cowboys', 'Pacific', 'Pacific', None, None, False, 2001, 116],
|
||||
[18, 'Dallas Cowboys', 'Pacific', 'Pacific', None, None, False, 2001, 122],
|
||||
[19, 'Dallas Cowboys', 'Pacific', 'Pacific', None, None, False, 2001, 117],
|
||||
[20, 'New York Giants', 'Pacific', 'Pacific', None, None, False, 2001, 281],
|
||||
[21, 'New York Giants', 'Pacific', 'Pacific', None, None, False, 2001, 321],
|
||||
[22, 'Philadelphia Eagles', 'Pacific', 'Pacific', None, None, False, 2001, 331],
|
||||
[23, 'Philadelphia Eagles', 'Pacific', 'Pacific', None, None, False, 2001, 324],
|
||||
[24, 'Washington Redskins', 'Pacific', 'Pacific', None, None, False, 2001, 445],
|
||||
[25, 'Atlanta Falcons', 'Pacific', 'Pacific', None, None, False, 2001, 28],
|
||||
[26, 'Atlanta Falcons', 'Pacific', 'Pacific', None, None, False, 2001, 17],
|
||||
[27, 'Atlanta Falcons', 'Pacific', 'Pacific', None, None, False, 2001, 23],
|
||||
[28, 'New Orleans Saints', 'Pacific', 'Pacific', None, None, False, 2001, 273],
|
||||
[29, 'San Francisco 49ers', 'Pacific', 'Pacific', None, None, False, 2001, 380],
|
||||
[30, 'San Francisco 49ers', 'Pacific', 'Pacific', None, None, False, 2001, 390],
|
||||
[31, 'San Francisco 49ers', 'Pacific', 'Pacific', None, None, False, 2001, 381],
|
||||
[32, 'San Francisco 49ers', 'Pacific', 'Pacific', None, None, False, 2001, 387],
|
||||
[33, 'San Francisco 49ers', 'Pacific', 'Pacific', None, None, False, 2001, 386],
|
||||
[34, 'St.Louis Rams', 'Pacific', 'Pacific', None, None, False, 2001, 349],
|
||||
[35, 'St.Louis Rams', 'Pacific', 'Pacific', None, None, False, 2001, 350],
|
||||
]
|
||||
for card_data in cards:
|
||||
card = Card()
|
||||
player_name = players[card_data[0]]
|
||||
(last_name, first_name) = player_name.split(',')
|
||||
card.player = Player.objects.get(
|
||||
{'last_name': last_name.strip(), 'first_name': first_name.strip()}
|
||||
)
|
||||
card.team = Team.objects.get({'name': card_data[1]})
|
||||
card.manufacturer = Manufacturer.objects.get({'name': card_data[2]})
|
||||
card.card_set = CardSet.objects.get({'name': card_data[3]})
|
||||
card.parallel_set = card_data[4]
|
||||
card.insert_set = card_data[5]
|
||||
card.rookie = card_data[6]
|
||||
card.year = card_data[7]
|
||||
card.number = card_data[8]
|
||||
card.save()
|
||||
@@ -1,76 +0,0 @@
|
||||
"""
|
||||
Define form to edit sport, teams, player, manufacturers and card types
|
||||
"""
|
||||
from flask_wtf import FlaskForm
|
||||
from wtforms import StringField, SubmitField, SelectField, IntegerField, BooleanField
|
||||
from wtforms.validators import DataRequired, Optional, NumberRange
|
||||
from bson import ObjectId
|
||||
|
||||
|
||||
class SportForm(FlaskForm):
|
||||
"""
|
||||
Form to add and edit a Sport
|
||||
"""
|
||||
name = StringField('Name', validators=[DataRequired()])
|
||||
submit = SubmitField('Submit')
|
||||
|
||||
|
||||
class TeamForm(FlaskForm):
|
||||
"""
|
||||
Form to add and edit a team
|
||||
"""
|
||||
name = StringField('Name', validators=[DataRequired()])
|
||||
shortname = StringField('Shortname', validators=[DataRequired()])
|
||||
sport = SelectField('Sport', coerce=ObjectId)
|
||||
submit = SubmitField('Submit')
|
||||
|
||||
|
||||
class PlayerForm(FlaskForm):
|
||||
"""
|
||||
Form to add and edit a player.
|
||||
"""
|
||||
first_name = StringField('First name', validators=[DataRequired()])
|
||||
last_name = StringField('Last name', validators=[DataRequired()])
|
||||
submit = SubmitField('Submit')
|
||||
|
||||
|
||||
class PositionForm(FlaskForm):
|
||||
"""
|
||||
Form to add and edit field positions for sports
|
||||
"""
|
||||
name = StringField('Name', validators=[DataRequired()])
|
||||
description = StringField('Description', validators=[DataRequired()])
|
||||
sport = SelectField('Sport', coerce=ObjectId)
|
||||
submit = SubmitField('Submit')
|
||||
|
||||
|
||||
class ManufacturerForm(FlaskForm):
|
||||
"""
|
||||
Form to add and edit a card manufacturer.
|
||||
"""
|
||||
name = StringField('Name', validators=[DataRequired()])
|
||||
submit = SubmitField('Submit')
|
||||
|
||||
|
||||
class CardSetForm(FlaskForm):
|
||||
"""
|
||||
Form to add and edit a regular card set
|
||||
"""
|
||||
name = StringField('Name', validators=[DataRequired()])
|
||||
manufacturer = SelectField('Manufacturer', coerce=ObjectId)
|
||||
submit = SubmitField('Submit')
|
||||
|
||||
|
||||
class CardForm(FlaskForm):
|
||||
"""
|
||||
Form to add and edit a trading card
|
||||
"""
|
||||
player = SelectField('Player', coerce=ObjectId)
|
||||
team = SelectField('Team', coerce=ObjectId)
|
||||
manufacturer = SelectField('Manufacturer', coerce=ObjectId)
|
||||
card_set = SelectField('Card Set', coerce=ObjectId)
|
||||
parallel_set = SelectField('Parallel Set', coerce=ObjectId, validators=[Optional()])
|
||||
insert_set = SelectField('Inserts', coerce=ObjectId, validators=[Optional()])
|
||||
rookie = BooleanField('Rookie', validators=[DataRequired()])
|
||||
year = IntegerField('Year', validators=[NumberRange(min=1956, max=2020)])
|
||||
number = IntegerField('Number', validators=[DataRequired()])
|
||||
@@ -1,155 +0,0 @@
|
||||
"""This modules declares the model for TradingCards related information."""
|
||||
from pymongo.write_concern import WriteConcern
|
||||
from pymodm import MongoModel, fields
|
||||
|
||||
|
||||
class Sport(MongoModel):
|
||||
"""Class Sport represents a sport."""
|
||||
name = fields.CharField()
|
||||
|
||||
def __str__(self):
|
||||
"""Returns printable version of Sport object."""
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
"""Returns printable version of Sport object."""
|
||||
return "Sport({})".format(self.name)
|
||||
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
|
||||
|
||||
class Position(MongoModel):
|
||||
"""Class Position represents the position of a player for a sport."""
|
||||
name = fields.CharField(max_length=4)
|
||||
description = fields.CharField(max_length=30)
|
||||
sport = fields.ReferenceField(Sport)
|
||||
|
||||
def __str__(self):
|
||||
"""Returns printable version of Position object."""
|
||||
return "{0}({1})".format(self.name, self.description)
|
||||
|
||||
def __repr__(self):
|
||||
"""Returns printable version of Position object."""
|
||||
return "Position({0}, {1})".format(self.name, self.description)
|
||||
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
|
||||
|
||||
class Team(MongoModel):
|
||||
"""Class Team represents a team for a sport."""
|
||||
name = fields.CharField(max_length=60)
|
||||
shortname = fields.CharField(max_length=30)
|
||||
sport = fields.ReferenceField(Sport, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
"""Returns printable version of Team object."""
|
||||
return self.name
|
||||
|
||||
def __repr__(self):
|
||||
"""Returns printable version of Team object."""
|
||||
return "Team({0}{1})".format(self.name, self.shortname)
|
||||
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
|
||||
|
||||
class Player(MongoModel):
|
||||
"""
|
||||
Class Player represents a player.
|
||||
"""
|
||||
first_name = fields.CharField(max_length=60)
|
||||
last_name = fields.CharField(max_length=60)
|
||||
|
||||
def __str__(self):
|
||||
"""Returns printable version of Team object."""
|
||||
return "{0} {1}".format(self.first_name, self.last_name)
|
||||
|
||||
def __repr__(self):
|
||||
"""Returns printable version of Team object."""
|
||||
return "Player({0} {1})".format(self.first_name, self.last_name)
|
||||
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
|
||||
|
||||
class Manufacturer(MongoModel):
|
||||
"""
|
||||
Class Manufacturer represents a manufacturer of trading cards.
|
||||
"""
|
||||
name = fields.CharField()
|
||||
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
|
||||
|
||||
class CardSet(MongoModel):
|
||||
"""
|
||||
Class CardSet represents the regular card set.
|
||||
"""
|
||||
name = fields.CharField()
|
||||
manufacturer = fields.ReferenceField(Manufacturer)
|
||||
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
|
||||
|
||||
class ParallelSet(MongoModel):
|
||||
"""
|
||||
Class CardSet represents the parallel card set.
|
||||
"""
|
||||
name = fields.CharField()
|
||||
manufacturer = fields.ReferenceField(Manufacturer)
|
||||
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
|
||||
|
||||
class InsertSet(MongoModel):
|
||||
"""
|
||||
Class CardSet represents the inserts card set.
|
||||
"""
|
||||
name = fields.CharField()
|
||||
manufacturer = fields.ReferenceField(Manufacturer)
|
||||
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
|
||||
|
||||
class Card(MongoModel):
|
||||
"""
|
||||
Class CardSet represents the regular card set.
|
||||
"""
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
# Nine is reasonable in this case.
|
||||
player = fields.ReferenceField(Player)
|
||||
team = fields.ReferenceField(Team)
|
||||
manufacturer = fields.ReferenceField(Manufacturer)
|
||||
card_set = fields.ReferenceField(CardSet, blank=True)
|
||||
parallel_set = fields.ReferenceField(ParallelSet, blank=True)
|
||||
insert_set = fields.ReferenceField(InsertSet, blank=True)
|
||||
rookie = fields.BooleanField(default=False)
|
||||
year = fields.IntegerField(min_value=1956, max_value=2020)
|
||||
number = fields.IntegerField()
|
||||
|
||||
class Meta:
|
||||
"""Sets the connection and connections details."""
|
||||
connection_alias = 'kontor'
|
||||
write_concern = WriteConcern(j=True)
|
||||
@@ -1,405 +0,0 @@
|
||||
"""
|
||||
Define BLueprint and Views for TradeYourSportsCards
|
||||
"""
|
||||
from flask import Blueprint, url_for, render_template, redirect, flash
|
||||
from flask_login import login_required
|
||||
from bson import ObjectId
|
||||
from pymongo.errors import PyMongoError
|
||||
from .forms import SportForm, TeamForm, PlayerForm, PositionForm
|
||||
from .forms import ManufacturerForm
|
||||
from .models import Sport, Team, Player, Position
|
||||
from .models import Manufacturer, CardSet, ParallelSet, InsertSet, Card
|
||||
|
||||
|
||||
TYSC = Blueprint('tysc', __name__)
|
||||
|
||||
|
||||
@TYSC.route('/sport')
|
||||
@login_required
|
||||
def list_sports():
|
||||
"""
|
||||
List sports.
|
||||
:return:
|
||||
"""
|
||||
sports = Sport.objects.all()
|
||||
return render_template('tysc/sports.html', sports=sports, title="Sports")
|
||||
|
||||
|
||||
@TYSC.route('/sport/edit/<sport_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_sport(sport_id):
|
||||
"""
|
||||
Edit a sport
|
||||
"""
|
||||
sport = Sport.objects.get({'_id': ObjectId(sport_id)})
|
||||
form = SportForm(obj=sport)
|
||||
if form.validate_on_submit():
|
||||
sport.name = form.name.data
|
||||
sport.save()
|
||||
flash('You have successfully edited the sport.')
|
||||
return redirect(url_for('tysc.list_sports'))
|
||||
form.name.data = sport.name
|
||||
return render_template('simpleform.html', action="Edit",
|
||||
form=form, sport=sport, title="Edit Sport")
|
||||
|
||||
|
||||
@TYSC.route('/sport/add', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_sport():
|
||||
"""
|
||||
Add a sport
|
||||
:return:
|
||||
"""
|
||||
form = SportForm()
|
||||
if form.validate_on_submit():
|
||||
sport = Sport()
|
||||
sport.name = form.name.data
|
||||
try:
|
||||
sport.save()
|
||||
flash('You have successfully added a new sport.')
|
||||
except PyMongoError:
|
||||
flash('Error: sport name already exists.')
|
||||
return redirect(url_for('tysc.list_sports'))
|
||||
return render_template('simpleform.html', action="Add",
|
||||
form=form, title="Add Sport")
|
||||
|
||||
|
||||
@TYSC.route('/sport/delete/<sport_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def delete_sport(sport_id):
|
||||
"""
|
||||
Delete a sport
|
||||
:param sport_id:
|
||||
:return:
|
||||
"""
|
||||
sport = Sport.objects.raw({'_id': ObjectId(sport_id)})
|
||||
if sport:
|
||||
sport.delete()
|
||||
flash('You have successfully deleted the sport.')
|
||||
return redirect(url_for('tysc.list_sports'))
|
||||
|
||||
|
||||
@TYSC.route('/team')
|
||||
@login_required
|
||||
def list_teams():
|
||||
"""
|
||||
List teams.
|
||||
:return:
|
||||
"""
|
||||
teams = Team.objects.all()
|
||||
return render_template('tysc/teams.html', teams=teams, title="Teams")
|
||||
|
||||
|
||||
@TYSC.route('/team/edit/<team_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_team(team_id):
|
||||
"""
|
||||
Edit a team
|
||||
"""
|
||||
team = Team.objects.get({'_id': ObjectId(team_id)})
|
||||
form = TeamForm(obj=team)
|
||||
form.sport.choices = [(s.pk, s.name) for s in Sport.objects.all()]
|
||||
if team.sport:
|
||||
form.sport.default = team.sport.pk
|
||||
form.sport.process_data(team.sport.pk)
|
||||
if form.validate_on_submit():
|
||||
team.name = form.name.data
|
||||
team.shortname = form.shortname.data
|
||||
team.sport = form.sport.data
|
||||
team.save()
|
||||
flash('You have successfully edited the team.')
|
||||
return redirect(url_for('tysc.list_teams'))
|
||||
form.name.data = team.name
|
||||
return render_template('simpleform.html', action="Edit",
|
||||
form=form, team=team, title="Edit Team")
|
||||
|
||||
|
||||
@TYSC.route('/team/add', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_team():
|
||||
"""
|
||||
Add a team
|
||||
:return:
|
||||
"""
|
||||
form = TeamForm()
|
||||
form.sport.choices = [(s.pk, s.name) for s in Sport.objects.all()]
|
||||
if form.validate_on_submit():
|
||||
team = Team()
|
||||
team.name = form.name.data
|
||||
team.shortname = form.shortname.data
|
||||
team.sport = form.sport.data
|
||||
try:
|
||||
team.save()
|
||||
flash('You have successfully added a new team.')
|
||||
except PyMongoError:
|
||||
flash('Error: team name already exists.')
|
||||
return redirect(url_for('tysc.list_teams'))
|
||||
return render_template('simpleform.html', action="Add",
|
||||
form=form, title="Add Team")
|
||||
|
||||
|
||||
@TYSC.route('/team/delete/<team_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def delete_team(team_id):
|
||||
"""
|
||||
Delete a team
|
||||
:param team_id:
|
||||
:return:
|
||||
"""
|
||||
team = Team.objects.raw({'_id': ObjectId(team_id)})
|
||||
if team:
|
||||
team.delete()
|
||||
return redirect(url_for('tysc.list_teams'))
|
||||
|
||||
|
||||
@TYSC.route('/position')
|
||||
@login_required
|
||||
def list_positions():
|
||||
"""
|
||||
List positions.
|
||||
:return:
|
||||
"""
|
||||
positions = Position.objects.all()
|
||||
return render_template('tysc/positions.html', positions=positions, title="Positions")
|
||||
|
||||
|
||||
@TYSC.route('/position/edit/<position_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_position(position_id):
|
||||
"""
|
||||
Edit a position
|
||||
"""
|
||||
position = Position.objects.get({'_id': ObjectId(position_id)})
|
||||
form = PositionForm(obj=position)
|
||||
form.sport.choices = [(s.pk, s.name) for s in Sport.objects.all()]
|
||||
if position.sport:
|
||||
form.sport.default = position.sport.pk
|
||||
form.sport.process_data(position.sport.pk)
|
||||
if form.validate_on_submit():
|
||||
position.name = form.name.data
|
||||
position.description = form.description.data
|
||||
position.sport = form.sport.data
|
||||
position.save()
|
||||
flash('You have successfully edited the position.')
|
||||
return redirect(url_for('tysc.list_positions'))
|
||||
form.name.data = position.name
|
||||
form.description.data = position.description
|
||||
return render_template('simpleform.html', action="Edit",
|
||||
form=form, position=position, title="Edit position")
|
||||
|
||||
|
||||
@TYSC.route('/position/add', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_position():
|
||||
"""
|
||||
Add a position
|
||||
:return:
|
||||
"""
|
||||
form = PositionForm()
|
||||
form.sport.choices = [(s.pk, s.name) for s in Sport.objects.all()]
|
||||
if form.validate_on_submit():
|
||||
position = Position()
|
||||
position.name = form.name.data
|
||||
position.description = form.description.data
|
||||
position.sport = form.sport.data
|
||||
try:
|
||||
position.save()
|
||||
flash('You have successfully added a new position.')
|
||||
except PyMongoError:
|
||||
flash('Error: team position already exists.')
|
||||
return redirect(url_for('tysc.list_positions'))
|
||||
return render_template('simpleform.html', action="Add",
|
||||
form=form, title="Add Position")
|
||||
|
||||
|
||||
@TYSC.route('/position/delete/<position_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def delete_position(position_id):
|
||||
"""
|
||||
Delete a position
|
||||
:param position_id:
|
||||
:return:
|
||||
"""
|
||||
position = Position.objects.raw({'_id': ObjectId(position_id)})
|
||||
if position:
|
||||
position.delete()
|
||||
return redirect(url_for('tysc.list_positions'))
|
||||
|
||||
|
||||
@TYSC.route('/player')
|
||||
@login_required
|
||||
def list_players():
|
||||
"""
|
||||
List players.
|
||||
:return:
|
||||
"""
|
||||
players = Player.objects.all()
|
||||
return render_template('tysc/players.html', players=players, title="Players")
|
||||
|
||||
|
||||
@TYSC.route('/player/edit/<player_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_player(player_id):
|
||||
"""
|
||||
Edit a player
|
||||
"""
|
||||
player = Player.objects.get({'_id': ObjectId(player_id)})
|
||||
form = PlayerForm(obj=player)
|
||||
if form.validate_on_submit():
|
||||
player.first_name = form.first_name.data
|
||||
player.last_name = form.last_name.data
|
||||
player.save()
|
||||
flash('You have successfully edited the player.')
|
||||
return redirect(url_for('tysc.list_players'))
|
||||
form.first_name.data = player.first_name
|
||||
form.last_name.data = player.last_name
|
||||
return render_template('simpleform.html', action="Edit",
|
||||
form=form, player=player, title="Edit player")
|
||||
|
||||
|
||||
@TYSC.route('/player/add', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_player():
|
||||
"""
|
||||
Add a player
|
||||
:return:
|
||||
"""
|
||||
form = PlayerForm()
|
||||
if form.validate_on_submit():
|
||||
player = Player()
|
||||
player.first_name = form.first_name.data
|
||||
player.last_name = form.last_name.data
|
||||
try:
|
||||
player.save()
|
||||
flash('You have successfully added a new player.')
|
||||
except PyMongoError:
|
||||
flash('Error: player name already exists.')
|
||||
return redirect(url_for('tysc.list_players'))
|
||||
return render_template('simpleform.html', action="Add",
|
||||
form=form, title="Add player")
|
||||
|
||||
|
||||
@TYSC.route('/player/delete/<player_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def delete_player(player_id):
|
||||
"""
|
||||
Delete a player
|
||||
:param player_id:
|
||||
:return:
|
||||
"""
|
||||
player = Player.objects.raw({'_id': ObjectId(player_id)})
|
||||
if player:
|
||||
player.delete()
|
||||
return redirect(url_for('tysc.list_players'))
|
||||
|
||||
|
||||
@TYSC.route('/manufacturer')
|
||||
@login_required
|
||||
def list_manufacturers():
|
||||
"""
|
||||
List manufacturers.
|
||||
:return:
|
||||
"""
|
||||
manufacturers = Manufacturer.objects.all()
|
||||
return render_template('tysc/manufacturers.html',
|
||||
manufacturers=manufacturers,
|
||||
title="Manufacturers")
|
||||
|
||||
|
||||
@TYSC.route('/manufacturer/edit/<manufacturer_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def edit_manufacturer(manufacturer_id):
|
||||
"""
|
||||
Edit a manufacturer
|
||||
"""
|
||||
manufacturer = Manufacturer.objects.get({'_id': ObjectId(manufacturer_id)})
|
||||
form = ManufacturerForm(obj=manufacturer)
|
||||
if form.validate_on_submit():
|
||||
manufacturer.name = form.name.data
|
||||
manufacturer.save()
|
||||
flash('You have successfully edited the manufacturer.')
|
||||
return redirect(url_for('tysc.list_manufacturers'))
|
||||
form.name.data = manufacturer.name
|
||||
return render_template('simpleform.html', action="Edit",
|
||||
form=form, manufacturer=manufacturer, title="Edit Manufacturer")
|
||||
|
||||
|
||||
@TYSC.route('/manufacturer/add', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def add_manufacturer():
|
||||
"""
|
||||
Add a manufacturer
|
||||
:return:
|
||||
"""
|
||||
form = ManufacturerForm()
|
||||
if form.validate_on_submit():
|
||||
manufacturer = Manufacturer()
|
||||
manufacturer.name = form.name.data
|
||||
try:
|
||||
manufacturer.save()
|
||||
flash('You have successfully added a new manufacturer.')
|
||||
except PyMongoError:
|
||||
flash('Error: manufacturer name already exists.')
|
||||
return redirect(url_for('tysc.list_manufacturers'))
|
||||
return render_template('simpleform.html', action="Add",
|
||||
form=form, title="Add Manufacturer")
|
||||
|
||||
|
||||
@TYSC.route('/manufacturer/delete/<manufacturer_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def delete_manufacturer(manufacturer_id):
|
||||
"""
|
||||
Delete a manufacturer
|
||||
:param manufacturer_id:
|
||||
:return:
|
||||
"""
|
||||
manufacturer = Manufacturer.objects.raw({'_id': ObjectId(manufacturer_id)})
|
||||
if manufacturer:
|
||||
manufacturer.delete()
|
||||
flash('You have successfully deleted the manufacturer.')
|
||||
return redirect(url_for('tysc.list_manufacturers'))
|
||||
|
||||
|
||||
@TYSC.route('/cardsets')
|
||||
@login_required
|
||||
def list_card_sets():
|
||||
"""
|
||||
List card sets.
|
||||
:return:
|
||||
"""
|
||||
card_sets = CardSet.objects.all()
|
||||
return render_template('tysc/cardsets.html', card_sets=card_sets, title="Card Sets")
|
||||
|
||||
|
||||
@TYSC.route('/parallelsets')
|
||||
@login_required
|
||||
def list_parallel_sets():
|
||||
"""
|
||||
List card sets.
|
||||
:return:
|
||||
"""
|
||||
parallel_sets = ParallelSet.objects.all()
|
||||
return render_template('tysc/parallelsets.html',
|
||||
parallel_sets=parallel_sets, title="Parallel Sets")
|
||||
|
||||
|
||||
@TYSC.route('/insertsets')
|
||||
@login_required
|
||||
def list_insert_sets():
|
||||
"""
|
||||
List card sets.
|
||||
:return:
|
||||
"""
|
||||
insert_sets = InsertSet.objects.all()
|
||||
return render_template('tysc/insertsets.html', insert_sets=insert_sets, title="Inserts")
|
||||
|
||||
|
||||
@TYSC.route('/cards')
|
||||
@login_required
|
||||
def list_cards():
|
||||
"""
|
||||
List card sets.
|
||||
:return:
|
||||
"""
|
||||
cards = Card.objects.all()
|
||||
return render_template('tysc/cards.html', cards=cards, title="Cards")
|
||||
@@ -1,2 +0,0 @@
|
||||
"""This module declares the version of the Kontor application."""
|
||||
__version__ = '0.0.7'
|
||||
@@ -1,382 +0,0 @@
|
||||
[MASTER]
|
||||
|
||||
# Specify a configuration file.
|
||||
#rcfile=
|
||||
|
||||
# Python code to execute, usually for sys.path manipulation such as
|
||||
# pygtk.require().
|
||||
init-hook='sys.path = list(); sys.path.append("./lib/python3.4/site-packages/")'
|
||||
|
||||
# Profiled execution.
|
||||
profile=no
|
||||
|
||||
# Add files or directories to the blacklist. They should be base names, not
|
||||
# paths.
|
||||
ignore=CVS
|
||||
|
||||
# Pickle collected data for later comparisons.
|
||||
persistent=yes
|
||||
|
||||
# List of plugins (as comma separated values of python modules names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=
|
||||
|
||||
# Use multiple processes to speed up Pylint.
|
||||
jobs=1
|
||||
|
||||
# Allow loading of arbitrary C extensions. Extensions are imported into the
|
||||
# active Python interpreter and may run arbitrary code.
|
||||
unsafe-load-any-extension=no
|
||||
|
||||
# A comma-separated list of package or module names from where C extensions may
|
||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||
# run arbitrary code
|
||||
extension-pkg-whitelist=
|
||||
|
||||
# Allow optimization of some AST trees. This will activate a peephole AST
|
||||
# optimizer, which will apply various small optimizations. For instance, it can
|
||||
# be used to obtain the result of joining multiple strings with the addition
|
||||
# operator. Joining a lot of strings can lead to a maximum recursion error in
|
||||
# Pylint and this flag can prevent that. It has one side effect, the resulting
|
||||
# AST will be different than the one from reality.
|
||||
optimize-ast=no
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Only show warnings with the listed confidence levels. Leave empty to show
|
||||
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
|
||||
confidence=
|
||||
|
||||
# Enable the message, report, category or checker with the given id(s). You can
|
||||
# either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time. See also the "--disable" option for examples.
|
||||
#enable=
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifiers separated by comma (,) or put this
|
||||
# option multiple times (only on the command line, not in the configuration
|
||||
# file where it should appear only once).You can also use "--disable=all" to
|
||||
# disable everything first and then reenable specific checks. For example, if
|
||||
# you want to run only the similarities checker, you can use "--disable=all
|
||||
# --enable=similarities". If you want to run only the classes checker, but have
|
||||
# no Warning level messages displayed, use"--disable=all --enable=classes
|
||||
# --disable=W"
|
||||
disable=W1601,W1606,W1604,W1630,E1605,E1604,W1636,W1603,W1633,W1610,W1615,W1626,E1606,W0704,I0020,W1622,E1608,W1612,W1638,W1614,W1616,W1605,W1613,W1634,E1603,I0021,W1640,W1621,W1625,E1602,W1639,W1602,W1620,W1617,W1624,W1609,W1618,E1601,E1607,W1637,W1632,W1629,W1635,W1611,W1623,W1608,W1627,W1628,W1607,W1619,E1101,R0201,R0903,R0801,locally-disabled
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
# Set the output format. Available formats are text, parseable, colorized, msvs
|
||||
# (visual studio) and html. You can also give a reporter class, eg
|
||||
# mypackage.mymodule.MyReporterClass.
|
||||
output-format=parseable
|
||||
|
||||
# Put messages in a separate file for each module / package specified on the
|
||||
# command line instead of printing them on stdout. Reports (if any) will be
|
||||
# written in a file name "pylint_global.[txt|html]".
|
||||
files-output=no
|
||||
|
||||
# Tells whether to display a full report or only the messages
|
||||
reports=yes
|
||||
|
||||
# Python expression which should return a note less than 10 (10 is the highest
|
||||
# note). You have access to the variables errors warning, statement which
|
||||
# respectively contain the number of errors / warnings messages and the total
|
||||
# number of statements analyzed. This is used by the global evaluation report
|
||||
# (RP0004).
|
||||
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
||||
|
||||
# Add a comment according to your evaluation note. This is used by the global
|
||||
# evaluation report (RP0004).
|
||||
comment=no
|
||||
|
||||
# Template used to display messages. This is a python new-style format string
|
||||
# used to format the message information. See doc for all details
|
||||
#msg-template=
|
||||
|
||||
|
||||
[SPELLING]
|
||||
|
||||
# Spelling dictionary name. Available dictionaries: none. To make it working
|
||||
# install python-enchant package.
|
||||
spelling-dict=
|
||||
|
||||
# List of comma separated words that should not be checked.
|
||||
spelling-ignore-words=
|
||||
|
||||
# A path to a file that contains private dictionary; one word per line.
|
||||
spelling-private-dict-file=
|
||||
|
||||
# Tells whether to store unknown words to indicated private dictionary in
|
||||
# --spelling-private-dict-file option instead of raising a message.
|
||||
spelling-store-unknown-words=no
|
||||
|
||||
|
||||
[TYPECHECK]
|
||||
|
||||
# Tells whether missing members accessed in mixin class should be ignored. A
|
||||
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
||||
ignore-mixin-members=yes
|
||||
|
||||
# List of module names for which member attributes should not be checked
|
||||
# (useful for modules/projects where namespaces are manipulated during runtime
|
||||
# and thus existing member attributes cannot be deduced by static analysis
|
||||
ignored-modules=
|
||||
|
||||
# List of classes names for which member attributes should not be checked
|
||||
# (useful for classes with attributes dynamically set).
|
||||
ignored-classes=SQLObject
|
||||
|
||||
# When zope mode is activated, add a predefined set of Zope acquired attributes
|
||||
# to generated-members.
|
||||
zope=no
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E0201 when accessed. Python regular
|
||||
# expressions are accepted.
|
||||
generated-members=REQUEST,acl_users,aq_parent
|
||||
|
||||
|
||||
[LOGGING]
|
||||
|
||||
# Logging modules to check that the string format arguments are in logging
|
||||
# function parameter format
|
||||
logging-modules=logging
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
|
||||
# Tells whether we should check for unused import in __init__ files.
|
||||
init-import=no
|
||||
|
||||
# A regular expression matching the name of dummy variables (i.e. expectedly
|
||||
# not used).
|
||||
dummy-variables-rgx=_$|dummy
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid to define new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
# List of strings which can identify a callback function by name. A callback
|
||||
# name must start or end with one of those strings.
|
||||
callbacks=cb_,_cb
|
||||
|
||||
|
||||
[FORMAT]
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=100
|
||||
|
||||
# Regexp for a line that is allowed to be longer than the limit.
|
||||
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||
|
||||
# Allow the body of an if to be on the same line as the test if there is no
|
||||
# else.
|
||||
single-line-if-stmt=no
|
||||
|
||||
# List of optional constructs for which whitespace checking is disabled
|
||||
no-space-check=trailing-comma,dict-separator
|
||||
|
||||
# Maximum number of lines in a module
|
||||
max-module-lines=1000
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string=' '
|
||||
|
||||
# Number of spaces of indent required inside a hanging or continued line.
|
||||
indent-after-paren=4
|
||||
|
||||
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
||||
expected-line-ending-format=
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
# Required attributes for module, separated by a comma
|
||||
#required-attributes=
|
||||
|
||||
# List of builtins function names that should not be used, separated by a comma
|
||||
bad-functions=map,filter
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma
|
||||
good-names=i,j,k,ex,Run,_
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma
|
||||
bad-names=foo,bar,baz,toto,tutu,tata
|
||||
|
||||
# Colon-delimited sets of names that determine each other's naming style when
|
||||
# the name regexes allow several styles.
|
||||
name-group=
|
||||
|
||||
# Include a hint for the correct naming format with invalid-name
|
||||
include-naming-hint=yes
|
||||
|
||||
# Regular expression matching correct class attribute names
|
||||
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
|
||||
|
||||
# Naming hint for class attribute names
|
||||
class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
|
||||
|
||||
# Regular expression matching correct function names
|
||||
function-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Naming hint for function names
|
||||
function-name-hint=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression matching correct attribute names
|
||||
attr-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Naming hint for attribute names
|
||||
attr-name-hint=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression matching correct method names
|
||||
method-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Naming hint for method names
|
||||
method-name-hint=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression matching correct argument names
|
||||
argument-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Naming hint for argument names
|
||||
argument-name-hint=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression matching correct inline iteration names
|
||||
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
|
||||
|
||||
# Naming hint for inline iteration names
|
||||
inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
|
||||
|
||||
# Regular expression matching correct module names
|
||||
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
|
||||
|
||||
# Naming hint for module names
|
||||
module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
|
||||
|
||||
# Regular expression matching correct constant names
|
||||
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
|
||||
|
||||
# Naming hint for constant names
|
||||
const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
|
||||
|
||||
# Regular expression matching correct class names
|
||||
class-rgx=[A-Z_][a-zA-Z0-9]+$
|
||||
|
||||
# Naming hint for class names
|
||||
class-name-hint=[A-Z_][a-zA-Z0-9]+$
|
||||
|
||||
# Regular expression matching correct variable names
|
||||
variable-rgx=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Naming hint for variable names
|
||||
variable-name-hint=[a-z_][a-z0-9_]{2,30}$
|
||||
|
||||
# Regular expression which should only match function or class names that do
|
||||
# not require a docstring.
|
||||
no-docstring-rgx=__.*__
|
||||
|
||||
# Minimum line length for functions/classes that require docstrings, shorter
|
||||
# ones are exempt.
|
||||
docstring-min-length=-1
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,XXX,TODO
|
||||
|
||||
|
||||
[SIMILARITIES]
|
||||
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
# Ignore comments when computing similarities.
|
||||
ignore-comments=yes
|
||||
|
||||
# Ignore docstrings when computing similarities.
|
||||
ignore-docstrings=yes
|
||||
|
||||
# Ignore imports when computing similarities.
|
||||
ignore-imports=no
|
||||
|
||||
|
||||
[CLASSES]
|
||||
|
||||
# List of interface methods to ignore, separated by a comma. This is used for
|
||||
# instance to not check methods defines in Zope's Interface base class.
|
||||
#ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
|
||||
|
||||
# List of method names used to declare (i.e. assign) instance attributes.
|
||||
defining-attr-methods=__init__,__new__,setUp
|
||||
|
||||
# List of valid names for the first argument in a class method.
|
||||
valid-classmethod-first-arg=cls
|
||||
|
||||
# List of valid names for the first argument in a metaclass class method.
|
||||
valid-metaclass-classmethod-first-arg=mcs
|
||||
|
||||
# List of member names, which should be excluded from the protected access
|
||||
# warning.
|
||||
exclude-protected=_asdict,_fields,_replace,_source,_make
|
||||
|
||||
|
||||
[DESIGN]
|
||||
|
||||
# Maximum number of arguments for function / method
|
||||
max-args=5
|
||||
|
||||
# Argument names that match this expression will be ignored. Default to name
|
||||
# with leading underscore
|
||||
ignored-argument-names=_.*
|
||||
|
||||
# Maximum number of locals for function / method body
|
||||
max-locals=15
|
||||
|
||||
# Maximum number of return / yield for function / method body
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of branch for function / method body
|
||||
max-branches=12
|
||||
|
||||
# Maximum number of statements in function / method body
|
||||
max-statements=50
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=7
|
||||
|
||||
# Minimum number of public methods for a class (see R0903).
|
||||
min-public-methods=2
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
|
||||
[IMPORTS]
|
||||
|
||||
# Deprecated modules which should not be used, separated by a comma
|
||||
deprecated-modules=stringprep,optparse
|
||||
|
||||
# Create a graph of every (i.e. internal and external) dependencies in the
|
||||
# given file (report RP0402 must not be disabled)
|
||||
import-graph=
|
||||
|
||||
# Create a graph of external dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
ext-import-graph=
|
||||
|
||||
# Create a graph of internal dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
int-import-graph=
|
||||
|
||||
|
||||
[EXCEPTIONS]
|
||||
|
||||
# Exceptions that will emit a warning when being caught. Defaults to
|
||||
# "Exception"
|
||||
overgeneral-exceptions=Exception
|
||||
@@ -1,11 +0,0 @@
|
||||
flask
|
||||
flask-login
|
||||
flask-bootstrap
|
||||
Flask-WTF
|
||||
flask-testing
|
||||
pymodm
|
||||
nose
|
||||
nose-htmloutput
|
||||
coverage
|
||||
pylint
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
from flask_testing import TestCase
|
||||
from kontor import create_app
|
||||
from kontor.models import User
|
||||
|
||||
|
||||
class TestBase(TestCase):
|
||||
|
||||
def create_app(self):
|
||||
|
||||
# pass in test configuration
|
||||
config_name = 'testing'
|
||||
app = create_app(config_name)
|
||||
return app
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Will be called before every test
|
||||
"""
|
||||
# create test admin user
|
||||
admin = User()
|
||||
admin.username="admin"
|
||||
admin.password="admin2016"
|
||||
admin.is_admin=True
|
||||
admin.save()
|
||||
|
||||
# create test non-admin user
|
||||
employee = User()
|
||||
employee.username="test_user"
|
||||
employee.password="test2016"
|
||||
employee.save()
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
Will be called after every test
|
||||
"""
|
||||
users = User.objects.all()
|
||||
for user in users:
|
||||
user.delete()
|
||||
@@ -1,51 +0,0 @@
|
||||
"""
|
||||
This module cantains tests for the comic data model
|
||||
"""
|
||||
import unittest
|
||||
from . import TestBase
|
||||
from kontor.comics.models import Artist, Comic, Publisher
|
||||
|
||||
|
||||
class TestComicsModel(TestBase):
|
||||
"""This TestCase contains tests for comic data model."""
|
||||
|
||||
def setUp(self):
|
||||
publisher = Publisher()
|
||||
publisher.name = "Publisher1"
|
||||
publisher.save()
|
||||
artist = Artist()
|
||||
artist.name = "Artist1"
|
||||
artist.save()
|
||||
comic = Comic()
|
||||
comic.title = "Title1"
|
||||
comic.save()
|
||||
|
||||
def tearDown(self):
|
||||
for comic in Comic.objects.all():
|
||||
comic.delete()
|
||||
for artist in Artist.objects.all():
|
||||
artist.delete()
|
||||
for publisher in Publisher.objects.all():
|
||||
publisher.delete()
|
||||
|
||||
def test_comic_model(self):
|
||||
comic_list = Comic.objects.all()
|
||||
self.assertEqual(comic_list.count(), 1)
|
||||
|
||||
def test_publisher_model(self):
|
||||
self.assertEqual(Publisher.objects.all().count(), 1)
|
||||
|
||||
def test_artist_model(self):
|
||||
self.assertEqual(Artist.objects.all().count(), 1)
|
||||
|
||||
def test_assign_publisher(self):
|
||||
comic = Comic.objects.first()
|
||||
publisher = Publisher.objects.first()
|
||||
comic.publisher = publisher
|
||||
comic.save()
|
||||
self.assertEqual(publisher.name, comic.publisher.name)
|
||||
self.assertEqual(publisher.comics.count(), 1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,44 +0,0 @@
|
||||
"""This module contains tests for Comic related urls."""
|
||||
import unittest
|
||||
from flask import url_for
|
||||
from . import TestBase
|
||||
|
||||
|
||||
class TestComicsViews(TestBase):
|
||||
|
||||
def test_comics_index(self):
|
||||
"""
|
||||
Test that comics page is inaccessible without login
|
||||
and redirects to login page then to comics page
|
||||
"""
|
||||
target_url = url_for('comic.list_comics')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
def test_comics_artist(self):
|
||||
"""
|
||||
Test that comics page is inaccessible without login
|
||||
and redirects to login page then to comics page
|
||||
"""
|
||||
target_url = url_for('comic.list_artists')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
def test_comics_publisher(self):
|
||||
"""
|
||||
Test that comics page is inaccessible without login
|
||||
and redirects to login page then to comics page
|
||||
"""
|
||||
target_url = url_for('comic.list_publishers')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,4 +0,0 @@
|
||||
# instance/config.py
|
||||
|
||||
SECRET_KEY = 'p9Bv<3Eid9%$i01'
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
"""
|
||||
This module cantains tests for the general Kontor data model.
|
||||
"""
|
||||
from . import TestBase
|
||||
from kontor.models import User
|
||||
|
||||
|
||||
class TestKontorModel(TestBase):
|
||||
"""This TestCase contains tests for users."""
|
||||
def test_user_model(self):
|
||||
"""
|
||||
Test number of records in User collection
|
||||
"""
|
||||
self.assertEqual(User.objects.all().count(), 2)
|
||||
@@ -1,58 +0,0 @@
|
||||
"""This module contains tests for Comic related urls."""
|
||||
import unittest
|
||||
from flask import url_for
|
||||
from . import TestBase
|
||||
|
||||
|
||||
class TestKontorViews(TestBase):
|
||||
|
||||
def test_homepage_view(self):
|
||||
"""
|
||||
Test that homepage is accessible without login
|
||||
"""
|
||||
response = self.client.get(url_for('home.homepage'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_login_view(self):
|
||||
"""
|
||||
Test that login page is accessible without login
|
||||
"""
|
||||
response = self.client.get(url_for('auth.login'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_logout_view(self):
|
||||
"""
|
||||
Test that logout link is inaccessible without login
|
||||
and redirects to login page then to logout
|
||||
"""
|
||||
target_url = url_for('auth.logout')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
def test_dashboard_view(self):
|
||||
"""
|
||||
Test that dashboard is inaccessible without login
|
||||
and redirects to login page then to dashboard
|
||||
"""
|
||||
target_url = url_for('home.dashboard')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
def test_admin_dashboard_view(self):
|
||||
"""
|
||||
Test that dashboard is inaccessible without login
|
||||
and redirects to login page then to dashboard
|
||||
"""
|
||||
target_url = url_for('home.admin_dashboard')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,49 +0,0 @@
|
||||
"""
|
||||
This module cantains tests for the comic data model
|
||||
"""
|
||||
import unittest
|
||||
from . import TestBase
|
||||
from kontor.library.models import Author, Publisher, Book
|
||||
|
||||
|
||||
class TestComicsModel(TestBase):
|
||||
"""This TestCase contains tests for comic data model."""
|
||||
|
||||
def setUp(self):
|
||||
publisher = Publisher()
|
||||
publisher.name = "Publisher1"
|
||||
publisher.save()
|
||||
author = Author()
|
||||
author.name = "Autor1"
|
||||
author.save()
|
||||
book = Book()
|
||||
book.title = "Title1"
|
||||
book.save()
|
||||
|
||||
def tearDown(self):
|
||||
for book in Book.objects.all():
|
||||
book.delete()
|
||||
for author in Author.objects.all():
|
||||
author.delete()
|
||||
for publisher in Publisher.objects.all():
|
||||
publisher.delete()
|
||||
|
||||
def test_comic_model(self):
|
||||
book_list = Book.objects.all()
|
||||
self.assertEqual(book_list.count(), 1)
|
||||
|
||||
def test_publisher_model(self):
|
||||
self.assertEqual(Publisher.objects.all().count(), 1)
|
||||
|
||||
def test_artist_model(self):
|
||||
self.assertEqual(Author.objects.all().count(), 1)
|
||||
|
||||
def test_assign_publisher(self):
|
||||
book = Book.objects.first()
|
||||
publisher = Publisher.objects.first()
|
||||
book.publisher = publisher
|
||||
book.save()
|
||||
self.assertEqual(publisher.name, book.publisher.name)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,44 +0,0 @@
|
||||
"""This module contains tests for Comic related urls."""
|
||||
import unittest
|
||||
from flask import url_for
|
||||
from . import TestBase
|
||||
|
||||
|
||||
class TestLibraryViews(TestBase):
|
||||
|
||||
def test_library_index(self):
|
||||
"""
|
||||
Test that comics page is inaccessible without login
|
||||
and redirects to login page then to comics page
|
||||
"""
|
||||
target_url = url_for('library.list_books')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
def test_library_author(self):
|
||||
"""
|
||||
Test that comics page is inaccessible without login
|
||||
and redirects to login page then to comics page
|
||||
"""
|
||||
target_url = url_for('library.list_authors')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
def test_library_publisher(self):
|
||||
"""
|
||||
Test that comics page is inaccessible without login
|
||||
and redirects to login page then to comics page
|
||||
"""
|
||||
target_url = url_for('library.list_publishers')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,53 +0,0 @@
|
||||
"""
|
||||
This module cantains tests for the TYSC data model
|
||||
"""
|
||||
import unittest
|
||||
from . import TestBase
|
||||
from kontor.tysc import initialize_model
|
||||
from kontor.tysc.models import Sport, Position, Team, Player
|
||||
from kontor.tysc.models import Manufacturer, CardSet, ParallelSet, InsertSet, Card
|
||||
|
||||
|
||||
class TestTYSCModel(TestBase):
|
||||
"""
|
||||
This TestCase contains tests for TYSC data model.
|
||||
"""
|
||||
_initialize_db_ = True
|
||||
|
||||
def setUp(self):
|
||||
if self._initialize_db_:
|
||||
initialize_model()
|
||||
self._initialize_db_ = False
|
||||
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def test_sport_model(self):
|
||||
self.assertEqual(Sport.objects.all().count(), 4)
|
||||
|
||||
def test_position_model(self):
|
||||
self.assertEqual(Position.objects.all().count(), 25)
|
||||
|
||||
def test_team_model(self):
|
||||
self.assertEqual(Team.objects.all().count(), 122)
|
||||
|
||||
def test_manufacturer_model(self):
|
||||
self.assertEqual(Manufacturer.objects.all().count(), 8)
|
||||
|
||||
def test_cardset_model(self):
|
||||
self.assertEqual(CardSet.objects.all().count(), 11)
|
||||
|
||||
def test_parallelset_model(self):
|
||||
self.assertEqual(ParallelSet.objects.all().count(), 3)
|
||||
|
||||
def test_insertset_model(self):
|
||||
self.assertEqual(InsertSet.objects.all().count(), 1)
|
||||
|
||||
def test_playerset_model(self):
|
||||
self.assertEqual(Player.objects.all().count(), 36)
|
||||
|
||||
def test_card_model(self):
|
||||
self.assertEqual(Card.objects.all().count(), 36)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,110 +0,0 @@
|
||||
"""This module contains tests for TradeYourSportsCards related urls."""
|
||||
import unittest
|
||||
from flask import url_for
|
||||
from . import TestBase
|
||||
|
||||
|
||||
class TestTYSCViews(TestBase):
|
||||
|
||||
def test_tysc_index(self):
|
||||
"""
|
||||
Test that TYSC page is inaccessible without login
|
||||
and redirects to login page then to TYSC page
|
||||
"""
|
||||
target_url = url_for('tysc.list_cards')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
def test_tysc_sport(self):
|
||||
"""
|
||||
Test that TYSC page is inaccessible without login
|
||||
and redirects to login page then to TYSC page
|
||||
"""
|
||||
target_url = url_for('tysc.list_sports')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
def test_tysc_team(self):
|
||||
"""
|
||||
Test that TYSC page is inaccessible without login
|
||||
and redirects to login page then to TYSC page
|
||||
"""
|
||||
target_url = url_for('tysc.list_teams')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
def test_tysc_player(self):
|
||||
"""
|
||||
Test that TYSC page is inaccessible without login
|
||||
and redirects to login page then to TYSC page
|
||||
"""
|
||||
target_url = url_for('tysc.list_players')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
def test_tysc_manufacturer(self):
|
||||
"""
|
||||
Test that TYSC page is inaccessible without login
|
||||
and redirects to login page then to TYSC page
|
||||
"""
|
||||
target_url = url_for('tysc.list_manufacturers')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
def test_tysc_card_set(self):
|
||||
"""
|
||||
Test that TYSC page is inaccessible without login
|
||||
and redirects to login page then to TYSC page
|
||||
"""
|
||||
target_url = url_for('tysc.list_card_sets')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
def test_tysc_parallel_set(self):
|
||||
"""
|
||||
Test that TYSC page is inaccessible without login
|
||||
and redirects to login page then to TYSC page
|
||||
"""
|
||||
target_url = url_for('tysc.list_parallel_sets')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
def test_tysc_insert_set(self):
|
||||
"""
|
||||
Test that TYSC page is inaccessible without login
|
||||
and redirects to login page then to TYSC page
|
||||
"""
|
||||
target_url = url_for('tysc.list_insert_sets')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
def test_tysc_card(self):
|
||||
"""
|
||||
Test that TYSC page is inaccessible without login
|
||||
and redirects to login page then to TYSC page
|
||||
"""
|
||||
target_url = url_for('tysc.list_cards')
|
||||
redirect_url = url_for('auth.login', next=target_url)
|
||||
response = self.client.get(target_url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertRedirects(response, redirect_url)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user