Fakultas Ilmu Komputer UI

Verified Commit 27e1991f authored by Muhammad Ariq Basyar's avatar Muhammad Ariq Basyar
Browse files

[GREEN] implemented seen and organisasi_komunitas field on BisaGoUser

- better email message with user.last_name and build absolute uri from request
- implemented serializer for update and detail BisaGoUser
- implemented serializer for register user
- fix linters
parent c6477b7a
Pipeline #78947 passed with stages
in 4 minutes and 51 seconds
......@@ -6,7 +6,7 @@ from .models import Lokasi, Fasilitas, Komentar, Kegiatan, KomentarKegiatan, Fot
class KomentarAdmin(admin.ModelAdmin):
list_display = ('__str__', 'deskripsi', 'user', 'notify_to')
list_display = ('__str__', 'user', 'notify_to')
actions = ('send_notification',)
def send_notification(self, request, queryset):
......
......@@ -32,10 +32,11 @@ class FotoKegiatanSerializer(serializers.ModelSerializer):
class KegiatanSerializer(serializers.ModelSerializer):
place_id = serializers.CharField(source='lokasi.place_id', read_only=True)
creator = serializers.CharField(source='user.last_name', read_only=True)
creator_email = serializers.CharField(source='user.email', read_only=True)
class Meta:
model = Kegiatan
fields = ('id', 'place_id', 'creator', 'lokasi', 'user',
fields = ('id', 'place_id', 'creator', 'lokasi', 'user', 'creator_email',
'nama_kegiatan', 'penyelenggara', 'deskripsi',
"links","narahubung", 'time_start', 'time_end')
extra_kwargs = {
......@@ -50,9 +51,12 @@ class KegiatanSerializer(serializers.ModelSerializer):
class KomentarKegiatanSerializer(serializers.ModelSerializer):
kegiatan = serializers.IntegerField(source='kegiatan.id', read_only=True)
creator = serializers.CharField(source='user.last_name', read_only=True)
creator_email = serializers.CharField(source='user.email', read_only=True)
class Meta:
model = KomentarKegiatan
fields = ('id', 'creator', 'kegiatan', 'deskripsi', 'created')
fields = ('id', 'creator', 'kegiatan', 'deskripsi', 'created',
'creator_email')
extra_kwargs = {
'deskripsi': {'required': True},
'created': {'required' : True}
......
......@@ -38,7 +38,7 @@ urlpatterns = [
path('lokasi/kegiatan-terdekat',
views_kegiatan.nearest_kegiatan, name='nearest-kegiatan'),
path('lokasi/search-kegiatan/<str:query>',
views_kegiatan.search_kegiatan, name='search-kegiatan'),
......@@ -59,7 +59,7 @@ urlpatterns = [
path('lokasi/add-komentar-kegiatan/<str:place_id>/<int:kegiatan_id>',
views_komentar_kegiatan.add_komentar_kegiatan, name='add-komentar-kegiatan'),
path('lokasi/delete-komentar-kegiatan/<str:place_id>/<int:kegiatan_id>/<int:komentar_id>',
views_komentar_kegiatan.delete_komentar_kegiatan, name='delete-komentar-kegiatan'),
......
......@@ -270,6 +270,7 @@ def list_komentar(request, place_id, id):
komentar_details["id"] = komentar.id
komentar_details["deskripsi"] = komentar.deskripsi
komentar_details["creator"] = komentar.user.last_name
komentar_details["creator_email"] = komentar.user.email
komentar_details["date_time"] = komentar.date_time.strftime(
TIME_FORMAT)
return JsonResponse(return_json, status=HTTPStatus.OK)
......
import json
from http import HTTPStatus
from django.test import TestCase, Client, override_settings
from django.conf import settings
from django.test import TestCase, Client
from django.db.utils import IntegrityError
from django.contrib.auth.models import User
from django.urls import path, include, reverse
import django
from pplbackend.utils import get_client_login_with_user
from .models import Sekolah, Penyandang, Komunitas
from .serializers import SekolahSerializer, KomunitasSerializer
......
from rest_framework import permissions
class UserViewPermission(permissions.BasePermission):
def has_permission(self, request, view):
if view.action in ['register', 'retrieve', 'activate']:
return True
if view.action == 'update':
return request.user.is_authenticated
return False
def has_object_permission(self, request, view, obj):
if view.action == 'update':
return request.user.id == obj.user.id
return True
from django.contrib.auth.tokens import PasswordResetTokenGenerator
from django.utils import six
class TokenGenerator(PasswordResetTokenGenerator):
def _make_hash_value(self, user, timestamp):
return (
six.text_type(user.pk) + six.text_type(timestamp) +
six.text_type(user.is_active)
)
account_activation_token = TokenGenerator()
\ No newline at end of file
account_activation_token = TokenGenerator()
from django.urls import path
import new_rest_api.views
from django.urls import path, include
from rest_framework.routers import SimpleRouter
from . import views
user_router = SimpleRouter()
user_router.register('', views.UserViewSet, basename='user')
urlpatterns = [
path('user-list/', new_rest_api.views.user_list, name='user-list'),
path('user-detail/<str:email>', new_rest_api.views.user_details, name='user-details'),
path('user-detail/?email=<str:email>',
new_rest_api.views.user_details, name='user-details-get'),
path('update-user/', new_rest_api.views.update_user, name='update-user'),
path('register/', new_rest_api.views.register_user, name='create-user'),
path(r'^activate/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$',
new_rest_api.views.activate, name='activate'),
path('user/', include(user_router.urls)),
]
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.core.mail import EmailMessage
from django.urls import reverse
from .tokens import account_activation_token
def send_activation_email(user, request, subject='Activate your account'):
uidb64 = urlsafe_base64_encode(force_bytes(user.pk))
token = account_activation_token.make_token(user)
absolute_uri = request.build_absolute_uri(reverse('user-activate',
kwargs={'uidb64':uidb64, 'token':token}))
message = render_to_string('acc_active_email.html',{
'user': user,
'absolute_uri': absolute_uri,
})
mail = EmailMessage(subject, message, to=[user.email])
mail.send()
from http import HTTPStatus as status
from django.contrib.auth.models import User
from django.http import JsonResponse, QueryDict
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
from django.utils.encoding import force_text
from django.utils.http import urlsafe_base64_decode
from rest_framework.decorators import api_view, permission_classes, authentication_classes
from rest_framework.utils.serializer_helpers import ReturnDict
from django.db.utils import IntegrityError
from django.utils.encoding import force_bytes, force_text
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode
from django.template.loader import render_to_string
from django.core.mail import EmailMessage
from django.core.exceptions import ObjectDoesNotExist
from rest_framework import viewsets
from rest_framework.authentication import TokenAuthentication
from rest_framework.decorators import action
from rest_framework.response import Response
from registrasi.models import BisaGoUser
from registrasi.serializers import BisaGoUserSerializers
from registrasi.serializers import BisaGoUserSerializers, RegisterUserSerializer
from .tokens import account_activation_token
from .permissions import UserViewPermission
from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from django.conf import settings
def request_error_message(request_kind):
return "get {} request instead".format(request_kind)
ACTIVATION_URL_REGEX =\
r'activate/(?P<uidb64>[0-9A-Za-z_-]+)/(?P<token>[0-9A-Za-z]+-[0-9A-Za-z]{32})'
def missing_key_message(key):
return "bad request. {} key needed".format(key)
class UserViewSet(viewsets.ModelViewSet):
queryset = BisaGoUser.objects.all()
serializer_class = BisaGoUserSerializers
lookup_field = 'user__username'
lookup_value_regex = '[^/]+'
authentication_classes = (TokenAuthentication,)
permission_classes = (UserViewPermission,)
@csrf_exempt
@api_view(['GET'])
@authentication_classes([])
@permission_classes([])
def user_list(request):
if request.method == 'GET':
json_return = []
for user in BisaGoUser.objects.all():
json_return.append({"username":user.user.email,
"name": user.user.last_name,
"email": user.user.email,
"phone_number": user.phone_number})
return JsonResponse(json_return, safe=False, status=status.OK)
else:
return JsonResponse({'response' : request_error_message("get")},
status=status.METHOD_NOT_ALLOWED)
@action(detail=False, methods=['POST'], serializer_class=RegisterUserSerializer)
def register(self, request):
data = request.data
serializer = self.get_serializer(data=data, context={'request':request})
serializer.is_valid(raise_exception=True)
instance = serializer.save()
return Response({
'response': 'User registered, check activation link on your email',
'email':instance.email, 'name':instance.last_name},
status=status.CREATED)
@api_view(['GET'])
@authentication_classes([])
@permission_classes([])
def user_details(request, email):
try:
if request.method == 'GET':
user = User.objects.get(username=email)
bisa_go_user = BisaGoUser.objects.get(user=user)
serializer = BisaGoUserSerializers(bisa_go_user)
json_return = {"username":user.email,
"name": user.last_name,
"email": user.email,
"phone_number": bisa_go_user.phone_number}
json_return.update(serializer.data)
if (json_return["seen"] == False) :
json_return.pop("phone_number")
json_return.pop("email")
json_return.pop("alamat")
return JsonResponse(json_return, safe=False, status=status.OK)
else:
return JsonResponse({'response' : request_error_message("get")},
status=status.METHOD_NOT_ALLOWED)
except ObjectDoesNotExist:
return JsonResponse({'response': 'User not found'}, status=status.NOT_FOUND)
@api_view(['POST'])
@authentication_classes([])
@permission_classes([])
def register_user(request):
try:
if request.method == 'POST':
name = request.POST['name']
email = request.POST['email']
password = request.POST['password']
user = User.objects.create_user(username=email, email=email,
password=password, last_name=name)
data = dict(list(request.POST.dict().items())[3:])
data['user'] = user.pk
data['seen'] = True
user.is_active = False
user.save()
mail_subject = "Activate your account"
message = render_to_string('acc_active_email.html', {
'user' : user,
'domain' : request.get_host,
'uid' : urlsafe_base64_encode(force_bytes(user.pk)),
'token' : account_activation_token.make_token(user),
})
mail = EmailMessage(mail_subject, message, to=[email])
mail.send()
data_query_dict = QueryDict('', mutable=True)
data_query_dict.update(data)
serializer = BisaGoUserSerializers(data=data_query_dict)
if serializer.is_valid():
serializer.save()
return JsonResponse({'response' : 'User created', 'email':email, 'name':name},
status=status.CREATED)
else:
return JsonResponse(serializer.errors, status=status.BAD_REQUEST)
except KeyError as error:
return JsonResponse({'response' : missing_key_message(str(error))},
status=status.INTERNAL_SERVER_ERROR)
except IntegrityError as error:
return JsonResponse({'response' : 'User is already exist'},
status=status.INTERNAL_SERVER_ERROR)
@action(detail=False, methods=['GET'], url_path=ACTIVATION_URL_REGEX)
def activate(self, request, uidb64, token):
return activate(uidb64, token)
@api_view(['GET'])
@authentication_classes([])
@permission_classes([])
def activate(request, uidb64, token):
if request.method == 'GET':
try:
uid = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=uid)
except(TypeError, ValueError, OverflowError, User.DoesNotExist):
user = None
if user is not None and account_activation_token.check_token(user, token):
user.is_active = True
user.save()
return JsonResponse({'response' : 'User activated'}, status=status.CREATED)
else:
return JsonResponse({'response' : request_error_message('get')},
status=status.BAD_REQUEST)
else:
return JsonResponse({'response' : request_error_message("get")}, status=status.BAD_REQUEST)
@api_view(['POST'])
@authentication_classes([])
@permission_classes([])
def update_user(request):
def activate(uidb64, token):
try:
if request.method == 'POST':
data = dict(list(request.POST.dict().items()))
if request.FILES :
type = request.FILES['foto'].content_type.split("/")[0]
if type == "image" :
data['foto'] = request.FILES['foto']
else :
return JsonResponse({'response': 'File is not image type'}, safe=False,
status=status.INTERNAL_SERVER_ERROR)
email = request.POST['email']
user = User.objects.get(username=email)
data["user"] = user.pk
bisa_go_user = BisaGoUser.objects.get(user=user)
data_query_dict = QueryDict('', mutable=True)
data_query_dict.update(data)
serializer = BisaGoUserSerializers(bisa_go_user, data=data_query_dict)
if serializer.is_valid():
user.save()
serializer.save()
else:
return JsonResponse({'response': 'Internal server error'}, safe=False,
status=status.INTERNAL_SERVER_ERROR)
return JsonResponse({'response': 'User updated'}, safe=False, status=status.OK)
except ObjectDoesNotExist:
return JsonResponse({'response': 'User not found'}, status=status.NOT_FOUND)
user_pk = force_text(urlsafe_base64_decode(uidb64))
user = User.objects.get(pk=user_pk)
except (TypeError, ValueError, OverflowError, User.DoesNotExist):
return JsonResponse({'response': 'error'}, status=status.BAD_REQUEST)
if account_activation_token.check_token(user, token):
user.is_active = True
user.save()
return JsonResponse({'response': 'User activated'}, status=status.OK)
return JsonResponse({'response': 'error'}, status=status.BAD_REQUEST)
# Generated by Django 3.1.7 on 2021-05-25 17:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('registrasi', '0007_merge_20210517_0447'),
]
operations = [
migrations.AlterField(
model_name='bisagouser',
name='foto',
field=models.ImageField(blank=True, default=None, null=True, upload_to='', verbose_name='Foto'),
),
]
# Generated by Django 3.1.7 on 2021-05-26 15:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('registrasi', '0008_auto_20210525_1756'),
]
operations = [
migrations.AddField(
model_name='bisagouser',
name='organisasi_komunitas',
field=models.CharField(default='-', max_length=64, null=True, verbose_name='Organisasi / Komunitas'),
),
]
from datetime import date
from django.db import models
from django.core.mail import send_mail
from django.contrib.auth.models import User
from datetime import date
class BisaGoUser(models.Model):
class Meta:
db_table = "BisaGoUser"
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="phone_number")
phone_number = models.CharField('Nomor Telepon', max_length=15, unique=True)
tanggal_lahir = models.DateField('Tanggal Lahir', max_length=15, null=False, default=date.today)
jenis_kelamin = models.CharField('Jenis Kelamin', max_length=20, default='-')
disabilitas = models.CharField('Disabilitas', max_length=64, null=True, default='Belum memilih')
organisasi_komunitas = models.CharField('Organisasi / Komunitas', max_length=64, null=True, default='-')
pekerjaan = models.CharField('Pekerjaan', max_length=64, default='-')
alamat = models.CharField('Alamat', max_length=255, default='-')
foto = models.ImageField('Foto', blank=True, default='-', null=True)
foto = models.ImageField('Foto', blank=True, default=None, null=True)
seen = models.BooleanField('Seen', blank=True, default=True)
class Meta:
db_table = "BisaGoUser"
def __str__(self):
return self.user.username
\ No newline at end of file
return self.user.username
from rest_framework import serializers
from django.db import models
from django.contrib.auth.models import User
from django.utils.regex_helper import _lazy_re_compile
from new_rest_api.utils import send_activation_email
from .models import BisaGoUser
class BisaGoUserSerializers(serializers.ModelSerializer):
username = serializers.CharField(source='user.username', read_only=True)
name = serializers.CharField(source='user.last_name')
email = serializers.CharField(source='user.email', read_only=True)
class Meta:
model = BisaGoUser
fields = (
'user',
'phone_number',
'tanggal_lahir',
'jenis_kelamin',
'disabilitas',
'pekerjaan',
'alamat',
'foto',
'seen',
'phone_number', 'tanggal_lahir', 'jenis_kelamin', 'name', 'email',
'disabilitas', 'pekerjaan', 'alamat', 'foto', 'seen', 'username',
'organisasi_komunitas',
)
extra_kwargs = {
'foto': {'required': False},
}
\ No newline at end of file
hidden_fields = ('phone_number', 'email', 'alamat')
hidden_replacement_char = '-'
update_fields_mapper = {
'phone_number': 'phone_number', 'seen': 'seen', 'alamat': 'alamat',
'jenis_kelamin': 'jenis_kelamin', 'tanggal_lahir': 'tanggal_lahir',
'disabilitas': 'disabilitas', 'pekerjaan': 'pekerjaan',
'foto': 'foto', 'organisasi_komunitas': 'organisasi_komunitas'
}
update_user_fields_mapper = {
'last_name': 'last_name',
}
def can_see_hidden_fields(self, instance):
request = self.context['request']
return request.user.id == instance.user.id or instance.seen
def to_representation(self, instance):
representation = super().to_representation(instance)
if not self.can_see_hidden_fields(instance):
for hidden_field in self.Meta.hidden_fields:
representation[hidden_field] = self.Meta.hidden_replacement_char
return representation
def update(self, instance, validated_data):
for key, value in self.Meta.update_fields_mapper.items():
setattr(instance, key, validated_data.get(value))
instance.save()
user = instance.user
for key, value in self.Meta.update_user_fields_mapper.items():
setattr(user, key, validated_data['user'].get(value))
user.save()
return instance
class RegisterUserSerializer(serializers.ModelSerializer):
phone_regex = _lazy_re_compile('^(?:[+0]9)?[0-9]{11,12}$')
name = serializers.CharField()
email = serializers.EmailField()
phone_number = serializers.CharField()
jenis_kelamin = serializers.CharField()
tanggal_lahir = serializers.DateField(format='%Y-%m-%d')
password = serializers.CharField(style={'input_type': 'password'},
write_only=True)
disabilitas = serializers.CharField(required=False)
organisasi_komunitas = serializers.CharField(required=False)
pekerjaan = serializers.CharField(required=False)
alamat = serializers.CharField(required=False)
foto = serializers.ImageField(required=False)
class Meta:
model = User
fields = (
'name', 'email', 'password', 'tanggal_lahir', 'jenis_kelamin',
'disabilitas', 'pekerjaan', 'alamat', 'phone_number', 'foto',
'organisasi_komunitas',
)
user_fields_mapper = {
'username': 'email', 'email': 'email', 'password': 'password',
'last_name': 'name',
}
bisago_fields_mapper = {
'phone_number': 'phone_number', 'tanggal_lahir': 'tanggal_lahir',
'jenis_kelamin': 'jenis_kelamin', 'disabilitas': 'disabilitas',
'pekerjaan': 'pekerjaan', 'alamat': 'alamat', 'foto': 'foto',
'user': 'user', 'organisasi_komunitas': 'organisasi_komunitas',
}
def validate_email(self, value):
if User.objects.filter(username=value).exists():
raise serializers.ValidationError('email already exists.')
return value
def validate_phone_number(self, value):
matches = self.phone_regex.search(value)
if not matches:
raise serializers.ValidationError('invalid phone number.')
if BisaGoUser.objects.filter(phone_number=value).exists():
raise serializers.ValidationError('phone number already exists.')
return value
def create(self, validated_data):
user = User.objects.create_user(
**{key:validated_data.get(value) for key, value in\
self.Meta.user_fields_mapper.items()\
if validated_data.get(value)},
is_active=False)
validated_data['user'] = user
BisaGoUser.objects.create(
**{key:validated_data.get(value) for key, value in\
self.Meta.bisago_fields_mapper.items()\
if validated_data.get(value)})
try:
request = self.context['request']
send_activation_email(user, request)
except ConnectionError:
print('Failed to send activation email to %s, connection error.' %\
(user.username))
return user
{% autoescape off %}
Hai {{ user.username }},
Hai {{ user.last_name }},
Selamat datang di aplikasi bisaGO.
Sebelum anda bisa menggunakan akun anda, silahkan melakukan aktivasi dengan meng-klik link di bawah ini.
http://{{ domain }}{% url 'activate' uidb64=uid token=token %}
{{ absolute_uri }}
Terima kasih dan selamat menggunakan bisaGO.
......
Supports Markdown
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