Browse Source

mustikas11: juurdepääsuõigused D7-ga vastavusse + filedepot kaustahierarhia

ardo 1 ngày trước cách đây
mục cha
commit
0dad14e076

+ 36 - 2
third/drupal/mustikas11/LOEMIND.md

@@ -50,7 +50,8 @@ Ehitamine: `docker compose build`
 | `/kanded/*/saldod` | `kanded` + views_aggregator SUM | summeeritud saldod |
 | `/kanded/koik-kanded` | `kanded` | kõik kanded |
 | `/synnipaevad`, `/liikmed/synnipaevad` | `synnipaevad` | emal_liige nimekiri |
-| `/docs` | `dokumendid` | filedepot_folder nimekiri |
+| `/docs` | `dokumendid` | filedepot_folder nimekiri (täispika hierarhilise teega) |
+| `/filedepot` | `dokumendid` (page_filedepot) | sama nimekiri, täispika teega |
 | `/liikmed/eksport` | `liikmed` data_export | CSV (nimed, isikukoodid, e-mailid) |
 | `/contact` | contact moodul | kontaktivorm (feedback) |
 
@@ -87,6 +88,36 @@ docker exec drupal_mustikas11 sh -c "cd /opt/drupal && php -d memory_limit=1024M
 | failid | 2675 | 854 (public) | osaline (private jäi) |
 | URL aliased | 11147 | ~11000 | ✓ |
 
+## Juurdepääsuõigused (seis 2026-08)
+
+Juurdekontroll on viidud D7-ga vastavusse:
+
+- Anonüümsele kasutajale on EEMALDATUD `access content` (View published content).
+  Selle tulemusena:
+  - `/` (Avaleht, node/5) -> 403 "Ligipääs keelatud" + juhendtekst + sisselogimisplokk külgribal
+  - `/liikmed`, `/projektid`, `/kanded/*`, `/docs`, `/filedepot`, `/synnipaevad`, kõik `/node/*` -> 403
+  - `/contact` -> 200 (kõigile)
+  - `/user/login`, `/user/password` -> 200; `/user/register` -> 403 (admin_only)
+  - Peamenüüs anonüümsele ainult "Avaleht" ja "Kontakt"
+- Eemaldatud standard profiili "Home" menüülink (`standard.front_page`) peamenüüst
+  (hook_menu_links_discovered_alter mustikas_export moodulis).
+- Lisa juhendteksti blokk (`anonymous_front_instruction`), nähtav ainult anonüümsele,
+  content regionis (D7 node/3 "Anonüümse kasutaja avalehe info" analogg).
+- `metro_user_login` blokk piiratud ainult anonüümsele.
+- `tools_sidebar` menüü peidetud anonüümsele.
+- D7 footer taastatud: `metro_block_4-7` (telefon, e-mail, lahtiolekuajad,
+  "Kirjuta meile" -> /contact) paigutatud `footer_top` regioni.
+- Tõlked (et): "Access denied" -> "Ligipääs keelatud",
+  "You are not authorized to access this page." -> "Sul puudub õigus antud lehte vaadata.",
+  kontaktvormi pealkiri "Website feedback" -> "Kontakt".
+
+Skriptid (kordustäitmiseks):
+- `revoke_anon_access.php` – eemaldab anonüümselt access content
+- `add_instruction_block.php` – loob juhendteksti bloki
+- `restrict_login_block.php` – metro_user_login anonüümsele
+- `restore_footer.php` – footer blokid footer_top
+- `restrict_tools_sidebar.php` – tools_sidebar peidetud anonüümsele
+
 ## Teadaolevad probleemid / edasiarendus
 
 1. **body "plain text" väli** – D7 body on konfigureeritud plain_text-iga, migrate
@@ -126,6 +157,9 @@ docker exec drupal_mustikas11 sh -c "cd /opt/drupal && php -d memory_limit=1024M
 - `fix_fields2.php` – loob datetime_range → daterange storage'id
 - `fix_er_sort.php` – parandab entityreference `sort` puuduva võtme (source DB)
 - `fix_text_maxlength.php` – tõstab liiga lühikese `text` välja max_length=255 (source DB)
