mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-01-21 07:55:00 +00:00
Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org> Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
157 lines
5.5 KiB
Python
157 lines
5.5 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
"""
|
|
Forms for directory selection.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
|
|
from django import forms
|
|
from django.core.exceptions import ValidationError
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
from plinth import actions
|
|
from plinth import app as app_module
|
|
from plinth.modules import storage
|
|
|
|
|
|
def get_available_samba_shares():
|
|
"""Get available samba shares."""
|
|
available_shares = []
|
|
if _is_app_enabled('samba'):
|
|
samba_shares = json.loads(
|
|
actions.superuser_run('samba', ['get-shares']))
|
|
if samba_shares:
|
|
disks = storage.get_mounts()
|
|
for share in samba_shares:
|
|
for disk in disks:
|
|
if share['mount_point'] == disk['mount_point']:
|
|
available_shares.append(share)
|
|
break
|
|
return available_shares
|
|
|
|
|
|
def _is_app_enabled(app_id):
|
|
"""Check whether a module is enabled."""
|
|
app = app_module.App.get(app_id)
|
|
if not app.needs_setup() and app.is_enabled():
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
class DirectoryValidator:
|
|
username = None
|
|
check_writable = False
|
|
check_creatable = False
|
|
add_user_to_share_group = False
|
|
service_to_restart = None
|
|
|
|
def __init__(self, username=None, check_writable=None,
|
|
check_creatable=None):
|
|
if username is not None:
|
|
self.username = username
|
|
if check_writable is not None:
|
|
self.check_writable = check_writable
|
|
if check_creatable is not None:
|
|
self.check_creatable = check_creatable
|
|
|
|
def __call__(self, value):
|
|
"""Validate a directory."""
|
|
if not value.startswith('/'):
|
|
raise ValidationError(_('Invalid directory name.'), 'invalid')
|
|
|
|
command = ['validate-directory', '--path', value]
|
|
if self.check_creatable:
|
|
command.append('--check-creatable')
|
|
elif self.check_writable:
|
|
command.append('--check-writable')
|
|
|
|
if self.username:
|
|
output = actions.run_as_user('storage', command,
|
|
become_user=self.username)
|
|
else:
|
|
output = actions.run('storage', command)
|
|
|
|
if 'ValidationError' in output:
|
|
error_nr = int(output.strip().split()[1])
|
|
if error_nr == 1:
|
|
raise ValidationError(_('Directory does not exist.'),
|
|
'invalid')
|
|
elif error_nr == 2:
|
|
raise ValidationError(_('Path is not a directory.'), 'invalid')
|
|
elif error_nr == 3:
|
|
raise ValidationError(
|
|
_('Directory is not readable by the user.'), 'invalid')
|
|
elif error_nr == 4:
|
|
raise ValidationError(
|
|
_('Directory is not writable by the user.'), 'invalid')
|
|
|
|
|
|
class DirectorySelectForm(forms.Form):
|
|
"""Directory selection form."""
|
|
storage_dir = forms.ChoiceField(choices=[], label=_('Directory'),
|
|
required=True)
|
|
storage_subdir = forms.CharField(label=_('Subdirectory (optional)'),
|
|
required=False)
|
|
|
|
def __init__(self, title=None, default='/', validator=DirectoryValidator,
|
|
*args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
if title:
|
|
self.fields['storage_dir'].label = title
|
|
self.validator = validator
|
|
self.default = default
|
|
self.set_form_data()
|
|
|
|
def clean(self):
|
|
"""Clean and validate form data."""
|
|
storage_dir = self.cleaned_data['storage_dir']
|
|
storage_subdir = self.cleaned_data['storage_subdir']
|
|
if storage_dir != '/':
|
|
storage_subdir = storage_subdir.lstrip('/')
|
|
storage_path = os.path.realpath(
|
|
os.path.join(storage_dir, storage_subdir))
|
|
if self.validator:
|
|
self.validator(storage_path)
|
|
self.cleaned_data.update({'storage_path': storage_path})
|
|
|
|
def get_initial(self, choices):
|
|
"""Get initial form data."""
|
|
initial_selection = ()
|
|
subdir = ''
|
|
storage_path = self.initial['storage_path']
|
|
for choice in choices:
|
|
if storage_path.startswith(choice[0]):
|
|
initial_selection = choice
|
|
subdir = storage_path.split(choice[0], 1)[1].strip('/')
|
|
if choice[0] == '/':
|
|
subdir = '/' + subdir
|
|
break
|
|
return (initial_selection, subdir)
|
|
|
|
def set_form_data(self):
|
|
"""Set initial form data."""
|
|
choices = []
|
|
if self.default:
|
|
choices = choices + [(self.default, '{0}: {1}'.format(
|
|
_('Default'), self.default))]
|
|
available_shares = get_available_samba_shares()
|
|
for share in available_shares:
|
|
if share['share_type'] != 'home':
|
|
share_type = _('Share')
|
|
if share['share_type'] == 'group':
|
|
share_type = _('Group Share')
|
|
elif share['share_type'] == 'open':
|
|
share_type = _('Open Share')
|
|
selection_text = 'Samba {0} ({1}): {2}'.format(
|
|
share_type, share['name'], share['path'])
|
|
choices = choices + [(share['path'], selection_text)]
|
|
choices = choices + [('/', _('Other directory (specify below)'))]
|
|
|
|
initial_value, subdir = self.get_initial(choices)
|
|
|
|
self.fields['storage_dir'].choices = choices
|
|
self.initial['storage_dir'] = initial_value
|
|
self.initial['storage_subdir'] = subdir
|