Skip to content

Commit 4a6c1e8

Browse files
authored
Merge pull request #51 from localgovdrupal/fix/1.x/41-import-pipeline-permission
Fix/1.x/41 import pipeline permission
2 parents af1ddb1 + 713c39d commit 4a6c1e8

11 files changed

+251
-37
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
status: true
2+
dependencies: { }
3+
id: standard
4+
label: Standard
5+
extract_plugin: smalot_pdfparser
6+
extract_plugin_configuration: { }
7+
transform_plugins:
8+
- transform_images
9+
- transform_line_breaks
10+
- transform_ai_aio
11+
transform_plugin_configurations:
12+
- { }
13+
- { }
14+
-
15+
prompt: "You are a website content editor. Format the provided text and HTML into valid JSON only.\r\n\r\nRequirements:\r\n- Return ONLY a JSON array of page objects, no other text\r\n- Each page object has: \"title\" (string), \"content\" (string)\r\n- Split the content into MULTIPLE pages\r\n- Each page should contain 200-500 words of content when possible\r\n- Break pages at natural stopping points: section boundaries, topic changes, or major headings\r\n- Content value contains HTML using only the tags: h1, h2, h3, h4, h5, h6, p, ul, ol, li, img\r\n- Use the first line as h1 if it's a complete sentence\r\n- Preserve original text and HTML tags exactly, only add HTML tags\r\n- Generate descriptive titles that reflect each page's main topic\r\n- Pay special attention to img tags - they must be preserved with all original attributes\r\n- Properly escape all double quotes in JSON strings\r\n- Ensure any JSON you create is valid. This is really important.\r\n\r\nSplit strategy:\r\n- Look for major headings, topic shifts, or natural content breaks\r\n- Each page should feel complete but part of a larger whole\r\n- Distribute content evenly across pages\r\n- Don't create pages that are too short (under 100 words) unless necessary\r\n\r\nExample format:\r\n[\r\n {\"title\":\"Introduction and Overview\",\"content\":\"<h1>Main Title</h1><img src=\"/example-image.jpg\"><p>Intro content...</p>\"},\r\n {\"title\":\"Key Concepts\",\"content\":\"<h2>Section Title</h2><p>More content...</p>\"},\r\n {\"title\":\"Advanced Topics\",\"content\":\"<h2>Another Section</h2><p>Final content...</p>\"}\r\n]\r\n"
16+
save_plugin: save_publication
17+
save_plugin_configuration: { }

config/install/views.view.imports.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ status: true
33
dependencies:
44
module:
55
- localgov_publications_importer
6+
- user
67
id: imports
78
label: Imports
89
module: views
@@ -429,8 +430,9 @@ display:
429430
sort_asc_label: Asc
430431
sort_desc_label: Desc
431432
access:
432-
type: none
433-
options: { }
433+
type: perm
434+
options:
435+
perm: 'view imports'
434436
cache:
435437
type: tag
436438
options: { }
@@ -504,6 +506,7 @@ display:
504506
- 'languages:language_content'
505507
- 'languages:language_interface'
506508
- url.query_args
509+
- user.permissions
507510
tags: { }
508511
page_1:
509512
id: page_1
@@ -527,4 +530,5 @@ display:
527530
- 'languages:language_content'
528531
- 'languages:language_interface'
529532
- url.query_args
533+
- user.permissions
530534
tags: { }

