Skip to content

Commit 1f2bc0c

Browse files
authored
Merge pull request #120 from luftdaten-at/111-geräte-kann-usern-zugeordnet-werden
111 geräte kann usern zugeordnet werden
2 parents 9a59914 + 6df4c4c commit 1f2bc0c

File tree

8 files changed

+129
-8
lines changed

8 files changed

+129
-8
lines changed

app/api/views.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ def post(self, request, *args, **kwargs):
189189
time_measured=station_data['time'],
190190
time_received=time_received,
191191
room = station.current_room,
192+
user = station.current_user,
192193
)
193194
measurement.save()
194195

app/campaign/forms.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,58 @@ def save(self, commit=True):
137137
# Save the room
138138
room.save()
139139

140-
return room
140+
return room
141+
142+
143+
class UserDeviceForm(forms.ModelForm):
144+
current_devices = (forms.ModelMultipleChoiceField(label='',
145+
queryset=Device.objects.none(),
146+
widget=FilteredSelectMultiple(
147+
verbose_name='Devices',
148+
is_stacked=False,
149+
),
150+
required=False))
151+
152+
class Meta:
153+
model = Room
154+
fields = ['current_devices']
155+
156+
class Media:
157+
css = {
158+
'all': ('/static/admin/css/widgets.css', '/static/css/adminoverrides.css', ),
159+
} # custom css
160+
161+
def __init__(self, *args, **kwargs):
162+
super().__init__(*args, **kwargs)
163+
164+
# Get the user from the passed arguments (initial data)
165+
self.user = kwargs.get('initial', {}).get('user', None)
166+
self.campaign = kwargs.get('initial', {}).get('campaign', None)
167+
168+
# query set should be a list of all devices in the same organisation as the room is
169+
self.fields['current_devices'].queryset = self.campaign.organization.current_devices.all()
170+
self.initial['current_devices'] = self.user.current_devices.all()
171+
172+
# Initialize form helper
173+
self.helper = FormHelper(self)
174+
self.helper.add_input(Submit('submit', 'Save'))
175+
176+
def save(self, commit=True):
177+
# Save the room instance
178+
user = super().save(commit=commit)
179+
180+
# Get the selected devices
181+
selected_devices = self.cleaned_data['current_devices']
182+
183+
# Update the ForeignKey for the devices
184+
if commit:
185+
# Unassign the devices previously linked to the room
186+
Device.objects.filter(current_user=user).update(current_user=None)
187+
188+
# Assign the selected devices to the current room
189+
selected_devices.update(current_user=user)
190+
191+
# Save the room
192+
user.save()
193+
194+
return user

app/campaign/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
path('<str:pk>/delete/', CampaignsDeleteView.as_view(), name='campaigns-delete'),
1111
path('<str:pk>/add-user/', CampaignAddUserView.as_view(), name='campaign-add-user'),
1212
path('<str:pk>/participants/<int:user>/', ParticipantDetailView.as_view(), name='participants-detail'),
13+
path('<str:campaign_pk>/participants/<int:pk>/add-devices', ParticipantsAddDevicesView.as_view(), name='user-add-device'),
1314
path('rooms/<int:pk>/', RoomDetailView.as_view(), name='room-detail'),
1415
path('rooms/<int:pk>/delete/', RoomDeleteView.as_view(), name='room-delete'),
1516
path('rooms/<int:pk>/add-device/', RoomAddDeviceView.as_view(),name='room-add-device'),

app/campaign/views.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212

1313
from .models import Campaign, Room
14-
from .forms import CampaignForm, CampaignUserForm, RoomDeviceForm
14+
from .forms import CampaignForm, CampaignUserForm, RoomDeviceForm, UserDeviceForm
1515
from accounts.models import CustomUser
1616
from main.enums import Dimension, SensorModel
1717

@@ -442,3 +442,28 @@ def dispatch(self, request, *args, **kwargs):
442442

