1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-11-09 19:52:16 +00:00

Wrapping all request handling in a database transaction

This commit is contained in:
spl0k 2018-02-14 22:48:44 +01:00
parent e3ccf0809f
commit 43b197a95e
14 changed files with 112 additions and 168 deletions

View File

@ -25,7 +25,7 @@ import uuid
from flask import request
from flask import Blueprint
from pony.orm import db_session, ObjectNotFound
from pony.orm import ObjectNotFound
from ..managers.user import UserManager
from ..py23 import dict
@ -83,11 +83,10 @@ def get_client_prefs():
return request.formatter.error(10, 'Missing required parameter')
client = request.values.get('c')
with db_session:
try:
ClientPrefs[request.user.id, client]
except ObjectNotFound:
ClientPrefs(user = User[request.user.id], client_name = client)
try:
ClientPrefs[request.user, client]
except ObjectNotFound:
ClientPrefs(user = request.user, client_name = client)
request.client = client

View File

@ -23,7 +23,7 @@ import uuid
from datetime import timedelta
from flask import request
from pony.orm import db_session, select, desc, avg, max, min, count
from pony.orm import select, desc, avg, max, min, count
from ..db import Folder, Artist, Album, Track, RatingFolder, StarredFolder, StarredArtist, StarredAlbum, StarredTrack, User
from ..db import now
@ -51,16 +51,14 @@ def rand_songs():
if genre:
query = query.filter(lambda t: t.genre == genre)
if fid:
with db_session:
if not Folder.exists(id = fid, root = True):
return request.formatter.error(70, 'Unknown folder')
if not Folder.exists(id = fid, root = True):
return request.formatter.error(70, 'Unknown folder')
query = query.filter(lambda t: t.root_folder.id == fid)
with db_session:
return request.formatter('randomSongs', dict(
song = [ t.as_subsonic_child(request.user, request.client) for t in query.random(size) ]
))
return request.formatter('randomSongs', dict(
song = [ t.as_subsonic_child(request.user, request.client) for t in query.random(size) ]
))
@api.route('/getAlbumList.view', methods = [ 'GET', 'POST' ])
def album_list():
@ -75,10 +73,9 @@ def album_list():
query = select(t.folder for t in Track)
if ltype == 'random':
with db_session:
return request.formatter('albumList', dict(
album = [ a.as_subsonic_child(request.user) for a in query.random(size) ]
))
return request.formatter('albumList', dict(
album = [ a.as_subsonic_child(request.user) for a in query.random(size) ]
))
elif ltype == 'newest':
query = query.order_by(desc(Folder.created))
elif ltype == 'highest':
@ -96,10 +93,9 @@ def album_list():
else:
return request.formatter.error(0, 'Unknown search type')
with db_session:
return request.formatter('albumList', dict(
album = [ f.as_subsonic_child(request.user) for f in query.limit(size, offset) ]
))
return request.formatter('albumList', dict(
album = [ f.as_subsonic_child(request.user) for f in query.limit(size, offset) ]
))
@api.route('/getAlbumList2.view', methods = [ 'GET', 'POST' ])
def album_list_id3():
@ -114,10 +110,9 @@ def album_list_id3():
query = Album.select()
if ltype == 'random':
with db_session:
return request.formatter('albumList2', dict(
album = [ a.as_subsonic_album(request.user) for a in query.random(size) ]
))
return request.formatter('albumList2', dict(
album = [ a.as_subsonic_album(request.user) for a in query.random(size) ]
))
elif ltype == 'newest':
query = query.order_by(lambda a: desc(min(a.tracks.created)))
elif ltype == 'frequent':
@ -133,13 +128,11 @@ def album_list_id3():
else:
return request.formatter.error(0, 'Unknown search type')
with db_session:
return request.formatter('albumList2', dict(
album = [ f.as_subsonic_album(request.user) for f in query.limit(size, offset) ]
))
return request.formatter('albumList2', dict(
album = [ f.as_subsonic_album(request.user) for f in query.limit(size, offset) ]
))
@api.route('/getNowPlaying.view', methods = [ 'GET', 'POST' ])
@db_session
def now_playing():
query = User.select(lambda u: u.last_play is not None and u.last_play_date + timedelta(minutes = 3) > now())
@ -151,7 +144,6 @@ def now_playing():
))
@api.route('/getStarred.view', methods = [ 'GET', 'POST' ])
@db_session
def get_starred():
folders = select(s.starred for s in StarredFolder if s.user.id == request.user.id)
@ -162,7 +154,6 @@ def get_starred():
))
@api.route('/getStarred2.view', methods = [ 'GET', 'POST' ])
@db_session
def get_starred_id3():
return request.formatter('starred2', dict(
artist = [ sa.as_subsonic_artist(request.user) for sa in select(s.starred for s in StarredArtist if s.user.id == request.user.id) ],

View File

@ -22,7 +22,7 @@ import time
import uuid
from flask import current_app, request
from pony.orm import db_session, delete
from pony.orm import delete
from pony.orm import ObjectNotFound
from ..db import Track, Album, Artist, Folder, User
@ -33,7 +33,6 @@ from ..py23 import dict
from . import api, get_entity
@db_session
def try_star(cls, starred_cls, eid):
""" Stars an entity
@ -52,15 +51,14 @@ def try_star(cls, starred_cls, eid):
return dict(code = 70, message = 'Unknown {} id {}'.format(cls.__name__, eid))
try:
starred_cls[request.user.id, uid]
starred_cls[request.user, uid]
return dict(code = 0, message = '{} {} already starred'.format(cls.__name__, eid))
except ObjectNotFound:
pass
starred_cls(user = User[request.user.id], starred = e)
starred_cls(user = request.user, starred = e)
return None
@db_session
def try_unstar(starred_cls, eid):
""" Unstars an entity
@ -153,31 +151,29 @@ def rate():
if not 0 <= rating <= 5:
return request.formatter.error(0, 'rating must be between 0 and 5 (inclusive)')
with db_session:
if rating == 0:
delete(r for r in RatingTrack if r.user.id == request.user.id and r.rated.id == uid)
delete(r for r in RatingFolder if r.user.id == request.user.id and r.rated.id == uid)
else:
if rating == 0:
delete(r for r in RatingTrack if r.user.id == request.user.id and r.rated.id == uid)
delete(r for r in RatingFolder if r.user.id == request.user.id and r.rated.id == uid)
else:
try:
rated = Track[uid]
rating_cls = RatingTrack
except ObjectNotFound:
try:
rated = Track[uid]
rating_cls = RatingTrack
rated = Folder[uid]
rating_cls = RatingFolder
except ObjectNotFound:
try:
rated = Folder[uid]
rating_cls = RatingFolder
except ObjectNotFound:
return request.formatter.error(70, 'Unknown id')
return request.formatter.error(70, 'Unknown id')
try:
rating_info = rating_cls[request.user.id, uid]
rating_info.rating = rating
except ObjectNotFound:
rating_cls(user = User[request.user.id], rated = rated, rating = rating)
try:
rating_info = rating_cls[request.user, uid]
rating_info.rating = rating
except ObjectNotFound:
rating_cls(user = request.user, rated = rated, rating = rating)
return request.formatter.empty
@api.route('/scrobble.view', methods = [ 'GET', 'POST' ])
@db_session
def scrobble():
status, res = get_entity(Track)
if not status:
@ -193,7 +189,7 @@ def scrobble():
else:
t = int(time.time())
lfm = LastFm(current_app.config['LASTFM'], User[request.user.id], current_app.logger)
lfm = LastFm(current_app.config['LASTFM'], request.user, current_app.logger)
if submission in (None, '', True, 'true', 'True', 1, '1'):
lfm.scrobble(res, t)

View File

@ -22,7 +22,6 @@ import string
import uuid
from flask import request
from pony.orm import db_session
from pony.orm import ObjectNotFound
from ..db import Folder, Artist, Album, Track
@ -31,7 +30,6 @@ from ..py23 import dict
from . import api, get_entity
@api.route('/getMusicFolders.view', methods = [ 'GET', 'POST' ])
@db_session
def list_folders():
return request.formatter('musicFolders', dict(
musicFolder = [ dict(
@ -41,7 +39,6 @@ def list_folders():
))
@api.route('/getIndexes.view', methods = [ 'GET', 'POST' ])
@db_session
def list_indexes():
musicFolderId = request.values.get('musicFolderId')
ifModifiedSince = request.values.get('ifModifiedSince')
@ -102,7 +99,6 @@ def list_indexes():
))
@api.route('/getMusicDirectory.view', methods = [ 'GET', 'POST' ])
@db_session
def show_directory():
status, res = get_entity(Folder)
if not status:
@ -119,7 +115,6 @@ def show_directory():
return request.formatter('directory', directory)
@api.route('/getArtists.view', methods = [ 'GET', 'POST' ])
@db_session
def list_artists():
# According to the API page, there are no parameters?
indexes = dict()
@ -143,7 +138,6 @@ def list_artists():
))
@api.route('/getArtist.view', methods = [ 'GET', 'POST' ])
@db_session
def artist_info():
status, res = get_entity(Artist)
if not status:
@ -157,7 +151,6 @@ def artist_info():
return request.formatter('artist', info)
@api.route('/getAlbum.view', methods = [ 'GET', 'POST' ])
@db_session
def album_info():
status, res = get_entity(Album)
if not status:
@ -169,7 +162,6 @@ def album_info():
return request.formatter('album', info)
@api.route('/getSong.view', methods = [ 'GET', 'POST' ])
@db_session
def track_info():
status, res = get_entity(Track)
if not status:

