Commit ce8eba89135c901fd4f04f1b2385bdbd23f48766

Authored by Dmitriy Zaporozhets
2 parents 5c492a70 621bfdb4

Merge branch 'wiki'

Conflicts:
	app/views/layouts/_project_menu.html.haml
app/assets/stylesheets/main.scss
... ... @@ -72,4 +72,6 @@ $hover: #FDF5D9;
72 72 @import "highlight.css.scss";
73 73 @import "highlight.black.css.scss";
74 74  
  75 +@import "wiki.scss";
  76 +
75 77  
... ...
app/assets/stylesheets/projects.css.scss
... ... @@ -221,3 +221,7 @@ input.git_clone_url {
221 221 width:270px;
222 222 background:#fff !important;
223 223 }
  224 +
  225 +.span12 hr{
  226 + margin-top: 2px;
  227 +}
... ...
app/assets/stylesheets/wiki.scss 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +p.time {
  2 + color: #999;
  3 + font-size: 90%;
  4 + margin: 30px 3px 3px 2px;
  5 +}
... ...
app/controllers/wikis_controller.rb 0 → 100644
... ... @@ -0,0 +1,68 @@
  1 +class WikisController < ApplicationController
  2 + before_filter :project
  3 + before_filter :add_project_abilities
  4 + before_filter :authorize_read_wiki!
  5 + before_filter :authorize_write_wiki!, :except => [:show, :destroy]
  6 + before_filter :authorize_admin_wiki!, :only => :destroy
  7 + layout "project"
  8 +
  9 + def show
  10 + if params[:old_page_id]
  11 + @wiki = @project.wikis.find(params[:old_page_id])
  12 + else
  13 + @wiki = @project.wikis.where(:slug => params[:id]).order("created_at").last
  14 + end
  15 + respond_to do |format|
  16 + if @wiki
  17 + format.html
  18 + else
  19 + @wiki = @project.wikis.new(:slug => params[:id])
  20 + format.html { render "edit" }
  21 + end
  22 + end
  23 + end
  24 +
  25 + def edit
  26 + @wiki = @project.wikis.where(:slug => params[:id]).order("created_at").last
  27 + @wiki = Wiki.regenerate_from @wiki
  28 + end
  29 +
  30 + def create
  31 + @wiki = @project.wikis.new(params[:wiki])
  32 + @wiki.user = current_user
  33 +
  34 + respond_to do |format|
  35 + if @wiki.save
  36 + format.html { redirect_to [@project, @wiki], notice: 'Wiki was successfully updated.' }
  37 + else
  38 + format.html { render action: "edit" }
  39 + end
  40 + end
  41 + end
  42 +
  43 + def history
  44 + @wikis = @project.wikis.where(:slug => params[:id]).order("created_at")
  45 + end
  46 +
  47 + def destroy
  48 + @wikis = @project.wikis.where(:slug => params[:id]).delete_all
  49 +
  50 + respond_to do |format|
  51 + format.html { redirect_to project_wiki_path(@project, :index), notice: "Page was successfully deleted" }
  52 + end
  53 + end
  54 +
  55 + protected
  56 +
  57 + def authorize_read_wiki!
  58 + can?(current_user, :read_wiki, @project)
  59 + end
  60 +
  61 + def authorize_write_wiki!
  62 + can?(current_user, :write_wiki, @project)
  63 + end
  64 +
  65 + def authorize_admin_wiki!
  66 + can?(current_user, :admin_wiki, @project)
  67 + end
  68 +end
... ...
app/helpers/wikis_helper.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +module WikisHelper
  2 + def markdown_to_html(text)
  3 + RDiscount.new(text).to_html.html_safe
  4 + end
  5 +end
... ...
app/models/ability.rb
... ... @@ -5,6 +5,7 @@ class Ability
5 5 when "Issue" then issue_abilities(object, subject)
6 6 when "Note" then note_abilities(object, subject)
7 7 when "Snippet" then snippet_abilities(object, subject)
  8 + when "Wiki" then wiki_abilities(object, subject)