-- `del_kirjeldus.php` – kustutab field_kirjeldus config'i (vajadusel)
+- `del_kirjeldus.php` - kustutab field_kirjeldus config'i (vajadusel)
+- `migrate_filedepot.php` – migreerib filedepot failid (file_managed + node__filedepot_folder_file)
+- `migrate_filedepot_hierarchy.php` – loob field_folder_parent välja ja täidab D7 filedepot_categories.pid järgi kaustade hierarhia
+- `custom_modules/mustikas_export/src/Plugin/views/field/FolderPath.php` – Views väli "Kausta täispikk tee" (`filedepot_folder_path`)
 
 Need on ka `/tmp/opencode/` kohalikus Dropboxis (kust sai scp).

+ 70 - 0
third/drupal/mustikas11/add_instruction_block.php

@@ -0,0 +1,70 @@
+<?php
+use Drupal\block_content\Entity\BlockContent;
+use Drupal\block\Entity\Block;
+
+// 1. Loome või laadime basic block_content juhendtekstiga.
+$text = '<div>Esmakordsel sisenemisel vajuta kõigepealt nuppu "soovin uut parooli". Seejärel sisesta lahtitulnud lehele aadress, mille oled liidule oma kontaktina andnud. Ühekordne parool saadetakse ainult sellele mailile. Peale sisselogimist saad kontaktaadressi ja parooli oma soovi kohaselt muuta. Kontrolli igaks juhuks ka rämpsposti</div>';
+
+// Otsi olemasolevat block_content info="Anonüümse avalehe juhend" järgi.
+$bc = NULL;
+$ids = \Drupal::entityQuery('block_content')
+  ->condition('type', 'basic')
+  ->condition('info', 'Anonüümse avalehe juhend')
+  ->accessCheck(FALSE)
+  ->execute();
+if ($ids) {
+  $bc = BlockContent::load(reset($ids));
+  echo "USING EXISTING block_content id=" . $bc->id() . PHP_EOL;
+} else {
+  $bc = BlockContent::create([
+    'type' => 'basic',
+    'info' => 'Anonüümse avalehe juhend',
+    'body' => [
+      'value' => $text,
+      'format' => 'filtered_html',
+    ],
+  ]);
+  $bc->save();
+  echo "CREATED block_content id=" . $bc->id() . PHP_EOL;
+}
+
+// 2. Loome blocki, mis seda kuvab anonüümsele content regionis.
+$block_id = 'anonymous_front_instruction';
+$existing = Block::load($block_id);
+if ($existing) {
+  echo "BLOCK EXISTS: $block_id" . PHP_EOL;
+} else {
+  $block = Block::create([
+    'id' => $block_id,
+    'theme' => 'olivero',
+    'region' => 'content',
+    'weight' => -10,
+    'status' => TRUE,
+    'provider' => 'block_content',
+    'plugin' => 'block_content:' . $bc->uuid(),
+    'settings' => [
+      'id' => 'block_content:' . $bc->uuid(),
+      'label' => 'Anonüümse avalehe juhend',
+      'label_display' => '0',
+      'provider' => 'block_content',
+      'view_mode' => 'full',
+    ],
+    'dependencies' => [
+      'content' => ['block_content:basic:' . $bc->uuid()],
+      'module' => ['block_content'],
+      'theme' => ['olivero'],
+    ],
+    'visibility' => [
+      'user_role' => [
+        'id' => 'user_role',
+        'negate' => FALSE,
+        'context_mapping' => [
+          'user' => '@user.current_user_context:current_user',
+        ],
+        'roles' => ['anonymous' => 'anonymous'],
+      ],
+    ],
+  ]);
+  $block->save();
+  echo "CREATED BLOCK $block_id" . PHP_EOL;
+}

+ 50 - 0
third/drupal/mustikas11/add_translations.php

