Nuevo plugin Private Wiki 0.2.0

This commit is contained in:
Manuel Cillero 2019-01-30 19:41:31 +01:00
parent 4e788bb03c
commit 49913ad11b
20 changed files with 480 additions and 0 deletions

View file

@ -0,0 +1,20 @@
Copyright (c) 2017 Alexandre BOUDINE, previous owner(s) : Oleg Kandaurov
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,39 @@
# Private Wiki
## A RedMine plugin
This plugin is based on the existing plugin "Redmine Private Wiki", developped by Oleg Kandaurov
Link of the original plugin : https://github.com/f0y/redmine_private_wiki
## Features :
As original plugin :
* It allows to set individual pages of wiki as privates
* Thoses privates pages are only visibles to the roles with the right permission
* Privatize pages are also a permission
## New Features :
New features :
* Hide private wikis in index and date_index for non-authorized users
* Add [PRIVATE] tag in index for authorized users
## Use :
To set public/private wiki page :
Projects -> MyProject -> Wiki -> select wiki page -> set private
## Installation :
$cd /path/to/redmine/directory/plugins
$git clone https://github.com/BlueXML/redmine_private_wiki.git
$bundle exec rake redmine:plugins:migrate RAILS_ENV=production
## Compatibility :
Tested for RedMine 3.3.* (Manually)
## License :
This plugin is licensed under the MIT license.

View file

@ -0,0 +1,19 @@
<% if controller and controller.class.name == 'WikiController' and controller.action_name == "show" and @page and @page.id and @page.visible? %><!--If the actual page is a wiki page-->
<!--If the wiki is private, set PRIVATE flag-->
<% if @page.private? and User.current.allowed_to?(:view_privates_wiki, @project) %>
<span class=private_wiki_flag><%= l(:private_flag) %></span>
<% end %>
<!--If authorized, allow user to see changing privacy buttons-->
<%= link_to_if_authorized(l(:button_setprivate_wiki), {:action => 'change_privacy', :id => @page.title, :private => 1}, :method => :post, :class => 'icon icon-setprivate') if !@page.private? %>
<%= link_to_if_authorized(l(:button_setpublic_wiki), {:action => 'change_privacy', :id => @page.title, :private => 0}, :method => :post, :class => 'icon icon-setpublic') if @page.private? %>
<script type="text/javascript">
$('.contextual:first').prepend($('.private_wiki_flag'));
$('.contextual:first').append($('.icon-setprivate'));
$('.contextual:first').append($('.icon-setpublic'));
</script>
<% end %>

View file

@ -0,0 +1,7 @@
<!--If the actual page is a wiki page-->
<% if controller and controller.class.name == 'WikiController' and (controller.action_name == "show" or controller.action_name == "index" or controller.action_name == "date_index") %>
<!--Insert stylesheet-->
<%= stylesheet_link_tag "private_wiki.css", :plugin => "redmine_private_wiki", :media => "screen" %>
<% end %>

View file

@ -0,0 +1,60 @@
<div class="contextual">
<% if User.current.allowed_to?(:edit_wiki_pages, @project) %>
<%= link_to l(:label_wiki_page_new), new_project_wiki_page_path(@project), :remote => true, :class => 'icon icon-add' %>
<% end %>
<%= watcher_link(@wiki, User.current) %>
</div>
<h2><%= l(:label_index_by_date) %></h2>
<% if @pages.empty? %>
<p class="nodata"><%= l(:label_no_data) %></p>
<% end %>
<% @pages_by_date.keys.sort.reverse.each do |date| %>
<% all_private = true %>
<% @pages_by_date[date].each do |page| %>
<% if !page.private? %>
<% all_private = false %>
<% end %>
<% end %>
<% if !all_private %>
<h3><%= format_date(date) %></h3>
<ul>
<% @pages_by_date[date].each do |page| %>
<% if !page.private? %>
<li><%= link_to page.pretty_title, :action => 'show', :id => page.title, :project_id => page.project %></li>
<% elsif User.current.allowed_to?(:view_privates_wiki, @project) %>
<li><%= link_to page.pretty_title, :action => 'show', :id => page.title, :project_id => page.project %>&nbsp;&nbsp;&nbsp;&nbsp;<span class='private_wiki_flag' style='display:inline-block;''><%= l(:private_flag) %></span></li>
<% end %>
<% end %>
</ul>
<% elsif User.current.allowed_to?(:view_privates_wiki, @project) %>
<h3><%= format_date(date) %></h3>
<ul>
<% @pages_by_date[date].each do |page| %>
<li><%= link_to page.pretty_title, :action => 'show', :id => page.title, :project_id => page.project %>&nbsp;&nbsp;&nbsp;&nbsp;<span class='private_wiki_flag' style='display:inline-block;''><%= l(:private_flag) %></span></li>
<% end %>
</ul>
<% end %>
<% end %>
<% content_for :sidebar do %>
<%= render :partial => 'sidebar' %>
<% end %>
<% unless @pages.empty? %>
<% other_formats_links do |f| %>
<%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => @project, :show_wiki_edits => 1, :key => User.current.rss_key} %>
<% if User.current.allowed_to?(:export_wiki_pages, @project) %>
<%= f.link_to('PDF', :url => {:action => 'export', :format => 'pdf'}) %>
<%= f.link_to('HTML', :url => {:action => 'export'}) %>
<% end %>
<% end %>
<% end %>
<% content_for :header_tags do %>
<%= auto_discovery_link_tag(:atom, :controller => 'activities', :action => 'index', :id => @project, :show_wiki_edits => 1, :format => 'atom', :key => User.current.rss_key) %>
<% end %>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -0,0 +1,14 @@
.private_wiki_flag {
background: #D22;
color: white;
padding: 2px 2px 2px 2px;
border-radius: 2px;
}
.icon-setprivate{
background-image: url(../images/hide.png);
}
.icon-setpublic{
background-image: url(../images/reveal.png);
}

