1
1
Fork 0

Great reorganization, rip flask-admin

dev
Jan Kužílek 5 years ago
parent 9464b2f3c0
commit 8255913c58

@ -6,15 +6,16 @@ from flask_migrate import Migrate
from flask_login import LoginManager from flask_login import LoginManager
from flask_assets import Environment as AssetsEnvironment, Bundle as AssetsBundle from flask_assets import Environment as AssetsEnvironment, Bundle as AssetsBundle
from flask_admin import Admin # from flask_admin import Admin
from flask_admin.contrib.sqla import ModelView # from flask_admin.contrib.sqla import ModelView
db = SQLAlchemy() db = SQLAlchemy()
migrate = Migrate() migrate = Migrate()
login = LoginManager() login = LoginManager()
assets = AssetsEnvironment() assets = AssetsEnvironment()
admin = Admin() # THIS FUCKER DARES TO MESS WITH MY BLUEPRINTS (that blueprint collision shitxception)
# admin = Admin()
def create_app(): def create_app():
@ -27,7 +28,7 @@ def create_app():
POST_LIST_THUMB_HEIGHT=200, POST_LIST_THUMB_HEIGHT=200,
POST_UPLOADS=os.path.join(app.instance_path, 'post'), POST_UPLOADS=os.path.join(app.instance_path, 'post'),
INSTANCE_NAME='YADC', INSTANCE_NAME='YADC',
POSTS_PER_PAGE=8, POSTS_PER_PAGE=4,
SQLALCHEMY_ECHO=True, SQLALCHEMY_ECHO=True,
) )
@ -44,17 +45,19 @@ def create_app():
from yadc import models from yadc import models
admin.init_app(app) # admin.init_app(app)
admin.add_view(ModelView(models.User, db.session)) # admin.add_view(ModelView(models.User, db.session))
admin.add_view(ModelView(models.Post, db.session)) # admin.add_view(ModelView(models.Post, db.session))
admin.add_view(ModelView(models.Tag, db.session)) # admin.add_view(ModelView(models.Tag, db.session))
admin.add_view(ModelView(models.Comment, db.session)) # admin.add_view(ModelView(models.Comment, db.session))
from yadc.bp import main, auth from yadc.bp import main, post, auth
app.register_blueprint(main.bp) app.register_blueprint(main.bp)
app.register_blueprint(post.bp, url_prefix='/post')
app.register_blueprint(auth.bp, url_prefix='/user') app.register_blueprint(auth.bp, url_prefix='/user')
login.login_view = 'auth.login' login.login_view = 'auth.login'
#assets.url = app.static_url_path #assets.url = app.static_url_path
scss = AssetsBundle('default.scss', filters='libsass', output='all.css') scss = AssetsBundle('default.scss', filters='libsass', output='all.css')
assets.register('scss_all', scss) assets.register('scss_all', scss)

