Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2160 internal user can view access requests #2469

Merged
merged 15 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,7 @@
"title": "Operator Administrators and Access Requests",
"icon": "Inbox",
"content": "View all operator administrators and administrator access requests here.",
"href": "/administration/tbd"
},
{
"title": "Operation Administrations",
"icon": "Layers",
"content": "View the administration of operations here.",
"href": "/administration/tbd"
"href": "/administration/operator-administrators-and-access-requests"
},
{
"title": "Contacts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,7 @@
"title": "Operator Administrators and Access Requests",
"icon": "Inbox",
"content": "View all operator administrators and administrator access requests here.",
"href": "/administration/tbd"
},
{
"title": "Operation Administrations",
"icon": "File",
"content": "View the administration of operations here.",
"href": "/administration/tbd"
"href": "/administration/operator-administrators-and-access-requests"
},
{
"title": "Contacts",
Expand Down
4 changes: 2 additions & 2 deletions bc_obps/common/fixtures/dashboard/bciers/internal.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
"href": "/administration/operations"
},
{
"title": "Operator Admins and Access Requests",
"href": "/administration/tbd"
"title": "Operator Administrators and Access Requests",
"href": "/administration/operator-administrators-and-access-requests"
},
{
"title": "Contacts",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ class TestEndpointPermissions(TestCase):
],
"authorized_irc_user": [
{"method": "get", "endpoint_name": "list_user_operators"},
{"method": "get", "endpoint_name": "list_user_operators_v2"},
{"method": "put", "endpoint_name": "update_operator_status", "kwargs": {"operator_id": mock_uuid}},
{
"method": "put",
Expand Down
26 changes: 24 additions & 2 deletions bc_obps/registration/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,7 @@

admin.site.register(AppRole)
admin.site.register(NaicsCode)
admin.site.register(User)
admin.site.register(Operator)
admin.site.register(UserOperator)
admin.site.register(ParentOperator)
admin.site.register(RegulatedProduct)
admin.site.register(Activity)
Expand Down Expand Up @@ -103,3 +101,27 @@ class DocumentAdmin(admin.ModelAdmin):
@staticmethod
def type_name(obj: Document) -> str:
return obj.type.name


@admin.register(User)
class UserAdmin(admin.ModelAdmin):
list_display = ('user_guid', 'first_name', 'last_name', 'email', 'position_title', 'role')
search_fields = ('user_guid', 'first_name', 'last_name')

@staticmethod
def role(obj: User) -> str:
return obj.app_role.role_name


@admin.register(UserOperator)
class UserOperatorAdmin(admin.ModelAdmin):
list_display = ('id', 'user_full_name', 'operator_legal_name', 'role', 'status')
ordering = ('-created_at',)

@staticmethod
def user_full_name(obj: UserOperator) -> str:
return obj.user.first_name + ' ' + obj.user.last_name

@staticmethod
def operator_legal_name(obj: UserOperator) -> str:
return obj.operator.legal_name
31 changes: 28 additions & 3 deletions bc_obps/registration/api/v2/user_operators.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,41 @@
from django.db.models import QuerySet
from ninja import Query
from common.permissions import authorize
from common.api.utils import get_current_user_guid
from django.http import HttpRequest
from registration.decorators import handle_http_errors
from registration.models import UserOperator
from registration.schema.generic import Message
from registration.api.router import router
from service.error_service.custom_codes_4xx import custom_codes_4xx
from typing import Literal, Tuple

from typing import Literal, Tuple, Optional, List
from registration.constants import USER_OPERATOR_TAGS_V2
from registration.schema.v2.operator import OperatorIn
from registration.schema.v2.user_operator import UserOperatorOperatorOut
from registration.schema.v2.user_operator import UserOperatorOperatorOut, UserOperatorListOut, UserOperatorFilterSchema
from service.user_operator_service_v2 import UserOperatorServiceV2
from ninja.pagination import paginate, PageNumberPagination

## GET
@router.get(
"/v2/user-operators",
response={200: List[UserOperatorListOut], custom_codes_4xx: Message},
tags=USER_OPERATOR_TAGS_V2,
description="""Retrieves a paginated list of user operators.
The endpoint allows authorized IRC roles to view user operators, sorted by various fields such as creation date,
user details, and operator legal name.""",
auth=authorize("authorized_irc_user"),
)
@handle_http_errors()
@paginate(PageNumberPagination)
def list_user_operators_v2(
request: HttpRequest,
filters: UserOperatorFilterSchema = Query(...),
sort_field: Optional[str] = "created_at",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

created_at isn't one of the grid columns, does that matter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, created_at serves as the default value for sorting when users do not specify their own sorting preferences.(It's used for the query)

sort_order: Optional[Literal["desc", "asc"]] = "desc",
paginate_result: bool = Query(True, description="Whether to paginate the results"),
) -> QuerySet[UserOperator]:
# NOTE: PageNumberPagination raises an error if we pass the response as a tuple (like 200, ...)
return UserOperatorServiceV2.list_user_operators_v2(get_current_user_guid(request), sort_field, sort_order, filters)


## POST
Expand Down
6 changes: 3 additions & 3 deletions bc_obps/registration/fixtures/mock/admin/user_operator.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
"fields": {
"user": "00000000-0000-0000-0000-000000000007",
"operator": "5712ee05-5f3b-4822-825d-6fffddafda4c",
"role": "pending",
"role": "admin",
"status": "Pending",
"verified_at": null,
"verified_by": null,
Expand Down Expand Up @@ -196,8 +196,8 @@
"fields": {
"user": "00000000-0000-0000-0000-000000000014",
"operator": "5712ee05-5f3b-4822-825d-6fffddafda4c",
"role": "pending",
"status": "Pending",
"role": "admin",
"status": "Declined",
"verified_at": null,
"verified_by": null,
"user_friendly_id": 17
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
"fields": {
"user": "00000000-0000-0000-0000-000000000007",
"operator": "5712ee05-5f3b-4822-825d-6fffddafda4c",
"role": "pending",
"role": "admin",
"status": "Pending",
"verified_at": null,
"verified_by": null,
Expand Down Expand Up @@ -196,8 +196,8 @@
"fields": {
"user": "00000000-0000-0000-0000-000000000014",
"operator": "5712ee05-5f3b-4822-825d-6fffddafda4c",
"role": "pending",
"status": "Pending",
"role": "admin",
"status": "Declined",
"verified_at": null,
"verified_by": null,
"user_friendly_id": 17
Expand Down
6 changes: 3 additions & 3 deletions bc_obps/registration/fixtures/mock/user_operator.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@
"fields": {
"user": "00000000-0000-0000-0000-000000000007",
"operator": "5712ee05-5f3b-4822-825d-6fffddafda4c",
"role": "pending",
"role": "admin",
"status": "Pending",
"verified_at": null,
"verified_by": null,
Expand Down Expand Up @@ -196,8 +196,8 @@
"fields": {
"user": "00000000-0000-0000-0000-000000000014",
"operator": "5712ee05-5f3b-4822-825d-6fffddafda4c",
"role": "pending",
"status": "Pending",
"role": "admin",
"status": "Declined",
"verified_at": null,
"verified_by": null,
"user_friendly_id": 17
Expand Down
39 changes: 38 additions & 1 deletion bc_obps/registration/schema/v2/user_operator.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,44 @@
from ninja import Schema
from typing import Optional
from django.db.models import Q
from ninja import Schema, FilterSchema, Field, ModelSchema
from uuid import UUID
from registration.models import UserOperator


class UserOperatorOperatorOut(Schema):
operator_id: UUID
user_operator_id: UUID


class UserOperatorFilterSchema(FilterSchema):
user_friendly_id: Optional[str] = Field(None, json_schema_extra={'q': 'user_friendly_id__icontains'})
status: Optional[str] = None
user__first_name: Optional[str] = Field(None, json_schema_extra={'q': 'user__first_name__icontains'})
user__last_name: Optional[str] = Field(None, json_schema_extra={'q': 'user__last_name__icontains'})
user__email: Optional[str] = Field(None, json_schema_extra={'q': 'user__email__icontains'})
user__bceid_business_name: Optional[str] = Field(
None, json_schema_extra={'q': 'user__bceid_business_name__icontains'}
)
operator__legal_name: Optional[str] = Field(None, json_schema_extra={'q': 'operator__legal_name__icontains'})

@staticmethod
def filter_status(value: Optional[str]) -> Q:
# Override the default filter_status method to handle the special case of 'admin' and 'access'
# The value in the frontend is 'admin access' but the value in the database is 'approved'
if value:
if value.lower() in "admin access":
value = "approved"
return Q(status__icontains=value)
return Q()


class UserOperatorListOut(ModelSchema):
user__first_name: str = Field(..., alias="user.first_name")
user__last_name: str = Field(..., alias="user.last_name")
user__email: str = Field(..., alias="user.email")
user__bceid_business_name: str = Field(..., alias="user.bceid_business_name")
operator__legal_name: str = Field(..., alias="operator.legal_name")

class Meta:
model = UserOperator
fields = ['id', 'user_friendly_id', 'status']
Loading