From d2fc9d6349d2d0ac154101e4d93855f382ca7595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Thu, 18 May 2017 08:38:00 +0200 Subject: [PATCH] =?UTF-8?q?First=20commit=20-=20databasbaserat=20system=20?= =?UTF-8?q?snarare=20=C3=A4n=20filer?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kvar att göra: Hantera foton Putsa på interface --- .gitignore | 5 ++ app/__init__.py | 12 +++ app/forms.py | 14 ++++ app/models.py | 99 ++++++++++++++++++++++ app/photo.py | 24 ++++++ app/static/favicon.ico | Bin 0 -> 1150 bytes app/templates/admin.html | 153 ++++++++++++++++++++++++++++++++++ app/templates/admin_page.html | 76 +++++++++++++++++ app/templates/base.html | 45 ++++++++++ app/templates/page.html | 120 ++++++++++++++++++++++++++ app/views.py | 88 +++++++++++++++++++ db_create.py | 35 ++++++++ run.py | 3 + 13 files changed, 674 insertions(+) create mode 100644 .gitignore create mode 100644 app/__init__.py create mode 100644 app/forms.py create mode 100644 app/models.py create mode 100644 app/photo.py create mode 100644 app/static/favicon.ico create mode 100644 app/templates/admin.html create mode 100644 app/templates/admin_page.html create mode 100644 app/templates/base.html create mode 100644 app/templates/page.html create mode 100644 app/views.py create mode 100755 db_create.py create mode 100755 run.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..443f0ff --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.DS_Store +__pycache__/ +*.jpg +*.db +config.py diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..2b61eba --- /dev/null +++ b/app/__init__.py @@ -0,0 +1,12 @@ +from flask import Flask +from flask_bootstrap import Bootstrap +from flaskext.markdown import Markdown +from flask_sqlalchemy import SQLAlchemy + +app = Flask(__name__) +app.config.from_object('config') +Bootstrap(app) +Markdown(app) +db = SQLAlchemy(app) + +from . import views, models diff --git a/app/forms.py b/app/forms.py new file mode 100644 index 0000000..87c1e3a --- /dev/null +++ b/app/forms.py @@ -0,0 +1,14 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, BooleanField, TextAreaField, SelectField, SelectMultipleField, SubmitField +from wtforms import widgets +from wtforms.validators import DataRequired + +class PageForm(FlaskForm): + + name = StringField('namn', validators=[DataRequired()]) + title = StringField('Title', validators=[DataRequired()]) + description = TextAreaField('Beskrivning') + endpoint = BooleanField('Produkt') + thumbnail = SelectField('Bild') + photos = SelectMultipleField('Galleri', option_widget=widgets.CheckboxInput(), widget=widgets.ListWidget(prefix_label=False)) + submit = SubmitField('Ok') diff --git a/app/models.py b/app/models.py new file mode 100644 index 0000000..52985aa --- /dev/null +++ b/app/models.py @@ -0,0 +1,99 @@ +from . import db +from flask import url_for +import random +from sqlalchemy import event + + +photos = db.Table('photos', + db.Column('page_id', db.Integer, db.ForeignKey('page.id')), + db.Column('photo_id', db.Integer, db.ForeignKey('photo.id')) + ) + +thumbnails = db.Table('thumbnails', + db.Column('page_id', db.Integer, db.ForeignKey('page.id')), + db.Column('photo_id', db.Integer, db.ForeignKey('photo.id')) + ) + + +class Page(db.Model): + __tablename__ = 'page' + + id = db.Column(db.Integer, primary_key=True) + + parent_id = db.Column(db.Integer, db.ForeignKey('page.id')) + children = db.relationship("Page", backref=db.backref('parent', remote_side=[id])) + + name = db.Column(db.String(64), index=True, default="") + permalink = db.Column(db.String(256), index=True, default="") + + title = db.Column(db.String(120), index=True, default="") + description = db.Column(db.Text(), index=True, default="") + + thumbnail = db.relationship('Photo', secondary=thumbnails, uselist=False) + + photos = db.relationship('Photo', secondary=photos) + + endpoint = db.Column(db.Boolean) + + + def update_permalink(self, name=None, parent_id=None): + parent_id = parent_id or self.parent_id + name = name or self.name + if self.id == 1: + self.permalink = "" + return + url = "" + if parent_id: + url = self.parent.permalink + url = "/".join(filter(None,[url, name])) + self.permalink = url + print("Set permalink of " + repr(name) + " to " + url) + + @property + def all_photos(self): + if self.photos: + return self.photos + else: + l = [photo for c in self.children for photo in c.all_photos] + random.shuffle(l) + if len(l) > 25: + del l[25:] + return l + @property + def breadcrumbs(self): + if self.parent: + l = list(self.parent.breadcrumbs) + else: + l = list() + l.append(self) + return l +@event.listens_for(Page.parent_id, 'set') +def parent_set(target, value, old_value, initiator): + if value: + target.update_permalink(parent_id=value) +@event.listens_for(Page.name, 'set') +def name_set(target, value, old_value, initiator): + if value: + target.update_permalink(name=value) + +class Photo(db.Model): + __tablename__ = 'photo' + + id = db.Column(db.Integer, primary_key=True) + link_id = db.Column(db.Integer, db.ForeignKey('page.id')) + link = db.relationship("Page", foreign_keys=[link_id], uselist=False) + alt = db.Column(db.String(120), index=True) + + @property + def url(self): + return url_for('photo', id=self.id) + @property + def thumbnail(self): + return url_for('thumbnail', id=self.id) + @property + def slide(self): + return url_for('slide', id=self.id) + + @property + def page(self): + return url_for('page', permalink = self.link.permalink) diff --git a/app/photo.py b/app/photo.py new file mode 100644 index 0000000..055a26c --- /dev/null +++ b/app/photo.py @@ -0,0 +1,24 @@ +from PIL import Image, ImageOps +import os + +def genimg(imgin, imgout, size): + img = Image.open(imgin) + img.thumbnail(size) + hpad = int((size[0]-img.size[0])/2) + vpad = int((size[1]-img.size[1])/2) + thumb = Image.new(mode='RGBA', size=size, color=(255,255,255,0)) + thumb.paste(img, (hpad, vpad)) + thumb.save(imgout) + +#thumb (171,180) +#slides (550,400) + +def genboth(num): + fn = '{}.jpg'.format(num) + imgin = os.path.join('app', 'photos', fn) + thumb = os.path.join('app', 'photos', 'thumbs', fn) + slide = os.path.join('app', 'photos', 'slides', fn) + + genimg(imgin, thumb, (171,180)) + genimg(imgin, slide, (550,400)) + diff --git a/app/static/favicon.ico b/app/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..332b6447752fd61a7cb9eb0ebc08b17a88c61667 GIT binary patch literal 1150 zcmc&wK@NgI5G#fUaM3Fq{gqdL;ZuByPcc42iLTv1lM;49HXeiwEuD4-7HD{P9rzq@ zZh-@UBa0H1Nhbj8RbCCyr^<}kl@(fRlX}MaW^gum#`!<;d1uWxl)NP^`WJbHzwFlx zVYJhA_lgVM7jgGyzTZ`z-(xvB&+wVc?)t6dEotlIq{u6be37o4F!Duu&h=x|bv<2x X&kcBc-GPzy%6PK6&U#{x^<;ekT{uMB literal 0 HcmV?d00001 diff --git a/app/templates/admin.html b/app/templates/admin.html new file mode 100644 index 0000000..2a463e3 --- /dev/null +++ b/app/templates/admin.html @@ -0,0 +1,153 @@ +{% extends "base.html" %} +{% block navbar %} +{% endblock %} +{% block styles %} +{{ super() }} + +{% endblock %} + +{% macro delete_button(type, title, id) -%} + +{%- endmacro %} + +{% block content %} + + + + +
+
+
+
+

