Skip to content

Commit

Permalink
Merge pull request #12 from openimis/feature/CM-869
Browse files Browse the repository at this point in the history
CM-869: add comment mutation and query
  • Loading branch information
delcroip authored Apr 23, 2024
2 parents 3ed4f7e + f989b76 commit 1ac5ea5
Show file tree
Hide file tree
Showing 10 changed files with 313 additions and 30 deletions.
20 changes: 8 additions & 12 deletions grievance_social_protection/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,12 @@

DEFAULT_CFG = {
"default_validations_disabled": False,
"gql_query_tickets_perms": ["123000"],
"gql_mutation_create_tickets_perms": ["123001"],
"gql_mutation_update_tickets_perms": ["123002"],
"gql_mutation_delete_tickets_perms": ["123003"],
"gql_query_categorys_perms": ["123004"],
"gql_mutation_create_categorys_perms": ["123005"],
"gql_mutation_update_categorys_perms": ["123006"],
"gql_mutation_delete_categorys_perms": ["123007"],
"gql_query_tickets_perms": ["127000"],
"gql_query_comments_perms": ["127004"],
"gql_mutation_create_tickets_perms": ["127001"],
"gql_mutation_update_tickets_perms": ["127002"],
"gql_mutation_delete_tickets_perms": ["127003"],
"gql_mutation_create_comment_perms": ["127005"],
"tickets_attachments_root_path": None,

"grievance_types": [DEFAULT_STRING, 'Category A', 'Category B'],
Expand All @@ -40,13 +38,11 @@ class TicketConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = MODULE_NAME
gql_query_tickets_perms = []
gql_query_comments_perms = []
gql_mutation_create_tickets_perms = []
gql_mutation_update_tickets_perms = []
gql_mutation_delete_tickets_perms = []
gql_query_categorys_perms = []
gql_mutation_create_categorys_perms = []
gql_mutation_update_categorys_perms = []
gql_mutation_delete_categorys_perms = []
gql_mutation_create_comment_perms = []
tickets_attachments_root_path = None

grievance_types = []
Expand Down
50 changes: 45 additions & 5 deletions grievance_social_protection/gql_mutations.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
from core.gql.gql_mutations.base_mutation import BaseHistoryModelCreateMutationMixin, BaseMutation, \
BaseHistoryModelUpdateMutationMixin, BaseHistoryModelDeleteMutationMixin
from core.schema import OpenIMISMutation
from .models import Ticket, TicketMutation
from .models import Ticket, TicketMutation, Comment

from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import ValidationError, PermissionDenied
from .apps import TicketConfig
from django.utils.translation import gettext_lazy as _

from .services import TicketService
from .services import TicketService, CommentService
from .validations import user_associated_with_ticket


class CreateTicketInputType(OpenIMISMutation.Input):
Expand All @@ -25,7 +25,7 @@ class TicketStatusEnum(graphene.Enum):
title = graphene.String(required=False)
description = graphene.String(required=False)
reporter_type = graphene.String(required=True, max_lenght=255)
reporter_id = graphene.String(required=True)
reporter_id = graphene.String(required=True, max_lenght=255)
attending_staff_id = graphene.UUID(required=False)
date_of_incident = graphene.Date(required=False)
status = graphene.Field(TicketStatusEnum, required=False)
Expand All @@ -41,6 +41,13 @@ class UpdateTicketInputType(CreateTicketInputType):
id = graphene.UUID(required=True)


class CreateCommentInputType(OpenIMISMutation.Input):
ticket_id = graphene.UUID(required=True)
commenter_type = graphene.String(required=True, max_lenght=255)
commenter_id = graphene.String(required=True, max_lenght=255)
comment = graphene.String(required=True)


class CreateTicketMutation(BaseHistoryModelCreateMutationMixin, BaseMutation):
_mutation_class = "CreateTicketMutation"
_mutation_module = "grievance_social_protection"
Expand Down Expand Up @@ -113,13 +120,46 @@ class DeleteTicketMutation(BaseHistoryModelDeleteMutationMixin, BaseMutation):
@classmethod
def _validate_mutation(cls, user, **data):
super()._validate_mutation(user, **data)
if type(user) is AnonymousUser or not user.has_perms(
if not user.has_perms(
TicketConfig.gql_mutation_delete_tickets_perms):
raise ValidationError("mutation.authentication_required")

class Input(OpenIMISMutation.Input):
ids = graphene.List(graphene.UUID)


class CreateCommentMutation(BaseHistoryModelCreateMutationMixin, BaseMutation):
_mutation_class = "CreateCommentMutation"
_mutation_module = "grievance_social_protection"
_model = Comment

@classmethod
def _validate_mutation(cls, user, **data):
super()._validate_mutation(user, **data)
if user.has_perms(TicketConfig.gql_mutation_delete_tickets_perms):
return
if user_associated_with_ticket(user):
return
raise ValidationError("mutation.authentication_required")

@classmethod
def _mutate(cls, user, **data):
if "client_mutation_id" in data:
data.pop('client_mutation_id')
if "client_mutation_label" in data:
data.pop('client_mutation_label')

data['commenter_type'] = data.get('commenter_type', '').lower()
service = CommentService(user)
response = service.create(data)

if not response['success']:
return response
return None

class Input(CreateCommentInputType):
pass

# class CreateTicketAttachmentMutation(OpenIMISMutation):
# _mutation_module = "grievance_social_protection"
# _mutation_class = "CreateTicketAttachmentMutation"
Expand Down
51 changes: 45 additions & 6 deletions grievance_social_protection/gql_queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,24 @@

from core.gql_queries import UserGQLType
from .apps import TicketConfig
from .models import Ticket
from .models import Ticket, Comment

from core import prefix_filterset, ExtendedConnection
from .util import model_obj_to_json
from .validations import user_associated_with_ticket


def check_perms(info):
def check_ticket_perms(info):
if not info.context.user.has_perms(TicketConfig.gql_query_tickets_perms):
raise PermissionDenied(_("unauthorized"))


def check_comment_perms(info):
user = info.context.user
if not (user_associated_with_ticket(user) or user.has_perms(TicketConfig.gql_query_comments_perms)):
raise PermissionDenied(_("Unauthorized"))


class TicketGQLType(DjangoObjectType):
# TODO on resolve check filters and remove anonymized so user can't fetch ticket using last_name if not visible
client_mutation_id = graphene.String()
Expand All @@ -26,17 +33,17 @@ class TicketGQLType(DjangoObjectType):

@staticmethod
def resolve_reporter_type(root, info):
check_perms(info)
check_ticket_perms(info)
return root.reporter_type.id

@staticmethod
def resolve_reporter_type_name(root, info):
check_perms(info)
check_ticket_perms(info)
return root.reporter_type.name

@staticmethod
def resolve_reporter(root, info):
check_perms(info)
check_ticket_perms(info)
return model_obj_to_json(root.reporter)

class Meta:
Expand All @@ -57,7 +64,6 @@ class Meta:
"due_date": ["exact", "istartswith", "icontains", "iexact"],
"date_of_incident": ["exact", "istartswith", "icontains", "iexact"],
"date_created": ["exact", "istartswith", "icontains", "iexact"],
# TODO reporter generic key
**prefix_filterset("attending_staff__", UserGQLType._meta.filter_fields),
}

Expand All @@ -69,6 +75,39 @@ def resolve_client_mutation_id(self, info):
return ticket_mutation.mutation.client_mutation_id if ticket_mutation else None


class CommentGQLType(DjangoObjectType):
commenter = graphene.JSONString()
commenter_type = graphene.Int()
commenter_type_name = graphene.String()

@staticmethod
def resolve_commenter_type(root, info):
check_comment_perms(info)
return root.commenter_type.id

@staticmethod
def resolve_commenter_type_name(root, info):
check_comment_perms(info)
return root.commenter_type.name

@staticmethod
def resolve_commenter(root, info):
check_comment_perms(info)
return model_obj_to_json(root.commenter)

class Meta:
model = Comment
interfaces = (graphene.relay.Node,)
filter_fields = {
"id": ["exact", "isnull"],
"comment": ["exact", "istartswith", "icontains", "iexact"],
"date_created": ["exact", "istartswith", "icontains", "iexact"],
**prefix_filterset("ticket__", TicketGQLType._meta.filter_fields),
}

connection_class = ExtendedConnection


# class TicketAttachmentGQLType(DjangoObjectType):
# class Meta:
# model = TicketAttachment
Expand Down
40 changes: 40 additions & 0 deletions grievance_social_protection/migrations/0013_auto_20240422_2108.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Generated by Django 3.2.24 on 2024-04-22 21:08

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('grievance_social_protection', '0012_auto_20240418_1137'),
]

