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
ppl-fasilkom-ui
2020
PPL-C
PPTI-Mobile Apps Monitoring Wabah Tuberkolosis
Neza-Backend
Commits
6457ab9a
Commit
6457ab9a
authored
Apr 19, 2020
by
Jonathan Christopher Jakub
Browse files
[RED] Implement reworked account endpoint
parent
dd92ebe2
Changes
6
Hide whitespace changes
Inline
Side-by-side
apps/accounts/filters.py
View file @
6457ab9a
from
django_filters
import
FilterSet
,
CharFilter
ACCOUNT_FILTERSET_FIELDS
=
(
"name"
,
"email"
,
"phone_number"
,
"area"
,
"is_admin"
,
"is_verified"
,
"is_active"
,
)
from
apps.accounts.models
import
Account
ACCOUNT_SEARCH_FIELDS
=
(
"name"
,
"email"
,
"phone_number"
,
"area"
,
"is_admin"
,
"is_verified"
,
"is_active"
,
)
class
AccountFilter
(
FilterSet
):
username
=
CharFilter
(
field_name
=
"user__username"
)
class
Meta
:
model
=
Account
fields
=
[
"username"
,
"name"
,
"email"
,
"phone_number"
,
"area"
,
"is_admin"
,
"is_verified"
,
]
ACCOUNT_ORDERING_FIELDS
=
(
"name"
,
"email"
,
"phone_number"
,
"area"
,
"is_admin"
,
"is_verified"
,
"is_active"
,
"created_at"
,
)
apps/accounts/migrations/0002_auto_20200419_0156.py
0 → 100644
View file @
6457ab9a
# Generated by Django 3.0.1 on 2020-04-18 18:56
from
django.db
import
migrations
,
models
import
uuid
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'accounts'
,
'0001_initial'
),
]
operations
=
[
migrations
.
CreateModel
(
name
=
'AccountHistory'
,
fields
=
[
(
'revision_id'
,
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
editable
=
False
,
primary_key
=
True
,
serialize
=
False
)),
(
'object_id'
,
models
.
UUIDField
(
default
=
uuid
.
uuid4
,
editable
=
False
)),
(
'action_type'
,
models
.
CharField
(
choices
=
[(
'Create'
,
'Create'
),
(
'Edit'
,
'Edit'
),
(
'Delete'
,
'Delete'
)],
max_length
=
64
)),
(
'recorded_at'
,
models
.
DateTimeField
(
auto_now_add
=
True
)),
(
'user_id'
,
models
.
IntegerField
()),
(
'name'
,
models
.
CharField
(
max_length
=
128
)),
(
'email'
,
models
.
EmailField
(
max_length
=
128
)),
(
'phone_number'
,
models
.
CharField
(
max_length
=
64
)),
(
'area'
,
models
.
CharField
(
max_length
=
128
)),
(
'is_admin'
,
models
.
BooleanField
(
default
=
False
)),
(
'is_verified'
,
models
.
BooleanField
(
default
=
False
)),
(
'is_active'
,
models
.
BooleanField
(
default
=
False
)),
],
options
=
{
'verbose_name_plural'
:
'account histories'
,
'db_table'
:
'account_history'
,
'ordering'
:
[
'-recorded_at'
],
},
),
migrations
.
AlterModelOptions
(
name
=
'account'
,
options
=
{
'ordering'
:
[
'-created_at'
],
'verbose_name_plural'
:
'accounts'
},
),
migrations
.
AddField
(
model_name
=
'account'
,
name
=
'deleted_at'
,
field
=
models
.
DateTimeField
(
blank
=
True
,
null
=
True
),
),
]
apps/accounts/models.py
View file @
6457ab9a
...
...
@@ -2,8 +2,32 @@ import uuid
from
django.contrib.auth.models
import
User
from
django.db
import
models
from
apps.commons.managers
import
SoftDeleteManager
from
apps.commons.models
import
HistoryEnabledModel
,
HistoryModel
class
Account
(
models
.
Model
):
class
AccountHistory
(
HistoryModel
):
user_id
=
models
.
IntegerField
(
null
=
False
)
name
=
models
.
CharField
(
max_length
=
128
)
email
=
models
.
EmailField
(
max_length
=
128
)
phone_number
=
models
.
CharField
(
max_length
=
64
)
area
=
models
.
CharField
(
max_length
=
128
)
is_admin
=
models
.
BooleanField
(
default
=
False
)
is_verified
=
models
.
BooleanField
(
default
=
False
)
is_active
=
models
.
BooleanField
(
default
=
False
)
objects
=
models
.
Manager
()
class
Meta
:
db_table
=
"account_history"
verbose_name_plural
=
"account histories"
ordering
=
[
"-recorded_at"
]
def
__str__
(
self
):
return
f
"[History] Rev.
{
self
.
revision_id
}
-
{
self
.
name
}
"
class
Account
(
HistoryEnabledModel
):
id
=
models
.
UUIDField
(
primary_key
=
True
,
default
=
uuid
.
uuid4
,
editable
=
False
)
user
=
models
.
OneToOneField
(
User
,
on_delete
=
models
.
CASCADE
)
name
=
models
.
CharField
(
max_length
=
128
)
...
...
@@ -15,13 +39,16 @@ class Account(models.Model):
is_active
=
models
.
BooleanField
(
default
=
False
)
created_at
=
models
.
DateTimeField
(
auto_now_add
=
True
)
objects
=
models
.
Manager
()
history_class
=
AccountHistory
relation_fields
=
[
"user"
]
objects
=
SoftDeleteManager
()
class
Meta
:
db_table
=
"account"
verbose_name_plural
=
"accounts"
ordering
=
[
"-created_at"
]
def
__str__
(
self
):
if
self
.
is_admin
:
return
f
"[Admin]
{
self
.
user
.
username
}
"
return
f
"[Officer]
{
self
.
user
.
username
}
"
account_role
=
"[Admin]"
if
self
.
is_admin
else
"[Officer]"
return
f
"
{
account_role
}
{
self
.
user
.
username
}
"
apps/accounts/serializers.py
View file @
6457ab9a
...
...
@@ -5,7 +5,7 @@ from apps.accounts.models import Account
class
AccountSerializer
(
serializers
.
ModelSerializer
):
username
=
serializers
.
CharField
(
source
=
"user.username"
,
re
quired
=
Fals
e
)
username
=
serializers
.
CharField
(
source
=
"user.username"
,
re
ad_only
=
Tru
e
)
class
Meta
:
model
=
Account
...
...
@@ -47,3 +47,8 @@ class AccountRegisterSerializer(serializers.ModelSerializer):
def
validate_password
(
self
,
value
):
password_validation
.
validate_password
(
value
)
return
value
def
to_representation
(
self
,
instance
):
serializer
=
AccountSerializer
(
instance
)
return
serializer
.
data
apps/accounts/tests/test_units/test_accounts.py
View file @
6457ab9a
...
...
@@ -113,15 +113,15 @@ class AccountViewTest(APITestCase):
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_201_CREATED
)
self
.
assertEqual
(
officer_current_count
,
officer_prev_count
+
1
)
#
#
Have account creation log for the new officer
#
new_officer_id = Account.objects.filter(email=_account_id)[0].id
#
response = self.client.get("/logs/")
#
response_string = response.rendered_content.decode("utf-8")
# Have account creation log for the new officer
new_officer_id
=
Account
.
objects
.
filter
(
email
=
_account_id
)[
0
].
id
response
=
self
.
client
.
get
(
"/logs/"
)
response_string
=
response
.
rendered_content
.
decode
(
"utf-8"
)
#
self.assertIn('"object_id":"{}"'.format(new_officer_id), response_string)
#
self.assertIn(
#
'"action_type":"{}"'.format(ACTIVITY_TYPE_CREATE), response_string
#
)
self
.
assertIn
(
'"object_id":"{}"'
.
format
(
new_officer_id
),
response_string
)
self
.
assertIn
(
'"action_type":"{}"'
.
format
(
ACTIVITY_TYPE_CREATE
),
response_string
)
def
test_create_new_account_fails_with_poor_password
(
self
):
url
=
self
.
BASE_URL
...
...
@@ -164,12 +164,12 @@ class AccountViewTest(APITestCase):
str
(
response
.
content
,
encoding
=
"utf8"
),
expected_returned_data
)
#
#
Have account update log
#
response = self.client.get("/logs/")
#
response_string = response.rendered_content.decode("utf-8")
# Have account update log
response
=
self
.
client
.
get
(
"/logs/"
)
response_string
=
response
.
rendered_content
.
decode
(
"utf-8"
)
#
self.assertIn('"object_id":"{}"'.format(self.officer.id), response_string)
#
self.assertIn('"action_type":"{}"'.format(ACTIVITY_TYPE_EDIT), response_string)
self
.
assertIn
(
'"object_id":"{}"'
.
format
(
self
.
officer
.
id
),
response_string
)
self
.
assertIn
(
'"action_type":"{}"'
.
format
(
ACTIVITY_TYPE_EDIT
),
response_string
)
def
test_edit_account_fail_without_complete_fields
(
self
):
url
=
self
.
BASE_URL
+
str
(
self
.
officer
.
id
)
+
"/"
...
...
@@ -190,14 +190,14 @@ class AccountViewTest(APITestCase):
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_204_NO_CONTENT
)
#
#
Have account deletion log
#
response = self.client.get("/logs/")
#
response_string = response.rendered_content.decode("utf-8")
# Have account deletion log
response
=
self
.
client
.
get
(
"/logs/"
)
response_string
=
response
.
rendered_content
.
decode
(
"utf-8"
)
#
self.assertIn('"object_id":"{}"'.format(self.officer.id), response_string)
#
self.assertIn(
#
'"action_type":"{}"'.format(ACTIVITY_TYPE_DELETE), response_string
#
)
self
.
assertIn
(
'"object_id":"{}"'
.
format
(
self
.
officer
.
id
),
response_string
)
self
.
assertIn
(
'"action_type":"{}"'
.
format
(
ACTIVITY_TYPE_DELETE
),
response_string
)
def
test_retrieve_current_profile_success
(
self
):
url
=
self
.
PROFILE_URL
...
...
apps/accounts/views.py
View file @
6457ab9a
...
...
@@ -3,17 +3,22 @@ from django.shortcuts import get_object_or_404
from
django_filters.rest_framework
import
DjangoFilterBackend
from
rest_framework
import
status
,
viewsets
from
rest_framework.decorators
import
action
from
rest_framework.filters
import
SearchFilter
,
OrderingFilter
from
rest_framework.pagination
import
PageNumberPagination
from
rest_framework.response
import
Response
from
apps.accounts.filters
import
AccountFilter
from
apps.accounts.filters
import
(
ACCOUNT_FILTERSET_FIELDS
,
ACCOUNT_ORDERING_FIELDS
,
ACCOUNT_SEARCH_FIELDS
,
)
from
apps.accounts.models
import
Account
from
apps.accounts.serializers
import
(
AccountSerializer
,
AccountRegisterSerializer
,
)
from
apps.commons.permissions
import
(
Is
SelfOrAdministrator
,
Is
Authenticated
,
CreateOnly
,
)
from
apps.constants
import
(
...
...
@@ -22,85 +27,36 @@ from apps.constants import (
ACTIVITY_TYPE_EDIT
,
ACTIVITY_TYPE_DELETE
,
)
from
apps.logs.models
import
Log
class
AccountViewSet
(
viewsets
.
ViewSet
):
queryset
=
Account
.
objects
.
all
().
select_related
(
"user"
).
order_by
(
"-created_at"
)
filter_backends
=
(
DjangoFilterBackend
,)
permission_classes
=
[
IsSelfOrAdministrator
|
CreateOnly
,
]
def
list
(
self
,
request
):
paginator
=
PageNumberPagination
()
filtered_set
=
AccountFilter
(
request
.
GET
,
queryset
=
self
.
queryset
).
qs
context
=
paginator
.
paginate_queryset
(
filtered_set
,
request
)
serializer
=
AccountSerializer
(
context
,
many
=
True
)
return
paginator
.
get_paginated_response
(
serializer
.
data
)
def
retrieve
(
self
,
request
,
pk
=
None
):
instance
=
get_object_or_404
(
self
.
queryset
,
pk
=
pk
)
self
.
check_object_permissions
(
request
,
instance
)
serializer
=
AccountSerializer
(
instance
)
return
Response
(
serializer
.
data
,
status
=
status
.
HTTP_200_OK
)
def
create
(
self
,
request
):
serializer
=
AccountRegisterSerializer
(
data
=
request
.
data
)
serializer
.
is_valid
(
raise_exception
=
True
)
class
AccountViewSet
(
viewsets
.
ModelViewSet
):
serializer_class
=
AccountSerializer
queryset
=
Account
.
objects
.
all
()
filter_backends
=
(
DjangoFilterBackend
,
SearchFilter
,
OrderingFilter
)
filterset_fields
=
ACCOUNT_FILTERSET_FIELDS
permission_classes
=
(
IsAuthenticated
|
CreateOnly
,
)
pagination_class
=
PageNumberPagination
search_fields
=
ACCOUNT_SEARCH_FIELDS
ordering_fields
=
ACCOUNT_ORDERING_FIELDS
def
get_queryset
(
self
):
user
=
self
.
request
.
user
account
=
Account
.
objects
.
filter
(
user
=
user
)
if
account
.
first
().
is_admin
:
return
Account
.
objects
.
all
()
return
account
def
get_serializer_class
(
self
):
if
self
.
action
in
[
'create'
]:
return
AccountRegisterSerializer
return
AccountSerializer
def
perform_create
(
self
,
serializer
):
username
=
serializer
.
validated_data
.
pop
(
"username"
).
lower
()
password
=
serializer
.
validated_data
.
pop
(
"password"
)
user
=
User
.
objects
.
create_user
(
username
=
username
,
password
=
password
)
account
=
Account
.
objects
.
create
(
user
=
user
,
**
serializer
.
validated_data
)
# Add account creation log
Log
.
objects
.
create
(
model_name
=
MODEL_NAME_ACCOUNT
,
object_id
=
account
.
id
,
action_type
=
ACTIVITY_TYPE_CREATE
,
author
=
account
,
)
return
Response
(
AccountSerializer
(
account
).
data
,
status
=
status
.
HTTP_201_CREATED
,
)
def
update
(
self
,
request
,
pk
=
None
):
instance
=
get_object_or_404
(
self
.
queryset
,
pk
=
pk
)
self
.
check_object_permissions
(
request
,
instance
)
serializer
=
AccountSerializer
(
instance
,
data
=
request
.
data
)
serializer
.
is_valid
(
raise_exception
=
True
)
serializer
.
save
()
# Add account update log
Log
.
objects
.
create
(
model_name
=
MODEL_NAME_ACCOUNT
,
object_id
=
pk
,
action_type
=
ACTIVITY_TYPE_EDIT
,
author
=
request
.
user
.
account
,
)
return
Response
(
serializer
.
data
,
status
=
status
.
HTTP_200_OK
)
def
destroy
(
self
,
request
,
pk
=
None
):
instance
=
get_object_or_404
(
self
.
queryset
,
pk
=
pk
)
self
.
check_object_permissions
(
request
,
instance
)
instance
.
delete
()
# Add account deletion log
Log
.
objects
.
create
(
model_name
=
MODEL_NAME_ACCOUNT
,
object_id
=
pk
,
action_type
=
ACTIVITY_TYPE_DELETE
,
author
=
request
.
user
.
account
,
)
serializer
=
AccountSerializer
(
instance
=
instance
)
return
Response
(
serializer
.
data
,
status
=
status
.
HTTP_200_OK
)
Account
.
objects
.
create
(
user
=
user
,
**
serializer
.
validated_data
)
@
action
(
detail
=
False
,
methods
=
[
"get"
],
url_path
=
"me"
)
def
profile
(
self
,
request
):
...
...
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