443443
def get_success_url(self):
444444
return reverse_lazy('campaigns-detail', kwargs={'pk': self.campaign.pk})
445+
446+
447+
class ParticipantsAddDevicesView(LoginRequiredMixin, UpdateView):
448+
model = CustomUser
449+
form_class = UserDeviceForm
450+
template_name = 'campaigns/participants/add_device.html'
451+
452+
def get_success_url(self):
453+
return reverse_lazy('campaigns-detail', kwargs={'pk': self.campaign.pk})
454+
455+
def dispatch(self, request, *args, **kwargs):
456+
self.campaign = Campaign.objects.get(pk=kwargs['campaign_pk'])
457+
458+
if self.request.user.is_superuser:
459+
return super().dispatch(request, *args, **kwargs)
460+
if self.request.user != self.campaign.owner:
461+
raise PermissionDenied("You are not allowed to create a Room")
462+
463+
return super().dispatch(request, *args, **kwargs)
464+
465+
def get_initial(self):
466+
initial = super().get_initial()
467+
initial['campaign'] = self.campaign
468+
initial['user'] = self.object
469+
return initial
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Generated by Django 5.1.2 on 2025-01-21 09:28
2+
3+
import django.db.models.deletion
4+
from django.conf import settings
5+
from django.db import migrations, models
6+
7+
8+
class Migration(migrations.Migration):
9+
10+
dependencies = [
11+
('campaign', '0009_remove_organization_owner_remove_organization_users_and_more'),
12+
('devices', '0012_alter_device_current_organization'),
13+
('organizations', '0001_initial'),
14+
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
15+
]
16+
17+
operations = [
18+
migrations.AddField(
19+
model_name='device',
20+
name='current_user',
21+
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='current_devices', to=settings.AUTH_USER_MODEL),
22+
),
23+
migrations.AddField(
24+
model_name='measurement',
25+
name='user',
26+
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='measurements', to=settings.AUTH_USER_MODEL),
27+
),
28+
migrations.AlterField(
29+
model_name='device',
30+
name='current_organization',
31+
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='current_devices', to='organizations.organization'),
32+
),
33+
migrations.AlterField(
34+
model_name='device',
35+
name='current_room',
36+
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='current_devices', to='campaign.room'),
37+
),
38+
]

app/devices/models.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from django.utils import timezone
33
from organizations.models import Organization
44
from campaign.models import Room
5+
from accounts.models import CustomUser
56

67

78
class Device(models.Model):
@@ -16,8 +17,9 @@ class Device(models.Model):
1617
last_update = models.DateTimeField(null=True, blank=True)
1718
notes = models.TextField(null=True, blank=True)
1819
api_key = models.CharField(max_length=64, null=True)
19-
current_room = models.ForeignKey(Room, on_delete=models.CASCADE, related_name='current_devices', null=True)
20-
current_organization = models.ForeignKey(Organization, on_delete=models.CASCADE, related_name='current_devices', null=True)
20+
current_room = models.ForeignKey(Room, related_name='current_devices', null=True, on_delete=models.SET_NULL)
21+
current_organization = models.ForeignKey(Organization, related_name='current_devices', null=True, on_delete=models.SET_NULL)
22+
current_user = models.ForeignKey(CustomUser, null=True, related_name='current_devices', on_delete=models.SET_NULL)
2123

2224
def __str__(self):
2325
return self.id or "Undefined Device" # Added fallback for undefined IDs
@@ -80,6 +82,7 @@ class Measurement(models.Model):
8082
sensor_model = models.IntegerField()
8183
device = models.ForeignKey(Device, on_delete=models.CASCADE, related_name='measurements')
8284
room = models.ForeignKey(Room, on_delete=models.CASCADE, null=True, related_name='measurements')
85+
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, null=True, related_name='measurements')
8386

8487
def __str__(self):
8588
return f'Measurement {self.id} from Device {self.device.id}'

app/main/util.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from devices.models import Device, DeviceStatus
55

6-
def get_or_create_station(station_info: dict):
6+
def get_or_create_station(station_info: dict):
77
'''
88
station_info dict:
99
{
@@ -28,11 +28,9 @@ def get_or_create_station(station_info: dict):
2828
)
2929
if created:
3030
station.device_name = station_info['device']
31-
station.firmware = station_info['firmware']
32-
station.last_update = datetime.datetime.now(datetime.timezone.utc)
33-
station.api_key = station_info['apikey']
3431
station.model = station_info['model']
3532
station.firmware = station_info['firmware']
33+
station.api_key = station_info['apikey']
3634

3735
# add a new DeviceStatus
3836
station_status = DeviceStatus.objects.create(

app/templates/campaigns/detail.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ <h3 class="mb-0">{% trans "Participants" %}</h3>
9595
<td>{{ user.email }}</td>
9696
<td>
9797
<div class="text-end d-flex flex-column flex-md-row gap-2 justify-content-end">
98+
<a href="{% url 'user-add-device' campaign.pk user.pk %}" class="btn btn-outline-primary btn-sm">{% trans "Add Device" %}</a>
9899
<a href="{% url 'participants-detail' campaign.pk user.pk %}" class="btn btn-primary btn-sm">
99100
<i class="bi bi-eye"></i>
100101
<span class="d-none d-sm-inline">{% trans "Details" %}</span>

0 commit comments

Comments
 (0)