@ -8,124 +8,15 @@ from PIL import Image
from sqlalchemy import func from sqlalchemy import func
from sqlalchemy.orm import aliased from sqlalchemy.orm import aliased
from werkzeug.urls import Href
from yadc import db from yadc import db
from yadc.forms import UploadPostForm from yadc.forms import UploadPostForm
from yadc.models import FILETYPE, RATING, Post, Tag, post_tags from yadc.models import FILETYPE, RATING, Post, Tag
def query_replace(dic, base=''):
args = request.args.to_dict()
return Href(base)(args.update(dic) or args)
bp = Blueprint('main', __name__) bp = Blueprint('main', __name__)
@bp.route('/') @bp.route('/')
def index(): def index():
return redirect(url_for('main.posts')) return redirect(url_for('post.posts'))
# @bp.route('/')
@bp.route('/post', defaults={'page': 1})
@bp.route('/post/<int:page>')
def posts(page):
def tags_prepare(posts):
# tags = db.session.query(Tag, func.array_agg(posts.c.id)).join(posts, Tag.posts).group_by(Tag.id).all()
tags = db.session.query(Tag, func.array_agg(Post.id)).join(Tag.posts).filter(Post.id.in_([p.id for p in posts])).group_by(Tag.id).all()
# tagset = set()
# taglist = list()
# for post in posts:
# for tag in post.tags:
# tagset.add(tag)
# taglist.append(tag)
# for tag in tagset:
# tag.count = taglist.count(tag)
for tag,p_ids in tags:
tag.count = len(p_ids)
tag.post_ids = p_ids
tag.endpoint = query_replace({'tags': tag.content.replace(' ','_')}, url_for('main.posts'))
# tags = list(tagset)
tags = [t[0] for t in tags]
tags.sort(key=lambda x: (x.category.value, x.content) )
return tags
def parse_args():
args = request.args
tags = (args.get('tags') or '').split(' ')
tags = [t.replace('_',' ') for t in tags] if tags[0] != '' else []
rating = {r.name : r for r in RATING}.get(args.get('rating')) or RATING.safe
matched_ratings = [r for r in RATING if r.value<=rating.value]
# page = int(args.get('page') or 1)
return (tags, matched_ratings)
f_tags, f_rating = parse_args()
posts_query = Post.query
if len(f_tags)>0:
posts_query = posts_query.join(Post.tags).group_by(Post.id).filter(Tag.content.in_(f_tags)).having(func.count(Post.id)==len(f_tags))
posts_query = posts_query.filter(Post.rating.in_(f_rating)).order_by(Post.created) #.offset((page-1)*posts_on_page).limit(posts_on_page)
posts = posts_query.paginate(page, app.config.get('POSTS_PER_PAGE'))
tags = tags_prepare(posts.items)
flash(parse_args())
# flash(posts.items)
# flash(tags)
return render_template('index.html', posts=posts.items, tags=tags, pagination=posts, query_replace=query_replace)
@bp.route('/post/show/<id>')
def post_show(id):
post = Post.query.filter_by(id=id).first()
# flash(post)
tags_count = db.session.query(Tag, func.count(Post.id)).join(Tag.posts).filter(Post.id==id).join(aliased(Post), Tag.posts).group_by(Tag).all()
for tag_count in tags_count:
tag, count = tag_count
tag.count = count
tag.endpoint = query_replace({'tags': tag.content.replace(' ','_')}, url_for('main.posts'))
return render_template('post.html', post=post, tags=post.tags)
@bp.route('/post/upload', methods=['GET', 'POST'])
@login_required
def post_upload():
form = UploadPostForm(request.form)
if request.method == 'POST' and form.validate():
file = request.files.get(form.post_img.name)
file.data = io.BytesIO(file.read())
# tagy
post = Post(file, source=form.sauce.data, rating=RATING[form.rating.data], author=current_user)
with open(post.image_path, "wb") as f:
f.write(file.data.getbuffer())
# file.seek(0)
# file.save(post.image_path)
with Image.open(file.data) as im:
im = im.convert('RGB')
if post.jpeg_path is not None:
im.save(post.jpeg_path, 'JPEG', quality=80)
im.thumbnail([512,512])
im.save(post.thumb_path, 'JPEG', quality=80)
db.session.add(post)
db.session.commit()
flash('Successfully submitted {}'.format(str(post)))
return redirect(url_for('main.post_upload'))
return render_template('upload.html', form=form)
@bp.route('/i/<path:path>') @bp.route('/i/<path:path>')
def uploaded_img(path, store='img', exten=None): def uploaded_img(path, store='img', exten=None):
@ -147,15 +38,15 @@ def uploaded_thumb(*args, **kwargs):
return uploaded_img(*args, **kwargs, store='thumb', exten='jpg') return uploaded_img(*args, **kwargs, store='thumb', exten='jpg')
@bp.route('/threads') # @bp.route('/threads')
def threads(): # def threads():
return render_template('index.html') # return render_template('index.html')
@bp.route('/user/show/<username>') # @bp.route('/user/show/<username>')
def user_profile(username): # def user_profile(username):
pass # pass
@bp.route('/user/settings') # @bp.route('/user/settings')
@login_required # @login_required
def user_settings(): # def user_settings():
pass # pass

