Skip to content

Commit

Permalink
systemfields: add parent community
Browse files Browse the repository at this point in the history
  • Loading branch information
jrcastro2 committed Feb 7, 2024
1 parent f94fb10 commit 269fdfe
Show file tree
Hide file tree
Showing 8 changed files with 202 additions and 0 deletions.
2 changes: 2 additions & 0 deletions invenio_communities/communities/records/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from . import models
from .systemfields.access import CommunityAccessField
from .systemfields.deletion_status import CommunityDeletionStatusField
from .systemfields.parent_community import ParentCommunityField
from .systemfields.pidslug import PIDSlugField
from .systemfields.tombstone import TombstoneField

Expand All @@ -52,6 +53,7 @@ class Community(Record):
id = ModelField()
slug = ModelField()
pid = PIDSlugField("id", "slug")
parent = ParentCommunityField()

schema = ConstantField("$schema", "local://communities/communities-v1.0.0.json")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,15 @@
}
}
},
"parent": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Identifier of the parent community."
}
}
},
"theme": {
"type": "object",
"description": "Community theme settings.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@
"is_deleted": {
"type": "boolean"
},
"parent": {
"type": "object",
"properties": {
"id": {"type": "keyword"}
}
},
"tombstone": {
"properties": {
"removal_reason": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@
"is_deleted": {
"type": "boolean"
},
"parent": {
"type": "object",
"properties": {
"id": {"type": "keyword"}
}
},
"tombstone": {
"properties": {
"removal_reason": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@
"is_deleted": {
"type": "boolean"
},
"parent": {
"type": "object",
"properties": {
"id": {"type": "keyword"}
}
},
"tombstone": {
"properties": {
"removal_reason": {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# -*- coding: utf-8 -*-
#
# This file is part of Invenio.
# Copyright (C) 2022 CERN.
#
# Invenio is free software; you can redistribute it and/or modify it
# under the terms of the MIT License; see LICENSE file for more details.

"""Community PID slug field."""
from uuid import UUID

from invenio_records.systemfields import SystemField
from sqlalchemy.orm.exc import NoResultFound


def is_valid_uuid(value):
"""Check if the provided value is a valid UUID."""
try:
UUID(str(value))
return True
except (ValueError, AttributeError, TypeError):
return False


class ParentCommunityField(SystemField):
"""System field for parent community."""

def __init__(self, key="parent"):
"""Create a new ParentCommunityField instance."""
super().__init__(key=key)

def obj(self, instance):
"""Get the access object."""
obj = self._get_cache(instance)
if obj is not None:
return obj

value = self.get_dictkey(instance)
if value:
obj = instance.get_record(value["id"])
else:
obj = None

self._set_cache(instance, obj)
return obj

def set_obj(self, record, obj):
"""Set the access object."""
# Check if obj is None and remove 'parent' key from record
if obj is None:
record.pop("parent", None)
return
if is_valid_uuid(obj):
try:
# Attempt to retrieve the community to confirm its existence
parent_community = record.get_record(obj)
record["parent"] = {"id": str(parent_community.id)}
self._set_cache(record, parent_community)
except NoResultFound as e:
raise ValueError("Community does not exist.") from e
elif isinstance(obj, type(record)):
record["parent"] = {"id": str(obj.id)}
else:
raise ValueError("Invalid parent community.")

def __get__(self, record, owner=None):
"""Get the record's access object."""
if record is None:
# access by class
return self

# access by object
return self.obj(record)

def __set__(self, record, obj):
"""Set the records access object."""
self.set_obj(record, obj)
24 changes: 24 additions & 0 deletions tests/communities/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
from invenio_records_resources.proxies import current_service_registry
from invenio_vocabularies.contrib.affiliations.api import Affiliation

from invenio_communities.communities.records.api import Community


@pytest.fixture()
def affiliation(app, db, superuser_identity):
Expand Down Expand Up @@ -50,3 +52,25 @@ def client_with_login(client, users):
login_user(user, remember=True)
login_user_via_session(client, email=user.email)
return client


@pytest.fixture(scope="module")
def parent_community(community_service, owner, minimal_community, location):
"""A community."""
minimal_community["slug"] = "parent"
minimal_community["title"] = "Parent Community"
c = community_service.create(owner.identity, minimal_community)
Community.index.refresh()
owner.refresh()
return c._record


@pytest.fixture(scope="module")
def child_community(community_service, owner, minimal_community, location):
"""A community."""
minimal_community["slug"] = "child"
minimal_community["title"] = "Child Community"
c = community_service.create(owner.identity, minimal_community)
Community.index.refresh()
owner.refresh()
return c._record
72 changes: 72 additions & 0 deletions tests/communities/test_parent_community.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2023 CERN.
#
# Invenio-Communities is free software; you can redistribute it and/or modify
# it under the terms of the MIT License; see LICENSE file for more details.

"""Test parent community."""

import pytest

from invenio_communities.communities.records.api import Community


def clean_child_comm(comm, db):
"""Remove parent from community."""
comm.parent = None
comm.commit()
db.session.commit()


def test_set_parent_community_with_comm_obj(parent_community, child_community, db):
child_community.parent = parent_community

assert child_community.parent == parent_community

child_community.commit()
db.session.commit()

comm = Community.get_record(str(child_community.id))
assert comm.parent == parent_community

clean_child_comm(comm, db)


def test_set_parent_community_with_comm_uuid(parent_community, child_community, db):
child_community.parent = parent_community.id

assert child_community.parent == parent_community

child_community.commit()
db.session.commit()

comm = Community.get_record(str(child_community.id))
assert comm.parent == parent_community

clean_child_comm(comm, db)


def test_set_parent_community_with_comm_uuid_string(
parent_community, child_community, db
):
child_community.parent = str(parent_community.id)

assert child_community.parent == parent_community

child_community.commit()
db.session.commit()
comm = Community.get_record(str(child_community.id))
assert comm.parent == parent_community

clean_child_comm(comm, db)


def test_invalid_set_parent_community_with_comm_slug(parent_community, child_community):
with pytest.raises(ValueError, match="Invalid parent community."):
child_community.parent = parent_community.slug


def test_invalid_set_parent_community_with_random_object(child_community):
with pytest.raises(ValueError, match="Invalid parent community."):
child_community.parent = dict(test="test")

0 comments on commit 269fdfe

Please sign in to comment.