8 9 else []
9 10 end
10 11 end
... ... @@ -14,35 +15,40 @@ class Ability
14 15  
15 16 rules << [
16 17 :read_project,
  18 + :read_wiki,
17 19 :read_issue,
18 20 :read_snippet,
19 21 :read_team_member,
20 22 :read_merge_request,
21   - :read_note
22   - ] if project.allow_read_for?(user)
23   -
24   - rules << [
  23 + :read_note,
25 24 :write_project,
26 25 :write_issue,
27 26 :write_snippet,
28 27 :write_merge_request,
29 28 :write_note
30   - ] if project.allow_write_for?(user)
  29 + ] if project.guest_access_for?(user)
  30 +
  31 + rules << [
  32 + :download_code,
  33 + ] if project.report_access_for?(user)
  34 +
  35 + rules << [
  36 + :write_wiki
  37 + ] if project.dev_access_for?(user)
31 38  
32 39 rules << [
33 40 :modify_issue,
34 41 :modify_snippet,
  42 + :modify_wiki,
35 43 :admin_project,
36 44 :admin_issue,
37 45 :admin_snippet,
38 46 :admin_team_member,
39 47 :admin_merge_request,
40   - :admin_note
41   - ] if project.allow_admin_for?(user)
  48 + :admin_note,
  49 + :admin_wiki
  50 + ] if project.master_access_for?(user)
42 51  
43   - rules << [
44   - :download_code,
45   - ] if project.allow_pull_for?(user)
46 52  
47 53 rules.flatten
48 54 end
... ...
app/models/project.rb
... ... @@ -12,6 +12,7 @@ class Project &lt; ActiveRecord::Base
12 12 has_many :deploy_keys, :dependent => :destroy, :foreign_key => "project_id", :class_name => "Key"
13 13 has_many :web_hooks, :dependent => :destroy
14 14 has_many :protected_branches, :dependent => :destroy
  15 + has_many :wikis, :dependent => :destroy
15 16  
16 17 acts_as_taggable
17 18  
... ... @@ -232,16 +233,20 @@ class Project &lt; ActiveRecord::Base
232 233 !users_projects.where(:user_id => user.id).empty?
233 234 end
234 235  
235   - def allow_write_for?(user)
  236 + def guest_access_for?(user)
236 237 !users_projects.where(:user_id => user.id).empty?
237 238 end
238 239  
239   - def allow_admin_for?(user)
240   - !users_projects.where(:user_id => user.id, :project_access => [UsersProject::MASTER]).empty? || owner_id == user.id
  240 + def report_access_for?(user)
  241 + !users_projects.where(:user_id => user.id, :project_access => [UsersProject::REPORTER, UsersProject::DEVELOPER, UsersProject::MASTER]).empty?
241 242 end
242 243  
243   - def allow_pull_for?(user)
244   - !users_projects.where(:user_id => user.id, :project_access => [UsersProject::REPORTER, UsersProject::DEVELOPER, UsersProject::MASTER]).empty?
  244 + def dev_access_for?(user)
  245 + !users_projects.where(:user_id => user.id, :project_access => [UsersProject::DEVELOPER, UsersProject::MASTER]).empty?
  246 + end
  247 +
  248 + def master_access_for?(user)
  249 + !users_projects.where(:user_id => user.id, :project_access => [UsersProject::MASTER]).empty? || owner_id == user.id
245 250 end
246 251  
247 252 def root_ref
... ...
app/models/wiki.rb 0 → 100644
... ... @@ -0,0 +1,33 @@
  1 +class Wiki < ActiveRecord::Base
  2 + belongs_to :project
  3 + belongs_to :user
  4 +
  5 + validates :content, :title, :user_id, :presence => true
  6 + validates :title, :length => 1..250
  7 +
  8 + before_update :set_slug
  9 +
  10 +
  11 + def to_param
  12 + slug
  13 + end
  14 +
  15 + protected
  16 +
  17 + def set_slug
  18 + self.slug = self.title.parameterize
  19 + end
  20 +
  21 + class << self
  22 + def regenerate_from wiki
  23 + regenerated_field = [:slug, :content, :title]
  24 +
  25 + new_wiki = Wiki.new
  26 + regenerated_field.each do |field|
  27 + new_wiki.send("#{field}=", wiki.send(field))
  28 + end
  29 + new_wiki
  30 + end
  31 +
  32 + end
  33 +end
