From b06342f29cff6c49256635c99a74eb3dafdb7efd Mon Sep 17 00:00:00 2001
From: Gary Wang <wzc782970009@gmail.com>
Date: Thu, 8 Jul 2021 07:23:09 +0800
Subject: [PATCH] fix: not able to update local created non-urlencoded wiki
 pages (#16139)

* fix: not able to update local created non-urlencoded wiki pages

* tidy code

* as per suggestion

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Don't replace space to dash for unescaped wiki filename

Co-authored-by: zeripath <art27@cantab.net>

* Remove incorrect comment

* Remove NameToUnescapedFilename()

Co-authored-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: techknowlogick <techknowlogick@gitea.io>
---
 services/wiki/wiki.go | 56 +++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 43 insertions(+), 13 deletions(-)

diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go
index 75b9d1d1f5..16301034da 100644
--- a/services/wiki/wiki.go
+++ b/services/wiki/wiki.go
@@ -81,6 +81,34 @@ func InitWiki(repo *models.Repository) error {
 	return nil
 }
 
+// prepareWikiFileName try to find a suitable file path with file name by the given raw wiki name.
+// return: existence, prepared file path with name, error
+func prepareWikiFileName(gitRepo *git.Repository, wikiName string) (bool, string, error) {
+	unescaped := wikiName + ".md"
+	escaped := NameToFilename(wikiName)
+
+	// Look for both files
+	filesInIndex, err := gitRepo.LsFiles(unescaped, escaped)
+	if err != nil {
+		log.Error("%v", err)
+		return false, escaped, err
+	}
+
+	foundEscaped := false
+	for _, filename := range filesInIndex {
+		switch filename {
+		case unescaped:
+			// if we find the unescaped file return it
+			return true, unescaped, nil
+		case escaped:
+			foundEscaped = true
+		}
+	}
+
+	// If not return whether the escaped file exists, and the escaped filename to keep backwards compatibility.
+	return foundEscaped, escaped, nil
+}
+
 // updateWikiPage adds a new page to the repository wiki.
 func updateWikiPage(doer *models.User, repo *models.Repository, oldWikiName, newWikiName, content, message string, isNew bool) (err error) {
 	if err = nameAllowed(newWikiName); err != nil {
@@ -133,27 +161,29 @@ func updateWikiPage(doer *models.User, repo *models.Repository, oldWikiName, new
 		}
 	}
 
-	newWikiPath := NameToFilename(newWikiName)
+	isWikiExist, newWikiPath, err := prepareWikiFileName(gitRepo, newWikiName)
+	if err != nil {
+		return err
+	}
+
 	if isNew {
-		filesInIndex, err := gitRepo.LsFiles(newWikiPath)
-		if err != nil {
-			log.Error("%v", err)
-			return err
-		}
-		if util.IsStringInSlice(newWikiPath, filesInIndex) {
+		if isWikiExist {
 			return models.ErrWikiAlreadyExist{
 				Title: newWikiPath,
 			}
 		}
 	} else {
-		oldWikiPath := NameToFilename(oldWikiName)
-		filesInIndex, err := gitRepo.LsFiles(oldWikiPath)
-		if err != nil {
-			log.Error("%v", err)
-			return err
+		// avoid check existence again if wiki name is not changed since gitRepo.LsFiles(...) is not free.
+		isOldWikiExist := true
+		oldWikiPath := newWikiPath
+		if oldWikiName != newWikiName {
+			isOldWikiExist, oldWikiPath, err = prepareWikiFileName(gitRepo, oldWikiName)
+			if err != nil {
+				return err
+			}
 		}
 
-		if util.IsStringInSlice(oldWikiPath, filesInIndex) {
+		if isOldWikiExist {
 			err := gitRepo.RemoveFilesFromIndex(oldWikiPath)
 			if err != nil {
 				log.Error("%v", err)