diff options
Diffstat (limited to 'app/models/wiki.rb')
-rw-r--r-- | app/models/wiki.rb | 86 |
1 files changed, 75 insertions, 11 deletions
diff --git a/app/models/wiki.rb b/app/models/wiki.rb index b3f09b20463..b29c43bcfe1 100644 --- a/app/models/wiki.rb +++ b/app/models/wiki.rb @@ -13,43 +13,65 @@ class Wiki markdown: { name: 'Markdown', default_extension: :md, + extension_regex: Regexp.new('md|mkdn?|mdown|markdown', 'i'), created_by_user: true }, rdoc: { name: 'RDoc', default_extension: :rdoc, + extension_regex: Regexp.new('rdoc', 'i'), created_by_user: true }, asciidoc: { name: 'AsciiDoc', default_extension: :asciidoc, + extension_regex: Regexp.new('adoc|asciidoc', 'i'), created_by_user: true }, org: { name: 'Org', default_extension: :org, + extension_regex: Regexp.new('org', 'i'), created_by_user: true }, textile: { name: 'Textile', - default_extension: :textile + default_extension: :textile, + extension_regex: Regexp.new('textile', 'i') }, creole: { name: 'Creole', - default_extension: :creole + default_extension: :creole, + extension_regex: Regexp.new('creole', 'i') }, rest: { name: 'reStructuredText', - default_extension: :rst + default_extension: :rst, + extension_regex: Regexp.new('re?st(\.txt)?', 'i') }, mediawiki: { name: 'MediaWiki', - default_extension: :mediawiki + default_extension: :mediawiki, + extension_regex: Regexp.new('(media)?wiki', 'i') + }, + pod: { + name: 'Pod', + default_extension: :pod, + extension_regex: Regexp.new('pod', 'i') + }, + plaintext: { + name: 'Plain Text', + default_extension: :txt, + extension_regex: Regexp.new('txt', 'i') } }.freeze unless defined?(MARKUPS) VALID_USER_MARKUPS = MARKUPS.select { |_, v| v[:created_by_user] }.freeze unless defined?(VALID_USER_MARKUPS) + unless defined?(ALLOWED_EXTENSIONS_REGEX) + ALLOWED_EXTENSIONS_REGEX = Regexp.union(MARKUPS.map { |key, value| value[:extension_regex] }).freeze + end + CouldNotCreateWikiError = Class.new(StandardError) HOMEPAGE = 'home' @@ -205,15 +227,36 @@ class Wiki end def create_page(title, content, format = :markdown, message = nil) - commit = commit_details(:created, message, title) + if Feature.enabled?(:gitaly_replace_wiki_create_page, container, default_enabled: :yaml) + with_valid_format(format) do |default_extension| + if file_exists_by_regex?(title) + raise_duplicate_page_error! + end + + capture_git_error(:created) do + create_wiki_repository unless repository_exists? + sanitized_path = sluggified_full_path(title, default_extension) + repository.create_file(user, sanitized_path, content, **multi_commit_options(:created, message, title)) + repository.expire_status_cache if repository.empty? + after_wiki_activity - wiki.write_page(title, format.to_sym, content, commit) - repository.expire_status_cache if repository.empty? - after_wiki_activity + true + rescue Gitlab::Git::Index::IndexError + raise_duplicate_page_error! + end + end + else + commit = commit_details(:created, message, title) + + wiki.write_page(title, format.to_sym, content, commit) + repository.expire_status_cache if repository.empty? + after_wiki_activity - true + true + end rescue Gitlab::Git::Wiki::DuplicatePageError => e - @error_message = "Duplicate page: #{e.message}" + @error_message = _("Duplicate page: %{error_message}" % { error_message: e.message }) + false end @@ -393,12 +436,33 @@ class Wiki yield default_extension end + def file_exists_by_regex?(title) + return false unless repository_exists? + + escaped_title = Regexp.escape(sluggified_title(title)) + regex = Regexp.new("^#{escaped_title}\.#{ALLOWED_EXTENSIONS_REGEX}$", 'i') + + repository.ls_files('HEAD').any? { |s| s =~ regex } + end + + def raise_duplicate_page_error! + raise Gitlab::Git::Wiki::DuplicatePageError, _('A page with that title already exists') + end + def sluggified_full_path(title, extension) sluggified_title(title) + '.' + extension end def sluggified_title(title) - Gitlab::EncodingHelper.encode_utf8_no_detect(title).tr(' ', '-') + utf8_encoded_title = Gitlab::EncodingHelper.encode_utf8_no_detect(title) + + sanitized_title(utf8_encoded_title).tr(' ', '-') + end + + def sanitized_title(title) + clean_absolute_path = File.expand_path(title, '/') + + Pathname.new(clean_absolute_path).relative_path_from('/').to_s end end |