clean responses messages; create doc
This commit is contained in:
parent
e8c62e9a83
commit
a4c876132e
301
README.md
301
README.md
@ -53,12 +53,307 @@ python manage.py migrate
|
|||||||
```
|
```
|
||||||
python manage.py runserver
|
python manage.py runserver
|
||||||
```
|
```
|
||||||
## Use
|
___
|
||||||
|
## Usage
|
||||||
|
|
||||||
URL is : http://127.0.0.1:8000
|
**URL:** http://127.0.0.1:8000
|
||||||
Endpoints and methods are coming soon
|
|
||||||
|
|
||||||
|
**Authentication :**
|
||||||
|
|
||||||
|
Without authentication (no token):
|
||||||
|
- you can create a user
|
||||||
|
- you can get the project's list
|
||||||
|
|
||||||
|
For any other action a token is required
|
||||||
|
To get details of a project you must be contributor
|
||||||
|
|
||||||
|
To create/get detail of issue or to create/get detail of comment you must be contributor to the project
|
||||||
|
|
||||||
|
User's management:
|
||||||
|
-----
|
||||||
|
|
||||||
|
### *User create:*
|
||||||
|
|
||||||
|
-> POST /api/user/create/
|
||||||
|
<- 201_CREATED ; 400_BAD_REQUEST
|
||||||
|
```
|
||||||
|
params:
|
||||||
|
|
||||||
|
{
|
||||||
|
"username": str,
|
||||||
|
"email": str,
|
||||||
|
"password": str,
|
||||||
|
"password2": str,
|
||||||
|
"age": int,
|
||||||
|
"can_be_contacted": boolean,
|
||||||
|
"can_data_be_shared": boolean
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### *User info:*
|
||||||
|
*token required*
|
||||||
|
-> GET /api/user/
|
||||||
|
<- 200_OK with user's info
|
||||||
|
|
||||||
|
### *User update:*
|
||||||
|
*token required*
|
||||||
|
-> PATCH /api/user/
|
||||||
|
<- 201_CREATED; 400_BAD_REQUEST
|
||||||
|
```
|
||||||
|
params:
|
||||||
|
|
||||||
|
{
|
||||||
|
"email": str,
|
||||||
|
"can_be_contacted": boolean,
|
||||||
|
"can_data_be_shared": boolean
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### *Password update:*
|
||||||
|
|
||||||
|
-> GET /api/user/password-update/
|
||||||
|
<- 204_NO_CONTENT; 400_BAD_REQUEST
|
||||||
|
```
|
||||||
|
params:
|
||||||
|
|
||||||
|
{
|
||||||
|
"old_password": str,
|
||||||
|
"new_password": str,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### *Delete a user*
|
||||||
|
|
||||||
|
*token required*
|
||||||
|
-> DELETE /api/user/
|
||||||
|
<- 204_NO_CONTENT; 401_UNAUTHORIZED
|
||||||
|
```
|
||||||
|
params:
|
||||||
|
|
||||||
|
{
|
||||||
|
"user": str
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### *Get token*
|
||||||
|
|
||||||
|
-> POST /api/token/
|
||||||
|
<- 200_OK
|
||||||
|
```
|
||||||
|
params
|
||||||
|
{
|
||||||
|
"username": str,
|
||||||
|
"password": str,
|
||||||
|
}
|
||||||
|
|
||||||
|
response
|
||||||
|
{
|
||||||
|
"refresh": "xxxxx",
|
||||||
|
"access": "xxxx"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### *Refresh token*
|
||||||
|
|
||||||
|
-> POST /api/token/refresh/
|
||||||
|
<- 200_OK
|
||||||
|
```
|
||||||
|
params
|
||||||
|
{
|
||||||
|
"username": str,
|
||||||
|
"password": str,
|
||||||
|
"refresh": "xxxxxx"
|
||||||
|
}
|
||||||
|
|
||||||
|
response
|
||||||
|
{
|
||||||
|
"refresh": "xxxxx",
|
||||||
|
"access": "xxxx"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Project:
|
||||||
|
---
|
||||||
|
### *Retrieve the list of projects*
|
||||||
|
-> GET /api/project/
|
||||||
|
<- 200_OK / data; 403_FORBIDDEN
|
||||||
|
```
|
||||||
|
querystrings
|
||||||
|
|
||||||
|
?contributor={user}
|
||||||
|
?author={user}
|
||||||
|
```
|
||||||
|
|
||||||
|
### *Create a project*
|
||||||
|
-> POST /api/project/
|
||||||
|
<- 200_OK / data; 403_FORBIDDEN
|
||||||
|
```
|
||||||
|
params:
|
||||||
|
|
||||||
|
{
|
||||||
|
"title": str,
|
||||||
|
"type":
|
||||||
|
"choices": [
|
||||||
|
{
|
||||||
|
"value": "BackEnd",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "FrontEnd",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "iOS",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "Android",
|
||||||
|
},
|
||||||
|
"description": str,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### *Get project's detail*
|
||||||
|
*token required*
|
||||||
|
-> GET /api/project/{id}/
|
||||||
|
<- 200_OK / data; 403_FORBIDDEN
|
||||||
|
|
||||||
|
### *Update a project*
|
||||||
|
*token required*
|
||||||
|
-> PATCH /api/project/{id}/
|
||||||
|
<- 200_OK / data; 403_FORBIDDEN
|
||||||
|
params:
|
||||||
|
|
||||||
|
{
|
||||||
|
"title": str,
|
||||||
|
"type":
|
||||||
|
"choices": [
|
||||||
|
{
|
||||||
|
"value": "BackEnd",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "FrontEnd",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "iOS",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "Android",
|
||||||
|
},
|
||||||
|
"description": str,
|
||||||
|
}
|
||||||
|
|
||||||
|
### *Add a contributor to a project*
|
||||||
|
*token required*
|
||||||
|
|
||||||
|
-> PATCH /api/project/{id}/contributor/
|
||||||
|
<- 202_ACCEPTED; 403_FORBIDDEN
|
||||||
|
```
|
||||||
|
params:
|
||||||
|
|
||||||
|
{
|
||||||
|
"contributor": {username}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### *Delete a project*
|
||||||
|
*token required*
|
||||||
|
-> DELETE /api/project/{id}/
|
||||||
|
<- 204_NO_CONTENT; 403_FORBIDDEN
|
||||||
|
|
||||||
|
Issue:
|
||||||
|
---
|
||||||
|
### *List issues (where requestor is contributor)*
|
||||||
|
*token required*
|
||||||
|
-> GET /api/issue/
|
||||||
|
<- 200_OK
|
||||||
|
|
||||||
|
### *Create an issue*
|
||||||
|
*token required*
|
||||||
|
-> POST /api/issue/
|
||||||
|
<- 201_CREATED / data; 403_FORBIDDEN
|
||||||
|
```
|
||||||
|
params:
|
||||||
|
|
||||||
|
{
|
||||||
|
"title": str,
|
||||||
|
"project": int,
|
||||||
|
"description": str,
|
||||||
|
"priority":
|
||||||
|
"choices": [
|
||||||
|
{
|
||||||
|
"value": "Low",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "Medium",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "High",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"tag":
|
||||||
|
"choices": [
|
||||||
|
{
|
||||||
|
"value": "Bug",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "Feature",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "Task",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
"status":
|
||||||
|
"choices": [
|
||||||
|
{
|
||||||
|
"value": "ToDo",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "In Progress",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"value": "Finished",,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### *Update an issue*
|
||||||
|
*token required*
|
||||||
|
-> PATCH /api/issue/{id}/
|
||||||
|
<- 200_OK / data; 403_FORBIDDEN
|
||||||
|
|
||||||
|
/!\ Only the author of an issue can affect it
|
||||||
|
(update to another author)
|
||||||
|
|
||||||
|
### *Delete an issue*
|
||||||
|
*token required*
|
||||||
|
-> DELETE /api/issue/{id}/
|
||||||
|
<- 204_NO_CONTENT; 403_FORBIDDEN
|
||||||
|
|
||||||
|
### *Retrieve contributors for a given issue*
|
||||||
|
*token required*
|
||||||
|
-> GET /api/issue/{id}/contributors/
|
||||||
|
<- 200_OK; 403_FORBIDDEN
|
||||||
|
|
||||||
|
Comment:
|
||||||
|
---
|
||||||
|
### *Create a comment*
|
||||||
|
*token required*
|
||||||
|
-> POST /api/comment/
|
||||||
|
<- 201_CREATED / data; 403_FORBIDDEN
|
||||||
|
```
|
||||||
|
params:
|
||||||
|
|
||||||
|
{
|
||||||
|
"title": str,
|
||||||
|
"issue": int,
|
||||||
|
"description": str
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### *Update a comment*
|
||||||
|
*token required*
|
||||||
|
-> PATCH /api/comment/{id}/
|
||||||
|
<- 200_OK / data; 403_FORBIDDEN
|
||||||
|
|
||||||
|
### *Delete a comment*
|
||||||
|
*token required*
|
||||||
|
-> DELETE /api/comment/{id}/
|
||||||
|
<- 204_NO_CONTENT; 403_FORBIDDEN
|
||||||
|
___
|
||||||
## Author
|
## Author
|
||||||
|
|
||||||
YaL <yann@needsome.coffee>
|
YaL <yann@needsome.coffee>
|
||||||
|
@ -6,6 +6,7 @@ from rest_framework.response import Response
|
|||||||
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
|
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
|
|
||||||
from authentication.models import User
|
from authentication.models import User
|
||||||
from authentication.serializers import (UserSerializer,
|
from authentication.serializers import (UserSerializer,
|
||||||
@ -18,29 +19,22 @@ class UserCreateView(APIView):
|
|||||||
"""
|
"""
|
||||||
Allow user registration for anyone
|
Allow user registration for anyone
|
||||||
"""
|
"""
|
||||||
|
|
||||||
#TODELETE : for testing purpose
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
user = User.objects.all()
|
|
||||||
serializer = UserSerializer(user, many=True)
|
|
||||||
return Response(serializer.data)
|
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
"""
|
"""
|
||||||
User subscription
|
Creates a new user
|
||||||
Args:
|
Requires :
|
||||||
|
username->str, email->str, password->str, password2->str, age->int,
|
||||||
|
can_be_contacted->bool, can_data_be_shared->bool
|
||||||
"""
|
"""
|
||||||
serializer = UserRegisterSerializer(data=request.data)
|
serializer = UserRegisterSerializer(data=request.data)
|
||||||
if serializer.is_valid(raise_exception=True):
|
if serializer.is_valid(raise_exception=True):
|
||||||
serializer.save()
|
serializer.save()
|
||||||
response = {
|
response = {
|
||||||
"message": "User created successfully",
|
"detail": "User created successfully",
|
||||||
"data": serializer.data
|
"data": serializer.data
|
||||||
}
|
}
|
||||||
return Response(data=response,
|
return Response(data=response, status=status.HTTP_201_CREATED)
|
||||||
status=status.HTTP_201_CREATED)
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
return Response(serializer.errors,
|
|
||||||
status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
|
|
||||||
class PasswordUpdateView(APIView):
|
class PasswordUpdateView(APIView):
|
||||||
@ -56,10 +50,11 @@ class PasswordUpdateView(APIView):
|
|||||||
user.set_password(serializer.data.get('new_password'))
|
user.set_password(serializer.data.get('new_password'))
|
||||||
user.save()
|
user.save()
|
||||||
update_session_auth_hash(request, user)
|
update_session_auth_hash(request, user)
|
||||||
return Response(serializer.errors,
|
response = {
|
||||||
status=status.HTTP_204_NO_CONTENT)
|
"detail": "Password updated successfully."
|
||||||
return Response(serializer.errors,
|
}
|
||||||
status=status.HTTP_400_BAD_REQUEST)
|
return Response(response, status=status.HTTP_204_NO_CONTENT)
|
||||||
|
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
class UserView(APIView):
|
class UserView(APIView):
|
||||||
permission_classes = [IsAuthenticated]
|
permission_classes = [IsAuthenticated]
|
||||||
@ -67,16 +62,18 @@ class UserView(APIView):
|
|||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
return Response(UserSerializer(request.user).data)
|
return Response(UserSerializer(request.user).data)
|
||||||
|
|
||||||
def put(self, request):
|
def patch(self, request):
|
||||||
user = request.user
|
user = request.user
|
||||||
serializer = UserUpdateSerializer(user, data=request.data)
|
serializer = UserUpdateSerializer(user, data=request.data)
|
||||||
print(serializer.initial_data)
|
|
||||||
if serializer.is_valid():
|
if serializer.is_valid():
|
||||||
serializer.save()
|
serializer.save()
|
||||||
return Response("Data updated",
|
response = {
|
||||||
status=status.HTTP_201_CREATED)
|
"detail": "Data updated",
|
||||||
return Response("Error",
|
"data": serializer.data
|
||||||
status=status.HTTP_400_BAD_REQUEST)
|
}
|
||||||
|
return Response(response, status=status.HTTP_201_CREATED)
|
||||||
|
response = {"detail": "Data error"}
|
||||||
|
return Response(response, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
def delete(self, request):
|
def delete(self, request):
|
||||||
user = request.user
|
user = request.user
|
||||||
@ -84,13 +81,9 @@ class UserView(APIView):
|
|||||||
if 'user' in request.data:
|
if 'user' in request.data:
|
||||||
if username == request.data['user']:
|
if username == request.data['user']:
|
||||||
user.delete()
|
user.delete()
|
||||||
return Response(f"User {username} deleted.",
|
response = {"detail": f"User {username} deleted."}
|
||||||
status=status.HTTP_204_NO_CONTENT)
|
return Response(response, status=status.HTTP_204_NO_CONTENT)
|
||||||
return Response("Token's owner and user provided don't match",
|
raise PermissionDenied()
|
||||||
status=status.HTTP_400_BAD_REQUEST)
|
response = {"detail": "Username to delete must be given in data"}
|
||||||
return Response("Username to delete must be given in data",
|
return Response(response, status=status.HTTP_400_BAD_REQUEST)
|
||||||
status=status.HTTP_400_BAD_REQUEST)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
21
softdesk/support/migrations/0015_alter_project_author.py
Normal file
21
softdesk/support/migrations/0015_alter_project_author.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Generated by Django 5.2.1 on 2025-06-09 09:40
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('support', '0014_alter_issue_project'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='project',
|
||||||
|
name='author',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='project_author', to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,26 @@
|
|||||||
|
# Generated by Django 5.2.1 on 2025-06-09 15:44
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('support', '0015_alter_project_author'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='issue',
|
||||||
|
name='author',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='issue_author', to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='project',
|
||||||
|
name='author',
|
||||||
|
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='project_author', to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,21 @@
|
|||||||
|
# Generated by Django 5.2.1 on 2025-06-09 15:59
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('support', '0016_alter_issue_author_alter_project_author'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='projectcontributor',
|
||||||
|
name='contributor',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
@ -17,7 +17,7 @@ class Project(models.Model):
|
|||||||
active = models.BooleanField(default=True)
|
active = models.BooleanField(default=True)
|
||||||
description = models.CharField(max_length=4000)
|
description = models.CharField(max_length=4000)
|
||||||
author = models.ForeignKey(settings.AUTH_USER_MODEL,
|
author = models.ForeignKey(settings.AUTH_USER_MODEL,
|
||||||
on_delete=models.DO_NOTHING,
|
on_delete=models.SET_NULL,
|
||||||
related_name='project_author', null=True)
|
related_name='project_author', null=True)
|
||||||
|
|
||||||
contributors = models.ManyToManyField(settings.AUTH_USER_MODEL,
|
contributors = models.ManyToManyField(settings.AUTH_USER_MODEL,
|
||||||
@ -29,7 +29,7 @@ class Project(models.Model):
|
|||||||
|
|
||||||
class ProjectContributor(models.Model):
|
class ProjectContributor(models.Model):
|
||||||
contributor = models.ForeignKey(settings.AUTH_USER_MODEL,
|
contributor = models.ForeignKey(settings.AUTH_USER_MODEL,
|
||||||
on_delete=models.DO_NOTHING)
|
on_delete=models.CASCADE)
|
||||||
active = models.BooleanField(default=True)
|
active = models.BooleanField(default=True)
|
||||||
project = models.ForeignKey('Project',
|
project = models.ForeignKey('Project',
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
@ -76,7 +76,7 @@ class Issue(models.Model):
|
|||||||
on_delete=models.CASCADE)
|
on_delete=models.CASCADE)
|
||||||
author = models.ForeignKey(settings.AUTH_USER_MODEL,
|
author = models.ForeignKey(settings.AUTH_USER_MODEL,
|
||||||
on_delete=models.DO_NOTHING,
|
on_delete=models.DO_NOTHING,
|
||||||
related_name='issue_author', null=True)
|
related_name='issue_author', blank=True, null=True)
|
||||||
|
|
||||||
|
|
||||||
class Comment(models.Model):
|
class Comment(models.Model):
|
||||||
|
@ -87,21 +87,25 @@ class ProjectViewSet(ModelViewSet):
|
|||||||
if not request.user in Project.objects.get(id=pk).contributors.all():
|
if not request.user in Project.objects.get(id=pk).contributors.all():
|
||||||
raise PermissionDenied()
|
raise PermissionDenied()
|
||||||
if request.data is None or not 'contributor' in request.data:
|
if request.data is None or not 'contributor' in request.data:
|
||||||
return Response(f"Key error;`contributor` is expected",
|
response = {"detail": "Key error;`contributor` is expected"}
|
||||||
status=status.HTTP_400_BAD_REQUEST)
|
return Response(response, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
requested_contributor = request.data['contributor']
|
||||||
#get the user's instance
|
#get the user's instance
|
||||||
contributor = User.objects.get(username=request.data['contributor'])
|
try:
|
||||||
data = {'contributor': contributor.id, 'project': int(pk)}
|
user = User.objects.get(username=requested_contributor)
|
||||||
|
data = {'contributor': user.id, 'project': int(pk)}
|
||||||
serializer = ContributorSerializer(data=data)
|
serializer = ContributorSerializer(data=data)
|
||||||
project = Project.objects.get(id=pk)
|
project = Project.objects.get(id=pk)
|
||||||
if serializer.is_valid():
|
if serializer.is_valid():
|
||||||
serializer.save()
|
serializer.save()
|
||||||
return Response(f"User {contributor} "
|
response = {"detail": f"User {user}"
|
||||||
f"added to project {project}",
|
f"added to project ''{project}''"}
|
||||||
status=status.HTTP_202_ACCEPTED)
|
return Response(response, status=status.HTTP_202_ACCEPTED)
|
||||||
response = {'message': 'This user is already contributing'}
|
response = {"detail": "This user is already contributing"}
|
||||||
return Response(response,
|
return Response(response, status=status.HTTP_226_IM_USED)
|
||||||
status=status.HTTP_226_IM_USED)
|
except:
|
||||||
|
response = {"detail": "User doesn't exist"}
|
||||||
|
return Response(response, status=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
|
||||||
class IssueViewSet(ModelViewSet):
|
class IssueViewSet(ModelViewSet):
|
||||||
@ -125,7 +129,8 @@ class IssueViewSet(ModelViewSet):
|
|||||||
id=project_id).contributors.all():
|
id=project_id).contributors.all():
|
||||||
raise PermissionDenied()
|
raise PermissionDenied()
|
||||||
return Issue.objects.filter(project=project_id)
|
return Issue.objects.filter(project=project_id)
|
||||||
projects = Project.objects.filter(contributors=self.request.user).values('id')
|
projects = Project.objects.filter(
|
||||||
|
contributors=self.request.user).values('id')
|
||||||
#query on a list
|
#query on a list
|
||||||
return Issue.objects.filter(project__in=projects)
|
return Issue.objects.filter(project__in=projects)
|
||||||
|
|
||||||
@ -143,7 +148,8 @@ class IssueViewSet(ModelViewSet):
|
|||||||
username=self.request.data['author'])
|
username=self.request.data['author'])
|
||||||
serializer.save(author=requested_author)
|
serializer.save(author=requested_author)
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
return Response("Data error", status=status.HTTP_400_BAD_REQUEST)
|
response = {"detail": "Data error"}
|
||||||
|
return Response(response, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
@action(detail=True, methods=['get'])
|
@action(detail=True, methods=['get'])
|
||||||
def contributors(self, request, pk):
|
def contributors(self, request, pk):
|
||||||
@ -152,8 +158,11 @@ class IssueViewSet(ModelViewSet):
|
|||||||
of the contributors to the issue's project or raise unauthorized
|
of the contributors to the issue's project or raise unauthorized
|
||||||
"""
|
"""
|
||||||
issue = Issue.objects.get(id=pk)
|
issue = Issue.objects.get(id=pk)
|
||||||
if ProjectContributor.objects.filter(project=issue.project).filter(contributor=request.user):
|
if (ProjectContributor.objects.
|
||||||
return Response(UserListSerializer(issue.project.contributors.all(), many=True).data)
|
filter(project=issue.project).
|
||||||
|
filter(contributor=request.user)):
|
||||||
|
return Response(UserListSerializer(
|
||||||
|
issue.project.contributors.all(), many=True).data)
|
||||||
else:
|
else:
|
||||||
raise PermissionDenied()
|
raise PermissionDenied()
|
||||||
|
|
||||||
@ -164,12 +173,14 @@ class IssueViewSet(ModelViewSet):
|
|||||||
project = Project.objects.get(id=request.data['project'])
|
project = Project.objects.get(id=request.data['project'])
|
||||||
serializer = IssueSerializer(data=request.data)
|
serializer = IssueSerializer(data=request.data)
|
||||||
if self.request.user not in project.contributors.all():
|
if self.request.user not in project.contributors.all():
|
||||||
return Response("Requestor isn't contributor for this project",
|
|
||||||
status=status.HTTP_403_FORBIDDEN)
|
|
||||||
if serializer.is_valid(raise_exception=True):
|
|
||||||
serializer.save(author=self.request.user)
|
|
||||||
response = {
|
response = {
|
||||||
"message": f"Issue created for project {project}",
|
"detail": "Requestor isn't contributor for this project"
|
||||||
|
}
|
||||||
|
return Response(response, status=status.HTTP_403_FORBIDDEN)
|
||||||
|
if serializer.is_valid(raise_exception=True):
|
||||||
|
issue = serializer.save(author=self.request.user)
|
||||||
|
response = {
|
||||||
|
"detail": f"Issue {issue.id} created for project {project}",
|
||||||
"data": serializer.data
|
"data": serializer.data
|
||||||
}
|
}
|
||||||
return Response(response, status = status.HTTP_201_CREATED)
|
return Response(response, status = status.HTTP_201_CREATED)
|
||||||
@ -210,9 +221,9 @@ class CommentViewSet(ModelViewSet):
|
|||||||
serializer = CommentDetailSerializer(data=request.data)
|
serializer = CommentDetailSerializer(data=request.data)
|
||||||
if serializer.is_valid(raise_exception=True):
|
if serializer.is_valid(raise_exception=True):
|
||||||
serializer.save(author=user)
|
serializer.save(author=user)
|
||||||
response = {"message": "comment created",
|
response = {"detail": "comment created",
|
||||||
"data": serializer.data}
|
"data": serializer.data}
|
||||||
return Response(response, status=status.HTTP_201_CREATED)
|
return Response(response, status=status.HTTP_201_CREATED)
|
||||||
return Response("Not allowed; "
|
response = {"detail": f"{user} isn't contributor for '{project}'"}
|
||||||
f"{user} isn't contributor for project {project}",
|
return Response(response, status=status.HTTP_403_FORBIDDEN)
|
||||||
status=status.HTTP_403_FORBIDDEN)
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user