Sidor

+
+
+
+
+ {% for page in pages recursive %} +
+ /{{ page.permalink }} - {{ page.title }} + + {% if page.endpoint %} + {% else %} + + {% endif %} + {% if page.id != 1 %} + {% if not page.children %} + {{ delete_button('page', page.title, page.id) }} + {% endif %} + {% endif %} +
+ {% if page.children %} +
+ {{ loop(page.children) }} +
+ {% endif %} + {% endfor %} +
+
+
+
+
+ +
+
+
+

Foton

+
+
+
+
+
+
+ +
+ +
+
+
+ {% for photo in photos %} +
+
+ + +
+
+ {% endfor %} +
+
+
+{% endblock %} + + +{% block scripts %} +{{super()}} + +{% endblock %} diff --git a/app/templates/admin_page.html b/app/templates/admin_page.html new file mode 100644 index 0000000..195f15e --- /dev/null +++ b/app/templates/admin_page.html @@ -0,0 +1,76 @@ +{% extends "base.html" %} +{% import "bootstrap/wtf.html" as wtf %} +{% block navbar %} +{% endblock %} + +{% block content %} +
+
+
+
+
+ + {{ wtf.form_field(form.name, form_type="horizontal") }} + + {{ wtf.form_field(form.title, form_type="horizontal") }} + +
+ +
+ {{ form.description(rows=20, class_="form-control") }} +
+
+ + {{ wtf.form_field(form.endpoint, form_type="horizontal") }} + +
+ +
+ {{ form.thumbnail(class_="form-control") }} +
+
+ +
+
+ + + + {{ wtf.form_field(form.submit, form_type="horizontal") }} + +
+
+
+
+
+
+ {{ page.description | markdown }} +
+
+
+
+
+{% endblock %} + +{% block scripts %} +{{super()}} + +{% endblock %} diff --git a/app/templates/base.html b/app/templates/base.html new file mode 100644 index 0000000..d29adbb --- /dev/null +++ b/app/templates/base.html @@ -0,0 +1,45 @@ +{% extends "bootstrap/base.html" %} +{% block title %} -- Design by Lovén -- {% endblock %} +{% block styles %} +{{super()}} + +{% endblock %} +{% block navbar %} + +{% endblock %} + diff --git a/app/templates/page.html b/app/templates/page.html new file mode 100644 index 0000000..e2b51ce --- /dev/null +++ b/app/templates/page.html @@ -0,0 +1,120 @@ +{% extends "base.html" %} +{% block content %} + +
+ +
+ + +
+
+
+

