diff --git a/equipment_tracker/accounts/admin.py b/equipment_tracker/accounts/admin.py index 81a42c3..15220f8 100644 --- a/equipment_tracker/accounts/admin.py +++ b/equipment_tracker/accounts/admin.py @@ -6,6 +6,7 @@ from .models import CustomUser class CustomUserAdmin(UserAdmin): model = CustomUser + list_display = UserAdmin.list_display + ('is_technician',) admin.site.register(CustomUser, CustomUserAdmin) diff --git a/equipment_tracker/accounts/migrations/0002_customuser_is_technician.py b/equipment_tracker/accounts/migrations/0002_customuser_is_technician.py new file mode 100644 index 0000000..a0f81d9 --- /dev/null +++ b/equipment_tracker/accounts/migrations/0002_customuser_is_technician.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2023-11-13 10:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='customuser', + name='is_technician', + field=models.BooleanField(default=False), + ), + ] diff --git a/equipment_tracker/accounts/models.py b/equipment_tracker/accounts/models.py index cf14fa9..7aa0a26 100644 --- a/equipment_tracker/accounts/models.py +++ b/equipment_tracker/accounts/models.py @@ -37,6 +37,7 @@ class CustomUser(AbstractUser): # Password inherited from base user class # is_admin inherited from base user class is_active = models.BooleanField(default=False) + is_technician = models.BooleanField(default=False) avatar = models.ImageField(upload_to=_get_upload_to, null=True) @property @@ -65,11 +66,11 @@ def create_superuser(sender, **kwargs): print('Created admin account') superuser.save() - username = 'usertest1' + username = 'test-user-technician' email = os.getenv('DJANGO_ADMIN_EMAIL') password = os.getenv('DJANGO_ADMIN_PASSWORD') first_name = 'Test' - last_name = 'User' + last_name = 'Technician' if not User.objects.filter(username=username).exists(): # Create the superuser with is_active set to False @@ -78,5 +79,5 @@ def create_superuser(sender, **kwargs): # Activate the user user.is_active = True - print('Created debug user account') + print('Created debug technician account') user.save() diff --git a/equipment_tracker/accounts/permissions.py b/equipment_tracker/accounts/permissions.py new file mode 100644 index 0000000..8486605 --- /dev/null +++ b/equipment_tracker/accounts/permissions.py @@ -0,0 +1,11 @@ +from rest_framework.permissions import BasePermission + + +class IsTechnician(BasePermission): + message = "You must be a technician to perform this action." + + def has_permission(self, request, view): + return request.user.is_authenticated and request.user.is_technician + + def has_object_permission(self, request, view, obj): + return request.user.is_authenticated and request.user.is_technician diff --git a/equipment_tracker/config/settings.py b/equipment_tracker/config/settings.py index cc422ea..62e48dc 100644 --- a/equipment_tracker/config/settings.py +++ b/equipment_tracker/config/settings.py @@ -29,7 +29,6 @@ SECRET_KEY = str(os.getenv('SECRET_KEY')) # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -FRONTEND_DEBUG = True ALLOWED_HOSTS = ['*'] # CSRF_TRUSTED_ORIGINS = [] To-do: Specify URL to web frontend @@ -71,6 +70,7 @@ INSTALLED_APPS = [ 'drf_spectacular_sidecar', 'accounts', 'equipments', + 'equipment_groups', ] MIDDLEWARE = [ @@ -162,9 +162,6 @@ AUTH_USER_MODEL = 'accounts.CustomUser' DJOSER = { 'SEND_ACTIVATION_EMAIL': True, 'SEND_CONFIRMATION_EMAIL': True, - 'EMAIL': { - 'activation': 'config.email.ActivationEmail' - }, 'ACTIVATION_URL': 'activation/{uid}/{token}', 'USER_AUTHENTICATION_RULES': ['djoser.authentication.TokenAuthenticationRule'], 'SERIALIZERS': { @@ -210,11 +207,7 @@ USE_TZ = True DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' -DOMAIN = '' -if (FRONTEND_DEBUG): - DOMAIN = 'exp' -else: - DOMAIN = 'citctracker' +DOMAIN = 'CITC-Tracker.keannu1.duckdns.org' SITE_NAME = 'CITC Equipment Tracker' diff --git a/equipment_tracker/equipment_groups/__init__.py b/equipment_tracker/equipment_groups/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/equipment_tracker/equipment_groups/admin.py b/equipment_tracker/equipment_groups/admin.py new file mode 100644 index 0000000..6d19b5a --- /dev/null +++ b/equipment_tracker/equipment_groups/admin.py @@ -0,0 +1,9 @@ +from django.contrib import admin +from .models import EquipmentGroup +from simple_history.admin import SimpleHistoryAdmin + + +@admin.register(EquipmentGroup) +class EquipmentGroupAdmin(SimpleHistoryAdmin): + readonly_fields = ['status'] + list_display = ('name', 'status', 'date_added', 'last_updated') diff --git a/equipment_tracker/equipment_groups/apps.py b/equipment_tracker/equipment_groups/apps.py new file mode 100644 index 0000000..3992bc6 --- /dev/null +++ b/equipment_tracker/equipment_groups/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class EquipmentGroupsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'equipment_groups' diff --git a/equipment_tracker/equipment_groups/migrations/0001_initial.py b/equipment_tracker/equipment_groups/migrations/0001_initial.py new file mode 100644 index 0000000..dfa74f7 --- /dev/null +++ b/equipment_tracker/equipment_groups/migrations/0001_initial.py @@ -0,0 +1,53 @@ +# Generated by Django 4.2.7 on 2023-11-13 09:43 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import simple_history.models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('equipments', '0003_historicalequipment'), + ] + + operations = [ + migrations.CreateModel( + name='HistoricalEquipmentGroup', + fields=[ + ('id', models.BigIntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('remarks', models.TextField(max_length=512)), + ('date_added', models.DateTimeField(default=django.utils.timezone.now, editable=False)), + ('last_updated', models.DateTimeField(blank=True, editable=False)), + ('history_id', models.AutoField(primary_key=True, serialize=False)), + ('history_date', models.DateTimeField(db_index=True)), + ('history_change_reason', models.CharField(max_length=100, null=True)), + ('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)), + ('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'verbose_name': 'historical equipment group', + 'verbose_name_plural': 'historical equipment groups', + 'ordering': ('-history_date', '-history_id'), + 'get_latest_by': ('history_date', 'history_id'), + }, + bases=(simple_history.models.HistoricalChanges, models.Model), + ), + migrations.CreateModel( + name='EquipmentGroup', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('remarks', models.TextField(max_length=512)), + ('date_added', models.DateTimeField(default=django.utils.timezone.now, editable=False)), + ('last_updated', models.DateTimeField(auto_now=True)), + ('equipments', models.ManyToManyField(to='equipments.equipmentinstance')), + ], + ), + ] diff --git a/equipment_tracker/equipment_groups/migrations/__init__.py b/equipment_tracker/equipment_groups/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/equipment_tracker/equipment_groups/models.py b/equipment_tracker/equipment_groups/models.py new file mode 100644 index 0000000..87cde52 --- /dev/null +++ b/equipment_tracker/equipment_groups/models.py @@ -0,0 +1,40 @@ +from django.db import models +from django.utils.timezone import now +from simple_history.models import HistoricalRecords +from django.db.models.signals import post_migrate +from django.dispatch import receiver +from equipments.models import EquipmentInstance + + +class EquipmentGroup(models.Model): + name = models.CharField(max_length=200) + remarks = models.TextField(max_length=512) + date_added = models.DateTimeField(default=now, editable=False) + last_updated = models.DateTimeField(auto_now=True, editable=False) + equipments = models.ManyToManyField(EquipmentInstance) + history = HistoricalRecords() + + @property + def status(self): + if self.equipments.filter(status='Broken').exists(): + return 'Broken' + elif self.equipments.filter(status='Under Maintenance').exists(): + return 'Under Maintenance' + elif self.equipments.filter(status='Decomissioned').exists(): + return 'Decomissioned' + else: + return 'Working' + + def __str__(self): + return self.name + + +@receiver(post_migrate) +def create_superuser(sender, **kwargs): + if sender.name == 'equipment_groups': + PC = EquipmentInstance.objects.filter(id=1).first().id + KEYBOARD = EquipmentInstance.objects.filter(id=2).first().id + MOUSE = EquipmentInstance.objects.filter(id=3).first().id + GROUP, CREATED = EquipmentGroup.objects.get_or_create( + name="HP All-In-One PC Set", remarks="First PC set of citc tracker!") + GROUP.equipments.set([PC, KEYBOARD, MOUSE]) diff --git a/equipment_tracker/equipment_groups/tests.py b/equipment_tracker/equipment_groups/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/equipment_tracker/equipment_groups/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/equipment_tracker/equipment_groups/views.py b/equipment_tracker/equipment_groups/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/equipment_tracker/equipment_groups/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/equipment_tracker/equipments/admin.py b/equipment_tracker/equipments/admin.py index ae71d72..d099ead 100644 --- a/equipment_tracker/equipments/admin.py +++ b/equipment_tracker/equipments/admin.py @@ -2,5 +2,14 @@ from django.contrib import admin from simple_history.admin import SimpleHistoryAdmin from .models import Equipment, EquipmentInstance -admin.site.register(Equipment, SimpleHistoryAdmin) -admin.site.register(EquipmentInstance, SimpleHistoryAdmin) + +@admin.register(Equipment) +class EquipmentAdmin(SimpleHistoryAdmin): + readonly_fields = ('date_added', 'last_updated') + list_display = ('name', 'date_added', 'last_updated') + + +@admin.register(EquipmentInstance) +class EquipmentInstanceAdmin(SimpleHistoryAdmin): + list_display = ('equipment', 'status', 'remarks', + 'date_added', 'last_updated') diff --git a/equipment_tracker/equipments/models.py b/equipment_tracker/equipments/models.py index 937f3be..8c7730f 100644 --- a/equipment_tracker/equipments/models.py +++ b/equipment_tracker/equipments/models.py @@ -42,9 +42,13 @@ def create_superuser(sender, **kwargs): if sender.name == 'equipments': EQUIPMENT, CREATED = Equipment.objects.get_or_create( name="HP All-in-One PC", description="I5 6500 8GB RAM 1TB HDD") - if (CREATED): - print("Created sample equipment") EQUIPMENT_INSTANCE, CREATED = EquipmentInstance.objects.get_or_create( - equipment=EQUIPMENT, status="Working", remarks="First PC of USTP!") - if (CREATED): - print("Created sample equipment instance") + equipment=EQUIPMENT, status="Working", remarks="First PC of citc equipment tracker!") + EQUIPMENT, CREATED = Equipment.objects.get_or_create( + name="HP Keyboard", description="Generic Membrane Keyboard") + EQUIPMENT_INSTANCE, CREATED = EquipmentInstance.objects.get_or_create( + equipment=EQUIPMENT, status="Working", remarks="First keyboard of citc equipment tracker!") + EQUIPMENT, CREATED = Equipment.objects.get_or_create( + name="HP Mouse", description="Generic Mouse") + EQUIPMENT_INSTANCE, CREATED = EquipmentInstance.objects.get_or_create( + equipment=EQUIPMENT, status="Working", remarks="First mouse of citc equipment tracker!") diff --git a/equipment_tracker/equipments/serializers.py b/equipment_tracker/equipments/serializers.py index e8831a2..d331100 100644 --- a/equipment_tracker/equipments/serializers.py +++ b/equipment_tracker/equipments/serializers.py @@ -1,6 +1,8 @@ from rest_framework import serializers -from django.contrib.auth.models import User from .models import Equipment, EquipmentInstance +from drf_spectacular.utils import extend_schema_field +from drf_spectacular.types import OpenApiTypes +from accounts.models import CustomUser # -- Equipment Serializers @@ -31,6 +33,7 @@ class EquipmentSerializer(serializers.HyperlinkedModelSerializer): def get_history_user(self, obj): return obj.history_user.username if obj.history_user else None + @extend_schema_field(OpenApiTypes.STR) def get_last_updated_by(self, obj): return obj.history.first().history_user if obj.history.first().history_user else None @@ -47,6 +50,7 @@ class EquipmentLogsSerializer(serializers.HyperlinkedModelSerializer): read_only_fields = ('history_id', 'id', 'name', 'description', 'history_date', 'history_user') + @extend_schema_field(OpenApiTypes.STR) def get_history_user(self, obj): return obj.history_user.username if obj.history_user else None @@ -68,6 +72,7 @@ class EquipmentLogSerializer(serializers.HyperlinkedModelSerializer): read_only_fields = ('id', 'last_updated', 'date_added', 'last_updated_by', 'history') + @extend_schema_field(OpenApiTypes.STR) def get_last_updated_by(self, obj): return obj.history.first().history_user if obj.history.first().history_user else None @@ -106,9 +111,11 @@ class EquipmentInstanceSerializer(serializers.HyperlinkedModelSerializer): read_only_fields = ('id', 'last_updated', 'last_updated_by', 'date_added') + @extend_schema_field(OpenApiTypes.STR) def get_history_user(self, obj): return obj.history_user.username if obj.history_user else None + @extend_schema_field(OpenApiTypes.STR) def get_last_updated_by(self, obj): return obj.history.first().history_user if obj.history.first().history_user else None @@ -127,6 +134,7 @@ class EquipmentInstanceLogsSerializer(serializers.HyperlinkedModelSerializer): read_only_fields = ('history_id', 'id', 'equipment', 'status', 'remarks', 'history_date', 'history_user') + @extend_schema_field(OpenApiTypes.STR) def get_history_user(self, obj): return obj.history_user.username if obj.history_user else None @@ -156,5 +164,6 @@ class EquipmentInstanceLogSerializer(serializers.HyperlinkedModelSerializer): read_only_fields = ('id', 'last_updated', 'date_added', 'last_updated_by', 'history') + @extend_schema_field(OpenApiTypes.STR) def get_last_updated_by(self, obj): return obj.history.first().history_user if obj.history.first().history_user else None diff --git a/equipment_tracker/equipments/views.py b/equipment_tracker/equipments/views.py index b97306d..a0adb45 100644 --- a/equipment_tracker/equipments/views.py +++ b/equipment_tracker/equipments/views.py @@ -3,13 +3,14 @@ from rest_framework import viewsets, generics from .models import Equipment, EquipmentInstance from . import serializers from config.settings import DEBUG +from accounts.permissions import IsTechnician # -- Equipment Viewsets class EquipmentViewSet(viewsets.ModelViewSet): if (not DEBUG): - permission_classes = [IsAuthenticated] + permission_classes = [IsAuthenticated, IsTechnician] serializer_class = serializers.EquipmentSerializer queryset = Equipment.objects.all().order_by('-date_added') @@ -18,7 +19,7 @@ class EquipmentViewSet(viewsets.ModelViewSet): class EquipmentsLogsViewSet(generics.ListAPIView): if (not DEBUG): - permission_classes = [IsAuthenticated] + permission_classes = [IsAuthenticated, IsTechnician] serializer_class = serializers.EquipmentLogsSerializer queryset = Equipment.history.all().order_by('-history_date') @@ -27,7 +28,7 @@ class EquipmentsLogsViewSet(generics.ListAPIView): class EquipmentLogViewSet(viewsets.ReadOnlyModelViewSet): if (not DEBUG): - permission_classes = [IsAuthenticated] + permission_classes = [IsAuthenticated, IsTechnician] serializer_class = serializers.EquipmentLogSerializer def get_queryset(self): @@ -39,7 +40,7 @@ class EquipmentLogViewSet(viewsets.ReadOnlyModelViewSet): class LastUpdatedEquipmentViewSet(generics.ListAPIView): if (not DEBUG): - permission_classes = [IsAuthenticated] + permission_classes = [IsAuthenticated, IsTechnician] serializer_class = serializers.EquipmentSerializer queryset = Equipment.objects.all().order_by('-date_added') @@ -51,7 +52,7 @@ class LastUpdatedEquipmentViewSet(generics.ListAPIView): class EquipmentInstanceViewSet(viewsets.ModelViewSet): if (not DEBUG): - permission_classes = [IsAuthenticated] + permission_classes = [IsAuthenticated, IsTechnician] serializer_class = serializers.EquipmentInstanceSerializer queryset = EquipmentInstance.objects.all().order_by('-date_added') @@ -60,7 +61,7 @@ class EquipmentInstanceViewSet(viewsets.ModelViewSet): class EquipmentInstancesLogsViewSet(generics.ListAPIView): if (not DEBUG): - permission_classes = [IsAuthenticated] + permission_classes = [IsAuthenticated, IsTechnician] serializer_class = serializers.EquipmentInstanceLogsSerializer queryset = EquipmentInstance.history.all().order_by('-history_date') @@ -69,7 +70,7 @@ class EquipmentInstancesLogsViewSet(generics.ListAPIView): class EquipmentInstanceLogViewSet(viewsets.ReadOnlyModelViewSet): if (not DEBUG): - permission_classes = [IsAuthenticated] + permission_classes = [IsAuthenticated, IsTechnician] serializer_class = serializers.EquipmentInstanceLogSerializer def get_queryset(self): @@ -81,7 +82,7 @@ class EquipmentInstanceLogViewSet(viewsets.ReadOnlyModelViewSet): class LastUpdatedEquipmentInstanceViewSet(generics.ListAPIView): if (not DEBUG): - permission_classes = [IsAuthenticated] + permission_classes = [IsAuthenticated, IsTechnician] serializer_class = serializers.EquipmentInstanceSerializer queryset = EquipmentInstance.objects.all().order_by('-date_added') diff --git a/equipment_tracker/schema.yml b/equipment_tracker/schema.yml index e9d73b7..b9dc8e5 100644 --- a/equipment_tracker/schema.yml +++ b/equipment_tracker/schema.yml @@ -997,7 +997,7 @@ components: equipment: type: integer status: - type: string + $ref: '#/components/schemas/StatusEnum' remarks: type: string last_updated: @@ -1062,6 +1062,11 @@ components: history_id: type: integer readOnly: true + id: + type: integer + readOnly: true + equipment: + type: integer status: allOf: - $ref: '#/components/schemas/StatusEnum' @@ -1077,9 +1082,11 @@ components: type: string readOnly: true required: + - equipment - history_date - history_id - history_user + - id - remarks - status EquipmentLog: @@ -1206,7 +1213,7 @@ components: equipment: type: integer status: - type: string + $ref: '#/components/schemas/StatusEnum' remarks: type: string last_updated: diff --git a/equipment_tracker/schema.yml1 b/equipment_tracker/schema.yml1 new file mode 100644 index 0000000..b9dc8e5 --- /dev/null +++ b/equipment_tracker/schema.yml1 @@ -0,0 +1,1359 @@ +openapi: 3.0.3 +info: + title: CITC Equipment Tracker Backend + version: 1.0.0 + description: An IT Elective 4 Project +paths: + /api/v1/accounts/jwt/create/: + post: + operationId: api_v1_accounts_jwt_create_create + description: |- + Takes a set of user credentials and returns an access and refresh JSON web + token pair to prove the authentication of those credentials. + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TokenObtainPair' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/TokenObtainPair' + multipart/form-data: + schema: + $ref: '#/components/schemas/TokenObtainPair' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TokenObtainPair' + description: '' + /api/v1/accounts/jwt/refresh/: + post: + operationId: api_v1_accounts_jwt_refresh_create + description: |- + Takes a refresh type JSON web token and returns an access type JSON web + token if the refresh token is valid. + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TokenRefresh' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/TokenRefresh' + multipart/form-data: + schema: + $ref: '#/components/schemas/TokenRefresh' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TokenRefresh' + description: '' + /api/v1/accounts/jwt/verify/: + post: + operationId: api_v1_accounts_jwt_verify_create + description: |- + Takes a token and indicates if it is valid. This view provides no + information about a token's fitness for a particular use. + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/TokenVerify' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/TokenVerify' + multipart/form-data: + schema: + $ref: '#/components/schemas/TokenVerify' + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/TokenVerify' + description: '' + /api/v1/accounts/users/: + get: + operationId: api_v1_accounts_users_list + tags: + - api + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/CustomUser' + description: '' + post: + operationId: api_v1_accounts_users_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserRegistration' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserRegistration' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserRegistration' + required: true + security: + - jwtAuth: [] + - {} + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/UserRegistration' + description: '' + /api/v1/accounts/users/{id}/: + get: + operationId: api_v1_accounts_users_retrieve + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this user. + required: true + tags: + - api + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + description: '' + put: + operationId: api_v1_accounts_users_update + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this user. + required: true + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/CustomUser' + multipart/form-data: + schema: + $ref: '#/components/schemas/CustomUser' + required: true + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + description: '' + patch: + operationId: api_v1_accounts_users_partial_update + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this user. + required: true + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedCustomUser' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedCustomUser' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedCustomUser' + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + description: '' + delete: + operationId: api_v1_accounts_users_destroy + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this user. + required: true + tags: + - api + security: + - jwtAuth: [] + responses: + '204': + description: No response body + /api/v1/accounts/users/activation/: + post: + operationId: api_v1_accounts_users_activation_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Activation' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/Activation' + multipart/form-data: + schema: + $ref: '#/components/schemas/Activation' + required: true + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Activation' + description: '' + /api/v1/accounts/users/me/: + get: + operationId: api_v1_accounts_users_me_retrieve + tags: + - api + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + description: '' + put: + operationId: api_v1_accounts_users_me_update + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/CustomUser' + multipart/form-data: + schema: + $ref: '#/components/schemas/CustomUser' + required: true + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + description: '' + patch: + operationId: api_v1_accounts_users_me_partial_update + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedCustomUser' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedCustomUser' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedCustomUser' + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/CustomUser' + description: '' + delete: + operationId: api_v1_accounts_users_me_destroy + tags: + - api + security: + - jwtAuth: [] + responses: + '204': + description: No response body + /api/v1/accounts/users/resend_activation/: + post: + operationId: api_v1_accounts_users_resend_activation_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SendEmailReset' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/SendEmailReset' + multipart/form-data: + schema: + $ref: '#/components/schemas/SendEmailReset' + required: true + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/SendEmailReset' + description: '' + /api/v1/accounts/users/reset_password/: + post: + operationId: api_v1_accounts_users_reset_password_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SendEmailReset' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/SendEmailReset' + multipart/form-data: + schema: + $ref: '#/components/schemas/SendEmailReset' + required: true + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/SendEmailReset' + description: '' + /api/v1/accounts/users/reset_password_confirm/: + post: + operationId: api_v1_accounts_users_reset_password_confirm_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PasswordResetConfirm' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PasswordResetConfirm' + multipart/form-data: + schema: + $ref: '#/components/schemas/PasswordResetConfirm' + required: true + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/PasswordResetConfirm' + description: '' + /api/v1/accounts/users/reset_username/: + post: + operationId: api_v1_accounts_users_reset_username_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SendEmailReset' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/SendEmailReset' + multipart/form-data: + schema: + $ref: '#/components/schemas/SendEmailReset' + required: true + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/SendEmailReset' + description: '' + /api/v1/accounts/users/reset_username_confirm/: + post: + operationId: api_v1_accounts_users_reset_username_confirm_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UsernameResetConfirm' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UsernameResetConfirm' + multipart/form-data: + schema: + $ref: '#/components/schemas/UsernameResetConfirm' + required: true + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/UsernameResetConfirm' + description: '' + /api/v1/accounts/users/set_password/: + post: + operationId: api_v1_accounts_users_set_password_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SetPassword' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/SetPassword' + multipart/form-data: + schema: + $ref: '#/components/schemas/SetPassword' + required: true + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/SetPassword' + description: '' + /api/v1/accounts/users/set_username/: + post: + operationId: api_v1_accounts_users_set_username_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SetUsername' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/SetUsername' + multipart/form-data: + schema: + $ref: '#/components/schemas/SetUsername' + required: true + security: + - jwtAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/SetUsername' + description: '' + /api/v1/equipments/equipment_instances/: + get: + operationId: api_v1_equipments_equipment_instances_list + tags: + - api + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/EquipmentInstance' + description: '' + post: + operationId: api_v1_equipments_equipment_instances_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/EquipmentInstance' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/EquipmentInstance' + multipart/form-data: + schema: + $ref: '#/components/schemas/EquipmentInstance' + required: true + security: + - jwtAuth: [] + - {} + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/EquipmentInstance' + description: '' + /api/v1/equipments/equipment_instances/{equipment_id}/logs/: + get: + operationId: api_v1_equipments_equipment_instances_logs_list_2 + parameters: + - in: path + name: equipment_id + schema: + type: integer + required: true + tags: + - api + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/EquipmentInstanceLog' + description: '' + /api/v1/equipments/equipment_instances/{id}/: + get: + operationId: api_v1_equipments_equipment_instances_retrieve + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this equipment instance. + required: true + tags: + - api + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EquipmentInstance' + description: '' + put: + operationId: api_v1_equipments_equipment_instances_update + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this equipment instance. + required: true + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/EquipmentInstance' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/EquipmentInstance' + multipart/form-data: + schema: + $ref: '#/components/schemas/EquipmentInstance' + required: true + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EquipmentInstance' + description: '' + patch: + operationId: api_v1_equipments_equipment_instances_partial_update + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this equipment instance. + required: true + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedEquipmentInstance' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedEquipmentInstance' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedEquipmentInstance' + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EquipmentInstance' + description: '' + delete: + operationId: api_v1_equipments_equipment_instances_destroy + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this equipment instance. + required: true + tags: + - api + security: + - jwtAuth: [] + - {} + responses: + '204': + description: No response body + /api/v1/equipments/equipment_instances/latest: + get: + operationId: api_v1_equipments_equipment_instances_latest_list + tags: + - api + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/EquipmentInstance' + description: '' + /api/v1/equipments/equipment_instances/logs: + get: + operationId: api_v1_equipments_equipment_instances_logs_list + tags: + - api + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/EquipmentInstanceLogs' + description: '' + /api/v1/equipments/equipments/: + get: + operationId: api_v1_equipments_equipments_list + tags: + - api + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Equipment' + description: '' + post: + operationId: api_v1_equipments_equipments_create + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Equipment' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/Equipment' + multipart/form-data: + schema: + $ref: '#/components/schemas/Equipment' + required: true + security: + - jwtAuth: [] + - {} + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/Equipment' + description: '' + /api/v1/equipments/equipments/{equipment_id}/logs/: + get: + operationId: api_v1_equipments_equipments_logs_list_2 + parameters: + - in: path + name: equipment_id + schema: + type: integer + required: true + tags: + - api + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/EquipmentLog' + description: '' + /api/v1/equipments/equipments/{id}/: + get: + operationId: api_v1_equipments_equipments_retrieve + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this equipment. + required: true + tags: + - api + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Equipment' + description: '' + put: + operationId: api_v1_equipments_equipments_update + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this equipment. + required: true + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Equipment' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/Equipment' + multipart/form-data: + schema: + $ref: '#/components/schemas/Equipment' + required: true + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Equipment' + description: '' + patch: + operationId: api_v1_equipments_equipments_partial_update + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this equipment. + required: true + tags: + - api + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedEquipment' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedEquipment' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedEquipment' + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Equipment' + description: '' + delete: + operationId: api_v1_equipments_equipments_destroy + parameters: + - in: path + name: id + schema: + type: integer + description: A unique integer value identifying this equipment. + required: true + tags: + - api + security: + - jwtAuth: [] + - {} + responses: + '204': + description: No response body + /api/v1/equipments/equipments/latest: + get: + operationId: api_v1_equipments_equipments_latest_list + tags: + - api + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Equipment' + description: '' + /api/v1/equipments/equipments/logs: + get: + operationId: api_v1_equipments_equipments_logs_list + tags: + - api + security: + - jwtAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/EquipmentLogs' + description: '' +components: + schemas: + Activation: + type: object + properties: + uid: + type: string + token: + type: string + required: + - token + - uid + CustomUser: + type: object + properties: + username: + type: string + readOnly: true + description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_ + only. + email: + type: string + format: email + title: Email address + maxLength: 254 + avatar: + type: string + format: uri + first_name: + type: string + maxLength: 100 + last_name: + type: string + maxLength: 100 + required: + - avatar + - first_name + - last_name + - username + Equipment: + type: object + properties: + id: + type: integer + readOnly: true + name: + type: string + description: + type: string + last_updated: + type: string + format: date-time + readOnly: true + last_updated_by: + type: string + readOnly: true + date_added: + type: string + format: date-time + readOnly: true + required: + - date_added + - description + - id + - last_updated + - last_updated_by + - name + EquipmentInstance: + type: object + properties: + id: + type: integer + readOnly: true + equipment: + type: integer + status: + $ref: '#/components/schemas/StatusEnum' + remarks: + type: string + last_updated: + type: string + format: date-time + readOnly: true + last_updated_by: + type: string + readOnly: true + date_added: + type: string + format: date-time + readOnly: true + required: + - date_added + - equipment + - id + - last_updated + - last_updated_by + - remarks + - status + EquipmentInstanceLog: + type: object + properties: + id: + type: integer + readOnly: true + equipment: + type: integer + status: + type: string + remarks: + type: string + last_updated: + type: string + format: date-time + readOnly: true + date_added: + type: string + format: date-time + readOnly: true + last_updated_by: + type: string + readOnly: true + history: + type: array + items: + type: object + additionalProperties: {} + required: + - date_added + - equipment + - history + - id + - last_updated + - last_updated_by + - remarks + - status + EquipmentInstanceLogs: + type: object + properties: + history_id: + type: integer + readOnly: true + id: + type: integer + readOnly: true + equipment: + type: integer + status: + allOf: + - $ref: '#/components/schemas/StatusEnum' + readOnly: true + remarks: + type: string + readOnly: true + history_date: + type: string + format: date-time + readOnly: true + history_user: + type: string + readOnly: true + required: + - equipment + - history_date + - history_id + - history_user + - id + - remarks + - status + EquipmentLog: + type: object + properties: + id: + type: integer + readOnly: true + name: + type: string + description: + type: string + last_updated: + type: string + format: date-time + readOnly: true + date_added: + type: string + format: date-time + readOnly: true + last_updated_by: + type: string + readOnly: true + history: + type: array + items: + type: object + additionalProperties: {} + required: + - date_added + - description + - history + - id + - last_updated + - last_updated_by + - name + EquipmentLogs: + type: object + properties: + history_id: + type: integer + readOnly: true + name: + type: string + readOnly: true + description: + type: string + readOnly: true + history_date: + type: string + format: date-time + readOnly: true + history_user: + type: string + readOnly: true + required: + - description + - history_date + - history_id + - history_user + - name + PasswordResetConfirm: + type: object + properties: + uid: + type: string + token: + type: string + new_password: + type: string + required: + - new_password + - token + - uid + PatchedCustomUser: + type: object + properties: + username: + type: string + readOnly: true + description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_ + only. + email: + type: string + format: email + title: Email address + maxLength: 254 + avatar: + type: string + format: uri + first_name: + type: string + maxLength: 100 + last_name: + type: string + maxLength: 100 + PatchedEquipment: + type: object + properties: + id: + type: integer + readOnly: true + name: + type: string + description: + type: string + last_updated: + type: string + format: date-time + readOnly: true + last_updated_by: + type: string + readOnly: true + date_added: + type: string + format: date-time + readOnly: true + PatchedEquipmentInstance: + type: object + properties: + id: + type: integer + readOnly: true + equipment: + type: integer + status: + $ref: '#/components/schemas/StatusEnum' + remarks: + type: string + last_updated: + type: string + format: date-time + readOnly: true + last_updated_by: + type: string + readOnly: true + date_added: + type: string + format: date-time + readOnly: true + SendEmailReset: + type: object + properties: + email: + type: string + format: email + required: + - email + SetPassword: + type: object + properties: + new_password: + type: string + current_password: + type: string + required: + - current_password + - new_password + SetUsername: + type: object + properties: + current_password: + type: string + new_username: + type: string + title: Username + description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_ + only. + pattern: ^[\w.@+-]+$ + maxLength: 150 + required: + - current_password + - new_username + StatusEnum: + enum: + - Working + - Broken + - Under Maintenance + - Decomissioned + type: string + description: "* `Working` - Working\n* `Broken` - Broken\n* `Under Maintenance`\ + \ - Under Maintenance\n* `Decomissioned` - Decomissioned " + TokenObtainPair: + type: object + properties: + username: + type: string + writeOnly: true + password: + type: string + writeOnly: true + access: + type: string + readOnly: true + refresh: + type: string + readOnly: true + required: + - access + - password + - refresh + - username + TokenRefresh: + type: object + properties: + access: + type: string + readOnly: true + refresh: + type: string + writeOnly: true + required: + - access + - refresh + TokenVerify: + type: object + properties: + token: + type: string + writeOnly: true + required: + - token + UserRegistration: + type: object + properties: + username: + type: string + description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_ + only. + pattern: ^[\w.@+-]+$ + maxLength: 150 + email: + type: string + format: email + password: + type: string + writeOnly: true + avatar: + type: string + format: uri + nullable: true + first_name: + type: string + maxLength: 100 + last_name: + type: string + maxLength: 100 + required: + - email + - first_name + - last_name + - password + - username + UsernameResetConfirm: + type: object + properties: + new_username: + type: string + title: Username + description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_ + only. + pattern: ^[\w.@+-]+$ + maxLength: 150 + required: + - new_username + securitySchemes: + jwtAuth: + type: http + scheme: bearer + bearerFormat: JWT