operations = [
migrations.AlterField(
model_name='comment',
name='commenter_id',
field=models.CharField(max_length=255),
),
migrations.AlterField(
model_name='comment',
name='commenter_type',
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='contenttypes.contenttype'),
),
migrations.AlterField(
model_name='comment',
name='ticket',
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='grievance_social_protection.ticket'),
),
migrations.AlterField(
model_name='historicalcomment',
name='commenter_id',
field=models.CharField(max_length=255),
),
migrations.AlterField(
model_name='ticket',
name='reporter_type',
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='contenttypes.contenttype'),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Generated by Django 3.2.24 on 2024-04-22 21:18

from django.db import migrations

from core.utils import insert_role_right_for_system, remove_role_right_for_system

IMIS_ADMIN_ROLE_IS_SYSTEM = 64

gql_query_tickets_perms = 127000
gql_query_comments_perms = 127004
gql_mutation_create_tickets_perms = 127001
gql_mutation_update_tickets_perms = 127002
gql_mutation_delete_tickets_perms = 127003
gql_mutation_create_comment_perms = 127005



def add_rights(apps, schema_editor):
"""
Add subscription CRUD permission to the IMIS Administrator.
"""
insert_role_right_for_system(IMIS_ADMIN_ROLE_IS_SYSTEM, gql_query_tickets_perms)
insert_role_right_for_system(IMIS_ADMIN_ROLE_IS_SYSTEM, gql_query_comments_perms)
insert_role_right_for_system(IMIS_ADMIN_ROLE_IS_SYSTEM, gql_mutation_create_tickets_perms)
insert_role_right_for_system(IMIS_ADMIN_ROLE_IS_SYSTEM, gql_mutation_update_tickets_perms)
insert_role_right_for_system(IMIS_ADMIN_ROLE_IS_SYSTEM, gql_mutation_delete_tickets_perms)
insert_role_right_for_system(IMIS_ADMIN_ROLE_IS_SYSTEM, gql_mutation_create_comment_perms)