View File

@ -19,7 +19,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from flask import request
from pony.orm import db_session
from ..db import ChatMessage, User
from ..py23 import dict
@ -33,12 +32,11 @@ def get_chat():
except ValueError:
return request.formatter.error(0, 'Invalid parameter')
with db_session:
query = ChatMessage.select().order_by(ChatMessage.time)
if since:
query = query.filter(lambda m: m.time > since)
query = ChatMessage.select().order_by(ChatMessage.time)
if since:
query = query.filter(lambda m: m.time > since)
return request.formatter('chatMessages', dict(chatMessage = [ msg.responsize() for msg in query ] ))
return request.formatter('chatMessages', dict(chatMessage = [ msg.responsize() for msg in query ] ))
@api.route('/addChatMessage.view', methods = [ 'GET', 'POST' ])
def add_chat_message():
@ -46,8 +44,7 @@ def add_chat_message():
if not msg:
return request.formatter.error(10, 'Missing message')
with db_session:
ChatMessage(user = User[request.user.id], message = msg)
ChatMessage(user = request.user, message = msg)
return request.formatter.empty

View File

@ -27,7 +27,6 @@ import subprocess
from flask import request, Response, send_file
from flask import current_app
from PIL import Image
from pony.orm import db_session
from xml.etree import ElementTree
from .. import scanner
@ -47,7 +46,6 @@ def prepare_transcoding_cmdline(base_cmdline, input_file, input_format, output_f
return ret
@api.route('/stream.view', methods = [ 'GET', 'POST' ])
@db_session
def stream_media():
status, res = get_entity(Track)
if not status:
@ -127,7 +125,7 @@ def stream_media():
res.play_count = res.play_count + 1
res.last_play = now()
user = User[request.user.id]
user = request.user
user.last_play = res
user.last_play_date = now()
@ -135,8 +133,7 @@ def stream_media():
@api.route('/download.view', methods = [ 'GET', 'POST' ])
def download_media():
with db_session:
status, res = get_entity(Track)
status, res = get_entity(Track)
if not status:
return res
@ -144,8 +141,7 @@ def download_media():
@api.route('/getCoverArt.view', methods = [ 'GET', 'POST' ])
def cover_art():
with db_session:
status, res = get_entity(Folder)
status, res = get_entity(Folder)
if not status:
return res
@ -184,26 +180,25 @@ def lyrics():
if not title:
return request.formatter.error(10, 'Missing title parameter')
with db_session:
query = Track.select(lambda t: title in t.title and artist in t.artist.name)
for track in query:
lyrics_path = os.path.splitext(track.path)[0] + '.txt'
if os.path.exists(lyrics_path):
current_app.logger.debug('Found lyrics file: ' + lyrics_path)
query = Track.select(lambda t: title in t.title and artist in t.artist.name)
for track in query:
lyrics_path = os.path.splitext(track.path)[0] + '.txt'
if os.path.exists(lyrics_path):
current_app.logger.debug('Found lyrics file: ' + lyrics_path)
try:
lyrics = read_file_as_unicode(lyrics_path)
except UnicodeError:
# Lyrics file couldn't be decoded. Rather than displaying an error, try with the potential next files or
# return no lyrics. Log it anyway.
current_app.logger.warning('Unsupported encoding for lyrics file ' + lyrics_path)
continue
try:
lyrics = read_file_as_unicode(lyrics_path)
except UnicodeError:
# Lyrics file couldn't be decoded. Rather than displaying an error, try with the potential next files or
# return no lyrics. Log it anyway.
current_app.logger.warning('Unsupported encoding for lyrics file ' + lyrics_path)
continue
return request.formatter('lyrics', dict(
artist = track.album.artist.name,
title = track.title,
_value_ = lyrics
))
return request.formatter('lyrics', dict(
artist = track.album.artist.name,
title = track.title,
_value_ = lyrics
))
try:
r = requests.get("http://api.chartlyrics.com/apiv1.asmx/SearchLyricDirect",

View File

@ -21,7 +21,7 @@
import uuid
from flask import request
from pony.orm import db_session, rollback
from pony.orm import rollback
from pony.orm import ObjectNotFound
from ..db import Playlist, User, Track
@ -38,18 +38,15 @@ def list_playlists():
if not request.user.admin:
return request.formatter.error(50, 'Restricted to admins')
with db_session:
user = User.get(name = username)
user = User.get(name = username)
if user is None:
return request.formatter.error(70, 'No such user')
query = Playlist.select(lambda p: p.user.name == username).order_by(Playlist.name)
with db_session:
return request.formatter('playlists', dict(playlist = [ p.as_subsonic_playlist(request.user) for p in query ] ))
return request.formatter('playlists', dict(playlist = [ p.as_subsonic_playlist(request.user) for p in query ] ))
@api.route('/getPlaylist.view', methods = [ 'GET', 'POST' ])
@db_session
def show_playlist():
status, res = get_entity(Playlist)
if not status:
@ -63,7 +60,6 @@ def show_playlist():
return request.formatter('playlist', info)
@api.route('/createPlaylist.view', methods = [ 'GET', 'POST' ])
@db_session
def create_playlist():
playlist_id, name = map(request.values.get, [ 'playlistId', 'name' ])
# songId actually doesn't seem to be required
@ -86,7 +82,7 @@ def create_playlist():
if name:
playlist.name = name
elif name:
playlist = Playlist(user = User[request.user.id], name = name)
playlist = Playlist(user = request.user, name = name)
else:
return request.formatter.error(10, 'Missing playlist id or name')
@ -105,7 +101,6 @@ def create_playlist():
return request.formatter.empty
@api.route('/deletePlaylist.view', methods = [ 'GET', 'POST' ])
@db_session
def delete_playlist():
status, res = get_entity(Playlist)
if not status:
@ -118,7 +113,6 @@ def delete_playlist():
return request.formatter.empty
@api.route('/updatePlaylist.view', methods = [ 'GET', 'POST' ])
@db_session
def update_playlist():
status, res = get_entity(Playlist, 'playlistId')
if not status:

View File

@ -21,7 +21,7 @@
from collections import OrderedDict
from datetime import datetime
from flask import request
from pony.orm import db_session, select
from pony.orm import select
from ..db import Folder, Track, Artist, Album
from ..py23 import dict
@ -48,28 +48,26 @@ def old_search():
elif anyf:
folders = Folder.select(lambda f: anyf in f.name and f.created > min_date)
tracks = Track.select(lambda t: anyf in t.title and t.created > min_date)
with db_session:
res = folders[offset : offset + count]
fcount = folders.count()
if offset + count > fcount:
toff = max(0, offset - fcount)
tend = offset + count - fcount
res += tracks[toff : tend]
res = folders[offset : offset + count]
fcount = folders.count()
if offset + count > fcount:
toff = max(0, offset - fcount)
tend = offset + count - fcount
res += tracks[toff : tend]
return request.formatter('searchResult', dict(
totalHits = folders.count() + tracks.count(),
offset = offset,
match = [ r.as_subsonic_child(request.user) if isinstance(r, Folder) else r.as_subsonic_child(request.user, request.client) for r in res ]
))
return request.formatter('searchResult', dict(
totalHits = folders.count() + tracks.count(),
offset = offset,
match = [ r.as_subsonic_child(request.user) if isinstance(r, Folder) else r.as_subsonic_child(request.user, request.client) for r in res ]
))
else:
return request.formatter.error(10, 'Missing search parameter')
with db_session:
return request.formatter('searchResult', dict(
totalHits = query.count(),
offset = offset,
match = [ r.as_subsonic_child(request.user) if isinstance(r, Folder) else r.as_subsonic_child(request.user, request.client) for r in query[offset : offset + count] ]
))
return request.formatter('searchResult', dict(
totalHits = query.count(),
offset = offset,
match = [ r.as_subsonic_child(request.user) if isinstance(r, Folder) else r.as_subsonic_child(request.user, request.client) for r in query[offset : offset + count] ]
))
@api.route('/search2.view', methods = [ 'GET', 'POST' ])
def new_search():
@ -89,16 +87,15 @@ def new_search():
if not query:
return request.formatter.error(10, 'Missing query parameter')
with db_session:
artists = select(t.folder.parent for t in Track if query in t.folder.parent.name).limit(artist_count, artist_offset)
albums = select(t.folder for t in Track if query in t.folder.name).limit(album_count, album_offset)
songs = Track.select(lambda t: query in t.title).limit(song_count, song_offset)
artists = select(t.folder.parent for t in Track if query in t.folder.parent.name).limit(artist_count, artist_offset)
albums = select(t.folder for t in Track if query in t.folder.name).limit(album_count, album_offset)
songs = Track.select(lambda t: query in t.title).limit(song_count, song_offset)
return request.formatter('searchResult2', OrderedDict((
('artist', [ dict(id = str(a.id), name = a.name) for a in artists ]),
('album', [ f.as_subsonic_child(request.user) for f in albums ]),
('song', [ t.as_subsonic_child(request.user, request.client) for t in songs ])
)))
return request.formatter('searchResult2', OrderedDict((
('artist', [ dict(id = str(a.id), name = a.name) for a in artists ]),
('album', [ f.as_subsonic_child(request.user) for f in albums ]),
('song', [ t.as_subsonic_child(request.user, request.client) for t in songs ])
)))
@api.route('/search3.view', methods = [ 'GET', 'POST' ])
def search_id3():
@ -118,14 +115,13 @@ def search_id3():
if not query:
return request.formatter.error(10, 'Missing query parameter')
with db_session:
artists = Artist.select(lambda a: query in a.name).limit(artist_count, artist_offset)
albums = Album.select(lambda a: query in a.name).limit(album_count, album_offset)
songs = Track.select(lambda t: query in t.title).limit(song_count, song_offset)
artists = Artist.select(lambda a: query in a.name).limit(artist_count, artist_offset)
albums = Album.select(lambda a: query in a.name).limit(album_count, album_offset)
songs = Track.select(lambda t: query in t.title).limit(song_count, song_offset)
return request.formatter('searchResult3', OrderedDict((
('artist', [ a.as_subsonic_artist(request.user) for a in artists ]),
('album', [ a.as_subsonic_album(request.user) for a in albums ]),
('song', [ t.as_subsonic_child(request.user, request.client) for t in songs ])
)))
return request.formatter('searchResult3', OrderedDict((
('artist', [ a.as_subsonic_artist(request.user) for a in artists ]),
('album', [ a.as_subsonic_album(request.user) for a in albums ]),
('song', [ t.as_subsonic_child(request.user, request.client) for t in songs ])
)))

View File

@ -19,7 +19,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from flask import request
from pony.orm import db_session
from ..db import User
from ..managers.user import UserManager
@ -36,8 +35,7 @@ def user_info():
if username != request.username and not request.user.admin:
return request.formatter.error(50, 'Admin restricted')
with db_session:
user = User.get(name = username)
user = User.get(name = username)
if user is None:
return request.formatter.error(70, 'Unknown user')
@ -48,8 +46,7 @@ def users_info():
if not request.user.admin:
return request.formatter.error(50, 'Admin restricted')
with db_session:
return request.formatter('users', dict(user = [ u.as_subsonic_user() for u in User.select() ] ))
return request.formatter('users', dict(user = [ u.as_subsonic_user() for u in User.select() ] ))
@api.route('/createUser.view', methods = [ 'GET', 'POST' ])
def user_add():
@ -77,8 +74,7 @@ def user_del():
if not username:
return request.formatter.error(10, 'Missing parameter')
with db_session:
user = User.get(name = username)
user = User.get(name = username)
if user is None:
return request.formatter.error(70, 'Unknown user')

View File

@ -12,7 +12,6 @@
from flask import redirect, request, session, url_for
from flask import Blueprint
from functools import wraps
from pony.orm import db_session
from ..db import Artist, Album, Track
from ..managers.user import UserManager
@ -36,7 +35,6 @@ def login_check():
return redirect(url_for('frontend.login', returnUrl = request.script_root + request.url[len(request.url_root)-1:]))
@frontend.route('/')
@db_session
def index():
stats = {
'artists': Artist.select().count(),

View File

@ -22,7 +22,6 @@ import os.path
import uuid
from flask import current_app, flash, redirect, render_template, request, url_for
from pony.orm import db_session
from ..db import Folder
from ..managers.user import UserManager
@ -33,7 +32,6 @@ from . import admin_only, frontend
@frontend.route('/folder')
@admin_only
@db_session
def folder_index():
return render_template('folders.html', folders = Folder.select(lambda f: f.root))
@ -85,7 +83,6 @@ def del_folder(id):
@frontend.route('/folder/scan')
@frontend.route('/folder/scan/<id>')
@admin_only
@db_session
def scan_folder(id = None):
extensions = current_app.config['BASE']['scanner_extensions']
if extensions:

View File

@ -21,7 +21,6 @@
import uuid
from flask import flash, redirect, render_template, request, url_for
from pony.orm import db_session
from pony.orm import ObjectNotFound
from ..db import Playlist
@ -30,14 +29,12 @@ from ..managers.user import UserManager
from . import frontend
@frontend.route('/playlist')
@db_session
def playlist_index():
return render_template('playlists.html',
mine = Playlist.select(lambda p: p.user == request.user),
others = Playlist.select(lambda p: p.user != request.user and p.public))
@frontend.route('/playlist/<uid>')
@db_session
def playlist_details(uid):
try:
uid = uuid.UUID(uid)
@ -54,7 +51,6 @@ def playlist_details(uid):
return render_template('playlist.html', playlist = playlist)
@frontend.route('/playlist/<uid>', methods = [ 'POST' ])
@db_session
def playlist_update(uid):
try:
uid = uuid.UUID(uid)
@ -80,7 +76,6 @@ def playlist_update(uid):
return playlist_details(str(uid))
@frontend.route('/playlist/del/<uid>')
@db_session
def playlist_delete(uid):
try:
uid = uuid.UUID(uid)

View File

@ -21,7 +21,6 @@
from flask import flash, redirect, render_template, request, session, url_for
from flask import current_app
from functools import wraps
from pony.orm import db_session
from ..db import User, ClientPrefs
from ..lastfm import LastFm
@ -31,7 +30,6 @@ from ..py23 import dict
from . import admin_only, frontend
def me_or_uuid(f, arg = 'uid'):
@db_session
@wraps(f)
def decorated_func(*args, **kwargs):
if kwargs:
@ -40,7 +38,7 @@ def me_or_uuid(f, arg = 'uid'):
uid = args[0]
if uid == 'me':
user = User[request.user.id] # Refetch user from previous transaction
user = request.user
elif not request.user.admin:
return redirect(url_for('frontend.index'))
else:
@ -60,7 +58,6 @@ def me_or_uuid(f, arg = 'uid'):
@frontend.route('/user')
@admin_only
@db_session
def user_index():
return render_template('users.html', users = User.select())
@ -116,7 +113,6 @@ def change_username_form(uid):
@frontend.route('/user/<uid>/changeusername', methods = [ 'POST' ])
@admin_only
@db_session
def change_username_post(uid):
code, user = UserManager.get(uid)
if code != UserManager.SUCCESS:

View File

@ -13,9 +13,10 @@ import mimetypes
from flask import Flask
from os import makedirs, path
from pony.orm import db_session
from .config import IniConfig
from .db import init_database, release_database
from .db import init_database
def create_application(config = None):
global app
@ -48,6 +49,7 @@ def create_application(config = None):
# Initialize database
init_database(app.config['BASE']['database_uri'])
app.wsgi_app = db_session(app.wsgi_app)
# Insert unknown mimetypes
for k, v in app.config['MIMETYPES'].items():