... ...
app/views/layouts/_project_menu.html.haml
... ... @@ -12,7 +12,6 @@
12 12 = link_to project_issues_filter_path(@project), :class => (controller.controller_name == "issues") ? "current" : nil do
13 13 Issues
14 14 %span.count= @project.issues.opened.count
15   -
16 15 - if @project.merge_requests_enabled
17 16 = link_to project_merge_requests_path(@project), :class => (controller.controller_name == "merge_requests") ? "current" : nil do
18 17 Merge Requests
... ... @@ -21,3 +20,7 @@
21 20 - if @project.wall_enabled
22 21 = link_to wall_project_path(@project), :class => current_page?(:controller => "projects", :action => "wall", :id => @project) ? "current" : nil do
23 22 Wall
  23 +
  24 + - if @project.wiki_enabled
  25 + = link_to project_wiki_path(@project, :index), :class => (controller.controller_name == "wikis") ? "current" : nil do
  26 + Wiki
... ...
app/views/projects/_form.html.haml
... ... @@ -41,6 +41,10 @@
41 41 .clearfix
42 42 = f.label :wall_enabled, "Wall"
43 43 .input= f.check_box :wall_enabled
  44 +
  45 + .clearfix
  46 + = f.label :wiki_enabled, "Wiki"
  47 + .input= f.check_box :wiki_enabled
44 48  
45 49 .clearfix
46 50 = f.label :description
... ...
app/views/wikis/_form.html.haml 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 += form_for [@project, @wiki] do |f|
  2 + -if @wiki.errors.any?
  3 + #error_explanation
  4 + %h2= "#{pluralize(@wiki.errors.count, "error")} prohibited this wiki from being saved:"
  5 + %ul
  6 + - @wiki.errors.full_messages.each do |msg|
  7 + %li= msg
  8 +
  9 + .clearfix
  10 + = f.label :title
  11 + .input= f.text_field :title, :class => :xxlarge
  12 + = f.hidden_field :slug
  13 + .clearfix
  14 + = f.label :content
  15 + .input= f.text_area :content, :class => :xxlarge
  16 + .actions
  17 + = f.submit 'Save', :class => "primary btn"
  18 + = link_to "Cancel", project_wiki_path(@project, :index), :class => "btn"
... ...
app/views/wikis/edit.html.haml 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +%h1 Editing page
  2 +
  3 += render 'form'
... ...
app/views/wikis/history.html.haml 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +%h2 Versions
  2 +%table
  3 + %thead
  4 + %tr
  5 + %th #
  6 + %th last edit
  7 + %th created by
  8 + %tbody
  9 + - @wikis.each_with_index do |wiki_page, i|
  10 + %tr
  11 + %td= i + 1
  12 + %td
  13 + = link_to wiki_page.created_at.to_s(:short), project_wiki_path(@project, wiki_page, :old_page_id => wiki_page.id)
  14 + (
  15 + = time_ago_in_words(wiki_page.created_at)
  16 + ago
  17 + )
  18 + %td= wiki_page.user.name
  19 +
... ...
app/views/wikis/show.html.haml 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +%h3
  2 + = @wiki.title
  3 + = link_to edit_project_wiki_path(@project, @wiki), :class => "right btn small" do
  4 + Edit
  5 + - if can? current_user, :write_wiki, @project
  6 + = link_to history_project_wiki_path(@project, @wiki), :class => "right btn small" do
  7 + History
  8 +%hr
  9 +
  10 += markdown_to_html @wiki.content
  11 +
  12 +%p.time Last edited by #{@wiki.user.name}, in #{time_ago_in_words @wiki.created_at}
  13 +- if can? current_user, :write_wiki, @project
  14 + = link_to project_wiki_path(@project, @wiki), :confirm => "Are you sure you want to delete this page?", :method => :delete do
  15 + Delete this page
... ...
config/routes.rb
1 1 Gitlab::Application.routes.draw do
2 2  
  3 +
3 4 # Optionally, enable Resque here
4 5 require 'resque/server'
5 6 mount Resque::Server.new, at: '/info/resque'
... ... @@ -55,6 +56,12 @@ Gitlab::Application.routes.draw do
55 56 get "files"
56 57 end
57 58  
  59 + resources :wikis, :only => [:show, :edit, :destroy, :create] do
  60 + member do
  61 + get "history"
  62 + end
  63 + end
  64 +
