Implemented first time setup wizard. There are still some problems to be solved.
@ -7,7 +7,7 @@ from django.conf import settings as dj_settings
|
|||||||
from .management.appconfig import global_prefs
|
from .management.appconfig import global_prefs
|
||||||
from .management.jobs.synchronize import schedule_synchronize_global
|
from .management.jobs.synchronize import schedule_synchronize_global
|
||||||
from .scheduler import initialize_scheduler
|
from .scheduler import initialize_scheduler
|
||||||
|
from django.db.utils import OperationalError
|
||||||
|
|
||||||
def __initialize_logger():
|
def __initialize_logger():
|
||||||
log_dir = os.path.join(dj_settings.DATA_DIR, 'logs')
|
log_dir = os.path.join(dj_settings.DATA_DIR, 'logs')
|
||||||
@ -29,8 +29,12 @@ def __initialize_logger():
|
|||||||
def main():
|
def main():
|
||||||
__initialize_logger()
|
__initialize_logger()
|
||||||
|
|
||||||
if global_prefs['hidden__initialized']:
|
try:
|
||||||
initialize_scheduler()
|
if global_prefs['hidden__initialized']:
|
||||||
schedule_synchronize_global()
|
initialize_scheduler()
|
||||||
|
schedule_synchronize_global()
|
||||||
|
except OperationalError:
|
||||||
|
# Settings table is not created when running migrate or makemigrations, so just don't do anything in this case.
|
||||||
|
pass
|
||||||
|
|
||||||
logging.info('Initialization complete.')
|
logging.info('Initialization complete.')
|
||||||
|
@ -4,6 +4,8 @@ from dynamic_preferences.registries import global_preferences_registry
|
|||||||
from dynamic_preferences.users.registries import user_preferences_registry
|
from dynamic_preferences.users.registries import user_preferences_registry
|
||||||
|
|
||||||
from YtManagerApp.models import VIDEO_ORDER_CHOICES
|
from YtManagerApp.models import VIDEO_ORDER_CHOICES
|
||||||
|
from django.conf import settings
|
||||||
|
import os
|
||||||
|
|
||||||
# we create some section objects to link related preferences together
|
# we create some section objects to link related preferences together
|
||||||
|
|
||||||
@ -83,7 +85,7 @@ class AutoDeleteWatched(BooleanPreference):
|
|||||||
@user_preferences_registry.register
|
@user_preferences_registry.register
|
||||||
class AutoDownloadEnabled(BooleanPreference):
|
class AutoDownloadEnabled(BooleanPreference):
|
||||||
section = downloader
|
section = downloader
|
||||||
name = 'download_enabled'
|
name = 'auto_enabled'
|
||||||
default = True
|
default = True
|
||||||
required = True
|
required = True
|
||||||
|
|
||||||
@ -91,7 +93,7 @@ class AutoDownloadEnabled(BooleanPreference):
|
|||||||
@user_preferences_registry.register
|
@user_preferences_registry.register
|
||||||
class DownloadGlobalLimit(IntegerPreference):
|
class DownloadGlobalLimit(IntegerPreference):
|
||||||
section = downloader
|
section = downloader
|
||||||
name = 'download_global_limit'
|
name = 'global_limit'
|
||||||
default = None
|
default = None
|
||||||
required = False
|
required = False
|
||||||
|
|
||||||
@ -107,7 +109,7 @@ class DownloadGlobalSizeLimit(IntegerPreference):
|
|||||||
@user_preferences_registry.register
|
@user_preferences_registry.register
|
||||||
class DownloadSubscriptionLimit(IntegerPreference):
|
class DownloadSubscriptionLimit(IntegerPreference):
|
||||||
section = downloader
|
section = downloader
|
||||||
name = 'download_limit_per_subscription'
|
name = 'limit_per_subscription'
|
||||||
default = 5
|
default = 5
|
||||||
required = False
|
required = False
|
||||||
|
|
||||||
@ -115,7 +117,7 @@ class DownloadSubscriptionLimit(IntegerPreference):
|
|||||||
@user_preferences_registry.register
|
@user_preferences_registry.register
|
||||||
class DownloadMaxAttempts(IntegerPreference):
|
class DownloadMaxAttempts(IntegerPreference):
|
||||||
section = downloader
|
section = downloader
|
||||||
name = 'download_max_attempts'
|
name = 'max_download_attempts'
|
||||||
default = 3
|
default = 3
|
||||||
required = True
|
required = True
|
||||||
|
|
||||||
@ -133,7 +135,7 @@ class DownloadOrder(ChoicePreference):
|
|||||||
class DownloadPath(StringPreference):
|
class DownloadPath(StringPreference):
|
||||||
section = downloader
|
section = downloader
|
||||||
name = 'download_path'
|
name = 'download_path'
|
||||||
default = None
|
default = os.path.join(settings.DATA_DIR, 'downloads')
|
||||||
required = False
|
required = False
|
||||||
|
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ def synchronize_subscription(subscription: Subscription):
|
|||||||
|
|
||||||
|
|
||||||
def schedule_synchronize_global():
|
def schedule_synchronize_global():
|
||||||
trigger = CronTrigger.from_crontab(global_prefs['synchronization_schedule'])
|
trigger = CronTrigger.from_crontab(global_prefs['scheduler__synchronization_schedule'])
|
||||||
job = scheduler.scheduler.add_job(synchronize, trigger, max_instances=1, coalesce=True)
|
job = scheduler.scheduler.add_job(synchronize, trigger, max_instances=1, coalesce=True)
|
||||||
log.info('Scheduled synchronize job job=%s', job.id)
|
log.info('Scheduled synchronize job job=%s', job.id)
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import logging
|
import logging
|
||||||
import sys
|
|
||||||
from apscheduler.schedulers.background import BackgroundScheduler
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
from django.conf import settings
|
|
||||||
|
from YtManagerApp.management.appconfig import global_prefs
|
||||||
|
|
||||||
scheduler: BackgroundScheduler = None
|
scheduler: BackgroundScheduler = None
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ def initialize_scheduler():
|
|||||||
executors = {
|
executors = {
|
||||||
'default': {
|
'default': {
|
||||||
'type': 'threadpool',
|
'type': 'threadpool',
|
||||||
'max_workers': settings.SCHEDULER_CONCURRENCY
|
'max_workers': global_prefs['scheduler__concurrency']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
job_defaults = {
|
job_defaults = {
|
||||||
|
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 12 KiB |
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>Done!</h1>
|
<h1>Done!</h1>
|
||||||
<p>The application is now ready to use!</p>
|
<p>The setup is finished, and the application is now ready to use!</p>
|
||||||
{% crispy form %}
|
{% crispy form %}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -0,0 +1,66 @@
|
|||||||
|
{% extends "YtManagerApp/master_default.html" %}
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
|
||||||
|
<h1>Step 1: Set up YouTube API key (optional)</h1>
|
||||||
|
<p>This program uses the YouTube API in order to obtain information about videos, channels and playlists.
|
||||||
|
In order to access this API, YouTube requires that we register on their site and request an API key. YouTube
|
||||||
|
uses this key in order to limit the number of requests made to their platform, in order to prevent abuses.</p>
|
||||||
|
|
||||||
|
<p>To use this program, it is <em>recommended</em> that you create an API key for your own account. While a key
|
||||||
|
is already provided the developer, there is a chance that the quota limits will be reached, which will prevent
|
||||||
|
this program from reaching YouTube. Follow the steps below, or press <strong>Skip</strong> to use the provided key.</p>
|
||||||
|
|
||||||
|
<h4>
|
||||||
|
<a data-toggle="collapse" href="#HowToObtainKey" role="button" aria-expanded="false" aria-controls="HowToObtainKey">
|
||||||
|
<span class="typcn typcn-arrow-sorted-down"></span>How to obtain a key
|
||||||
|
</a>
|
||||||
|
</h4>
|
||||||
|
|
||||||
|
<div class="collapse" id="HowToObtainKey">
|
||||||
|
<ol>
|
||||||
|
<li>Visit <a href="https://developers.google.com/">https://developers.google.com/</a>, log in or create an account, if necessary.</li>
|
||||||
|
<li>Go to <a href="https://console.developers.google.com/project"></a>, and click on the <strong>Create project</strong> button.
|
||||||
|
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_create_project.png' %}">
|
||||||
|
</li>
|
||||||
|
<li>Give a name to the project, and then click on <strong>Create</strong>. Wait for a few seconds, until Google finishes creating the project.
|
||||||
|
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_project_name.png' %}">
|
||||||
|
</li>
|
||||||
|
<li>Make sure the newly created project is selected in the top bar and then, in the left sidebar,
|
||||||
|
go to <strong>APIs & Services</strong> - <strong>Library</strong>.
|
||||||
|
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_goto_apis.png' %}">
|
||||||
|
</li>
|
||||||
|
<li>Find and click on the <strong>YouTube Data API v3</strong> from the list.
|
||||||
|
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_select_ytapi.png' %}">
|
||||||
|
</li>
|
||||||
|
<li>Click <strong>Enable</strong> to enable the YouTube API for your account.
|
||||||
|
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_enable_ytapi.png' %}">
|
||||||
|
</li>
|
||||||
|
<li>In the navigation sidebar, go to the <strong>Credentials</strong> page.
|
||||||
|
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_goto_credentials.png' %}">
|
||||||
|
</li>
|
||||||
|
<li>Click on <strong>Create credentials</strong>.
|
||||||
|
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_create_credential.png' %}">
|
||||||
|
</li>
|
||||||
|
<li>Fill the requested information; we will need access to the <strong>YouTube Data v3</strong>,
|
||||||
|
we will be calling the API from a <strong>Web server</strong>, and we will access the <strong>Public data</strong>.
|
||||||
|
After filling the information, click on the <strong>What credentials do I need?</strong> button.
|
||||||
|
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_create_credential_options.png' %}">
|
||||||
|
</li>
|
||||||
|
<li>Copy the created key in the box below, and then hit <strong>Done</strong>.
|
||||||
|
<img class="d-block" src="{% static 'YtManagerApp/img/first_time/ytapi_done.png' %}">
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% crispy form %}
|
||||||
|
|
||||||
|
<a href="{% url 'first_time_2' %}">Skip</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock body %}
|
@ -0,0 +1,15 @@
|
|||||||
|
{% extends "YtManagerApp/master_default.html" %}
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
|
||||||
|
<h1>Step 2: Create an administrator account</h1>
|
||||||
|
|
||||||
|
{% crispy form %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock body %}
|
@ -0,0 +1,17 @@
|
|||||||
|
{% extends "YtManagerApp/master_default.html" %}
|
||||||
|
{% load crispy_forms_tags %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
|
||||||
|
<h1>Step 3: Configure the server</h1>
|
||||||
|
|
||||||
|
<p>Here you can customize some basic options for the application. There are many more options which can be changed in the settings page.</p>
|
||||||
|
|
||||||
|
{% crispy form %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock body %}
|
@ -24,6 +24,7 @@ from .views.auth import ExtendedLoginView, RegisterView, RegisterDoneView
|
|||||||
from .views.index import index, ajax_get_tree, ajax_get_videos, CreateFolderModal, UpdateFolderModal, DeleteFolderModal, \
|
from .views.index import index, ajax_get_tree, ajax_get_videos, CreateFolderModal, UpdateFolderModal, DeleteFolderModal, \
|
||||||
CreateSubscriptionModal, UpdateSubscriptionModal, DeleteSubscriptionModal, ImportSubscriptionsModal
|
CreateSubscriptionModal, UpdateSubscriptionModal, DeleteSubscriptionModal, ImportSubscriptionsModal
|
||||||
from .views.settings import SettingsView
|
from .views.settings import SettingsView
|
||||||
|
from .views import first_time
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
# Authentication URLs
|
# Authentication URLs
|
||||||
@ -59,4 +60,11 @@ urlpatterns = [
|
|||||||
path('', index, name='home'),
|
path('', index, name='home'),
|
||||||
path('settings/', SettingsView.as_view(), name='settings'),
|
path('settings/', SettingsView.as_view(), name='settings'),
|
||||||
|
|
||||||
|
# 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/step3_config', first_time.Step3ConfigureView.as_view(), name='first_time_3'),
|
||||||
|
path('first_time/done', first_time.DoneView.as_view(), name='first_time_done'),
|
||||||
|
|
||||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
@ -3,49 +3,165 @@ from crispy_forms.layout import Layout, HTML, Submit
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.views.generic import UpdateView
|
from django.views.generic import UpdateView, FormView
|
||||||
|
from django.shortcuts import render, redirect
|
||||||
|
from YtManagerApp.views.auth import RegisterView
|
||||||
from YtManagerApp.models import UserSettings
|
from YtManagerApp.models import UserSettings
|
||||||
|
|
||||||
|
from YtManagerApp.management.appconfig import global_prefs
|
||||||
|
from django.http import HttpResponseForbidden
|
||||||
|
|
||||||
class SettingsForm(forms.ModelForm):
|
|
||||||
class Meta:
|
class ProtectInitializedMixin(object):
|
||||||
model = UserSettings
|
|
||||||
exclude = ['user']
|
def get(self, request, *args, **kwargs):
|
||||||
|
if global_prefs['hidden__initialized']:
|
||||||
|
return redirect('home')
|
||||||
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def post(self, request, *args, **kwargs):
|
||||||
|
if global_prefs['hidden__initialized']:
|
||||||
|
return HttpResponseForbidden()
|
||||||
|
return super().post(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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):
|
||||||
|
template_name = 'YtManagerApp/first_time_setup/step0_welcome.html'
|
||||||
|
form_class = Step0WelcomeForm
|
||||||
|
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):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.helper = FormHelper()
|
self.helper = FormHelper()
|
||||||
self.helper.form_class = 'form-horizontal'
|
|
||||||
self.helper.label_class = 'col-lg-3'
|
|
||||||
self.helper.field_class = 'col-lg-9'
|
|
||||||
self.helper.layout = Layout(
|
self.helper.layout = Layout(
|
||||||
'mark_deleted_as_watched',
|
'api_key',
|
||||||
'delete_watched',
|
Submit('submit', value='Continue'),
|
||||||
HTML('<h2>Download settings</h2>'),
|
|
||||||
'auto_download',
|
|
||||||
'download_path',
|
|
||||||
'download_file_pattern',
|
|
||||||
'download_format',
|
|
||||||
'download_order',
|
|
||||||
'download_global_limit',
|
|
||||||
'download_subscription_limit',
|
|
||||||
HTML('<h2>Subtitles download settings</h2>'),
|
|
||||||
'download_subtitles',
|
|
||||||
'download_subtitles_langs',
|
|
||||||
'download_subtitles_all',
|
|
||||||
'download_autogenerated_subtitles',
|
|
||||||
'download_subtitles_format',
|
|
||||||
Submit('submit', value='Save')
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SettingsView(LoginRequiredMixin, UpdateView):
|
class Step1ApiKeyView(ProtectInitializedMixin, FormView):
|
||||||
form_class = SettingsForm
|
template_name = 'YtManagerApp/first_time_setup/step1_apikey.html'
|
||||||
model = UserSettings
|
form_class = Step1ApiKeyForm
|
||||||
template_name = 'YtManagerApp/settings.html'
|
success_url = reverse_lazy('first_time_2')
|
||||||
success_url = reverse_lazy('home')
|
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def form_valid(self, form):
|
||||||
obj, _ = self.model.objects.get_or_create(user=self.request.user)
|
key = form.cleaned_data['api_key']
|
||||||
return obj
|
# TODO: validate key
|
||||||
|
if key is not None and len(key) > 0:
|
||||||
|
global_prefs['general__youtube_api_key'] = key
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Step 2: create admin user
|
||||||
|
#
|
||||||
|
class Step2CreateAdminUserView(ProtectInitializedMixin, RegisterView):
|
||||||
|
template_name = 'YtManagerApp/first_time_setup/step2_admin.html'
|
||||||
|
success_url = reverse_lazy('first_time_3')
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# 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):
|
||||||
|
template_name = 'YtManagerApp/first_time_setup/step3_configure.html'
|
||||||
|
form_class = Step3ConfigureForm
|
||||||
|
success_url = reverse_lazy('first_time_done')
|
||||||
|
|
||||||
|
def form_valid(self, form):
|
||||||
|
allow_registrations = form.cleaned_data['allow_registrations']
|
||||||
|
if allow_registrations is not None:
|
||||||
|
global_prefs['general__allow_registrations'] = allow_registrations
|
||||||
|
|
||||||
|
sync_schedule = form.cleaned_data['sync_schedule']
|
||||||
|
if sync_schedule is not None and len(sync_schedule) > 0:
|
||||||
|
global_prefs['scheduler__synchronization_schedule'] = sync_schedule
|
||||||
|
|
||||||
|
auto_download = form.cleaned_data['auto_download']
|
||||||
|
if auto_download is not None:
|
||||||
|
self.request.user.preferences['downloader__auto_enabled'] = auto_download
|
||||||
|
|
||||||
|
download_location = form.cleaned_data['download_location']
|
||||||
|
if download_location is not None and len(download_location) > 0:
|
||||||
|
self.request.user.preferences['downloader__download_path'] = download_location
|
||||||
|
|
||||||
|
# Set initialized to true
|
||||||
|
global_prefs['hidden__initialized'] = True
|
||||||
|
|
||||||
|
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
|
||||||
|
success_url = reverse_lazy('home')
|
||||||
|
@ -5,11 +5,12 @@ from django.contrib.auth.decorators import login_required
|
|||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.http import HttpRequest, HttpResponseBadRequest, JsonResponse
|
from django.http import HttpRequest, HttpResponseBadRequest, JsonResponse
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render, redirect
|
||||||
from django.views.generic import CreateView, UpdateView, DeleteView, FormView
|
from django.views.generic import CreateView, UpdateView, DeleteView, FormView
|
||||||
from django.views.generic.edit import FormMixin
|
from django.views.generic.edit import FormMixin
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from YtManagerApp.management.videos import get_videos
|
from YtManagerApp.management.videos import get_videos
|
||||||
|
from YtManagerApp.management.appconfig import global_prefs
|
||||||
from YtManagerApp.models import Subscription, SubscriptionFolder, VIDEO_ORDER_CHOICES, VIDEO_ORDER_MAPPING
|
from YtManagerApp.models import Subscription, SubscriptionFolder, VIDEO_ORDER_CHOICES, VIDEO_ORDER_MAPPING
|
||||||
from YtManagerApp.utils import youtube, subscription_file_parser
|
from YtManagerApp.utils import youtube, subscription_file_parser
|
||||||
from YtManagerApp.views.controls.modal import ModalMixin
|
from YtManagerApp.views.controls.modal import ModalMixin
|
||||||
@ -94,6 +95,10 @@ def __tree_sub_id(sub_id):
|
|||||||
|
|
||||||
|
|
||||||
def index(request: HttpRequest):
|
def index(request: HttpRequest):
|
||||||
|
|
||||||
|
if not global_prefs['hidden__initialized']:
|
||||||
|
return redirect('first_time_0')
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'config_errors': settings.CONFIG_ERRORS,
|
'config_errors': settings.CONFIG_ERRORS,
|
||||||
'config_warnings': settings.CONFIG_WARNINGS,
|
'config_warnings': settings.CONFIG_WARNINGS,
|
||||||
|