repa main, repa device view, repa device and cafe assignments

This commit is contained in:
Tom Irgang 2023-06-18 17:15:21 +02:00
parent f91ae88592
commit a7501ec565
9 changed files with 299 additions and 28 deletions

View file

@ -0,0 +1,24 @@
# Generated by Django 4.2 on 2023-06-18 07:46
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('repapp', '0010_customuser_notifications'),
]
operations = [
migrations.AddField(
model_name='reparateur',
name='cafe',
field=models.ManyToManyField(to='repapp.cafe'),
),
migrations.AlterField(
model_name='device',
name='guest',
field=models.ForeignKey(choices=[(-1, 'abgelehnt'), (0, 'neu'), (1, 'in Orga Rückfrage'), (2, 'in Orga Rückfrage beantwortet'), (3, 'in der Warteliste')], null=True, on_delete=django.db.models.deletion.CASCADE, to='repapp.guest', verbose_name='Gast'),
),
]

View file

@ -0,0 +1,22 @@
# Generated by Django 4.2 on 2023-06-18 13:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('repapp', '0011_reparateur_cafe_alter_device_guest'),
]
operations = [
migrations.RemoveField(
model_name='reparateur',
name='cafe',
),
migrations.AddField(
model_name='cafe',
name='reparateur',
field=models.ManyToManyField(to='repapp.reparateur'),
),
]

View file

@ -0,0 +1,18 @@
# Generated by Django 4.2 on 2023-06-18 14:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('repapp', '0012_remove_reparateur_cafe_cafe_reparateur'),
]
operations = [
migrations.AddField(
model_name='device',
name='reparateur',
field=models.ManyToManyField(to='repapp.reparateur'),
),
]

View file

@ -30,6 +30,21 @@ class CustomUser(AbstractUser):
return f'{self.email}'
class Reparateur(models.Model):
"""
A Reparateur is a member of the Repair-Café who supports guests with fixing their devices.
"""
name = models.CharField(max_length=200, verbose_name=_("Name"))
mail = models.CharField(max_length=200, verbose_name=_("eMail"))
class Meta:
verbose_name = _('Reparateur')
verbose_name_plural = _('Reparateure')
def __str__(self):
return f'Reparateur {self.name} (eMail: {self.mail})'
class Cafe(models.Model):
"""
A Cafe is a "Repair-Café event.
@ -39,6 +54,7 @@ class Cafe(models.Model):
address = models.CharField(
max_length=200, verbose_name=_("Adresse"))
event_date = models.DateField(verbose_name=_("Datum"))
reparateur = models.ManyToManyField(Reparateur)
class Meta:
verbose_name = _('Repair-Café')
@ -48,22 +64,6 @@ class Cafe(models.Model):
return f'Repair-Café am {self.event_date} (Ort: {self.location})'
class Reparateur(models.Model):
"""
A Reparateur is a member of the Repair-Café who supports guests with fixing their devices.
"""
name = models.CharField(max_length=200, verbose_name=_("Name"))
mail = models.CharField(max_length=200, verbose_name=_("eMail"))
cafe = models.ManyToManyField(Cafe)
class Meta:
verbose_name = _('Reparateur')
verbose_name_plural = _('Reparateure')
def __str__(self):
return f'Reparateur {self.name} (eMail: {self.mail})'
class Organisator(models.Model):
"""
A Organisator is a member of the Repair-Café who arranges repair appointments with guests.
@ -108,12 +108,16 @@ class Device(models.Model):
STATUS_ORGA_QUESTION = 1
STATUS_ORGA_QUESTION_ANSWERED = 2
STATUS_WAITING_LIST = 3
STATUS_REPA_QUESTION = 4
STATUS_REPA_QUESTION_ANSWERED = 5
STATUS = (
(STATUS_REJECTED, 'abgelehnt'),
(STATUS_NEW, 'neu'),
(STATUS_ORGA_QUESTION, 'in Orga Rückfrage'),
(STATUS_ORGA_QUESTION_ANSWERED, 'in Orga Rückfrage beantwortet'),
(STATUS_WAITING_LIST, 'in der Warteliste'),
(STATUS_REPA_QUESTION, 'in Repa Rückfrage'),
(STATUS_REPA_QUESTION_ANSWERED, 'in Repa Rückfrage beantwortet'),
)
identifier = models.CharField(max_length=200, verbose_name=_("ID"))
@ -134,6 +138,7 @@ class Device(models.Model):
Guest, on_delete=models.CASCADE, null=True, verbose_name=_("Gast"), choices=STATUS)
cafe = models.ForeignKey(
Cafe, on_delete=models.CASCADE, null=False, verbose_name=_("Repair-Café"))
reparateur = models.ManyToManyField(Reparateur)
class Meta:
verbose_name = _('Gerät')

