mirror of
				https://github.com/chibicitiberiu/ytsm.git
				synced 2024-02-24 05:43:31 +00:00 
			
		
		
		
	Fixed registration step of first time setup. General improvements to settings and first time setup wizard.
This commit is contained in:
		@@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/1.11/ref/settings/
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
import logging
 | 
			
		||||
from os.path import dirname as up
 | 
			
		||||
 | 
			
		||||
@@ -128,7 +129,6 @@ BASE_DIR = up(os.path.dirname(__file__))                    # Base dir of the ap
 | 
			
		||||
 | 
			
		||||
CONFIG_DIR = os.getenv("YTSM_CONFIG_DIR", os.path.join(PROJECT_ROOT, "config"))
 | 
			
		||||
DATA_DIR = os.getenv("YTSM_DATA_DIR", os.path.join(PROJECT_ROOT, "data"))
 | 
			
		||||
os.chdir(DATA_DIR)
 | 
			
		||||
 | 
			
		||||
STATIC_ROOT = os.path.join(PROJECT_ROOT, "static")
 | 
			
		||||
MEDIA_ROOT = os.path.join(DATA_DIR, 'media')
 | 
			
		||||
@@ -154,6 +154,16 @@ CONFIG_ERRORS = []
 | 
			
		||||
CONFIG_WARNINGS = []
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Config parser options
 | 
			
		||||
#
 | 
			
		||||
