import from kontor-flask branch develop/0.1.0

This commit is contained in:
Thomas Peetz
2025-01-08 22:34:21 +01:00
committed by Thomas Peetz
parent 0d2f27f771
commit 28746adfbb
82 changed files with 562 additions and 4270 deletions
+51 -64
View File
@@ -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
-4
View File
@@ -1,4 +0,0 @@
"""
Module admin implements administration functions.
"""
from . import views
-17
View File
@@ -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')
-63
View File
@@ -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')
+5
View File
@@ -0,0 +1,5 @@
from flask import Blueprint
api_bp = Blueprint('api_bp', __name__)
from kontor.api import routes
+30
View File
@@ -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}!'}
+22 -4
View File
@@ -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
-50
View File
@@ -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')
+45
View File
@@ -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"))
-79
View File
@@ -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'))
+9 -3
View File
@@ -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
+28
View File
@@ -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)
-31
View File
@@ -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')
-51
View File
@@ -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)
+16
View File
@@ -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 %}
-222
View File
@@ -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'))
+10
View File
@@ -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
+5
View File
@@ -0,0 +1,5 @@
import flask_sqlalchemy
from flask_marshmallow import Marshmallow
db = flask_sqlalchemy.SQLAlchemy()
ma = Marshmallow()
-3
View File
@@ -1,3 +0,0 @@
"""
Module for the Kontor homepage.
"""
-39
View File
@@ -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")
-3
View File
@@ -1,3 +0,0 @@
"""
Define routing rules for library related information
"""
-35
View File
@@ -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')
-55
View File
@@ -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)
-228
View File
@@ -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'))
+5
View File
@@ -0,0 +1,5 @@
from flask import Blueprint
bp = Blueprint('main', __name__)
from kontor.main import routes
+18
View File
@@ -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')
+9
View File
@@ -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
+18
View File
@@ -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)
+43
View 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)
+16
View File
@@ -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
View File
@@ -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)
-3
View File
@@ -1,3 +0,0 @@
"""
Define routing rules for office related information
"""
-126
View File
@@ -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 %}
-18
View File
@@ -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 %}
-14
View File
@@ -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 %}
+59 -98
View File
@@ -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 %}
-66
View File
@@ -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 %}
-20
View File
@@ -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 %}
+8
View File
@@ -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 %}
-74
View File
@@ -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 %}
-21
View File
@@ -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 %}
-60
View File
@@ -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 %}
-58
View File
@@ -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 %}
-60
View File
@@ -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 %}
-377
View File
@@ -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()
-76
View File
@@ -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()])
-155
View File
@@ -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)
-405
View File
@@ -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")
-2
View File
@@ -1,2 +0,0 @@
"""This module declares the version of the Kontor application."""
__version__ = '0.0.7'