def remove_rights(apps, schema_editor):
"""
Remove subscription CRUD permissions to the IMIS Administrator.
"""
remove_role_right_for_system(IMIS_ADMIN_ROLE_IS_SYSTEM, gql_query_tickets_perms)
remove_role_right_for_system(IMIS_ADMIN_ROLE_IS_SYSTEM, gql_query_comments_perms)
remove_role_right_for_system(IMIS_ADMIN_ROLE_IS_SYSTEM, gql_mutation_create_tickets_perms)
remove_role_right_for_system(IMIS_ADMIN_ROLE_IS_SYSTEM, gql_mutation_update_tickets_perms)
remove_role_right_for_system(IMIS_ADMIN_ROLE_IS_SYSTEM, gql_mutation_delete_tickets_perms)
remove_role_right_for_system(IMIS_ADMIN_ROLE_IS_SYSTEM, gql_mutation_create_comment_perms)


class Migration(migrations.Migration):


dependencies = [
('grievance_social_protection', '0013_auto_20240422_2108'),
]

operations = [
migrations.RunPython(add_rights, remove_rights),
]
8 changes: 4 additions & 4 deletions grievance_social_protection/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class TicketStatus(models.TextChoices):
description = models.TextField(max_length=255, blank=True, null=True)
code = models.CharField(max_length=16, unique=True, blank=True, null=True)

reporter_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=False, blank=False)
reporter_type = models.ForeignKey(ContentType, on_delete=models.DO_NOTHING, null=False, blank=False)
reporter_id = models.CharField(max_length=255, null=False, blank=False)
reporter = GenericForeignKey('reporter_type', 'reporter_id')

Expand Down Expand Up @@ -86,9 +86,9 @@ class Meta:


class Comment(HistoryModel):
ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE, null=False, blank=False)
commenter_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=False, blank=False)
commenter_id = models.PositiveIntegerField(null=False, blank=False)
ticket = models.ForeignKey(Ticket, on_delete=models.DO_NOTHING, null=False, blank=False)
commenter_type = models.ForeignKey(ContentType, on_delete=models.DO_NOTHING, null=False, blank=False)
commenter_id = models.CharField(max_length=255, null=False, blank=False)
commenter = GenericForeignKey('commenter_type', 'commenter_id')
comment = models.TextField(blank=False, null=False)

Expand Down
15 changes: 15 additions & 0 deletions grievance_social_protection/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ class Query(graphene.ObjectType):

grievance_config = graphene.Field(GrievanceTypeConfigurationGQLType)

comments = OrderedDjangoFilterConnectionField(
CommentGQLType,
orderBy=graphene.List(of_type=graphene.String),
)

def resolve_comments(self, info, **kwargs):
user = info.context.user

if not (user_associated_with_ticket(user) or user.has_perms(TicketConfig.gql_query_comments_perms)):
raise PermissionDenied(_("Unauthorized"))

return gql_optimizer.query(Comment.objects.all(), info)

def resolve_ticket_details(self, info, **kwargs):
if not info.context.user.has_perms(TicketConfig.gql_query_tickets_perms):
raise PermissionDenied(_("unauthorized"))
Expand Down Expand Up @@ -104,6 +117,8 @@ class Mutation(graphene.ObjectType):
update_Ticket = UpdateTicketMutation.Field()
delete_Ticket = DeleteTicketMutation.Field()

create_comment = CreateCommentMutation.Field()

# create_ticket_attachment = CreateTicketAttachmentMutation.Field()
# update_ticket_attachment = UpdateTicketAttachmentMutation.Field()

Expand Down
Loading

0 comments on commit 1ac5ea5

Please sign in to comment.