@ -0,0 +1,117 @@
import io
import os
from flask import (Blueprint, abort, current_app, flash, redirect,
render_template, request, send_from_directory, url_for)
from flask_login import current_user, login_required
from PIL import Image
from sqlalchemy import func
from sqlalchemy.orm import aliased
from yadc import db
from yadc.forms import UploadPostForm
from yadc.models import FILETYPE, RATING, Post, Tag
from yadc.utils import query_replace
bp = Blueprint('post', __name__)
# @bp.route('/')
@bp.route('', defaults={'page': 1})
@bp.route('/<int:page>')
def posts(page):
def tags_prepare(posts):
# tags = db.session.query(Tag, func.array_agg(posts.c.id)).join(posts, Tag.posts).group_by(Tag.id).all()
tags = db.session.query(Tag, func.array_agg(Post.id)).join(Tag.posts).filter(Post.id.in_([p.id for p in posts])).group_by(Tag.id).all()
# tagset = set()
# taglist = list()
# for post in posts:
# for tag in post.tags:
# tagset.add(tag)
# taglist.append(tag)
# for tag in tagset:
# tag.count = taglist.count(tag)
for tag,p_ids in tags:
tag.count = len(p_ids)
tag.post_ids = p_ids
tag.endpoint = query_replace({'tags': tag.content.replace(' ','_')}, url_for('.posts'))
# tags = list(tagset)
tags = [t[0] for t in tags]
tags.sort(key=lambda x: (x.category.value, x.content) )
return tags
def parse_args():
args = request.args
tags = (args.get('tags') or '').split(' ')
tags = [t.replace('_',' ') for t in tags] if tags[0] != '' else []
rating = {r.name : r for r in RATING}.get(args.get('rating')) or RATING.safe
matched_ratings = [r for r in RATING if r.value<=rating.value]
# page = int(args.get('page') or 1)
return (tags, matched_ratings)
f_tags, f_rating = parse_args()
posts_query = Post.query
if len(f_tags)>0:
posts_query = posts_query.join(Post.tags).group_by(Post.id).filter(Tag.content.in_(f_tags)).having(func.count(Post.id)==len(f_tags))
posts_query = posts_query.filter(Post.rating.in_(f_rating)).order_by(Post.created) #.offset((page-1)*posts_on_page).limit(posts_on_page)
posts = posts_query.paginate(page, current_app.config.get('POSTS_PER_PAGE'))
tags = tags_prepare(posts.items)
flash(parse_args())
# flash(posts.items)
# flash(tags)
return render_template('index.html', posts=posts.items, tags=tags, pagination=posts, query_replace=query_replace)
@bp.route('/show/<id>')
def post_show(id):
post = Post.query.filter_by(id=id).first()
# flash(post)
tags_count = db.session.query(Tag, func.count(Post.id)).join(Tag.posts).filter(Post.id==id).join(aliased(Post), Tag.posts).group_by(Tag).all()
for tag_count in tags_count:
tag, count = tag_count
tag.count = count
tag.endpoint = query_replace({'tags': tag.content.replace(' ','_')}, url_for('.posts'))
return render_template('post.html', post=post, tags=post.tags)
@bp.route('/upload', methods=['GET', 'POST'])
@login_required
def post_upload():
form = UploadPostForm(request.form)
if request.method == 'POST' and form.validate():
file = request.files.get(form.post_img.name)
file.data = io.BytesIO(file.read())
# tagy
post = Post(file, source=form.sauce.data, rating=RATING[form.rating.data], author=current_user)
with open(post.image_path, "wb") as f:
f.write(file.data.getbuffer())
# file.seek(0)
# file.save(post.image_path)
with Image.open(file.data) as im:
im = im.convert('RGB')
if post.jpeg_path is not None:
im.save(post.jpeg_path, 'JPEG', quality=80)
im.thumbnail([512,512])
im.save(post.thumb_path, 'JPEG', quality=80)
db.session.add(post)
db.session.commit()
flash('Successfully submitted {}'.format(str(post)))
return redirect(url_for('.post_upload'))
return render_template('upload.html', form=form)

@ -78,4 +78,7 @@ class UploadPostForm(CSRFForm):
# Not sure if safe # Not sure if safe
# real_mimetype = Magic(mime=True).from_buffer(file.stream.read()) # real_mimetype = Magic(mime=True).from_buffer(file.stream.read())
if client_mimetype not in ['image/png','image/jpeg']: if client_mimetype not in ['image/png','image/jpeg']:
raise ValidationError('Please select an image file of PNG or JPEG format') raise ValidationError('Please select an image file of PNG or JPEG format')
# class CommentForm(CSRFForm):

