Fakultas Ilmu Komputer UI

Commit 91ebf75b authored by Agas Yanpratama's avatar Agas Yanpratama 💬
Browse files

Merge branch 'exercise7-2' into 'master'

Exercise7 2

See merge request !15
parents 870a2a64 64b998b7
Pipeline #24840 passed with stages
in 31 minutes and 27 seconds
......@@ -255,6 +255,22 @@ Dalam pengerjaan penulis berhasil membuat mutant yang _strongly killed_. Penulis
***
### Exercise 7
#### Apa itu _Spiking_ dan _De-Spiking_?
_Spiking_ berasal dari kata _Spike_ yang merupakan salah satu teknik yang ada pada TDD. _Spike_ sendiri memiliki arti untuk melakukan sebuah hal yang cepat atau _prototype_ untuk mengetahui apakah suatu _code_ bekerja sesuai fungsinya tanpa melakukan tes sama sekali atau hanya membuat sedikit tes. _Spiking_ berarti melakukan teknik _Spike_ yang termasuk salah satu teknik dalam TDD.
_De-Spiking_ Berarti menulis ulang _prototype_ atau solusi yang dibuat dengan TDD karena kita sudah mengetahui cara mengimplementasikan sebuah solusi baru untuk program kita.
#### Kenapa _Spiking_ dan _De-Spiking_?
_Spiking_ sangat berguna karena jika kita ingin mencoba solusi baru yang akan diimplementasikan program kita, kita bisa mempelajari bagaimana kerjanya tanpa terlalu pusing dengan pembuatan tes yang lengkap karena kita belum mengetahui tentang solusi baru yang akan diterapkan.
Pertanyaan berikutnya adalah kenapa melakukan _De-Spiking_, padahal kita sudah mempunyai program yang berjalan sesuai keinginan Kita. Hal ini dilakukan karena kita sudah mengetahui informasi yang cukup untuk menerapkan TDD yang baik. Oleh karena itu, walaupun pada awalnya tidak ada TDD, dengan proses _spike_ dan _de-spike_ kita bisa mencoba mempelajari implementasi hal baru dengan mudah dan tetap menggunakan prinsip TDD yang sesuai.
***
### Referensi Pengerjaan Latihan:
* Percival, H. (2017). Test-driven development with Python obey the testing goat. London: OReilly. referesnsi: https://www.obeythetestinggoat.com/
......
import sys
from accounts.models import ListUser, Token
class PasswordlessAuthenticationBackend(object):
def authenticate(self, request, uid):
print('uid', uid, file=sys.stderr)
if not Token.objects.filter(uid=uid).exists():
print('no token found', file=sys.stderr)
return None
token = Token.objects.get(uid=uid)
print('got token', file=sys.stderr)
try:
user = ListUser.objects.get(email=token.email)
print('got user', file=sys.stderr)
return user
except ListUser.DoesNotExist:
print('new user', file=sys.stderr)
return ListUser.objects.create(email=token.email)
def get_user(self, email):
return ListUser.objects.get(email=email)
from django.contrib.auth.base_user import BaseUserManager
from django.contrib.auth.models import (
AbstractBaseUser, PermissionsMixin
)
import uuid
from django.db import models
class Token(models.Model):
email = models.EmailField()
uid = models.CharField(max_length=255)
class ListUserManager(BaseUserManager):
def create_user(self, email):
ListUser.objects.create(email=email)
def create_superuser(self, email, password):
self.create_user(email)
class ListUser(AbstractBaseUser, PermissionsMixin):
class User(models.Model):
email = models.EmailField(primary_key=True)
USERNAME_FIELD = 'email'
#REQUIRED_FIELDS = ['email', 'height']
objects = ListUserManager()
@property
def is_staff(self):
return self.email == 'agas.yanpratama@gmail.com'
REQUIRED_FIELDS = []
USERNAME_FIELD = 'email'
is_anonymous = False
is_authenticated = True
@property
def is_active(self):
return True
class Token(models.Model):
email = models.EmailField()
uid = models.CharField(default=uuid.uuid4, max_length=40)
\ No newline at end of file
<html>
<h1>Email sent</h1>
<p>Check your email, you'll find a message with a link that will log you into
the site.</p>
</html>
\ No newline at end of file
from django.test import TestCase
# Create your tests here.
from accounts.models import Token
from django.test import TestCase
from django.contrib.auth import get_user_model
User = get_user_model()
class UserModelTest(TestCase):
def test_user_is_valid_with_email_only(self):
user = User(email='a@b.com')
user.full_clean() # should not raise
def test_email_is_primary_key(self):
user = User(email='a@b.com')
self.assertEqual(user.pk, 'a@b.com')
class TokenModelTest(TestCase):
def test_links_user_with_auto_generated_uid(self):
token1 = Token.objects.create(email='a@b.com')
token2 = Token.objects.create(email='a@b.com')
self.assertNotEqual(token1.uid, token2.uid)
\ No newline at end of file
from django.conf.urls import url
from accounts import views
urlpatterns = [
url(r'^send_email$', views.send_login_email, name='send_login_email'),
url(r'^login$', views.login, name='login'),
url(r'^logout$', views.logout, name='logout'),
]
\ No newline at end of file
import uuid
import sys
from django.shortcuts import render
from django.contrib.auth import authenticate
from django.contrib.auth import login as auth_login, logout as auth_logout
from django.core.mail import send_mail
from django.shortcuts import redirect, render
from accounts.models import Token
def send_login_email(request):
email = request.POST['email']
uid = str(uuid.uuid4())
Token.objects.create(email=email, uid=uid)
print('saving uid', uid, 'for email', email, file=sys.stderr)
url = request.build_absolute_uri(f'/accounts/login?uid={uid}')
send_mail(
'Your login link for Superlists',
f'Use this link to log in:\n\n{url}',
'noreply@superlists',
[email],
)
return render(request, 'login_email_sent.html')
def login(request):
print('login view', file=sys.stderr)
print(request)
uid = request.GET.get('uid')
user = authenticate(request, uid=uid)
# Cek Error
print(uid)
print(user)
if user is not None:
auth_login(request, user)
# print("masuk none")
return redirect('/')
def logout(request):
auth_logout(request)
return redirect('/')
# Create your views here.
'''
import re
import time
......@@ -49,4 +50,4 @@ class LoginTest(FunctionalTest):
)
navbar = self.browser.find_element_by_css_selector('.navbar')
self.assertIn(TEST_EMAIL, navbar.text)
'''
\ No newline at end of file
......@@ -16,17 +16,19 @@
<body>
<div class="container">
<div class="navbar">
{% if user.is_authenticated %}
<p>Logged in as {{ user.email }}</p>
<p><a id="id_logout" href="{% url 'logout' %}">Log out</a></p>
{% else %}
<form method="POST" action="{% url 'send_login_email' %}">
Enter email to log in: <input name="email" type="text" />
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<a class="navbar-brand" href="/">Superlists</a>
{% comment %}
<form class="navbar-form navbar-right" method="POST" action="#">
<span>Enter email to log in:</span>
<input class="form-control" name="email" type="text" />
{% csrf_token %}
</form>
{% endif %}
</div>
{% endcomment %}
</div>
</nav>
<div class="row">
<div class="col-md-6 col-md-offset-3 jumbotron">
<div class="text-center">
......
......@@ -44,11 +44,7 @@ INSTALLED_APPS = [
'accounts',
]
AUTH_USER_MODEL = 'accounts.ListUser'
AUTHENTICATION_BACKENDS = [
'accounts.authentication.PasswordlessAuthenticationBackend',
]
AUTH_USER_MODEL = 'accounts.User'
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
......@@ -162,4 +158,22 @@ EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_USER = 'dev.agasyanp@gmail.com'
EMAIL_HOST_PASSWORD = os.environ.get('DEV_EMAIL_PASSWORD')
\ No newline at end of file
EMAIL_HOST_PASSWORD = os.environ.get('DEV_EMAIL_PASSWORD')
# Logging to STDERR
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django': {
'handlers': ['console'],
},
},
'root': {'level': 'INFO'},
}
\ No newline at end of file
from django.conf.urls import include, url
from lists import views as list_views
from lists import urls as list_urls
from accounts import urls as accounts_urls
urlpatterns = [
url(r'^$', list_views.home_page, name='home'),
url(r'^lists/', include(list_urls)),
url(r'^accounts/', include(accounts_urls)),
]
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment