Hi
under admin/config/services/rest there are some endpoints for Rest. I can enable all the settings for GET, POST, etc..

/group/{group}/content/{group_content}

I just cannot find an example on how to use it in order to create a new group node.

Creating a node by clicking uses this link:

https://www.example.com/group/4/content/create/group_node:article

What is the proper REST/url instead of /entity/node which is used for creating non-group nodes POST.

Could someone who knows the magic please add it this documentation?

https://www.drupal.org/docs/8/core/modules/rest/javascript-and-drupal-8-...

A regular node gets REST-created this way:

Create article
POST: http://example.com/entity/node
Content-type: application/json

{
  "type":[{"target_id":"article"}],
  "title":[{"value":"Hello World"}],
  "body":[{"value":"How are you?"}]
}

How do I create a group-article?

POST: http://example.com/???
Content-type: application/json

{
  "type":[{"target_id":"article"}],
  "title":[{"value":"Hello World"}],
  "body":[{"value":"How are you?"}]
}

What informations are required? URL? UUID of group? ...?

Issue fork group-2872645

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

maxilein created an issue. See original summary.

maxilein’s picture

Issue summary: View changes
maxilein’s picture

Issue summary: View changes
maxilein’s picture

... /node/group/4/content/create/group_node:article

page not found

noblescz’s picture

I have the same problem. Usually I get the fields by calling GET of the API and I receive the object containing all the fields.

In this case I end up with error:

The website encountered an unexpected error. Please try again later.

Recoverable fatal error: Argument 1 passed to Drupal\rest\Plugin\rest\resource\EntityResource::get() must implement interface Drupal\Core\Entity\EntityInterface, string given in
Drupal\rest\Plugin\rest\resource\EntityResource->get() (line
122 of
core/modules/rest/src/Plugin/rest/resource/EntityResource.php).

When calling:
/group/2/content/5?_format=hal_json

I don't know if it is problem of the core, or of the group_node module, but this way we can't get the info about the object.

maxilein’s picture

GET with a group/content does work for me.
I am using D 8.3.1. and the latest beta of Group.

I just do not know how to write the JSON for the POST.

noblescz’s picture

Ok, then I have some other problem - I am on the same version 8.3.1. of Drupal and I using _format=hal_json and basic auth and I am getting this error.

But I just realized, that GET object would not help us. I was expecting, that the relation is hidden in "_embedded": part of the node, but in fact it is not in the node, but somewhere else in "group content" tables.

May be it should be posted as a regular node and then added to group using "Relate node", which is not implemented in the API yet. But it is just a wild guess.

maxilein’s picture

I figure so, too. But I have no clue where to look..

The link under the group nodes list to edit a node is the regular link.
Which is ok. Creating a node like that.

Just how do you assign a node to a group then?
That is something that is missing terribly in the groups concept:
1. create a node the normal way, then 2. selecting its' group association.

Now there are too many clicks involved (see https://www.drupal.org/node/2864253)

Are there any rules to assign a node to a group?
How do you do it programmatically?

noblescz’s picture

Workaround - programatically you can add node to group:


use Drupal\group\Entity;
use Drupal\group\Entity\Group;

$node = Node::load($node_id);
$plugin_id = 'group_node:' . $node->bundle();
$group = Group::load($group_id);
$group->addContent($node,$plugin_id);
    
maxilein’s picture

Thanks!

maxilein’s picture

Still, I would like to know the status of REST /JSON support in groups ...
Do you have any idea?

noblescz’s picture

I think we should be able to find the right POST path our selves by studying the architecture. It seems, that Entity brings automatically REST calls functionality and the only missing part are the routes, so may be a little patch would do...

I was trying to decode the source code of the Group module, but I am still not completely familiar with all the structure theory, so I got lost. I don't have time to study it further now, so we will have to wait for the maintainers of the project.

maxilein’s picture

Same with me: I got completely disoriented on the way ... ;-(

maxilein’s picture

tpzurdo’s picture

Is there any update on this issue?
I'm also trying to post an entity related to a group using this endpoint '/entity/group_content?_format=json'
I''ve also tried the regular REST endpoint '/entity/node?_format=json' but group users receive a 403 because they can't publish any kind of content according to regular Drupal Permission settings.

Actually I can use the interface for publishing related nodes without problems.

jeremdow’s picture

I had better luck with this using JSON API, but ultimately stymied on posting members and related content, something similar to #2862846.

Enable /entity/group_content_type/{group_content_type} and do a GET request to that, it will show the machine names of the group_content bundles that you need to target in the other calls (GET seems to work fine, POST and PATCH, not so much, or at least I couldn't work it out.)

u_batin’s picture

I'm having same issue. I using JSONAPI to create group content. I 'm try to POST tohttp://example.com/jsonapi/group_content/{GROUP TYPE}-group_node-article with -

{
  "data": {
    "type": "group_content--{GROUP TYPE}-group_node-article",
    "attributes": {
      "label": "Simple Title"
    }
  }
}

Server response with 500 Internal Server Error status code.

How can I solve this issue?

jlscott’s picture

I have a group type of "client" and a node of type "typeface_asset" and am trying to assign the node to the group using jsonapi calls.

The POST request is:

http://vmgportal/jsonapi/group_content/client-group_node-typeface_asset?...

The headers specified are:

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1N....
Content-type: application/vnd.api+json

The request body is:

{
    "data": {
        "type": "group_content--client-group_node-typeface_asset",
        "attributes": {
            "langcode": "en",
            "label": "My new typeface to client via jsonapi",
            "path": null,
            "default_langcode": "1"
        },
        "relationships": {
            "type": {
                "data": {
                    "type": "group_content_type--group_content_type",
                    "id": "client-group_node-typeface_asset"
                }
            },
            "gid": {
                "data": {
                    "type": "group--client",
                    "id": "1"
                }
            },
            "entity_id": {
                "data": {
                    "type": "node--typeface_asset",
                    "id": "27"
                }
            },
            "uid": {
                "data": {
                    "type": "user--user",
                    "id": "7"
                }
            }
        }
    }
}

and I get the response:

The website encountered an unexpected error. Please try again later.

The Drupal watchdog log reports two error messages:

Notice: Undefined index: group in Drupal\group\Entity\Access\GroupContentAccessControlHandler->checkCreateAccess() (line 30 of /home/james/vmg/vmgportal/docroot/modules/contrib/group/src/Entity/Access/GroupContentAccessControlHandler.php)

TypeError: Argument 1 passed to Drupal\group\Plugin\GroupContentEnablerBase::createAccess() must implement interface Drupal\group\Entity\GroupInterface, null given, called in /home/james/vmg/vmgportal/docroot/modules/contrib/group/src/Entity/Access/GroupContentAccessControlHandler.php on line 30 in Drupal\group\Plugin\GroupContentEnablerBase->createAccess() (line 321 of /home/james/vmg/vmgportal/docroot/modules/contrib/group/src/Plugin/GroupContentEnablerBase.php)

I get the same results whether I use id values for the relationships in the request body (as shown above), or UUID values.

I can successfully retrieve the client group, and the group contents of nodes already related to the group via jsonapi calls.

worthwhileindustries’s picture

The naming on these is hard to map.

/group/{group} translates to /group/1 (which is really the group id and I get a proper response)

can someone tell me what {group_content} translates to?

/group/{group}/content/{group_content}

mibstar’s picture

I'm having the same issue and the workaround in #9 is not an option for me.

I have the following:
Drupal 8.4.3
jsonapi 8.x-1.6

In my case I'm posting to /api/group_content/hd_family-group_node-hd_photo.

My specific error is:

TypeError: Argument 1 passed to Drupal\group\Plugin\GroupContentEnablerBase::createAccess() must implement interface Drupal\group\Entity\GroupInterface, null given, called in /var/www/html/web/modules/contrib/group/src/Entity/Access/GroupContentAccessControlHandler.php on line 30 in /var/www/html/web/modules/contrib/group/src/Plugin/GroupContentEnablerBase.php on line 321 #0 /var/www/html/web/modules/contrib/group/src/Entity/Access/GroupContentAccessControlHandler.php(30): Drupal\group\Plugin\GroupContentEnablerBase->createAccess(NULL, Object(Drupal\Core\Session\AccountProxy))"
#1 /var/www/html/web/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php(260): Drupal\group\Entity\Access\GroupContentAccessControlHandler->checkCreateAccess(Object(Drupal\Core\Session\AccountProxy), Array, 'hd_family-group...')
#2 /var/www/html/web/core/lib/Drupal/Core/Entity/ContentEntityBase.php(627): Drupal\Core\Entity\EntityAccessControlHandler->createAccess('hd_family-group...', Object(Drupal\Core\Session\AccountProxy), Array, true)
#3 /var/www/html/web/modules/contrib/jsonapi/src/Controller/EntityResource.php(173): Drupal\Core\Entity\ContentEntityBase->access('create', NULL, true)
#4 [internal function]: Drupal\jsonapi\Controller\EntityResource->createIndividual(Object(Drupal\group\Entity\GroupContent), Object(Symfony\Component\HttpFoundation\Request))
#5 /var/www/html/web/modules/contrib/jsonapi/src/Controller/RequestHandler.php(89): call_user_func_array(Array, Array)
#6 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(576): Drupal\jsonapi\Controller\RequestHandler->Drupal\jsonapi\Controller\{closure}()
#7 /var/www/html/web/modules/contrib/jsonapi/src/Controller/RequestHandler.php(90): Drupal\Core\Render\Renderer->executeInRenderContext(Object(Drupal\Core\Render\RenderContext), Object(Closure))
#8 [internal function]: Drupal\jsonapi\Controller\RequestHandler->handle(Object(Drupal\Core\Routing\RouteMatch), Object(Symfony\Component\HttpFoundation\Request))
#9 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array)
#10 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(576): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#11 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(124): Drupal\Core\Render\Renderer->executeInRenderContext(Object(Drupal\Core\Render\RenderContext), Object(Closure))
#12 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array)
#13 [internal function]: Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#14 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(153): call_user_func_array(Object(Closure), Array)
#15 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(68): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1)
#16 /var/www/html/web/modules/contrib/simple_oauth/src/HttpMiddleware/BasicAuthSwap.php(67): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#17 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Drupal\simple_oauth\HttpMiddleware\BasicAuthSwap->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#18 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\Core\StackMiddleware\Session->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#19 /var/www/html/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(99): Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#20 /var/www/html/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(78): Drupal\page_cache\StackMiddleware\PageCache->pass(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#21 /var/www/html/web/modules/contrib/jsonapi/src/StackMiddleware/FormatSetter.php(38): Drupal\page_cache\StackMiddleware\PageCache->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#22 /var/www/html/vendor/asm89/stack-cors/src/Asm89/Stack/Cors.php(49): Drupal\jsonapi\StackMiddleware\FormatSetter->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#23 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Asm89\Stack\Cors->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#24 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(50): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#25 /var/www/html/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#26 /var/www/html/web/core/lib/Drupal/Core/DrupalKernel.php(657): Stack\StackedHttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#27 /var/www/html/web/index.php(19): Drupal\Core\DrupalKernel->handle(Object(Symfony\Component\HttpFoundation\Request))
#28 {main}"

And specifically line 30 of:

modules/contrib/group/src/Entity/Access/GroupContentAccessControlHandler.php on line 30

Where $context['group'] is null which is odd as $context is an array. Not sure if the issue is this group module or jsonapi but I'd be inclined to say it's the latter based on comment https://www.drupal.org/project/jsonapi/issues/2848419#comment-11918370 by @dawehner

josueValRob’s picture

What about to create a module for rest services?.

In organic groups we have Organic services:

lawxen’s picture

@mibstar I got the same error, and create a issue about the post error.
https://www.drupal.org/project/group/issues/2942069

laboratory.mike’s picture

I have found the key steps in this issue. Its a core issue, or maybe Group needs to build around this case. First, the stack trace: starting from when the post object is received:

/var/www/d8docs/web/modules/contrib/group/src/Entity/Access/GroupContentAccessControlHandler.php) 
#0 /var/www/d8docs/web/core/includes/bootstrap.inc(582): _drupal_error_handler_real(8, 'Undefined index...', '/var/www/d8docs...', 31, Array) 
#1 /var/www/d8docs/web/modules/contrib/group/src/Entity/Access/GroupContentAccessControlHandler.php(31): _drupal_error_handler(8, 'Undefined index...', '/var/www/d8docs...', 31, Array) 
#2 /var/www/d8docs/web/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php(260): Drupal\group\Entity\Access\GroupContentAccessControlHandler->checkCreateAccess(Object(Drupal\Core\Session\AccountProxy), Array, 'kb_group-group_...')
#3 /var/www/d8docs/web/core/lib/Drupal/Core/Entity/ContentEntityBase.php(698): Drupal\Core\Entity\EntityAccessControlHandler->createAccess('kb_group-group_...', Object(Drupal\Core\Session\AccountProxy), Array, true) 
#4 /var/www/d8docs/web/core/modules/rest/src/Plugin/rest/resource/EntityResource.php(165): Drupal\Core\Entity\ContentEntityBase->access('create', NULL, true) 
#5 [internal function]: Drupal\rest\Plugin\rest\resource\EntityResource->post(Object(Drupal\group\Entity\GroupContent)) 

The key items that stuck out to me are lines #2 and #3. #3 passes an empty context array to the function at #2, which means the group context is not passed. The exact point is in core/lib/Drupal/Core/Entity/ContentEntityBase.php(698):

  public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
    if ($operation == 'create') {
      return $this->entityManager()
        ->getAccessControlHandler($this->entityTypeId)
        ->createAccess($this->bundle(), $account, [], $return_as_object); // <------ Right here!
    }
    return $this->entityManager()
      ->getAccessControlHandler($this->entityTypeId)
      ->access($this, $operation, $account, $return_as_object);

In comparison, I deliberately broke #2 by stuffing a fake function in, and here's the relevant trace when trying to create a group node via the website:

Error: Call to undefined function Drupal\Core\Entity\xqj() in Drupal\Core\Entity\EntityAccessControlHandler->createAccess() (line 230 of /var/www/d8docs/web/core/lib/Drupal/Core/Entity/EntityAccessControlHandler.php) 
#0 /var/www/d8docs/web/modules/contrib/group/src/Entity/Controller/GroupContentController.php(110): Drupal\Core\Entity\EntityAccessControlHandler->createAccess('group_content_t...', Object(Drupal\Core\Session\AccountProxy), Array, true) 
#1 /var/www/d8docs/web/modules/contrib/group/modules/gnode/src/Controller/GroupNodeController.php(62): Drupal\group\Entity\Controller\GroupContentController->addPage(Object(Drupal\group\Entity\Group), true) 
#2 [internal function]: Drupal\gnode\Controller\GroupNodeController->addPage(Object(Drupal\group\Entity\Group), true) 
#3 /var/www/d8docs/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array)

The takeaway is, the programmatic versus web versions are coming to the same access function by different routes,, which means that either Drupal needs to change how post requests are handled, Group needs to make a different endpoint to get around the issue, or maybe there's a way to register with the REST apis so that the group context is passed correctly.

laboratory.mike’s picture

Component: Documentation » Code

I also wanted to add a comment that I could pay for some support on this issue, as I need the functionality and would rather not spend a couple of months working it out myself, if possible.

joaogarin’s picture

Hello,

I am getting the same :

TypeError: Argument 1 passed to Drupal\group\Plugin\GroupContentEnablerBase::createAccess() must implement interface Drupal\group\Entity\GroupInterface, null given

Using graphql with the groups module in a decoupled project. Any chances on a pointer where this could be fixed ? I could work on a patch to handle this, but would need a bit of guidance most likely on where to tackle it.

Best regards
Joao Garin

mhdev90’s picture

I have the same issue, but here is a possible solution:

Override the "access" method in the GroupContent entity with the following:

  public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
    if ($operation == 'create') {
      return $this->entityManager()
        ->getAccessControlHandler($this->entityTypeId)
        ->createAccess($this->bundle(), $account, ['group' => $this->getGroup()], $return_as_object);
    }
    return $this->entityManager()
      ->getAccessControlHandler($this->entityTypeId)
      ->access($this, $operation, $account, $return_as_object);
  }

Then you can use this POST to create a GroupContent entity (Article):

Route: /entity/group_content
Method: POST

{  
   "langcode":[  
      {  
         "value":"en"
      }
   ],
   "type":[  
      {  
         "target_id":"groups-group_node-article",
         "target_type":"group_content_type"
      }
   ],
   "gid":[  
      {  
         "target_id":1,
         "target_type":"group",
         "url":"\/group\/1"
      }
   ],
   "entity_id":[  
      {  
         "target_id":1,
         "target_type":"node",
         "url":"\/node\/1"
      }
   ],
   "label":[  
      {  
         "value":"Inhalt"
      }
   ],
   "uid":[  
      {  
         "target_id":1,
         "target_type":"user",
         "url":"\/user\/1"
      }
   ],
   "default_langcode":[  
      {  
         "value":true
      }
   ]
}

Sorry for this code snippet, but i don't know how to create a patch. =/

laboratory.mike’s picture

To make a patch, make two copies of the module, one with your edited code and one without. Next, make sure Git is installed on your machine (which OS do you have?) and at the folder containing the two module folders, type this command in the command line:

git diff module_old module_new > mypatch.patch

This will put the changes into a patch, formatted for the module.

johnreytanquinco’s picture

any update on this?

johnreytanquinco’s picture

@HenKeM

I tried to apply my custom content type,

   "type":[  
      {  
         "target_id":"business_group-group_node-custom_content", // or "target_id":"groups-group_node-custom_content",
         "target_type":"group_content_type"
      }
   ],

POST: http://localhost:8080/entity/group_content?_format=json

But getting:

{
	"message": "\"business_group-group_node-custom_content\" is not a valid bundle type for denormalization."
}
zak.schlemmer’s picture

I was experiencing this same issue.
I attempted to apply the change suggested by @HemkeM
This worked for POST on group_content, but did not allow for a POST to /entity/group that had previously worked without issue.

Error: Call to undefined method Drupal\group\Entity\Group::getGroup() in Drupal\Core\Entity\ContentEntityBase->access() (line 704 of /growmobot/core/lib/Drupal/Core/Entity/ContentEntityBase.php) #0 /growmobot/core/modules/rest/src/Plugin/rest/resource/EntityResource.php(166): Drupal\Core\Entity\ContentEntityBase->access('create', NULL, true) #1 [internal function]: Drupal\rest\Plugin\rest\resource\EntityResource->post(Object(Drupal\group\Entity\Group)) #2 /growmobot/core/modules/rest/src/RequestHandler.php(242): call_user_func_array(Array, Array) #3 /growmobot/core/modules/rest/src/RequestHandler.php(80): Drupal\rest\RequestHandler->delegateToRestResourcePlugin(Object(Drupal\Core\Routing\RouteMatch), Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\group\Entity\Group), Object(Drupal\rest\Plugin\rest\resource\EntityResource))

This makes sense, as the access would not exist on group create.
Could anyone suggest something that would work for both actions?
Thanks in advance.

Wim Leers’s picture

Title: How to create group node using Restful JSON? » Creating `Group` content is impossible via REST, JSON:API and GraphQL due to `$context['group']` being required in checking `create` access
Category: Support request » Bug report
Issue tags: +API-First Initiative
Related issues: +#2942069: Using JSON:API to POST group content article results in error due to `$context['group']` being required
Wim Leers’s picture

Wim Leers’s picture

Let's turn #26 into a patch!

kristiaanvandeneynde’s picture

The approach in #26 is correct. So far we've had 3 classes call the access control handler for GroupContent and all 3 grabbed the group ID from the route:

  • GroupContentController:addPage() to show the content you are allowed to add
  • GroupContentCreateAnyAccessCheck (a route access check)
  • GroupContentCreateAccessCheck (a route access check)

This means it will work fine with Group's UI, but as demonstrated, won't work when someone tries to create a GC entity directly while still checking the access layer. In order to fix this, we need to override ContentEntityBase::access() to inform it about the expectation of a group context in our access control handler.

The code from #26 does exactly that.

Wim Leers’s picture

Status: Active » Needs work
Issue tags: +Novice, +php-novice, +Needs reroll

Alright, thanks for checking and confirming, @kristiaanvandeneynde! 🙏So all we need now is for somebody to turn #26 into a patch!

psf_’s picture

Assigned: Unassigned » psf_

I will try to make the patch : )

