Filter all library and user data for guests

This commit is contained in:
JonnyWong16 2016-04-25 23:51:34 -07:00
parent d462ebe8e5
commit c0a5a8d775
13 changed files with 382 additions and 246 deletions

View file

@ -1791,7 +1791,7 @@ a:hover .item-children-poster {
height: 80px;
width: 80px;
}
.library-user-instance-box:hover {
a .library-user-instance-box:hover {
-webkit-box-shadow: inset 0 0 0 2px #e9a049;
-moz-box-shadow: inset 0 0 0 2px #e9a049;
box-shadow: inset 0 0 0 2px #e9a049;

View file

@ -540,12 +540,10 @@ DOCUMENTATION :: END
<h4>
% if top_stat['rows'][0]['user_id']:
<a href="user?user_id=${top_stat['rows'][0]['user_id']}" title="${top_stat['rows'][0]['friendly_name']}">
% elif top_stat['rows'][0]['user']:
<a href="user?user=${top_stat['rows'][0]['user']}" title="${top_stat['rows'][0]['friendly_name']}">
% endif
${top_stat['rows'][0]['friendly_name']}
% if top_stat['rows'][0]['user_id'] or top_stat['rows'][0]['user']:
</a>
% else:
${top_stat['rows'][0]['friendly_name']}
% endif
</h4>
% if top_stat['stat_type'] == 'total_plays':
@ -558,8 +556,6 @@ DOCUMENTATION :: END
</div>
% if top_stat['rows'][0]['user_id']:
<a href="user?user_id=${top_stat['rows'][0]['user_id']}" title="${top_stat['rows'][0]['friendly_name']}">
% elif top_stat['rows'][0]['user']:
<a href="user?user=${top_stat['rows'][0]['user']}" title="${top_stat['rows'][0]['friendly_name']}">
% endif
% if top_stat['rows'][0]['user_thumb'] != '':
<div class="home-platforms-instance-poster">
@ -570,7 +566,7 @@ DOCUMENTATION :: END
<div class="home-platforms-instance-oval" style="background-image: url(${http_root}images/gravatar-default.png);"></div>
</div>
% endif
% if top_stat['rows'][0]['user_id'] or top_stat['rows'][0]['user']:
% if top_stat['rows'][0]['user_id']:
</a>
% endif
% if len(top_stat['rows']) > 1:
@ -586,12 +582,10 @@ DOCUMENTATION :: END
<h5>
% if top_stat['rows'][loop.index]['user_id']:
<a href="user?user_id=${top_stat['rows'][loop.index]['user_id']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
% elif top_stat['rows'][loop.index]['user']:
<a href="user?user=${top_stat['rows'][loop.index]['user']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
% endif
${top_stat['rows'][loop.index]['friendly_name']}
% if top_stat['rows'][loop.index]['user_id'] or top_stat['rows'][loop.index]['user']:
</a>
% else:
${top_stat['rows'][loop.index]['friendly_name']}
% endif
</h5>
</div>
@ -606,8 +600,6 @@ DOCUMENTATION :: END
</div>
% if top_stat['rows'][loop.index]['user_id']:
<a href="user?user_id=${top_stat['rows'][loop.index]['user_id']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
% elif top_stat['rows'][loop.index]['user']:
<a href="user?user=${top_stat['rows'][loop.index]['user']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
% endif
% if top_stat['rows'][loop.index]['user_thumb'] != '':
<div class="home-platforms-instance-poster">
@ -618,7 +610,7 @@ DOCUMENTATION :: END
<div class="home-platforms-instance-list-oval" style="background-image: url(${http_root}images/gravatar-default.png);"></div>
</div>
% endif
% if top_stat['rows'][loop.index]['user_id'] or top_stat['rows'][loop.index]['user']:
% if top_stat['rows'][loop.index]['user_id']:
</a>
% endif
<div class="home-platforms-instance-list-number">
@ -711,11 +703,11 @@ DOCUMENTATION :: END
<h5>
% if top_stat['rows'][0]['user_id']:
<a href="user?user_id=${top_stat['rows'][0]['user_id']}" title="${top_stat['rows'][0]['friendly_name']}">
% else:
<a href="user?user=${top_stat['rows'][0]['user']}" title="${top_stat['rows'][0]['friendly_name']}">
% endif
${top_stat['rows'][0]['friendly_name']}
</a>
% else:
${top_stat['rows'][0]['friendly_name']}
% endif
</h5>
<p>
<span id="last-watch-stat">
@ -757,11 +749,11 @@ DOCUMENTATION :: END
<h5>
% if top_stat['rows'][loop.index]['user_id']:
<a href="user?user_id=${top_stat['rows'][loop.index]['user_id']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
% else:
<a href="user?user=${top_stat['rows'][loop.index]['user']}" title="${top_stat['rows'][loop.index]['friendly_name']}">
% endif
${top_stat['rows'][loop.index]['friendly_name']}
</a>
% else:
${top_stat['rows'][loop.index]['friendly_name']}
% endif
</h5>
<p>
<span id="home-platforms-instance-list-last-watch-${loop.index + 1}">

View file

@ -181,10 +181,12 @@ DOCUMENTATION :: END
</div>
<div class="button-bar">
<div class="colvis-button-bar hidden-xs" id="button-bar-history"></div>
% if _session['user_group'] == 'admin':
<button class="btn btn-danger btn-edit" data-toggle="button" aria-pressed="false" autocomplete="off" id="row-edit-mode">
<i class="fa fa-trash-o"></i> Delete mode
</button>
<div class="alert alert-danger alert-edit" role="alert" id="row-edit-mode-alert"><i class="fa fa-exclamation-triangle"></i>&nbspSelect rows to delete. Data is deleted upon exiting delete mode.</div>
% endif
</div>
</div>
<div class="table-card-back">

View file

@ -10,9 +10,9 @@ Variable names: data [array]
data[array_index] :: Usable parameters
== Global keys ==
user Returns the name of the user.
friendly_name Returns the friendly name of the user.
user_id Returns the user id of the user.
thumb Returns the avatar of the user.
user_thumb Returns the avatar of the user.
total_plays Returns the play count for the user.
DOCUMENTATION :: END
@ -23,12 +23,19 @@ DOCUMENTATION :: END
<ul class="list-unstyled">
<div class="user-player-instance">
<li>
<a href="user?user_id=${a['user_id']}" title="${a['user']}">
<div class="library-user-instance-box" style="background-image: url(${a['thumb']});"></div>
% if a['user_id']:
<a href="user?user_id=${a['user_id']}" title="${a['friendly_name']}">
<div class="library-user-instance-box" style="background-image: url(${a['user_thumb']});"></div>
</a>
<div class=" user-player-instance-name">
<a href="user?user_id=${a['user_id']}" title="${a['user']}">${a['user']}</a>
<a href="user?user_id=${a['user_id']}" title="${a['friendly_name']}">${a['friendly_name']}</a>
</div>
% else:
<div class="library-user-instance-box" style="background-image: url(${a['user_thumb']});"></div>
<div class=" user-player-instance-name">
${a['friendly_name']}
</div>
% endif
<div class="user-player-instance-playcount">
<h3>${a['total_plays']}</h3>
<p> plays</p>

View file

@ -13,10 +13,10 @@
# You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
from plexpy import logger, datatables, common, database, helpers
import datetime
from plexpy import logger, datatables, common, database, helpers, session
class DataFactory(object):
"""
@ -29,6 +29,23 @@ class DataFactory(object):
def get_datatables_history(self, kwargs=None, custom_where=None, grouping=0, watched_percent=85):
data_tables = datatables.DataTables()
if session.get_session_user_id():
session_user_id = str(session.get_session_user_id())
added = False
for c_where in custom_where:
if 'user_id' in c_where[0]:
# This currently only works if c_where[1] is not a list or tuple
if str(c_where[1]) == session_user_id:
added = True
break
else:
c_where[1] = (c_where[1], session_user_id)
added = True
if not added:
custom_where = [['session_history.user_id', session.get_session_user_id()]]
group_by = ['session_history.reference_id'] if grouping else ['session_history.id']
columns = ['session_history.reference_id',
@ -148,7 +165,7 @@ class DataFactory(object):
dict = {'recordsFiltered': query['filteredCount'],
'recordsTotal': query['totalCount'],
'data': helpers.filter_session_info(rows, 'user_id'),
'data': rows,
'draw': query['draw'],
'filter_duration': helpers.human_duration(filter_duration, sig='dhm'),
'total_duration': helpers.human_duration(total_duration, sig='dhm')
@ -162,6 +179,13 @@ class DataFactory(object):
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
sort_type = 'total_plays' if stats_type == 0 else 'total_duration'
library_cond = ''
if session.get_session_libraries():
library_cond = 'AND ('
for section_id in session.get_session_libraries():
library_cond += 'session_history_metadata.section_id = %s OR ' % section_id
library_cond = library_cond.rstrip(' OR ') + ')'
home_stats = []
for stat in stats_cards:
@ -177,11 +201,11 @@ class DataFactory(object):
' JOIN session_history_metadata ON session_history_metadata.id = session_history.id ' \
' WHERE datetime(session_history.stopped, "unixepoch", "localtime") ' \
' >= datetime("now", "-%s days", "localtime") ' \
' AND session_history.media_type = "episode" ' \
' AND session_history.media_type = "episode" %s ' \
' GROUP BY %s) AS t ' \
'GROUP BY t.grandparent_title ' \
'ORDER BY %s DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
'LIMIT %s ' % (time_range, library_cond, group_by, sort_type, stats_count)
result = monitor_db.select(query)
except Exception as e:
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: top_tv: %s." % e)
@ -207,7 +231,7 @@ class DataFactory(object):
home_stats.append({'stat_id': stat,
'stat_type': sort_type,
'rows': helpers.filter_session_info(top_tv, 'section_id')})
'rows': session.mask_session_info(top_tv, mask_metadata=True)})
elif stat == 'popular_tv':
popular_tv = []
@ -222,11 +246,11 @@ class DataFactory(object):
' JOIN session_history_metadata ON session_history_metadata.id = session_history.id ' \
' WHERE datetime(session_history.stopped, "unixepoch", "localtime") ' \
' >= datetime("now", "-%s days", "localtime") ' \
' AND session_history.media_type = "episode" ' \
' AND session_history.media_type = "episode" %s ' \
' GROUP BY %s) AS t ' \
'GROUP BY t.grandparent_title ' \
'ORDER BY users_watched DESC, %s DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
'LIMIT %s ' % (time_range, library_cond, group_by, sort_type, stats_count)
result = monitor_db.select(query)
except Exception as e:
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: popular_tv: %s." % e)
@ -250,7 +274,7 @@ class DataFactory(object):
popular_tv.append(row)
home_stats.append({'stat_id': stat,
'rows': helpers.filter_session_info(popular_tv, 'section_id')})
'rows': session.mask_session_info(popular_tv, mask_metadata=True)})
elif stat == 'top_movies':
top_movies = []
@ -264,11 +288,11 @@ class DataFactory(object):
' JOIN session_history_metadata ON session_history_metadata.id = session_history.id ' \
' WHERE datetime(session_history.stopped, "unixepoch", "localtime") ' \
' >= datetime("now", "-%s days", "localtime") ' \
' AND session_history.media_type = "movie" ' \
' AND session_history.media_type = "movie" %s ' \
' GROUP BY %s) AS t ' \
'GROUP BY t.full_title ' \
'ORDER BY %s DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
'LIMIT %s ' % (time_range, library_cond, group_by, sort_type, stats_count)
result = monitor_db.select(query)
except Exception as e:
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: top_movies: %s." % e)
@ -291,9 +315,10 @@ class DataFactory(object):
'row_id': item['id']
}
top_movies.append(row)
home_stats.append({'stat_id': stat,
'stat_type': sort_type,
'rows': helpers.filter_session_info(top_movies, 'section_id')})
'rows': session.mask_session_info(top_movies, mask_metadata=True)})
elif stat == 'popular_movies':
popular_movies = []
@ -308,11 +333,11 @@ class DataFactory(object):
' JOIN session_history_metadata ON session_history_metadata.id = session_history.id ' \
' WHERE datetime(session_history.stopped, "unixepoch", "localtime") ' \
' >= datetime("now", "-%s days", "localtime") ' \
' AND session_history.media_type = "movie" ' \
' AND session_history.media_type = "movie" %s ' \
' GROUP BY %s) AS t ' \
'GROUP BY t.full_title ' \
'ORDER BY users_watched DESC, %s DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
'LIMIT %s ' % (time_range, library_cond, group_by, sort_type, stats_count)
result = monitor_db.select(query)
except Exception as e:
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: popular_movies: %s." % e)
@ -336,7 +361,7 @@ class DataFactory(object):
popular_movies.append(row)
home_stats.append({'stat_id': stat,
'rows': helpers.filter_session_info(popular_movies, 'section_id')})
'rows': session.mask_session_info(popular_movies, mask_metadata=True)})
elif stat == 'top_music':
top_music = []
@ -350,11 +375,11 @@ class DataFactory(object):
' JOIN session_history_metadata ON session_history_metadata.id = session_history.id ' \
' WHERE datetime(session_history.stopped, "unixepoch", "localtime") ' \
' >= datetime("now", "-%s days", "localtime") ' \
' AND session_history.media_type = "track" ' \
' AND session_history.media_type = "track" %s ' \
' GROUP BY %s) AS t ' \
'GROUP BY t.grandparent_title ' \
'ORDER BY %s DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
'LIMIT %s ' % (time_range, library_cond, group_by, sort_type, stats_count)
result = monitor_db.select(query)
except Exception as e:
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: top_music: %s." % e)
@ -380,7 +405,7 @@ class DataFactory(object):
home_stats.append({'stat_id': stat,
'stat_type': sort_type,
'rows': helpers.filter_session_info(top_music, 'section_id')})
'rows': session.mask_session_info(top_music, mask_metadata=True)})
elif stat == 'popular_music':
popular_music = []
@ -395,11 +420,11 @@ class DataFactory(object):
' JOIN session_history_metadata ON session_history_metadata.id = session_history.id ' \
' WHERE datetime(session_history.stopped, "unixepoch", "localtime") ' \
' >= datetime("now", "-%s days", "localtime") ' \
' AND session_history.media_type = "track" ' \
' AND session_history.media_type = "track" %s ' \
' GROUP BY %s) AS t ' \
'GROUP BY t.grandparent_title ' \
'ORDER BY users_watched DESC, %s DESC ' \
'LIMIT %s ' % (time_range, group_by, sort_type, stats_count)
'LIMIT %s ' % (time_range, library_cond, group_by, sort_type, stats_count)
result = monitor_db.select(query)
except Exception as e:
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: popular_music: %s." % e)
@ -423,7 +448,7 @@ class DataFactory(object):
popular_music.append(row)
home_stats.append({'stat_id': stat,
'rows': helpers.filter_session_info(popular_music, 'section_id')})
'rows': session.mask_session_info(popular_music, mask_metadata=True)})
elif stat == 'top_users':
top_users = []
@ -476,7 +501,7 @@ class DataFactory(object):
home_stats.append({'stat_id': stat,
'stat_type': sort_type,
'rows': helpers.mask_session_info(top_users)})
'rows': session.mask_session_info(top_users, mask_metadata=True)})
elif stat == 'top_platforms':
top_platform = []
@ -522,13 +547,13 @@ class DataFactory(object):
home_stats.append({'stat_id': stat,
'stat_type': sort_type,
'rows': top_platform})
'rows': session.mask_session_info(top_platform, mask_metadata=True)})
elif stat == 'last_watched':
last_watched = []
try:
query = 'SELECT t.id, t.full_title, t.rating_key, t.thumb, t.grandparent_thumb, ' \
't.user, t.user_id, t.custom_avatar_url as user_thumb, t.player, ' \
't.user, t.user_id, t.custom_avatar_url as user_thumb, t.player, t.section_id, ' \
'(CASE WHEN t.friendly_name IS NULL THEN t.username ELSE t.friendly_name END) ' \
' AS friendly_name, ' \
'MAX(t.started) AS last_watch, ' \
@ -541,12 +566,12 @@ class DataFactory(object):
' WHERE datetime(session_history.stopped, "unixepoch", "localtime") ' \
' >= datetime("now", "-%s days", "localtime") ' \
' AND (session_history.media_type = "movie" ' \
' OR session_history_metadata.media_type = "episode") ' \
' OR session_history_metadata.media_type = "episode") %s ' \
' GROUP BY %s) AS t ' \
'WHERE percent_complete >= %s ' \
'GROUP BY t.id ' \
'ORDER BY last_watch DESC ' \
'LIMIT %s' % (time_range, group_by, notify_watched_percent, stats_count)
'LIMIT %s' % (time_range, library_cond, group_by, notify_watched_percent, stats_count)
result = monitor_db.select(query)
except Exception as e:
logger.warn(u"PlexPy DataFactory :: Unable to execute database query for get_home_stats: last_watched: %s." % e)
@ -567,13 +592,14 @@ class DataFactory(object):
'rating_key': item['rating_key'],
'thumb': thumb,
'grandparent_thumb': item['grandparent_thumb'],
'section_id': item['section_id'],
'last_watch': item['last_watch'],
'player': item['player']
}
last_watched.append(row)
home_stats.append({'stat_id': stat,
'rows': helpers.filter_session_info(last_watched, 'user_id')})
'rows': session.mask_session_info(last_watched, mask_metadata=True)})
elif stat == 'most_concurrent':
@ -692,19 +718,24 @@ class DataFactory(object):
}
library_stats.append(library)
return helpers.filter_session_info(library_stats, 'section_id')
return session.filter_session_info(library_stats, 'section_id')
def get_stream_details(self, row_id=None):
monitor_db = database.MonitorDatabase()
user_cond = ''
if session.get_session_user_id():
user_cond = 'AND session_history.user_id = %s ' % session.get_session_user_id()
if row_id:
query = 'SELECT container, bitrate, video_resolution, width, height, aspect_ratio, video_framerate, ' \
'video_codec, audio_codec, audio_channels, video_decision, transcode_video_codec, transcode_height, ' \
'transcode_width, audio_decision, transcode_audio_codec, transcode_audio_channels, media_type, ' \
'title, grandparent_title ' \
'from session_history_media_info ' \
'join session_history_metadata on session_history_media_info.id = session_history_metadata.id ' \
'where session_history_media_info.id = ?'
'transcode_width, audio_decision, transcode_audio_codec, transcode_audio_channels, ' \
'session_history_metadata.media_type, title, grandparent_title ' \
'FROM session_history_media_info ' \
'JOIN session_history ON session_history_media_info.id = session_history.id ' \
'JOIN session_history_metadata ON session_history_media_info.id = session_history_metadata.id ' \
'WHERE session_history_media_info.id = ? %s' % user_cond
result = monitor_db.select(query, args=[row_id])
else:
return None

View file

@ -89,15 +89,14 @@ class DataTables(object):
# Build custom where parameters
if custom_where:
for w in custom_where:
if isinstance(w[1], (list, tuple)) and len(w[1]):
c_where += '('
for w_ in w[1]:
c_where += w[0] + ' = ? OR '
args.append(w_)
c_where = c_where.rstrip(' OR ') + ') AND '
else:
c_where += w[0] + ' = ? AND '
# The order of our args changes if we are grouping
#if grouping:
# args.insert(0, w[1])
#else:
# args.append(w[1])
# My testing shows that order of args doesn't change
args.append(w[1])
if c_where:

View file

@ -564,103 +564,3 @@ def uploadToImgur(imgPath, imgTitle=''):
logger.warn(u"PlexPy Helpers :: Unable to upload image to Imgur: %s" % e)
return img_url
def allow_session_user(user_id):
"""
Returns True or False if the user_id is allowed for the user session
"""
import cherrypy
from plexpy.webauth import SESSION_KEY
if cherrypy.config.get('tools.auth.on'):
_session = cherrypy.session.get(SESSION_KEY)
if str(user_id) != _session['user_id']:
return False
return True
def allow_session_library(section_id):
"""
Returns True or False if the section_id is allowed for the user session
"""
import cherrypy
from plexpy.webauth import SESSION_KEY
if cherrypy.config.get('tools.auth.on'):
_session = cherrypy.session.get(SESSION_KEY)
if str(section_id) not in _session['user_libraries']:
return False
return True
def filter_session_info(list_of_dicts, filter_key=None):
"""
Filters a list of dictionary items to only return the info for the current logged in user
"""
import cherrypy
from plexpy.webauth import SESSION_KEY
if cherrypy.config.get('tools.auth.on'):
_session = cherrypy.session.get(SESSION_KEY)
if filter_key == 'user_id' and _session['user_id']:
session_user_id = str(_session['user_id'])
return [d for d in list_of_dicts if str(d.get('user_id','')) == session_user_id]
elif filter_key == 'section_id' and _session['user_libraries']:
session_library_ids = _session['user_libraries']
return [d for d in list_of_dicts if str(d.get('section_id','')) in session_library_ids]
return list_of_dicts
def mask_session_info(list_of_dicts, mask_metadata=False):
"""
Masks user info in a list of dictionary items to only display info for the current logged in user
"""
import cherrypy
from plexpy.webauth import SESSION_KEY
if cherrypy.config.get('tools.auth.on'):
_session = cherrypy.session.get(SESSION_KEY)
keys_to_mask = {'user_id': '',
'user': '',
'friendly_name': 'Plex User',
'user_thumb': common.DEFAULT_USER_THUMB,
'ip_address': 'N/A',
'machine_id': ''
}
metadata_to_mask = {'media_index': '',
'parent_media_index': '',
'art': common.DEFAULT_ART,
'parent_thumb': common.DEFAULT_POSTER_THUMB,
'grandparent_thumb': common.DEFAULT_POSTER_THUMB,
'thumb': common.DEFAULT_POSTER_THUMB,
'bif_thumb': '',
'grandparent_title': '',
'parent_title': '',
'title': '',
'rating_key': '',
'parent_rating_key': '',
'grandparent_rating_key': '',
'year': ''
}
if _session['user_id']:
session_user_id = str(_session['user_id'])
session_library_ids = _session['user_libraries']
for d in list_of_dicts:
if not (str(d.get('user_id')) == session_user_id or d.get('user') == _session['user']):
for k, v in keys_to_mask.iteritems():
if k in d: d[k] = keys_to_mask[k]
if mask_metadata and str(d.get('section_id','')) not in session_library_ids:
for k, v in metadata_to_mask.iteritems():
if k in d: d[k] = metadata_to_mask[k]
return list_of_dicts
return list_of_dicts

View file

@ -13,8 +13,8 @@
# You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
from plexpy import logger, datatables, common, database, helpers
import plexpy
from plexpy import logger, datatables, common, database, helpers, session
def update_section_ids():
from plexpy import pmsconnect, activity_pinger
@ -119,9 +119,18 @@ class Libraries(object):
pass
def get_datatables_list(self, kwargs=None):
default_return = {'recordsFiltered': 0,
'recordsTotal': 0,
'draw': 0,
'data': 'null',
'error': 'Unable to execute database query.'}
data_tables = datatables.DataTables()
custom_where = ['library_sections.deleted_section', 0]
custom_where = [['library_sections.deleted_section', 0]]
if session.get_session_libraries():
custom_where.append(['library_sections.section_id', session.get_session_libraries()])
columns = ['library_sections.section_id',
'library_sections.section_name',
@ -155,7 +164,7 @@ class Libraries(object):
try:
query = data_tables.ssp_query(table_name='library_sections',
columns=columns,
custom_where=[custom_where],
custom_where=custom_where,
group_by=['library_sections.server_id', 'library_sections.section_id'],
join_types=['LEFT OUTER JOIN',
'LEFT OUTER JOIN',
@ -169,11 +178,7 @@ class Libraries(object):
kwargs=kwargs)
except Exception as e:
logger.warn(u"PlexPy Libraries :: Unable to execute database query for get_list: %s." % e)
return {'recordsFiltered': 0,
'recordsTotal': 0,
'draw': 0,
'data': 'null',
'error': 'Unable to execute database query.'}
return default_return
result = query['result']
@ -222,7 +227,7 @@ class Libraries(object):
dict = {'recordsFiltered': query['filteredCount'],
'recordsTotal': query['totalCount'],
'data': helpers.filter_session_info(rows, 'section_id'),
'data': rows,
'draw': query['draw']
}
@ -235,9 +240,12 @@ class Libraries(object):
default_return = {'recordsFiltered': 0,
'recordsTotal': 0,
'draw': 0,
'data': None,
'data': 'null',
'error': 'Unable to execute database query.'}
if not session.allow_session_library(section_id):
return default_return
if section_id and not str(section_id).isdigit():
logger.warn(u"PlexPy Libraries :: Datatable media info called by invalid section_id provided.")
return default_return
@ -443,6 +451,9 @@ class Libraries(object):
from plexpy import pmsconnect
import json, os
if not session.allow_session_library(section_id):
return False
if section_id and not str(section_id).isdigit():
logger.warn(u"PlexPy Libraries :: Datatable media info file size called by invalid section_id provided.")
return False
@ -619,6 +630,9 @@ class Libraries(object):
return default_return
def get_watch_time_stats(self, section_id=None):
if not session.allow_session_library(section_id):
return []
monitor_db = database.MonitorDatabase()
time_queries = [1, 7, 30, 0]
@ -671,6 +685,9 @@ class Libraries(object):
return library_watch_time_stats
def get_user_stats(self, section_id=None):
if not session.allow_session_library(section_id):
return []
monitor_db = database.MonitorDatabase()
user_stats = []
@ -678,7 +695,7 @@ class Libraries(object):
try:
if str(section_id).isdigit():
query = 'SELECT (CASE WHEN users.friendly_name IS NULL THEN users.username ' \
'ELSE users.friendly_name END) AS user, users.user_id, users.thumb, COUNT(user) AS user_count ' \
'ELSE users.friendly_name END) AS friendly_name, users.user_id, users.thumb, COUNT(user) AS user_count ' \
'FROM session_history ' \
'JOIN session_history_metadata ON session_history_metadata.id = session_history.id ' \
'JOIN users ON users.user_id = session_history.user_id ' \
@ -693,16 +710,19 @@ class Libraries(object):
result = []
for item in result:
row = {'user': item['user'],
row = {'friendly_name': item['friendly_name'],
'user_id': item['user_id'],
'thumb': item['thumb'],
'user_thumb': item['thumb'],
'total_plays': item['user_count']
}
user_stats.append(row)
return helpers.filter_session_info(user_stats, 'user_id')
return session.mask_session_info(user_stats)
def get_recently_watched(self, section_id=None, limit='10'):
if not session.allow_session_library(section_id):
return []
monitor_db = database.MonitorDatabase()
recently_watched = []

View file

@ -16,14 +16,13 @@
# You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
from plexpy import logger, helpers, http_handler, database, users
import xmltodict
import json
from xml.dom import minidom
import requests
import base64
import json
import xmltodict
from xml.dom import minidom
import plexpy
from plexpy import logger, helpers, http_handler, database, users, session
def refresh_users():
@ -401,7 +400,7 @@ class PlexTV(object):
synced_items.append(sync_details)
return helpers.filter_session_info(synced_items, 'user_id')
return session.filter_session_info(synced_items, 'user_id')
def get_server_urls(self, include_https=True):

View file

@ -13,11 +13,11 @@
# You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
from plexpy import logger, helpers, users, http_handler, common, database
import urllib2
from urlparse import urlparse
import plexpy
import urllib2
from plexpy import logger, helpers, users, http_handler, common, database, session
def get_server_friendly_name():
@ -462,7 +462,7 @@ class PmsConnect(object):
'grandparent_title': helpers.get_xml_attr(item, 'grandparentTitle'),
'media_index': helpers.get_xml_attr(item, 'index'),
'parent_media_index': helpers.get_xml_attr(item, 'parentIndex'),
'section_id': helpers.get_xml_attr(item, 'librarySectionID'),
'section_id': section_id if section_id else helpers.get_xml_attr(item, 'librarySectionID'),
'library_name': helpers.get_xml_attr(item, 'librarySectionTitle'),
'year': helpers.get_xml_attr(item, 'year'),
'thumb': helpers.get_xml_attr(item, 'thumb'),
@ -484,7 +484,7 @@ class PmsConnect(object):
'grandparent_title': helpers.get_xml_attr(item, 'grandparentTitle'),
'media_index': helpers.get_xml_attr(item, 'index'),
'parent_media_index': helpers.get_xml_attr(item, 'parentIndex'),
'section_id': helpers.get_xml_attr(item, 'librarySectionID'),
'section_id': section_id if section_id else helpers.get_xml_attr(item, 'librarySectionID'),
'library_name': helpers.get_xml_attr(item, 'librarySectionTitle'),
'year': helpers.get_xml_attr(item, 'year'),
'thumb': helpers.get_xml_attr(item, 'thumb'),
@ -494,8 +494,9 @@ class PmsConnect(object):
}
recents_list.append(recent_items)
output = {'recently_added': helpers.filter_session_info(
output = {'recently_added': session.filter_session_info(
sorted(recents_list, key=lambda k: k['added_at'], reverse=True), 'section_id')}
return output
def get_metadata_details(self, rating_key='', get_media_info=False):
@ -975,7 +976,7 @@ class PmsConnect(object):
session_list.append(session_output)
output = {'stream_count': helpers.get_xml_attr(xml_head[0], 'size'),
'sessions': helpers.mask_session_info(session_list, True)
'sessions': session.mask_session_info(session_list, True)
}
return output

150
plexpy/session.py Normal file
View file

@ -0,0 +1,150 @@
# This file is part of PlexPy.
#
# PlexPy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# PlexPy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
import cherrypy
from plexpy import common
def get_session_info():
"""
Returns the session info for the user session
"""
from plexpy.webauth import SESSION_KEY
if cherrypy.config.get('tools.auth.on'):
_session = cherrypy.session.get(SESSION_KEY)
if _session:
return _session
return {'user_id': None,
'user': None,
'user_group': 'admin',
'user_libraries': None,
'expiry': None}
def get_session_user():
"""
Returns the user_id for the current logged in session
"""
_session = get_session_info()
return _session['user']
def get_session_user_id():
"""
Returns the user_id for the current logged in session
"""
_session = get_session_info()
return str(_session['user_id']) if _session['user_id'] else None
def get_session_libraries():
"""
Returns a tuple of section_id for the current logged in session
"""
_session = get_session_info()
return _session['user_libraries']
def allow_session_user(user_id):
"""
Returns True or False if the user_id is allowed for the current logged in session
"""
session_user_id = get_session_user_id()
if session_user_id and str(user_id) != session_user_id:
return False
return True
def allow_session_library(section_id):
"""
Returns True or False if the section_id is allowed for the current logged in session
"""
session_library_ids = get_session_libraries()
if session_library_ids and str(section_id) not in session_library_ids:
return False
return True
def filter_session_info(list_of_dicts, filter_key=None):
"""
Filters a list of dictionary items to only return the info for the current logged in session
"""
session_user_id = get_session_user_id()
session_library_ids = get_session_libraries()
list_of_dicts = friendly_name_to_username(list_of_dicts)
if filter_key == 'user_id' and session_user_id:
return [d for d in list_of_dicts if str(d.get('user_id','')) == session_user_id]
elif filter_key == 'section_id' and session_library_ids:
return [d for d in list_of_dicts if str(d.get('section_id','')) in session_library_ids]
return list_of_dicts
def mask_session_info(list_of_dicts, mask_metadata=False):
"""
Masks user info in a list of dictionary items to only display info for the current logged in session
"""
session_user = get_session_user()
session_user_id = get_session_user_id()
session_library_ids = get_session_libraries()
keys_to_mask = {'user_id': '',
'user': 'Plex User',
'friendly_name': 'Plex User',
'user_thumb': common.DEFAULT_USER_THUMB,
'ip_address': 'N/A',
'machine_id': '',
'player': 'Player'
}
metadata_to_mask = {'media_index': '',
'parent_media_index': '',
'art': common.DEFAULT_ART,
'parent_thumb': common.DEFAULT_POSTER_THUMB,
'grandparent_thumb': common.DEFAULT_POSTER_THUMB,
'thumb': common.DEFAULT_POSTER_THUMB,
'bif_thumb': '',
'grandparent_title': '',
'parent_title': '',
'title': '',
'rating_key': '',
'parent_rating_key': '',
'grandparent_rating_key': '',
'year': ''
}
list_of_dicts = friendly_name_to_username(list_of_dicts)
for d in list_of_dicts:
if session_user_id and not (str(d.get('user_id')) == session_user_id or d.get('user') == session_user):
for k, v in keys_to_mask.iteritems():
if k in d: d[k] = keys_to_mask[k]
if mask_metadata and session_library_ids and str(d.get('section_id','')) not in session_library_ids:
for k, v in metadata_to_mask.iteritems():
if k in d: d[k] = metadata_to_mask[k]
return list_of_dicts
def friendly_name_to_username(list_of_dicts):
"""
Reverts the friendly name back to the username of the current logged in session
"""
session_user = get_session_user()
for d in list_of_dicts:
if 'friendly_name' in d and d['friendly_name'] != session_user:
d['friendly_name'] = session_user
return list_of_dicts

View file

@ -13,7 +13,8 @@
# You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
from plexpy import logger, datatables, common, database, helpers
import plexpy
from plexpy import logger, datatables, common, database, helpers, session
def user_login(username=None, password=None):
from plexpy import plextv
@ -85,9 +86,18 @@ class Users(object):
pass
def get_datatables_list(self, kwargs=None):
default_return = {'recordsFiltered': 0,
'recordsTotal': 0,
'draw': 0,
'data': 'null',
'error': 'Unable to execute database query.'}
data_tables = datatables.DataTables()
custom_where = ['users.deleted_user', 0]
custom_where = [['users.deleted_user', 0]]
if session.get_session_user_id():
custom_where.append(['users.user_id', session.get_session_user_id()])
columns = ['users.user_id',
'(CASE WHEN users.friendly_name IS NULL OR TRIM(users.friendly_name) = "" \
@ -121,7 +131,7 @@ class Users(object):
try:
query = data_tables.ssp_query(table_name='users',
columns=columns,
custom_where=[custom_where],
custom_where=custom_where,
group_by=['users.user_id'],
join_types=['LEFT OUTER JOIN',
'LEFT OUTER JOIN',
@ -135,11 +145,7 @@ class Users(object):
kwargs=kwargs)
except Exception as e:
logger.warn(u"PlexPy Users :: Unable to execute database query for get_list: %s." % e)
return {'recordsFiltered': 0,
'recordsTotal': 0,
'draw': 0,
'data': 'null',
'error': 'Unable to execute database query.'}
return default_return
users = query['result']
@ -190,13 +196,22 @@ class Users(object):
dict = {'recordsFiltered': query['filteredCount'],
'recordsTotal': query['totalCount'],
'data': helpers.filter_session_info(rows, 'user_id'),
'data': session.friendly_name_to_username(rows),
'draw': query['draw']
}
return dict
def get_datatables_unique_ips(self, user_id=None, kwargs=None):
default_return = {'recordsFiltered': 0,
'recordsTotal': 0,
'draw': 0,
'data': 'null',
'error': 'Unable to execute database query.'}
if not session.allow_session_user(user_id):
return default_return
data_tables = datatables.DataTables()
custom_where = ['users.user_id', user_id]
@ -241,11 +256,7 @@ class Users(object):
kwargs=kwargs)
except Exception as e:
logger.warn(u"PlexPy Users :: Unable to execute database query for get_unique_ips: %s." % e)
return {'recordsFiltered': 0,
'recordsTotal': 0,
'draw': 0,
'data': 'null',
'error': 'Unable to execute database query.'}
return default_return
results = query['result']
@ -284,7 +295,7 @@ class Users(object):
dict = {'recordsFiltered': query['filteredCount'],
'recordsTotal': query['totalCount'],
'data': helpers.filter_session_info(rows, 'user_id'),
'data': session.friendly_name_to_username(rows),
'draw': query['draw']
}
@ -356,7 +367,9 @@ class Users(object):
user_details = {}
if result:
for item in result:
if item['friendly_name']:
if session.get_session_user():
friendly_name = session.get_session_user()
elif item['friendly_name']:
friendly_name = item['friendly_name']
else:
friendly_name = item['username']
@ -407,6 +420,9 @@ class Users(object):
return default_return
def get_watch_time_stats(self, user_id=None):
if not session.allow_session_user(user_id):
return []
monitor_db = database.MonitorDatabase()
time_queries = [1, 7, 30, 0]
@ -457,6 +473,9 @@ class Users(object):
return user_watch_time_stats
def get_player_stats(self, user_id=None):
if not session.allow_session_user(user_id):
return []
monitor_db = database.MonitorDatabase()
player_stats = []
@ -491,6 +510,9 @@ class Users(object):
return player_stats
def get_recently_watched(self, user_id=None, limit='10'):
if not session.allow_session_user(user_id):
return []
monitor_db = database.MonitorDatabase()
recently_watched = []

View file

@ -13,32 +13,24 @@
# You should have received a copy of the GNU General Public License
# along with PlexPy. If not, see <http://www.gnu.org/licenses/>.
from plexpy import logger, notifiers, plextv, pmsconnect, common, log_reader, \
datafactory, graphs, users, libraries, database, web_socket
from plexpy.helpers import checked, addtoapi, get_ip, create_https_certificates
from plexpy.webauth import AuthController, requireAuth, member_of, name_is, SESSION_KEY
from mako.lookup import TemplateLookup
from mako import exceptions
from hashing_passwords import make_hash
import plexpy
import threading
import cherrypy
import hashlib
import random
import json
import os
from api2 import API2
import random
import threading
try:
# pylint:disable=E0611
# ignore this error because we are catching the ImportError
from collections import OrderedDict
# pylint:enable=E0611
except ImportError:
# Python 2.6.x fallback, from libs
from ordereddict import OrderedDict
from hashing_passwords import make_hash
from mako.lookup import TemplateLookup
from mako import exceptions
import plexpy
from plexpy import logger, notifiers, plextv, pmsconnect, common, log_reader, \
datafactory, graphs, users, libraries, database, web_socket
from plexpy.api2 import API2
from plexpy.helpers import checked, addtoapi, get_ip, create_https_certificates
from plexpy.session import get_session_info, allow_session_user, allow_session_library
from plexpy.webauth import AuthController, requireAuth, member_of, name_is, SESSION_KEY
def serve_template(templatename, **kwargs):
@ -49,13 +41,7 @@ def serve_template(templatename, **kwargs):
server_name = plexpy.CONFIG.PMS_NAME
_session = {'user_id': None,
'user': None,
'user_group': 'admin',
'expiry': None}
if cherrypy.config.get('tools.auth.on'):
_session = cherrypy.session.get(SESSION_KEY)
_session = get_session_info()
try:
template = _hplookup.get_template(templatename)
@ -351,6 +337,9 @@ class WebInterface(object):
@cherrypy.expose
@requireAuth()
def library(self, section_id=None):
if not allow_session_library(section_id):
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
config = {
"get_file_sizes": plexpy.CONFIG.GET_FILE_SIZES,
"get_file_sizes_hold": plexpy.CONFIG.GET_FILE_SIZES_HOLD
@ -409,6 +398,9 @@ class WebInterface(object):
@cherrypy.expose
@requireAuth()
def get_library_watch_time_stats(self, section_id=None, **kwargs):
if not allow_session_library(section_id):
return serve_template(templatename="user_watch_time_stats.html", data=None, title="Watch Stats")
if section_id:
library_data = libraries.Libraries()
result = library_data.get_watch_time_stats(section_id=section_id)
@ -424,6 +416,9 @@ class WebInterface(object):
@cherrypy.expose
@requireAuth()
def get_library_user_stats(self, section_id=None, **kwargs):
if not allow_session_library(section_id):
return serve_template(templatename="library_user_stats.html", data=None, title="Player Stats")
if section_id:
library_data = libraries.Libraries()
result = library_data.get_user_stats(section_id=section_id)
@ -439,6 +434,9 @@ class WebInterface(object):
@cherrypy.expose
@requireAuth()
def get_library_recently_watched(self, section_id=None, limit='10', **kwargs):
if not allow_session_library(section_id):
return serve_template(templatename="user_recently_watched.html", data=None, title="Recently Watched")
if section_id:
library_data = libraries.Libraries()
result = library_data.get_recently_watched(section_id=section_id, limit=limit)
@ -454,6 +452,9 @@ class WebInterface(object):
@cherrypy.expose
@requireAuth()
def get_library_recently_added(self, section_id=None, limit='10', **kwargs):
if not allow_session_library(section_id):
return serve_template(templatename="library_recently_added.html", data=None, title="Recently Added")
if section_id:
pms_connect = pmsconnect.PmsConnect()
result = pms_connect.get_recently_added_details(section_id=section_id, count=limit)
@ -649,6 +650,9 @@ class WebInterface(object):
@cherrypy.expose
@requireAuth()
def user(self, user_id=None):
if not allow_session_user(user_id):
raise cherrypy.HTTPRedirect(plexpy.HTTP_ROOT)
user_data = users.Users()
if user_id:
try:
@ -702,6 +706,9 @@ class WebInterface(object):
@cherrypy.expose
@requireAuth()
def get_user_watch_time_stats(self, user=None, user_id=None, **kwargs):
if not allow_session_user(user_id):
return serve_template(templatename="user_watch_time_stats.html", data=None, title="Watch Stats")
if user_id or user:
user_data = users.Users()
result = user_data.get_watch_time_stats(user_id=user_id)
@ -717,6 +724,9 @@ class WebInterface(object):
@cherrypy.expose
@requireAuth()
def get_user_player_stats(self, user=None, user_id=None, **kwargs):
if not allow_session_user(user_id):
return serve_template(templatename="user_player_stats.html", data=None, title="Player Stats")
if user_id or user:
user_data = users.Users()
result = user_data.get_player_stats(user_id=user_id)
@ -732,6 +742,9 @@ class WebInterface(object):
@cherrypy.expose
@requireAuth()
def get_user_recently_watched(self, user=None, user_id=None, limit='10', **kwargs):
if not allow_session_user(user_id):
return serve_template(templatename="user_recently_watched.html", data=None, title="Recently Watched")
if user_id or user:
user_data = users.Users()
result = user_data.get_recently_watched(user_id=user_id, limit=limit)
@ -1242,7 +1255,7 @@ class WebInterface(object):
message,
file.rpartition('/')[-1].partition('?')[0],
line))
return True
return "js error logged."
@cherrypy.expose
@requireAuth(member_of("admin"))