environment class
get_session
This commit is contained in:
+10
-13
@@ -1,10 +1,14 @@
|
|||||||
from couchpotato.core.auth import requires_auth
|
from couchpotato.core.auth import requires_auth
|
||||||
from couchpotato.core.logger import CPLog
|
from couchpotato.core.logger import CPLog
|
||||||
|
from couchpotato.environment import Env
|
||||||
from flask.app import Flask
|
from flask.app import Flask
|
||||||
from flask.globals import request
|
from flask.globals import request
|
||||||
from flask.helpers import url_for
|
from flask.helpers import url_for
|
||||||
from flask.module import Module
|
from flask.module import Module
|
||||||
from flask.templating import render_template
|
from flask.templating import render_template
|
||||||
|
from sqlalchemy.engine import create_engine
|
||||||
|
from sqlalchemy.orm import scoped_session
|
||||||
|
from sqlalchemy.orm.session import sessionmaker
|
||||||
from werkzeug.utils import redirect
|
from werkzeug.utils import redirect
|
||||||
import os
|
import os
|
||||||
|
|
||||||
@@ -12,6 +16,12 @@ app = Flask(__name__)
|
|||||||
log = CPLog(__name__)
|
log = CPLog(__name__)
|
||||||
web = Module(__name__, 'web')
|
web = Module(__name__, 'web')
|
||||||
|
|
||||||
|
def get_session(engine):
|
||||||
|
engine = engine if engine else get_engine()
|
||||||
|
return scoped_session(sessionmaker(autoflush = True, transactional = True, bind = engine))
|
||||||
|
|
||||||
|
def get_engine():
|
||||||
|
return create_engine('sqlite:///' + Env.get('db_path'), echo = Env.get('debug'))
|
||||||
|
|
||||||
@web.route('/')
|
@web.route('/')
|
||||||
@requires_auth
|
@requires_auth
|
||||||
@@ -23,16 +33,3 @@ def page_not_found(error):
|
|||||||
index_url = url_for('web.index')
|
index_url = url_for('web.index')
|
||||||
url = request.path[len(index_url):]
|
url = request.path[len(index_url):]
|
||||||
return redirect(index_url + '#' + url)
|
return redirect(index_url + '#' + url)
|
||||||
|
|
||||||
@web.route('/exit')
|
|
||||||
@requires_auth
|
|
||||||
def exit():
|
|
||||||
# stopping code
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
@web.route('/restart')
|
|
||||||
@requires_auth
|
|
||||||
def restart():
|
|
||||||
# restart code
|
|
||||||
pass
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from couchpotato.api.file_browser import FileBrowser
|
from couchpotato.api.file_browser import FileBrowser
|
||||||
from couchpotato.core.settings import settings
|
|
||||||
from couchpotato.core.settings.loader import settings_loader
|
from couchpotato.core.settings.loader import settings_loader
|
||||||
|
from couchpotato.core.settings.model import Resource
|
||||||
|
from couchpotato.environment import Env
|
||||||
from flask import Module
|
from flask import Module
|
||||||
from flask.helpers import jsonify
|
from flask.helpers import jsonify
|
||||||
import flask
|
import flask
|
||||||
@@ -16,7 +17,7 @@ def index():
|
|||||||
def settings_view():
|
def settings_view():
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'sections': settings_loader.sections,
|
'sections': settings_loader.sections,
|
||||||
'values': settings.getValues()
|
'values': Env.get('settings').getValues()
|
||||||
})
|
})
|
||||||
|
|
||||||
@api.route('setting.save/')
|
@api.route('setting.save/')
|
||||||
@@ -27,8 +28,8 @@ def setting_save_view():
|
|||||||
option = a.get('name')
|
option = a.get('name')
|
||||||
value = a.get('value')
|
value = a.get('value')
|
||||||
|
|
||||||
settings.set(section, option, value)
|
Env.get('settings').set(section, option, value)
|
||||||
settings.save()
|
Env.get('settings').save()
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'success': True,
|
'success': True,
|
||||||
@@ -36,6 +37,7 @@ def setting_save_view():
|
|||||||
|
|
||||||
@api.route('movie/')
|
@api.route('movie/')
|
||||||
def movie():
|
def movie():
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
'success': True,
|
'success': True,
|
||||||
'movies': [
|
'movies': [
|
||||||
|
|||||||
+22
-11
@@ -1,6 +1,8 @@
|
|||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from couchpotato import web
|
from couchpotato import get_engine, web
|
||||||
from couchpotato.api import api
|
from couchpotato.api import api
|
||||||
|
from couchpotato.core.settings.model import *
|
||||||
|
from couchpotato.environment import Env
|
||||||
from libs.daemon import createDaemon
|
from libs.daemon import createDaemon
|
||||||
from logging import handlers
|
from logging import handlers
|
||||||
import logging
|
import logging
|
||||||
@@ -13,8 +15,8 @@ def cmd_couchpotato(base_path, args):
|
|||||||
|
|
||||||
# Options
|
# Options
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
parser.add_argument('-s', '--datadir', default = base_path,
|
parser.add_argument('-s', '--datadir', default = os.path.join(base_path, '_data'),
|
||||||
dest = 'data_dir', help = 'Absolute or ~/ path, where settings/logs/database data is saved (default ./)')
|
dest = 'data_dir', help = 'Absolute or ~/ path, where settings/logs/database data is saved (default ./_data)')
|
||||||
parser.add_argument('-t', '--test', '--debug', action = 'store_true',
|
parser.add_argument('-t', '--test', '--debug', action = 'store_true',
|
||||||
dest = 'debug', help = 'Debug mode')
|
dest = 'debug', help = 'Debug mode')
|
||||||
parser.add_argument('-q', '--quiet', action = 'store_true',
|
parser.add_argument('-q', '--quiet', action = 'store_true',
|
||||||
@@ -41,12 +43,15 @@ def cmd_couchpotato(base_path, args):
|
|||||||
createDaemon()
|
createDaemon()
|
||||||
|
|
||||||
|
|
||||||
# Register settings
|
# Register environment settings
|
||||||
from couchpotato.core.settings import settings
|
Env.get('settings').setFile(os.path.join(options.data_dir, 'settings.conf'))
|
||||||
settings.setFile(os.path.join(options.data_dir, 'settings.conf'))
|
Env.set('app_dir', base_path)
|
||||||
|
Env.set('data_dir', options.data_dir)
|
||||||
|
Env.set('db_path', os.path.join(options.data_dir, 'couchpotato.db'))
|
||||||
|
|
||||||
# Determine debug
|
# Determine debug
|
||||||
debug = options.debug or settings.get('debug', default = False)
|
debug = options.debug or Env.get('settings').get('debug', default = False)
|
||||||
|
Env.set('debug', debug)
|
||||||
|
|
||||||
|
|
||||||
# Logger
|
# Logger
|
||||||
@@ -83,15 +88,21 @@ def cmd_couchpotato(base_path, args):
|
|||||||
settings_loader.run()
|
settings_loader.run()
|
||||||
|
|
||||||
|
|
||||||
|
# Configure Database
|
||||||
|
from elixir import setup_all, create_all
|
||||||
|
setup_all()
|
||||||
|
create_all(get_engine())
|
||||||
|
|
||||||
|
|
||||||
# Create app
|
# Create app
|
||||||
from couchpotato import app
|
from couchpotato import app
|
||||||
api_key = settings.get('api_key')
|
api_key = Env.get('settings').get('api_key')
|
||||||
url_base = '/' + settings.get('url_base') if settings.get('url_base') else ''
|
url_base = '/' + Env.get('settings').get('url_base') if Env.get('settings').get('url_base') else ''
|
||||||
reloader = debug and not options.daemonize
|
reloader = debug and not options.daemonize
|
||||||
|
|
||||||
# Basic config
|
# Basic config
|
||||||
app.host = settings.get('host', default = '0.0.0.0')
|
app.host = Env.get('settings').get('host', default = '0.0.0.0')
|
||||||
app.port = settings.get('port', default = 5000)
|
app.port = Env.get('settings').get('port', default = 5000)
|
||||||
app.debug = debug
|
app.debug = debug
|
||||||
app.secret_key = api_key
|
app.secret_key = api_key
|
||||||
app.static_path = url_base + '/static'
|
app.static_path = url_base + '/static'
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
from couchpotato.core.settings import settings
|
from couchpotato.environment import Env
|
||||||
from flask import request, Response
|
from flask import request, Response
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
def check_auth(username, password):
|
def check_auth(username, password):
|
||||||
return username == settings.get('username') and password == settings.get('password')
|
return username == Env.get('settings').get('username') and password == Env.get('settings').get('password')
|
||||||
|
|
||||||
def authenticate():
|
def authenticate():
|
||||||
return Response(
|
return Response(
|
||||||
@@ -16,7 +16,7 @@ def requires_auth(f):
|
|||||||
@wraps(f)
|
@wraps(f)
|
||||||
def decorated(*args, **kwargs):
|
def decorated(*args, **kwargs):
|
||||||
auth = request.authorization
|
auth = request.authorization
|
||||||
if settings.get('username') and (not auth or not check_auth(auth.username, auth.password)):
|
if Env.get('settings').get('username') and (not auth or not check_auth(auth.username, auth.password)):
|
||||||
return authenticate()
|
return authenticate()
|
||||||
|
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
|
|||||||
@@ -94,5 +94,3 @@ class Settings():
|
|||||||
return True
|
return True
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
settings = Settings()
|
|
||||||
|
|||||||
@@ -1,64 +0,0 @@
|
|||||||
import sqlalchemy as sa
|
|
||||||
from sqlalchemy import orm
|
|
||||||
|
|
||||||
|
|
||||||
class DatabaseError(Exception):
|
|
||||||
"""Custom exceptions related to the database."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def _session_cls_cache(cache={}):
|
|
||||||
"""Holds a dictionary to cache session objects."""
|
|
||||||
return cache
|
|
||||||
|
|
||||||
|
|
||||||
def get_session(engine=None, test=False):
|
|
||||||
"""
|
|
||||||
Get the current session or create a new one based on the engine.
|
|
||||||
|
|
||||||
>>> from couchpotato import db
|
|
||||||
>>> from sqlalchemy import create_engine
|
|
||||||
>>> engine = create_engine('sqlite:///:memory:')
|
|
||||||
>>> session = db.get_session(engine)
|
|
||||||
>>> session #doctest: +ELLIPSIS
|
|
||||||
<sqlalchemy.orm.session.Session object at ...>
|
|
||||||
|
|
||||||
Once a session has been created, get_session will return session instances
|
|
||||||
of the same Session class.
|
|
||||||
>>> type(session) == type(db.get_session())
|
|
||||||
True
|
|
||||||
|
|
||||||
If you create multiple sessions for different engines, you need to
|
|
||||||
specify which session you want by passing the engine explicitely.
|
|
||||||
|
|
||||||
>>> other_engine = create_engine('sqlite:///:memory:')
|
|
||||||
>>> other_session = db.get_session(other_engine)
|
|
||||||
>>> type(other_session) is type(db.get_session(other_engine))
|
|
||||||
True
|
|
||||||
|
|
||||||
"""
|
|
||||||
cache = _session_cls_cache()
|
|
||||||
|
|
||||||
assert not(engine and test), "Cannot pass both test and engine."
|
|
||||||
# It doesn't make sense to both pass an engine and instruct the function
|
|
||||||
# to create a new engine. Decide what you want to do, but not both.
|
|
||||||
if test:
|
|
||||||
in_memory = sa.create_engine('sqlite:///:memory:')
|
|
||||||
session = orm.sessionmaker(bind=in_memory)()
|
|
||||||
# create Session class ^ ^
|
|
||||||
# create Session instance ^
|
|
||||||
elif engine:
|
|
||||||
key = (engine, )
|
|
||||||
if key not in cache:
|
|
||||||
cache[key] = orm.sessionmaker(bind=engine)
|
|
||||||
session = cache[key]()
|
|
||||||
elif len(cache) == 1:
|
|
||||||
session = (cache[key] for key in cache).next()()
|
|
||||||
# return the first element ^ ^
|
|
||||||
# instantiate session ^
|
|
||||||
elif len(cache) >= 1:
|
|
||||||
raise DatabaseError("Multiple Session classes found. Choose one.")
|
|
||||||
else:
|
|
||||||
raise DatabaseError("No session found. You need to create one.")
|
|
||||||
|
|
||||||
return session
|
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
from elixir import *
|
from elixir.entity import Entity
|
||||||
from sqlalchemy import create_engine
|
from elixir.fields import Field
|
||||||
from sqlalchemy.orm import scoped_session, sessionmaker
|
from elixir.options import options_defaults
|
||||||
from sqlalchemy.schema import ThreadLocalMetaData
|
from elixir.relationships import OneToMany, ManyToOne
|
||||||
|
from sqlalchemy.types import Integer, String, Unicode
|
||||||
|
|
||||||
|
options_defaults["shortnames"] = True
|
||||||
|
|
||||||
# We would like to be able to create this schema in a specific database at
|
# We would like to be able to create this schema in a specific database at
|
||||||
# will, so we can test it easily.
|
# will, so we can test it easily.
|
||||||
@@ -10,12 +13,11 @@ from sqlalchemy.schema import ThreadLocalMetaData
|
|||||||
# http://elixir.ematia.de/trac/wiki/Recipes/MultipleDatabasesOneMetadata
|
# http://elixir.ematia.de/trac/wiki/Recipes/MultipleDatabasesOneMetadata
|
||||||
__session__ = None
|
__session__ = None
|
||||||
|
|
||||||
|
|
||||||
class Resource(Entity):
|
class Resource(Entity):
|
||||||
"""Represents a resource of movies. This recources can be online or
|
"""Represents a resource of movies.
|
||||||
offline."""
|
This resources can be online or offline."""
|
||||||
name = Field(UnicodeString(255))
|
name = Field(Unicode(255))
|
||||||
path = Field(UnicodeString(255))
|
path = Field(Unicode(255))
|
||||||
releases = OneToMany('Release')
|
releases = OneToMany('Release')
|
||||||
|
|
||||||
|
|
||||||
@@ -30,7 +32,7 @@ class Release(Entity):
|
|||||||
class File(Entity):
|
class File(Entity):
|
||||||
"""File that belongs to a release."""
|
"""File that belongs to a release."""
|
||||||
history = OneToMany('RenameHistory')
|
history = OneToMany('RenameHistory')
|
||||||
path = Field(UnicodeString(255), nullable = False, unique = True)
|
path = Field(Unicode(255), nullable = False, unique = True)
|
||||||
# Subtitles can have multiple parts, too
|
# Subtitles can have multiple parts, too
|
||||||
part = Field(Integer)
|
part = Field(Integer)
|
||||||
release = ManyToOne('Release')
|
release = ManyToOne('Release')
|
||||||
@@ -42,7 +44,7 @@ class File(Entity):
|
|||||||
class FileType(Entity):
|
class FileType(Entity):
|
||||||
"""Types could be trailer, subtitle, movie, partial movie etc."""
|
"""Types could be trailer, subtitle, movie, partial movie etc."""
|
||||||
identifier = Field(String(20), unique = True)
|
identifier = Field(String(20), unique = True)
|
||||||
name = Field(UnicodeString(255), nullable = False)
|
name = Field(Unicode(255), nullable = False)
|
||||||
files = OneToMany('File')
|
files = OneToMany('File')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
from couchpotato.core.settings import Settings
|
||||||
|
|
||||||
|
class Env:
|
||||||
|
_debug = False
|
||||||
|
_settings = Settings()
|
||||||
|
_options = None
|
||||||
|
_args = None
|
||||||
|
_quiet = False
|
||||||
|
|
||||||
|
_app_dir = ""
|
||||||
|
_data_dir = ""
|
||||||
|
_db_path = ""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def doDebug():
|
||||||
|
return Env._debug
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get(attr):
|
||||||
|
return getattr(Env, '_' + attr)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set(attr, value):
|
||||||
|
return setattr(Env, '_' + attr, value)
|
||||||
Reference in New Issue
Block a user