View file

@ -0,0 +1,5 @@
# English strings go here for Rails i18n
en:
button_setprivate_wiki: Set Private
button_setpublic_wiki: Set Public
private_flag: PRIVATE

View file

@ -0,0 +1,5 @@
# French strings go here for Rails i18n
fr:
button_setprivate_wiki: Rendre Privé
button_setpublic_wiki: Rendre Public
private_flag: PRIVÉ

View file

@ -0,0 +1,5 @@
# Plugin's routes
RedmineApp::Application.routes.draw do
#Allow utilisation of action 'change_privacy' in links (set route to wiki method)
match 'projects/:project_id/wiki/:id/change_privacy/:private', :controller => 'wiki', :action => 'change_privacy', :via => [:post]
end

View file

@ -0,0 +1,12 @@
class AddPrivateWikiAttribute < ActiveRecord::Migration
def change
#Add a "Private" attribute used to identify visibility of wikis
add_column(:wiki_pages, "private", :boolean, :default => false)
end
def self.down
remove_column(:wiki_pages, "private")
end
end

View file

@ -0,0 +1,37 @@
require 'redmine'
require_dependency 'wiki_patches/hook' #Apply views modifications
Rails.configuration.to_prepare do
#Apply patch on wiki controller
require_dependency 'wiki_controller'
unless WikiController.included_modules.include? WikiPatches::WikiControllerPatch
WikiController.send(:include, WikiPatches::WikiControllerPatch)
end
#Apply patch on wiki page
require_dependency 'wiki_page'
unless WikiPage.included_modules.include? WikiPatches::WikiPagePatch
WikiPage.send(:include, WikiPatches::WikiPagePatch)
end
require_dependency 'application_helper'
unless ApplicationHelper.included_modules.include? WikiPatches::ApplicationHelperPatch
ApplicationHelper.send(:include, WikiPatches::ApplicationHelperPatch)
end
end
Redmine::Plugin.register :redmine_private_wiki do
name 'Private Wiki plugin'
author 'Alexandre BOUDINE'
description 'Add privatization of wiki pages'
version '0.2.0'
url ''
author_url ''
#Add permissions
project_module :wiki do
permission :view_privates_wiki, {:wiki => [:show, :edit]}
permission :manage_privates_wiki, {:wiki => :change_privacy}, :require => :member
end
end

View file