config/schema/localgov_publications_importer.schema.yml renamed to config/schema/localgov_publications_importer.import_pipeline.schema.yml

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
drupal\localgov_publications_importer\Entity\ImportPipeline:
1+
localgov_publications_importer.import_pipeline.*:
22
type: config_entity
33
label: 'Import Pipeline'
44
mapping:
@@ -12,25 +12,19 @@ drupal\localgov_publications_importer\Entity\ImportPipeline:
1212
type: string
1313
label: 'Extract Plugin'
1414
extract_plugin_configuration:
15-
type: sequence
15+
type: ignore
1616
label: 'Extract Plugin Configuration'
17-
sequence:
18-
- type: any
1917
transform_plugins:
2018
type: sequence
2119
label: 'Transform Plugins'
2220
sequence:
23-
- type: string
21+
type: ignore
2422
transform_plugin_configurations:
25-
type: sequence
23+
type: ignore
2624
label: 'Transform Plugin Configurations'
27-
sequence:
28-
- type: any
2925
save_plugin:
3026
type: string
3127
label: 'Save Plugin'
3228
save_plugin_configuration:
33-
type: sequence
29+
type: ignore
3430
label: 'Save Plugin Configuration'
35-
sequence:
36-
- type: any
Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
1-
import localgov publications from PDF:
2-
title: 'Import localgov publications from PDF'
3-
description: 'Allows users to upload PDF files, which will be turned into publications.'
1+
create imports:
2+
title: 'Create imports'
3+
description: 'Allows users to create imports.'
44
administer imports:
55
title: 'Administer imports'
66
description: 'Allows full control over imports.'
7-
access imports:
8-
title: 'Access imports'
7+
view imports:
8+
title: 'View imports'
99
description: 'Allows viewing of imports.'
1010
delete own imports:
1111
title: 'Delete own imports'
1212
description: 'Allows users to delete imports that they started.'
13-
delete any imports:
14-
title: 'Delete any imports'
15-
description: 'Allows users to delete imports that anyone started.'
13+
administer import pipelines:
14+
title: 'Administer import pipelines'
15+
description: 'Allows full control over import pipelines.'
16+
create import pipelines:
17+
title: 'Create import pipelines'
18+
description: 'Allows users to create new import pipelines.'
19+
view import pipelines:
20+
title: 'View import pipelines'
21+
description: 'Allows users to view import pipelines.'
22+
update import pipelines:
23+
title: 'Update import pipelines'
24+
description: 'Allows users to update import pipelines.'
25+
delete import pipelines:
26+
title: 'Delete import pipelines'
27+
description: 'Allows users to delete import pipelines.'
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
localgov_publications_importer.import:
2-
path: '/admin/content/imports/import-publication'
2+
path: '/admin/content/imports/create'
33
defaults:
44
_form: 'Drupal\localgov_publications_importer\Form\PublicationImportForm'
55
_title: 'Import Publication'
66
requirements:
7-
_permission : 'import localgov publications from PDF'
7+
_entity_create_access : 'import'

src/Entity/Import.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Drupal\Core\Entity\ContentEntityBase;
66
use Drupal\Core\Entity\EntityTypeInterface;
7+
use Drupal\Core\Url;
78
use Drupal\user\UserInterface;
89
use Drupal\Core\Field\BaseFieldDefinition;
910
use Drupal\Core\Field\FieldStorageDefinitionInterface;
@@ -32,6 +33,7 @@
3233
* "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm"
3334
* },
3435
* },
36+
* admin_permission = "administer imports",
3537
* base_table = "import",
3638
* entity_keys = {
3739
* "id" = "id",
@@ -365,4 +367,14 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
365367
return $fields;
366368
}
367369

370+
/**
371+
* {@inheritdoc}
372+
*/
373+
public function toUrl($rel = NULL, array $options = []) {
374+
// Use the listing view for the canonical URL for this entity until we get
375+
// round to needing actual pages for them. Right now we just need something
376+
// to let the 'Cancel' button on the delete form work.
377+
return Url::fromUri('internal:/admin/content/imports');
378+
}
379+
368380
}