{{ page.title }}

+ {{ page.description | markdown }} +
+ +
+
+
+ + {% if page.endpoint %} +
+
+
+
    + {% for p in page.photos %} +
  • + + {{ p.alt }} + +
  • + {% endfor %} +
+
+
+
+ {% else %} +
+ {% for c in page.children %} +
+
+ + +
+
+ {% endfor %} +
+ {% endif %} + + +
+ + + +{% endblock %} + +{% block scripts %} +{{super()}} + +{% endblock %} diff --git a/app/views.py b/app/views.py new file mode 100644 index 0000000..9c58081 --- /dev/null +++ b/app/views.py @@ -0,0 +1,88 @@ +from flask import render_template, send_from_directory, redirect, url_for, request, render_template_string +from . import app, db +from .models import Page, Photo +from .forms import PageForm + + +@app.route('/') +@app.route('/') +def page(permalink=""): + permalink = permalink.strip("/") + print("asked for:" + permalink) + + page = Page.query.filter_by(permalink=permalink).first_or_404() + + return render_template("page.html", page = page) + +@app.route('/photo/') +def photo(id): + return send_from_directory('photos', '{}.jpg'.format(id)) +@app.route('/thumbnail/') +def thumbnail(id): + return send_from_directory('photos/thumbs', '{}.jpg'.format(id)) +@app.route('/slide/') +def slide(id): + return send_from_directory('photos/slides', '{}.jpg'.format(id)) + +@app.route('/favicon.ico') +def favicon(): + return send_from_directory('static', 'favicon.ico') + + +@app.route('/admin') +def admin(): + pages = [Page.query.first()] + photos = Photo.query.all() + return render_template("admin.html", pages=pages, photos=photos) + +@app.route('/admin/page/', methods=['GET', 'POST']) +def admin_page(id): + page = Page.query.filter_by(id=id).first_or_404() + form = PageForm() + photos = Photo.query.all() + form.photos.choices = [('{}'.format(p.id), ''.format(p.id)) for p in photos] + form.thumbnail.choices = [('{}'.format(p.id), p.alt) for p in photos] + + if form.validate_on_submit(): + page.name = form.name.data + page.title = form.title.data + page.description = form.description.data + page.endpoint = form.endpoint.data + page.thumbnail = Photo.query.filter_by(id=form.thumbnail.data).first() + page.photos = [Photo.query.filter_by(id=int(p)).first() for p in form.photos.data] + + db.session.add(page) + db.session.commit() + return redirect(url_for('admin')) + + else: + form.name.data = page.name + form.title.data = page.title + form.description.data = page.description + form.endpoint.data = page.endpoint + print(page.thumbnail) + form.thumbnail.data = str(page.thumbnail.id) if page.thumbnail else '1' + form.photos.data = [str(p.id) for p in page.photos] + return render_template('admin_page.html', page=page, form=form) + +@app.route('/admin/newpage/') +def admin_newpage(parent): + parent = Page.query.filter_by(id=parent).first_or_404() + new = Page(name="child_{}".format(len(parent.children)+1), title="Ny sida", endpoint=True, parent=parent, parent_id=parent.id) + + db.session.add(new) + + db.session.commit() + return redirect(url_for('admin')) + +@app.route('/admin/delpage/') +def admin_delpage(id): + page = Page.query.filter_by(id=id).first_or_404() + root = Page.query.filter_by(id=1).first() + db.session.delete(page) + db.session.commit() + return redirect(url_for('admin')) + +@app.route('/admin/markdown', methods=['POST']) +def markdown(): + return render_template_string('{{ md | markdown }}', md=request.form['md']) diff --git a/db_create.py b/db_create.py new file mode 100755 index 0000000..88cec9e --- /dev/null +++ b/db_create.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +from config import SQLALCHEMY_DATABASE_URI +from app import db, models + +db.create_all() + +ph1 = models.Photo(alt="Kuvertbody superman") +ph2 = models.Photo(alt="Kuvertbody linjer") +ph3 = models.Photo(alt="Kuvertbody Hedvig") + +index = models.Page(name="", title="Design by Lovén", description="Välkommen till *Design* by **Lovén**") + +kuvertbody = models.Page(name="kuvertbody", title="Kuvertbody", description="An praktisk body som man kan dra av neråt", thumbnail=ph1) +linjer = models.Page(name="linjer", title="Kuvertbody - Linjer", description="Raka sömmar på framsidan", photos=[ph2, ph3], thumbnail=ph2, endpoint = True) +superman = models.Page(name="superman", title="Kuvertbody - Superman", description="Alla barn är superhjältar", photos=[ph1], thumbnail=ph1, endpoint = True) + +index.children = [kuvertbody] +kuvertbody.children.append(linjer) +kuvertbody.children.append(superman) + +ph1.link = superman +ph2.link = linjer +ph3.link = linjer + + +db.session.add(ph1) +db.session.add(ph2) +db.session.add(ph3) +db.session.add(index) +db.session.add(kuvertbody) +db.session.add(linjer) +db.session.add(superman) +db.session.commit() + + diff --git a/run.py b/run.py new file mode 100755 index 0000000..612831a --- /dev/null +++ b/run.py @@ -0,0 +1,3 @@ +#!/usr/bin/env python3 +from app import app +app.run(debug=True)