diff --git a/README.md b/README.md
index e8d8487..d21a16b 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@ https://ayxan.pythonanywhere.com
**pip install -r requirements.txt
cd src/
**
-add SECRET_KEY to .env.example file
+add SECRET_KEY, EMAIL_HOST_PASSWORD to .env.example file
rename .env.example to .env
**python3 manage.py makemigrations account --settings=config.settings.development
diff --git a/src/.env.example b/src/.env.example
index bce366d..154bb73 100644
--- a/src/.env.example
+++ b/src/.env.example
@@ -1,4 +1,5 @@
SECRET_KEY=
DB_NAME=
DB_USER=
-DB_PASSWORD=
\ No newline at end of file
+DB_PASSWORD=
+EMAIL_HOST_PASSWORD=
\ No newline at end of file
diff --git a/src/account/admin.py b/src/account/admin.py
index 7eb755d..ed2c911 100644
--- a/src/account/admin.py
+++ b/src/account/admin.py
@@ -5,9 +5,21 @@ from .models import User
@admin.register(User)
class CustomAdmin(UserAdmin):
- list_display = ('username', 'email')
- fieldsets = UserAdmin.fieldsets + (
- ('IMDB API Key Field', {
- 'fields': ['imdb_api_key']
+ fieldsets = (
+ (None, {'fields': ('username', 'email', 'password')}),
+ (('Permissions'), {
+ 'fields': ('is_active', 'email_notification_is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions'),
+ }),
+ (('Important dates'), {'fields': ('last_login', 'date_joined')}),
+ )
+ add_fieldsets = (
+ (None, {
+ 'classes': ('wide',),
+ 'fields': ('email', 'password1', 'password2'),
}),
)
+ list_display = ('username', 'email', 'is_staff')
+ list_filter = ('is_staff', 'email_notification_is_active', 'is_superuser', 'is_active', 'groups')
+ search_fields = ('email',)
+ ordering = ('email',)
+ filter_horizontal = ('groups', 'user_permissions',)
\ No newline at end of file
diff --git a/src/account/models.py b/src/account/models.py
index fd8ad45..b75dd8f 100644
--- a/src/account/models.py
+++ b/src/account/models.py
@@ -3,7 +3,11 @@ from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
+ first_name = None
+ last_name = None
+ email = models.EmailField('email', unique=True, blank=True, null=True)
imdb_api_key = models.CharField(max_length=15, blank=False, null=False)
+ email_notification_is_active = models.BooleanField(default=False)
class Meta:
db_table = 'user'
diff --git a/src/account/templates/acc_active_email.html b/src/account/templates/acc_active_email.html
new file mode 100644
index 0000000..eddbd4c
--- /dev/null
+++ b/src/account/templates/acc_active_email.html
@@ -0,0 +1,6 @@
+{% autoescape off %}
+Hi {{ user.username }},
+Please click on the link to confirm your registration,
+http://{{ domain }}{% url 'activate' uidb64=uid token=token %}
+If you think, it's not you, then just ignore this email.
+{% endautoescape %}
\ No newline at end of file
diff --git a/src/account/urls.py b/src/account/urls.py
index 8ba8230..1a53bfe 100644
--- a/src/account/urls.py
+++ b/src/account/urls.py
@@ -8,8 +8,9 @@ urlpatterns = [
template_name = 'login.html'
), name='login'),
path('register', views.register_view, name='register'),
+ path('activate///', views.activate_view, name='activate'),
path('logout', views.logout_view, name='logout'),
path('change-password', views.change_password_view, name='change-password'),
path('profile-editing', views.profile_editing_view, name='profile-editing'),
- path('profile', views.ProfileDetailView.as_view(), name='profile')
+ path('profile', views.ProfileDetailView.as_view(), name='profile'),
]
diff --git a/src/account/views/__init__.py b/src/account/views/__init__.py
index d0a044b..5fc3e49 100644
--- a/src/account/views/__init__.py
+++ b/src/account/views/__init__.py
@@ -1,4 +1,5 @@
-from .register import register_view
+from .register import (register_view,
+ activate_view)
from .logout import logout_view
from .change_password import change_password_view
from .profile_editing import profile_editing_view
diff --git a/src/account/views/profile_editing.py b/src/account/views/profile_editing.py
index 921631f..1e4b94d 100644
--- a/src/account/views/profile_editing.py
+++ b/src/account/views/profile_editing.py
@@ -1,8 +1,15 @@
-from django.shortcuts import render, redirect
+from django.shortcuts import (render,
+ redirect)
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from account.forms import ProfileEditingForm
from requests import get
+from django.contrib.auth.tokens import default_token_generator
+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='/')
@@ -10,25 +17,46 @@ def profile_editing_view(request):
if request.method == 'POST':
form = ProfileEditingForm(request.POST, instance=request.user)
if form.is_valid():
- raw_data = get(f"https://imdb-api.com/en/API/Title/{request.POST['imdb_api_key']}/tt0110413")
+ if 'imdb_api_key' in form.changed_data:
+ raw_data = get(f"https://imdb-api.com/en/API/Title/{request.POST['imdb_api_key']}/tt0110413")
- if raw_data.status_code != 200:
- messages.info(request, 'Account not created. Please try again later')
- return redirect('profile-editing')
- data = raw_data.json()
+ if raw_data.status_code != 200:
+ messages.info(request, 'Account not created. Please try again later')
+ return redirect('profile-editing')
+ data = raw_data.json()
- if data['errorMessage']:
- if 'Maximum usage' in data['errorMessage']:
+ if data['errorMessage']:
+ if 'Maximum usage' in data['errorMessage']:
+ messages.info(request, f"IMDB API: {data['errorMessage']}")
+ return redirect('profile-editing')
+
+ elif data['errorMessage'] == 'Invalid API Key':
+ form.add_error('imdb_api_key', 'Invalid API Key')
+ return render(request, 'profile_editing.html', context={"form": form})
messages.info(request, f"IMDB API: {data['errorMessage']}")
return redirect('profile-editing')
- elif data['errorMessage'] == 'Invalid API Key':
- form.add_error('imdb_api_key', 'Invalid API Key')
- return render(request, 'profile_editing.html', context={"form": form})
- messages.info(request, f"IMDB API: {data['errorMessage']}")
- return redirect('profile-editing')
-
form.save()
+ if 'email' in form.changed_data:
+ user = request.user
+ user.email_notification_is_active = False
+ user.save()
+ to_email = form.cleaned_data.get('email')
+ 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=[to_email]
+ )
+ email.send()
+ messages.warning(request, "Please confirm your email address to receive notifications of new episodes.")
+ return redirect('homepage')
+
messages.success(request, 'Profile Updated')
return redirect('homepage')
diff --git a/src/account/views/register.py b/src/account/views/register.py
index cc380a4..1c447da 100644
--- a/src/account/views/register.py
+++ b/src/account/views/register.py
@@ -1,8 +1,18 @@
-from django.shortcuts import render, redirect
+from django.shortcuts import (render,
+ redirect)
from django.contrib import messages
from account.forms import RegisterForm
-from django.contrib.auth import login, authenticate
+from django.contrib.auth import (login,
+ authenticate)
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.template.loader import render_to_string
+from django.utils.encoding import force_bytes
+from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
def register_view(request):
@@ -27,16 +37,48 @@ def register_view(request):
messages.info(request, f"IMDB API: {data['errorMessage']}")
return redirect('register')
+ to_email = form.cleaned_data.get('email')
form.save()
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password1')
user = authenticate(username=username, password=password)
login(request, user)
+ if to_email is not None:
+ 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=[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')
return redirect('homepage')
- else:
+ else:
form = RegisterForm()
- return render(request, 'register.html', context={"form": form})
\ No newline at end of file
+ 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')
\ No newline at end of file
diff --git a/src/config/settings/base.py b/src/config/settings/base.py
index 7ca7697..4fb1002 100644
--- a/src/config/settings/base.py
+++ b/src/config/settings/base.py
@@ -81,4 +81,12 @@ USE_I18N = True
USE_TZ = True
-DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
\ No newline at end of file
+DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
+
+EMAIL_BACKEND = 'django_smtp_ssl.SSLEmailBackend'
+EMAIL_USE_TLS = True
+EMAIL_HOST = 'smtp.gmail.com'
+EMAIL_HOST_USER = 'series.notification@gmail.com'
+EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD")
+DEFAULT_FROM_EMAIL = 'series.notification@gmail.com'
+EMAIL_PORT = 465
\ No newline at end of file