Compare commits
3 commits
16ac2fa024
...
3c9fbc16dd
Author | SHA1 | Date | |
---|---|---|---|
3c9fbc16dd | |||
1fecad329e | |||
c8f7456d60 |
9 changed files with 139 additions and 110 deletions
|
@ -1 +1,3 @@
|
||||||
ansible-playbook deploy/ansible/playbooks/deploy-c3lf-sys3.yml --inventory=deploy/ansible/inventory.yml
|
ansible-playbook deploy/ansible/playbooks/deploy-c3lf-sys3.yml --inventory=deploy/ansible/inventory.yml
|
||||||
|
|
||||||
|
ssh root@andromeda.lab.or.it -A -L8080:localhost:11334
|
|
@ -6,13 +6,7 @@ from rest_framework.response import Response
|
||||||
|
|
||||||
from files.models import File
|
from files.models import File
|
||||||
from inventory.models import Event, Container, Item
|
from inventory.models import Event, Container, Item
|
||||||
|
from inventory.serializers import EventSerializer, ContainerSerializer
|
||||||
|
|
||||||
class EventSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Event
|
|
||||||
fields = ['eid', 'slug', 'name', 'start', 'end', 'pre_start', 'post_end']
|
|
||||||
read_only_fields = ['eid']
|
|
||||||
|
|
||||||
|
|
||||||
class EventViewSet(viewsets.ModelViewSet):
|
class EventViewSet(viewsets.ModelViewSet):
|
||||||
|
@ -22,18 +16,6 @@ class EventViewSet(viewsets.ModelViewSet):
|
||||||
authentication_classes = []
|
authentication_classes = []
|
||||||
|
|
||||||
|
|
||||||
class ContainerSerializer(serializers.ModelSerializer):
|
|
||||||
itemCount = serializers.SerializerMethodField()
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Container
|
|
||||||
fields = ['cid', 'name', 'itemCount']
|
|
||||||
read_only_fields = ['cid', 'itemCount']
|
|
||||||
|
|
||||||
def get_itemCount(self, instance):
|
|
||||||
return Item.objects.filter(container=instance.cid).count()
|
|
||||||
|
|
||||||
|
|
||||||
class ContainerViewSet(viewsets.ModelViewSet):
|
class ContainerViewSet(viewsets.ModelViewSet):
|
||||||
serializer_class = ContainerSerializer
|
serializer_class = ContainerSerializer
|
||||||
queryset = Container.objects.all()
|
queryset = Container.objects.all()
|
||||||
|
|
|
@ -1,20 +1,12 @@
|
||||||
from django.utils import timezone
|
from django.urls import path
|
||||||
from django.urls import path, re_path
|
|
||||||
from django.contrib.auth.decorators import permission_required
|
from django.contrib.auth.decorators import permission_required
|
||||||
from rest_framework import routers, viewsets, serializers
|
from rest_framework import routers, viewsets
|
||||||
from rest_framework.decorators import api_view, permission_classes
|
from rest_framework.decorators import api_view, permission_classes
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
|
||||||
from files.models import File
|
|
||||||
from inventory.models import Event, Container, Item
|
from inventory.models import Event, Container, Item
|
||||||
|
from inventory.serializers import EventSerializer, ContainerSerializer, ItemSerializer
|
||||||
|
|
||||||
class EventSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Event
|
|
||||||
fields = ['eid', 'slug', 'name', 'start', 'end', 'pre_start', 'post_end']
|
|
||||||
read_only_fields = ['eid']
|
|
||||||
|
|
||||||
|
|
||||||
class EventViewSet(viewsets.ModelViewSet):
|
class EventViewSet(viewsets.ModelViewSet):
|
||||||
|
@ -23,87 +15,11 @@ class EventViewSet(viewsets.ModelViewSet):
|
||||||
permission_classes = []
|
permission_classes = []
|
||||||
|
|
||||||
|
|
||||||
class ContainerSerializer(serializers.ModelSerializer):
|
|
||||||
itemCount = serializers.SerializerMethodField()
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Container
|
|
||||||
fields = ['cid', 'name', 'itemCount']
|
|
||||||
read_only_fields = ['cid', 'itemCount']
|
|
||||||
|
|
||||||
def get_itemCount(self, instance):
|
|
||||||
return Item.objects.filter(container=instance.cid).count()
|
|
||||||
|
|
||||||
|
|
||||||
class ContainerViewSet(viewsets.ModelViewSet):
|
class ContainerViewSet(viewsets.ModelViewSet):
|
||||||
serializer_class = ContainerSerializer
|
serializer_class = ContainerSerializer
|
||||||
queryset = Container.objects.all()
|
queryset = Container.objects.all()
|
||||||
|
|
||||||
|
|
||||||
class ItemSerializer(serializers.ModelSerializer):
|
|
||||||
dataImage = serializers.CharField(write_only=True, required=False)
|
|
||||||
cid = serializers.SerializerMethodField()
|
|
||||||
box = serializers.SerializerMethodField()
|
|
||||||
file = serializers.SerializerMethodField()
|
|
||||||
returned = serializers.SerializerMethodField(required=False)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Item
|
|
||||||
fields = ['cid', 'box', 'uid', 'description', 'file', 'dataImage', 'returned']
|
|
||||||
read_only_fields = ['uid']
|
|
||||||
|
|
||||||
def get_cid(self, instance):
|
|
||||||
return instance.container.cid
|
|
||||||
|
|
||||||
def get_box(self, instance):
|
|
||||||
return instance.container.name
|
|
||||||
|
|
||||||
def get_file(self, instance):
|
|
||||||
if len(instance.files.all()) > 0:
|
|
||||||
return instance.files.all().order_by('-created_at')[0].hash
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_returned(self, instance):
|
|
||||||
return instance.returned_at is not None
|
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
|
||||||
container = None
|
|
||||||
returned = False
|
|
||||||
if 'cid' in data:
|
|
||||||
container = Container.objects.get(cid=data['cid'])
|
|
||||||
if 'returned' in data:
|
|
||||||
returned = data['returned']
|
|
||||||
internal = super().to_internal_value(data)
|
|
||||||
if container:
|
|
||||||
internal['container'] = container
|
|
||||||
if returned:
|
|
||||||
internal['returned_at'] = timezone.now()
|
|
||||||
return internal
|
|
||||||
|
|
||||||
def validate(self, attrs):
|
|
||||||
return super().validate(attrs)
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
if 'dataImage' in validated_data:
|
|
||||||
file = File.objects.create(data=validated_data['dataImage'])
|
|
||||||
validated_data.pop('dataImage')
|
|
||||||
item = Item.objects.create(**validated_data)
|
|
||||||
item.files.set([file])
|
|
||||||
return item
|
|
||||||
return Item.objects.create(**validated_data)
|
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
|
||||||
if 'returned' in validated_data:
|
|
||||||
if validated_data['returned']:
|
|
||||||
validated_data['returned_at'] = timezone.now()
|
|
||||||
validated_data.pop('returned')
|
|
||||||
if 'dataImage' in validated_data:
|
|
||||||
file = File.objects.create(data=validated_data['dataImage'])
|
|
||||||
validated_data.pop('dataImage')
|
|
||||||
instance.files.add(file)
|
|
||||||
return super().update(instance, validated_data)
|
|
||||||
|
|
||||||
|
|
||||||
@api_view(['GET'])
|
@api_view(['GET'])
|
||||||
@permission_classes([IsAuthenticated])
|
@permission_classes([IsAuthenticated])
|
||||||
@permission_required('view_item', raise_exception=True)
|
@permission_required('view_item', raise_exception=True)
|
||||||
|
|
88
core/inventory/serializers.py
Normal file
88
core/inventory/serializers.py
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
from django.utils import timezone
|
||||||
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from files.models import File
|
||||||
|
from inventory.models import Event, Container, Item
|
||||||
|
|
||||||
|
|
||||||
|
class EventSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = Event
|
||||||
|
fields = ['eid', 'slug', 'name', 'start', 'end', 'pre_start', 'post_end']
|
||||||
|
read_only_fields = ['eid']
|
||||||
|
|
||||||
|
|
||||||
|
class ContainerSerializer(serializers.ModelSerializer):
|
||||||
|
itemCount = serializers.SerializerMethodField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Container
|
||||||
|
fields = ['cid', 'name', 'itemCount']
|
||||||
|
read_only_fields = ['cid', 'itemCount']
|
||||||
|
|
||||||
|
def get_itemCount(self, instance):
|
||||||
|
return Item.objects.filter(container=instance.cid).count()
|
||||||
|
|
||||||
|
|
||||||
|
class ItemSerializer(serializers.ModelSerializer):
|
||||||
|
dataImage = serializers.CharField(write_only=True, required=False)
|
||||||
|
cid = serializers.SerializerMethodField()
|
||||||
|
box = serializers.SerializerMethodField()
|
||||||
|
file = serializers.SerializerMethodField()
|
||||||
|
returned = serializers.SerializerMethodField(required=False)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Item
|
||||||
|
fields = ['cid', 'box', 'uid', 'description', 'file', 'dataImage', 'returned']
|
||||||
|
read_only_fields = ['uid']
|
||||||
|
|
||||||
|
def get_cid(self, instance):
|
||||||
|
return instance.container.cid
|
||||||
|
|
||||||
|
def get_box(self, instance):
|
||||||
|
return instance.container.name
|
||||||
|
|
||||||
|
def get_file(self, instance):
|
||||||
|
if len(instance.files.all()) > 0:
|
||||||
|
return instance.files.all().order_by('-created_at')[0].hash
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_returned(self, instance):
|
||||||
|
return instance.returned_at is not None
|
||||||
|
|
||||||
|
def to_internal_value(self, data):
|
||||||
|
container = None
|
||||||
|
returned = False
|
||||||
|
if 'cid' in data:
|
||||||
|
container = Container.objects.get(cid=data['cid'])
|
||||||
|
if 'returned' in data:
|
||||||
|
returned = data['returned']
|
||||||
|
internal = super().to_internal_value(data)
|
||||||
|
if container:
|
||||||
|
internal['container'] = container
|
||||||
|
if returned:
|
||||||
|
internal['returned_at'] = timezone.now()
|
||||||
|
return internal
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
return super().validate(attrs)
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
if 'dataImage' in validated_data:
|
||||||
|
file = File.objects.create(data=validated_data['dataImage'])
|
||||||
|
validated_data.pop('dataImage')
|
||||||
|
item = Item.objects.create(**validated_data)
|
||||||
|
item.files.set([file])
|
||||||
|
return item
|
||||||
|
return Item.objects.create(**validated_data)
|
||||||
|
|
||||||
|
def update(self, instance, validated_data):
|
||||||
|
if 'returned' in validated_data:
|
||||||
|
if validated_data['returned']:
|
||||||
|
validated_data['returned_at'] = timezone.now()
|
||||||
|
validated_data.pop('returned')
|
||||||
|
if 'dataImage' in validated_data:
|
||||||
|
file = File.objects.create(data=validated_data['dataImage'])
|
||||||
|
validated_data.pop('dataImage')
|
||||||
|
instance.files.add(file)
|
||||||
|
return super().update(instance, validated_data)
|
19
core/tickets/migrations/0011_issuethread_related_items.py
Normal file
19
core/tickets/migrations/0011_issuethread_related_items.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 4.2.7 on 2024-06-14 17:48
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('inventory', '0004_alter_event_created_at_alter_item_created_at'),
|
||||||
|
('tickets', '0010_itemrelation'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='issuethread',
|
||||||
|
name='related_items',
|
||||||
|
field=models.ManyToManyField(through='tickets.ItemRelation', to='inventory.item'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -42,6 +42,7 @@ class IssueThread(SoftDeleteModel):
|
||||||
name = models.CharField(max_length=255)
|
name = models.CharField(max_length=255)
|
||||||
event = models.ForeignKey(Event, null=True, on_delete=models.SET_NULL, related_name='issue_threads')
|
event = models.ForeignKey(Event, null=True, on_delete=models.SET_NULL, related_name='issue_threads')
|
||||||
manually_created = models.BooleanField(default=False)
|
manually_created = models.BooleanField(default=False)
|
||||||
|
related_items = models.ManyToManyField(Item, through='ItemRelation')
|
||||||
|
|
||||||
def short_uuid(self):
|
def short_uuid(self):
|
||||||
return self.uuid[:8]
|
return self.uuid[:8]
|
||||||
|
|
|
@ -3,6 +3,7 @@ from rest_framework import serializers
|
||||||
from authentication.models import ExtendedUser
|
from authentication.models import ExtendedUser
|
||||||
from mail.api_v2 import AttachmentSerializer
|
from mail.api_v2 import AttachmentSerializer
|
||||||
from tickets.models import IssueThread, Comment, STATE_CHOICES
|
from tickets.models import IssueThread, Comment, STATE_CHOICES
|
||||||
|
from inventory.serializers import ItemSerializer
|
||||||
|
|
||||||
|
|
||||||
class CommentSerializer(serializers.ModelSerializer):
|
class CommentSerializer(serializers.ModelSerializer):
|
||||||
|
@ -33,18 +34,19 @@ class IssueSerializer(serializers.ModelSerializer):
|
||||||
last_activity = serializers.SerializerMethodField()
|
last_activity = serializers.SerializerMethodField()
|
||||||
assigned_to = serializers.SlugRelatedField(slug_field='username', queryset=ExtendedUser.objects.all(),
|
assigned_to = serializers.SlugRelatedField(slug_field='username', queryset=ExtendedUser.objects.all(),
|
||||||
allow_null=True, required=False)
|
allow_null=True, required=False)
|
||||||
|
related_items = ItemSerializer(many=True, read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IssueThread
|
model = IssueThread
|
||||||
fields = ('id', 'timeline', 'name', 'state', 'assigned_to', 'last_activity', 'uuid')
|
fields = ('id', 'timeline', 'name', 'state', 'assigned_to', 'last_activity', 'uuid', 'related_items')
|
||||||
read_only_fields = ('id', 'timeline', 'last_activity', 'uuid')
|
read_only_fields = ('id', 'timeline', 'last_activity', 'uuid', 'related_items')
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
ret = super().to_internal_value(data)
|
ret = super().to_internal_value(data)
|
||||||
if 'state' in data:
|
if 'state' in data:
|
||||||
ret['state'] = data['state']
|
ret['state'] = data['state']
|
||||||
# if 'assigned_to' in data:
|
# if 'assigned_to' in data:
|
||||||
# ret['assigned_to'] = data['assigned_to']
|
# ret['assigned_to'] = data['assigned_to']
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
|
|
|
@ -11,6 +11,11 @@
|
||||||
name: postfix
|
name: postfix
|
||||||
state: restarted
|
state: restarted
|
||||||
|
|
||||||
|
- name: restart rspamd
|
||||||
|
service:
|
||||||
|
name: rspamd
|
||||||
|
state: restarted
|
||||||
|
|
||||||
- name: restart mariadb
|
- name: restart mariadb
|
||||||
service:
|
service:
|
||||||
name: mariadb
|
name: mariadb
|
||||||
|
@ -82,6 +87,7 @@
|
||||||
- default-libmysqlclient-dev
|
- default-libmysqlclient-dev
|
||||||
- build-essential
|
- build-essential
|
||||||
- postfix
|
- postfix
|
||||||
|
- rspamd
|
||||||
- git
|
- git
|
||||||
- pkg-config
|
- pkg-config
|
||||||
- npm
|
- npm
|
||||||
|
@ -339,6 +345,16 @@
|
||||||
notify:
|
notify:
|
||||||
- restart postfix
|
- restart postfix
|
||||||
|
|
||||||
|
- name: configure rspamd
|
||||||
|
copy:
|
||||||
|
content: |
|
||||||
|
write_servers = "localhost";
|
||||||
|
read_servers = "localhost";
|
||||||
|
dest: /etc/rspamd/local.d/redis.conf
|
||||||
|
notify:
|
||||||
|
- restart rspamd
|
||||||
|
|
||||||
|
|
||||||
- name: UFW allow smtp
|
- name: UFW allow smtp
|
||||||
ufw:
|
ufw:
|
||||||
rule: allow
|
rule: allow
|
||||||
|
|
|
@ -48,3 +48,6 @@ maillog_file = /var/log/mail.log
|
||||||
|
|
||||||
virtual_mailbox_domains = {{ mail_domain }}
|
virtual_mailbox_domains = {{ mail_domain }}
|
||||||
virtual_transport=c3lf-sys3:unix:/var/www/c3lf-sys3/lmtp.sock
|
virtual_transport=c3lf-sys3:unix:/var/www/c3lf-sys3/lmtp.sock
|
||||||
|
|
||||||
|
smtpd_milters = inet:localhost:11332
|
||||||
|
milter_default_action = accept
|
Loading…
Reference in a new issue