Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into invitation-modal
Browse files Browse the repository at this point in the history
  • Loading branch information
Ducica committed Oct 1, 2024
2 parents a7dfdfb + d18aafb commit fa2d38d
Show file tree
Hide file tree
Showing 11 changed files with 375 additions and 58 deletions.
12 changes: 11 additions & 1 deletion oarepo_communities/ext.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from functools import cached_property

from flask_principal import identity_loaded

import oarepo_communities.cli # noqa - imported to register CLI commands

from .resources.community_records.config import CommunityRecordsResourceConfig
from .resources.community_records.resource import CommunityRecordsResource
from .services.community_inclusion.service import CommunityInclusionService
from .services.community_records.config import CommunityRecordsServiceConfig
from .services.community_records.service import CommunityRecordsService
from .utils import get_urlprefix_service_id_mapping
from .utils import get_urlprefix_service_id_mapping, load_community_user_needs
from .workflow import community_default_workflow


Expand All @@ -24,6 +26,7 @@ def init_app(self, app):
self.app = app
self.init_services(app)
self.init_resources(app)
self.init_hooks(app)
self.init_config(app)
app.extensions["oarepo-communities"] = self

Expand Down Expand Up @@ -80,6 +83,13 @@ def init_resources(self, app):
service=self.community_records_service,
)

def init_hooks(self, app):
"""Initialize hooks."""

@identity_loaded.connect_via(app)
def on_identity_loaded(_, identity):
load_community_user_needs(identity)

def get_default_community_from_record(self, record, **kwargs):
record = record.parent if hasattr(record, "parent") else record
try:
Expand Down
9 changes: 5 additions & 4 deletions oarepo_communities/services/links.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
from copy import deepcopy
from typing import Dict

from uritemplate import URITemplate
from invenio_records_resources.services.base.links import preprocess_vars, Link
from invenio_communities.communities.records.api import Community
from invenio_records_resources.services.base.links import Link, preprocess_vars
from uritemplate import URITemplate


class CommunitiesLinks(Link):
"""Utility class for keeping track of and resolve links."""

def __init__(self, uritemplate_strs: Dict, when=None, vars=None):
"""Constructor."""
self._uritemplates = {k: URITemplate(v) for k,v in uritemplate_strs.items()}
self._uritemplates = {k: URITemplate(v) for k, v in uritemplate_strs.items()}
self._when_func = when
self._vars_func = vars

Expand All @@ -31,4 +32,4 @@ def expand(self, obj, context):
link = uritemplate.expand(**vars)
community_links[link_name] = link
links[community_id] = community_links
return links
return links
64 changes: 64 additions & 0 deletions oarepo_communities/services/permissions/generators.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import abc
import uuid
from collections import namedtuple
from functools import partial, reduce

from invenio_access.permissions import system_identity
from invenio_communities.communities.records.api import Community
from invenio_communities.generators import CommunityRoleNeed, CommunityRoles
from invenio_communities.proxies import current_communities, current_roles
from invenio_records_permissions.generators import Generator
from invenio_search.engine import dsl
from oarepo_workflows.errors import MissingWorkflowError
from oarepo_workflows.requests.policy import RecipientGeneratorMixin
from oarepo_workflows.services.permissions.generators import WorkflowPermission
Expand All @@ -16,6 +19,9 @@
)
from oarepo_communities.proxies import current_oarepo_communities

_Need = namedtuple("Need", ["method", "user", "community"])
UserInCommunityNeed = partial(_Need, "user_in_community")


class InAnyCommunity(Generator):
def __init__(self, permission_generator, **kwargs):
Expand Down Expand Up @@ -194,3 +200,61 @@ def roles(self, **kwargs):


PrimaryCommunityMembers = DefaultCommunityMembers


class RecordOwnerInDefaultRecordCommunity(DefaultCommunityRoleMixin, Generator):
default_or_ids = "default"

def _record_communities(self, record, **kwargs):
return set(self._get_record_communities(record, **kwargs))

def needs(self, record=None, **kwargs):
record_communities = set(self._get_record_communities(record, **kwargs))
return self._needs(record_communities, record=record)

def _needs(self, record_communities, record=None):
owners = getattr(record.parent, "owners", None)
ret = []
for owner in owners:
ret += [
UserInCommunityNeed(owner.id, community)
for community in record_communities
]
return ret

def query_filter(self, identity=None, **kwargs):
"""Filters for current identity as owner."""
user_in_communities = {
(n.user, n.community)
for n in identity.provides
if n.method == "user_in_community"
}
terms = []
for element in user_in_communities:
terms.append(
dsl.Q("term", **{"parent.owners.user": element[0]})
& dsl.Q(
"term", **{f"parent.communities.{self.default_or_ids}": element[1]}
)
)
if not terms:
return []
query = reduce(lambda f1, f2: f1 | f2, terms)
return query


RecordOwnerInPrimaryRecordCommunity = RecordOwnerInDefaultRecordCommunity


class RecordOwnerInRecordCommunity(
CommunityRoleMixin, RecordOwnerInDefaultRecordCommunity
):
default_or_ids = "ids"

# trick to use CommunityRoleMixin instead of DefaultCommunityRoleMixin
def _record_communities(self, record, **kwargs):
return set(self._get_record_communities(record, **kwargs))

def needs(self, record=None, **kwargs):
record_communities = set(self._get_record_communities(record, **kwargs))
return self._needs(record_communities, record=record)
5 changes: 4 additions & 1 deletion oarepo_communities/services/permissions/policy.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from oarepo_requests.services.permissions.workflow_policies import RequestBasedWorkflowPermissions
from oarepo_requests.services.permissions.workflow_policies import (
RequestBasedWorkflowPermissions,
)
from oarepo_workflows.services.permissions.policy import WorkflowPermissionPolicy

