Skip to content

Commit

Permalink
GAD-4: FTS SDK
Browse files Browse the repository at this point in the history
* fix requirements and docker-compose

* fix docker compose and dependencies

* add sdk and api folder structure

* add sdk methods and fix some urls

* update models for API

* add urls for api

* add methods for viewing file, inbox, outbox, getting designation with serializers and minor bug fixes

* fix serializers and fix file attachment functionality in forward_file

* sync with upstream

* add views and fix urls

* create file

* create file change

* fix create_file, without upload_file feature

* fix sdk forward_file : accept remarks

* add view_history in sdk

* add blueprint for draft and archive methods to sdk

* fix FileHeaderSerializer to include id

* fix empty file upload error

* fix inbox outbox methods to return unique ids

* fix complete_flag to is_read

* fix inbox outbox methods to not show archived

* add view_archived method to sdk

* add archive_file method to sdk

* fix inbox and outbox output and add support for attachments

* add draft methods to sdk

* fix default values of named params

* fix css for filetracking.html

* fix fts serializer.py

* add dept adding method to sdk

* add helper methods to sdk

* fix inbox based on SDK

* remove track from TabMenu

* fix outbox using SDK

* fix archive view for SDK

* fix Drafts based on SDK

* fix the view file functionality in the web app

* fix frontend

* fix .gitignore to untrack migrations

* fix 1. order of files in inbox and outbox 2. order of files is mantained in uniqueList function

* fix login required on viewing file

* fix create_file method so that subject and description are also accepted

* add rest api for create file and view file

* add rest api for create, view and  delete file

* add rest api for inbox, outbox, history view

* add rest api for draft view, forward file

* prevent student access of the filetracking module

* add dropdown filtering based on reciever username and update notallowed template

* add option to unarchive files

* fix template for filetrackingnotallowed page

* fix attachments view in the history of the file

* make the fields in draft view editable

* update the views

---------

Co-authored-by: Aragorn-64 <[email protected]>
Co-authored-by: aish0749 <[email protected]>
  • Loading branch information
3 people authored Mar 11, 2024
1 parent ee8f6be commit 4962f02
Show file tree
Hide file tree
Showing 30 changed files with 1,915 additions and 640 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,6 @@ node_modules/

FusionIIIT/static/
package-lock.json

# migrations
migrations/
24 changes: 24 additions & 0 deletions FusionIIIT/applications/filetracking/api/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from applications.filetracking.models import File, Tracking
from django.core.files import File as DjangoFile
from rest_framework import serializers


class FileSerializer(serializers.ModelSerializer):
class Meta:
model = File
fields = '__all__'


class TrackingSerializer(serializers.ModelSerializer):
class Meta:
model = Tracking
fields = '__all__'


class FileHeaderSerializer(serializers.ModelSerializer):
'''
This serializes everything except the attachments of a file and whether it is read or not
'''
class Meta:
model = File
exclude = ['upload_file', 'is_read']
24 changes: 24 additions & 0 deletions FusionIIIT/applications/filetracking/api/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from django.conf.urls import url
from .views import (
CreateFileView,
ViewFileView,
ViewInboxView,
ViewOutboxView,
ViewHistoryView,
ForwardFileView,
DraftFileView,
CreateDraftFile,
GetDesignationsView,
)

urlpatterns = [
url(r'^file/$', CreateFileView.as_view(), name='create_file'),
url(r'^file/(?P<file_id>\d+)/$', ViewFileView.as_view(), name='view_file'),
url(r'^inbox/$', ViewInboxView.as_view(), name='view_inbox'),
url(r'^outbox/$', ViewOutboxView.as_view(), name='view_outbox'),
url(r'^history/(?P<file_id>\d+)/$', ViewHistoryView.as_view(), name='view_history'),
url(r'^forwardfile/(?P<file_id>\d+)/$', ForwardFileView.as_view(), name='forward_file'),
url(r'^draft/$', DraftFileView.as_view(), name='view_drafts'),
url(r'^createdraft/$', CreateDraftFile.as_view(), name='create_draft'),
url(r'^designations/(?P<username>\w+)/$', GetDesignationsView.as_view(), name='get_designations'),
]
247 changes: 247 additions & 0 deletions FusionIIIT/applications/filetracking/api/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
import logging
from venv import logger
from django.forms import ValidationError
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status, permissions
from rest_framework.authentication import TokenAuthentication
from ..models import File, Tracking
from ..sdk.methods import create_draft, create_file, view_drafts, view_file, delete_file, view_inbox, view_outbox, view_history, forward_file, get_designations

class CreateFileView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]

