summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/stylesheets/application.scss1
-rw-r--r--app/assets/stylesheets/sections/wiki.scss6
-rw-r--r--app/controllers/wikis_controller.rb94
-rw-r--r--app/models/gollum_wiki.rb125
-rw-r--r--app/models/wiki_page.rb181
-rw-r--r--app/observers/project_observer.rb5
-rw-r--r--app/views/layouts/project_resource.html.haml2
-rw-r--r--app/views/wikis/_form.html.haml12
-rw-r--r--app/views/wikis/_main_links.html.haml16
-rw-r--r--app/views/wikis/edit.html.haml8
-rw-r--r--app/views/wikis/git_access.html.haml36
-rw-r--r--app/views/wikis/history.html.haml28
-rw-r--r--app/views/wikis/pages.html.haml14
-rw-r--r--app/views/wikis/show.html.haml19
14 files changed, 482 insertions, 65 deletions
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 6b500b88823..d6f2fa9632e 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -33,6 +33,7 @@
@import "sections/login.scss";
@import "sections/editor.scss";
@import "sections/admin.scss";
+@import "sections/wiki.scss";
@import "highlight/white.scss";
@import "highlight/dark.scss";
diff --git a/app/assets/stylesheets/sections/wiki.scss b/app/assets/stylesheets/sections/wiki.scss
new file mode 100644
index 00000000000..175911d7312
--- /dev/null
+++ b/app/assets/stylesheets/sections/wiki.scss
@@ -0,0 +1,6 @@
+h3.page_title .edit-wiki-header {
+ width: 780px;
+ margin-left: auto;
+ margin-right: auto;
+ padding-right: 7px;
+}
diff --git a/app/controllers/wikis_controller.rb b/app/controllers/wikis_controller.rb
index 69280291003..940b1e97340 100644
--- a/app/controllers/wikis_controller.rb
+++ b/app/controllers/wikis_controller.rb
@@ -2,58 +2,94 @@ class WikisController < ProjectResourceController
before_filter :authorize_read_wiki!
before_filter :authorize_write_wiki!, only: [:edit, :create, :history]
before_filter :authorize_admin_wiki!, only: :destroy
+ before_filter :load_gollum_wiki
def pages
- @wiki_pages = @project.wikis.group(:slug).ordered
+ @wiki_pages = @gollum_wiki.pages
end
def show
- @most_recent_wiki = @project.wikis.where(slug: params[:id]).ordered.first
- if params[:version_id]
- @wiki = @project.wikis.find(params[:version_id])
- else
- @wiki = @most_recent_wiki
- end
+ @wiki = @gollum_wiki.find_page(params[:id], params[:version_id])
if @wiki
render 'show'
else
- if can?(current_user, :write_wiki, @project)
- @wiki = @project.wikis.new(slug: params[:id])
- render 'edit'
- else
- render 'empty'
- end
+ return render('empty') unless can?(current_user, :write_wiki, @project)
+ @wiki = WikiPage.new(@gollum_wiki)
+ @wiki.title = params[:id]
+
+ render 'edit'
end
end
def edit
- @wiki = @project.wikis.where(slug: params[:id]).ordered.first
- @wiki = Wiki.regenerate_from @wiki
+ @wiki = @gollum_wiki.find_page(params[:id])
+ end
+
+ def update
+ @wiki = @gollum_wiki.find_page(params[:id])
+
+ return render('empty') unless can?(current_user, :write_wiki, @project)
+
+ if @wiki.update(content, format, message)
+ redirect_to [@project, @wiki], notice: 'Wiki was successfully updated.'
+ else
+ render 'edit'
+ end
end
def create
- @wiki = @project.wikis.new(params[:wiki])
- @wiki.user = current_user
-
- respond_to do |format|
- if @wiki.save
- format.html { redirect_to [@project, @wiki], notice: 'Wiki was successfully updated.' }
- else
- format.html { render action: "edit" }
- end
+ @wiki = WikiPage.new(@gollum_wiki)
+
+ if @wiki.create(wiki_params)
+ redirect_to project_wiki_path(@project, @wiki), notice: 'Wiki was successfully updated.'
+ else
+ render action: "edit"
end
end
def history
- @wiki_pages = @project.wikis.where(slug: params[:id]).ordered
+ unless @wiki = @gollum_wiki.find_page(params[:id])
+ redirect_to project_wiki_path(@project, :home), notice: "Page not found"
+ end
end
def destroy
- @wikis = @project.wikis.where(slug: params[:id]).delete_all
+ @wiki = @gollum_wiki.find_page(params[:id])
+ @wiki.delete if @wiki
+ redirect_to project_wiki_path(@project, :home), notice: "Page was successfully deleted"
+ end
- respond_to do |format|
- format.html { redirect_to project_wiki_path(@project, :index), notice: "Page was successfully deleted" }
- end
+ def git_access
end
+
+ private
+
+ def load_gollum_wiki
+ @gollum_wiki = GollumWiki.new(@project, current_user)
+
+ # Call #wiki to make sure the Wiki Repo is initialized
+ @gollum_wiki.wiki
+ rescue GollumWiki::CouldNotCreateWikiError => ex
+ flash[:notice] = "Could not create Wiki Repository at this time. Please try again later."
+ redirect_to @project
+ return false
+ end
+
+ def wiki_params
+ params[:wiki].slice(:title, :content, :format, :message)
+ end
+
+ def content
+ params[:wiki][:content]
+ end
+
+ def format
+ params[:wiki][:format]
+ end
+
+ def message
+ params[:wiki][:message]
+ end
+
end
diff --git a/app/models/gollum_wiki.rb b/app/models/gollum_wiki.rb
new file mode 100644
index 00000000000..91641ff1873
--- /dev/null
+++ b/app/models/gollum_wiki.rb
@@ -0,0 +1,125 @@
+class GollumWiki
+
+ MARKUPS = {
+ "Markdown" => :markdown,
+ "Textile" => :textile,
+ "RDoc" => :rdoc,
+ "Org-mode" => :org,
+ "Creole" => :creole,
+ "reStructuredText" => :rest,
+ "AsciiDoc" => :asciidoc,
+ "MediaWiki" => :mediawiki,
+ "Pod" => :post
+ }
+
+ class CouldNotCreateWikiError < StandardError; end
+
+ # Returns a string describing what went wrong after
+ # an operation fails.
+ attr_reader :error_message
+
+ def initialize(project, user = nil)
+ @project = project
+ @user = user
+ end
+
+ def path_with_namespace
+ @project.path_with_namespace + ".wiki"
+ end
+
+ def url_to_repo
+ gitlab_shell.url_to_repo(path_with_namespace)
+ end
+
+ def ssh_url_to_repo
+ url_to_repo
+ end
+
+ def http_url_to_repo
+ http_url = [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
+ end
+
+ # Returns the Gollum::Wiki object.
+ def wiki
+ @wiki ||= begin
+ Gollum::Wiki.new(path_to_repo)
+ rescue Grit::NoSuchPathError
+ create_repo!
+ end
+ end
+
+ # Returns an Array of Gitlab WikiPage instances or an
+ # empty Array if this Wiki has no pages.
+ def pages
+ wiki.pages.map { |page| WikiPage.new(self, page, true) }
+ end
+
+ # Returns the last 30 Commit objects accross the entire
+ # repository.
+ def recent_history
+ Commit.fresh_commits(wiki.repo, 30)
+ end
+
+ # Finds a page within the repository based on a tile
+ # or slug.
+ #
+ # title - The human readable or parameterized title of
+ # the page.
+ #
+ # Returns an initialized WikiPage instance or nil
+ def find_page(title, version = nil)
+ if page = wiki.page(title, version)
+ WikiPage.new(self, page, true)
+ else
+ nil
+ end
+ end
+
+ def create_page(title, content, format = :markdown, message = nil)
+ commit = commit_details(:created, message, title)
+
+ wiki.write_page(title, format, content, commit)
+ rescue Gollum::DuplicatePageError => e
+ @error_message = "Duplicate page: #{e.message}"
+ return false
+ end
+
+ def update_page(page, content, format = :markdown, message = nil)
+ commit = commit_details(:updated, message, page.title)
+
+ wiki.update_page(page, page.name, format, content, commit)
+ end
+
+ def delete_page(page, message = nil)
+ wiki.delete_page(page, commit_details(:deleted, message, page.title))
+ end
+
+ private
+
+ def create_repo!
+ if gitlab_shell.add_repository(path_with_namespace)
+ Gollum::Wiki.new(path_to_repo)
+ else
+ raise CouldNotCreateWikiError
+ end
+ end
+
+ def commit_details(action, message = nil, title = nil)
+ commit_message = message || default_message(action, title)
+
+ {email: @user.email, name: @user.name, message: commit_message}
+ end
+
+ def default_message(action, title)
+ "#{@user.username} #{action} page: #{title}"
+ end
+
+ def gitlab_shell
+ @gitlab_shell ||= Gitlab::Shell.new
+ end
+
+ def path_to_repo
+ @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git")
+ end
+
+end
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
new file mode 100644
index 00000000000..adc77b22231
--- /dev/null
+++ b/app/models/wiki_page.rb
@@ -0,0 +1,181 @@
+class WikiPage
+ include ActiveModel::Validations
+ include ActiveModel::Conversion
+ include StaticModel
+ extend ActiveModel::Naming
+
+ def self.primary_key
+ 'slug'
+ end
+
+ def self.model_name
+ ActiveModel::Name.new(self, nil, 'wiki')
+ end
+
+ def to_key
+ [:slug]
+ end
+
+ validates :title, presence: true
+ validates :content, presence: true
+
+ # The Gitlab GollumWiki instance.
+ attr_reader :wiki
+
+ # The raw Gollum::Page instance.
+ attr_reader :page
+
+ # The attributes Hash used for storing and validating
+ # new Page values before writing to the Gollum repository.
+ attr_accessor :attributes
+
+ def initialize(wiki, page = nil, persisted = false)
+ @wiki = wiki
+ @page = page
+ @persisted = persisted
+ @attributes = {}.with_indifferent_access
+
+ set_attributes if persisted?
+ end
+
+ # The escaped URL path of this page.
+ def slug
+ @attributes[:slug]
+ end
+
+ alias :to_param :slug
+
+ # The formatted title of this page.
+ def title
+ @attributes[:title] || ""
+ end
+
+ # Sets the title of this page.
+ def title=(new_title)
+ @attributes[:title] = new_title
+ end
+
+ # The raw content of this page.
+ def content
+ @attributes[:content]
+ end
+
+ # The processed/formatted content of this page.
+ def formatted_content
+ @attributes[:formatted_content]
+ end
+
+ # The markup format for the page.
+ def format
+ @attributes[:format] || :markdown
+ end
+
+ # The commit message for this page version.
+ def message
+ version.try(:message)
+ end
+
+ # The Gitlab Commit instance for this page.
+ def version
+ return nil unless persisted?
+
+ @version ||= Commit.new(@page.version)
+ end
+
+ # Returns an array of Gitlab Commit instances.
+ def versions
+ return [] unless persisted?
+
+ @page.versions.map { |v| Commit.new(v) }
+ end
+
+ # Returns the Date that this latest version was
+ # created on.
+ def created_at
+ @page.version.date
+ end
+
+ # Returns boolean True or False if this instance
+ # is an old version of the page.
+ def historical?
+ @page.historical?
+ end
+
+ # Returns boolean True or False if this instance
+ # has been fully saved to disk or not.
+ def persisted?
+ @persisted == true
+ end
+
+ # Creates a new Wiki Page.
+ #
+ # attr - Hash of attributes to set on the new page.
+ # :title - The title for the new page.
+ # :content - The raw markup content.
+ # :format - Optional symbol representing the
+ # content format. Can be any type
+ # listed in the GollumWiki::MARKUPS
+ # Hash.
+ # :message - Optional commit message to set on
+ # the new page.
+ #
+ # Returns the String SHA1 of the newly created page
+ # or False if the save was unsuccessful.
+ def create(attr = {})
+ @attributes.merge!(attr)
+
+ save :create_page, title, content, format, message
+ end
+
+ # Updates an existing Wiki Page, creating a new version.
+ #
+ # new_content - The raw markup content to replace the existing.
+ # format - Optional symbol representing the content format.
+ # See GollumWiki::MARKUPS Hash for available formats.
+ # message - Optional commit message to set on the new version.
+ #
+ # Returns the String SHA1 of the newly created page
+ # or False if the save was unsuccessful.
+ def update(new_content = "", format = :markdown, message = nil)
+ @attributes[:content] = new_content
+ @attributes[:format] = format
+
+ save :update_page, @page, content, format, message
+ end
+
+ # Destroys the WIki Page.
+ #
+ # Returns boolean True or False.
+ def delete
+ if wiki.delete_page(@page)
+ true
+ else
+ false
+ end
+ end
+
+ private
+
+ def set_attributes
+ attributes[:slug] = @page.escaped_url_path
+ attributes[:title] = @page.title
+ attributes[:content] = @page.raw_data
+ attributes[:formatted_content] = @page.formatted_data
+ attributes[:format] = @page.format
+ end
+
+ def save(method, *args)
+ if valid? && wiki.send(method, *args)
+ @page = wiki.wiki.paged(title)
+
+ set_attributes
+
+ @persisted = true
+ else
+ errors.add(:base, wiki.error_message) if wiki.error_message
+ @persisted = false
+ end
+ @persisted
+ end
+
+end
diff --git a/app/observers/project_observer.rb b/app/observers/project_observer.rb
index 4b1f8295dc2..89dc97ac140 100644
--- a/app/observers/project_observer.rb
+++ b/app/observers/project_observer.rb
@@ -18,6 +18,11 @@ class ProjectObserver < ActiveRecord::Observer
project.path_with_namespace
)
+ GitlabShellWorker.perform_async(
+ :remove_repository,
+ project.path_with_namespace + ".wiki"
+ )
+
project.satellite.destroy
log_info("Project \"#{project.name}\" was removed")
diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml
index 37d0f16fa20..3c53c0f2b46 100644
--- a/app/views/layouts/project_resource.html.haml
+++ b/app/views/layouts/project_resource.html.haml
@@ -41,6 +41,6 @@
- if @project.wiki_enabled
= nav_link(controller: :wikis) do
- = link_to 'Wiki', project_wiki_path(@project, :index)
+ = link_to 'Wiki', project_wiki_path(@project, :home)
.content= yield
diff --git a/app/views/wikis/_form.html.haml b/app/views/wikis/_form.html.haml
index 7758b129b07..6fa41db4f7a 100644
--- a/app/views/wikis/_form.html.haml
+++ b/app/views/wikis/_form.html.haml
@@ -8,9 +8,12 @@
.ui-box.ui-box-show
.ui-box-head
- = f.label :title
- .input= f.text_field :title, class: 'span8'
- = f.hidden_field :slug
+ %h3.page_title
+ .edit-wiki-header
+ = @wiki.title.titleize
+ = f.hidden_field :title, value: @wiki.title
+ = f.select :format, options_for_select(GollumWiki::MARKUPS, {selected: @wiki.format}), {}, class: "pull-right input-medium"
+ = f.label :format, class: "pull-right", style: "padding-right: 20px;"
.ui-box-body
.input
%span.cgray
@@ -22,6 +25,9 @@
.ui-box-bottom
= f.label :content
.input= f.text_area :content, class: 'span8 js-gfm-input'
+ .ui-box-bottom
+ = f.label :commit_message
+ .input= f.text_field :message, class: 'span8'
.actions
= f.submit 'Save', class: "btn-save btn"
= link_to "Cancel", project_wiki_path(@project, :index), class: "btn btn-cancel"
diff --git a/app/views/wikis/_main_links.html.haml b/app/views/wikis/_main_links.html.haml
new file mode 100644
index 00000000000..262ed74681c
--- /dev/null
+++ b/app/views/wikis/_main_links.html.haml
@@ -0,0 +1,16 @@
+%span.pull-right
+ = link_to project_wiki_path(@project, :home), class: "btn btn-small grouped" do
+ Home
+ = link_to pages_project_wikis_path(@project), class: "btn btn-small grouped" do
+ Pages
+ - if (@wiki && @wiki.persisted?)
+ = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do
+ History
+ - if can?(current_user, :write_wiki, @project)
+ - if @wiki && @wiki.persisted?
+ = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do
+ %i.icon-edit
+ Edit
+ = link_to git_access_project_wikis_path(@project), class: "btn btn-small grouped" do
+ %i.icon-download-alt
+ Git Access
diff --git a/app/views/wikis/edit.html.haml b/app/views/wikis/edit.html.haml
index 9e221aba47d..1e78d16e53b 100644
--- a/app/views/wikis/edit.html.haml
+++ b/app/views/wikis/edit.html.haml
@@ -1,8 +1,10 @@
-%h3.page_title Editing page
+%h3.page_title
+ Editing page
+ = render partial: 'main_links'
%hr
= render 'form'
.pull-right
- if can? current_user, :admin_wiki, @project
- = link_to project_wiki_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete, class: "btn btn-small btn-remove" do
- Delete this page \ No newline at end of file
+ = link_to project_wikis_path(@project, @wiki), confirm: "Are you sure you want to delete this page?", method: :delete, class: "btn btn-small btn-remove" do
+ Delete this page
diff --git a/app/views/wikis/git_access.html.haml b/app/views/wikis/git_access.html.haml
new file mode 100644
index 00000000000..353d86f2d4d
--- /dev/null
+++ b/app/views/wikis/git_access.html.haml
@@ -0,0 +1,36 @@
+%h3.page_title
+ Git Access
+ %strong= @gollum_wiki.path_with_namespace
+ = render partial: 'main_links'
+
+%br
+.content
+ .project_clone_panel
+ .row
+ .span7
+ .form-horizontal
+ .input-prepend.project_clone_holder
+ %button{class: "btn active", :"data-clone" => @gollum_wiki.ssh_url_to_repo} SSH
+ %button{class: "btn", :"data-clone" => @gollum_wiki.http_url_to_repo}= Gitlab.config.gitlab.protocol.upcase
+ = text_field_tag :project_clone, @gollum_wiki.url_to_repo, class: "one_click_select input-xxlarge", readonly: true
+ .git-empty
+ %fieldset
+ %legend Install Gollum:
+ %pre.dark
+ :preserve
+ gem install gollum
+
+ %legend Clone Your Wiki:
+ %pre.dark
+ :preserve
+ git clone #{@gollum_wiki.path_with_namespace}.git
+ cd #{@gollum_wiki.path_with_namespace}
+
+ %legend Start Gollum And Edit Locally:
+ %pre.dark
+ :preserve
+ gollum
+ == Sinatra/1.3.5 has taken the stage on 4567 for development with backup from Thin
+ >> Thin web server (v1.5.0 codename Knife)
+ >> Maximum connections set to 1024
+ >> Listening on 0.0.0.0:4567, CTRL+C to stop
diff --git a/app/views/wikis/history.html.haml b/app/views/wikis/history.html.haml
index 18df8e1d71b..609207106ab 100644
--- a/app/views/wikis/history.html.haml
+++ b/app/views/wikis/history.html.haml
@@ -1,23 +1,29 @@
%h3.page_title
%span.cgray History for
- = @wiki_pages.first.title
+ = @wiki.title.titleize
+ = render partial: 'main_links'
%br
%table
%thead
%tr
%th Page version
+ %th Author
+ %th Commit Message
%th Last updated
- %th Updated by
+ %th Format
%tbody
- - @wiki_pages.each_with_index do |wiki_page, i|
+ - @wiki.versions.each do |version|
+ - commit = CommitDecorator.new(version)
%tr
%td
- %strong
- = link_to project_wiki_path(@project, wiki_page, version_id: wiki_page.id) do
- Version
- = @wiki_pages.count - i
+ = link_to project_wiki_path(@project, @wiki, version_id: commit.id) do
+ = commit.short_id
+ %td= commit.author_link avatar: true, size: 24
+ %td
+ = commit.title
%td
- = wiki_page.created_at.to_s(:short)
- (#{time_ago_in_words(wiki_page.created_at)}
- ago)
- %td= link_to_member(@project, wiki_page.user)
+ = time_ago_in_words(version.date)
+ ago
+ %td
+ %strong
+ = @wiki.page.wiki.page(@wiki.page.name, commit.id).try(:format)
diff --git a/app/views/wikis/pages.html.haml b/app/views/wikis/pages.html.haml
index 2e0f091ce72..fe35a2ede6b 100644
--- a/app/views/wikis/pages.html.haml
+++ b/app/views/wikis/pages.html.haml
@@ -1,20 +1,24 @@
-%h3.page_title All Pages
+%h3.page_title
+ All Pages
+ = render partial: 'main_links'
%br
%table
%thead
%tr
%th Title
- %th Slug
+ %th Format
%th Last updated
%th Updated by
%tbody
- @wiki_pages.each do |wiki_page|
%tr
%td
- %strong= link_to wiki_page.title, project_wiki_path(@project, wiki_page)
- %td= wiki_page.slug
+ %strong= link_to wiki_page.title.titleize, project_wiki_path(@project, wiki_page)
+ %td
+ %strong= wiki_page.format
%td
= wiki_page.created_at.to_s(:short) do
(#{time_ago_in_words(wiki_page.created_at)}
ago)
- %td= link_to_member(@project, wiki_page.user)
+ - commit = CommitDecorator.decorate(wiki_page.version)
+ %td= commit.author_link avatar: true, size: 24
diff --git a/app/views/wikis/show.html.haml b/app/views/wikis/show.html.haml
index 7ff8b5cc01e..54d2a728504 100644
--- a/app/views/wikis/show.html.haml
+++ b/app/views/wikis/show.html.haml
@@ -1,16 +1,8 @@
%h3.page_title
- = @wiki.title
- %span.pull-right
- = link_to pages_project_wikis_path(@project), class: "btn btn-small grouped" do
- Pages
- - if can? current_user, :write_wiki, @project
- = link_to history_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do
- History
- = link_to edit_project_wiki_path(@project, @wiki), class: "btn btn-small grouped" do
- %i.icon-edit
- Edit
+ = @wiki.title.titleize
+ = render partial: 'main_links'
%br
-- if @wiki != @most_recent_wiki
+- if @wiki.historical?
.warning_message
This is an old version of this page.
You can view the #{link_to "most recent version", project_wiki_path(@project, @wiki)} or browse the #{link_to "history", history_project_wiki_path(@project, @wiki)}.
@@ -18,6 +10,7 @@
.file_holder
.file_content.wiki
= preserve do
- = markdown @wiki.content
+ = @wiki.formatted_content.html_safe
-%p.time Last edited by #{link_to_member @project, @wiki.user}, #{time_ago_in_words @wiki.created_at} ago
+- commit = CommitDecorator.new(@wiki.version)
+%p.time Last edited by #{commit.author_link(avatar: true, size: 16)} #{time_ago_in_words @wiki.created_at} ago