psf_’s picture

Assigned: psf_ » Unassigned

I'm debugging using JSON:API calls, and I overwrote GroupContent:access and GroupContentAccessControlHandler:access but never are called.

I always get stopped in GroupContentAccessControlHandler:checkCreateAccess, searching in code, pointed in #34 and others, the group is detected by the route definition, not by context.

In the case of JSON:API, and I think that with REST is the same, the routes are generic and dynamically created, and can't validate the group.

I see in EntityAccessControlHandler:createAccess that we can implement hook_entity_create_access or hook_content_group_create_access. but I don't know if a correct way. This should be fixed with GroupContent:access, or any access handler... but I don't find where.

I'll try tomorrow again... :)

psf_’s picture

I'm sorry, but I can't get the group in group_group_content_create_access(AccountInterface $account = NULL, array &$context, $entity_bundle), I can get the group type only :(

I wanted to add the group in the context array, but I can't...

taylormade415’s picture

To help those testing and per the maintainers here, I put together a patch file for #26, but it does not work for the default rest endpoint: /file/upload/{entity_type_id}/{bundle}/{field_name}: POST

taylormade415’s picture

Meanwhile, what does work for me is rewritting checkCreateAccess in src/Entity/Access/GroupContentAccessControlHandler.php as:

protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
  $group_content_type = GroupContentType::load($entity_bundle);
  if (!isset($context['group'])) {
    $grps = \Drupal::service('group.membership_loader')->loadByUser($account);
    if (empty($grps)) {
      $context['group'] = \Drupal::entityTypeManager()->getStorage('group')->create(['type' => 'groups']);
      $context['group']->setOwnerId($account->id());
    } else {
      $context['group'] = $grps[0]->getGroup();
    }
  }
  return $group_content_type->getContentPlugin()->createAccess($context['group'], $account);
}

