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 os | ||||||
|  | import sys | ||||||
| import logging | import logging | ||||||
| from os.path import dirname as up | 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")) | 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")) | 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") | STATIC_ROOT = os.path.join(PROJECT_ROOT, "static") | ||||||
| MEDIA_ROOT = os.path.join(DATA_DIR, 'media') | MEDIA_ROOT = os.path.join(DATA_DIR, 'media') | ||||||
| @@ -154,6 +154,16 @@ CONFIG_ERRORS = [] | |||||||
| CONFIG_WARNINGS = [] | 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 | # 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 |     # Get from config parser | ||||||
|     if boolean: |     if boolean: | ||||||
|         try: |         try: | ||||||
|             return cfgparser.getboolean('global', name, fallback=fallback) |             return cfgparser.getboolean('global', name, fallback=fallback, vars=CFG_PARSER_OPTS) | ||||||
|         except ValueError: |         except ValueError: | ||||||
|             CONFIG_WARNINGS.append(f'config.ini file: Value set for option global.{name} is not valid! ' |             CONFIG_WARNINGS.append(f'config.ini file: Value set for option global.{name} is not valid! ' | ||||||
|                                    f'Valid options: true, false, on, off.') |                                    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: |     if integer: | ||||||
|         try: |         try: | ||||||
|             return cfgparser.getint('global', name, fallback=fallback) |             return cfgparser.getint('global', name, fallback=fallback, vars=CFG_PARSER_OPTS) | ||||||
|         except ValueError: |         except ValueError: | ||||||
|             CONFIG_WARNINGS.append(f'config.ini file: Value set for option global.{name} must be an integer number! ') |             CONFIG_WARNINGS.append(f'config.ini file: Value set for option global.{name} must be an integer number! ') | ||||||
|             return fallback |             return fallback | ||||||
|  |  | ||||||
|     return cfgparser.get('global', name, fallback=fallback) |     return cfgparser.get('global', name, fallback=fallback, vars=CFG_PARSER_OPTS) | ||||||
|  |  | ||||||
|  |  | ||||||
| def load_config_ini(): | def load_config_ini(): | ||||||
| @@ -210,6 +220,13 @@ def load_config_ini(): | |||||||
|     from YtManagerApp.utils.extended_interpolation_with_env import ExtendedInterpolatorWithEnv |     from YtManagerApp.utils.extended_interpolation_with_env import ExtendedInterpolatorWithEnv | ||||||
|     import dj_database_url |     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 = ConfigParser(allow_no_value=True, interpolation=ExtendedInterpolatorWithEnv()) | ||||||
|  |  | ||||||
|     cfg_file = os.path.join(CONFIG_DIR, "config.ini") |     cfg_file = os.path.join(CONFIG_DIR, "config.ini") | ||||||
| @@ -235,7 +252,7 @@ def load_config_ini(): | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     if cfg.has_option('global', 'DatabaseURL'): |     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: |     else: | ||||||
|         DATABASES['default'] = { |         DATABASES['default'] = { | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| #main_body { | #main_body { | ||||||
|   margin-bottom: 4rem; |   margin-bottom: 4rem; | ||||||
|   margin-top: 2rem; } |   margin-top: 0; } | ||||||
|  |  | ||||||
| #main_footer { | #main_footer { | ||||||
|   position: fixed; |   position: fixed; | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
| "version": 3, | "version": 3, | ||||||
| "mappings": "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", | "mappings": "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", | ||||||
| "sources": ["style.scss"], | "sources": ["style.scss"], | ||||||
| "names": [], | "names": [], | ||||||
| "file": "style.css" | "file": "style.css" | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ $accent-color: #007bff; | |||||||
|  |  | ||||||
| #main_body { | #main_body { | ||||||
|     margin-bottom: 4rem; |     margin-bottom: 4rem; | ||||||
|     margin-top: 2rem; |     margin-top: 0; | ||||||
| } | } | ||||||
|  |  | ||||||
| #main_footer { | #main_footer { | ||||||
|   | |||||||
| @@ -63,8 +63,7 @@ urlpatterns = [ | |||||||
|     # First time setup |     # First time setup | ||||||
|     path('first_time/step0_welcome', first_time.Step0WelcomeView.as_view(), name='first_time_0'), |     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/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_admin', first_time.Step2SetupAdminUserView.as_view(), name='first_time_2'), | ||||||
|     path('first_time/step2_login', first_time.Step2LoginAdminUserView.as_view(), name='first_time_2_login'), |  | ||||||
|     path('first_time/step3_config', first_time.Step3ConfigureView.as_view(), name='first_time_3'), |     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'), |     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 import login, authenticate | ||||||
| from django.contrib.auth.forms import AuthenticationForm, UserCreationForm |  | ||||||
| from django.contrib.auth.mixins import LoginRequiredMixin | from django.contrib.auth.mixins import LoginRequiredMixin | ||||||
| from django.contrib.auth.models import User | from django.contrib.auth.models import User | ||||||
| from django.contrib.auth.views import LoginView | from django.contrib.auth.views import LoginView | ||||||
| from django.urls import reverse_lazy | from django.urls import reverse_lazy | ||||||
| from django.views.generic import FormView, TemplateView | from django.views.generic import FormView, TemplateView | ||||||
|  |  | ||||||
|  | from .forms.auth import ExtendedAuthenticationForm, ExtendedUserCreationForm | ||||||
| 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 ExtendedLoginView(LoginView): | class ExtendedLoginView(LoginView): | ||||||
|     form_class = ExtendedAuthenticationForm |     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): | class RegisterView(FormView): | ||||||
|     template_name = 'registration/register.html' |     template_name = 'registration/register.html' | ||||||
|     form_class = ExtendedUserCreationForm |     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 | 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") | logger = logging.getLogger("FirstTimeWizard") | ||||||
|  |  | ||||||
|  |  | ||||||
| class ProtectInitializedMixin(object): | class WizardStepMixin(object): | ||||||
|  |  | ||||||
|     def get(self, request, *args, **kwargs): |     def get(self, request, *args, **kwargs): | ||||||
|  |  | ||||||
|  |         # Prevent access if application is already initialized | ||||||
|         if global_prefs['hidden__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 redirect('home') | ||||||
|  |  | ||||||
|         return super().get(request, *args, **kwargs) |         return super().get(request, *args, **kwargs) | ||||||
|  |  | ||||||
|     def post(self, request, *args, **kwargs): |     def post(self, request, *args, **kwargs): | ||||||
| @@ -37,44 +35,25 @@ class ProtectInitializedMixin(object): | |||||||
| # | # | ||||||
| # Step 0: welcome screen | # Step 0: welcome screen | ||||||
| # | # | ||||||
| class Step0WelcomeForm(forms.Form): | class Step0WelcomeView(WizardStepMixin, FormView): | ||||||
|     def __init__(self, *args, **kwargs): |  | ||||||
|         super().__init__(*args, **kwargs) |  | ||||||
|         self.helper = FormHelper() |  | ||||||
|         self.helper.layout = Layout( |  | ||||||
|             Submit('submit', value='Continue') |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class Step0WelcomeView(ProtectInitializedMixin, FormView): |  | ||||||
|     template_name = 'YtManagerApp/first_time_setup/step0_welcome.html' |     template_name = 'YtManagerApp/first_time_setup/step0_welcome.html' | ||||||
|     form_class = Step0WelcomeForm |     form_class = WelcomeForm | ||||||
|     success_url = reverse_lazy('first_time_1') |     success_url = reverse_lazy('first_time_1') | ||||||
|  |  | ||||||
|  |  | ||||||
| # | # | ||||||
| # Step 1: setup API key | # Step 1: setup API key | ||||||
| # | # | ||||||
| class Step1ApiKeyForm(forms.Form): | class Step1ApiKeyView(WizardStepMixin, FormView): | ||||||
|     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): |  | ||||||
|     template_name = 'YtManagerApp/first_time_setup/step1_apikey.html' |     template_name = 'YtManagerApp/first_time_setup/step1_apikey.html' | ||||||
|     form_class = Step1ApiKeyForm |     form_class = ApiKeyForm | ||||||
|     success_url = reverse_lazy('first_time_2') |     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): |     def form_valid(self, form): | ||||||
|         key = form.cleaned_data['api_key'] |         key = form.cleaned_data['api_key'] | ||||||
|         # TODO: validate key |         # TODO: validate key | ||||||
| @@ -85,26 +64,50 @@ class Step1ApiKeyView(ProtectInitializedMixin, FormView): | |||||||
| # | # | ||||||
| # Step 2: create admin user | # Step 2: create admin user | ||||||
| # | # | ||||||
| class Step2CreateAdminUserView(ProtectInitializedMixin, FormView): | class Step2SetupAdminUserView(WizardStepMixin, FormView): | ||||||
|     template_name = 'YtManagerApp/first_time_setup/step2_admin.html' |     template_name = 'YtManagerApp/first_time_setup/step2_admin.html' | ||||||
|     success_url = reverse_lazy('first_time_3') |     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): |     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 |         # Skip if admin is already logged in | ||||||
|         if request.user.is_authenticated and request.user.is_superuser: |         if request.user.is_authenticated and request.user.is_superuser: | ||||||
|             logger.debug("Admin user already exists and is logged in!") |             logger.debug("Admin user already exists and is logged in!") | ||||||
|             return redirect(self.success_url) |             return redirect(self.success_url) | ||||||
|  |  | ||||||
|         # Check if an admin user already exists |         # Check if an admin user already exists | ||||||
|         if User.objects.filter(is_superuser=True).count() > 0: |         elif have_admin: | ||||||
|             logger.warn("Admin user already exists! Will redirect to login page!") |             logger.debug("Admin user already exists and is not logged in!") | ||||||
|             return redirect('first_time_2_login') |             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) |         return super().get(request, *args, **kwargs) | ||||||
|  |  | ||||||
|  |     def form_invalid(self, form): | ||||||
|  |         print("FORM INVALID!") | ||||||
|  |  | ||||||
|     def form_valid(self, form): |     def form_valid(self, form): | ||||||
|  |         if isinstance(form, ExtendedAuthenticationForm): | ||||||
|  |             login(self.request, form.get_user()) | ||||||
|  |  | ||||||
|  |         elif isinstance(form, UserCreationForm): | ||||||
|             user = form.save() |             user = form.save() | ||||||
|             user.is_staff = True |             user.is_staff = True | ||||||
|             user.is_superuser = True |             user.is_superuser = True | ||||||
| @@ -115,71 +118,33 @@ class Step2CreateAdminUserView(ProtectInitializedMixin, FormView): | |||||||
|             user = authenticate(username=username, password=password) |             user = authenticate(username=username, password=password) | ||||||
|             login(self.request, user) |             login(self.request, user) | ||||||
|  |  | ||||||
|         return super().form_valid(form) |         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') | ||||||
|  |  | ||||||
| # |  | ||||||
| # 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_valid(self, form): |  | ||||||
|         login(self.request, form.get_user()) |  | ||||||
|         return super().form_valid(form) |         return super().form_valid(form) | ||||||
|  |  | ||||||
|  |  | ||||||
| # | # | ||||||
| # Step 3: configure server | # Step 3: configure server | ||||||
| # | # | ||||||
| class Step3ConfigureForm(forms.Form): | class Step3ConfigureView(WizardStepMixin, FormView): | ||||||
|  |  | ||||||
|     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): |  | ||||||
|     template_name = 'YtManagerApp/first_time_setup/step3_configure.html' |     template_name = 'YtManagerApp/first_time_setup/step3_configure.html' | ||||||
|     form_class = Step3ConfigureForm |     form_class = ServerConfigForm | ||||||
|     success_url = reverse_lazy('first_time_done') |     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): |     def form_valid(self, form): | ||||||
|         allow_registrations = form.cleaned_data['allow_registrations'] |         allow_registrations = form.cleaned_data['allow_registrations'] | ||||||
|         if allow_registrations is not None: |         if allow_registrations is not None: | ||||||
| @@ -202,18 +167,10 @@ class Step3ConfigureView(ProtectInitializedMixin, FormView): | |||||||
|          |          | ||||||
|         return super().form_valid(form) |         return super().form_valid(form) | ||||||
|  |  | ||||||
|  |  | ||||||
| # | # | ||||||
| # Done screen | # 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): | class DoneView(FormView): | ||||||
|     template_name = 'YtManagerApp/first_time_setup/done.html' |     template_name = 'YtManagerApp/first_time_setup/done.html' | ||||||
|     form_class = DoneForm |     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') | ||||||
|  |         ) | ||||||
| @@ -15,7 +15,7 @@ SecretKey=^zv8@i2h!ko2lo=%ivq(9e#x=%q*i^^)6#4@(juzdx%&0c+9a0 | |||||||
| ; Others databases might be supported by installing the corect pip package. | ; Others databases might be supported by installing the corect pip package. | ||||||
|  |  | ||||||
| DatabaseEngine=django.db.backends.sqlite3 | DatabaseEngine=django.db.backends.sqlite3 | ||||||
| DatabaseName=ytmanager.db | DatabaseName=${DATA_DIR}/ytmanager.db | ||||||
| ;DatabaseHost= | ;DatabaseHost= | ||||||
| ;DatabaseUser= | ;DatabaseUser= | ||||||
| ;DatabasePassword= | ;DatabasePassword= | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user