src/Entity/ImportPipeline.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
* "route_provider" = {
2020
* "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
2121
* },
22+
* "access" = "Drupal\localgov_publications_importer\ImportPipelineAccessControlHandler",
2223
* },
2324
* config_prefix = "import_pipeline",
24-
* admin_permission = "administer site configuration",
25+
* admin_permission = "administer import pipelines",
26+
* collection_permission = "view import pipelines",
2527
* entity_keys = {
2628
* "id" = "id",
2729
* "label" = "label"

src/ImportAccessControlHandler.php

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Drupal\localgov_publications_importer;
44

55
use Drupal\Core\Access\AccessResult;
6+
use Drupal\Core\Access\AccessResultNeutral;
67
use Drupal\Core\Entity\EntityAccessControlHandler;
78
use Drupal\Core\Entity\EntityInterface;
89
use Drupal\Core\Session\AccountInterface;
@@ -15,34 +16,55 @@ class ImportAccessControlHandler extends EntityAccessControlHandler {
1516
/**
1617
* {@inheritdoc}
1718
*/
18-
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
19-
if ($account->hasPermission('administer imports')) {
19+
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
20+
$result = parent::checkCreateAccess($account, $context, $entity_bundle);
21+
if (!$result instanceof AccessResultNeutral) {
22+
return $result;
23+
}
24+
if ($account->hasPermission('create imports')) {
2025
return AccessResult::allowed()->cachePerPermissions();
2126
}
27+
return AccessResult::neutral()->setReason("The following permissions are required: 'create imports'.");
28+
}
29+
30+
/**
31+
* {@inheritdoc}
32+
*/
33+
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
34+
35+
/** @var \Drupal\localgov_publications_importer\ImportInterface $entity */
36+
37+
// Parent checks admin perm and is new.
38+
$result = parent::checkAccess($entity, $operation, $account);
39+
if (!$result instanceof AccessResultNeutral) {
40+
return $result;
41+
}
2242

2343
switch ($operation) {
2444
case 'view':
25-
if ($account->hasPermission('access imports')) {
45+
case 'view label':
46+
if ($account->hasPermission('view imports')) {
2647
return AccessResult::allowed()->cachePerPermissions();
2748
}
28-
return AccessResult::neutral()->setReason("The following permissions are required: 'access imports'.");
49+
return AccessResult::neutral()->setReason("The following permissions are required: 'view imports'.");
2950

30-
case 'delete':
31-
32-
if ($account->hasPermission('delete any imports')) {
33-
return AccessResult::allowed()->cachePerPermissions();
51+
case 'update':
52+
$owner = $entity->getCreator();
53+
if ($owner instanceof AccountInterface && $owner->id() === $account->id()) {
54+
if ($account->hasPermission('update own imports')) {
55+
return AccessResult::allowed()->cachePerPermissions();
56+
}
3457
}
58+
return AccessResult::neutral()->setReason("The following permissions are required: 'update own imports'.");
3559

60+
case 'delete':
3661
$owner = $entity->getCreator();
37-
38-
// @todo Verify this.
3962
if ($owner instanceof AccountInterface && $owner->id() === $account->id()) {
4063
if ($account->hasPermission('delete own imports')) {
4164
return AccessResult::allowed()->cachePerPermissions();
4265
}
4366
}
44-
45-
return AccessResult::neutral()->setReason("The following permissions are required: 'delete terms in {$entity->bundle()}' OR 'administer taxonomy'.");
67+
return AccessResult::neutral()->setReason("The following permissions are required: 'delete own imports'.");
4668

4769
default:
4870
// No opinion.

src/ImportInterface.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
namespace Drupal\localgov_publications_importer;
44

5+
use Drupal\Core\Entity\EntityInterface;
56
use Drupal\file\Entity\File;
67
use Drupal\user\UserInterface;
78

89
/**
910
* Interface for content being imported.
1011
*/
11-
interface ImportInterface {
12+
interface ImportInterface extends EntityInterface {
1213

1314
/**
1415
* Set the title of the import.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
namespace Drupal\localgov_publications_importer;
4+
5+
use Drupal\Core\Access\AccessResult;
6+
use Drupal\Core\Access\AccessResultNeutral;
7+
use Drupal\Core\Entity\EntityAccessControlHandler;
8+
use Drupal\Core\Entity\EntityInterface;
9+
use Drupal\Core\Session\AccountInterface;
10+
11+
/**
12+
* Defines the access control handler for the import entity type.
13+
*/
14+
class ImportPipelineAccessControlHandler extends EntityAccessControlHandler {
15+
16+
/**
17+
* {@inheritdoc}
18+
*/
19+
protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
20+
$result = parent::checkCreateAccess($account, $context, $entity_bundle);
21+
if (!$result instanceof AccessResultNeutral) {
22+
return $result;
23+
}
24+
if ($account->hasPermission('create import pipelines')) {
25+
return AccessResult::allowed()->cachePerPermissions();
26+
}
27+
return AccessResult::neutral()->setReason("The following permissions are required: 'create import pipelines'.");
28+
}
29+
30+
/**
31+
* {@inheritdoc}
32+
*/
33+
protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
34+
35+
// Parent checks admin perm and is new.
36+
$result = parent::checkAccess($entity, $operation, $account);
37+
if (!$result instanceof AccessResultNeutral) {
38+
return $result;
39+
}
40+
41+
// Make 'view label' work like 'view'.
42+
if ($operation === 'view label') {
43+
$operation = 'view';
44+
}
45+
46+
switch ($operation) {
47+
case 'view':
48+
case 'update':
49+
case 'delete':
50+
if ($account->hasPermission($operation . ' import pipelines')) {
51+
return AccessResult::allowed()->cachePerPermissions();
52+
}
53+
return AccessResult::neutral()->setReason("The following permissions are required: '" . $operation . " import pipelines'.");
54+
55+
default:
56+
// No opinion.
57+
return AccessResult::neutral()->cachePerPermissions();
58+
}
59+
}
60+
61+
}

0 commit comments

Comments
 (0)