Fakultas Ilmu Komputer UI
Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
PMPL
Class Project
DIGIPUS
Commits
648487be
Commit
648487be
authored
Oct 30, 2020
by
Arief Pratama
Browse files
[
#9
] Auth: Register Admin/Contrib Email Verification
parent
5e569261
Changes
10
Hide whitespace changes
Inline
Side-by-side
app/templates/app/base_profile.html
View file @
648487be
...
...
@@ -24,6 +24,8 @@
<!-- Custom styles for this page -->
<link
href=
"{% static 'vendor/datatables/dataTables.bootstrap4.min.css' %}"
rel=
"stylesheet"
>
{% block stylesheets %}{% endblock %}
<script
type=
"text/javascript"
src=
"{% static 'vendor/jquery/jquery-3.2.1.min.js' %}"
></script>
</head>
<body
id=
"page-top"
style=
"font-family: 'Poppins', sans-serif;"
>
...
...
app/templates/sunting.html
View file @
648487be
...
...
@@ -3,18 +3,18 @@
{% block title %}
<title>
Sunting Profil | Digipus
</title>
{% endblock %}
{% endblock %}
{% block content %}
<div
class=
"container"
>
<div
class=
"col-20"
>
<h1
class=
"mt-2"
>
{% if user.is_admin %}
Sunting Profil Admin
Sunting Profil Admin
{% elif user.is_contributor %}
Sunting Profil Kontributor
Sunting Profil Kontributor
{% else %}
Sunting Profil User
Sunting Profil User
{% endif %}
</h1>
<hr
class=
"mt-0 mb-4"
>
...
...
@@ -24,6 +24,26 @@
<div
class=
"col-md-6"
>
<div
class=
"fieldWrapper"
>
{{ field.label_tag }} {{ field }}
{% if field.name == 'email' %}
<div
class=
"my-3"
>
{% if user.is_email_verified %}
<span
class=
"text-success"
>
Email Status: Verified
</span>
{% else %}
<span
class=
"text-danger"
>
Email Status: Unverified
<button
class=
"btn btn-success"
id=
'verify-button'
style=
"background-color: #615CFD; border-color: #615CFD;"
>
Verify
</button>
</span>
{% endif %}
</div>
{% endif %}
{% if field.errors %}
<span
class=
"text-danger"
>
{{ field.errors }}
...
...
@@ -33,15 +53,41 @@
<p
class=
"help"
>
{{ field.help_text|safe }}
</p>
{% endif %}
</div>
</div>
{% endfor %}
<div
class=
"form-margin"
></div>
<div
class=
"col-md-6"
>
<div
class=
"fieldWrapper"
>
<button
type=
"submit"
class=
"btn btn-success btn-edit"
style=
"background-color: #615CFD; border-color: #615CFD;"
>
Simpan
</button>
<button
type=
"submit"
class=
"btn btn-success btn-edit"
style=
"background-color: #615CFD; border-color: #615CFD;"
>
Simpan
</button>
</div>
</div>
</form>
</div>
</div>
<script
type=
"text/javascript"
>
$
(
document
).
ready
(
function
()
{
const
csrftoken
=
document
.
querySelector
(
'
[name=csrfmiddlewaretoken]
'
).
value
;
$
(
'
#verify-button
'
).
click
(
function
()
{
$
.
ajax
({
url
:
'
/registrasi/send-verify-email
'
,
headers
:
{
'
X-CSRFToken
'
:
csrftoken
},
method
:
'
POST
'
,
data
:
{
email
:
$
(
'
#id_email
'
).
val
()
},
success
:
function
(
data
,
status
)
{
alert
(
data
)
},
})
return
false
;
});
});
</script>
{% endblock %}
\ No newline at end of file
authentication/models.py
View file @
648487be
...
...
@@ -81,6 +81,7 @@ class User(AbstractUser):
default_profile_picture
=
models
.
BooleanField
(
blank
=
True
,
default
=
False
)
profile_picture
=
models
.
ImageField
(
default
=
"default-image.jpg"
)
is_subscribing_to_material_comments
=
models
.
BooleanField
(
blank
=
False
,
default
=
True
)
is_email_verified
=
models
.
BooleanField
(
default
=
False
)
objects
=
CustomUserManager
()
...
...
register/migrations/__init__.py
0 → 100644
View file @
648487be
register/models.py
View file @
648487be
from
authentication.models
import
User
from
django.db
import
models
import
uuid
# Create your models here.
class
EmailVerification
(
models
.
Model
):
token
=
models
.
UUIDField
(
primary_key
=
True
,
default
=
uuid
.
uuid4
,
editable
=
False
)
created_on
=
models
.
DateTimeField
(
auto_now_add
=
True
)
expire_on
=
models
.
DateTimeField
(
null
=
True
)
user
=
models
.
ForeignKey
(
User
,
on_delete
=
models
.
SET_NULL
,
null
=
True
)
register/services.py
View file @
648487be
import
datetime
from
django.contrib.auth.hashers
import
make_password
from
django.contrib.auth.password_validation
import
validate_password
from
django.core.exceptions
import
ValidationError
from
.models
import
EmailVerification
from
django.utils
import
timezone
from
django.conf
import
settings
from
django.core.mail
import
send_mail
from
django.urls
import
reverse
class
RegistrationService
:
...
...
@@ -69,3 +75,27 @@ class RegistrationService:
create_result
[
"form"
]
=
form
return
create_result
@
staticmethod
def
create_email_verification
(
request
,
user
):
verify
=
EmailVerification
()
verify
.
created_on
=
timezone
.
now
()
verify
.
expire_on
=
verify
.
created_on
+
datetime
.
timedelta
(
hours
=
24
)
verify
.
user
=
user
verify
.
save
()
path
=
reverse
(
'register:verify-email'
,
args
=
[
verify
.
token
])
url
=
request
.
build_absolute_uri
(
path
)
email_content
=
f
"""
Dear
{
user
.
name
}
,
\n\n
Mohon verifikasi email Anda dengan klik pada link berikut:
{
url
}
"""
send_mail
(
subject
=
'DIGIPUS: Verifikasi Alamat Email'
,
message
=
email_content
,
from_email
=
getattr
(
settings
,
'EMAIL_HOST_USER'
),
recipient_list
=
[
user
.
email
],
fail_silently
=
False
)
register/templates/email_verify.html
0 → 100644
View file @
648487be
{% load static %}
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"UTF-8"
>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0"
>
<title>
Verifikasi Email
</title>
<link
rel=
"icon"
type=
"image/png"
href=
"{% static 'images/icons/logo.ico' %}"
/>
<!--===============================================================================================-->
<link
rel=
"stylesheet"
type=
"text/css"
href=
"{% static 'vendor/bootstrap/css/bootstrap.min.css' %}"
>
<!--===============================================================================================-->
<link
rel=
"stylesheet"
type=
"text/css"
href=
"{% static 'fonts/font-awesome-4.7.0/css/font-awesome.min.css' %}"
>
<!--===============================================================================================-->
<!--===============================================================================================-->
<link
rel=
"stylesheet"
type=
"text/css"
href=
"{% static 'vendor/animate/animate.css' %}"
>
<!--===============================================================================================-->
<link
rel=
"stylesheet"
type=
"text/css"
href=
"{% static 'vendor/css-hamburgers/hamburgers.min.css' %}"
>
<!--===============================================================================================-->
<link
rel=
"stylesheet"
type=
"text/css"
href=
"{% static 'vendor/animsition/css/animsition.min.css' %}"
>
<!--===============================================================================================-->
<link
rel=
"stylesheet"
type=
"text/css"
href=
"{% static 'vendor/select2/select2.min.css' %}"
>
<!--===============================================================================================-->
<link
rel=
"stylesheet"
type=
"text/css"
href=
"{% static 'vendor/daterangepicker/daterangepicker.css' %}"
>
<!--===============================================================================================-->
<link
rel=
"stylesheet"
type=
"text/css"
href=
"{% static 'css/styles.css' %}"
>
<link
rel=
"stylesheet"
type=
"text/css"
href=
"{% static 'css/util.css' %}"
>
<link
rel=
"stylesheet"
type=
"text/css"
href=
"{% static 'css/main.css' %}"
>
<!--===============================================================================================-->
<link
href=
"https://fonts.googleapis.com/css2?family=Montserrat:ital@1&display=swap"
rel=
"stylesheet"
>
<link
href=
"https://fonts.googleapis.com/css2?family=Poppins&display=swap"
rel=
"stylesheet"
>
</head>
<body>
<main>
{% if message %}
<div>
{{ message }}
</div>
<div>
Kembali ke
<a
href=
"/"
>
home
</a>
</div>
{% endif %}
</main>
<!--===============================================================================================-->
<script
src=
"../static/vendor/jquery/jquery-3.2.1.min.js"
></script>
<!--===============================================================================================-->
<script
src=
"../static/vendor/animsition/js/animsition.min.js"
></script>
<!--===============================================================================================-->
<script
src=
"../static/vendor/bootstrap/js/popper.js"
></script>
<script
src=
"../static/../static/../static/../static/../static/../static/vendor/bootstrap/js/bootstrap.min.js"
></script>
<!--===============================================================================================-->
<script
src=
"../static/../static/../static/../static/../static/vendor/select2/select2.min.js"
></script>
<!--===============================================================================================-->
<script
src=
"../static/../static/../static/../static/vendor/daterangepicker/moment.min.js"
></script>
<script
src=
"../static/../static/../static/vendor/daterangepicker/daterangepicker.js"
></script>
<!--===============================================================================================-->
<script
src=
"../static/../static/vendor/countdowntime/countdowntime.js"
></script>
<!--===============================================================================================-->
<script
src=
"../static/js/login.js"
></script>
<script
src=
"../static/js/navbar.js"
></script>
</body>
</html>
\ No newline at end of file
register/tests.py
View file @
648487be
import
datetime
from
django.core
import
mail
from
django.utils
import
timezone
from
register.models
import
EmailVerification
from
django.test
import
Client
,
TestCase
from
django.urls
import
resolve
...
...
@@ -883,3 +888,47 @@ class RegisterPublicTest(TestCase):
self
.
assertEqual
(
User
.
objects
.
all
().
count
(),
0
)
self
.
assertIn
(
b
"Password must have at least 8 characters"
,
response
.
content
)
class
VerifyEmailTest
(
TestCase
):
def
setUp
(
self
):
self
.
credential
=
{
'email'
:
'example@test.com'
,
'password'
:
'P@ssw0rd'
}
self
.
user
=
User
.
objects
.
create_contributor
(
**
self
.
credential
)
self
.
user
.
save
()
self
.
verif_valid
=
EmailVerification
(
expire_on
=
timezone
.
now
()
+
datetime
.
timedelta
(
hours
=
24
),
user
=
self
.
user
)
self
.
verif_valid
.
save
()
self
.
verif_expire
=
EmailVerification
(
created_on
=
timezone
.
now
()
+
datetime
.
timedelta
(
hours
=-
24
),
expire_on
=
timezone
.
now
()
+
datetime
.
timedelta
(
hours
=-
1
),
user
=
self
.
user
)
self
.
verif_expire
.
save
()
self
.
client
=
Client
()
def
test_email_notif_anonymous
(
self
):
response
=
self
.
client
.
post
(
'/registrasi/send-verify-email'
,
{
'email'
:
self
.
user
.
email
})
self
.
assertEqual
(
response
.
status_code
,
403
)
def
test_email_notif_authorized
(
self
):
login
=
self
.
client
.
login
(
**
self
.
credential
)
self
.
client
.
post
(
'/registrasi/send-verify-email'
,
{
'email'
:
self
.
user
.
email
})
self
.
assertEqual
(
len
(
mail
.
outbox
),
1
)
def
test_verify_email_before_24h
(
self
):
response
=
self
.
client
.
get
(
f
'/registrasi/verify-email/
{
self
.
verif_valid
.
token
}
'
)
self
.
assertContains
(
response
,
f
'Email Anda
{
self
.
verif_valid
.
user
.
email
}
berhasil diverifikasi'
)
def
test_verify_email_after_24h
(
self
):
response
=
self
.
client
.
get
(
f
'/registrasi/verify-email/
{
self
.
verif_expire
.
token
}
'
)
self
.
assertContains
(
response
,
'Link verifikasi telah expire'
)
def
test_verify_email_wrong_token
(
self
):
response
=
self
.
client
.
get
(
f
'/registrasi/verify-email/not-a-valid-token'
)
self
.
assertContains
(
response
,
'Email gagal diverifikasi'
)
register/urls.py
View file @
648487be
...
...
@@ -7,5 +7,7 @@ app_name = "register"
urlpatterns
=
[
path
(
""
,
views
.
index
.
as_view
()),
path
(
"umum/"
,
views
.
RegistrasiUmum
.
as_view
()),
path
(
"admin/"
,
views
.
RegistrasiAdmin
.
as_view
())
path
(
"admin/"
,
views
.
RegistrasiAdmin
.
as_view
()),
path
(
"verify-email/<str:token>"
,
views
.
verify_email
,
name
=
'verify-email'
),
path
(
"send-verify-email"
,
views
.
send_verify_email
),
]
register/views.py
View file @
648487be
from
django.http
import
response
from
authentication.models
import
User
from
django.utils
import
timezone
from
django.shortcuts
import
render
from
register.models
import
EmailVerification
from
django.contrib.auth
import
login
from
django.db
import
models
from
django.http
import
HttpResponseRedirect
from
django.views.generic
import
TemplateView
from
django.core.exceptions
import
PermissionDenied
from
register.forms
import
UserForm
# Create your views here.
from
register.services
import
RegistrationService
...
...
@@ -98,3 +105,36 @@ class RegistrasiUmum(TemplateView):
context
=
self
.
get_context_data
(
**
kwargs
)
context
[
"form"
]
=
UserForm
return
self
.
render_to_response
(
context
=
context
)
def
send_verify_email
(
request
):
if
not
request
.
user
.
is_authenticated
:
raise
PermissionDenied
(
request
)
if
request
.
method
==
'POST'
:
RegistrationService
.
create_email_verification
(
request
,
request
.
user
)
return
response
.
HttpResponse
(
'Email verifikasi telah dikirim'
)
def
verify_email
(
request
,
token
):
template_name
=
'email_verify.html'
try
:
verif
=
EmailVerification
.
objects
.
get
(
token
=
token
)
if
verif
.
expire_on
>
timezone
.
now
():
user
=
User
.
objects
.
get
(
email
=
verif
.
user
.
email
)
user
.
is_email_verified
=
True
user
.
save
()
return
render
(
request
,
template_name
,
{
'message'
:
f
'Email Anda
{
verif
.
user
.
email
}
berhasil diverifikasi'
})
else
:
return
render
(
request
,
template_name
,
{
'message'
:
f
'Link verifikasi telah expire'
})
except
:
return
render
(
request
,
template_name
,
{
'message'
:
f
'Email gagal diverifikasi'
})
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment