mirror of
				https://github.com/chibicitiberiu/ytsm.git
				synced 2024-02-24 05:43:31 +00:00 
			
		
		
		
	First time setup improvements
This commit is contained in:
		| @@ -1,6 +1,7 @@ | |||||||
| import logging | import logging | ||||||
| import logging.handlers | import logging.handlers | ||||||
| import os | import os | ||||||
|  | import sys | ||||||
|  |  | ||||||
| from django.conf import settings as dj_settings | from django.conf import settings as dj_settings | ||||||
|  |  | ||||||
| @@ -9,20 +10,29 @@ from .management.jobs.synchronize import schedule_synchronize_global | |||||||
| from .scheduler import initialize_scheduler | from .scheduler import initialize_scheduler | ||||||
| from django.db.utils import OperationalError | 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') | ||||||
|     os.makedirs(log_dir, exist_ok=True) |     os.makedirs(log_dir, exist_ok=True) | ||||||
|  |  | ||||||
|  |     handlers = [] | ||||||
|  |  | ||||||
|     file_handler = logging.handlers.RotatingFileHandler( |     file_handler = logging.handlers.RotatingFileHandler( | ||||||
|         os.path.join(log_dir, "log.log"), |         os.path.join(log_dir, "log.log"), | ||||||
|         maxBytes=1024 * 1024, |         maxBytes=1024 * 1024, | ||||||
|         backupCount=5 |         backupCount=5 | ||||||
|     ) |     ) | ||||||
|  |     handlers.append(file_handler) | ||||||
|  |  | ||||||
|  |     if dj_settings.DEBUG: | ||||||
|  |         console_handler = logging.StreamHandler(stream=sys.stdout) | ||||||
|  |         console_handler.setLevel(logging.DEBUG) | ||||||
|  |         handlers.append(console_handler) | ||||||
|  |  | ||||||
|     logging.basicConfig( |     logging.basicConfig( | ||||||
|         level=dj_settings.LOG_LEVEL, |         level=dj_settings.LOG_LEVEL, | ||||||
|         format=dj_settings.LOG_FORMAT, |         format=dj_settings.LOG_FORMAT, | ||||||
|         handlers=[file_handler] |         handlers=handlers | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| #main_body { | #main_body { | ||||||
|   margin-bottom: 4rem; } |   margin-bottom: 4rem; | ||||||
|  |   margin-top: 2rem; } | ||||||
|  |  | ||||||
| #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,6 +2,7 @@ $accent-color: #007bff; | |||||||
|  |  | ||||||
| #main_body { | #main_body { | ||||||
|     margin-bottom: 4rem; |     margin-bottom: 4rem; | ||||||
|  |     margin-top: 2rem; | ||||||
| } | } | ||||||
|  |  | ||||||
| #main_footer { | #main_footer { | ||||||
|   | |||||||
| @@ -8,10 +8,10 @@ | |||||||
|  |  | ||||||
|         <h1>Step 1: Set up YouTube API key (optional)</h1> |         <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. |         <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 |         To access this API, YouTube requires users to 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> |         uses this key to control access and 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 |         <p>To use this program, it is <em>recommended</em>, but not required, 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 |         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> |         this program from reaching YouTube. Follow the steps below, or press <strong>Skip</strong> to use the provided key.</p> | ||||||
|  |  | ||||||
| @@ -59,8 +59,6 @@ | |||||||
|  |  | ||||||
|         {% crispy form %} |         {% crispy form %} | ||||||
|  |  | ||||||
|         <a href="{% url 'first_time_2' %}">Skip</a> |  | ||||||
|  |  | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
| {% endblock body %} | {% endblock body %} | ||||||
| @@ -24,12 +24,6 @@ | |||||||
|             {% endif %} |             {% endif %} | ||||||
|         {% endif %} |         {% endif %} | ||||||
|  |  | ||||||
|         {% if is_first_user %} |  | ||||||
|             <div class="alert alert-info" role="alert"> |  | ||||||
|                 Since this is the first user to register, it will be the system administrator. |  | ||||||
|             </div> |  | ||||||
|         {% endif %} |  | ||||||
|  |  | ||||||
|         <h5>Register</h5> |         <h5>Register</h5> | ||||||
|  |  | ||||||
|         {% crispy form %} |         {% crispy form %} | ||||||
|   | |||||||
| @@ -64,6 +64,7 @@ urlpatterns = [ | |||||||
|     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.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/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'), | ||||||
|  |  | ||||||
|   | |||||||
| @@ -58,13 +58,8 @@ class RegisterView(FormView): | |||||||
|     success_url = reverse_lazy('register_done') |     success_url = reverse_lazy('register_done') | ||||||
|  |  | ||||||
|     def form_valid(self, form): |     def form_valid(self, form): | ||||||
|         is_first_user = (User.objects.count() == 0) |  | ||||||
|  |  | ||||||
|         user = form.save() |         form.save() | ||||||
|         if is_first_user: |  | ||||||
|             user.is_staff = True |  | ||||||
|             user.is_superuser = True |  | ||||||
|             user.save() |  | ||||||
|  |  | ||||||
|         username = form.cleaned_data.get('username') |         username = form.cleaned_data.get('username') | ||||||
|         password = form.cleaned_data.get('password1') |         password = form.cleaned_data.get('password1') | ||||||
|   | |||||||
| @@ -1,26 +1,35 @@ | |||||||
| from crispy_forms.helper import FormHelper | from crispy_forms.helper import FormHelper | ||||||
| from crispy_forms.layout import Layout, HTML, Submit | from crispy_forms.layout import Layout, HTML, Submit, Column | ||||||
| from django import forms | from django import forms | ||||||
|  | from django.contrib.auth import authenticate, login | ||||||
| from django.contrib.auth.mixins import LoginRequiredMixin | from django.contrib.auth.mixins import LoginRequiredMixin | ||||||
|  | from django.contrib.auth.models import User | ||||||
| from django.urls import reverse_lazy | from django.urls import reverse_lazy | ||||||
| from django.views.generic import UpdateView, FormView | from django.views.generic import UpdateView, FormView | ||||||
| from django.shortcuts import render, redirect | from django.shortcuts import render, redirect | ||||||
| from YtManagerApp.views.auth import RegisterView | from YtManagerApp.views.auth import RegisterView, ExtendedUserCreationForm, ExtendedAuthenticationForm | ||||||
| from YtManagerApp.models import UserSettings | from YtManagerApp.models import UserSettings | ||||||
|  |  | ||||||
| from YtManagerApp.management.appconfig import global_prefs | from YtManagerApp.management.appconfig import global_prefs | ||||||
| from django.http import HttpResponseForbidden | from django.http import HttpResponseForbidden | ||||||
|  |  | ||||||
|  | import logging | ||||||
|  |  | ||||||
|  |  | ||||||
|  | logger = logging.getLogger("FirstTimeWizard") | ||||||
|  |  | ||||||
|  |  | ||||||
| class ProtectInitializedMixin(object): | class ProtectInitializedMixin(object): | ||||||
|  |  | ||||||
|     def get(self, request, *args, **kwargs): |     def get(self, request, *args, **kwargs): | ||||||
|         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.") | ||||||
|             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): | ||||||
|         if global_prefs['hidden__initialized']: |         if global_prefs['hidden__initialized']: | ||||||
|  |             logger.debug(f"Attempted to post {request.path}, but first time setup already run.") | ||||||
|             return HttpResponseForbidden() |             return HttpResponseForbidden() | ||||||
|         return super().post(request, *args, **kwargs) |         return super().post(request, *args, **kwargs) | ||||||
|  |  | ||||||
| @@ -54,7 +63,10 @@ class Step1ApiKeyForm(forms.Form): | |||||||
|         self.helper = FormHelper() |         self.helper = FormHelper() | ||||||
|         self.helper.layout = Layout( |         self.helper.layout = Layout( | ||||||
|             'api_key', |             'api_key', | ||||||
|  |             Column( | ||||||
|                 Submit('submit', value='Continue'), |                 Submit('submit', value='Continue'), | ||||||
|  |                 HTML('<a href="{% url \'first_time_2\' %}" class="btn">Skip</a>') | ||||||
|  |             ) | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -73,9 +85,50 @@ class Step1ApiKeyView(ProtectInitializedMixin, FormView): | |||||||
| # | # | ||||||
| # Step 2: create admin user | # Step 2: create admin user | ||||||
| # | # | ||||||
| class Step2CreateAdminUserView(ProtectInitializedMixin, RegisterView): | class Step2CreateAdminUserView(ProtectInitializedMixin, 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 get(self, request, *args, **kwargs): | ||||||
|  |  | ||||||
|  |         # 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') | ||||||
|  |  | ||||||
|  |         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_valid(self, form): | ||||||
|  |         login(self.request, form.get_user()) | ||||||
|  |         return super().form_valid(form) | ||||||
|  |  | ||||||
|  |  | ||||||
| # | # | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user