1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-12-22 17:06:17 +00:00

Converting...

This commit is contained in:
spl0k 2014-03-16 18:51:19 +01:00
parent 3a06107fd6
commit f26cfbbb76
8 changed files with 75 additions and 55 deletions

View File

@ -23,7 +23,7 @@ or as a WSGI application (on Apache for instance). But first:
### Prerequisites ### Prerequisites
* Python 2.7 * Python 2.7
* [Flask](http://flask.pocoo.org/) >= 0.7 (`pip install flask`) * [Flask](http://flask.pocoo.org/) >= 0.9 (`pip install flask`)
* [SQLAlchemy](http://www.sqlalchemy.org/) (`apt-get install python-sqlalchemy`) * [SQLAlchemy](http://www.sqlalchemy.org/) (`apt-get install python-sqlalchemy`)
* Python Imaging Library (`apt-get install python-imaging`) * Python Imaging Library (`apt-get install python-imaging`)
* simplejson (`apt-get install python-simplejson`) * simplejson (`apt-get install python-simplejson`)

8
db.py
View File

@ -261,7 +261,7 @@ class User(object):
class ClientPrefs(object): class ClientPrefs(object):
__storm_table__ = 'client_prefs' __storm_table__ = 'client_prefs'
__storm_primary__ = 'user_id, client_name' __storm_primary__ = 'user_id', 'client_name'
user_id = UUID() user_id = UUID()
client_name = Unicode() client_name = Unicode()
@ -269,7 +269,7 @@ class ClientPrefs(object):
bitrate = Int() # nullable bitrate = Int() # nullable
class BaseStarred(object): class BaseStarred(object):
__storm_primary__ = 'user_id, starred_id' __storm_primary__ = 'user_id', 'starred_id'
user_id = UUID() user_id = UUID()
starred_id = UUID() starred_id = UUID()
@ -298,7 +298,7 @@ class StarredTrack(BaseStarred):
starred = Reference(BaseStarred.starred_id, Track.id) starred = Reference(BaseStarred.starred_id, Track.id)
class BaseRating(object): class BaseRating(object):
__storm_primary__ = 'user_id, rated_id' __storm_primary__ = 'user_id', 'rated_id'
user_id = UUID() user_id = UUID()
rated_id = UUID() rated_id = UUID()
@ -361,7 +361,7 @@ class Playlist(object):
class PlaylistTrack(object): class PlaylistTrack(object):
__storm_table__ = 'playlist_track' __storm_table__ = 'playlist_track'
__storm_primary__ = 'playlist_id, track_id' __storm_primary__ = 'playlist_id', 'track_id'
playlist_id = UUID() playlist_id = UUID()
track_id = UUID() track_id = UUID()

View File

@ -18,7 +18,9 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from web import app from flask import session
from web import app, store
from db import Artist, Album, Track
from managers.user import UserManager from managers.user import UserManager
app.add_template_filter(str) app.add_template_filter(str)
@ -32,7 +34,7 @@ def login_check():
should_login = False should_login = False
if not session.get('userid'): if not session.get('userid'):
should_login = True should_login = True
elif UserManager.get(session.get('userid'))[0] != UserManager.SUCCESS: elif UserManager.get(store, session.get('userid'))[0] != UserManager.SUCCESS:
session.clear() session.clear()
should_login = True should_login = True
@ -43,11 +45,11 @@ def login_check():
@app.route('/') @app.route('/')
def index(): def index():
stats = { stats = {
'artists': db.Artist.query.count(), 'artists': store.find(Artist).count(),
'albums': db.Album.query.count(), 'albums': store.find(Album).count(),
'tracks': db.Track.query.count() 'tracks': store.find(Track).count()
} }
return render_template('home.html', stats = stats, admin = UserManager.get(session.get('userid'))[1].admin) return render_template('home.html', stats = stats, admin = UserManager.get(store, session.get('userid'))[1].admin)
from .user import * from .user import *
from .folder import * from .folder import *

View File

@ -18,12 +18,12 @@
# You should have received a copy of the GNU Affero General Public License # You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from flask import request, flash, render_template, redirect, url_for, session as fl_sess from flask import request, flash, render_template, redirect, url_for, session
import os.path import os.path
import uuid import uuid
from web import app from web import app, store
from db import session, Folder from db import Folder
from scanner import Scanner from scanner import Scanner
from managers.user import UserManager from managers.user import UserManager
from managers.folder import FolderManager from managers.folder import FolderManager
@ -33,7 +33,7 @@ def check_admin():
if not request.path.startswith('/folder'): if not request.path.startswith('/folder'):
return return
if not UserManager.get(fl_sess.get('userid'))[1].admin: if not UserManager.get(store, session.get('userid'))[1].admin:
return redirect(url_for('index')) return redirect(url_for('index'))
@app.route('/folder') @app.route('/folder')
@ -95,7 +95,7 @@ def scan_folder(id = None):
return redirect(url_for('folder_index')) return redirect(url_for('folder_index'))
added, deleted = s.stats() added, deleted = s.stats()
session.commit() store.commit()
flash('Added: %i artists, %i albums, %i tracks' % (added[0], added[1], added[2])) flash('Added: %i artists, %i albums, %i tracks' % (added[0], added[1], added[2]))
flash('Deleted: %i artists, %i albums, %i tracks' % (deleted[0], deleted[1], deleted[2])) flash('Deleted: %i artists, %i albums, %i tracks' % (deleted[0], deleted[1], deleted[2]))

View File

@ -20,9 +20,9 @@
from flask import request, session, flash, render_template, redirect, url_for, make_response from flask import request, session, flash, render_template, redirect, url_for, make_response
from web import app from web import app, store
from managers.user import UserManager from managers.user import UserManager
from db import User, ClientPrefs, session as db_sess from db import User, ClientPrefs
import uuid, csv import uuid, csv
import config import config
from lastfm import LastFm from lastfm import LastFm
@ -32,46 +32,46 @@ def check_admin():
if not request.path.startswith('/user'): if not request.path.startswith('/user'):
return return
if request.endpoint in ('user_index', 'add_user', 'del_user', 'export_users', 'import_users', 'do_user_import') and not UserManager.get(session.get('userid'))[1].admin: if request.endpoint in ('user_index', 'add_user', 'del_user', 'export_users', 'import_users', 'do_user_import') and not UserManager.get(store, session.get('userid'))[1].admin:
return redirect(url_for('index')) return redirect(url_for('index'))
@app.route('/user') @app.route('/user')
def user_index(): def user_index():
return render_template('users.html', users = User.query.all()) return render_template('users.html', users = store.find(User))
@app.route('/user/me') @app.route('/user/me')
def user_profile(): def user_profile():
prefs = ClientPrefs.query.filter(ClientPrefs.user_id == uuid.UUID(session.get('userid'))) prefs = store.find(ClientPrefs, ClientPrefs.user_id == uuid.UUID(session.get('userid')))
return render_template('profile.html', user = UserManager.get(session.get('userid'))[1], api_key = config.get('lastfm', 'api_key'), clients = prefs) return render_template('profile.html', user = UserManager.get(store, session.get('userid'))[1], api_key = config.get('lastfm', 'api_key'), clients = prefs)
@app.route('/user/me', methods = [ 'POST' ]) @app.route('/user/me', methods = [ 'POST' ])
def update_clients(): def update_clients():
clients_opts = {} clients_opts = {}
for client in set(map(lambda k: k.rsplit('_', 1)[0],request.form.keys())): for client in set(map(lambda k: k.rsplit('_', 1)[0], request.form.keys())):
clients_opts[client] = { k.rsplit('_', 1)[1]: v for k, v in filter(lambda (k, v): k.startswith(client), request.form.iteritems()) } clients_opts[client] = { k.rsplit('_', 1)[1]: v for k, v in filter(lambda (k, v): k.startswith(client), request.form.iteritems()) }
app.logger.debug(clients_opts) app.logger.debug(clients_opts)
for client, opts in clients_opts.iteritems(): for client, opts in clients_opts.iteritems():
prefs = ClientPrefs.query.get((uuid.UUID(session.get('userid')), client)) prefs = store.get(ClientPrefs, (uuid.UUID(session.get('userid')), client))
if 'delete' in opts and opts['delete'] in [ 'on', 'true', 'checked', 'selected', '1' ]: if 'delete' in opts and opts['delete'] in [ 'on', 'true', 'checked', 'selected', '1' ]:
db_sess.delete(prefs) store.remove(prefs)
continue continue
prefs.format = opts['format'] if 'format' in opts and opts['format'] else None prefs.format = opts['format'] if 'format' in opts and opts['format'] else None
prefs.bitrate = int(opts['bitrate']) if 'bitrate' in opts and opts['bitrate'] else None prefs.bitrate = int(opts['bitrate']) if 'bitrate' in opts and opts['bitrate'] else None
db_sess.commit() store.commit()
flash('Clients preferences updated.') flash('Clients preferences updated.')
return user_profile() return user_profile()
@app.route('/user/changemail', methods = [ 'GET', 'POST' ]) @app.route('/user/changemail', methods = [ 'GET', 'POST' ])
def change_mail(): def change_mail():
user = UserManager.get(session.get('userid'))[1] user = UserManager.get(store, session.get('userid'))[1]
if request.method == 'POST': if request.method == 'POST':
mail = request.form.get('mail') mail = request.form.get('mail')
# No validation, lol. # No validation, lol.
user.mail = mail user.mail = mail
db_sess.commit() store.commit()
return redirect(url_for('user_profile')) return redirect(url_for('user_profile'))
return render_template('change_mail.html', user = user) return render_template('change_mail.html', user = user)
@ -92,14 +92,14 @@ def change_password():
error = True error = True
if not error: if not error:
status = UserManager.change_password(session.get('userid'), current, new) status = UserManager.change_password(store, session.get('userid'), current, new)
if status != UserManager.SUCCESS: if status != UserManager.SUCCESS:
flash(UserManager.error_str(status)) flash(UserManager.error_str(status))
else: else:
flash('Password changed') flash('Password changed')
return redirect(url_for('user_profile')) return redirect(url_for('user_profile'))
return render_template('change_pass.html', user = UserManager.get(session.get('userid'))[1].name) return render_template('change_pass.html', user = UserManager.get(store, session.get('userid'))[1].name)
@app.route('/user/add', methods = [ 'GET', 'POST' ]) @app.route('/user/add', methods = [ 'GET', 'POST' ])
def add_user(): def add_user():
@ -119,12 +119,12 @@ def add_user():
error = True error = True
if admin is None: if admin is None:
admin = True if User.query.filter(User.admin == True).count() == 0 else False admin = True if store.find(User, User.admin == True).count() == 0 else False
else: else:
admin = True admin = True
if not error: if not error:
status = UserManager.add(name, passwd, mail, admin) status = UserManager.add(store, name, passwd, mail, admin)
if status == UserManager.SUCCESS: if status == UserManager.SUCCESS:
flash("User '%s' successfully added" % name) flash("User '%s' successfully added" % name)
return redirect(url_for('user_index')) return redirect(url_for('user_index'))
@ -136,7 +136,7 @@ def add_user():
@app.route('/user/del/<uid>') @app.route('/user/del/<uid>')
def del_user(uid): def del_user(uid):
status = UserManager.delete(uid) status = UserManager.delete(store, uid)
if status == UserManager.SUCCESS: if status == UserManager.SUCCESS:
flash('Deleted user') flash('Deleted user')
else: else:
@ -147,7 +147,7 @@ def del_user(uid):
@app.route('/user/export') @app.route('/user/export')
def export_users(): def export_users():
resp = make_response('\n'.join([ '%s,%s,%s,%s,"%s",%s,%s,%s' % (u.id, u.name, u.mail, u.password, u.salt, u.admin, u.lastfm_session, u.lastfm_status) resp = make_response('\n'.join([ '%s,%s,%s,%s,"%s",%s,%s,%s' % (u.id, u.name, u.mail, u.password, u.salt, u.admin, u.lastfm_session, u.lastfm_status)
for u in User.query.all() ])) for u in store.find(User) ]))
resp.headers['Content-disposition'] = 'attachment;filename=users.csv' resp.headers['Content-disposition'] = 'attachment;filename=users.csv'
resp.headers['Content-type'] = 'text/csv' resp.headers['Content-type'] = 'text/csv'
return resp return resp
@ -168,12 +168,22 @@ def do_user_import():
admin = admin == 'True' admin = admin == 'True'
lfmsess = None if lfmsess == 'None' else lfmsess lfmsess = None if lfmsess == 'None' else lfmsess
lfmstatus = lfmstatus == 'True' lfmstatus = lfmstatus == 'True'
users.append(User(id = uuid.UUID(id), name = name, password = password, salt = salt, admin = admin, lastfm_session = lfmsess, lastfm_status = lfmstatus))
User.query.delete() user = User()
user.id = uuid.UUID(id)
user.name = name
user.password = password
user.salt = salt
user.admin = admin
user.lastfm_session = lfmsess
user.lastfm_status = lfmstatus
users.append(user)
store.find(User).remove()
for u in users: for u in users:
db_sess.add(u) store.add(u)
db_sess.commit() store.commit()
return redirect(url_for('user_index')) return redirect(url_for('user_index'))
@ -184,16 +194,18 @@ def lastfm_reg():
flash('Missing LastFM auth token') flash('Missing LastFM auth token')
return redirect(url_for('user_profile')) return redirect(url_for('user_profile'))
lfm = LastFm(UserManager.get(session.get('userid'))[1], app.logger) lfm = LastFm(UserManager.get(store, session.get('userid'))[1], app.logger)
status, error = lfm.link_account(token) status, error = lfm.link_account(token)
store.commit()
flash(error if not status else 'Successfully linked LastFM account') flash(error if not status else 'Successfully linked LastFM account')
return redirect(url_for('user_profile')) return redirect(url_for('user_profile'))
@app.route('/user/lastfm/unlink') @app.route('/user/lastfm/unlink')
def lastfm_unreg(): def lastfm_unreg():
lfm = LastFm(UserManager.get(session.get('userid'))[1], app.logger) lfm = LastFm(UserManager.get(store, session.get('userid'))[1], app.logger)
lfm.unlink_account() lfm.unlink_account()
store.commit()
flash('Unliked LastFM account') flash('Unliked LastFM account')
return redirect(url_for('user_profile')) return redirect(url_for('user_profile'))
@ -217,7 +229,7 @@ def login():
error = True error = True
if not error: if not error:
status, user = UserManager.try_auth(name, password) status, user = UserManager.try_auth(store, name, password)
if status == UserManager.SUCCESS: if status == UserManager.SUCCESS:
session['userid'] = str(user.id) session['userid'] = str(user.id)
session['username'] = user.name session['username'] = user.name

View File

@ -20,7 +20,6 @@
import requests, hashlib import requests, hashlib
import config import config
from db import session
class LastFm: class LastFm:
def __init__(self, user, logger): def __init__(self, user, logger):
@ -40,13 +39,11 @@ class LastFm:
else: else:
self.__user.lastfm_session = res['session']['key'] self.__user.lastfm_session = res['session']['key']
self.__user.lastfm_status = True self.__user.lastfm_status = True
session.commit()
return True, 'OK' return True, 'OK'
def unlink_account(self): def unlink_account(self):
self.__user.lastfm_session = None self.__user.lastfm_session = None
self.__user.lastfm_status = True self.__user.lastfm_status = True
session.commit()
def now_playing(self, track): def now_playing(self, track):
if not self.__enabled: if not self.__enabled:
@ -92,7 +89,6 @@ class LastFm:
if 'error' in r.json: if 'error' in r.json:
if r.json['error'] in (9, '9'): if r.json['error'] in (9, '9'):
self.__user.lastfm_status = False self.__user.lastfm_status = False
session.commit()
self.__logger.warn('LastFM error %i: %s' % (r.json['error'], r.json['message'])) self.__logger.warn('LastFM error %i: %s' % (r.json['error'], r.json['message']))
return r.json return r.json

View File

@ -31,7 +31,7 @@ class UserManager:
WRONG_PASS = 4 WRONG_PASS = 4
@staticmethod @staticmethod
def get(stotre, uid): def get(store, uid):
if type(uid) in (str, unicode): if type(uid) in (str, unicode):
try: try:
uid = uuid.UUID(uid) uid = uuid.UUID(uid)

28
web.py
View File

@ -19,15 +19,28 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
import os.path import os.path
from flask import Flask, request, session, flash, render_template, redirect, url_for from flask import Flask, g
from werkzeug.local import LocalProxy
import config import config
from db import get_store
def teardown(exception): def get_db_store():
db.session.remove() store = getattr(g, 'store', None)
if store:
return store
g.store = get_store(config.get('base', 'database_uri'))
return g.store
store = LocalProxy(get_db_store)
def teardown_db(exception):
store = getattr(g, 'store', None)
if store:
store.close()
def create_application(): def create_application():
global app, db, UserManager global app
if not config.check(): if not config.check():
return None return None
@ -35,12 +48,11 @@ def create_application():
if not os.path.exists(config.get('base', 'cache_dir')): if not os.path.exists(config.get('base', 'cache_dir')):
os.makedirs(config.get('base', 'cache_dir')) os.makedirs(config.get('base', 'cache_dir'))
import db
db.init_db()
app = Flask(__name__) app = Flask(__name__)
app.secret_key = '?9huDM\\H' app.secret_key = '?9huDM\\H'
app.teardown_appcontext(teardown_db)
if config.get('base', 'log_file'): if config.get('base', 'log_file'):
import logging import logging
from logging.handlers import TimedRotatingFileHandler from logging.handlers import TimedRotatingFileHandler
@ -48,8 +60,6 @@ def create_application():
handler.setLevel(logging.WARNING) handler.setLevel(logging.WARNING)
app.logger.addHandler(handler) app.logger.addHandler(handler)
app.teardown_request(teardown)
import frontend import frontend
import api import api