def post(self, request):
try:
current_user = request.user.username
current_designation = request.data.get('designation')
receiver_username = request.data.get('receiver_username')
receiver_designation = request.data.get('receiver_designation')
subject = request.data.get('subject')
description = request.data.get('description')

if None in [current_designation, receiver_username, receiver_designation, subject, description]:
return Response({'error': 'One or more required fields are missing.'}, status=status.HTTP_400_BAD_REQUEST)

file_id = create_file(uploader=current_user, uploader_designation=current_designation,
receiver=receiver_username, receiver_designation=receiver_designation, subject=subject, description=description)

return Response({'file_id': file_id}, status=status.HTTP_201_CREATED)
except Exception as e:
return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST)


class ViewFileView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]

def get(self, request, file_id):
try:
file_details = view_file(int(file_id))
# print(file_details)
return Response(file_details, status=status.HTTP_200_OK)
except ValueError:
return Response({'error': 'Invalid file ID format.'}, status=status.HTTP_400_BAD_REQUEST)
except File.DoesNotExist:
return Response({'error': 'File not found.'}, status=status.HTTP_404_NOT_FOUND)
except Exception as e:
return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST)

def delete(self, request, file_id):
try:
# file_details = view_file(int(file_id))
# print(file_details)
success = delete_file(int(file_id))
if success:
return Response({'message': 'File deleted successfully'},
status=status.HTTP_204_NO_CONTENT)
else :
return

except ValueError:
return Response({'error': 'Invalid file ID format'},
status=status.HTTP_400_BAD_REQUEST)
except File.DoesNotExist:
return Response({'error': 'File not found'},
status=status.HTTP_404_NOT_FOUND)
except ValidationError as e:
return Response(e.detail, status=status.HTTP_400_BAD_REQUEST) # Handle ValidationError specifically
except Exception as e: # Catch unexpected errors
logger.error(f"Unexpected error in DeleteFileView: {e}")
return Response({'error': 'An internal server error occurred'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class ViewInboxView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]

def get(self, request):
"""
API endpoint to view inbox files.
Expects query parameters:
- username (required): User requesting the inbox.
- designation (optional): Designation to filter files by.
- src_module (required): Source module to filter files by.
Returns:
JSON response containing a list of serialized file data, including sender information.
"""

username = request.query_params.get('username')
designation = request.query_params.get('designation')
src_module = request.query_params.get('src_module')


# if not username or not src_module:
# return Response({'error': 'Missing required query parameters: username and src_module.'}, status=400)

inbox_files = view_inbox(username, designation, src_module)
return Response(inbox_files)

class ViewOutboxView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]


def get(self, request):
"""
API endpoint to view outbox files.
Expects query parameters:
- username (required): User requesting the outbox.
- designation (optional): Designation to filter files by.
- src_module (required): Source module to filter files by.
Returns:
JSON response containing a paginated list of serialized file data.
"""

username = request.query_params.get('username')
designation = request.query_params.get('designation')
src_module = request.query_params.get('src_module')


if not username or not src_module:
return Response({'error': 'Missing required query parameters: username and src_module.'}, status=400)

outbox_files = view_outbox(username, designation, src_module)
return Response(outbox_files)


class ViewHistoryView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]

def get(self, request, file_id):
"""
View history of a particular file with the given file_id.
Args:
request (rest_framework.request.Request): The incoming request object.
file_id (int): Primary key of the file to retrieve history for.
Returns:
rest_framework.response.Response: JSON response containing serialized tracking history.
"""

try:
history = view_history(file_id)
return Response(history)
except Tracking.DoesNotExist:
return Response({'error': f'File with ID {file_id} not found.'}, status=404)
except Exception as e:
logger.error(f"An unexpected error occurred: {e}")
return Response({'error': 'Internal server error.'}, status=500)

class ForwardFileView(APIView):
# # # Authentication and permission classes (adjust based on your needs)
authentication_classes = [TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]

def post(self, request, file_id):
# # Extract data from request.data
receiver = request.data.get('receiver')
receiver_designation = request.data.get('receiver_designation')
file_extra_JSON = request.data.get('file_extra_JSON', {})
remarks = request.data.get('remarks', "")

# Validate data
if not receiver or not receiver_designation:
raise ValidationError("Missing required fields: receiver and receiver_designation")

# # Extract and validate file attachment (if present)
file_attachment = request.FILES.get('file_attachment')
if file_attachment:
if file_attachment.size > 10 * 1024 * 1024: # Adjust size limit as needed
raise ValidationError("File size exceeds limit (10 MB)")

# Call forward_file function
try:
new_tracking_id = forward_file(
int(file_id),
receiver,
receiver_designation,
file_extra_JSON,
remarks,
file_attachment
)
logging.info(f"Successfully forwarded file {file_id} with tracking ID: {new_tracking_id}")
except Exception as e:
logging.error(f"Error forwarding file {file_id}: {str(e)}")
raise ValidationError(str(e)) # Re-raise exception with a user-friendly message

# Return response
return Response({'tracking_id': new_tracking_id}, status=status.HTTP_201_CREATED)

class CreateDraftFile(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]

def post(self, request):
uploader = request.data.get('uploader')
uploader_designation = request.data.get('uploader_designation')
src_module = request.data.get('src_module', 'filetracking')
src_object_id = request.data.get('src_object_id', '')
file_extra_JSON = request.data.get('file_extra_JSON', {})
attached_file = request.FILES.get('attached_file', None)

try:
file_id = create_draft(
uploader=uploader,
uploader_designation=uploader_designation,
src_module=src_module,
src_object_id=src_object_id,
file_extra_JSON=file_extra_JSON,
attached_file=attached_file
)
return Response({'file_id': file_id}, status=status.HTTP_201_CREATED)
except Exception as e:
return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

class DraftFileView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [permissions.IsAuthenticated]

def get(self, request):
username = request.query_params.get('username')
designation = request.query_params.get('designation')
src_module = request.query_params.get('src_module')

try:
draft_files = view_drafts(username, designation, src_module)
print(draft_files)
return Response(draft_files, status=status.HTTP_200_OK)
except Exception as e:
return Response({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)



class GetDesignationsView(APIView):
#authentication_classes = [TokenAuthentication]
#permission_classes = [permissions.IsAuthenticated]

def get(self, request, username, *args, **kwargs):
user_designations = get_designations(username)
return Response({'designations': user_designations})
38 changes: 38 additions & 0 deletions FusionIIIT/applications/filetracking/decorators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from django.shortcuts import render, get_object_or_404
from django.contrib.auth.models import User
from applications.globals.models import ExtraInfo, HoldsDesignation


def user_check(request):
"""
This function is used to check if the user is a student or not.
Its return type is bool.
@param:
request - contains metadata about the requested page
@Variables:
current_user - get user from request
user_details - extract details of the user from the database
desig_id - check for designation
student - designation for a student
final_user - final designation of the request(our user)
"""
try:
current_user = get_object_or_404(User, username=request.user.username)
user_details = ExtraInfo.objects.select_related('user','department').get(user=request.user)
des = HoldsDesignation.objects.all().select_related().filter(user=request.user).first()
if str(des.designation) == "student":
return True
else:
return False
except Exception as e:
return False

def user_is_student(view_func):
def _wrapped_view(request, *args, **kwargs):
if user_check(request):
return render(request, 'filetracking/fileTrackingNotAllowed.html')
else:
return view_func(request, *args, **kwargs)
return _wrapped_view

12 changes: 9 additions & 3 deletions FusionIIIT/applications/filetracking/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ class File(models.Model):
is_read = models.BooleanField(default = False)


# additions for API
src_module = models.CharField(max_length=100, default='filetracking')
src_object_id = models.CharField(max_length=100,null=True)
file_extra_JSON = models.JSONField(null=True)

class Meta:
db_table = 'File'

Expand All @@ -25,13 +30,11 @@ class Meta:

class Tracking(models.Model):
"""
This is File Tracing Table which contains the status of each indivisual file created by the user
This is File Tracing Table which contains the status of each individual file created by the user
"""
file_id = models.ForeignKey(File, on_delete=models.CASCADE, null=True)
current_id = models.ForeignKey(ExtraInfo, on_delete=models.CASCADE)
current_design = models.ForeignKey(HoldsDesignation, null=True, on_delete=models.CASCADE)
# receiver_id = models.ForeignKey(ExtraInfo, on_delete=models.CASCADE, related_name='receiver_id')
# receive_design = models.ForeignKey(HoldsDesignation, null=True, on_delete=models.CASCADE, related_name='rec_design')
receiver_id = models.ForeignKey(User,null = True, on_delete=models.CASCADE, related_name='receiver_id')
receive_design = models.ForeignKey(Designation, null=True, on_delete=models.CASCADE, related_name='rec_design')

Expand All @@ -41,5 +44,8 @@ class Tracking(models.Model):
upload_file = models.FileField(blank=True)
is_read = models.BooleanField(default = False)

# additions for API
tracking_extra_JSON = models.JSONField(null=True)

class Meta:
db_table = 'Tracking'
Loading

0 comments on commit 4962f02

Please sign in to comment.