Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 177550f
Showing
20 changed files
with
827 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
### https://raw.github.com/github/gitignore/218a941be92679ce67d0484547e3e142b2f5f6f0/Python.gitignore | ||
|
||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# C extensions | ||
*.so | ||
|
||
# Distribution / packaging | ||
.Python | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
wheels/ | ||
share/python-wheels/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
MANIFEST | ||
|
||
# PyInstaller | ||
# Usually these files are written by a python script from a template | ||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
*.manifest | ||
*.spec | ||
|
||
# Installer logs | ||
pip-log.txt | ||
pip-delete-this-directory.txt | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
.tox/ | ||
.nox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*.cover | ||
*.py,cover | ||
.hypothesis/ | ||
.pytest_cache/ | ||
cover/ | ||
|
||
# Translations | ||
*.mo | ||
*.pot | ||
|
||
# Django stuff: | ||
*.log | ||
local_settings.py | ||
db.sqlite3 | ||
db.sqlite3-journal | ||
|
||
# Flask stuff: | ||
instance/ | ||
.webassets-cache | ||
|
||
# Scrapy stuff: | ||
.scrapy | ||
|
||
# Sphinx documentation | ||
docs/_build/ | ||
|
||
# PyBuilder | ||
.pybuilder/ | ||
target/ | ||
|
||
# Jupyter Notebook | ||
.ipynb_checkpoints | ||
|
||
# IPython | ||
profile_default/ | ||
ipython_config.py | ||
|
||
# pyenv | ||
# For a library or package, you might want to ignore these files since the code is | ||
# intended to run in multiple environments; otherwise, check them in: | ||
# .python-version | ||
|
||
# pipenv | ||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. | ||
# However, in case of collaboration, if having platform-specific dependencies or dependencies | ||
# having no cross-platform support, pipenv may install dependencies that don't work, or not | ||
# install all needed dependencies. | ||
#Pipfile.lock | ||
|
||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow | ||
__pypackages__/ | ||
|
||
# Celery stuff | ||
celerybeat-schedule | ||
celerybeat.pid | ||
|
||
# SageMath parsed files | ||
*.sage.py | ||
|
||
# Environments | ||
.env | ||
.venv | ||
env/ | ||
venv/ | ||
ENV/ | ||
env.bak/ | ||
venv.bak/ | ||
|
||
# Spyder project settings | ||
.spyderproject | ||
.spyproject | ||
|
||
# Rope project settings | ||
.ropeproject | ||
|
||
# mkdocs documentation | ||
/site | ||
|
||
# mypy | ||
.mypy_cache/ | ||
.dmypy.json | ||
dmypy.json | ||
|
||
# Pyre type checker | ||
.pyre/ | ||
|
||
# pytype static type analyzer | ||
.pytype/ | ||
|
||
# Cython debug symbols | ||
cython_debug/ | ||
|
||
|
||
### https://raw.github.com/github/gitignore/218a941be92679ce67d0484547e3e142b2f5f6f0/Global/Emacs.gitignore | ||
|
||
# -*- mode: gitignore; -*- | ||
*~ | ||
\#*\# | ||
/.emacs.desktop | ||
/.emacs.desktop.lock | ||
*.elc | ||
auto-save-list | ||
tramp | ||
.\#* | ||
|
||
# Org-mode | ||
.org-id-locations | ||
*_archive | ||
|
||
# flymake-mode | ||
*_flymake.* | ||
|
||
# eshell files | ||
/eshell/history | ||
/eshell/lastdir | ||
|
||
# elpa packages | ||
/elpa/ | ||
|
||
# reftex files | ||
*.rel | ||
|
||
# AUCTeX auto folder | ||
/auto/ | ||
|
||
# cask packages | ||
.cask/ | ||
dist/ | ||
|
||
# Flycheck | ||
flycheck_*.el | ||
|
||
# server auth directory | ||
/server/ | ||
|
||
# projectiles files | ||
.projectile | ||
|
||
# directory configuration | ||
.dir-locals.el | ||
|
||
# network security | ||
/network-security.data | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
from flask import Flask | ||
from flask_sqlalchemy import SQLAlchemy | ||
from flask_migrate import Migrate | ||
from flask_login import LoginManager | ||
from .config import Config | ||
|
||
app = Flask(__name__) | ||
app.config.from_object(Config) | ||
db = SQLAlchemy(app) | ||
migrate = Migrate(app, db) | ||
login = LoginManager(app) | ||
|
||
from . import routes, models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import os | ||
basedir = os.path.abspath(os.path.dirname(__file__)) | ||
|
||
|
||
class Config(object): | ||
SECRET_KEY = os.environ.get('CC0_SECRET_KEY') | ||
SQLALCHEMY_DATABASE_URI = os.environ.get("CC0_SQLALCHEMY_DATABASE_URI") or f"sqlite:///{os.path.join(basedir, 'app.db')}" | ||
SQLALCHEMY_TRACK_MODIFICATIONS = False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from flask_wtf import FlaskForm | ||
from wtforms import StringField, PasswordField, BooleanField, SubmitField | ||
from wtforms.validators import DataRequired, ValidationError, URL | ||
from .models import CopyrightHolder | ||
|
||
class LoginForm(FlaskForm): | ||
name = StringField('username', validators=[DataRequired()]) | ||
password = PasswordField('password', validators=[DataRequired()]) | ||
remember = BooleanField('🍪') | ||
submit = SubmitField('login') | ||
|
||
class RegistrationForm(FlaskForm): | ||
name = StringField('username', validators=[DataRequired()]) | ||
password = PasswordField('password', validators=[DataRequired()]) | ||
legal_name = StringField('legal name', validators=[DataRequired()]) | ||
website = StringField('website url', validators=[DataRequired(), URL()]) | ||
submit = SubmitField('register') | ||
|
||
def validate_name(self, username): | ||
user = CopyrightHolder.query.filter_by(username=username.data).first() | ||
|
||
if user is not None or user in ["login", "register", "logout"]: | ||
raise ValidationError('sorry, username in use') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
from datetime import datetime | ||
from werkzeug.security import generate_password_hash, check_password_hash | ||
from flask_login import UserMixin | ||
from . import db | ||
from . import login | ||
|
||
@login.user_loader | ||
def load_user(id): | ||
return CopyrightHolder.query.get(int(id)) | ||
|
||
class CopyrightHolder(UserMixin, db.Model): | ||
id = db.Column(db.Integer, primary_key=True) | ||
username = db.Column(db.String(128), index=True, unique=True) | ||
legal_name = db.Column(db.String(128), index=True) | ||
password_hash = db.Column(db.String(128)) | ||
email = db.Column(db.String(128), index=True, unique=True) | ||
website = db.Column(db.String(256), index=True, unique=True) | ||
collections = db.relationship('Collection', backref='copyright_holder', lazy='dynamic') | ||
|
||
def __repr__(self): | ||
return f'<CopyrightHolder {self.username} ("{self.legal_name}" <{self.email}>)>' | ||
|
||
def set_password(self, password): | ||
self.password_hash = generate_password_hash(password) | ||
def check_password(self, password): | ||
return check_password_hash(self.password_hash, password) | ||
def is_admin(self): | ||
return self.id == 1 | ||
|
||
class Collection(db.Model): | ||
id = db.Column(db.Integer, primary_key=True) | ||
name = db.Column(db.String(128), index=True, unique=True) | ||
description = db.Column(db.String(256)) | ||
slug = db.Column(db.String(128), index=True) | ||
copyright_holder_id = db.Column(db.Integer, db.ForeignKey('copyright_holder.id')) | ||
password_hash = db.Column(db.String(128)) | ||
pieces = db.relationship('Piece', backref='collection', lazy='dynamic') | ||
def __repr__(self): | ||
return f'<Collection {self.name}>' | ||
|
||
class Piece(db.Model): | ||
id = db.Column(db.Integer, primary_key=True) | ||
name = db.Column(db.String(128), index=True, unique=True) | ||
description = db.Column(db.String(256)) | ||
url = db.Column(db.String(128)) | ||
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow) | ||
type = db.Column(db.String(10), index=True) | ||
collection_id = db.Column(db.Integer, db.ForeignKey('collection.id')) | ||
def __repr__(self): | ||
return f'<Piece {self.name}>' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
from flask import render_template, flash, redirect, url_for | ||
from flask_login import current_user, login_user | ||
from . import app | ||
from . import db | ||
from .forms import LoginForm, RegistrationForm | ||
from .models import CopyrightHolder, Collection, Piece | ||
|
||
from os import scandir | ||
from os.path import join, dirname | ||
|
||
@app.route('/') | ||
def index(): | ||
return render_template("index.html", | ||
collections=Collection.query.all()) | ||
|
||
@app.route('/logout') | ||
def logout(): | ||
return render_template("base.html") | ||
|
||
@app.route('/register', methods=['GET', 'POST']) | ||
def register(): | ||
form = RegistrationForm() | ||
if form.validate_on_submit(): | ||
ch = CopyrightHolder( | ||
username=form.name.data, | ||
legal_name=form.legal_name.data | ||
) | ||
ch.set_password(form.password.data) | ||
db.session.add(ch) | ||
db.session.commit() | ||
flash(f"{ch} created") | ||
return redirect(url_for('index')) | ||
return render_template('register.html', title="make user", form=form) | ||
|
||
@app.route('/login', methods=['GET', 'POST']) | ||
def login(): | ||
if current_user.is_authenticated: | ||
return redirect(url_for('index')) | ||
form = LoginForm() | ||
if form.validate_on_submit(): | ||
copyright_holder = CopyrightHolder.query.filter_by(username=form.name.data).first() | ||
if copyright_holder is None or not copyright_holder.check_password(form.password.data): | ||
flash('bad name or wrong pass') | ||
return redirect(url_for('login')) | ||
login_user(copyright_holder, remember=form.remember.data) | ||
return redirect(url_for('index')) | ||
return render_template('login.html', title="login", form=form) | ||
|
||
@app.route('/<username>') | ||
def copyright_holder(username): | ||
ch = CopyrightHolder.query.filter_by(username=username).first() | ||
if ch is None: | ||
return "404" | ||
return render_template("copyright_holder.html", | ||
copyright_holder=ch) | ||
|
||
@app.route('/<username>/new') | ||
def new_collection(username): | ||
return render_template("base.html") | ||
|
||
|
||
@app.route('/<username>/<slug>') | ||
def collection(username, slug): | ||
collection = Collection.query.filter_by(slug=slug).first() | ||
if collection is None: | ||
return "404" | ||
return render_template("collection.html", | ||
copyright_holder=collection) | ||
|
||
@app.route('/<username>/<slug>/new') | ||
def new_piece(username, slug): | ||
return render_template("base.html") |
Oops, something went wrong.