project model create and add contributors

This commit is contained in:
yann 2025-05-26 20:08:34 +02:00
parent 278ea3ed0a
commit 776ba21695
14 changed files with 273 additions and 30 deletions

View File

@ -1,6 +1,5 @@
from rest_framework.serializers import ModelSerializer, SerializerMethodField, ValidationError from rest_framework.serializers import ModelSerializer, SerializerMethodField, ValidationError
from rest_framework import serializers from rest_framework import serializers
from support.models import Project, Issue, Comment, Contributor
from authentication.models import User from authentication.models import User

View File

@ -22,12 +22,8 @@ class UserCreateView(APIView):
#TODELETE : for testing purpose #TODELETE : for testing purpose
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
user = User.objects.all() user = User.objects.all()
print(request.user)
serializer = UserSerializer(user, many=True) serializer = UserSerializer(user, many=True)
print(serializer.data)
#if serializer.is_valid():
return Response(serializer.data) return Response(serializer.data)
#return Response("prout", status=status.HTTP_226_IM_USED)
def post(self, request): def post(self, request):
""" """
@ -73,7 +69,6 @@ class UserView(APIView):
def put(self, request): def put(self, request):
user = request.user user = request.user
print("coucou", request.data['user'])
serializer = UserUpdateSerializer(user, data=request.data) serializer = UserUpdateSerializer(user, data=request.data)
print(serializer.initial_data) print(serializer.initial_data)
if serializer.is_valid(): if serializer.is_valid():

View File

@ -1,5 +1,5 @@
from django.contrib import admin from django.contrib import admin
from support.models import Project, Issue, Comment, Contributor from support.models import Project, Issue, Comment, ProjectContributor
from authentication.models import User from authentication.models import User
class AdminUser: class AdminUser:
@ -9,5 +9,5 @@ admin.site.register(User)
admin.site.register(Project) admin.site.register(Project)
admin.site.register(Issue) admin.site.register(Issue)
admin.site.register(Comment) admin.site.register(Comment)
admin.site.register(Contributor) admin.site.register(ProjectContributor)

View File

@ -0,0 +1,19 @@
# Generated by Django 5.2.1 on 2025-05-25 19:36
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('support', '0003_rename_contributor_contributor_user'),
]
operations = [
migrations.AlterField(
model_name='project',
name='author',
field=models.ForeignKey(blank=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='author', to='support.contributor'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 5.2.1 on 2025-05-25 19:37
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('support', '0004_alter_project_author'),
]
operations = [
migrations.AlterField(
model_name='project',
name='author',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='author', to='support.contributor'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 5.2.1 on 2025-05-25 19:37
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('support', '0005_alter_project_author'),
]
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='author', to='support.contributor'),
),
]

View File

@ -0,0 +1,26 @@
# Generated by Django 5.2.1 on 2025-05-25 19:49
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('support', '0006_alter_project_author'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='contributor',
name='active',
field=models.BooleanField(default=True),
),
migrations.AlterField(
model_name='project',
name='author',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='author', to=settings.AUTH_USER_MODEL),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 5.2.1 on 2025-05-25 19:52
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('support', '0007_contributor_active_alter_project_author'),
]
operations = [
migrations.RenameField(
model_name='contributor',
old_name='user',
new_name='contributor_user',
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 5.2.1 on 2025-05-26 05:26
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('support', '0008_rename_user_contributor_contributor_user'),
]
operations = [
migrations.RenameField(
model_name='contributor',
old_name='contributor_user',
new_name='username',
),
]

View File

@ -0,0 +1,52 @@
# Generated by Django 5.2.1 on 2025-05-26 05:53
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('support', '0009_rename_contributor_user_contributor_username'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AlterField(
model_name='comment',
name='author',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='comment_author', to=settings.AUTH_USER_MODEL),
),
migrations.AlterField(
model_name='issue',
name='author',
field=models.ForeignKey(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.DO_NOTHING, related_name='project_author', to=settings.AUTH_USER_MODEL),
),
migrations.CreateModel(
name='ProjectContributor',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('active', models.BooleanField(default=True)),
('data', models.CharField(blank=True, max_length=255)),
('contributor', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL)),
('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='project', to='support.project')),
],
options={
'unique_together': {('contributor', 'project')},
},
),
migrations.AlterField(
model_name='project',
name='contributors',
field=models.ManyToManyField(related_name='contribution', through='support.ProjectContributor', to=settings.AUTH_USER_MODEL),
),
migrations.DeleteModel(
name='Contributor',
),
]

View File

