Add ability to set default homescreen layout

--get_policy is now --get_defaults, as it now allows you to store a
default user configuration and displayPreferences, which define the
layout of the home screen. It can also now display non publicly visible
accounts.
This commit is contained in:
Harvey Tindall 2020-06-07 15:00:31 +01:00
parent ac264a4f4b
commit 674636b3a2
4 changed files with 90 additions and 16 deletions

View File

@ -65,13 +65,14 @@ optional arguments:
~/.jf-accounts.
--host HOST address to host web ui on.
-p PORT, --port PORT port to host web ui on.
-g, --get_policy tool to grab a JF users policy (access, perms, etc.)
and output as json to be used as a user template.
-g, --get_defaults tool to grab a JF users policy (access, perms, etc.)
and homescreen layout and output it as json to be used
as a user template.
```
### Setup
#### Policy template
* You may want to restrict a user from accessing certain libraries (e.g 4K Movies), or display their account on the login screen by default. Jellyfin stores these settings as a user's policy.
* Make a temporary account and change its settings, then run `jf-accounts --get_policy`. Choose your user, and the policy will be stored at the location you set in `user_template`, and used for all subsequent new accounts.
#### New user template
* You may want to restrict a user from accessing certain libraries (e.g 4K Movies), display their account on the login screen by default, or set a default homecrseen layout. Jellyfin stores these settings in the user's policy, configuration and displayPreferences.
* Make a temporary account and change its settings, then run `jf-accounts --get_defaults`. Choose your user, and this data will be stored at the location you set in `user_template`, `user_configuration` and `user_displayprefs` (or their default locations), and used for all subsequent new accounts.
#### Emails/Password Resets
* When someone initiates forget password on Jellyfin, a file named `passwordreset*.json` is created in its configuration directory. This directory is monitored and when created, the program reads the username, expiry time and PIN, puts it into a template and sends it to whatever address is specified in `emails.json`.
* **The default forget password popup references the `passwordreset*.json` file created. This is confusing for users, so a quick fix is to edit the `MessageForgotPasswordFileCreated` string in Jellyfin's language folder.**
@ -196,10 +197,14 @@ password = smtp password
invites =
; Path to store emails addresses in JSON
emails =
; Path to the user policy template. Can be acquired with get-template.
; Path to the user policy template. Can be acquired with get-defaults (jf-accounts -g).
user_template =
; Path to the user configuration template (part of homescreen layout). Can be acquired with get-defaults (jf-accounts -g).
user_configuration =
; Path to the user display preferences template (part of homescreen layout). Can be acquired with get-defaults (jf-accounts -g).
user_displayprefs =
; Path to custom bootstrap.css
custom_css =
custom_css =
```

View File

@ -105,8 +105,12 @@ password = smtp password
invites =
; Path to store emails addresses in JSON
emails =
; Path to the user policy template. Can be acquired with get-template.
; Path to the user policy template. Can be acquired with get-defaults (jf-accounts -g).
user_template =
; Path to the user configuration template (part of homescreen layout). Can be acquired with get-defaults (jf-accounts -g).
user_configuration =
; Path to the user display preferences template (part of homescreen layout). Can be acquired with get-defaults (jf-accounts -g).
user_displayprefs =
; Path to custom bootstrap.css
custom_css =

View File

@ -124,7 +124,7 @@ def newUser():
valid = False
if valid:
log.debug('User password valid')
try:
try:
jf.authenticate(config['jellyfin']['username'],
config['jellyfin']['password'])
user = jf.newUser(data['username'], data['password'])
@ -142,7 +142,21 @@ def newUser():
default_policy = json.load(f)
jf.setPolicy(user.json()['Id'], default_policy)
except:
log.debug('setPolicy failed')
log.error('Failed to set new user policy. ' +
'Ignore if you didn\'t create a template')
try:
with open(config['files']['user_configuration'], 'r') as f:
default_configuration = json.load(f)
with open(config['files']['user_displayprefs'], 'r') as f:
default_displayprefs = json.load(f)
if jf.setConfiguration(user.json()['Id'],
default_configuration):
jf.setDisplayPreferences(user.json()['Id'],
default_displayprefs)
log.debug('Set homescreen layout.')
except:
log.error('Failed to set new user homescreen kayout.' +
'Ignore if you didn\'t create a template')
if config.getboolean('password_resets', 'enabled'):
try:
with open(config['files']['emails'], 'r') as f:

