Skip to content

Commit

Permalink
Merge pull request #75 from JSv4/JSv4/add-gui-elements-to-create-meta…
Browse files Browse the repository at this point in the history
…data-labels

Add GUI Elements to Filter on Metadata and Thumbnails for Docs
  • Loading branch information
JSv4 committed Feb 18, 2023
2 parents 4635f17 + deb5853 commit d349fb3
Show file tree
Hide file tree
Showing 58 changed files with 704 additions and 234 deletions.
1 change: 1 addition & 0 deletions .github/workflows/backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ name: Backend CI
env:
DOCKER_BUILDKIT: 1
COMPOSE_DOCKER_CLI_BUILD: 1
SKLEARN_ALLOW_DEPRECATED_SKLEARN_PACKAGE_INSTALL: True

defaults:
run:
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ repos:
- id: black

- repo: https://github.com/PyCQA/isort
rev: 5.10.1
rev: 5.12.0
hooks:
- id: isort

Expand Down
5 changes: 4 additions & 1 deletion compose/local/django/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ RUN apt-get update && apt-get install --no-install-recommends -y \
git \
poppler-utils \
tesseract-ocr \
libtesseract-dev \
libtesseract-dev \
ffmpeg \
libsm6 \
libxext6 \
# cleaning up unused files
&& apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
&& rm -rf /var/lib/apt/lists/*
Expand Down
23 changes: 17 additions & 6 deletions config/graphql/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@
import logging
from abc import ABC

import django.db.models
import graphene
from graphene.relay import Node
from graphene_django import DjangoObjectType
from graphql_jwt.decorators import login_required
from graphql_relay import from_global_id
from graphql_relay import from_global_id, to_global_id

from opencontractserver.shared.resolvers import resolve_single_oc_model_from_id
from opencontractserver.utils.data_types import PermissionTypes
from opencontractserver.utils.permissioning_utils import (
from opencontractserver.types.enums import PermissionTypes
from opencontractserver.utils.permissioning import (
set_permissions_for_obj_to_user,
user_has_permission_for_obj,
)
Expand Down Expand Up @@ -115,22 +117,25 @@ def mutate(cls, root, info, *args, **kwargs):

class DRFMutation(graphene.Mutation):
class IOSettings(ABC):
pk_fields = []
pk_fields: list[str | int] = []
lookup_field = "id"
model = None
model: django.db.models.Model = None
graphene_model: DjangoObjectType = None
serializer = None

class Arguments(ABC):
pass

ok = graphene.Boolean()
message = graphene.String()
obj_id = graphene.ID()

@classmethod
@login_required
def mutate(cls, root, info, *args, **kwargs):

ok = False
obj_id = None

try:
logger.info("Test if context has user")
Expand Down Expand Up @@ -196,6 +201,9 @@ def mutate(cls, root, info, *args, **kwargs):
obj_serializer.save()
ok = True
message = "Success"
obj_id = to_global_id(
cls.IOSettings.graphene_model.__class__.__name__, obj.id
)
logger.info("Succeeded updating obj")

else:
Expand All @@ -215,8 +223,11 @@ def mutate(cls, root, info, *args, **kwargs):

ok = True
message = "Success"
obj_id = to_global_id(
cls.IOSettings.graphene_model.__class__.__name__, obj.id
)

except Exception as e:
message = f"Mutation failed due to error: {e}"

return cls(ok=ok, message=message)
return cls(ok=ok, message=message, obj_id=obj_id)
20 changes: 16 additions & 4 deletions config/graphql/mutations.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from django.utils import timezone
from graphene.types.generic import GenericScalar
from graphql_jwt.decorators import login_required, user_passes_test
from graphql_relay import from_global_id
from graphql_relay import from_global_id, to_global_id

from config.graphql.base import DRFDeletion, DRFMutation
from config.graphql.graphene_types import (
Expand Down Expand Up @@ -56,9 +56,9 @@
make_analysis_public_task,
make_corpus_public_task,
)
from opencontractserver.types.enums import PermissionTypes
from opencontractserver.users.models import UserExport
from opencontractserver.utils.data_types import PermissionTypes
from opencontractserver.utils.permissioning_utils import (
from opencontractserver.utils.permissioning import (
set_permissions_for_obj_to_user,
user_has_permission_for_obj,
)
Expand Down Expand Up @@ -132,6 +132,7 @@ class IOSettings:
lookup_field = "id"
serializer = LabelsetSerializer
model = LabelSet
graphene_model = LabelSetType

class Arguments:
id = graphene.String(required=True)
Expand Down Expand Up @@ -303,6 +304,7 @@ class IOSettings:
lookup_field = "id"
serializer = DocumentSerializer
model = Document
graphene_model = DocumentType

class Arguments:
id = graphene.String(required=True)
Expand Down Expand Up @@ -883,6 +885,7 @@ class IOSettings:
lookup_field = "id"
serializer = AnnotationSerializer
model = Annotation
graphene_model = AnnotationType

class Arguments:
id = graphene.String(required=True)
Expand Down Expand Up @@ -979,6 +982,7 @@ class IOSettings:
pk_fields = ["label_set"]
serializer = CorpusSerializer
model = Corpus
graphene_model = CorpusType

class Arguments:
title = graphene.String(required=False)
Expand All @@ -993,6 +997,7 @@ class IOSettings:
pk_fields = ["label_set"]
serializer = CorpusSerializer
model = Corpus
graphene_model = CorpusType

class Arguments:
id = graphene.String(required=True)
Expand All @@ -1016,6 +1021,7 @@ class IOSettings:
pk_fields = []
serializer = AnnotationLabelSerializer
model = AnnotationLabel
graphene_model = AnnotationLabelType

class Arguments:
text = graphene.String(required=False)
Expand All @@ -1031,6 +1037,7 @@ class IOSettings:
serializer = AnnotationLabelSerializer
lookup_field = "id"
model = AnnotationLabel
graphene_model = AnnotationLabelType

class Arguments:
id = graphene.String(required=True)
Expand Down Expand Up @@ -1094,12 +1101,14 @@ class Arguments:
ok = graphene.Boolean()
message = graphene.String()
obj = graphene.Field(AnnotationLabelType)
obj_id = graphene.ID()

@login_required
def mutate(root, info, labelset_id, text, description, color, icon, label_type):

ok = False
obj = None
obj_id = None

try:
labelset = LabelSet.objects.get(
Expand All @@ -1114,6 +1123,7 @@ def mutate(root, info, labelset_id, text, description, color, icon, label_type):
label_type=label_type,
creator=info.context.user,
)
obj_id = to_global_id("AnnotationLabelType", obj.id)
logger.debug("CreateLabelForLabelsetMutation - mutate / Created label", obj)

set_permissions_for_obj_to_user(
Expand All @@ -1131,7 +1141,9 @@ def mutate(root, info, labelset_id, text, description, color, icon, label_type):
except Exception as e:
message = f"Failed to create label for labelset due to error: {e}"

return CreateLabelForLabelsetMutation(obj=obj, message=message, ok=ok)
return CreateLabelForLabelsetMutation(
obj=obj, obj_id=obj_id, message=message, ok=ok
)


class StartCorpusAnalysisMutation(graphene.Mutation):
Expand Down
2 changes: 1 addition & 1 deletion config/graphql/permission_annotator/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from config.graphql.permission_annotator.middleware import (
get_permissions_for_user_on_model_in_app,
)
from opencontractserver.utils.data_types import PermissionTypes
from opencontractserver.types.enums import PermissionTypes

User = get_user_model()

Expand Down
4 changes: 2 additions & 2 deletions config/graphql/queries.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
from opencontractserver.corpuses.models import Corpus
from opencontractserver.documents.models import Document
from opencontractserver.shared.resolvers import resolve_oc_model_queryset
from opencontractserver.types.enums import LabelType
from opencontractserver.users.models import Assignment, UserExport, UserImport
from opencontractserver.utils.data_types import LabelType

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -109,7 +109,7 @@ def resolve_bulk_doc_relationships_in_corpus(self, info, corpus_id, document_id)

bulk_doc_annotations_in_corpus = graphene.Field(
graphene.List(AnnotationType),
corpus_id=graphene.String(required=True),
corpus_id=graphene.ID(required=True),
document_id=graphene.ID(required=False),
for_analysis_ids=graphene.String(required=False),
label_type=graphene.List(label_type_enum),
Expand Down
14 changes: 0 additions & 14 deletions config/graphql_api_key_auth/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +0,0 @@
# Copyright (C) 2022 John Scrudato / Gordium Knot Inc. d/b/a OpenSource.Legal
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
15 changes: 0 additions & 15 deletions config/graphql_api_key_auth/backends.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,10 @@
# Copyright (C) 2022 John Scrudato / Gordium Knot Inc. d/b/a OpenSource.Legal
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
from django.conf import settings

# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
from django.contrib.auth import get_user_model
from django.utils.translation import gettext_lazy as _
from rest_framework import exceptions

from config.graphql_api_key_auth.utils import get_authorization_header

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.


UserModel = get_user_model()


Expand Down
30 changes: 25 additions & 5 deletions config/graphql_api_key_auth/middleware.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
from django.contrib.auth import authenticate
from django.contrib.auth import authenticate, get_user_model

from config.graphql_api_key_auth.utils import get_http_authorization, get_token_argument

User = get_user_model()


def _context_has_user(request):
return hasattr(request, "user") and request.user.is_authenticated


def _authenticate(request):
is_anonymous = not hasattr(request, "user") or request.user.is_anonymous
is_anonymous = _context_has_user(request)
return is_anonymous and get_http_authorization(request) is not None


Expand All @@ -21,16 +27,30 @@ def authenticate_context(self, info, **kwargs):

def resolve(self, next, root, info, **kwargs):

# Check to see if user already on context

if "user" in info.context.POST:
existing_user = info.context.POST["user"]
if (
existing_user is not None
and isinstance(existing_user, User)
and existing_user.is_authenticated
):
return next(root, info, **kwargs)

context = info.context
token_argument = get_token_argument(context, **kwargs)

if (
_authenticate(context) or token_argument is not None
) and self.authenticate_context(info, **kwargs):

user = authenticate(request=context, **kwargs)
# If we already have an authenticated user for our request, don't bother re-authenticating
# same request. This was causing a massive performance hit.
if not _context_has_user(context):
user = authenticate(request=context, **kwargs)

if user is not None:
context.user = user
if user is not None:
context.user = user

return next(root, info, **kwargs)
4 changes: 2 additions & 2 deletions config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,10 +403,10 @@
CELERY_RESULT_SERIALIZER = "json"
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-time-limit
# TODO: set to whatever value is adequate in your circumstances
CELERY_TASK_TIME_LIMIT = 5 * 3600
# CELERY_TASK_TIME_LIMIT = 5 * 3600
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#task-soft-time-limit
# TODO: set to whatever value is adequate in your circumstances
CELERY_TASK_SOFT_TIME_LIMIT = 3600
# CELERY_TASK_SOFT_TIME_LIMIT = 3600
# http://docs.celeryproject.org/en/latest/userguide/configuration.html#beat-scheduler
CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler"
CELERY_WORKER_MAX_MEMORY_PER_CHILD = 1024000
Expand Down
7 changes: 6 additions & 1 deletion config/settings/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
# django-extensions
# ------------------------------------------------------------------------------
# https://django-extensions.readthedocs.io/en/latest/installation_instructions.html#configuration
INSTALLED_APPS += ["django_extensions"] # noqa F405
INSTALLED_APPS += ["django_extensions", "silk"] # noqa F405

# Celery
# ------------------------------------------------------------------------------
Expand All @@ -57,3 +57,8 @@

# Your stuff...
# ------------------------------------------------------------------------------
MIDDLEWARE += [
"django_cprofile_middleware.middleware.ProfilerMiddleware",
"silk.middleware.SilkyMiddleware",
]
SILKY_PYTHON_PROFILER = True
3 changes: 2 additions & 1 deletion config/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path
from django.urls import include, path
from django.views import defaults as default_views
from django.views.decorators.csrf import csrf_exempt
from graphene_django.views import GraphQLView
Expand All @@ -26,6 +26,7 @@
[]
if not settings.DEBUG
else [
path("silk/", include("silk.urls", namespace="silk")),
path(
"400/",
default_views.bad_request,
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/assets/configurations/menus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export const header_menu_items = [
id: "label_set_menu_button",
},
{
title: "Provisions",
title: "Annotations",
route: "/annotations/",
protected: false,
id: "annotation_menu_button",
Expand Down
Loading

0 comments on commit d349fb3

Please sign in to comment.