From e7b305a1d58ff75fe5d11a2f83fcb039d7d83dd7 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 29 Jun 2015 01:35:17 +0200 Subject: [PATCH] Early implementation of friendly names. This be aware that this writes a new table to your plexWatch database. Note: To edit friendly name, go to user page and click the pencil icon next to the user name. Currently only works on home stats and user info page. Adjust some table styling issues. Fix bug with user IP modal details not showing. Fix users default list order. --- .../default/css/plexwatch-tables.css | 7 +-- data/interfaces/default/edit_user.html | 56 +++++++++++++++++++ data/interfaces/default/history.html | 4 +- data/interfaces/default/home_stats.html | 4 +- data/interfaces/default/info.html | 4 +- data/interfaces/default/js/tables/user_ips.js | 5 +- data/interfaces/default/js/tables/users.js | 2 +- data/interfaces/default/user.html | 23 +++++++- plexpy/__init__.py | 2 + plexpy/plexwatch.py | 36 +++++++++--- plexpy/webserve.py | 37 +++++++++++- 11 files changed, 155 insertions(+), 25 deletions(-) create mode 100644 data/interfaces/default/edit_user.html diff --git a/data/interfaces/default/css/plexwatch-tables.css b/data/interfaces/default/css/plexwatch-tables.css index a54dfc0e..07b85a0b 100644 --- a/data/interfaces/default/css/plexwatch-tables.css +++ b/data/interfaces/default/css/plexwatch-tables.css @@ -161,9 +161,7 @@ table.display { table.display thead th { white-space:nowrap; -padding: 0px 0px 0px 19px; -border-top: 1px solid #2d2d2d; -border-bottom: 1px solid #0e0e0e; +padding: 0px 0px 0px 18px; cursor: pointer; color: #999; background-color: #212121; @@ -180,6 +178,7 @@ table.display thead .sorting_asc, table.display thead .sorting_desc { cursor: pointer; *cursor: hand; + height: 35px; } table.display thead .sorting, table.display thead .sorting_asc, @@ -216,7 +215,7 @@ table.display tr.heading2 td { } table.display td { - padding: 5px 0 5px 20px; + padding: 5px 0 5px 5px; } table.display td.title { diff --git a/data/interfaces/default/edit_user.html b/data/interfaces/default/edit_user.html new file mode 100644 index 00000000..895292ff --- /dev/null +++ b/data/interfaces/default/edit_user.html @@ -0,0 +1,56 @@ +<%doc> +USAGE DOCUMENTATION :: PLEASE LEAVE THIS AT THE TOP OF THIS FILE + +For Mako templating syntax documentation please visit: http://docs.makotemplates.org/en/latest/ + +Filename: edit_user.html +Version: 0.1 +Variable names: data [list] + +data :: Usable parameters + +== Global keys == +user Return the real Plex username +friendly_name Returns the friendly edited Plex username + +DOCUMENTATION :: END + + +% if data is not None: + + + + + +% endif \ No newline at end of file diff --git a/data/interfaces/default/history.html b/data/interfaces/default/history.html index 0f34116e..4e8ad8a3 100644 --- a/data/interfaces/default/history.html +++ b/data/interfaces/default/history.html @@ -31,10 +31,10 @@ from plexpy import helpers ID Time User - Platform + Platform IP Address Title - Started + Started Paused Stopped Duration diff --git a/data/interfaces/default/home_stats.html b/data/interfaces/default/home_stats.html index 54f917f4..c71c47f4 100644 --- a/data/interfaces/default/home_stats.html +++ b/data/interfaces/default/home_stats.html @@ -28,6 +28,7 @@ users_watched Returns the count for the associated stat. == Only if 'stat_id' is 'top_user' == thumb Returns url of the user's gravatar. Returns '' if none exists. user Returns the username for the associated stat. +friendly_name Returns the friendly name of the user for the associated stat. == Only if 'stat_id' is 'top_platform' == platform_type Returns the platform name for the associated stat. @@ -112,12 +113,11 @@ DOCUMENTATION :: END

Most Active User

-
${a['rows'][0]['user']}
+
${a['rows'][0]['friendly_name']}

${a['rows'][0]['total_plays']}

-

plays

diff --git a/data/interfaces/default/info.html b/data/interfaces/default/info.html index ab3d0329..7b571059 100644 --- a/data/interfaces/default/info.html +++ b/data/interfaces/default/info.html @@ -190,10 +190,10 @@ from plexpy import helpers ID Time User - Platform + Platform IP Address Title - Started + Started Paused Stopped Duration diff --git a/data/interfaces/default/js/tables/user_ips.js b/data/interfaces/default/js/tables/user_ips.js index 808be44c..fe52a452 100644 --- a/data/interfaces/default/js/tables/user_ips.js +++ b/data/interfaces/default/js/tables/user_ips.js @@ -33,7 +33,7 @@ user_ip_table_options = { "targets": [1], "data":"ip_address", "width": "15%", - "className": "modal-control", + "className": "modal-control no-wrap", "createdCell": function (td, cellData, rowData, row, col) { if (isPrivateIP(cellData)) { if (cellData != '') { @@ -45,8 +45,7 @@ user_ip_table_options = { $(td).html(' ' + cellData +''); } }, - "width": "15%", - "className": "no-wrap" + "width": "15%" }, { "targets": [2], diff --git a/data/interfaces/default/js/tables/users.js b/data/interfaces/default/js/tables/users.js index 4d9d4ea4..e872e6d8 100644 --- a/data/interfaces/default/js/tables/users.js +++ b/data/interfaces/default/js/tables/users.js @@ -14,7 +14,7 @@ users_list_table_options = { "processing": false, "serverSide": true, "pageLength": 10, - "order": [ 0, 'asc'], + "order": [ 1, 'asc'], "ajax": { "url": "get_user_list" }, diff --git a/data/interfaces/default/user.html b/data/interfaces/default/user.html index 2b7b7356..54a5ea0d 100644 --- a/data/interfaces/default/user.html +++ b/data/interfaces/default/user.html @@ -10,6 +10,7 @@ Variable names: user [string] user :: Usable parameters user Returns the name of the user. +friendly_name Returns the friendly name of the user. DOCUMENTATION :: END @@ -35,7 +36,7 @@ from plexpy import helpers
- ${user} + ${friendly_name}
+
@@ -108,7 +112,7 @@ from plexpy import helpers

IP Addresses for - ${user} + ${friendly_name}

@@ -164,7 +168,7 @@ from plexpy import helpers

Watch History for - ${user} + ${friendly_name}

@@ -272,6 +276,19 @@ from plexpy import helpers } } }); + + // Load edit user modal + $("#toggle-edit-user-modal").click(function() { + $.ajax({ + url: 'edit_user', + data: {user: '${user}'}, + cache: false, + async: true, + complete: function(xhr, status) { + $("#edit-user-modal").html(xhr.responseText); + } + }); + }); }); diff --git a/plexpy/__init__.py b/plexpy/__init__.py index f456bb8c..07141e9b 100644 --- a/plexpy/__init__.py +++ b/plexpy/__init__.py @@ -307,6 +307,8 @@ def sig_handler(signum=None, frame=None): def dbcheck(): conn = sqlite3.connect(plexpy.CONFIG.PLEXWATCH_DATABASE) c = conn.cursor() + c.execute('CREATE TABLE IF NOT EXISTS plexpy_users (id INTEGER PRIMARY KEY AUTOINCREMENT, ' + 'username TEXT NOT NULL UNIQUE, friendly_name TEXT)') conn.commit() c.close() diff --git a/plexpy/plexwatch.py b/plexpy/plexwatch.py index 5e19939f..7f639c0e 100644 --- a/plexpy/plexwatch.py +++ b/plexpy/plexwatch.py @@ -660,11 +660,14 @@ class PlexWatch(object): elif 'top_users' in stat: top_users = [] try: - query = 'SELECT user, COUNT(id) as total_plays, MAX(time) as last_watch ' \ - 'FROM %s ' \ - 'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-%s days", "localtime") ' \ - 'GROUP BY user ' \ - 'ORDER BY total_plays DESC LIMIT 10' % (self.get_history_table_name(), time_range) + s = self.get_history_table_name() + query = 'SELECT user, (case when friendly_name is null then user else friendly_name end) as friendly_name,' \ + 'COUNT(' + s + '.id) as total_plays, MAX(time) as last_watch ' \ + 'FROM ' + s + ' ' \ + 'LEFT OUTER JOIN plexpy_users ON ' + s + '.user = plexpy_users.username ' \ + 'WHERE datetime(stopped, "unixepoch", "localtime") >= datetime("now", "-' + time_range + ' days", "localtime") '\ + 'GROUP BY ' + s + '.user ' \ + 'ORDER BY total_plays DESC LIMIT 10' result = myDB.select(query) except: logger.warn("Unable to open PlexWatch database.") @@ -673,8 +676,9 @@ class PlexWatch(object): for item in result: thumb = self.get_user_gravatar_image(item[0]) row = {'user': item[0], - 'total_plays': item[1], - 'last_play': item[2], + 'friendly_name': item[1], + 'total_plays': item[2], + 'last_play': item[3], 'thumb': thumb['user_thumb'] } top_users.append(row) @@ -875,6 +879,24 @@ class PlexWatch(object): 'series': [series_1_output]} return output + def set_user_friendly_name(self, user=None, friendly_name=None): + if user and friendly_name: + myDB = db.DBConnection() + + control_value_dict = {"username": user} + new_value_dict = {"friendly_name": friendly_name} + + myDB.upsert('plexpy_users', new_value_dict, control_value_dict) + + def get_user_friendly_name(self, user=None): + if user: + myDB = db.DBConnection() + + query = 'select friendly_name FROM plexpy_users WHERE username = "%s"' % user + result = myDB.select_single(query) + + return result + # Taken from: # https://stackoverflow.com/questions/18066269/group-by-and-aggregate-the-values-of-a-list-of-dictionaries-in-python @staticmethod diff --git a/plexpy/webserve.py b/plexpy/webserve.py index d756dbeb..aee82594 100644 --- a/plexpy/webserve.py +++ b/plexpy/webserve.py @@ -99,7 +99,42 @@ class WebInterface(object): @cherrypy.expose def user(self, user=None): - return serve_template(templatename="user.html", title="User", user=user) + try: + plex_watch = plexwatch.PlexWatch() + friendly_name = plex_watch.get_user_friendly_name(user) + except: + logger.warn("Unable to retrieve friendly name for user %s " % user) + friendly_name = user + + return serve_template(templatename="user.html", title="User", user=user, friendly_name=friendly_name) + + @cherrypy.expose + def edit_user(self, user=None, friendly_name=None, **kwargs): + if user and friendly_name: + try: + plex_watch = plexwatch.PlexWatch() + plex_watch.set_user_friendly_name(user, friendly_name) + status_message = "Successfully updated user." + return status_message + except: + status_message = "Failed to updated user." + return status_message + elif user and not friendly_name: + try: + plex_watch = plexwatch.PlexWatch() + result = {'user': user, + 'friendly_name': plex_watch.get_user_friendly_name(user) + } + status_message = "" + except: + result = {'user': user, + 'friendly_name': '' + } + status_message = "There was an error." + + return serve_template(templatename="edit_user.html", title="Edit User", data=result, status_message=status_message) + else: + return serve_template(templatename="edit_user.html", title="Edit User", data=user, status_message='Unknown error.') @cherrypy.expose def get_stream_data(self, row_id=None, user=None, **kwargs):