from oarepo_communities.services.permissions.generators import (
Expand All @@ -21,6 +23,7 @@ class MyWorkflowPermissions(CommunityDefaultWorkflowPermissions):
)
}
"""

can_create = [
DefaultCommunityMembers(),
]
Expand Down
59 changes: 31 additions & 28 deletions oarepo_communities/ui/oarepo_communities/__init__.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,46 @@
from oarepo_global_search.ui.config import (
GlobalSearchUIResourceConfig,
GlobalSearchUIResource,
)
from flask import g
from flask_menu import current_menu
import marshmallow as ma
from flask import g, redirect, url_for
from flask_login import login_required
from oarepo_runtime.i18n import lazy_gettext as _
from flask import redirect, url_for
from flask_resources import resource_requestctx
from flask_menu import current_menu
from flask_resources import from_conf, request_parser, resource_requestctx
from invenio_communities.communities.resources.serializer import (
UICommunityJSONSerializer,
)
from invenio_communities.views.communities import (
communities_settings as invenio_communities_settings,
communities_settings_pages as invenio_communities_settings_pages,
members as invenio_communities_members,
communities_curation_policy as invenio_communities_curation_policy,
communities_about as invenio_communities_about,
)
from invenio_communities.views.communities import (
communities_curation_policy as invenio_communities_curation_policy,
)
from invenio_communities.views.communities import (
communities_frontpage as invenio_communities_frontpage,
communities_search as invenio_communities_search,
)
from invenio_communities.views.communities import (
communities_new as invenio_communities_new,
)


from invenio_communities.views.communities import (
communities_search as invenio_communities_search,
)
from invenio_communities.views.communities import (
communities_settings as invenio_communities_settings,
)
from invenio_communities.views.communities import (
communities_settings_pages as invenio_communities_settings_pages,
)
from invenio_communities.views.communities import members as invenio_communities_members
from invenio_communities.views.ui import (
_has_about_page_content,
_has_curation_policy_page_content,
)

from flask_resources import request_parser, from_conf

from .components import GetCommunityComponent

from invenio_records_resources.resources.records.resource import (
request_view_args,
)
from invenio_records_resources.proxies import current_service_registry

from invenio_communities.communities.resources.serializer import (
UICommunityJSONSerializer,
from invenio_records_resources.resources.records.resource import request_view_args
from oarepo_global_search.ui.config import (
GlobalSearchUIResource,
GlobalSearchUIResourceConfig,
)
import marshmallow as ma
from oarepo_runtime.i18n import lazy_gettext as _

from .components import GetCommunityComponent


class CommunityValidationSchema(ma.Schema):
Expand Down
13 changes: 5 additions & 8 deletions oarepo_communities/ui/oarepo_communities/components.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
from oarepo_ui.resources.components import UIResourceComponent
from invenio_records_resources.proxies import current_service_registry
from invenio_communities.views.communities import (
HEADER_PERMISSIONS,
)
from flask import request
from invenio_communities.views.communities import HEADER_PERMISSIONS
from oarepo_ui.resources.components import UIResourceComponent


class GetCommunityComponent(UIResourceComponent):
Expand All @@ -18,6 +15,6 @@ def before_ui_search(
permissions = community.has_permissions_to(HEADER_PERMISSIONS)
extra_context["community"] = community
extra_context["permissions"] = permissions
search_options["overrides"]["ui_endpoint"] = (
f"/communities/{community.id}/records"
)
search_options["overrides"][
"ui_endpoint"
] = f"/communities/{community.id}/records"
42 changes: 40 additions & 2 deletions oarepo_communities/utils.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,47 @@
from flask import current_app
from flask import current_app, session
from invenio_communities.communities.records.api import Community
from invenio_communities.proxies import current_communities
from invenio_communities.proxies import current_communities, current_identities_cache
from invenio_communities.utils import identity_cache_key
from invenio_records_resources.proxies import current_service_registry

from oarepo_communities.proxies import current_oarepo_communities
from oarepo_communities.services.permissions.generators import UserInCommunityNeed


def get_community_needs_for_identity(identity):
# see invenio_communities.utils.load_community_needs
if identity.id is None:
# no user is logged in
return

cache_key = identity_cache_key(identity)
community_roles = current_identities_cache.get(cache_key)
if community_roles is None:
# aka Member.get_memberships(identity)
roles_ids = session.get("unmanaged_roles_ids", [])

member_cls = current_communities.service.members.config.record_cls
managed_community_roles = member_cls.get_memberships(identity)
unmanaged_community_roles = member_cls.get_memberships_from_group_ids(
identity, roles_ids
)
community_roles = managed_community_roles + unmanaged_community_roles

current_identities_cache.set(
cache_key,
community_roles,
)
return community_roles


def load_community_user_needs(identity):
# todo assuming there's one user and identity_id = user_id
community_roles = get_community_needs_for_identity(identity)
if not community_roles:
return
communities = {community_role[0] for community_role in community_roles}
needs = {UserInCommunityNeed(identity.id, community) for community in communities}
identity.provides |= needs


def get_associated_service(record_service, service_type):
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = oarepo-communities
version = 5.0.15
version = 5.0.16
description =
authors = Ronald Krist <[email protected]>
readme = README.md
Expand Down
Loading

0 comments on commit fa2d38d

Please sign in to comment.