View file

@ -52,7 +52,8 @@
background-repeat: no-repeat;
background-size: cover;
background-position: center;
max-width:1920px;>
max-width:1920px;
margin-bottom:10px">
<div class="col-md-5 p-lg-5 mx-auto my-5">
<h1 class="display-4 font-weight-normal"
style="font-size: 60px;

View file

@ -26,9 +26,19 @@
<tr>
<td>{{ cafe.event_date|date:"l" }}, {{ cafe.event_date|date }}</td>
<td>{{ cafe.location }}</td>
<td>Nein</td>
<td>
<a href="" class="btn btn-primary">teilnehmen</a>
{% if cafe.accepted %}
Ja
{% else %}
Nein
{% endif %}
</td>
<td>
{% if cafe.accepted %}
<a href="{% url 'repa_cafe_decline' cafe.pk %}" class="btn btn-primary">absagen</a>
{% else %}
<a href="{% url 'repa_cafe_accept' cafe.pk %}" class="btn btn-primary">teilnehmen</a>
{% endif %}
</td>
</tr>
{% empty %}
@ -47,6 +57,7 @@
<th scope="col">Hersteller & Modell/Typ</th>
<th scope="col">Repair-Café</th>
<th scope="col">Ort</th>
<th scope="col">mir zugeordnet?</th>
<th scope="col"></th>
</tr>
</thead>
@ -58,7 +69,14 @@
<td>{{ device.cafe.event_date|date:"l" }}, {{ device.cafe.event_date|date }}</td>
<td>{{ device.cafe.location }}</td>
<td>
<a href="" class="btn btn-primary">Details</a>
{% if device.assigned %}
Ja
{% else %}
Nein
{% endif %}
</td>
<td>
<a href="{% url 'repa_view_device' device.pk %}" class="btn btn-primary">Details</a>
</td>
</tr>
{% empty %}

View file

@ -0,0 +1,75 @@
{% extends "repapp/base.html" %}
{% load crispy_forms_tags %}
{% block title %}
- Gerät
{% endblock title %}
{% block page_title %}
Gerät
{% endblock page_title %}
{% block content %}
<p>
<a href="{% url 'repa' %}" class="btn btn-primary">Zurück</a>
{% if assigned %}
<a href="{% url 'repa_device_unassign' device.pk %}"
class="btn btn-primary">Gerät ablehnen</a>
<a href="{% url 'device_question' device.pk %}" class="btn btn-primary">Rückfrage</a>
{% else %}
<a href="{% url 'repa_device_assign' device.pk %}"
class="btn btn-primary">Gerät mir zuordnen</a>
{% endif %}
</p>
<hr class="mt-0 mb-4">
<h1 class="mt-2">Gerät</h1>
<table class="table">
<tbody>
<tr>
<th scope="row">Art des Geräts</th>
<td>{{ device.device }}</td>
</tr>
<tr>
<th scope="row">Hersteller & Modell/Typ</th>
<td>{{ device.manufacturer }}</td>
</tr>
<tr>
<th scope="row">Fehlerbeschreibung</th>
<td>{{ device.error }}</td>
</tr>
<tr>
<th scope="row">Folgetermin</th>
<td>
{% if device.follow_up %}
Ja
{% else %}
Nein
{% endif %}
</td>
</tr>
<tr>
<th scope="row">Foto vom Gerät</th>
<td>
{% if device.device_picture %}
<img alt="Foto vom Gerät"
height="100%"
width="50%"
src="/media/{{ device.device_picture }}" />
{% else %}
kein Bild
{% endif %}
</td>
</tr>
<tr>
<th scope="row">Foto vom Typenschild</th>
<td>
{% if device.device_picture %}
<img alt="Foto vom Typenschild"
height="100%"
width="50%"
src="/media/{{ device.type_plate_picture }}" />
{% else %}
kein Bild
{% endif %}
</td>
</tr>
</tbody>
</table>
{% endblock content %}

View file

