plexpy/plexpy/users.py
2024-05-09 22:43:57 -07:00

1023 lines
44 KiB
Python

# -*- coding: utf-8 -*-
# This file is part of Tautulli.
#
# Tautulli 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.
#
# Tautulli 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 Tautulli. If not, see <http://www.gnu.org/licenses/>.
from urllib.parse import parse_qsl
import arrow
import httpagentparser
import plexpy
from plexpy import common
from plexpy import database
from plexpy import datatables
from plexpy import helpers
from plexpy import libraries
from plexpy import logger
from plexpy import plextv
from plexpy import session
def refresh_users():
logger.info("Tautulli Users :: Requesting users list refresh...")
result = plextv.PlexTV().get_full_users_list()
server_id = plexpy.CONFIG.PMS_IDENTIFIER
if not server_id:
logger.error("Tautulli Users :: No PMS identifier, cannot refresh users. Verify server in settings.")
return
if result:
monitor_db = database.MonitorDatabase()
# Keep track of user_id to update is_active status
user_ids = [0] # Local user always considered active
new_users = []
for item in result:
if item.get('shared_libraries'):
item['shared_libraries'] = ';'.join(item['shared_libraries'])
# Only append user if libraries are shared
user_ids.append(helpers.cast_to_int(item['user_id']))
elif item.get('server_token'):
libs = libraries.Libraries().get_sections()
item['shared_libraries'] = ';'.join([str(l['section_id']) for l in libs])
# Only append user if libraries are shared
user_ids.append(helpers.cast_to_int(item['user_id']))
keys_dict = {"user_id": item.pop('user_id')}
# Check if we've set a custom avatar if so don't overwrite it.
if keys_dict['user_id']:
avatar_urls = monitor_db.select("SELECT thumb, custom_avatar_url "
"FROM users WHERE user_id = ?",
[keys_dict['user_id']])
if avatar_urls:
if not avatar_urls[0]['custom_avatar_url'] or \
avatar_urls[0]['custom_avatar_url'] == avatar_urls[0]['thumb']:
item['custom_avatar_url'] = item['thumb']
else:
item['custom_avatar_url'] = item['thumb']
# Check if title is the same as the username
if item['title'] == item['username']:
item['title'] = None
# Check if username is blank (Managed Users)
if not item['username']:
item['username'] = item['title']
result = monitor_db.upsert('users', key_dict=keys_dict, value_dict=item)
if result == 'insert':
new_users.append(item['username'])
query = "UPDATE users SET is_active = 0 WHERE user_id NOT IN ({})".format(", ".join(["?"] * len(user_ids)))
monitor_db.action(query=query, args=user_ids)
# Add new users to logger username filter
logger.filter_usernames(new_users)
logger.info("Tautulli Users :: Users list refreshed.")
return True
else:
logger.warn("Tautulli Users :: Unable to refresh users list.")
return False
class Users(object):
def __init__(self):
pass
def get_datatables_list(self, kwargs=None, grouping=None):
default_return = {'recordsFiltered': 0,
'recordsTotal': 0,
'draw': 0,
'data': []}
data_tables = datatables.DataTables()
custom_where = [['users.deleted_user', 0]]
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
if session.get_session_user_id():
custom_where.append(['users.user_id', session.get_session_user_id()])
if kwargs.get('user_id'):
custom_where.append(['users.user_id', kwargs.get('user_id')])
group_by = 'session_history.reference_id' if grouping else 'session_history.id'
columns = ["users.id AS row_id",
"users.user_id",
"users.username",
"(CASE WHEN users.friendly_name IS NULL OR TRIM(users.friendly_name) = '' \
THEN users.username ELSE users.friendly_name END) AS friendly_name",
"users.title",
"users.email",
"users.thumb AS user_thumb",
"users.custom_avatar_url AS custom_thumb",
"COUNT(DISTINCT %s) AS plays" % group_by,
"SUM(CASE WHEN session_history.stopped > 0 THEN (session_history.stopped - session_history.started) \
ELSE 0 END) - SUM(CASE WHEN session_history.paused_counter IS NULL THEN 0 ELSE \
session_history.paused_counter END) AS duration",
"MAX(session_history.started) AS last_seen",
"MAX(session_history.id) AS history_row_id",
"session_history_metadata.full_title AS last_played",
"session_history.ip_address",
"session_history.platform",
"session_history.player",
"session_history.rating_key",
"session_history_metadata.media_type",
"session_history_metadata.thumb",
"session_history_metadata.parent_thumb",
"session_history_metadata.grandparent_thumb",
"session_history_metadata.parent_title",
"session_history_metadata.year",
"session_history_metadata.media_index",
"session_history_metadata.parent_media_index",
"session_history_metadata.live",
"session_history_metadata.added_at",
"session_history_metadata.originally_available_at",
"session_history_metadata.guid",
"session_history_media_info.transcode_decision",
"users.do_notify AS do_notify",
"users.keep_history AS keep_history",
"users.allow_guest AS allow_guest",
"users.is_active AS is_active"
]
try:
query = data_tables.ssp_query(table_name='users',
columns=columns,
custom_where=custom_where,
group_by=['users.user_id'],
join_types=['LEFT OUTER JOIN',
'LEFT OUTER JOIN',
'LEFT OUTER JOIN'],
join_tables=['session_history',
'session_history_metadata',
'session_history_media_info'],
join_evals=[['session_history.user_id', 'users.user_id'],
['session_history.id', 'session_history_metadata.id'],
['session_history.id', 'session_history_media_info.id']],
kwargs=kwargs)
except Exception as e:
logger.warn("Tautulli Users :: Unable to execute database query for get_list: %s." % e)
return default_return
users = query['result']
rows = []
for item in users:
if item['media_type'] == 'episode' and item['parent_thumb']:
thumb = item['parent_thumb']
elif item['media_type'] == 'episode':
thumb = item['grandparent_thumb']
else:
thumb = item['thumb']
if item['custom_thumb'] and item['custom_thumb'] != item['user_thumb']:
user_thumb = item['custom_thumb']
elif item['user_thumb']:
user_thumb = item['user_thumb']
else:
user_thumb = common.DEFAULT_USER_THUMB
# Rename Mystery platform names
platform = common.PLATFORM_NAME_OVERRIDES.get(item['platform'], item['platform'])
row = {'row_id': item['row_id'],
'user_id': item['user_id'],
'username': item['username'],
'friendly_name': item['friendly_name'],
'title': item['title'],
'email': item['email'],
'user_thumb': user_thumb,
'plays': item['plays'],
'duration': item['duration'],
'last_seen': item['last_seen'],
'last_played': item['last_played'],
'history_row_id': item['history_row_id'],
'ip_address': item['ip_address'],
'platform': platform,
'player': item['player'],
'rating_key': item['rating_key'],
'media_type': item['media_type'],
'thumb': thumb,
'parent_title': item['parent_title'],
'year': item['year'],
'media_index': item['media_index'],
'parent_media_index': item['parent_media_index'],
'live': item['live'],
'originally_available_at': item['originally_available_at'],
'guid': item['guid'],
'transcode_decision': item['transcode_decision'],
'do_notify': item['do_notify'],
'keep_history': item['keep_history'],
'allow_guest': item['allow_guest'],
'is_active': item['is_active']
}
rows.append(row)
dict = {'recordsFiltered': query['filteredCount'],
'recordsTotal': query['totalCount'],
'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': []}
if not session.allow_session_user(user_id):
return default_return
data_tables = datatables.DataTables()
custom_where = ['users.user_id', user_id]
columns = ["session_history.id AS history_row_id",
"MIN(session_history.started) AS first_seen",
"MAX(session_history.started) AS last_seen",
"session_history.ip_address",
"COUNT(session_history.id) AS play_count",
"session_history.platform",
"session_history.player",
"session_history.rating_key",
"session_history_metadata.full_title AS last_played",
"session_history_metadata.thumb",
"session_history_metadata.parent_thumb",
"session_history_metadata.grandparent_thumb",
"session_history_metadata.media_type",
"session_history_metadata.parent_title",
"session_history_metadata.year",
"session_history_metadata.media_index",
"session_history_metadata.parent_media_index",
"session_history_metadata.live",
"session_history_metadata.added_at",
"session_history_metadata.originally_available_at",
"session_history_metadata.guid",
"session_history_media_info.transcode_decision",
"session_history.user",
"session_history.user_id as custom_user_id",
"(CASE WHEN users.friendly_name IS NULL OR TRIM(users.friendly_name) = '' \
THEN users.username ELSE users.friendly_name END) AS friendly_name"
]
try:
query = data_tables.ssp_query(table_name='session_history',
columns=columns,
custom_where=[custom_where],
group_by=['ip_address'],
join_types=['JOIN',
'JOIN',
'JOIN'],
join_tables=['users',
'session_history_metadata',
'session_history_media_info'],
join_evals=[['session_history.user_id', 'users.user_id'],
['session_history.id', 'session_history_metadata.id'],
['session_history.id', 'session_history_media_info.id']],
kwargs=kwargs)
except Exception as e:
logger.warn("Tautulli Users :: Unable to execute database query for get_unique_ips: %s." % e)
return default_return
results = query['result']
rows = []
for item in results:
if item["media_type"] == 'episode' and item["parent_thumb"]:
thumb = item["parent_thumb"]
elif item["media_type"] == 'episode':
thumb = item["grandparent_thumb"]
else:
thumb = item["thumb"]
# Rename Mystery platform names
platform = common.PLATFORM_NAME_OVERRIDES.get(item["platform"], item["platform"])
row = {'history_row_id': item['history_row_id'],
'last_seen': item['last_seen'],
'first_seen': item['first_seen'],
'ip_address': item['ip_address'],
'play_count': item['play_count'],
'platform': platform,
'player': item['player'],
'last_played': item['last_played'],
'rating_key': item['rating_key'],
'thumb': thumb,
'media_type': item['media_type'],
'parent_title': item['parent_title'],
'year': item['year'],
'media_index': item['media_index'],
'parent_media_index': item['parent_media_index'],
'live': item['live'],
'originally_available_at': item['originally_available_at'],
'guid': item['guid'],
'transcode_decision': item['transcode_decision'],
'friendly_name': item['friendly_name'],
'user_id': item['custom_user_id']
}
rows.append(row)
dict = {'recordsFiltered': query['filteredCount'],
'recordsTotal': query['totalCount'],
'data': session.friendly_name_to_username(rows),
'draw': query['draw']
}
return dict
def set_config(self, user_id=None, friendly_name='', custom_thumb='', do_notify=1, keep_history=1, allow_guest=1):
if str(user_id).isdigit():
monitor_db = database.MonitorDatabase()
user = monitor_db.select_single('SELECT username FROM users WHERE user_id = ?', [user_id])
if user.get('username') == friendly_name:
friendly_name = None
key_dict = {'user_id': user_id}
value_dict = {'friendly_name': friendly_name,
'custom_avatar_url': custom_thumb,
'do_notify': do_notify,
'keep_history': keep_history,
'allow_guest': allow_guest
}
try:
monitor_db.upsert('users', value_dict, key_dict)
except Exception as e:
logger.warn("Tautulli Users :: Unable to execute database query for set_config: %s." % e)
def get_details(self, user_id=None, user=None, email=None, include_last_seen=False):
default_return = {'row_id': 0,
'user_id': 0,
'username': 'Local',
'friendly_name': 'Local',
'user_thumb': common.DEFAULT_USER_THUMB,
'email': '',
'is_active': 1,
'is_admin': '',
'is_home_user': 0,
'is_allow_sync': 0,
'is_restricted': 0,
'do_notify': 0,
'keep_history': 1,
'allow_guest': 0,
'deleted_user': 0,
'shared_libraries': (),
'last_seen': None
}
if user_id in (None, '') and not user and not email:
return default_return
user_details = self.get_user_details(user_id=user_id, user=user, email=email,
include_last_seen=include_last_seen)
if user_details:
return user_details
else:
logger.warn("Tautulli Users :: Unable to retrieve user %s from database. Requesting user list refresh."
% user_id if user_id else user)
# Let's first refresh the user list to make sure the user isn't newly added and not in the db yet
refresh_users()
user_details = self.get_user_details(user_id=user_id, user=user, email=email,
include_last_seen=include_last_seen)
if user_details:
return user_details
else:
logger.warn("Tautulli Users :: Unable to retrieve user %s from database. Returning 'Local' user."
% user_id if user_id else user)
# If there is no user data we must return something
# Use "Local" user to retain compatibility with PlexWatch database value
return default_return
def get_user_details(self, user_id=None, user=None, email=None, include_last_seen=False):
last_seen = 'NULL'
join = ''
if include_last_seen:
last_seen = "MAX(session_history.started)"
join = "LEFT OUTER JOIN session_history ON users.user_id = session_history.user_id"
monitor_db = database.MonitorDatabase()
try:
if str(user_id).isdigit():
where = "users.user_id = ?"
args = [user_id]
elif user:
where = "users.username = ?"
args = [user]
elif email:
where = "users.email = ?"
args = [email]
else:
raise Exception("Missing user_id, username, or email")
query = "SELECT users.id AS row_id, users.user_id, username, friendly_name, " \
"thumb AS user_thumb, custom_avatar_url AS custom_thumb, " \
"email, is_active, is_admin, is_home_user, is_allow_sync, is_restricted, " \
"do_notify, keep_history, deleted_user, " \
"allow_guest, shared_libraries, %s AS last_seen " \
"FROM users %s " \
"WHERE %s COLLATE NOCASE" % (last_seen, join, where)
result = monitor_db.select(query, args=args)
except Exception as e:
logger.warn("Tautulli Users :: Unable to execute database query for get_user_details: %s." % e)
result = []
user_details = {}
if result:
for item in result:
if session.get_session_user_id():
friendly_name = session.get_session_user()
elif item['friendly_name']:
friendly_name = item['friendly_name']
else:
friendly_name = item['username']
if item['custom_thumb'] and item['custom_thumb'] != item['user_thumb']:
user_thumb = item['custom_thumb']
elif item['user_thumb']:
user_thumb = item['user_thumb']
else:
user_thumb = common.DEFAULT_USER_THUMB
shared_libraries = tuple(item['shared_libraries'].split(';')) if item['shared_libraries'] else ()
user_details = {'row_id': item['row_id'],
'user_id': item['user_id'],
'username': item['username'],
'friendly_name': friendly_name,
'user_thumb': user_thumb,
'email': item['email'],
'is_active': item['is_active'],
'is_admin': item['is_admin'],
'is_home_user': item['is_home_user'],
'is_allow_sync': item['is_allow_sync'],
'is_restricted': item['is_restricted'],
'do_notify': item['do_notify'],
'keep_history': item['keep_history'],
'deleted_user': item['deleted_user'],
'allow_guest': item['allow_guest'],
'shared_libraries': shared_libraries,
'last_seen': item['last_seen']
}
return user_details
def get_watch_time_stats(self, user_id=None, grouping=None, query_days=None):
if not session.allow_session_user(user_id):
return []
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
if query_days and query_days is not None:
query_days = map(helpers.cast_to_int, str(query_days).split(','))
else:
query_days = [1, 7, 30, 0]
timestamp = helpers.timestamp()
monitor_db = database.MonitorDatabase()
user_watch_time_stats = []
group_by = 'reference_id' if grouping else 'id'
for days in query_days:
timestamp_query = timestamp - days * 24 * 60 * 60
try:
if days > 0:
if str(user_id).isdigit():
query = "SELECT (SUM(stopped - started) - " \
" SUM(CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END)) AS total_time, " \
"COUNT(DISTINCT %s) AS total_plays " \
"FROM session_history " \
"WHERE stopped >= %s " \
"AND user_id = ? " % (group_by, timestamp_query)
result = monitor_db.select(query, args=[user_id])
else:
result = []
else:
if str(user_id).isdigit():
query = "SELECT (SUM(stopped - started) - " \
" SUM(CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END)) AS total_time, " \
"COUNT(DISTINCT %s) AS total_plays " \
"FROM session_history " \
"WHERE user_id = ? " % group_by
result = monitor_db.select(query, args=[user_id])
else:
result = []
except Exception as e:
logger.warn("Tautulli Users :: Unable to execute database query for get_watch_time_stats: %s." % e)
result = []
for item in result:
if item['total_time']:
total_time = item['total_time']
total_plays = item['total_plays']
else:
total_time = 0
total_plays = 0
row = {'query_days': days,
'total_time': total_time,
'total_plays': total_plays
}
user_watch_time_stats.append(row)
return user_watch_time_stats
def get_player_stats(self, user_id=None, grouping=None):
if not session.allow_session_user(user_id):
return []
if grouping is None:
grouping = plexpy.CONFIG.GROUP_HISTORY_TABLES
monitor_db = database.MonitorDatabase()
player_stats = []
result_id = 0
group_by = 'reference_id' if grouping else 'id'
try:
if str(user_id).isdigit():
query = "SELECT player, COUNT(DISTINCT %s) as total_plays, (SUM(stopped - started) - " \
"SUM(CASE WHEN paused_counter IS NULL THEN 0 ELSE paused_counter END)) AS total_time, " \
"platform " \
"FROM session_history " \
"WHERE user_id = ? " \
"GROUP BY player " \
"ORDER BY total_plays DESC, total_time DESC" % group_by
result = monitor_db.select(query, args=[user_id])
else:
result = []
except Exception as e:
logger.warn("Tautulli Users :: Unable to execute database query for get_player_stats: %s." % e)
result = []
for item in result:
# Rename Mystery platform names
platform = common.PLATFORM_NAME_OVERRIDES.get(item['platform'], item['platform'])
platform_name = next((v for k, v in common.PLATFORM_NAMES.items() if k in platform.lower()), 'default')
row = {'player_name': item['player'],
'platform': platform,
'platform_name': platform_name,
'total_plays': item['total_plays'],
'total_time': item['total_time'],
'result_id': result_id
}
player_stats.append(row)
result_id += 1
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 = []
if not limit.isdigit():
limit = '10'
try:
if str(user_id).isdigit():
query = "SELECT session_history.id, session_history.media_type, guid, " \
"session_history.rating_key, session_history.parent_rating_key, session_history.grandparent_rating_key, " \
"title, parent_title, grandparent_title, original_title, " \
"thumb, parent_thumb, grandparent_thumb, media_index, parent_media_index, " \
"year, originally_available_at, added_at, live, started, user " \
"FROM session_history_metadata " \
"JOIN session_history ON session_history_metadata.id = session_history.id " \
"WHERE user_id = ? " \
"GROUP BY (CASE WHEN session_history.media_type = 'track' THEN session_history.parent_rating_key " \
" ELSE session_history.rating_key END) " \
"ORDER BY MAX(started) DESC LIMIT ?"
result = monitor_db.select(query, args=[user_id, limit])
else:
result = []
except Exception as e:
logger.warn("Tautulli Users :: Unable to execute database query for get_recently_watched: %s." % e)
result = []
for row in result:
if row['media_type'] == 'episode' and row['parent_thumb']:
thumb = row['parent_thumb']
elif row['media_type'] == 'episode':
thumb = row['grandparent_thumb']
else:
thumb = row['thumb']
recent_output = {'row_id': row['id'],
'media_type': row['media_type'],
'rating_key': row['rating_key'],
'parent_rating_key': row['parent_rating_key'],
'grandparent_rating_key': row['grandparent_rating_key'],
'title': row['title'],
'parent_title': row['parent_title'],
'grandparent_title': row['grandparent_title'],
'original_title': row['original_title'],
'thumb': thumb,
'media_index': row['media_index'],
'parent_media_index': row['parent_media_index'],
'year': row['year'],
'originally_available_at': row['originally_available_at'],
'live': row['live'],
'guid': row['guid'],
'time': row['started'],
'user': row['user']
}
recently_watched.append(recent_output)
return recently_watched
def get_users(self, include_deleted=False):
monitor_db = database.MonitorDatabase()
where = '' if include_deleted else 'WHERE deleted_user = 0'
try:
query = "SELECT id AS row_id, user_id, username, friendly_name, thumb, custom_avatar_url, email, " \
"is_active, is_admin, is_home_user, is_allow_sync, is_restricted, " \
"do_notify, keep_history, allow_guest, shared_libraries, " \
"filter_all, filter_movies, filter_tv, filter_music, filter_photos " \
"FROM users %s" % where
result = monitor_db.select(query=query)
except Exception as e:
logger.warn("Tautulli Users :: Unable to execute database query for get_users: %s." % e)
return []
users = []
for item in result:
shared_libraries = tuple(item['shared_libraries'].split(';')) if item['shared_libraries'] else ()
user = {'row_id': item['row_id'],
'user_id': item['user_id'],
'username': item['username'],
'friendly_name': item['friendly_name'] or item['username'],
'thumb': item['custom_avatar_url'] or item['thumb'],
'email': item['email'],
'is_active': item['is_active'],
'is_admin': item['is_admin'],
'is_home_user': item['is_home_user'],
'is_allow_sync': item['is_allow_sync'],
'is_restricted': item['is_restricted'],
'do_notify': item['do_notify'],
'keep_history': item['keep_history'],
'allow_guest': item['allow_guest'],
'shared_libraries': shared_libraries,
'filter_all': item['filter_all'],
'filter_movies': item['filter_movies'],
'filter_tv': item['filter_tv'],
'filter_music': item['filter_music'],
'filter_photos': item['filter_photos'],
}
users.append(user)
return users
def delete(self, user_id=None, row_ids=None, purge_only=False):
monitor_db = database.MonitorDatabase()
if row_ids and row_ids is not None:
row_ids = list(map(helpers.cast_to_int, row_ids.split(',')))
# Get the user_ids corresponding to the row_ids
result = monitor_db.select("SELECT user_id FROM users "
"WHERE id IN ({})".format(",".join(["?"] * len(row_ids))), row_ids)
success = []
for user in result:
success.append(self.delete(user_id=user['user_id'],
purge_only=purge_only))
return all(success)
elif str(user_id).isdigit():
delete_success = database.delete_user_history(user_id=user_id)
if purge_only:
return delete_success
else:
logger.info("Tautulli Users :: Deleting user with user_id %s from database."
% user_id)
try:
monitor_db.action("UPDATE users "
"SET deleted_user = 1, keep_history = 0, do_notify = 0 "
"WHERE user_id = ?", [user_id])
return delete_success
except Exception as e:
logger.warn("Tautulli Users :: Unable to execute database query for delete: %s." % e)
else:
return False
def undelete(self, user_id=None, username=None):
monitor_db = database.MonitorDatabase()
try:
if user_id and str(user_id).isdigit():
query = "SELECT * FROM users WHERE user_id = ?"
result = monitor_db.select(query=query, args=[user_id])
if result:
logger.info("Tautulli Users :: Re-adding user with id %s to database." % user_id)
monitor_db.action("UPDATE users "
"SET deleted_user = 0, keep_history = 1, do_notify = 1 "
"WHERE user_id = ?", [user_id])
return True
else:
return False
elif username:
query = "SELECT * FROM users WHERE username = ?"
result = monitor_db.select(query=query, args=[username])
if result:
logger.info("Tautulli Users :: Re-adding user with username %s to database." % username)
monitor_db.action("UPDATE users "
"SET deleted_user = 0, keep_history = 1, do_notify = 1 "
"WHERE username = ?", [username])
return True
else:
return False
except Exception as e:
logger.warn("Tautulli Users :: Unable to execute database query for undelete: %s." % e)
# Keep method for PlexWatch/Plexivity import
def get_user_id(self, user=None):
if user:
try:
monitor_db = database.MonitorDatabase()
query = "SELECT user_id FROM users WHERE username = ?"
result = monitor_db.select_single(query, args=[user])
if result:
return result['user_id']
else:
return None
except:
return None
return None
def get_user_names(self, kwargs=None):
monitor_db = database.MonitorDatabase()
user_cond = ''
if session.get_session_user_id():
user_cond = "AND user_id = %s " % session.get_session_user_id()
try:
query = "SELECT user_id, " \
"(CASE WHEN users.friendly_name IS NULL OR TRIM(users.friendly_name) = '' \
THEN users.username ELSE users.friendly_name END) AS friendly_name " \
"FROM users " \
"WHERE deleted_user = 0 %s" % user_cond
result = monitor_db.select(query)
except Exception as e:
logger.warn("Tautulli Users :: Unable to execute database query for get_user_names: %s." % e)
return None
return session.friendly_name_to_username(result)
def get_tokens(self, user_id=None):
tokens = {
'allow_guest': 0,
'user_token': '',
'server_token': ''
}
if user_id:
try:
monitor_db = database.MonitorDatabase()
query = "SELECT allow_guest, user_token, server_token FROM users " \
"WHERE user_id = ? AND deleted_user = 0"
result = monitor_db.select_single(query, args=[user_id])
if result:
tokens = {'allow_guest': result['allow_guest'],
'user_token': result['user_token'],
'server_token': result['server_token']
}
return tokens
else:
return tokens
except:
return tokens
return tokens
def get_filters(self, user_id=None):
if not user_id:
return {}
try:
monitor_db = database.MonitorDatabase()
query = "SELECT filter_all, filter_movies, filter_tv, filter_music, filter_photos FROM users " \
"WHERE user_id = ?"
result = monitor_db.select_single(query, args=[user_id])
except Exception as e:
logger.warn("Tautulli Users :: Unable to execute database query for get_filters: %s." % e)
result = {}
filters_list = {}
for k, v in result.items():
filters = {}
for f in v.split('|'):
if 'contentRating=' in f or 'label=' in f:
filters.update(dict(parse_qsl(f)))
filters['content_rating'] = tuple(f for f in filters.pop('contentRating', '').split(',') if f)
filters['labels'] = tuple(f for f in filters.pop('label', '').split(',') if f)
filters_list[k] = filters
return filters_list
def set_user_login(self, user_id=None, user=None, user_group=None, ip_address=None, host=None,
user_agent=None, success=0, expiry=None, jwt_token=None):
if user_id is None or str(user_id).isdigit():
monitor_db = database.MonitorDatabase()
if expiry is not None:
expiry = helpers.datetime_to_iso(expiry)
keys = {'timestamp': helpers.timestamp(),
'user_id': user_id}
values = {'user': user,
'user_group': user_group,
'ip_address': ip_address,
'host': host,
'user_agent': user_agent,
'success': success,
'expiry': expiry,
'jwt_token': jwt_token}
try:
monitor_db.upsert(table_name='user_login', key_dict=keys, value_dict=values)
except Exception as e:
logger.warn("Tautulli Users :: Unable to execute database query for set_login_log: %s." % e)
def get_user_login(self, jwt_token):
monitor_db = database.MonitorDatabase()
result = monitor_db.select_single("SELECT * FROM user_login "
"WHERE jwt_token = ?",
[jwt_token])
return result
def clear_user_login_token(self, jwt_token=None, row_ids=None):
monitor_db = database.MonitorDatabase()
if jwt_token:
logger.debug("Tautulli Users :: Clearing user JWT token.")
try:
monitor_db.action("UPDATE user_login SET jwt_token = NULL "
"WHERE jwt_token = ?",
[jwt_token])
except Exception as e:
logger.error("Tautulli Users :: Unable to clear user JWT token: %s.", e)
return False
elif row_ids and row_ids is not None:
row_ids = list(map(helpers.cast_to_int, row_ids.split(',')))
logger.debug("Tautulli Users :: Clearing JWT tokens for row_ids %s.", row_ids)
try:
monitor_db.action("UPDATE user_login SET jwt_token = NULL "
"WHERE id in ({})".format(",".join(["?"] * len(row_ids))),
row_ids)
except Exception as e:
logger.error("Tautulli Users :: Unable to clear JWT tokens: %s.", e)
return False
return True
def get_datatables_user_login(self, user_id=None, jwt_token=None, kwargs=None):
default_return = {'recordsFiltered': 0,
'recordsTotal': 0,
'draw': 0,
'data': []}
if not session.allow_session_user(user_id):
return default_return
data_tables = datatables.DataTables()
if session.get_session_user_id():
custom_where = [['user_login.user_id', session.get_session_user_id()]]
else:
custom_where = [['user_login.user_id', user_id]] if user_id else []
columns = ["user_login.id AS row_id",
"user_login.timestamp",
"user_login.user_id",
"user_login.user",
"user_login.user_group",
"user_login.ip_address",
"user_login.host",
"user_login.user_agent",
"user_login.success",
"user_login.expiry",
"user_login.jwt_token",
"(CASE WHEN users.friendly_name IS NULL OR TRIM(users.friendly_name) = '' \
THEN users.username ELSE users.friendly_name END) AS friendly_name"
]
try:
query = data_tables.ssp_query(table_name='user_login',
columns=columns,
custom_where=custom_where,
group_by=[],
join_types=['LEFT OUTER JOIN'],
join_tables=['users'],
join_evals=[['user_login.user_id', 'users.user_id']],
kwargs=kwargs)
except Exception as e:
logger.warn("Tautulli Users :: Unable to execute database query for get_datatables_user_login: %s." % e)
return default_return
results = query['result']
rows = []
for item in results:
(os, browser) = httpagentparser.simple_detect(item['user_agent'])
expiry = None
current = False
if item['jwt_token'] and item['expiry']:
_expiry = helpers.iso_to_datetime(item['expiry'])
if _expiry > arrow.now():
expiry = _expiry.strftime('%Y-%m-%d %H:%M:%S')
current = (item['jwt_token'] == jwt_token)
row = {'row_id': item['row_id'],
'timestamp': item['timestamp'],
'user_id': item['user_id'],
'user_group': item['user_group'],
'ip_address': item['ip_address'],
'host': item['host'],
'user_agent': item['user_agent'],
'os': os,
'browser': browser,
'success': item['success'],
'expiry': expiry,
'current': current,
'friendly_name': item['friendly_name'] or item['user']
}
rows.append(row)
dict = {'recordsFiltered': query['filteredCount'],
'recordsTotal': query['totalCount'],
'data': session.friendly_name_to_username(rows),
'draw': query['draw']
}
return dict
def delete_login_log(self):
monitor_db = database.MonitorDatabase()
try:
logger.info("Tautulli Users :: Clearing login logs from database.")
monitor_db.action('DELETE FROM user_login')
monitor_db.action('VACUUM')
return True
except Exception as e:
logger.warn("Tautulli Users :: Unable to execute database query for delete_login_log: %s." % e)
return False