@ -16,23 +16,31 @@ class Project(models.Model):
type = models.CharField(choices=Type.choices, max_length=10) type = models.CharField(choices=Type.choices, max_length=10)
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('Contributor', author = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.DO_NOTHING, on_delete=models.DO_NOTHING,
related_name='author') related_name='project_author', null=True)
contributors = models.ManyToManyField(settings.AUTH_USER_MODEL, contributors = models.ManyToManyField(settings.AUTH_USER_MODEL,
through='Contributor', through='ProjectContributor',
related_name='contribution') related_name='contribution')
def __str__(self):
return self.title
class Contributor(models.Model): class ProjectContributor(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, contributor = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.DO_NOTHING) on_delete=models.DO_NOTHING)
active = models.BooleanField(default=True)
project = models.ForeignKey('Project', project = models.ForeignKey('Project',
on_delete=models.CASCADE, on_delete=models.CASCADE,
related_name='project') related_name='project')
data = models.CharField(max_length=255, blank=True) data = models.CharField(max_length=255, blank=True)
class Meta:
unique_together = ('contributor', 'project')
def __str__(self):
return self.contributor.username
class Issue(models.Model): class Issue(models.Model):
@ -57,21 +65,24 @@ class Issue(models.Model):
title = models.CharField(max_length=255, verbose_name='title') title = models.CharField(max_length=255, verbose_name='title')
date_created = models.DateTimeField(auto_now_add=True) date_created = models.DateTimeField(auto_now_add=True)
description = models.TextField() description = models.TextField()
status = models.CharField(Status.choices, max_length=15)
priority = models.CharField(Priority.choices, max_length=15)
tag = models.CharField(Tag.choices, max_length=15)
project = models.ForeignKey(Project, project = models.ForeignKey(Project,
null=True, null=True,
on_delete=models.CASCADE, on_delete=models.CASCADE,
blank=True) blank=True)
status = models.CharField(Status.choices, max_length=15) author = models.ForeignKey(settings.AUTH_USER_MODEL,
priority = models.CharField(Priority.choices, max_length=15) on_delete=models.DO_NOTHING,
tag = models.CharField(Tag.choices, max_length=15) related_name='issue_author', null=True)
author = models.ForeignKey('Contributor', on_delete=models.DO_NOTHING)
class Comment(models.Model): class Comment(models.Model):
title = models.CharField(max_length=255) title = models.CharField(max_length=255)
date_created = models.DateTimeField(auto_now_add=True) date_created = models.DateTimeField(auto_now_add=True)
description = models.CharField(max_length=4000) description = models.CharField(max_length=4000)
author = models.ForeignKey('Contributor', on_delete=models.DO_NOTHING)
issue = models.ForeignKey(Issue, on_delete=models.CASCADE) issue = models.ForeignKey(Issue, on_delete=models.CASCADE)
author = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.DO_NOTHING,
related_name='comment_author', null=True)

View File

@ -0,0 +1,9 @@
from rest_framework.permissions import BasePermission
class IsAuthor(BasePermission):
def has_object_permission(self, request, view, project):
return bool(request.user
and request.user.is_authenticated
and request.user==project.author)

View File

@ -1,17 +1,36 @@
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import (ModelSerializer,
from support.models import Project, Contributor, Issue, Comment StringRelatedField,
SlugRelatedField)
from support.models import Project, ProjectContributor, Issue, Comment
class ContributorSerializer(ModelSerializer):
class Meta:
model = ProjectContributor
fields = ['contributor', 'project', 'data']
class ProjectSerializer(ModelSerializer): class ProjectSerializer(ModelSerializer):
contributors = SlugRelatedField(many=True,
read_only='True',
slug_field='username')
author = StringRelatedField(many=False)
class Meta: class Meta:
model = Project model = Project
fields = ['title', 'date_created', 'type', 'description', 'author', fields = ['id', 'title', 'date_created', 'type', 'description', 'author',
'contributors'] 'contributors']
class ProjectDetailSerializer(ModelSerializer):
pass
class ContributorSerialier(ModelSerializer): class IssueSerializer(ModelSerializer):
class Meta: class Meta:
model = Contributor model = Issue
Fields = [''] fields = ['title', 'date_created', 'priority', 'tag', 'status', 'author']

View File

@ -1,11 +1,50 @@
from django.shortcuts import render from django.shortcuts import render
from rest_framework.serializers import raise_errors_on_nested_writes
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from support.models import Project, Contributor, Issue, Comment from support.models import Project, ProjectContributor, Issue, Comment
from support.serializers import ProjectSerializer from authentication.models import User
from support.serializers import ProjectSerializer, ContributorSerializer
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import (IsAuthenticated,
IsAuthenticatedOrReadOnly)
from support.permissions import IsAuthor
from rest_framework.decorators import action
class ProjectViewSet(ModelViewSet): class ProjectViewSet(ModelViewSet):
serializer_class = ProjectSerializer permission_classes=[IsAuthenticatedOrReadOnly]
def get_queryset(self): serializer_class = ProjectSerializer
return Project.objects.all() queryset = Project.objects.filter(active=True)
def perform_create(self, serializer):
"""set authenticated user as author and contributor on creation"""
test = serializer.save(author=self.request.user)
data = {'contributor': self.request.user.id, 'project': test.id}
contributor_serializer = ContributorSerializer(data=data)
if contributor_serializer.is_valid():
contributor_serializer.save()
@action(detail=True, methods=['patch'],
permission_classes=[IsAuthor],
basename='add_contributor')
def add_contributor(self, request, pk):
"""Create the user/project contributor's relation"""
if 'contributor' in request.data:
contributor = User.objects.get(username=request.data['contributor'])
data = {'contributor': contributor.id, 'project': pk}
serializer = ContributorSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(f"User {contributor} added",
status=status.HTTP_202_ACCEPTED)
return Response("This user is already contributing",
status=status.HTTP_226_IM_USED)
return Response(f"Key error;`contributor` is expected, "
f"not `{list(request.data)[0]}`",
status=status.HTTP_400_BAD_REQUEST)
class IssueViewSet(ModelViewSet):
serializer =