View File

@ -21,10 +21,11 @@ parser.add_argument("--host",
help="address to host web ui on.")
parser.add_argument("-p", "--port",
help="port to host web ui on.")
parser.add_argument("-g", "--get_policy",
parser.add_argument("-g", "--get_defaults",
help=("tool to grab a JF users " +
"policy (access, perms, etc.) and " +
"output as json to be used as a user template."),
"homescreen layout and " +
"output it as json to be used as a user template."),
action='store_true')
args, leftovers = parser.parse_known_args()
@ -91,6 +92,11 @@ for key in config['files']:
log.debug(f'Using default {key}')
config['files'][key] = str(data_dir / (key + '.json'))
for key in ['user_configuration', 'user_displayprefs']:
if key not in config['files']:
log.debug(f'Using default {key}')
config['files'][key] = str(data_dir / (key + '.json'))
def default_css():
css = {}
@ -138,7 +144,7 @@ if ('public_server' not in config['jellyfin'] or
config['jellyfin']['public_server'] == ''):
config['jellyfin']['public_server'] = config['jellyfin']['server']
if args.get_policy:
if args.get_defaults:
import json
from jellyfin_accounts.jf_api import Jellyfin
jf = Jellyfin(config['jellyfin']['server'],
@ -147,14 +153,37 @@ if args.get_policy:
config['jellyfin']['device'],
config['jellyfin']['device_id'])
# No auth needed.
print("Make sure the user is publicly visible!")
users = jf.getUsers()
print("""
This tool lets you grab various settings from a user,
so that they can be applied every time a new account is
created. """)
print("Step 1: User Policy.")
print("""
A user policy stores a users permissions (e.g access rights and
most of the other settings in the 'Profile' and 'Access' tabs
of a user). """)
success = False
msg = "Get public users only or all users? (requires auth) [public/all]: "
public = False
while not success:
choice = input(msg)
if choice == 'public':
public = True
print("Make sure the user is publicly visible!")
success = True
elif choice == 'all':
jf.authenticate(config['jellyfin']['username'],
config['jellyfin']['password'])
public = False
success = True
users = jf.getUsers(public=public)
for index, user in enumerate(users):
print(f'{index+1}) {user["Name"]}')
success = False
while not success:
try:
policy = users[int(input(">: "))-1]['Policy']
user_index = int(input(">: "))-1
policy = users[user_index]['Policy']
success = True
except (ValueError, IndexError):
pass
@ -162,6 +191,28 @@ if args.get_policy:
f.write(json.dumps(policy, indent=4))
print(f'Policy written to "{config["files"]["user_template"]}".')
print('In future, this policy will be copied to all new users.')
print('Step 2: Homescreen Layout')
print("""
You may want to customize the default layout of a new user's
home screen. These settings can be applied to an account through
the 'Home' section in a user's settings. """)
success = False
while not success:
choice = input("Grab the chosen user's homescreen layout? [y/n]: ")
if choice.lower() == 'y':
user_id = users[user_index]['Id']
configuration = users[user_index]['Configuration']
display_prefs = jf.getDisplayPreferences(user_id)
with open(config['files']['user_configuration'], 'w') as f:
f.write(json.dumps(configuration, indent=4))
print(f'Configuration written to "{config["files"]["user_configuration"]}".')
with open(config['files']['user_displayprefs'], 'w') as f:
f.write(json.dumps(display_prefs, indent=4))
print(f'Display Prefs written to "{config["files"]["user_displayprefs"]}".')
success = True
elif choice.lower() == 'n':
success = True
else:
def signal_handler(sig, frame):
print('Quitting...')