@@ -0,0 +1,50 @@
+<?php
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+// Lisa tõlge "Access denied" -> "Ligipääs keelatud" (et).
+$translation = [
+  'Access denied' => 'Ligipääs keelatud',
+  'You are not authorized to access this page.' => 'Sul puudub õigus antud lehte vaadata.',
+];
+
+foreach ($translation as $source => $target) {
+  // Kontrolli kas source juba olemas.
+  $lid = \Drupal::database()->select('locales_source', 'ls')
+    ->fields('ls', ['lid'])
+    ->condition('source', $source)
+    ->condition('context', '')
+    ->execute()->fetchField();
+
+  if (!$lid) {
+    $lid = \Drupal::database()->insert('locales_source')
+      ->fields(['source' => $source, 'context' => '', 'version' => ''])
+      ->execute();
+    echo "SOURCE_ADDED: $source\n";
+  }
+
+  // Lisa tõlge (et).
+  $exists = \Drupal::database()->select('locales_target', 'lt')
+    ->fields('lt', ['lid'])
+    ->condition('lid', $lid)
+    ->condition('language', 'et')
+    ->execute()->fetchField();
+
+  if (!$exists) {
+    \Drupal::database()->insert('locales_target')
+      ->fields([
+        'lid' => $lid,
+        'language' => 'et',
+        'translation' => $target,
+        'customized' => 1,
+      ])
+      ->execute();
+    echo "TRANSLATION_ADDED: $source -> $target\n";
+  } else {
+    \Drupal::database()->update('locales_target')
+      ->fields(['translation' => $target, 'customized' => 1])
+      ->condition('lid', $lid)
+      ->condition('language', 'et')
+      ->execute();
+    echo "TRANSLATION_UPDATED: $source -> $target\n";
+  }
+}

+ 30 - 0
third/drupal/mustikas11/custom_modules/mustikas_export/mustikas_export.module

@@ -150,3 +150,33 @@ function mustikas_export_entity_view_alter(array &$build, EntityInterface $entit
     ];
   }
 }
+
+
+/**
+ * Implements hook_views_data_alter().
+ *
+ * Registreeri kohandatud "filedepot_folder_path" väli node_field_data
+ * tabelile, et saaks seda filedepot vaates kasutada.
+ */
+function mustikas_export_views_data_alter(array &$data) {
+  $data['node_field_data']['filedepot_folder_path'] = [
+    'title' => t('Folder path'),
+    'help' => t('Kausta täispikk hierarhiline tee.'),
+    'field' => [
+      'id' => 'filedepot_folder_path',
+    ],
+  ];
+}
+
+
+/**
+ * Implements hook_menu_links_discovered_alter().
+ *
+ * Eemalda standard installiprofiili "Home" menüülink peamenüüst
+ * (D7-s seda linki polnud, ainult " Avaleht"). Kuna link tuleb
+ * standard profiili YAML-st (MenuLinkDefault), siis vaid menu_tree
+ * keelamine ei püsi — peame selle discovery-st eemaldama.
+ */
+function mustikas_export_menu_links_discovered_alter(array &$links) {
+  unset($links['standard.front_page']);
+}

+ 84 - 0
third/drupal/mustikas11/custom_modules/mustikas_export/src/Plugin/views/field/FolderPath.php