@ -44,6 +44,15 @@ urlpatterns = [
path("member/question/",
views.questions, name="device_questions"),
path("repa/", views.repa, name="repa"),
path("repa/<int:cafe>/accept", views.repa_cafe_accept, name="repa_cafe_accept"),
path("repa/<int:cafe>/decline",
views.repa_cafe_decline, name="repa_cafe_decline"),
path("repa/<int:device>/",
views.repa_view_device, name="repa_view_device"),
path("repa/<int:device>/assign",
views.repa_device_assign, name="repa_device_assign"),
path("repa/<int:device>/unassign",
views.repa_device_unassign, name="repa_device_unassign"),
path("cafe/", views.CafeView.as_view(), name="cafe"),
path("cafe/create", views.CafeCreateView.as_view(), name="create_cafe"),
path("cafe/<int:pk>/edit", views.CafeUpdateView.as_view(), name="edit_cafe"),

View file

@ -618,7 +618,7 @@ class QuestionDeviceFormView(LoginRequiredMixin, UserPassesTestMixin, generic.ed
login_url = reverse_lazy('member')
def test_func(self):
return is_organisator(self.request.user)
return is_member(self.request.user)
def form_valid(self, form):
device = self.kwargs['device']
@ -628,23 +628,31 @@ class QuestionDeviceFormView(LoginRequiredMixin, UserPassesTestMixin, generic.ed
message = form.cleaned_data['message']
mail = self.request.user.email
organisator = Organisator.objects.filter(mail=mail).first()
reparateur = Reparateur.objects.filter(mail=mail).first()
if organisator:
question = Question(
question=message,
organisator=organisator,
device=device
)
send_device_question_mail(question, self.request)
device.status = Device.STATUS_ORGA_QUESTION
elif reparateur:
question = Question(
question=message,
reparateur=reparateur,
device=device
)
device.status = Device.STATUS_REPA_QUESTION
else:
raise PermissionDenied('Not valid member found!')
question.save()
send_device_question_mail(question, self.request)
device.status = Device.STATUS_ORGA_QUESTION
device.save()
return HttpResponseRedirect(
reverse_lazy('orga')
reverse_lazy('member')
)
def get_initial(self, **kwargs):
@ -782,8 +790,21 @@ def repa(request):
logger.warning('The user %s is no reparateur!', str(request.user))
raise PermissionDenied('Not reparateur!')
cafes = Cafe.objects.filter(event_date__gte=datetime.date.today())
devices = Device.objects.filter(status=Device.STATUS_WAITING_LIST)
devices = []
for device in Device.objects.filter(status__gte=Device.STATUS_WAITING_LIST):
if device.reparateur.filter(mail=request.user.email).count() > 0:
device.assigned = True
else:
device.assigned = False
devices.append(device)
cafes = []
for cafe in Cafe.objects.filter(event_date__gte=datetime.date.today()):
if cafe.reparateur.filter(mail=request.user.email).count() > 0:
cafe.accepted = True
else:
cafe.accepted = False
cafes.append(cafe)
return render(
request,
@ -977,3 +998,81 @@ class MemberSettingsFormView(LoginRequiredMixin, UserPassesTestMixin, generic.ed
def test_func(self):
return is_member(self.request.user)
@login_required(login_url=reverse_lazy('member'))
def repa_cafe_accept(request, cafe):
if not is_reparateur(request.user):
raise PermissionDenied('Not a reparateur!')
cafe = get_object_or_404(Cafe, pk=cafe)
reparateur = get_object_or_404(Reparateur, mail=request.user.email)
cafe.reparateur.add(reparateur)
cafe.save()
return HttpResponseRedirect(reverse_lazy('repa'))
@login_required(login_url=reverse_lazy('member'))
def repa_cafe_decline(request, cafe):
if not is_reparateur(request.user):
raise PermissionDenied('Not a reparateur!')
cafe = get_object_or_404(Cafe, pk=cafe)
reparateur = get_object_or_404(Reparateur, mail=request.user.email)
cafe.reparateur.remove(reparateur)
cafe.save()
return HttpResponseRedirect(reverse_lazy('repa'))
@login_required(login_url=reverse_lazy('member'))
def repa_view_device(request, device):
"""
View device details.
"""
# TODO: test
if not is_reparateur(request.user):
raise PermissionDenied('Not reparateur!')
device = get_object_or_404(Device, pk=device)
assigned = device.reparateur.filter(mail=request.user.email).count() > 0
return render(
request,
"repapp/repa/view_device.html",
{
'device': device,
'assigned': assigned,
}
)
@login_required(login_url=reverse_lazy('member'))
def repa_device_assign(request, device):
if not is_reparateur(request.user):
raise PermissionDenied('Not a reparateur!')
device = get_object_or_404(Device, pk=device)
reparateur = get_object_or_404(Reparateur, mail=request.user.email)
device.reparateur.add(reparateur)
device.save()
return HttpResponseRedirect(reverse_lazy('repa_view_device', kwargs={
'device': device.id
}))
@login_required(login_url=reverse_lazy('member'))
def repa_device_unassign(request, device):
if not is_reparateur(request.user):
raise PermissionDenied('Not a reparateur!')
device = get_object_or_404(Device, pk=device)
reparateur = get_object_or_404(Reparateur, mail=request.user.email)
device.reparateur.remove(reparateur)
device.save()
return HttpResponseRedirect(reverse_lazy('repa_view_device', kwargs={
'device': device.id
}))