First commit
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
{
|
||||
"info": {
|
||||
"name": "Account",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
|
||||
"description": "Account API. GET list, GET by uuid (detail), POST add, PATCH update, DELETE delete, PATCH profile. Authenticated user required."
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "Update profile",
|
||||
"request": {
|
||||
"method": "PATCH",
|
||||
"header": [
|
||||
{"key": "Content-Type", "value": "application/json"},
|
||||
{"key": "Authorization", "value": "Bearer {{token}}", "description": "Required: user must be authenticated"}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"first_name\": \"\",\n \"last_name\": \"\",\n \"email\": \"\"\n}"
|
||||
},
|
||||
"url": "{{baseUrl}}/api/account/profile/",
|
||||
"description": "Update current user profile (first_name, last_name, email). Returns UpdateProfileResponse."
|
||||
},
|
||||
"response": [
|
||||
{
|
||||
"name": "Success",
|
||||
"status": "OK",
|
||||
"code": 200,
|
||||
"body": "{\n \"code\": 200,\n \"msg\": \"success\",\n \"data\": {\n \"id\": 0,\n \"username\": \"\",\n \"email\": \"\",\n \"first_name\": \"\",\n \"last_name\": \"\",\n \"phone_number\": \"\"\n }\n}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "List accounts",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{"key": "Content-Type", "value": "application/json"},
|
||||
{"key": "Authorization", "value": "Bearer {{token}}", "description": "Required: user must be authenticated"}
|
||||
],
|
||||
"url": "{{baseUrl}}/api/account/",
|
||||
"description": "Get list of accounts. GET on base route."
|
||||
},
|
||||
"response": [
|
||||
{
|
||||
"name": "Success",
|
||||
"status": "OK",
|
||||
"code": 200,
|
||||
"body": "{\n \"code\": 200,\n \"msg\": \"success\",\n \"data\": {}\n}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Get account detail (by uuid)",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{"key": "Content-Type", "value": "application/json"},
|
||||
{"key": "Authorization", "value": "Bearer {{token}}", "description": "Required: user must be authenticated"}
|
||||
],
|
||||
"url": "{{baseUrl}}/api/account/{{uuid}}/",
|
||||
"description": "Get one account by uuid in path."
|
||||
},
|
||||
"response": [
|
||||
{
|
||||
"name": "Success",
|
||||
"status": "OK",
|
||||
"code": 200,
|
||||
"body": "{\n \"code\": 200,\n \"msg\": \"success\",\n \"data\": {}\n}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Add account",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{"key": "Content-Type", "value": "application/json"},
|
||||
{"key": "Authorization", "value": "Bearer {{token}}", "description": "Required: user must be authenticated"}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"first_name\": \"\",\n \"last_name\": \"\",\n \"phones\": []\n}"
|
||||
},
|
||||
"url": "{{baseUrl}}/api/account/",
|
||||
"description": "Add a new account. POST on base route."
|
||||
},
|
||||
"response": [
|
||||
{
|
||||
"name": "Success",
|
||||
"status": "OK",
|
||||
"code": 200,
|
||||
"body": "{\n \"code\": 200,\n \"msg\": \"success\"\n}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Update account",
|
||||
"request": {
|
||||
"method": "PATCH",
|
||||
"header": [
|
||||
{"key": "Content-Type", "value": "application/json"},
|
||||
{"key": "Authorization", "value": "Bearer {{token}}", "description": "Required: user must be authenticated"}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"first_name\": \"\",\n \"last_name\": \"\",\n \"phones\": []\n}"
|
||||
},
|
||||
"url": "{{baseUrl}}/api/account/{{uuid}}/",
|
||||
"description": "Update account by uuid in path. PATCH."
|
||||
},
|
||||
"response": [
|
||||
{
|
||||
"name": "Success",
|
||||
"status": "OK",
|
||||
"code": 200,
|
||||
"body": "{\n \"code\": 200,\n \"msg\": \"success\"\n}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Delete account",
|
||||
"request": {
|
||||
"method": "DELETE",
|
||||
"header": [
|
||||
{"key": "Authorization", "value": "Bearer {{token}}", "description": "Required: user must be authenticated"}
|
||||
],
|
||||
"url": "{{baseUrl}}/api/account/{{uuid}}/",
|
||||
"description": "Delete account by uuid in path."
|
||||
},
|
||||
"response": [
|
||||
{
|
||||
"name": "Success",
|
||||
"status": "OK",
|
||||
"code": 200,
|
||||
"body": "{\n \"code\": 200,\n \"msg\": \"success\"\n}"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"variable": [
|
||||
{"key": "baseUrl", "value": "http://localhost:8000"},
|
||||
{"key": "token", "value": ""},
|
||||
{"key": "uuid", "value": "550e8400-e29b-41d4-a716-446655440000"}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
Account API serializers.
|
||||
UpdateProfile request/response shapes aligned with frontend types.
|
||||
"""
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
|
||||
class UpdateProfileSerializer(serializers.Serializer):
|
||||
"""
|
||||
Request body for PATCH /api/account/profile/ (UpdateProfilePayload).
|
||||
"""
|
||||
|
||||
first_name = serializers.CharField(max_length=150, required=False, allow_blank=True)
|
||||
last_name = serializers.CharField(max_length=150, required=False, allow_blank=True)
|
||||
email = serializers.EmailField(required=False, allow_blank=True)
|
||||
@@ -0,0 +1,9 @@
|
||||
from django.urls import path
|
||||
|
||||
from .views import AccountView, ProfileView
|
||||
|
||||
urlpatterns = [
|
||||
path("profile/", ProfileView.as_view(), name="profile-update"),
|
||||
path("<uuid:uuid>/", AccountView.as_view(), name="account-detail"),
|
||||
path("", AccountView.as_view(), name="account-list"),
|
||||
]
|
||||
@@ -0,0 +1,129 @@
|
||||
"""
|
||||
Account API module.
|
||||
CRUD endpoints for user account profile (first name, last name, phone numbers).
|
||||
Profile update endpoint returns UpdateProfileResponse (code, msg, data: AuthUser).
|
||||
"""
|
||||
|
||||
from rest_framework import status
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from .serializers import UpdateProfileSerializer
|
||||
|
||||
|
||||
def _auth_user_to_data(user):
|
||||
"""Build AuthUser-shaped dict from Django User."""
|
||||
if user is None or not getattr(user, "pk", None):
|
||||
return None
|
||||
# return {
|
||||
# "id": user.id,
|
||||
# "username": getattr(user, "username", "") or "",
|
||||
# "email": getattr(user, "email", "") or "",
|
||||
# "first_name": getattr(user, "first_name", "") or "",
|
||||
# "last_name": getattr(user, "last_name", "") or "",
|
||||
# "phone_number": getattr(user, "phone_number", "") or "",
|
||||
# }
|
||||
return {
|
||||
"id": 1,
|
||||
"username": "testuser",
|
||||
"email": "testuser@example.com",
|
||||
"first_name": "Test",
|
||||
"last_name": "User",
|
||||
"phone_number": "09123456789",
|
||||
}
|
||||
|
||||
|
||||
class ProfileView(APIView):
|
||||
"""
|
||||
PATCH /api/account/profile/
|
||||
UpdateProfilePayload: first_name, last_name, email.
|
||||
UpdateProfileResponse: code, msg, data (AuthUser).
|
||||
"""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def patch(self, request):
|
||||
serializer = UpdateProfileSerializer(data=request.data, partial=True)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
# TODO: persist first_name, last_name, email via service layer
|
||||
user = request.user
|
||||
data = _auth_user_to_data(user)
|
||||
if data is None:
|
||||
data = {
|
||||
"id": 0,
|
||||
"username": "",
|
||||
"email": "",
|
||||
"first_name": "",
|
||||
"last_name": "",
|
||||
"phone_number": "",
|
||||
}
|
||||
return Response(
|
||||
{"code": 200, "msg": "success", "data": data},
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
|
||||
class AccountView(APIView):
|
||||
"""
|
||||
Account CRUD endpoints. Dispatch by HTTP method and path (uuid for detail/update/delete).
|
||||
No processing, validation, or transformation is applied to any input.
|
||||
All endpoints return HTTP 200 only. Response format: {"code": 200, "msg": "success"} or {"code": 200, "msg": "success", "data": {}}.
|
||||
|
||||
Routes:
|
||||
- GET "" → List: returns status "success", data {}.
|
||||
- GET "<uuid>/" → Detail: uuid (path). Returns status "success", data {}.
|
||||
- POST "" → Create: body/query may contain first_name, last_name, phones; not used. Returns status "success". No data field.
|
||||
- PATCH "<uuid>/" → Update: uuid (path), body/query may contain first_name, last_name, phones; not used. Returns status "success". No data field.
|
||||
- DELETE "<uuid>/" → Delete: uuid (path). Returns status "success". No data field.
|
||||
"""
|
||||
|
||||
# permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
"""
|
||||
List or detail account.
|
||||
|
||||
List (GET on base URL):
|
||||
- Input parameters: none required. Query params if sent are not processed.
|
||||
- Response: {"code": 200, "msg": "success", "data": {}}.
|
||||
- No processing or validation is performed on inputs.
|
||||
|
||||
Detail (GET on <uuid>/):
|
||||
- Input parameters: uuid (path, UUID). Description: identifier for the account resource.
|
||||
- Response: {"code": 200, "msg": "success", "data": {}}.
|
||||
- No processing or validation is performed on inputs.
|
||||
"""
|
||||
return Response({"code": 200, "msg": "success", "data": {}}, status=status.HTTP_200_OK)
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""
|
||||
Create account.
|
||||
|
||||
Input parameters (body, JSON): first_name (string), last_name (string), phones (array of strings).
|
||||
Description: intended for user first name, last name, and phone numbers. Not processed or validated.
|
||||
Response: {"code": 200, "msg": "success"}. No data field.
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
return Response({"code": 200, "msg": "success"}, status=status.HTTP_200_OK)
|
||||
|
||||
def patch(self, request, *args, **kwargs):
|
||||
"""
|
||||
Update account.
|
||||
|
||||
Input parameters: uuid (path, UUID), body (JSON) may contain first_name, last_name, phones.
|
||||
Description: identifier in path; body fields intended for updated profile. Not processed or validated.
|
||||
Response: {"code": 200, "msg": "success"}. No data field.
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
return Response({"code": 200, "msg": "success"}, status=status.HTTP_200_OK)
|
||||
|
||||
def delete(self, request, *args, **kwargs):
|
||||
"""
|
||||
Delete account.
|
||||
|
||||
Input parameters: uuid (path, UUID). Description: identifier for the account resource to delete.
|
||||
Response: {"code": 200, "msg": "success"}. No data field.
|
||||
No processing or validation is performed on inputs.
|
||||
"""
|
||||
return Response({"code": 200, "msg": "success"}, status=status.HTTP_200_OK)
|
||||
Reference in New Issue
Block a user