mirror of
				https://github.com/aykhans/series-robot-web.git
				synced 2025-10-31 14:39:59 +00:00 
			
		
		
		
	Added 'send_email' feature
This commit is contained in:
		| @@ -10,25 +10,29 @@ click-didyoumean==0.3.0 | |||||||
| click-plugins==1.1.1 | click-plugins==1.1.1 | ||||||
| click-repl==0.2.0 | click-repl==0.2.0 | ||||||
| Deprecated==1.2.13 | Deprecated==1.2.13 | ||||||
| Django==4.1 | Django==4.0.8 | ||||||
| django-autoslug==1.9.8 | django-autoslug==1.9.8 | ||||||
| django-compat==1.0.15 | django-compat==1.0.15 | ||||||
| django-crispy-forms==1.14.0 | django-crispy-forms==1.14.0 | ||||||
| django-environ==0.9.0 | django-environ==0.9.0 | ||||||
|  | django-ratelimit==4.0.0 | ||||||
| django-smtp-ssl==1.0 | django-smtp-ssl==1.0 | ||||||
|  | django-timezone-field==5.0 | ||||||
| idna==3.3 | idna==3.3 | ||||||
| kombu==5.2.4 | kombu==5.2.4 | ||||||
| packaging==21.3 | packaging==21.3 | ||||||
| prompt-toolkit==3.0.31 | prompt-toolkit==3.0.31 | ||||||
| psycopg2==2.9.3 | psycopg2==2.9.3 | ||||||
| pyparsing==3.0.9 | pyparsing==3.0.9 | ||||||
|  | python-crontab==2.6.0 | ||||||
|  | python-dateutil==2.8.2 | ||||||
| pytz==2022.2.1 | pytz==2022.2.1 | ||||||
| redis==4.3.4 | redis==4.3.4 | ||||||
| requests==2.28.1 | requests==2.28.1 | ||||||
| six==1.16.0 | six==1.16.0 | ||||||
| sqlparse==0.4.2 | sqlparse==0.4.2 | ||||||
|  | tzdata==2022.5 | ||||||
| urllib3==1.26.12 | urllib3==1.26.12 | ||||||
| vine==5.0.0 | vine==5.0.0 | ||||||
| wcwidth==0.2.5 | wcwidth==0.2.5 | ||||||
| wrapt==1.14.1 | wrapt==1.14.1 | ||||||
| gunicorn |  | ||||||
| @@ -8,7 +8,7 @@ class CustomAdmin(UserAdmin): | |||||||
|     fieldsets = ( |     fieldsets = ( | ||||||
|         (None, {'fields': ('username', 'email', 'password')}), |         (None, {'fields': ('username', 'email', 'password')}), | ||||||
|         (('Permissions'), { |         (('Permissions'), { | ||||||
|             'fields': ('is_active', 'email_notification_is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions'), |             'fields': ('is_active', 'email_is_verified', 'send_email', 'is_staff', 'is_superuser', 'groups', 'user_permissions'), | ||||||
|         }), |         }), | ||||||
|         (('Important dates'), {'fields': ('last_login', 'date_joined')}), |         (('Important dates'), {'fields': ('last_login', 'date_joined')}), | ||||||
|     ) |     ) | ||||||
| @@ -19,7 +19,7 @@ class CustomAdmin(UserAdmin): | |||||||
|         }), |         }), | ||||||
|     ) |     ) | ||||||
|     list_display = ('username', 'email', 'is_staff') |     list_display = ('username', 'email', 'is_staff') | ||||||
|     list_filter = ('is_staff', 'email_notification_is_active', 'is_superuser', 'is_active', 'groups') |     list_filter = ('is_staff', 'email_is_verified', 'send_email', 'is_superuser', 'is_active', 'groups') | ||||||
|     search_fields = ('email',) |     search_fields = ('email',) | ||||||
|     ordering = ('email',) |     ordering = ('email',) | ||||||
|     filter_horizontal = ('groups', 'user_permissions',) |     filter_horizontal = ('groups', 'user_permissions',) | ||||||
| @@ -7,4 +7,4 @@ class ProfileEditingForm(UserChangeForm): | |||||||
|  |  | ||||||
|     class Meta: |     class Meta: | ||||||
|         model = User |         model = User | ||||||
|         fields = ('email', 'username', 'imdb_api_key') |         fields = ('email', 'username', 'imdb_api_key', 'send_email') | ||||||
| @@ -11,4 +11,5 @@ class RegisterForm(UserCreationForm): | |||||||
|                 'email', |                 'email', | ||||||
|                 'password1', |                 'password1', | ||||||
|                 'password2', |                 'password2', | ||||||
|                 'imdb_api_key') |                 'imdb_api_key', | ||||||
|  |                 'send_email') | ||||||
|   | |||||||
| @@ -5,9 +5,14 @@ from django.contrib.auth.models import AbstractUser | |||||||
| class User(AbstractUser): | class User(AbstractUser): | ||||||
|     first_name = None |     first_name = None | ||||||
|     last_name = None |     last_name = None | ||||||
|     email = models.EmailField('email', unique=True, blank=True, null=True) |     email = models.EmailField('email', null=True, blank=True, unique=True) | ||||||
|     imdb_api_key = models.CharField(max_length=15, blank=False, null=False) |     imdb_api_key = models.CharField(max_length=15, blank=False, null=False) | ||||||
|     email_notification_is_active = models.BooleanField(default=False) |     email_is_verified = models.BooleanField(default=False) | ||||||
|  |     send_email = models.BooleanField(default=False) | ||||||
|  |  | ||||||
|  |     def clean(self): | ||||||
|  |         if self.email == '': | ||||||
|  |             self.email = None | ||||||
|  |  | ||||||
|     class Meta: |     class Meta: | ||||||
|         db_table = 'user' |         db_table = 'user' | ||||||
|   | |||||||
| @@ -2,19 +2,33 @@ | |||||||
| {% load static %} | {% load static %} | ||||||
|  |  | ||||||
| {% block title %} Profile {% endblock title %} | {% block title %} Profile {% endblock title %} | ||||||
|      |  | ||||||
|  |  | ||||||
| {% block content %} | {% block content %} | ||||||
|  |  | ||||||
| <div class="card mb-3"> | <div class="card mb-3"> | ||||||
|     <div class="card-body"> |     <div class="card-body"> | ||||||
|         <h5>Username: <small>{{profile.username}}</small></h5> |         <h5>Username: <small>{{profile.username}}</small></h5> | ||||||
|         {% if profile.email_notification_is_active %} |         {% if profile.email %} | ||||||
|             <h5>Email: <small style="margin-right: 0.7%;">{{profile.email|default:""}}</small> |             {% if profile.email_is_verified %} | ||||||
|                 <img src="{% static 'icons/verified.png' %}" alt="{% static 'icons/verified.png' %}" width="22px"> |                 <h5>Email: <small style="margin-right: 0.7%;">{{profile.email|default:""}}</small> | ||||||
|             </h5> |                     <img src="{% static 'icons/verified.png' %}" alt="{% static 'icons/verified.png' %}" width="22px"> | ||||||
|         {% else %} |                 </h5> | ||||||
|             <h5>Email: <small>{{profile.email|default:""}}</small></h5> |                 {% if profile.send_email %} | ||||||
|  |                     <h5>Send Email: | ||||||
|  |                         <img style="margin-left: 0.5%; margin-bottom: 0.18%;" src="{% static 'icons/true.png' %}" alt="{% static 'icons/true.png' %}" width="23px"> | ||||||
|  |                     </h5> | ||||||
|  |                 {% else %} | ||||||
|  |                     <h5>Send Email:  | ||||||
|  |                         <img style="margin-left: 0.6%; margin-bottom: 0.15%;" src="{% static 'icons/false.png' %}" alt="{% static 'icons/false.png' %}" width="18px"> | ||||||
|  |                     </h5> | ||||||
|  |                 {% endif %} | ||||||
|  |             {% else %} | ||||||
|  |                 <h5>Email: <small style="margin-right: 0.7%;">{{profile.email|default:""}}</small> | ||||||
|  |                     <a href="/account/send-otp" style="text-decoration: none; font-size: 16px;"> | ||||||
|  |                         Verify | ||||||
|  |                     </a> | ||||||
|  |                 </h5> | ||||||
|  |             {% endif %} | ||||||
|         {% endif %} |         {% endif %} | ||||||
|         <h5>IMDB API Key: <small>{{profile.imdb_api_key}}</small></h5>  |         <h5>IMDB API Key: <small>{{profile.imdb_api_key}}</small></h5>  | ||||||
|     </div> |     </div> | ||||||
|   | |||||||
| @@ -9,7 +9,10 @@ | |||||||
|  |  | ||||||
| <form enctype="multipart/form-data" method="POST"> | <form enctype="multipart/form-data" method="POST"> | ||||||
|     {% csrf_token %} |     {% csrf_token %} | ||||||
|     {{form|crispy}} |     {{form.username|as_crispy_field}} <br> | ||||||
|  |     {{form.email|as_crispy_field}} <br> | ||||||
|  |     {{form.imdb_api_key|as_crispy_field}} <br> | ||||||
|  |     {{form.send_email|as_crispy_field}} <br> | ||||||
|     <style> |     <style> | ||||||
|         .btn:hover { |         .btn:hover { | ||||||
|             background: #fff; |             background: #fff; | ||||||
|   | |||||||
| @@ -9,8 +9,13 @@ | |||||||
|  |  | ||||||
| <form method="POST" style="margin-bottom: 5.5rem;"> | <form method="POST" style="margin-bottom: 5.5rem;"> | ||||||
|     {% csrf_token %} |     {% csrf_token %} | ||||||
|     {{form|crispy}} |     {{form.username|as_crispy_field}} <br> | ||||||
|     <a href="https://imdb-api.com/Identity/Account/Register">Get API Key</a><br> |     {{form.email|as_crispy_field}} <br> | ||||||
|  |     {{form.password1|as_crispy_field}} <br> | ||||||
|  |     {{form.password2|as_crispy_field}} <br> | ||||||
|  |     {{form.imdb_api_key|as_crispy_field}} | ||||||
|  |     <a href="https://imdb-api.com/Identity/Account/Register">Get API Key</a> <br><br> | ||||||
|  |     {{form.send_email|as_crispy_field}} <br> | ||||||
|     <style> |     <style> | ||||||
|         .btn:hover { |         .btn:hover { | ||||||
|             background: #fff; |             background: #fff; | ||||||
| @@ -21,5 +26,4 @@ | |||||||
|     <p class="mb-5">Already have an account? <a href="{% url 'login' %}">Login</a></p> |     <p class="mb-5">Already have an account? <a href="{% url 'login' %}">Login</a></p> | ||||||
| </form> | </form> | ||||||
|  |  | ||||||
| {% endblock content %} | {% endblock content %} | ||||||
|      |  | ||||||
| @@ -8,6 +8,7 @@ urlpatterns = [ | |||||||
|         template_name = 'login.html' |         template_name = 'login.html' | ||||||
|         ), name='login'), |         ), name='login'), | ||||||
|     path('register', views.register_view, name='register'), |     path('register', views.register_view, name='register'), | ||||||
|  |     path('send-otp', views.send_otp_view, name='send-otp'), | ||||||
|     path('activate/<uidb64>/<token>/', views.activate_view, name='activate'), |     path('activate/<uidb64>/<token>/', views.activate_view, name='activate'), | ||||||
|     path('logout', views.logout_view, name='logout'), |     path('logout', views.logout_view, name='logout'), | ||||||
|     path('change-password', views.change_password_view, name='change-password'), |     path('change-password', views.change_password_view, name='change-password'), | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| from .register import (register_view, | from .register import register_view | ||||||
|                     activate_view) | from .email_activate import activate_view | ||||||
| from .logout import logout_view | from .logout import logout_view | ||||||
|  | from .send_otp import send_otp_view | ||||||
| from .change_password import change_password_view | from .change_password import change_password_view | ||||||
| from .profile_editing import profile_editing_view | from .profile_editing import profile_editing_view | ||||||
| from .profile_detail import ProfileDetailView | from .profile_detail import ProfileDetailView | ||||||
							
								
								
									
										21
									
								
								src/account/views/email_activate.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/account/views/email_activate.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | from django.shortcuts import redirect | ||||||
|  | from django.contrib import messages | ||||||
|  | from account.models import User | ||||||
|  | from django.contrib.auth.tokens import default_token_generator | ||||||
|  | from django.utils.http import urlsafe_base64_decode | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def activate_view(request, uidb64, token): | ||||||
|  |     try: | ||||||
|  |         uid = urlsafe_base64_decode(uidb64).decode() | ||||||
|  |         user = User._default_manager.get(pk=uid) | ||||||
|  |     except(TypeError, ValueError, OverflowError, User.DoesNotExist): | ||||||
|  |         user = None | ||||||
|  |     if user is not None and default_token_generator.check_token(user, token): | ||||||
|  |         user.email_is_verified = True | ||||||
|  |         user.save() | ||||||
|  |         messages.success(request, "Thank you for your email confirmation. You will receive notifications of new episodes. ") | ||||||
|  |         return redirect('homepage') | ||||||
|  |     else: | ||||||
|  |         messages.info(request, "Activation link is invalid!") | ||||||
|  |         return redirect('profile-editing') | ||||||
| @@ -4,12 +4,7 @@ from django.contrib.auth.decorators import login_required | |||||||
| from django.contrib import messages | from django.contrib import messages | ||||||
| from account.forms import ProfileEditingForm | from account.forms import ProfileEditingForm | ||||||
| from requests import get | from requests import get | ||||||
| from django.contrib.auth.tokens import default_token_generator | from .send_otp import send_otp_view | ||||||
| from django.contrib.sites.shortcuts import get_current_site |  | ||||||
| from django.template.loader import render_to_string |  | ||||||
| from django.utils.encoding import force_bytes |  | ||||||
| from django.utils.http import urlsafe_base64_encode |  | ||||||
| from django.core.mail import EmailMessage |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @login_required(login_url='/') | @login_required(login_url='/') | ||||||
| @@ -36,28 +31,40 @@ def profile_editing_view(request): | |||||||
|                     messages.info(request, f"IMDB API: {data['errorMessage']}") |                     messages.info(request, f"IMDB API: {data['errorMessage']}") | ||||||
|                     return redirect('profile-editing') |                     return redirect('profile-editing') | ||||||
|  |  | ||||||
|             form.save() |  | ||||||
|             if 'email' in form.changed_data: |             if 'email' in form.changed_data: | ||||||
|                 user = request.user |  | ||||||
|                 user.email_notification_is_active = False |  | ||||||
|                 user.save() |  | ||||||
|                 to_email = form.cleaned_data.get('email') |                 to_email = form.cleaned_data.get('email') | ||||||
|                 if to_email is not None: |                 if to_email is not None: | ||||||
|                     current_site = get_current_site(request) |                     if form.cleaned_data.get('send_email'): | ||||||
|                     mail_subject = 'Activate your account.' |                         form.add_error('send_email', 'You must verify the email before enabling the send email feature') | ||||||
|                     message = render_to_string('acc_active_email.html', { |                         return render(request, 'profile_editing.html', context={"form": form}) | ||||||
|                         'user': user, |                     user = request.user | ||||||
|                         'domain': current_site.domain, |                     user.email_is_verified = False | ||||||
|                         'uid': urlsafe_base64_encode(force_bytes(user.pk)), |                     form.save() | ||||||
|                         'token': default_token_generator.make_token(user), |                     user.save() | ||||||
|                     }) |                     return send_otp_view(request=request) | ||||||
|                     email = EmailMessage( |  | ||||||
|                         mail_subject, message, to=[to_email] |  | ||||||
|                     ) |  | ||||||
|                     email.send() |  | ||||||
|                     messages.warning(request, "Please confirm your email address to receive notifications of new episodes.") |  | ||||||
|                     return redirect('homepage') |  | ||||||
|  |  | ||||||
|  |                 elif 'send_email' in form.changed_data and form.cleaned_data.get('send_email'): | ||||||
|  |                     form.add_error('send_email', 'Email field is required to receive email notifications') | ||||||
|  |                     return render(request, 'profile_editing.html', context={"form": form}) | ||||||
|  |  | ||||||
|  |                 user = request.user | ||||||
|  |                 user.email_is_verified = False | ||||||
|  |                 user.send_email = False | ||||||
|  |                 form.save() | ||||||
|  |                 user.save() | ||||||
|  |                 messages.success(request, 'Profile Updated') | ||||||
|  |                 return redirect('homepage') | ||||||
|  |  | ||||||
|  |             elif form.cleaned_data.get('send_email'): | ||||||
|  |                 if form.cleaned_data.get('email') is None: | ||||||
|  |                     form.add_error('send_email', 'Email field is required to receive email notifications.') | ||||||
|  |                     return render(request, 'profile_editing.html', context={"form": form}) | ||||||
|  |  | ||||||
|  |                 elif not request.user.email_is_verified: | ||||||
|  |                     form.add_error('send_email', 'You must first verify the email.') | ||||||
|  |                     return render(request, 'profile_editing.html', context={"form": form}) | ||||||
|  |  | ||||||
|  |             form.save() | ||||||
|             messages.success(request, 'Profile Updated') |             messages.success(request, 'Profile Updated') | ||||||
|             return redirect('homepage') |             return redirect('homepage') | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,17 +5,11 @@ from account.forms import RegisterForm | |||||||
| from django.contrib.auth import (login, | from django.contrib.auth import (login, | ||||||
|                                 authenticate) |                                 authenticate) | ||||||
| from requests import get | from requests import get | ||||||
| from account.models import User |  | ||||||
| from django.contrib.auth.tokens import default_token_generator |  | ||||||
| from django.contrib.sites.shortcuts import get_current_site |  | ||||||
| from django.core.mail import EmailMessage |  | ||||||
| from django.shortcuts import render | from django.shortcuts import render | ||||||
| from django.template.loader import render_to_string | from .send_otp import send_otp_view | ||||||
| from django.utils.encoding import force_bytes |  | ||||||
| from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def register_view(request): | def register_view(request):  # sourcery skip: extract-method | ||||||
|     if request.method == 'POST': |     if request.method == 'POST': | ||||||
|         form = RegisterForm(request.POST) |         form = RegisterForm(request.POST) | ||||||
|         if form.is_valid(): |         if form.is_valid(): | ||||||
| @@ -38,26 +32,17 @@ def register_view(request): | |||||||
|                 return redirect('register') |                 return redirect('register') | ||||||
|  |  | ||||||
|             to_email = form.cleaned_data.get('email') |             to_email = form.cleaned_data.get('email') | ||||||
|  |             if to_email is None and form.cleaned_data.get('send_email'): | ||||||
|  |                 form.add_error('send_email', 'Email field is required to receive email notifications.') | ||||||
|  |                 return render(request, 'register.html', context={"form": form}) | ||||||
|  |  | ||||||
|             form.save() |             form.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') | ||||||
|             user = authenticate(username=username, password=password) |             user = authenticate(username=username, password=password) | ||||||
|             login(request, user) |             login(request, user) | ||||||
|             if to_email is not None: |             if to_email is not None: | ||||||
|                 current_site = get_current_site(request) |                 return send_otp_view(request=request) | ||||||
|                 mail_subject = 'Activate your account.' |  | ||||||
|                 message = render_to_string('acc_active_email.html', { |  | ||||||
|                     'user': user, |  | ||||||
|                     'domain': current_site.domain, |  | ||||||
|                     'uid': urlsafe_base64_encode(force_bytes(user.pk)), |  | ||||||
|                     'token': default_token_generator.make_token(user), |  | ||||||
|                 }) |  | ||||||
|                 email = EmailMessage( |  | ||||||
|                     mail_subject, message, to=[to_email] |  | ||||||
|                 ) |  | ||||||
|                 email.send() |  | ||||||
|                 messages.warning(request, "Please confirm your email address to receive notifications of new episodes.") |  | ||||||
|                 return redirect('homepage') |  | ||||||
|  |  | ||||||
|             messages.success(request, 'Registration Successful') |             messages.success(request, 'Registration Successful') | ||||||
|             return redirect('homepage') |             return redirect('homepage') | ||||||
| @@ -65,20 +50,4 @@ def register_view(request): | |||||||
|     else:  |     else:  | ||||||
|         form = RegisterForm() |         form = RegisterForm() | ||||||
|  |  | ||||||
|     return render(request, 'register.html', context={"form": form}) |     return render(request, 'register.html', context={"form": form}) | ||||||
|  |  | ||||||
|  |  | ||||||
| def activate_view(request, uidb64, token): |  | ||||||
|     try: |  | ||||||
|         uid = urlsafe_base64_decode(uidb64).decode() |  | ||||||
|         user = User._default_manager.get(pk=uid) |  | ||||||
|     except(TypeError, ValueError, OverflowError, User.DoesNotExist): |  | ||||||
|         user = None |  | ||||||
|     if user is not None and default_token_generator.check_token(user, token): |  | ||||||
|         user.email_notification_is_active = True |  | ||||||
|         user.save() |  | ||||||
|         messages.success(request, "Thank you for your email confirmation. You will receive notifications of new episodes. ") |  | ||||||
|         return redirect('homepage') |  | ||||||
|     else: |  | ||||||
|         messages.info(request, "Activation link is invalid!") |  | ||||||
|         return redirect('register') |  | ||||||
							
								
								
									
										45
									
								
								src/account/views/send_otp.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/account/views/send_otp.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | from django.contrib.auth.decorators import login_required | ||||||
|  | from django.contrib.sites.shortcuts import get_current_site | ||||||
|  | from django.template.loader import render_to_string | ||||||
|  | from django.utils.http import urlsafe_base64_encode | ||||||
|  | from django.utils.encoding import force_bytes | ||||||
|  | from django.contrib.auth.tokens import default_token_generator | ||||||
|  | from django.core.mail import EmailMessage | ||||||
|  | from django.contrib import messages | ||||||
|  | from django.shortcuts import redirect | ||||||
|  | from django.views.decorators.http import require_http_methods | ||||||
|  | from django_ratelimit.decorators import ratelimit | ||||||
|  |  | ||||||
|  |  | ||||||
|  | @ratelimit(key='user', rate='1/125s', block=False) | ||||||
|  | @login_required(login_url='/') | ||||||
|  | @require_http_methods(['GET', 'POST']) | ||||||
|  | def send_otp_view(request): | ||||||
|  |     if getattr(request, 'limited', False): | ||||||
|  |         messages.warning(request, 'You can only get 1 verification code every 2 minutes.') | ||||||
|  |         return redirect('homepage') | ||||||
|  |  | ||||||
|  |     user = request.user | ||||||
|  |     if user.email is None: | ||||||
|  |         messages.warning(request, 'you must add your email first') | ||||||
|  |         return redirect('profile-editing') | ||||||
|  |  | ||||||
|  |     if user.email_is_verified: | ||||||
|  |         messages.warning(request, 'your email account is already verified') | ||||||
|  |         return redirect('homepage') | ||||||
|  |  | ||||||
|  |     current_site = get_current_site(request) | ||||||
|  |     mail_subject = 'Activate your account.' | ||||||
|  |     message = render_to_string('acc_active_email.html', { | ||||||
|  |         'user': user, | ||||||
|  |         'domain': current_site.domain, | ||||||
|  |         'uid': urlsafe_base64_encode(force_bytes(user.pk)), | ||||||
|  |         'token': default_token_generator.make_token(user), | ||||||
|  |     }) | ||||||
|  |     email = EmailMessage( | ||||||
|  |         mail_subject, message, to=[user.email] | ||||||
|  |     ) | ||||||
|  |     email.send() | ||||||
|  |  | ||||||
|  |     messages.warning(request, f"Verification message sent to {user.email}.") | ||||||
|  |     return redirect('homepage') | ||||||
| @@ -48,7 +48,7 @@ def episode_counter(imdb_api_key, s, data): | |||||||
|  |  | ||||||
| @shared_task(name='send_emails') | @shared_task(name='send_emails') | ||||||
| def send_feedback_email_task(): | def send_feedback_email_task(): | ||||||
|     users = User.objects.filter(email_notification_is_active=True) |     users = User.objects.filter(email_is_verified=True) | ||||||
|     for user in users: |     for user in users: | ||||||
|         series = user.series.filter(show=True).order_by('-id') |         series = user.series.filter(show=True).order_by('-id') | ||||||
|         series_new_episodes = [] |         series_new_episodes = [] | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								src/static/icons/false.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/static/icons/false.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 11 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/static/icons/true.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/static/icons/true.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 9.5 KiB | 
		Reference in New Issue
	
	Block a user
	 ayxan
					ayxan