@@ -0,0 +1,84 @@
+<?php
+
+namespace Drupal\mustikas_export\Plugin\views\field;
+
+use Drupal\views\Plugin\views\field\FieldPluginBase;
+use Drupal\views\ResultRow;
+
+/**
+ * Kuvab filedepot kausta täispika hierarhilise tee.
+ *
+ * @ViewsField("filedepot_folder_path")
+ */
+class FolderPath extends FieldPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function usesGroupBy() {
+    return FALSE;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function query() {
+    // Vaja on ainult nid-d; vaate baas on node_field_data, nii et see
+    // on juba saadaval.
+  }
+
+  /**
+   * Ehita kausta täispikk tee (ülemkaust > ülemkaust > kaust).
+   */
+  protected function buildPath(int $nid): array {
+    $storage = \Drupal::entityTypeManager()->getStorage('node');
+    $parts = [];
+    $current = $nid;
+    $seen = [];
+    while ($current && !isset($seen[$current])) {
+      $seen[$current] = TRUE;
+      $node = $storage->load($current);
+      if (!$node) {
+        break;
+      }
+      $parts[] = $node->label();
+      $parent = $node->get('field_folder_parent')->target_id;
+      if ($parent) {
+        $current = (int) $parent;
+      }
+      else {
+        break;
+      }
+    }
+    return array_reverse($parts);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function render(ResultRow $values) {
+    $nid = (int) $values->nid;
+    $parts = $this->buildPath($nid);
+
+    $out = [];
+    $last = count($parts) - 1;
+    foreach ($parts as $i => $p) {
+      if ($i < $last) {
+        $out[] = '<span class="folder-path-parent">' . htmlspecialchars($p, ENT_QUOTES, 'UTF-8') . '</span>';
+      }
+      else {
+        $url = \Drupal::entityTypeManager()->getStorage('node')->load($nid)->toUrl();
+        $link = [
+          '#type' => 'link',
+          '#title' => $p,
+          '#url' => $url,
+        ];
+        $out[] = '<span class="folder-path-current">' . \Drupal::service('renderer')->render($link) . '</span>';
+      }
+    }
+    return [
+      '#markup' => implode(' <span class="folder-path-sep">›</span> ', $out),
+    ];
+  }
+
+}

+ 89 - 0
third/drupal/mustikas11/migrate_filedepot_hierarchy.php

@@ -0,0 +1,89 @@
+<?php
+// Migreeri D7 filedepot kaustade hierarhia D11-sse.
+//
+// D7: filedepot_categories (cid, pid, nid, name) — puu struktuur.
+//     pid osutab ülemkausta cid-le; nid on filedepot_folder node.
+// D11: filedepot_folder node'il oli vaid desc + file väljad, hierarhia kadus.
+//
+// See skript:
+// 1. Loob field_folder_parent entity_reference välja (node -> filedepot_folder).
+// 2. Täidab selle D7 filedepot_categories.pid järgi (child nid -> parent nid).
+//
+// NB! Eeldab, et D7 nid == D11 nid (migratsioon säilitas nid-d).
+
+use Drupal\field\Entity\FieldStorageConfig;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\Core\Database\Database;
+use Drupal\node\Entity\Node;
+
+$src = Database::getConnection('default', 'migrate');
+
+// 1. Väli.
+$storage = FieldStorageConfig::loadByName('node', 'field_folder_parent');
+if (!$storage) {
+  $storage = FieldStorageConfig::create([
+    'field_name' => 'field_folder_parent',
+    'entity_type' => 'node',
+    'type' => 'entity_reference',
+    'settings' => ['target_type' => 'node'],
+    'module' => 'core',
+    'cardinality' => 1,
+    'translatable' => FALSE,
+  ]);
+  $storage->save();
+  echo "STORAGE_CREATED\n";
+} else {
+  echo "STORAGE_EXISTS\n";
+}
+
+$field = FieldConfig::loadByName('node', 'filedepot_folder', 'field_folder_parent');
+if (!$field) {
+  $field = FieldConfig::create([
+    'field_storage' => $storage,
+    'bundle' => 'filedepot_folder',
+    'label' => 'Ülemkaust',
+    'required' => FALSE,
+    'settings' => [
+      'handler' => 'default:node',
+      'handler_settings' => [
+        'target_bundles' => ['filedepot_folder' => 'filedepot_folder'],
+        'sort' => ['field' => 'title', 'direction' => 'ASC'],
+        'auto_create' => FALSE,
+      ],
+    ],
+  ]);
+  $field->save();
+  echo "FIELD_CREATED\n";
+} else {
+  echo "FIELD_EXISTS\n";
+}
+
+// 2. Ehita pid -> nid kaart ja määra vanemad.
+$cid_nid = [];
+foreach ($src->query("SELECT cid, nid FROM {filedepot_categories}") as $r) {
+  $cid_nid[(int) $r->cid] = (int) $r->nid;
+}
+
+$map = []; // child nid -> parent nid
+foreach ($src->query("SELECT cid, pid, nid FROM {filedepot_categories} WHERE pid <> 0") as $r) {
+  $parent_nid = $cid_nid[(int) $r->pid] ?? NULL;
+  if ($parent_nid) {
+    $map[(int) $r->nid] = $parent_nid;
+  }
+}
+
+$ok = 0;
+$fail = 0;
+foreach ($map as $child => $parent) {
+  $node = Node::load($child);
+  if (!$node) {
+    echo "MISSING NODE $child\n";
+    $fail++;
+    continue;
+  }
+  $node->set('field_folder_parent', ['target_id' => $parent]);
+  $node->save();
+  $ok++;
+}
+echo "POPULATED: $ok, FAILED: $fail\n";
+echo "done\n";

+ 25 - 0
third/drupal/mustikas11/restore_footer.php

@@ -0,0 +1,25 @@
+<?php
+use Drupal\block\Entity\Block;
+
+// D7 footer blokid: 5(telefon), 7(e-mail), 6(lahtiolekuajad), 4(Kirjuta meile).
+// D11-s: metro_block_5, metro_block_7, metro_block_6, metro_block_4 (block_content 5,7,6,4).
+$footer_map = [
+  'metro_block_5' => -50, // telefon 5060 834
+  'metro_block_7' => -49, // info@maastikuarhitekt.ee
+  'metro_block_6' => -48, // E-R: 9.00-16.00
+  'metro_block_4' => -47, // Kirjuta meile -> /contact
+];
+
+foreach ($footer_map as $id => $weight) {
+  $block = Block::load($id);
+  if (!$block) {
+    echo "MISSING $id" . PHP_EOL;
+    continue;
+  }
+  $block->set('region', 'footer_top');
+  $block->set('weight', $weight);
+  $block->set('status', TRUE);
+  $block->set('visibility', []);
+  $block->save();
+  echo "ENABLED $id -> footer_top weight=$weight" . PHP_EOL;
+}

+ 22 - 0
third/drupal/mustikas11/restrict_login_block.php

@@ -0,0 +1,22 @@
+<?php
+use Drupal\block\Entity\Block;
+
+$block = Block::load('metro_user_login');
+if (!$block) {
+  echo "BLOCK metro_user_login NOT FOUND" . PHP_EOL;
+  exit;
+}
+
+// Sisselogimisvorm ainult anonüümsele (D7-s login block oli anonüümne).
+$block->set('visibility', [
+  'user_role' => [
+    'id' => 'user_role',
+    'negate' => FALSE,
+    'context_mapping' => [
+      'user' => '@user.current_user_context:current_user',
+    ],
+    'roles' => ['anonymous' => 'anonymous'],
+  ],
+]);
+$block->save();
+echo "metro_user_login restricted to anonymous" . PHP_EOL;

+ 22 - 0
third/drupal/mustikas11/restrict_tools_sidebar.php

@@ -0,0 +1,22 @@
+<?php
+use Drupal\block\Entity\Block;
+
+$block = Block::load('tools_sidebar');
+if (!$block) {
+  echo "BLOCK tools_sidebar NOT FOUND" . PHP_EOL;
+  exit;
+}
+
+// Filedepot/teised menüülingid on anonüümsele 403 — peida menüü autenditud kasutajatele.
+$block->set('visibility', [
+  'user_role' => [
+    'id' => 'user_role',
+    'negate' => TRUE,
+    'context_mapping' => [
+      'user' => '@user.current_user_context:current_user',
+    ],
+    'roles' => ['anonymous' => 'anonymous'],
+  ],
+]);
+$block->save();
+echo "tools_sidebar hidden for anonymous" . PHP_EOL;

+ 19 - 0
third/drupal/mustikas11/revoke_anon_access.php

@@ -0,0 +1,19 @@
+<?php
+use Drupal\user\Entity\Role;
+
+$role = Role::load('anonymous');
+if (!$role) {
+  echo "ANON_ROLE_NOT_FOUND" . PHP_EOL;
+  exit;
+}
+
+// Eemalda access content (D7-s anonüümne seda ei omanud).
+if ($role->hasPermission('access content')) {
+  $role->revokePermission('access content');
+  $role->save();
+  echo "REVOKED access content" . PHP_EOL;
+} else {
+  echo "ALREADY NO access content" . PHP_EOL;
+}
+
+echo "Anonymous permissions: " . implode(', ', $role->getPermissions()) . PHP_EOL;