@ -0,0 +1,38 @@
require_dependency 'application_helper'
module WikiPatches
module ApplicationHelperPatch
def self.included(base)
base.class_eval do
#Override application's method to not display hidden wikis or to display it with the PRIVATE flag
def render_page_hierarchy_with_wiki_hidding(pages, node=nil, options={})
content = ''
if pages[node]
content << "<ul class=\"pages-hierarchy\">\n"
pages[node].each do |page|
if !page.private? then
content << "<li>"
content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title, :version => nil},
:title => (options[:timestamp] && page.updated_on ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
content << "\n" + render_page_hierarchy(pages, page.id, options) if pages[page.id]
content << "</li>\n"
elsif User.current.allowed_to?(:view_privates_wiki, @project) then
content << "<li>"
content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title, :version => nil},
:title => (options[:timestamp] && page.updated_on ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
content << "&nbsp;&nbsp;&nbsp;&nbsp;<span class='private_wiki_flag' style='display:inline-block;''>" + l(:private_flag) + " </span>"
content << "\n" + render_page_hierarchy(pages, page.id, options) if pages[page.id]
content << "</li>\n"
end
end
content << "</ul>\n"
end
content.html_safe
end
alias_method_chain :render_page_hierarchy, :wiki_hidding
end
end
end
end

View file

@ -0,0 +1,7 @@
module WikiPatches
class WikiPatchesHook < Redmine::Hook::ViewListener
#Add the content of private_wiki_management_views/_body_bottom.html.erb to general layout
render_on :view_layouts_base_body_bottom, :partial => 'private_wiki_management_views/body_bottom'
render_on :view_layouts_base_html_head, :partial => 'private_wiki_management_views/html_head'
end
end

View file

@ -0,0 +1,28 @@
module WikiPatches
module WikiControllerPatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
#Test :valide before :show action on wiki_controller
before_filter :validate, :only => [:show,:edit,:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy]
end
end
module InstanceMethods
def change_privacy
find_existing_page
#":private" attribute of wiki page is set to :private parameter
@page.update_attribute :private, params[:private]
#Then redirection to the previous page
redirect_to project_wiki_page_path(@project, @page.title)
end
def validate
#If page is private and user not allowed to see it, then deny_access
deny_access and return if @page.private? and !User.current.allowed_to?(:view_privates_wiki, @project)
end
end
end
end

View file

@ -0,0 +1,32 @@
module WikiPatches
module WikiPagePatch
def self.included(base)
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
end
end
module InstanceMethods
#Check if the wiki page as any private parent
def has_private_parent?()
@res = self.parent_title
while @res != nil
if self.project.wiki.find_page(@res).private?
return true
else
@res = self.project.wiki.find_page(@res).parent_title
end
end
return false;
end
end
end
end

View file

@ -0,0 +1,121 @@
require File.expand_path('../../test_helper',__FILE__)
class WikiControllerPatchTest < ActionController::TestCase
fixtures :projects, :users, :roles, :members, :member_roles, :wikis, :wiki_pages, :wiki_contents
setup do
@controller = WikiController.new
@project = Project.find(1)
@project.enable_module! :wiki
@role = Role.find(1)
User.current = nil
@request.session[:user_id] = 2
@wiki = @project.wiki
@page = @wiki.find_page('Another_page')
@page.private = true
@page.save!
end
test 'show_without_permission' do
#User not allowed to see the wiki page
get :show, :project_id => @project, :id => @page.title
assert_response 403
assert_select "span.private_wiki_flag", false, "There should not be a private flag"
end
test 'show_with_permission' do
#User allowed to see the wiki page
@role.add_permission! :view_privates_wiki
get :show, :project_id => @project, :id => @page.title
assert_response :success
assert_select "span.private_wiki_flag", true, "There should be a private flag"
#User not allowed to change privacy of wiki
assert_select "a.icon-setpublic", false, "There should not be a privacy button"
#User allowed to change privacy of wiki
@role.add_permission! :manage_privates_wiki
get :show, :project_id => @project, :id => @page.title
assert_select "body" do |elements|
elements.each do |element|
Rails::logger.debug("FLAG")
Rails::logger.debug(element)
end
end
assert_select "a.icon-setpublic", true, "There should be a privacy button"
end
test 'edit_without_permission' do
#User not allowed to edit wiki
get :edit, :project_id => @project, :id => @page.title
assert_response 403
end
test 'edit_with_permission' do
#User allowed to edit wiki
@role.add_permission! :view_privates_wiki
get :edit, :project_id => @project, :id => @page.title
assert_response :success
end
test 'post_change_privacy_without_permission' do
#User not allowed to change privacy of wiki
post :change_privacy, :project_id => @project, :id => @page.title, :private => 0
assert_response 403
end
test 'post_change_privacy_with_permission' do
#User allowed to change privacy of wiki
@role.add_permission! :manage_privates_wiki
post :change_privacy, :project_id => @project, :id => @page.title, :private => 0
assert_response :redirect
assert !@page.reload.private
end
#Next tests somehow fails, but actually works ...
#Probably due to the fact that elements are added directly through JS as text and not as elements.
test 'index_without_permission' do
#User not allowed to see the wiki page
get :index, :project_id => @project
assert_response :success
assert_select "li.hide_private", true, "There should be a private <li>"
end
test 'index_with_permission' do
#User allowed to see the wiki page
@role.add_permission! :view_privates_wiki
get :index, :project_id => @project
assert_response :success
assert_select "span.private_wiki_flag", true, "There should be a private flag"
assert_select "li.hide_private", false, "There should not be a private <li>"
end
test 'date_index_without_permission' do
#User not allowed to see the wiki page
get :date_index, :project_id => @project
assert_select "li.hide_private", true, "There should be a private <li>"
end
test 'date_index_with_permission' do
#User allowed to see the wiki page
@role.add_permission! :view_privates_wiki
get :date_index, :project_id => @project
assert_select "span.private_wiki_flag", true, "There should be a private flag"
assert_select "li.hide_private", false, "There should not be a private <li>"
end
end

View file

@ -0,0 +1,2 @@
# Load the Redmine helper
require File.expand_path(File.dirname(__FILE__) + '/../../../test/test_helper')

View file

@ -0,0 +1,29 @@
require File.expand_path('../../test_helper',__FILE__)
class WikiPagePatchTest < ActiveSupport::TestCase
fixtures :projects, :wikis, :wiki_pages
setup do
@controller = WikiController.new
@project = Project.find(1)
@project.enable_module! :wiki
@wiki = @project.wiki
@page = @wiki.find_page('Another_page')
@page.private = true
@page.save!
end
test 'has_private_parent_true' do
#A page that has a private parent
@page = @wiki.find_page('Child_1')
assert_equal true, @page.has_private_parent?
end
test 'has_private_parent_false' do
#A page that doesn't have a private parent
assert_equal true, !@page.has_private_parent?
end
end