CFG_PARSER_OPTS = {
 | 
			
		||||
    'PROJECT_ROOT' : PROJECT_ROOT,
 | 
			
		||||
    'BASE_DIR' : BASE_DIR,
 | 
			
		||||
    'CONFIG_DIR' : CONFIG_DIR,
 | 
			
		||||
    'DATA_DIR' : DATA_DIR,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Load globals from config.ini
 | 
			
		||||
#
 | 
			
		||||
@@ -189,7 +199,7 @@ def get_global_opt(name, cfgparser, env_variable=None, fallback=None, boolean=Fa
 | 
			
		||||
    # Get from config parser
 | 
			
		||||
    if boolean:
 | 
			
		||||
        try:
 | 
			
		||||
            return cfgparser.getboolean('global', name, fallback=fallback)
 | 
			
		||||
            return cfgparser.getboolean('global', name, fallback=fallback, vars=CFG_PARSER_OPTS)
 | 
			
		||||
        except ValueError:
 | 
			
		||||
            CONFIG_WARNINGS.append(f'config.ini file: Value set for option global.{name} is not valid! '
 | 
			
		||||
                                   f'Valid options: true, false, on, off.')
 | 
			
		||||
@@ -197,12 +207,12 @@ def get_global_opt(name, cfgparser, env_variable=None, fallback=None, boolean=Fa
 | 
			
		||||
 | 
			
		||||
    if integer:
 | 
			
		||||
        try:
 | 
			
		||||
            return cfgparser.getint('global', name, fallback=fallback)
 | 
			
		||||
            return cfgparser.getint('global', name, fallback=fallback, vars=CFG_PARSER_OPTS)
 | 
			
		||||
        except ValueError:
 | 
			
		||||
            CONFIG_WARNINGS.append(f'config.ini file: Value set for option global.{name} must be an integer number! ')
 | 
			
		||||
            return fallback
 | 
			
		||||
 | 
			
		||||
    return cfgparser.get('global', name, fallback=fallback)
 | 
			
		||||
    return cfgparser.get('global', name, fallback=fallback, vars=CFG_PARSER_OPTS)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def load_config_ini():
 | 
			
		||||
@@ -210,6 +220,13 @@ def load_config_ini():
 | 
			
		||||
    from YtManagerApp.utils.extended_interpolation_with_env import ExtendedInterpolatorWithEnv
 | 
			
		||||
    import dj_database_url
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        os.makedirs(DATA_DIR, exist_ok=True)
 | 
			
		||||
        logging.info(f"Using data directory {DATA_DIR}")
 | 
			
		||||
    except OSError as e:
 | 
			
		||||
        print(f'CRITICAL ERROR! Cannot create data directory {DATA_DIR}! {e}', file=sys.stderr)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    cfg = ConfigParser(allow_no_value=True, interpolation=ExtendedInterpolatorWithEnv())
 | 
			
		||||
 | 
			
		||||
    cfg_file = os.path.join(CONFIG_DIR, "config.ini")
 | 
			
		||||
@@ -235,7 +252,7 @@ def load_config_ini():
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if cfg.has_option('global', 'DatabaseURL'):
 | 
			
		||||
        DATABASES['default'] = dj_database_url.parse(cfg.get('global', 'DatabaseURL'), conn_max_age=600)
 | 
			
		||||
        DATABASES['default'] = dj_database_url.parse(cfg.get('global', 'DatabaseURL', vars=CFG_PARSER_OPTS), conn_max_age=600)
 | 
			
		||||
 | 
			
		||||
    else:
 | 
			
		||||
        DATABASES['default'] = {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
#main_body {
 | 
			
		||||
  margin-bottom: 4rem;
 | 
			
		||||
  margin-top: 2rem; }
 | 
			
		||||
  margin-top: 0; }
 | 
			
		||||
 | 
			
		||||
#main_footer {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
"version": 3,
 | 
			
		||||
"mappings": "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",
 | 
			
		||||
"mappings": "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",
 | 
			
		||||
"sources": ["style.scss"],
 | 
			
		||||
"names": [],
 | 
			
		||||
"file": "style.css"
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ $accent-color: #007bff;
 | 
			
		||||
 | 
			
		||||
#main_body {
 | 
			
		||||
    margin-bottom: 4rem;
 | 
			
		||||
    margin-top: 2rem;
 | 
			
		||||
    margin-top: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#main_footer {
 | 
			
		||||
 
 | 
			
		||||
@@ -63,8 +63,7 @@ urlpatterns = [
 | 
			
		||||
    # First time setup
 | 
			
		||||
    path('first_time/step0_welcome', first_time.Step0WelcomeView.as_view(), name='first_time_0'),
 | 
			
		||||
    path('first_time/step1_apikey', first_time.Step1ApiKeyView.as_view(), name='first_time_1'),
 | 
			
		||||
    path('first_time/step2_admin', first_time.Step2CreateAdminUserView.as_view(), name='first_time_2'),
 | 
			
		||||
    path('first_time/step2_login', first_time.Step2LoginAdminUserView.as_view(), name='first_time_2_login'),
 | 
			
		||||
    path('first_time/step2_admin', first_time.Step2SetupAdminUserView.as_view(), name='first_time_2'),
 | 
			
		||||
    path('first_time/step3_config', first_time.Step3ConfigureView.as_view(), name='first_time_3'),
 | 
			
		||||
    path('first_time/done', first_time.DoneView.as_view(), name='first_time_done'),
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,57 +1,17 @@
 | 
			
		||||
from crispy_forms.helper import FormHelper
 | 
			
		||||
from crispy_forms.layout import Submit
 | 
			
		||||
from django import forms
 | 
			
		||||
from django.contrib.auth import login, authenticate
 | 
			
		||||
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
 | 
			
		||||
from django.contrib.auth.mixins import LoginRequiredMixin
 | 
			
		||||
from django.contrib.auth.models import User
 | 
			
		||||
from django.contrib.auth.views import LoginView
 | 
			
		||||
from django.urls import reverse_lazy
 | 
			
		||||
from django.views.generic import FormView, TemplateView
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ExtendedAuthenticationForm(AuthenticationForm):
 | 
			
		||||
    remember_me = forms.BooleanField(label='Remember me', required=False, initial=False)
 | 
			
		||||
 | 
			
		||||
    def clean(self):
 | 
			
		||||
        remember_me = self.cleaned_data.get('remember_me')
 | 
			
		||||
        if remember_me:
 | 
			
		||||
            expiry = 3600 * 24 * 30
 | 
			
		||||
        else:
 | 
			
		||||
            expiry = 0
 | 
			
		||||
        self.request.session.set_expiry(expiry)
 | 
			
		||||
 | 
			
		||||
        return super().clean()
 | 
			
		||||
from .forms.auth import ExtendedAuthenticationForm, ExtendedUserCreationForm
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ExtendedLoginView(LoginView):
 | 
			
		||||
    form_class = ExtendedAuthenticationForm
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ExtendedUserCreationForm(UserCreationForm):
 | 
			
		||||
    email = forms.EmailField(required=False,
 | 
			
		||||
                             label='E-mail address',
 | 
			
		||||
                             help_text='The e-mail address is optional, but it is the only way to recover a lost '
 | 
			
		||||
                                       'password.')
 | 
			
		||||
    first_name = forms.CharField(max_length=30, required=False,
 | 
			
		||||
                                 label='First name')
 | 
			
		||||
    last_name = forms.CharField(max_length=150, required=False,
 | 
			
		||||
                                label='Last name')
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.helper = FormHelper()
 | 
			
		||||
        self.helper.label_class = 'col-3'
 | 
			
		||||
        self.helper.field_class = 'col-9'
 | 
			
		||||
        self.helper.form_class = 'form-horizontal'
 | 
			
		||||
        self.helper.form_method = 'post'
 | 
			
		||||
        self.helper.form_action = reverse_lazy('register')
 | 
			
		||||
        self.helper.add_input(Submit('submit', 'register'))
 | 
			
		||||
 | 
			
		||||
    class Meta(UserCreationForm.Meta):
 | 
			
		||||
        fields = ['username', 'email', 'first_name', 'last_name']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RegisterView(FormView):
 | 
			
		||||
    template_name = 'registration/register.html'
 | 
			
		||||
    form_class = ExtendedUserCreationForm
 | 
			
		||||
 
 | 
			
		||||
@@ -1,30 +1,28 @@
 | 
			
		||||
from crispy_forms.helper import FormHelper
 | 
			
		||||
from crispy_forms.layout import Layout, HTML, Submit, Column
 | 
			
		||||
from django import forms
 | 
			
		||||
from django.contrib.auth import authenticate, login
 | 
			
		||||
from django.contrib.auth.mixins import LoginRequiredMixin
 | 
			
		||||
from django.contrib.auth.models import User
 | 
			
		||||
from django.urls import reverse_lazy
 | 
			
		||||
from django.views.generic import UpdateView, FormView
 | 
			
		||||
from django.shortcuts import render, redirect
 | 
			
		||||
from YtManagerApp.views.auth import RegisterView, ExtendedUserCreationForm, ExtendedAuthenticationForm
 | 
			
		||||
from YtManagerApp.models import UserSettings
 | 
			
		||||
 | 
			
		||||
from YtManagerApp.management.appconfig import global_prefs
 | 
			
		||||
from django.http import HttpResponseForbidden
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from django.contrib.auth import authenticate, login
 | 
			
		||||
from django.contrib.auth.models import User
 | 
			
		||||
from django.http import HttpResponseForbidden
 | 
			
		||||
from django.shortcuts import redirect
 | 
			
		||||
from django.urls import reverse_lazy
 | 
			
		||||
from django.views.generic import FormView
 | 
			
		||||
 | 
			
		||||
from YtManagerApp.management.appconfig import global_prefs
 | 
			
		||||
from YtManagerApp.views.forms.auth import ExtendedAuthenticationForm
 | 
			
		||||
from YtManagerApp.views.forms.first_time import WelcomeForm, ApiKeyForm, PickAdminUserForm, ServerConfigForm, DoneForm, UserCreationForm
 | 
			
		||||
 | 
			
		||||
logger = logging.getLogger("FirstTimeWizard")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProtectInitializedMixin(object):
 | 
			
		||||
 | 
			
		||||
class WizardStepMixin(object):
 | 
			
		||||
    def get(self, request, *args, **kwargs):
 | 
			
		||||
 | 
			
		||||
        # Prevent access if application is already initialized
 | 
			
		||||
        if global_prefs['hidden__initialized']:
 | 
			
		||||
            logger.debug(f"Attempted to access {request.path}, but first time setup already run. Redirected to home page.")
 | 
			
		||||
            logger.debug(f"Attempted to access {request.path}, but first time setup already run. Redirected to home "
 | 
			
		||||
                         f"page.")
 | 
			
		||||
            return redirect('home')
 | 
			
		||||
 | 
			
		||||
        return super().get(request, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def post(self, request, *args, **kwargs):
 | 
			
		||||
@@ -37,44 +35,25 @@ class ProtectInitializedMixin(object):
 | 
			
		||||
#
 | 
			
		||||
# Step 0: welcome screen
 | 
			
		||||
#
 | 
			
		||||
class Step0WelcomeForm(forms.Form):
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.helper = FormHelper()
 | 
			
		||||
        self.helper.layout = Layout(
 | 
			
		||||
            Submit('submit', value='Continue')
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Step0WelcomeView(ProtectInitializedMixin, FormView):
 | 
			
		||||
class Step0WelcomeView(WizardStepMixin, FormView):
 | 
			
		||||
    template_name = 'YtManagerApp/first_time_setup/step0_welcome.html'
 | 
			
		||||
    form_class = Step0WelcomeForm
 | 
			
		||||
    form_class = WelcomeForm
 | 
			
		||||
    success_url = reverse_lazy('first_time_1')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Step 1: setup API key
 | 
			
		||||
#
 | 
			
		||||
class Step1ApiKeyForm(forms.Form):
 | 
			
		||||
    api_key = forms.CharField(label="YouTube API Key:")
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.helper = FormHelper()
 | 
			
		||||
        self.helper.layout = Layout(
 | 
			
		||||
            'api_key',
 | 
			
		||||
            Column(
 | 
			
		||||
                Submit('submit', value='Continue'),
 | 
			
		||||
                HTML('<a href="{% url \'first_time_2\' %}" class="btn">Skip</a>')
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Step1ApiKeyView(ProtectInitializedMixin, FormView):
 | 
			
		||||
class Step1ApiKeyView(WizardStepMixin, FormView):
 | 
			
		||||
    template_name = 'YtManagerApp/first_time_setup/step1_apikey.html'
 | 
			
		||||
    form_class = Step1ApiKeyForm
 | 
			
		||||
    form_class = ApiKeyForm
 | 
			
		||||
    success_url = reverse_lazy('first_time_2')
 | 
			
		||||
 | 
			
		||||
    def get_initial(self):
 | 
			
		||||
        initial = super().get_initial()
 | 
			
		||||
        initial['api_key'] = global_prefs['general__youtube_api_key']
 | 
			
		||||
        return initial
 | 
			
		||||
 | 
			
		||||
    def form_valid(self, form):
 | 
			
		||||
        key = form.cleaned_data['api_key']
 | 
			
		||||
        # TODO: validate key
 | 
			
		||||
@@ -85,101 +64,87 @@ class Step1ApiKeyView(ProtectInitializedMixin, FormView):
 | 
			
		||||
#
 | 
			
		||||
# Step 2: create admin user
 | 
			
		||||
#
 | 
			
		||||
class Step2CreateAdminUserView(ProtectInitializedMixin, FormView):
 | 
			
		||||
class Step2SetupAdminUserView(WizardStepMixin, FormView):
 | 
			
		||||
    template_name = 'YtManagerApp/first_time_setup/step2_admin.html'
 | 
			
		||||
    success_url = reverse_lazy('first_time_3')
 | 
			
		||||
    form_class = ExtendedUserCreationForm
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.__form_class = UserCreationForm
 | 
			
		||||
 | 
			
		||||
    def get_form_class(self):
 | 
			
		||||
        return self.__form_class
 | 
			
		||||
 | 
			
		||||
    def get(self, request, *args, **kwargs):
 | 
			
		||||
 | 
			
		||||
        have_users = User.objects.count() > 0
 | 
			
		||||
        have_admin = User.objects.filter(is_superuser=True).count() > 0
 | 
			
		||||
 | 
			
		||||
        # Skip if admin is already logged in
 | 
			
		||||
        if request.user.is_authenticated and request.user.is_superuser:
 | 
			
		||||
            logger.debug("Admin user already exists and is logged in!")
 | 
			
		||||
            return redirect(self.success_url)
 | 
			
		||||
 | 
			
		||||
        # Check if an admin user already exists
 | 
			
		||||
        if User.objects.filter(is_superuser=True).count() > 0:
 | 
			
		||||
            logger.warn("Admin user already exists! Will redirect to login page!")
 | 
			
		||||
            return redirect('first_time_2_login')
 | 
			
		||||
        elif have_admin:
 | 
			
		||||
            logger.debug("Admin user already exists and is not logged in!")
 | 
			
		||||
            self.__form_class = ExtendedAuthenticationForm
 | 
			
		||||
 | 
			
		||||
        elif have_users and 'register' not in kwargs:
 | 
			
		||||
            logger.debug("There are users but no admin!")
 | 
			
		||||
            self.__form_class = PickAdminUserForm
 | 
			
		||||
 | 
			
		||||
        else:
 | 
			
		||||
            logger.debug("No admin user exists, will register a new account!")
 | 
			
		||||
            self.__form_class = UserCreationForm
 | 
			
		||||
 | 
			
		||||
        return super().get(request, *args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def form_valid(self, form):
 | 
			
		||||
        user = form.save()
 | 
			
		||||
        user.is_staff = True
 | 
			
		||||
        user.is_superuser = True
 | 
			
		||||
        user.save()
 | 
			
		||||
 | 
			
		||||
        username = form.cleaned_data.get('username')
 | 
			
		||||
        password = form.cleaned_data.get('password1')
 | 
			
		||||
        user = authenticate(username=username, password=password)
 | 
			
		||||
        login(self.request, user)
 | 
			
		||||
 | 
			
		||||
        return super().form_valid(form)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Step 2: create admin user
 | 
			
		||||
#
 | 
			
		||||
class Step2LoginAdminUserView(ProtectInitializedMixin, FormView):
 | 
			
		||||
    template_name = 'YtManagerApp/first_time_setup/step2_admin.html'
 | 
			
		||||
    success_url = reverse_lazy('first_time_3')
 | 
			
		||||
    form_class = ExtendedAuthenticationForm
 | 
			
		||||
    def form_invalid(self, form):
 | 
			
		||||
        print("FORM INVALID!")
 | 
			
		||||
 | 
			
		||||
    def form_valid(self, form):
 | 
			
		||||
        login(self.request, form.get_user())
 | 
			
		||||
        if isinstance(form, ExtendedAuthenticationForm):
 | 
			
		||||
            login(self.request, form.get_user())
 | 
			
		||||
 | 
			
		||||
        elif isinstance(form, UserCreationForm):
 | 
			
		||||
            user = form.save()
 | 
			
		||||
            user.is_staff = True
 | 
			
		||||
            user.is_superuser = True
 | 
			
		||||
            user.save()
 | 
			
		||||
 | 
			
		||||
            username = form.cleaned_data.get('username')
 | 
			
		||||
            password = form.cleaned_data.get('password1')
 | 
			
		||||
            user = authenticate(username=username, password=password)
 | 
			
		||||
            login(self.request, user)
 | 
			
		||||
 | 
			
		||||
        elif isinstance(form, PickAdminUserForm):
 | 
			
		||||
            user = form.cleaned_data['admin_user']
 | 
			
		||||
            user.is_staff = True
 | 
			
		||||
            user.is_superuser = True
 | 
			
		||||
            user.save()
 | 
			
		||||
 | 
			
		||||
            return redirect('first_time_2', assigned_success='1')
 | 
			
		||||
 | 
			
		||||
        return super().form_valid(form)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Step 3: configure server
 | 
			
		||||
#
 | 
			
		||||
class Step3ConfigureForm(forms.Form):
 | 
			
		||||
 | 
			
		||||
    allow_registrations = forms.BooleanField(
 | 
			
		||||
        label="Allow user registrations",
 | 
			
		||||
        help_text="Disabling this option will prevent anyone from registering to the site.",
 | 
			
		||||
        initial=True,
 | 
			
		||||
        required=False
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    sync_schedule = forms.CharField(
 | 
			
		||||
        label="Synchronization schedule",
 | 
			
		||||
        help_text="How often should the application look for new videos.",
 | 
			
		||||
        initial="5 * * * *",
 | 
			
		||||
        required=True
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    auto_download = forms.BooleanField(
 | 
			
		||||
        label="Download videos automatically",
 | 
			
		||||
        required=False
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    download_location = forms.CharField(
 | 
			
		||||
        label="Download location",
 | 
			
		||||
        help_text="Location on the server where videos are downloaded.",
 | 
			
		||||
        required=True
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.helper = FormHelper()
 | 
			
		||||
        self.helper.layout = Layout(
 | 
			
		||||
            HTML('<h3>Server settings</h3>'),
 | 
			
		||||
            'sync_schedule',
 | 
			
		||||
            'allow_registrations',
 | 
			
		||||
            HTML('<h3>User settings</h3>'),
 | 
			
		||||
            'auto_download',
 | 
			
		||||
            'download_location',
 | 
			
		||||
            Submit('submit', value='Continue'),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Step3ConfigureView(ProtectInitializedMixin, FormView):
 | 
			
		||||
class Step3ConfigureView(WizardStepMixin, FormView):
 | 
			
		||||
    template_name = 'YtManagerApp/first_time_setup/step3_configure.html'
 | 
			
		||||
    form_class = Step3ConfigureForm
 | 
			
		||||
    form_class = ServerConfigForm
 | 
			
		||||
    success_url = reverse_lazy('first_time_done')
 | 
			
		||||
 | 
			
		||||
    def get_initial(self):
 | 
			
		||||
        initial = super().get_initial()
 | 
			
		||||
        initial['allow_registrations'] = global_prefs['general__allow_registrations']
 | 
			
		||||
        initial['sync_schedule'] =  global_prefs['scheduler__synchronization_schedule']
 | 
			
		||||
        initial['auto_download'] = self.request.user.preferences['downloader__auto_enabled']
 | 
			
		||||
        initial['download_location'] = self.request.user.preferences['downloader__download_path']
 | 
			
		||||
        return initial
 | 
			
		||||
 | 
			
		||||
    def form_valid(self, form):
 | 
			
		||||
        allow_registrations = form.cleaned_data['allow_registrations']
 | 
			
		||||
        if allow_registrations is not None:
 | 
			
		||||
@@ -202,18 +167,10 @@ class Step3ConfigureView(ProtectInitializedMixin, FormView):
 | 
			
		||||
        
 | 
			
		||||
        return super().form_valid(form)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Done screen
 | 
			
		||||
#
 | 
			
		||||
class DoneForm(forms.Form):
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.helper = FormHelper()
 | 
			
		||||
        self.helper.layout = Layout(
 | 
			
		||||
            Submit('submit', value='Finish')
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DoneView(FormView):
 | 
			
		||||
    template_name = 'YtManagerApp/first_time_setup/done.html'
 | 
			
		||||
    form_class = DoneForm
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										45
									
								
								app/YtManagerApp/views/forms/auth.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								app/YtManagerApp/views/forms/auth.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
from crispy_forms.helper import FormHelper
 | 
			
		||||
from crispy_forms.layout import Submit
 | 
			
		||||
from django import forms
 | 
			
		||||
from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
 | 
			
		||||
from django.urls import reverse_lazy
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ExtendedAuthenticationForm(AuthenticationForm):
 | 
			
		||||
    remember_me = forms.BooleanField(label='Remember me', required=False, initial=False)
 | 
			
		||||
 | 
			
		||||
    def clean(self):
 | 
			
		||||
        remember_me = self.cleaned_data.get('remember_me')
 | 
			
		||||
        if remember_me:
 | 
			
		||||
            expiry = 3600 * 24 * 30
 | 
			
		||||
        else:
 | 
			
		||||
            expiry = 0
 | 
			
		||||
        self.request.session.set_expiry(expiry)
 | 
			
		||||
 | 
			
		||||
        return super().clean()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ExtendedUserCreationForm(UserCreationForm):
 | 
			
		||||
    email = forms.EmailField(required=False,
 | 
			
		||||
                             label='E-mail address',
 | 
			
		||||
                             help_text='The e-mail address is optional, but it is the only way to recover a lost '
 | 
			
		||||
                                       'password.')
 | 
			
		||||
    first_name = forms.CharField(max_length=30, required=False,
 | 
			
		||||
                                 label='First name')
 | 
			
		||||
    last_name = forms.CharField(max_length=150, required=False,
 | 
			
		||||
                                label='Last name')
 | 
			
		||||
 | 
			
		||||
    form_action = reverse_lazy('register')
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.helper = FormHelper()
 | 
			
		||||
        self.helper.label_class = 'col-3'
 | 
			
		||||
        self.helper.field_class = 'col-9'
 | 
			
		||||
        self.helper.form_class = 'form-horizontal'
 | 
			
		||||
        self.helper.form_method = 'post'
 | 
			
		||||
        self.helper.form_action = self.form_action
 | 
			
		||||
        self.helper.add_input(Submit('submit', 'register'))
 | 
			
		||||
 | 
			
		||||
    class Meta(UserCreationForm.Meta):
 | 
			
		||||
        fields = ['username', 'email', 'first_name', 'last_name']
 | 
			
		||||
							
								
								
									
										108
									
								
								app/YtManagerApp/views/forms/first_time.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								app/YtManagerApp/views/forms/first_time.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from crispy_forms.helper import FormHelper
 | 
			
		||||
from crispy_forms.layout import Layout, HTML, Submit, Column
 | 
			
		||||
from django import forms
 | 
			
		||||
from django.contrib.auth import authenticate, login
 | 
			
		||||
from django.contrib.auth.models import User
 | 
			
		||||
from YtManagerApp.views.forms.auth import ExtendedUserCreationForm
 | 
			
		||||
from django.urls import reverse_lazy
 | 
			
		||||
from YtManagerApp.management.appconfig import global_prefs
 | 
			
		||||
 | 
			
		||||
logger = logging.getLogger("FirstTimeWizard")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class WelcomeForm(forms.Form):
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.helper = FormHelper()
 | 
			
		||||
        self.helper.layout = Layout(
 | 
			
		||||
            Submit('submit', value='Continue')
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ApiKeyForm(forms.Form):
 | 
			
		||||
    api_key = forms.CharField(label="YouTube API Key:")
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.helper = FormHelper()
 | 
			
		||||
        self.helper.layout = Layout(
 | 
			
		||||
            'api_key',
 | 
			
		||||
            Column(
 | 
			
		||||
                Submit('submit', value='Continue'),
 | 
			
		||||
                HTML('<a href="{% url \'first_time_2\' %}" class="btn">Skip</a>')
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UserCreationForm(ExtendedUserCreationForm):
 | 
			
		||||
    form_action = reverse_lazy('first_time_2')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PickAdminUserForm(forms.Form):
 | 
			
		||||
    admin_user = forms.ModelChoiceField(
 | 
			
		||||
            User.objects.order_by('username'),
 | 
			
		||||
            label='User to promote to admin',
 | 
			
		||||
            required=True)
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.helper = FormHelper()
 | 
			
		||||
        self.helper.layout = Layout(
 | 
			
		||||
            'admin_user',
 | 
			
		||||
            Column(
 | 
			
		||||
                Submit('submit', value='Continue'),
 | 
			
		||||
                HTML('<a href="{% url \'first_time_2\' %}®ister=1" class="btn">Register a new admin user</a>')
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ServerConfigForm(forms.Form):
 | 
			
		||||
 | 
			
		||||
    allow_registrations = forms.BooleanField(
 | 
			
		||||
        label="Allow user registrations",
 | 
			
		||||
        help_text="Disabling this option will prevent anyone from registering to the site.",
 | 
			
		||||
        initial=True,
 | 
			
		||||
        required=False
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    sync_schedule = forms.CharField(
 | 
			
		||||
        label="Synchronization schedule",
 | 
			
		||||
        help_text="How often should the application look for new videos.",
 | 
			
		||||
        initial="5 * * * *",
 | 
			
		||||
        required=True
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    auto_download = forms.BooleanField(
 | 
			
		||||
        label="Download videos automatically",
 | 
			
		||||
        required=False
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    download_location = forms.CharField(
 | 
			
		||||
        label="Download location",
 | 
			
		||||
        help_text="Location on the server where videos are downloaded.",
 | 
			
		||||
        required=True
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.helper = FormHelper()
 | 
			
		||||
        self.helper.layout = Layout(
 | 
			
		||||
            HTML('<h3>Server settings</h3>'),
 | 
			
		||||
            'sync_schedule',
 | 
			
		||||
            'allow_registrations',
 | 
			
		||||
            HTML('<h3>User settings</h3>'),
 | 
			
		||||
            'auto_download',
 | 
			
		||||
            'download_location',
 | 
			
		||||
            Submit('submit', value='Continue'),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class DoneForm(forms.Form):
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.helper = FormHelper()
 | 
			
		||||
        self.helper.layout = Layout(
 | 
			
		||||
            Submit('submit', value='Finish')
 | 
			
		||||
        )
 | 
			
		||||
		Reference in New Issue
	
	Block a user