From 75c15d66b2d29ebe19200e7f0f681dd365eacaf1 Mon Sep 17 00:00:00 2001
From: Starbeamrainbowlabs <sbrl@starbeamrainbowlabs.com>
Date: Thu, 6 Aug 2020 15:47:41 +0100
Subject: [PATCH] page-move: Ensure that the new subpage actually exists -
 fixes #201

---
 Changelog.md          |  3 ++-
 core/05-functions.php | 20 ++++++++++++++------
 modules/page-move.php | 19 +++++++++++--------
 3 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/Changelog.md b/Changelog.md
index 14ddceb..828709c 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -54,7 +54,8 @@ Make sure you have PHP 7.3+ when you update past this point! It isn't the end of
  - Fixed an obscure bug in the search engine when excluding terms that appear both in a page's title and body
  - Squashed a warning at the top of search results (more insight is needed though to squash the inconsistencies in the search index that creep in though)
  - Removed annoying scrollbars when editing long pages
- - Fixed an obscure warning when previewing PDFs
+ - Fixed an obscure warning when previewing PDFs (#202)
+ - Ensure that the parent page exists when moving a page to be a child of a non-existent parent (#201)
 
 
 ## v0.21.1-hotfix1
diff --git a/core/05-functions.php b/core/05-functions.php
index ddb522b..6848165 100644
--- a/core/05-functions.php
+++ b/core/05-functions.php
@@ -210,23 +210,26 @@ function get_subpages($pageindex, $pagename)
 /**
  * Makes sure that a subpage's parents exist.
  * Note this doesn't check the pagename itself.
- * @package core
- * @param string	$pagename	The pagename to check.
+ * @package	core
+ * @param	string	$pagename	The pagename to check.
+ * @param	bool	$create_dir	Whether to create an associated directory for subpages or not.
  */
-function check_subpage_parents(string $pagename)
+function check_subpage_parents(string $pagename, bool $create_dir = true)
 {
 	global $pageindex, $paths, $env;
 	// Save the new pageindex and return if there aren't any more parent pages to check
 	if(strpos($pagename, "/") === false)
 		return save_pageindex();
-
+	
+	$pagename = makepathsafe($pagename); // Just in case
+	
 	$parent_pagename = substr($pagename, 0, strrpos($pagename, "/"));
 	$parent_page_filename = "$parent_pagename.md";
 	if(!file_exists($env->storage_prefix . $parent_page_filename))
 	{
 		// This parent page doesn't exist! Create it and add it to the page index.
 		touch($env->storage_prefix . $parent_page_filename, 0);
-
+		
 		$newentry = new stdClass();
 		$newentry->filename = $parent_page_filename;
 		$newentry->size = 0;
@@ -234,8 +237,13 @@ function check_subpage_parents(string $pagename)
 		$newentry->lasteditor = "none";
 		$pageindex->$parent_pagename = $newentry;
 	}
+	if($create_dir) {
+		$dirname = $env->storage_prefix . $parent_pagename;
+		if(!file_exists($dirname))
+			mkdir($dirname, 0755, true);
+	}
 
-	check_subpage_parents($parent_pagename);
+	check_subpage_parents($parent_pagename, $create_dir);
 }
 
 /**
diff --git a/modules/page-move.php b/modules/page-move.php
index b5d16b7..6d18992 100644
--- a/modules/page-move.php
+++ b/modules/page-move.php
@@ -1,7 +1,7 @@
 <?php
 register_module([
 	"name" => "Page mover",
-	"version" => "0.9.4",
+	"version" => "0.9.5",
 	"author" => "Starbeamrainbowlabs",
 	"description" => "Adds an action to allow administrators to move pages.",
 	"id" => "page-move",
@@ -72,21 +72,25 @@ register_module([
 			
 			if(isset($pageindex->$page->uploadedfile) and
 				file_exists($new_name))
-				exit(page_renderer::render_main("Moving $env->page - Error - $settings->sitename", "<p>Whilst moving the file associated with $env->page, $settings->sitename detected a pre-existing file on the server's file system. Because $settings->sitename can't determine whether the existing file is important to another component of $settings->sitename or it's host web server, the move have been aborted - just in case.</p>
+				exit(page_renderer::render_main("Moving $env->page - Error - $settings->sitename", "<p>Whilst moving the file associated with $env->page, $settings->sitename detected a pre-existing file on the server's file system. Because $settings->sitename can't determine whether the existing file is important to another component of $settings->sitename or it's host web server, the move has been aborted - just in case.</p>
 				<p>If you know that this move is actually safe, please get your site administrator (" . $settings->admindetails_name . ") to perform the move manually. Their contact address can be found at the bottom of every page (including this one).</p>"));
+				
+			// Make sure that the parent page exists
+			$do_create_dir = true;
+			if(strpos($new_name, "/", $do_create_dir) === false)
+				$do_create_dir = false;
+			check_subpage_parents($new_name, $do_create_dir);
 			
 			// Move the page in the page index
 			$pageindex->$new_name = new stdClass();
-			foreach($pageindex->$page as $key => $value)
-			{
+			foreach($pageindex->$page as $key => $value) {
 				$pageindex->$new_name->$key = $value;
 			}
 			unset($pageindex->$page);
 			$pageindex->$new_name->filename = "$new_name.md";
 			
 			// If this page has an associated file, then we should move that too
-			if(!empty($pageindex->$new_name->uploadedfile))
-			{
+			if(!empty($pageindex->$new_name->uploadedfile)) {
 				// Update the filepath to point to the description and not the image
 				$pageindex->$new_name->filename = $pageindex->$new_name->filename . ".md";
 				// Move the file in the pageindex
@@ -96,8 +100,7 @@ register_module([
 			}
 			
 			// Come to think about it, we should probably move the history while we're at it
-			foreach($pageindex->$new_name->history as &$revisionData)
-			{
+			foreach($pageindex->$new_name->history as &$revisionData) {
 				// We're only interested in edits
 				if($revisionData->type !== "edit") continue;
 				$newRevisionName = $pageindex->$new_name->filename . ".r$revisionData->rid";