58 65 resource :repository do
59 66 member do
60 67 get "branches"
... ...
db/migrate/20120216215008_create_wikis.rb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +class CreateWikis < ActiveRecord::Migration
  2 + def change
  3 + create_table :wikis do |t|
  4 + t.string :title
  5 + t.text :content
  6 + t.integer :project_id
  7 +
  8 + t.timestamps
  9 + end
  10 + end
  11 +end
... ...
db/migrate/20120219130957_add_slug_to_wiki.rb 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +class AddSlugToWiki < ActiveRecord::Migration
  2 + def change
  3 + add_column :wikis, :slug, :string
  4 +
  5 + end
  6 +end
... ...
db/migrate/20120219140810_add_wiki_enabled_to_project.rb 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +class AddWikiEnabledToProject < ActiveRecord::Migration
  2 + def change
  3 + add_column :projects, :wiki_enabled, :boolean, :default => true, :null => false
  4 +
  5 + end
  6 +end
... ...
db/migrate/20120219193300_add_user_to_wiki.rb 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +class AddUserToWiki < ActiveRecord::Migration
  2 + def change
  3 + add_column :wikis, :user_id, :integer
  4 +
  5 + end
  6 +end
... ...
db/schema.rb
... ... @@ -11,7 +11,7 @@
11 11 #
12 12 # It's strongly recommended to check this file into your version control system.
13 13  
14   -ActiveRecord::Schema.define(:version => 20120216085842) do
  14 +ActiveRecord::Schema.define(:version => 20120219193300) do
15 15  
16 16 create_table "issues", :force => true do |t|
17 17 t.string "title"
... ... @@ -80,6 +80,7 @@ ActiveRecord::Schema.define(:version =&gt; 20120216085842) do
80 80 t.boolean "issues_enabled", :default => true, :null => false
81 81 t.boolean "wall_enabled", :default => true, :null => false
82 82 t.boolean "merge_requests_enabled", :default => true, :null => false
  83 + t.boolean "wiki_enabled", :default => true, :null => false
83 84 end
84 85  
85 86 create_table "protected_branches", :force => true do |t|
... ... @@ -158,4 +159,14 @@ ActiveRecord::Schema.define(:version =&gt; 20120216085842) do
158 159 t.datetime "updated_at"
159 160 end
160 161  
  162 + create_table "wikis", :force => true do |t|
  163 + t.string "title"
  164 + t.text "content"
  165 + t.integer "project_id"
  166 + t.datetime "created_at", :null => false
  167 + t.datetime "updated_at", :null => false
  168 + t.string "slug"
  169 + t.integer "user_id"
  170 + end
  171 +
161 172 end
... ...
spec/factories.rb
... ... @@ -59,3 +59,8 @@ end
59 59 Factory.add(:web_hook, WebHook) do |obj|
60 60 obj.url = Faker::Internet.url
61 61 end
  62 +
  63 +Factory.add(:wikis, WebHook) do |obj|
  64 + obj.title = Faker::Lorem.sentence
  65 + obj.content = Faker::Lorem.sentence
  66 +end
... ...
spec/requests/wikis_spec.rb 0 → 100644
... ... @@ -0,0 +1,35 @@
  1 +require 'spec_helper'
  2 +
  3 +describe "Wiki" do
  4 + let(:project) { Factory :project }
  5 +
  6 + before do
  7 + login_as :user
  8 + project.add_access(@user, :read, :write)
  9 + end
  10 +
  11 + describe "Add pages" do
  12 + before do
  13 + visit project_wiki_path(project, :index)
  14 + end
  15 +
  16 + it "should see form" do
  17 + page.should have_content("Editing page")
  18 + end
  19 +
  20 + it "should see added page" do
  21 + fill_in "Title", :with => 'Test title'
  22 + fill_in "Content", :with => '[link test](test)'
  23 + click_on "Save"
  24 +
  25 + page.should have_content("Test title")
  26 + page.should have_content("link test")
  27 +
  28 + click_link "link test"
  29 +
  30 + page.should have_content("Editing page")
  31 + end
  32 +
  33 + end
  34 +
  35 +end
... ...