I suspect this isn't an ideal solution as it just creates a fake group or selects one at random, but the permissions being checked should be respected in either case.

AjitS’s picture

Issue tags: -Needs reroll
sam711’s picture

I'm setting this up to work with JSON:API calls.

#26 doesn't work for POST requests because the GroupContent entity doesn't exist at this
point, so the access check is directly forwarded to the EntityAccessControlHandler
by the Entity API. It'd be expensive to create the entity before checking for
create entity access.

Group access check is different than a regular entity access check, because the
permissions depend on the specific group where you're trying to create the content.
You need to know the group id.

Using the UI the group id is taken from the Route and added to the context, while
when using JSON:API it has to be taken from the body (which hasn't been processed at this
point either). If we use a custom Rest endpoint all this is more flexible, but at the
same time more unpredictable.

The patch in #40 is wrong because the access check needs to depend on the specific
group the content is created in, not in a random group or a new group where the
user is the owner.

#37 and #38 follow the correct logic and are close to a solution. What is left is
that you need to take the group id from the request, as the JSON:API doesn't provide
an API for this.

Here's a first patch to make it work using JSON:API. Bear in mind that the JSON:API
POST is just trying to create the relationship between the content Entity and the
Group, so the entity needs to exist before making this call. If you need to create
the content entity and the relationship in one request you can use Subrequests module.

