Unverified Commit bfb832db authored by CapsLock's avatar CapsLock

PEP, externalizing settings, port detection, picture auto rotate by reading exif, readme file

parent 7788e273
......@@ -2,3 +2,5 @@
uploads/*
venv
core
settings.py
__pycache__/
# With my ISP
The goal is to create a photo album to show all the cool things you can do
in a DIY ISP.
# How it works
Each album is differentiated by the hostname
# Installation
## Ansible
ansible-playbook ansible.yml --ask-pass --ask-sudo-pass
## Postgresql grants
# su postgres
$ psql template1
# \c avecmonfai
# grant all on pictures to avecmonfai;
# grant all on domain_names to avecmonfai;
# grant all on pictures_domain_names to avecmonfai;
# grant all on pictures_id_seq to avecmonfai;
# grant all on domain_names_id_seq to avecmonfai;
# grant all on pictures_id_seq to avecmonfai;
# grant all on pictures_domain_names_id_seq to avecmonfai;
## settings
# cd /home/avecmonfai/avecmonfai
# cp settings.yml.example setings.yml
## supervisor:
# vi /etc/supervisor/conf.d/avecmonfai.conf
[program:avecmonfai]
directory = /home/avecmonfai/avecmonfai
user = avecmonfai
command = /home/avecmonfai/avecmonfai/venv/bin/python /home/avecmonfai/avecmonfai/start.py --user=avecmonfai --group=avecmonfai --log-level=debug --log-file=/home/avecmonfai/logs/avecmonfai.log
stdout_logfile = /home/avecmonfai/logs/avecmonfai-std.log
stderr_logfile = /home/avecmonfai/logs/avecmonfai-err.log
# supervisorctl reload
# supervisorctl start avecmonfai
## Web server
you may put this behind a reverse proxy which match on your domain.com and *.domain.com
## DNS
you have to configure the zone of your domain.com to resolve *.domain.com to your web server
\ No newline at end of file
- hosts: change_this
remote_user: change_this
vars:
sysuser: 'withmyisp'
dbpassword: 'change_this'
amf_project_path: "/home/{{ sysuser}}/{{sysuser}}"
amf_logs_path: "/home/{{ sysuser}}/logs"
amf_www_path: "/home/{{ sysuser}}/www"
sudo: yes
tasks:
- name: Create user
user: name={{ sysuser }} state=present shell="/bin/false" createhome=yes comment="Avec mon fai user, created by ansible"
- name: install supervisor
apt: pkg=supervisor state=installed
- name: Install python3, virtualenv
apt: pkg="python3,python3-dev,python-virtualenv" state=installed
- name: Install postgresql
apt: pkg="postgresql-9.1,postgresql-server-dev-9.1" state=installed
- name: check postgresql-server is running
service: name="postgresql" state=running enabled=yes
- name: Install python postgresql client
apt: pkg="python3-psycopg2,python-psycopg2" state=installed
- name: mkdir logs folder
file: path={{ amf_logs_path }} owner={{sysuser}} group={{sysuser}} state=directory
- name: mkdir www folder
file: path={{ amf_www_path }} owner={{sysuser}} group={{sysuser}} state=directory
- name: get {{sysuser}} sources
git: repo="https://git.legeox.net/capslock/withmyisp.git" dest={{ amf_project_path }}
sudo_user: "{{ sysuser }}"
- name: create virtualenv
shell: chdir={{ amf_project_path }} virtualenv -p python3 venv
sudo_user: "{{ sysuser }}"
- name: install python requirements
shell: chdir={{ amf_project_path }} executable=/bin/bash export LANG="fr_FR.UTF-8" && source venv/bin/activate && pip install -r requirements.txt
sudo_user: "{{ sysuser }}"
- name: create db user
postgresql_user: name={{sysuser}} password={{dbpassword}}
sudo_user: postgres
- name: create db
postgresql_db: name={{sysuser}} encoding='UTF-8' lc_collate='fr_FR.UTF-8' lc_ctype='fr_FR.UTF-8' template='template0' owner='{{sysuser}}'
sudo_user: postgres
- name: script sql
command: psql -d {{sysuser}} -a -f /home/{{sysuser}}/{{sysuser}}/db.sql
sudo_user: postgres
- name: grants
postgresql_privs: db={{sysuser}} privs=ALL type=table objs=ALL_IN_SCHEMA schema=public role={{sysuser}}
sudo_user: postgres
# Change to match to your domain name
domain_name = 'coin.pan'
# Database settings
db_name = 'avecmonfai'
db_username = 'avecmonfai'
db_password = 'avecmonfai'
# Site title
site_name = 'With My ISP'
# Server configuration
listen_address = '0.0.0.0.0'
listen_port = '8080'
# For development only, you can change those values to True
enable_debug = False
auto_reload_on_change=False
\ No newline at end of file
from bottle import Bottle, route, run, template, request, static_file, redirect
from bottle import Bottle, run, template, request, static_file, redirect
import bottle_pgsql
import bottle
import datetime
from urllib.parse import urlparse
from PIL import Image
import os
domain_name = 'coin.pan'
db_name = 'avecmonfai'
db_username = 'avecmonfai'
db_password = 'avecmonfai'
site_name = 'With My ISP'
# CREATE USER avecmonfai with password 'avecmonfai';
# CREATE DATABASE avecmonfai owner avecmonfai;
# CREATE TABLE pictures(id serial PRIMARY KEY, filename VARCHAR(250) NOT NULL, description VARCHAR(500), created_on TIMESTAMP NOT NULL);
# CREATE TABLE domain_names(id serial PRIMARY KEY, name VARCHAR(800) NOT NULL, related_to integer, created_on TIMESTAMP NOT NULL);
# CREATE TABLE pictures_domain_names(id serial PRIMARY KEY, picture_id integer, domain_name_id integer, created_on TIMESTAMP NOT NULL,
# avecmonfai(# CONSTRAINT pictures_domain_names_picture_id_fkey FOREIGN KEY(picture_id) REFERENCES pictures(id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION,
# avecmonfai(# CONSTRAINT pictures_domain_names_domain_name_id_fkey FOREIGN KEY(domain_name_id) REFERENCES domain_names(id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION)
# grant all on pictures to avecmonfai
# grant all on domain_names to avecmonfai
# grant all on pictures_domain_names to avecmonfai
# grant all on pictures_id_seq to avecmonfai;
# grant all on domain_names_id_seq to avecmonfai;
# grant all on pictures_id_seq to avecmonfai;
# grant all on pictures_domain_names_id_seq to avecmonfai;
# grant all on domain_names_related_to_seq to avecmonfai;
import settings
PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))
app = Bottle()
bottle.debug(True)
bottle.debug(settings.enable_debug)
plugin = bottle_pgsql.Plugin(
'dbname=%s user=%s password=%s' % (db_name, db_username, db_password))
'dbname=%s user=%s password=%s' % (settings.db_name,
settings.db_username,
settings.db_password))
app.install(plugin)
......@@ -43,12 +24,21 @@ def get_host_name():
if url_parse is not None:
result = url_parse.hostname
result = result.replace(".%s" % domain_name, "")
if result == domain_name:
result = result.replace(".%s" % settings.domain_name, "")
if result == settings.domain_name:
result = ''
return result
def get_port():
url_parse = urlparse(request.url)
if url_parse.port is not None:
port = url_parse.port
else:
port = 80
return port
def get_scheme():
url_parse = urlparse(request.url)
return url_parse.scheme
......@@ -56,13 +46,14 @@ def get_scheme():
def get_root_url():
url_parse = urlparse(request.url)
return "%s://%s:%s" % (url_parse.scheme, domain_name, url_parse.port)
return "%s://%s:%s" % (url_parse.scheme, settings.domain_name, get_port())
def get_alias_url(alias):
url_parse = urlparse(request.url)
return "%s://%s.%s:%s" % (
url_parse.scheme, alias, domain_name, url_parse.port)
return "%s://%s.%s:%s" % (url_parse.scheme,
alias,
settings.domain_name, get_port())
def get_base_url():
......@@ -99,29 +90,29 @@ def default(db):
else:
squery = request.params['q']
db.execute('select distinct on (name) *'
' from domain_names dn where name like %s'
' and name is not null and name <>\'\' ',
db.execute("select distinct on (name) *"
" from domain_names dn where name like %s"
" and name is not null and name <> '' ",
(('%%%s%%' % squery),))
else:
db.execute('select * from domain_names dn'
' where name is not null and name <>\'\' ')
db.execute("select * from domain_names dn"
" where name is not null and name <> '' ")
domain_names = db.fetchall()
else:
db.execute(
'select p.* from pictures p, pictures_domain_names pdn,'
' domain_names dn where p.id = pdn.picture_id'
' and pdn.domain_name_id = dn.id'
' and dn.name = %s', (get_host_name(),))
"select p.* from pictures p, pictures_domain_names pdn,"
" domain_names dn where p.id = pdn.picture_id"
" and pdn.domain_name_id = dn.id"
" and dn.name = %s", (get_host_name(),))
pictures = db.fetchall()
db.execute('select * from domain_names where id in('
' select related_to from domain_names where name = %s'
' )'
' union all'
' select * from domain_names where related_to in('
' select id from domain_names where name = %s'
' );', (get_host_name(), get_host_name(),))
db.execute("select * from domain_names where id in("
" select related_to from domain_names where name = %s"
" )"
" union all"
" select * from domain_names where related_to in("
" select id from domain_names where name = %s"
" );", (get_host_name(), get_host_name(),))
aliases = db.fetchall()
current_hostname = get_host_name()
......@@ -130,14 +121,39 @@ def default(db):
domain_names=domain_names,
current_hostname=current_hostname,
base_url=get_alias_url('%s'),
domain_name=domain_name,
domain_name=settings.domain_name,
display_new_links=get_host_name() != '',
scheme=get_scheme(),
aliases=aliases,
site_name=site_name,
site_name=settings.site_name,
status=status)
def autorotate(path):
""" This function autorotates a picture """
image = Image.open(path)
exif = image._getexif()
if not exif:
return False
orientation_key = 274 # cf ExifTags
if orientation_key in exif:
orientation = exif[orientation_key]
rotate_values = {
3: 180,
6: 270,
8: 90
}
if orientation in rotate_values:
# Rotate and save the picture
image = image.rotate(rotate_values[orientation])
image.save(path, quality=100)
return True
return False
# upload new pictures
@app.route('/new', method='POST')
def do_upload(db):
......@@ -172,7 +188,8 @@ def do_upload(db):
or not os.path.isdir(temp_thumb_folder)):
os.makedirs(temp_thumb_folder)
image_name = '%s%s' % (datetime.datetime.now().strftime('%Y%m%d%H%M%s%f'), ext)
image_name = '%s%s' % (datetime.datetime.now().strftime('%Y%m%d%H%M%s%f'),
ext)
image_path = os.path.join(dest_folder, image_name)
thumb_path = os.path.join(dest_thumb_folder, image_name)
......@@ -183,6 +200,7 @@ def do_upload(db):
upload.save(temp_image)
try:
autorotate(temp_image)
img = Image.open(temp_image)
img.thumbnail((400, 400), Image.ANTIALIAS)
img.save(temp_thumb)
......@@ -199,7 +217,8 @@ def do_upload(db):
os.rename(temp_thumb, thumb_path)
db.execute(
"INSERT INTO pictures(filename, description, created_on) values (%s, %s, %s)",
"INSERT INTO pictures(filename, description,"
" created_on) values (%s, %s, %s)",
(image_name, description, datetime.datetime.now()))
db.execute("select lastval()")
......@@ -208,8 +227,6 @@ def do_upload(db):
db.execute("select * from domain_names where name=%s", (domain, ))
domain_entity = db.fetchone()
domain_id = None
if not domain_entity:
db.execute(
"insert into domain_names (name, created_on) values (%s, %s)",
......@@ -221,7 +238,8 @@ def do_upload(db):
db.connection.commit()
db.execute(
"INSERT INTO pictures_domain_names(picture_id, domain_name_id, created_on) values (%s, %s, %s)",
"INSERT INTO pictures_domain_names(picture_id,"
" domain_name_id, created_on) values (%s, %s, %s)",
(picture_id, domain_id, datetime.datetime.now()))
return redirect('/?status=%s' % status)
......@@ -273,6 +291,7 @@ def send_static(filename):
if __name__ == "__main__":
run(app, host='localhost', port=8080)
#, reloader=True)
run(app,
host=settings.listen_address,
port=settings.listen_port,
reloader=settings.auto_reload_on_change)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment