Skip to content

Commit

Permalink
feat: API for querying asset field values (#236)
Browse files Browse the repository at this point in the history
* build: Build CI/CD pipeline using github actions (#228)

* fix: Only show assets which are not deleted

* fix: Fix Pagination bug

* build: Dockerize backend and frontend services

* build: Add production deployment script

* chore: Remove environment files from git tracking

* Feat charts (#230)

* feat:charts

* feat: Add new chart to view individual asset type count

* fix: changed namings

* feat: Add test to backend assetype and assetview

* feat: added new chart

* feat: Add new chart cards for improved dashboard user experience

* Add bar chart component which feature individual asset count and card components that show various data for enhanced ux experience

* fix: fixes to some code lines

* fix: Fix dashboard ui padding and margin

* fixes

* fix: AssetView fix

* fix: ui

* fix: code structure

* feat: new ui design for charts

* feat:making chart responsive

* fix charts

* feat-charts

* feat-charts

* Feat charts (#231)

* feat:charts

* feat: Add new chart to view individual asset type count

* fix: changed namings

* feat: Add test to backend assetype and assetview

* feat: added new chart

* feat: Add new chart cards for improved dashboard user experience

* Add bar chart component which feature individual asset count and card components that show various data for enhanced ux experience

* fix: fixes to some code lines

* fix: Fix dashboard ui padding and margin

* fixes

* fix: AssetView fix

* fix: ui

* fix: code structure

* feat: new ui design for charts

* feat:making chart responsive

* fix charts

* feat-charts

* feat-charts

* revert: reverted back to old files due to crashing

* fix

* Feat charts (#233)

* feat:charts

* feat: Add new chart to view individual asset type count

* fix: changed namings

* feat: Add test to backend assetype and assetview

* feat: added new chart

* feat: Add new chart cards for improved dashboard user experience

* Add bar chart component which feature individual asset count and card components that show various data for enhanced ux experience

* fix: fixes to some code lines

* fix: Fix dashboard ui padding and margin

* fixes

* fix: AssetView fix

* fix: ui

* fix: code structure

* feat: new ui design for charts

* feat:making chart responsive

* fix charts

* feat-charts

* feat-charts

* revert: reverted back to old files due to crashing

* fix

* fix: responsiveness of dashboard

* feat:Add new UI display to charts when no data is found

* feat: Create API for getting unique values of different fields in the asset table (#234)

* fix: Only show assets which are not deleted

* fix: Fix Pagination bug

* build: Dockerize backend and frontend services

* feat: Create API for getting unique values of different fields in asset table

* fix: Change sidebar tooltip message (#235)

* fix: Only show assets which are not deleted

* fix: Fix Pagination bug

* build: Dockerize backend and frontend services

* fix: Change tooltip message in download menu item in sidebar

---------

Co-authored-by: Aidrin Varghese <[email protected]>
  • Loading branch information
getwithashish and AidrinVarghese authored Apr 19, 2024
1 parent 14828c1 commit 76c7da3
Show file tree
Hide file tree
Showing 25 changed files with 397 additions and 219 deletions.
15 changes: 15 additions & 0 deletions exam_django/.prod.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
DJANGO_SECRET_KEY=1)e@l)h^ipetx7m9e)2agttg@vn4kwn%$4mlwf#m^3o)r@amkz

DB_NAME=asset_management_db
DB_USER=root
DB_PORT=3306

DB_PASSWORD=experion@123
DB_HOST=mysql-db-service

ALLOWED_HOSTS=localhost,127.0.0.1

EMAIL_HOST_USER=[email protected]
EMAIL_HOST_PASSWORD=ovbh xecf yztb wopx
EMAIL_PORT=587
EMAIL_USE_TLS=True
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import json
from rest_framework import status
from django.db.models import Q
from rest_framework.pagination import LimitOffsetPagination

from asset.service.asset_crud_service.asset_query_abstract import AssetQueryAbstract
from asset.models.asset import Asset
from asset.serializers.asset_serializer import AssetReadSerializer
from utils.table_util import TableUtil
from exceptions import NotAcceptableOperationException, NotFoundException
from messages import (
ASSET_FIELD_NOT_FILTERABLE,
ASSET_FIELD_NOT_FOUND,
ASSET_FIELD_VALUE_LIST_SUCCESSFULLY_RETRIEVED,
ASSET_FIELD_VALUE_QUERY_PARAM_NOT_FOUND,
)


class AssetFieldValueQueryService(AssetQueryAbstract):

# Used for autocomplete functionality
def get_asset_details(self, serializer, request):

self.pagination = LimitOffsetPagination()
queryset = Asset.objects.all()

unfilterable_fields = [
"asset_uuid",
"version",
"asset_category",
"date_of_purchase",
"status",
"notes",
"approval_status_message",
"warranty_period",
"asset_detail_status",
"assign_status",
"created_at",
"updated_at",
]

foreign_fields = [
"asset_type",
"custodian",
"location",
"invoice_location",
"business_unit",
"memory",
"approved_by",
"requester",
]

asset_field_value_filter = request.query_params.get("asset_field_value_filter")
if asset_field_value_filter:
asset_field_object = json.loads(asset_field_value_filter)
asset_field_name = list(asset_field_object.keys())[0]
asset_field_value = asset_field_object.get(asset_field_name)

if (
asset_field_name in unfilterable_fields
or asset_field_name in foreign_fields
):
raise NotAcceptableOperationException(
{},
ASSET_FIELD_NOT_FILTERABLE,
status.HTTP_406_NOT_ACCEPTABLE,
)

if TableUtil.field_exists_in_table(Asset, asset_field_name):
filterConditionQObject = Q(
**{asset_field_name + "__icontains": asset_field_value}
)
queryset = queryset.filter(filterConditionQObject)
else:
raise NotFoundException(
{},
ASSET_FIELD_NOT_FOUND,
status.HTTP_406_NOT_ACCEPTABLE,
)

fields_to_select = [asset_field_name]
queryset = queryset.distinct()
queryset = queryset.values(*fields_to_select)

serializer_class = type(
"DynamicSerializer",
(AssetReadSerializer,),
{
"Meta": type(
"Meta", (), {"model": Asset, "fields": fields_to_select}
)
},
)

page = self.pagination.paginate_queryset(queryset, request)
if page is not None:
serializer = serializer_class(page, many=True)
serializer = self.pagination.get_paginated_response(serializer.data)

else:
serializer = serializer_class(queryset, many=True)

return (
serializer.data,
ASSET_FIELD_VALUE_LIST_SUCCESSFULLY_RETRIEVED,
status.HTTP_200_OK,
)

else:
raise NotFoundException(
{},
ASSET_FIELD_VALUE_QUERY_PARAM_NOT_FOUND,
status.HTTP_406_NOT_ACCEPTABLE,
)
2 changes: 0 additions & 2 deletions exam_django/asset/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
EmployeeView,
AssignAssetView,
AssetApproveView,
AssetSearchWithFilterView,
AssetLogView,
DataImportView,
AssetExportView,
Expand All @@ -29,7 +28,6 @@
path("employee", EmployeeView.as_view(), name="employee_view"),
path("assign_asset", AssignAssetView.as_view(), name="assign_asset"),
path("approve_asset", AssetApproveView.as_view(), name="approve_asset"),
path("search", AssetSearchWithFilterView.as_view(), name="search"),
path("asset_logs/<str:asset_uuid>", AssetLogView.as_view(), name="asset_logs"),
path("import-csv/", DataImportView.as_view(), name="csv_file_import"),
path("export", AssetExportView.as_view(), name="export"),
Expand Down
84 changes: 0 additions & 84 deletions exam_django/asset/views/AssetSearchView.py

This file was deleted.

2 changes: 0 additions & 2 deletions exam_django/asset/views/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from .AssetSearchView import AssetSearchWithFilterView
from .asset_view import AssetView, UserAgentAssetView
from .asset_approve_view import AssetApproveView
from .asset_type_view import AssetTypeView
Expand All @@ -25,7 +24,6 @@
"EmployeeView",
"AssignAssetView",
"UnassignAssetView",
"AssetSearchWithFilterView",
"AssetLogView",
"DataImportView",
"AssetExportView",
Expand Down
26 changes: 21 additions & 5 deletions exam_django/asset/views/asset_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,21 @@
from asset.service.asset_crud_service.asset_advanced_query_service_with_json_logic import (
AssetAdvancedQueryServiceWithJsonLogic,
)
from exceptions import NotAcceptableOperationException, PermissionDeniedException
from asset.service.asset_crud_service.asset_field_value_query_service import (
AssetFieldValueQueryService,
)
from exceptions import (
NotAcceptableOperationException,
NotFoundException,
PermissionDeniedException,
)
from response import APIResponse
from messages import (
ASSET_CREATED_UNSUCCESSFUL,
ASSET_LIST_RETRIEVAL_UNSUCCESSFUL,
ASSET_NOT_FOUND,
USER_UNAUTHORIZED,
ASSET_DELETION_SUCCESSFUL
ASSET_DELETION_SUCCESSFUL,
)


Expand All @@ -45,6 +52,8 @@ def get(self, request, *args, **kwargs):

if request.query_params.get("json_logic"):
asset_query_service = AssetAdvancedQueryServiceWithJsonLogic()
elif request.query_params.get("asset_field_value_filter"):
asset_query_service = AssetFieldValueQueryService()
else:
asset_query_service = AssetNormalQueryService()

Expand All @@ -57,10 +66,16 @@ def get(self, request, *args, **kwargs):
status=http_status,
)

except NotFoundException as e:
return APIResponse(
data=str(e),
message=ASSET_LIST_RETRIEVAL_UNSUCCESSFUL,
status=status.HTTP_400_BAD_REQUEST,
)

except Exception as e:
print("Error: ", e)
return APIResponse(
data={},
data=str(e),
message=ASSET_LIST_RETRIEVAL_UNSUCCESSFUL,
status=status.HTTP_400_BAD_REQUEST,
)
Expand Down Expand Up @@ -147,7 +162,7 @@ def patch(self, request):
message=e.message,
status=e.status,
)

def delete(self, request):
asset_uuid = request.data.get("asset_uuid")
try:
Expand All @@ -168,6 +183,7 @@ def delete(self, request):
status=status.HTTP_400_BAD_REQUEST,
)


class UserAgentAssetView(APIView):
permission_classes = [AllowAny]

Expand Down
6 changes: 5 additions & 1 deletion exam_django/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,15 @@

# Asset Success Messages
ASSET_LIST_SUCCESSFULLY_RETRIEVED = "Asset list is successfully retreived."
ASSET_FIELD_VALUE_LIST_SUCCESSFULLY_RETRIEVED = "Asset field value list is successfully retrieved"
ASSET_COUNT_RETRIEVAL_UNSUCCESSFUL = (
"Asset count failed to be retrieved. Please try again."
)
ASSET_ASSIGNMENT_FAILED = "Failed to assign asset. Please try again."

ASSET_FIELD_VALUE_QUERY_PARAM_NOT_FOUND = "No valid Asset Field Value Query Param was found"
ASSET_FIELD_NOT_FOUND = "No valid Asset Field was found"
ASSET_FIELD_NOT_FILTERABLE = "Asset Field is not filterable"

# Asset Success Messages
ASSET_LIST_SUCCESSFULLY_RETRIEVED = "Asset list is successfully retreived."
Expand Down Expand Up @@ -172,4 +176,4 @@
MEMORY_SUCCESSFULLY_RETRIEVED = "Memory retrieved succesfully"
MEMORY_EXISTS = "Memory already exists"

ASSET_DELETION_SUCCESSFUL="Asset Deletion is sucessful"
ASSET_DELETION_SUCCESSFUL = "Asset Deletion is sucessful"
11 changes: 11 additions & 0 deletions exam_django/utils/table_util.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
from django.db import models


class TableUtil:

@classmethod
Expand All @@ -14,3 +17,11 @@ def has_expected_keys(cls, obj, expected_keys):
object_keys = set(obj.keys())
matching_keys = object_keys & set(expected_keys)
return bool(matching_keys)

@classmethod
def field_exists_in_table(cls, model_class, field_name):
try:
model_class._meta.get_field(field_name)
return True
except models.fields.FieldDoesNotExist:
return False
1 change: 1 addition & 0 deletions exam_frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"classnames": "^2.3.2",
"flowbite": "^1.5.5",
"flowbite-react": "^0.7.2",
"framer-motion": "^11.1.3",
"jspdf": "^2.5.1",
"react-apexcharts": "^1.4.0",
"react-autocomplete": "^1.8.1",
Expand Down
9 changes: 9 additions & 0 deletions exam_frontend/public/images/no data.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 11 additions & 12 deletions exam_frontend/src/components/AssetTable/api/getAssetLog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@ import { AxiosError } from "axios";
import axiosInstance from "../../../config/AxiosConfig";
import { LogData } from "../types";

const getAssetLog=async (selectedAssetId:string|null):Promise<LogData[]> => {



const response = await axiosInstance.get(`asset/asset_logs/${selectedAssetId}`);
console.log('Returned Log Data: ', response.data.data.logs);
return response.data.data.logs;
}

export {getAssetLog}


const getAssetLog = async (
selectedAssetId: string | null
): Promise<LogData[]> => {
const response = await axiosInstance.get(
`asset/asset_logs/${selectedAssetId}`
);
console.log("Returned Log Data: ", response.data.data.logs);
return response.data.data.logs;
};

export { getAssetLog };
Loading

0 comments on commit 76c7da3

Please sign in to comment.