Also, the user performing the request needs to have the 'Relationship: Add entity
relation' permission.

Here's an example for the POST request using JSON:API.

POST /jsonapi/group_content/group_type-custom_content-type

{
    "data": {
        "type": "group_content--group_type-custom_content-type",
        "attributes": {
            "langcode": "en",
            "label": "Title for your custom content"
        },
        "relationships": {
           "gid": {
             "data":
             {
               "type": "group--group_type",
               "id": "ac1039fd-277a-4df0-96fa-4ff178cefe69"
             }
          },
          "entity_id": {
            "data": {
                "type": "custom_content--type",
                "id": "97b8e8e0-7fb2-45d0-8038-9ab616481111"
            }
          }
        }
    }
}

Similar approach would work for default REST endpoints.

Dhammika’s picture

I am new to JSONAPI and Groups. I am trying to decipher the above from @sam711. I hoping someone can help provide some insight as to the JSON:API endpoints and JSON as to how one posts a content type (say of type budget) and add it to a group (of type department)

Step 1: (Add content type)

POST : ????

JSON : ???

Step 2: (Add to department group)

POST:

JSON : ???

boki’s picture

I am new to the Drupal community (first post!) so my apologies if I missed the answer in the above posts. Is the solution to the original question (and that of https://www.drupal.org/project/group/issues/2872269 ) to use the patch suggested in #26? And to clarify, does the patch allow the REST API to be used to:

  1. associate an existing content node with an existing Group? and/or
  2. create a new content node "inside" an existing Group?

Our team is using Acquia-hosted Lightning (Drupal core 8.8.1, Groups 1), with no additional patches. So, an alternate question: When the REST resource /entity/group_content: POST is enabled, is there an intended use that works without applying patches? If yes, an example would be much appreciated.

narendra.rajwar27’s picture

Version: 8.x-1.x-dev » 8.x-1.2
FileSize
1.11 KB

Solution from comment #40 works for me for group 8.x.1.2 version.
Patch was not getting applied. Adding re-rolled patch.

kristiaanvandeneynde’s picture

Having had another look, the problem is that you really need to tell the system which group you're trying to create the group content in. Solutions like #45 won't work because it guesses which group you're trying to add it to. Just because you have create access in group A1, does not mean you can create the same group content in group A2.

A better solution might be to have REST, JSON:API and GraphQL allow you to specify the context parameters for the access check. Or to have core provide a way to do so so that the three aforementioned modules can simply use that system.

garphy made their first commit to this issue’s fork.

sachbearbeiter’s picture

Is someone working on this?

whiz11’s picture

Re-rolling a patch for the 3.0 version

globexplorer’s picture

We have to have a solution for both JSONAPI and RESTAPI.

globexplorer’s picture

This patch fixes both JSONAPI and RESTAPI.

lambic’s picture

Here's a version of globexplorer's patch for group 2.2.x