- Issue created by @brandonratz
- π¦πΊAustralia almunnings Melbourne, π¦πΊ
All cool things
I'll take a look at these today, suss out whats required to get started
- π¦πΊAustralia almunnings Melbourne, π¦πΊ
Ok cool,
All three are content field-able types, which makes integration really easy. You just need a plugin definition to extend your schema types out for it. It'll then... Just work.For each of these examples, pretend you have created your own custom module called "brandon_graphql_compose"
For Config Page:
Create a file: web/modules/custom/brandon_graphql_compose/src/Plugin/GraphQLCompose/EntityType/ConfigPage.php
declare(strict_types=1); namespace Drupal\brandon_graphql_compose\Plugin\GraphQLCompose\EntityType; use Drupal\graphql_compose\Plugin\GraphQLCompose\GraphQLComposeEntityTypeBase; /** * Define entity type. * * @GraphQLComposeEntityType( * id = "config_pages", * interfaces = { "Node" }, * prefix = "ConfigPage", * base_fields = { * "uuid" = {}, * "changed" = {}, * "status" = {}, * "context" = {}, * "title" = { * "field_type" = "entity_label", * } * } * ) */ class ConfigPage extends GraphQLComposeEntityTypeBase { }
Fragments...
Create a file: web/modules/custom/brandon_graphql_compose/src/Plugin/GraphQLCompose/EntityType/Fragment.php
declare(strict_types=1); namespace Drupal\brandon_graphql_compose\Plugin\GraphQLCompose\EntityType; use Drupal\graphql_compose\Plugin\GraphQLCompose\GraphQLComposeEntityTypeBase; /** * Define entity type. * * @GraphQLComposeEntityType( * id = "fragment", * interfaces = { "Node" }, * prefix = "Fragment", * base_fields = { * "uuid" = {}, * "created" = {}, * "changed" = {}, * "status" = {}, * "title" = { * "field_type" = "entity_label", * } * } * ) */ class Fragment extends GraphQLComposeEntityTypeBase { }
Site Settings
Create a file: web/modules/custom/brandon_graphql_compose/src/Plugin/GraphQLCompose/EntityType/SiteSettings.php
declare(strict_types=1); namespace Drupal\brandon_graphql_compose\Plugin\GraphQLCompose\EntityType; use Drupal\graphql_compose\Plugin\GraphQLCompose\GraphQLComposeEntityTypeBase; /** * Define entity type. * * @GraphQLComposeEntityType( * id = "site_setting_entity", * interfaces = { "Node" }, * prefix = "SiteSetting", * base_fields = { * "uuid" = {}, * "langcode" = {}, * "created" = {}, * "changed" = {}, * "status" = {}, * "fieldset" = {}, * "title" = { * "field_type" = "entity_label", * } * } * ) */ class SiteSettings extends GraphQLComposeEntityTypeBase { }
---
So you could create just a custom module to to these entity types, really easily.
I don't really have a preference for one over the other, and I might sit on the integration for a bit, and just compare their uses with some colleagues -- But is that easy enough for you to get started with these modules today?
The thing I'm not so sure on for these entity types is permissions. Have a play and let me know how it's working for you.
- πΊπΈUnited States brandonratz
@AlMunnings
Great pointers here. I think we can integrate our needs with these code snippets.
There are a lot of similarities between Config Pages and Site Settings & Labels. There are almost identical with slight implementation differences. I had challenges selecting between them myself.
I like to think of Config Pages as a way to create configuration routes. And I consider SS&L to be a single screen with sections of configuration. I like how they expose these settings to Twig, etc.
https://www.drupal.org/project/site_settings/issues/2980857#comment-13387097 β - Status changed to Postponed
over 1 year ago 5:45am 25 May 2023 - π¦πΊAustralia almunnings Melbourne, π¦πΊ
Of the three, I'd lean towards site_setting_entity due to it having langcode support on the entity. It'll gel better with multisite builds in the gql queries.
- πΊπΈUnited States jmolivas El Centro, CA
Of those thee we mostly use site_setting when we have a need for data settings.
- π¦πΊAustralia almunnings Melbourne, π¦πΊ
Ok cool!
So theres no harm in adding a basic extra entity type in the root package, if you don't have the entity type installed, it does nothing.I'll take a look into the permissions side of it, and roll into dev if no issue
- Status changed to Active
over 1 year ago 1:57am 31 May 2023 - Assigned to almunnings
- π¦πΊAustralia almunnings Melbourne, π¦πΊ
Looking more at this tonight, I think we'll might need to contrib up the line a hook_query_TAG_alter for site_settings so edge connections don't leak potentially private data via entity query.
- π¦πΊAustralia almunnings Melbourne, π¦πΊ
Due to how entityQuery works,
I'm kind of leaning towards this hook_query_TAG_alter to limit the results of exposed entities to work with the site_settings hook_ENTITY_TYPE_access function...
Because it's a hook, we can probably roll it ourself. I'm just not comfortable leaving a gap like this with something like a "site setting" that administrators would assume is private unless permissions apply.
/** * Implements hook_query_TAG_alter(). * * Limit the site setting entities that are returned to the user based on * their permissions to access a specific site setting type. */ function site_settings_type_permissions_query_site_setting_entity_access_alter(AlterableInterface $query) { // We're only interested in applying our access restrictions to // SELECT queries. hook_ENTITY_TYPE_access() can be used to apply // access control to 'update' and 'delete' operations. if (!($query instanceof SelectInterface)) { return; } $permissions = &drupal_static(__FUNCTION__, []); $account = $query->getMetaData('account') ?: \Drupal::currentUser(); $uid = $account->id(); if (!isset($permissions[$uid])) { $permissions[$uid] = []; $entity_type = \Drupal::entityTypeManager()->getDefinition('site_setting_entity'); $entity_type_storage = \Drupal::entityTypeManager()->getStorage($entity_type->getBundleEntityType()); // Get a list of all types for site_settings_entity. $entity_bundles = $entity_type_storage ->getQuery() ->accessCheck(FALSE) ->execute(); $data_table = $entity_type->getDataTable(); $bundle_key = $entity_type->getKey('bundle'); foreach ($entity_bundles as $type) { if ($account->hasPermission('view published site setting entities') || $account->hasPermission('view published ' . $type . ' site setting entities')) { $permissions[$uid]["[$data_table].[$bundle_key]"][] = $type; } } } if (empty($permissions[$uid])) { $query->alwaysFalse(); } foreach ($permissions[$uid] as $table_row => $types) { $query->condition($table_row, $types, 'IN'); } }
At least this way, the exposed site setting will pay attention to the
view published site setting entities
andview published ' . $type . ' site setting entities
permissions, in it's own way, by limiting the entityQuery by site_setting type.But by adding the generic site_setting view permissions to a role, admins are exposing routes like https://my.site/admin/structure/site_setting_entity/1 - Which isn't ideal.
---
So it's feeling like we need a custom resolver at this point, It doesn't really fit the pattern of content.
Any thoughts on a structure and permissions we could implement?
- π¦πΊAustralia almunnings Melbourne, π¦πΊ
Ok,
Had another idea.I just mutilate the connection a little.
/** * Applies slicing and reordering to the result so that it can be transmitted. * * The result from the database may be out of order and have overfetched. When * returning edges or nodes, this needs to be compensated in the same way. * This function removes the overfetching and ensures the results are in the * requested order. */ protected function getOrderedResult(): SyncPromise { return $this->getResult() ->then(function ($edges) { // This is probably against the spec, but we need SOME sort check. // If an entity doesn't implement hook_query_TAG_alter then we // can't guarantee the access check is applied. return array_filter($edges, function (Edge $edge) { $entity = $edge->getNode(); return ($entity instanceof AccessibleInterface) ? $entity->access('view') : FALSE; }); }) ->then(function ($edges) { // To allow for pagination we over-fetch results by one above the limits // so we must fix that now. $edges = array_slice($edges, 0, $this->first ?? $this->last); if ($this->shouldReverseResultEdges()) { $edges = array_reverse($edges); } return $edges; }); }
This introduces:
return array_filter($edges, function (Edge $edge) { $entity = $edge->getNode(); return ($entity instanceof AccessibleInterface) ? $entity->access('view') : FALSE; });
Which will run an access check on all rows of the connection check. And remove rows. The side effect of this, is if you're not using a
hook_query_TAG_alter
for the entity being retrieved, results could be sometimes 10 items, sometimes, 6, sometimes 1. Hypothetically. But its safer.@jmolivas thoughts?
- π¦πΊAustralia almunnings Melbourne, π¦πΊ
Ok. So Iβve closed up the security issue on develop. Pretty sure π
Now its more about a deeper integration with this site setting module.
Itβs a trickier integration because of how sensitive the data potentially is. I think its worthy of a submodule and its own hooks and modifications
- πΊπΈUnited States jmolivas El Centro, CA
Agree on adding this feature as submodule
- π¦πΊAustralia almunnings Melbourne, π¦πΊ
I've not forgotten this ticket.
I'm just figuring out alternative ways to do what you request without integrating heavily into those modules.I've kind of landed on the idea of custom settings being added to the info query.
I've got the data prototyped.
Just need to hook it up in a resolver.It should satisfy the original request for arbitrary settings being added, and any further integration with other modules is the responsibility of the site builder, or warrants its own module. I cant justify fixing up security gaps in a third party module as a part of this module.
Hopefully adding these settings gets the core requirement over the line.
- π¦πΊAustralia almunnings Melbourne, π¦πΊ
Ok,
I think this'll do it.- Custom settings
- Allow plaintext global token replacement on value
- Allow for multiple with same field name
- Type castingSite settings exposes tokens.
You can create a custom setting with that token value in it.Bingo bango, the scope is done.
-
almunnings β
committed 2ef326fa on 2.0.x
Issue #3361379: Expose Configuration Type Entities for Site-Wide Data
-
almunnings β
committed 2ef326fa on 2.0.x
- Status changed to Fixed
over 1 year ago 1:36pm 3 August 2023 - Status changed to Fixed
over 1 year ago 12:27am 4 August 2023 - π¦πΊAustralia almunnings Melbourne, π¦πΊ
This is now part of beta9.
Thanks!