@ -152,7 +152,7 @@ class Post(TimestampMixin, db.Model):
@property @property
def image_path(self): def image_path(self):
filename = "{}.{}".format(self.md5, 'jpg' if self.filetype is FILETYPE.jpeg else 'png') filename = "{}.{}".format(self.md5, 'jpg' if self.filetype is FILETYPE.jpeg else 'png')
return os.path.join(current_app.instance_path, 'post', 'img', filename) return os.path.join(current_app.config.get('POST_UPLOADS'), 'img', filename)
@property @property
def jpeg_path(self): def jpeg_path(self):
@ -160,12 +160,12 @@ class Post(TimestampMixin, db.Model):
return None return None
jpeg_filename = "{}.{}".format(self.md5, 'jpg') jpeg_filename = "{}.{}".format(self.md5, 'jpg')
return os.path.join(current_app.instance_path, 'post', 'jpeg', jpeg_filename) return os.path.join(current_app.config.get('POST_UPLOADS'), 'jpeg', jpeg_filename)
@property @property
def thumb_path(self): def thumb_path(self):
jpeg_filename = "{}.{}".format(self.md5, 'jpg') jpeg_filename = "{}.{}".format(self.md5, 'jpg')
return os.path.join(current_app.instance_path, 'post', 'thumb', jpeg_filename) return os.path.join(current_app.config.get('POST_UPLOADS'), 'thumb', jpeg_filename)
@cached_property @cached_property
def image_resolution(self): def image_resolution(self):

@ -17,9 +17,8 @@
<span>YaDc</span> <span>YaDc</span>
</a> </a>
<nav id="main-nav"> <nav id="main-nav">
<a href="{{ url_for('main.posts') }}">Posts</a> <a href="{{ url_for('post.posts') }}">Posts</a>
<!-- <a href="{{ url_for('main.threads') }}">Threads</a> --> <a href="{{ url_for('post.post_upload') }}">Upload</a>
<a href="{{ url_for('main.post_upload') }}">Upload</a>
<div class="user"> <div class="user">
{% if current_user.is_anonymous %} {% if current_user.is_anonymous %}

@ -10,7 +10,7 @@
<div class="posts"> <div class="posts">
{% for post in posts %} {% for post in posts %}
<figure style="{{ post.flex }}"> <figure style="{{ post.flex }}">
<a href="{{ url_for('main.post_show', id=post.id) }}"> <a href="{{ url_for('post.post_show', id=post.id) }}">
<img src="{{ post.url(path=post.image_url, endpoint='thumb') }}" alt=""> <img src="{{ post.url(path=post.image_url, endpoint='thumb') }}" alt="">
</a> </a>
</figure> </figure>
@ -27,7 +27,7 @@
</div> </div>
</figure> --> </figure> -->
</div> </div>
{{ render_pagination('main.posts') }} {{ render_pagination('post.posts') }}
</section> </section>
</div> </div>
{% endblock content %} {% endblock content %}

@ -1,5 +1,5 @@
{% extends 'base.html' %} {% extends 'base.html' %}
{% from '_includes.html' import tags as tags_block %} {% from '_includes.html' import render_tags with context %}
{% block content %} {% block content %}
<div class="important_subwrap"> <div class="important_subwrap">
@ -25,11 +25,10 @@
{% endif %} {% endif %}
</article> </article>
{{ tags_block(tags) }} {{ render_tags() }}
</section> </section>
<section class="post_single"> <section class="post_single">
<div class="image"> <div class="image">
<!-- <img src="/static/pixiv/illust_72206228_20191026_131238.jpg" alt=""> -->
<img src="{{ post.url(path=post.image_url, endpoint='jpeg') }}" alt=""> <img src="{{ post.url(path=post.image_url, endpoint='jpeg') }}" alt="">
</div> </div>
</section> </section>

@ -5,4 +5,11 @@ def sizeof_fmt(num, suffix='B'):
if abs(num) < 1024.0: if abs(num) < 1024.0:
return "%3.1f%s%s" % (num, unit, suffix) return "%3.1f%s%s" % (num, unit, suffix)
num /= 1024.0 num /= 1024.0
return "%.1f%s%s" % (num, 'Yi', suffix) return "%.1f%s%s" % (num, 'Yi', suffix)
from flask import request
from werkzeug.urls import Href
def query_replace(dic, base=''):
args = request.args.to_dict()
return Href(base)(args.update(dic) or args)
Loading…
Cancel
Save