Move plugins to separate directory.
This commit is contained in:
parent
6e990fed4c
commit
6aa8ee7968
59 changed files with 4 additions and 4 deletions
18
plugins/messages/README.md
Normal file
18
plugins/messages/README.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
FoodsoftMessages
|
||||
================
|
||||
|
||||
This plugin adds messages to foodsoft. A new 'Messages' menu entry is added below the 'Foodcoops' menu in the navigation bar.
|
||||
|
||||
This plugin is enabled by default in foodsoft, so you don't need to do anything
|
||||
to install it. If you still want to, for example when it has been disabled,
|
||||
add the following to foodsoft's Gemfile:
|
||||
|
||||
```Gemfile
|
||||
gem 'foodsoft_messages', path: 'lib/foodsoft_messages'
|
||||
```
|
||||
|
||||
This plugin introduces the foodcoop config option `use_messages`, which can be
|
||||
set to `false` to disable messages. May be useful in multicoop deployments.
|
||||
|
||||
This plugin is part of the foodsoft package and uses the GPL-3 license (see
|
||||
foodsoft's LICENSE for the full license text).
|
||||
40
plugins/messages/Rakefile
Normal file
40
plugins/messages/Rakefile
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env rake
|
||||
begin
|
||||
require 'bundler/setup'
|
||||
rescue LoadError
|
||||
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
||||
end
|
||||
begin
|
||||
require 'rdoc/task'
|
||||
rescue LoadError
|
||||
require 'rdoc/rdoc'
|
||||
require 'rake/rdoctask'
|
||||
RDoc::Task = Rake::RDocTask
|
||||
end
|
||||
|
||||
RDoc::Task.new(:rdoc) do |rdoc|
|
||||
rdoc.rdoc_dir = 'rdoc'
|
||||
rdoc.title = 'FoodsoftMessages'
|
||||
rdoc.options << '--line-numbers'
|
||||
rdoc.rdoc_files.include('README.rdoc')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
||||
|
||||
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
||||
load 'rails/tasks/engine.rake'
|
||||
|
||||
|
||||
|
||||
Bundler::GemHelper.install_tasks
|
||||
|
||||
require 'rake/testtask'
|
||||
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'lib'
|
||||
t.libs << 'test'
|
||||
t.pattern = 'test/**/*_test.rb'
|
||||
t.verbose = false
|
||||
end
|
||||
|
||||
|
||||
task :default => :test
|
||||
36
plugins/messages/app/controllers/messages_controller.rb
Normal file
36
plugins/messages/app/controllers/messages_controller.rb
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
class MessagesController < ApplicationController
|
||||
|
||||
before_filter -> { require_plugin_enabled FoodsoftMessages }
|
||||
|
||||
# Renders the "inbox" action.
|
||||
def index
|
||||
@messages = Message.pub.page(params[:page]).per(@per_page).order('created_at DESC').includes(:sender)
|
||||
end
|
||||
|
||||
# Creates a new message object.
|
||||
def new
|
||||
@message = Message.new(params[:message])
|
||||
if @message.reply_to and not @message.reply_to.is_readable_for?(current_user)
|
||||
redirect_to new_message_url, alert: 'Nachricht ist privat!'
|
||||
end
|
||||
end
|
||||
|
||||
# Creates a new message.
|
||||
def create
|
||||
@message = @current_user.send_messages.new(params[:message])
|
||||
if @message.save
|
||||
Resque.enqueue(MessageNotifier, FoodsoftConfig.scope, 'message_deliver', @message.id)
|
||||
redirect_to messages_url, :notice => I18n.t('messages.create.notice')
|
||||
else
|
||||
render :action => 'new'
|
||||
end
|
||||
end
|
||||
|
||||
# Shows a single message.
|
||||
def show
|
||||
@message = Message.find(params[:id])
|
||||
unless @message.is_readable_for?(current_user)
|
||||
redirect_to messages_url, alert: 'Nachricht ist privat!'
|
||||
end
|
||||
end
|
||||
end
|
||||
21
plugins/messages/app/helpers/messages_helper.rb
Normal file
21
plugins/messages/app/helpers/messages_helper.rb
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
module MessagesHelper
|
||||
def format_subject(message, length)
|
||||
if message.subject.length > length
|
||||
subject = truncate(message.subject, :length => length)
|
||||
body = ""
|
||||
else
|
||||
subject = message.subject
|
||||
body = truncate(message.body, :length => length - subject.length)
|
||||
end
|
||||
"<b>#{link_to(h(subject), message)}</b> <span style='color:grey'>#{h(body)}</span>".html_safe
|
||||
end
|
||||
|
||||
def link_to_new_message(options = {})
|
||||
messages_params = options[:message_params] || nil
|
||||
link_text = content_tag :id, nil, class: 'icon-envelope'
|
||||
link_text << " #{options[:text]}" if options[:text].present?
|
||||
link_to(link_text.html_safe, new_message_path(message: messages_params), class: 'btn',
|
||||
title: I18n.t('helpers.submit.message.create'))
|
||||
end
|
||||
|
||||
end
|
||||
11
plugins/messages/app/mailers/messages_mailer.rb
Normal file
11
plugins/messages/app/mailers/messages_mailer.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
class MessagesMailer < Mailer
|
||||
# Sends an email copy of the given internal foodsoft message.
|
||||
def foodsoft_message(message, recipient)
|
||||
set_foodcoop_scope
|
||||
@message = message
|
||||
|
||||
mail subject: "[#{FoodsoftConfig[:name]}] " + message.subject,
|
||||
to: recipient.email,
|
||||
from: "#{show_user(message.sender)} <#{message.sender.email}>"
|
||||
end
|
||||
end
|
||||
92
plugins/messages/app/models/message.rb
Normal file
92
plugins/messages/app/models/message.rb
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
class Message < ActiveRecord::Base
|
||||
belongs_to :sender, :class_name => "User", :foreign_key => "sender_id"
|
||||
|
||||
serialize :recipients_ids, Array
|
||||
attr_accessor :sent_to_all, :group_id, :recipient_tokens, :reply_to
|
||||
|
||||
scope :pending, -> { where(:email_state => 0) }
|
||||
scope :sent, -> { where(:email_state => 1) }
|
||||
scope :pub, -> { where(:private => false) }
|
||||
|
||||
# Values for the email_state attribute: :none, :pending, :sent, :failed
|
||||
EMAIL_STATE = {
|
||||
:pending => 0,
|
||||
:sent => 1,
|
||||
:failed => 2
|
||||
}
|
||||
|
||||
validates_presence_of :recipients_ids, :subject, :body
|
||||
validates_length_of :subject, :in => 1..255
|
||||
validates_inclusion_of :email_state, :in => EMAIL_STATE.values
|
||||
|
||||
before_validation :clean_up_recipient_ids, :on => :create
|
||||
|
||||
def self.deliver(message_id)
|
||||
find(message_id).deliver
|
||||
end
|
||||
|
||||
def clean_up_recipient_ids
|
||||
self.recipients_ids = recipients_ids.uniq.reject { |id| id.blank? } unless recipients_ids.nil?
|
||||
self.recipients_ids = User.all.collect(&:id) if sent_to_all == "1"
|
||||
end
|
||||
|
||||
def add_recipients(users)
|
||||
self.recipients_ids = [] if recipients_ids.blank?
|
||||
self.recipients_ids += users.collect(&:id) unless users.blank?
|
||||
end
|
||||
|
||||
def group_id=(group_id)
|
||||
@group_id = group_id
|
||||
add_recipients Group.find(group_id).users unless group_id.blank?
|
||||
end
|
||||
|
||||
def recipient_tokens=(ids)
|
||||
@recipient_tokens = ids
|
||||
add_recipients ids.split(",").collect { |id| User.find(id) }
|
||||
end
|
||||
|
||||
def reply_to=(message_id)
|
||||
@reply_to = Message.find(message_id)
|
||||
add_recipients([@reply_to.sender])
|
||||
self.subject = I18n.t('messages.model.reply_subject', :subject => @reply_to.subject)
|
||||
self.body = I18n.t('messages.model.reply_header', :user => @reply_to.sender.display, :when => I18n.l(@reply_to.created_at, :format => :short)) + "\n"
|
||||
@reply_to.body.each_line{ |l| self.body += I18n.t('messages.model.reply_indent', :line => l) }
|
||||
end
|
||||
|
||||
def mail_to=(user_id)
|
||||
user = User.find(user_id)
|
||||
add_recipients([user])
|
||||
end
|
||||
|
||||
# Returns true if this message is a system message, i.e. was sent automatically by Foodsoft itself.
|
||||
def system_message?
|
||||
self.sender_id.nil?
|
||||
end
|
||||
|
||||
def sender_name
|
||||
system_message? ? I18n.t('layouts.foodsoft') : sender.display rescue "?"
|
||||
end
|
||||
|
||||
def recipients
|
||||
User.find(recipients_ids)
|
||||
end
|
||||
|
||||
def deliver
|
||||
for user in recipients
|
||||
if user.receive_email?
|
||||
begin
|
||||
MessagesMailer.foodsoft_message(self, user).deliver
|
||||
rescue
|
||||
Rails.logger.warn "Deliver failed for user \##{user.id}: #{user.email}"
|
||||
end
|
||||
end
|
||||
end
|
||||
update_attribute(:email_state, 1)
|
||||
end
|
||||
|
||||
def is_readable_for?(user)
|
||||
!private || sender == user || recipients_ids.include?(user.id)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
/ insert_bottom ':root:last-child'
|
||||
= config_use_heading form, :use_messages do
|
||||
= config_input form, :mailing_list, as: :string, input_html: {class: 'input-xlarge'}
|
||||
= config_input form, :mailing_list_subscribe, as: :string, input_html: {class: 'input-xlarge'}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/ insert_after 'erb:contains("delete")'
|
||||
- if FoodsoftMessages.enabled?
|
||||
= link_to t('.send_message'), new_message_path(:message => {:group_id => @ordergroup.id}), class: 'btn'
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/ insert_after 'erb:contains("delete")'
|
||||
- if FoodsoftMessages.enabled?
|
||||
= link_to t('.send_message'), new_message_path(:message => {:mail_to => @user.id}), class: 'btn'
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/ insert_after 'erb:contains("delete")'
|
||||
- if FoodsoftMessages.enabled?
|
||||
= link_to_new_message(message_params: {group_id: @workgroup.id})
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/ insert_bottom 'tbody tr'
|
||||
- if FoodsoftMessages.enabled?
|
||||
%td= link_to_new_message(message_params: {group_id: ordergroup.id})
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/ insert_bottom 'tbody tr'
|
||||
- if FoodsoftMessages.enabled?
|
||||
%td= link_to_new_message(message_params: {mail_to: user.id})
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/ insert_after 'erb:contains("tasks")'
|
||||
- if FoodsoftMessages.enabled?
|
||||
= link_to_new_message message_params: {group_id: workgroup.id}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
/ insert_after 'erb:contains("tasks")'
|
||||
- if FoodsoftMessages.enabled?
|
||||
%li= link_to t('.write_message'), new_message_path
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
/ insert_after 'erb[silent]:contains("<dashboard_middle_mark>")'
|
||||
- if FoodsoftMessages.enabled?
|
||||
- unless Message.pub.empty?
|
||||
%section#messages
|
||||
%h2= t '.messages.title'
|
||||
= render 'messages/messages', messages: Message.pub.order('created_at DESC').limit(5), pagination: false
|
||||
%p= link_to t('.messages.view_all'), messages_path
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
/ insert_before 'erb:contains("simple_fields_for :notify")'
|
||||
- if FoodsoftMessages.enabled?
|
||||
= s.simple_fields_for :messages, defaults: { inline_label: true, label: false } do |messages|
|
||||
= messages.input 'send_as_email', as: :boolean, input_html: { checked: f.object.settings.messages['send_as_email'] }
|
||||
14
plugins/messages/app/views/messages/_messages.html.haml
Normal file
14
plugins/messages/app/views/messages/_messages.html.haml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
- if pagination
|
||||
- if Message.pub.count > 20
|
||||
= items_per_page
|
||||
= pagination_links_remote messages
|
||||
|
||||
- unless messages.empty?
|
||||
%table.table.table-striped
|
||||
%tbody
|
||||
- for message in messages
|
||||
%tr
|
||||
%td= format_subject(message, 130)
|
||||
%td= h(message.sender_name)
|
||||
%td= format_time(message.created_at)
|
||||
%td= link_to t('.reply'), new_message_path(:message => {:reply_to => message.id}), class: 'btn'
|
||||
6
plugins/messages/app/views/messages/index.html.haml
Normal file
6
plugins/messages/app/views/messages/index.html.haml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
- title t('.title')
|
||||
|
||||
- content_for :actionbar do
|
||||
= link_to t('.new'), new_message_path, class: 'btn btn-primary'
|
||||
#messages
|
||||
= render 'messages', messages: @messages, pagination: true
|
||||
1
plugins/messages/app/views/messages/index.js.haml
Normal file
1
plugins/messages/app/views/messages/index.js.haml
Normal file
|
|
@ -0,0 +1 @@
|
|||
$('#messages').html('#{j(render('messages', messages: @messages, pagination: true))}');
|
||||
46
plugins/messages/app/views/messages/new.haml
Normal file
46
plugins/messages/app/views/messages/new.haml
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
- content_for :javascript do
|
||||
:javascript
|
||||
$(function() {
|
||||
$('#message_recipient_tokens').tokenInput("#{users_path(:format => :json)}", {
|
||||
crossDomain: false,
|
||||
prePopulate: $('#message_recipient_tokens').data('pre'),
|
||||
hintText: '#{t '.search_user'}',
|
||||
noResultText: '#{t '.no_user_found'}',
|
||||
searchingText: '#{t '.search'}',
|
||||
theme: 'facebook'
|
||||
});
|
||||
|
||||
$('#message_sent_to_all').on('touchclick', function() {
|
||||
if ($(this).is(':checked')) {
|
||||
$('#recipients').slideUp();
|
||||
} else {
|
||||
$('#recipients').slideDown();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
- title t('.title')
|
||||
|
||||
= simple_form_for @message do |f|
|
||||
- if FoodsoftConfig[:mailing_list].blank?
|
||||
= f.input :sent_to_all, :as => :boolean
|
||||
- else
|
||||
%b= t('.list.desc', list: mail_to(FoodsoftConfig[:mailing_list])).html_safe
|
||||
%br/
|
||||
%small{:style => "color:grey"}
|
||||
= t '.list.subscribe_msg'
|
||||
%br/
|
||||
- if FoodsoftConfig[:mailing_list_subscribe].blank?
|
||||
= t('.list.subscribe', link: link_to(t('.list.wiki'), wiki_page_path('MailingListe'))).html_safe
|
||||
- else
|
||||
= t('.list.mail', email: mail_to(FoodsoftConfig[:mailing_list_subscribe])).html_safe
|
||||
|
||||
#recipients
|
||||
= f.input :recipient_tokens, :input_html => { 'data-pre' => User.where(id: @message.recipients_ids).map(&:token_attributes).to_json }
|
||||
= f.input :group_id, :as => :select, :collection => Group.undeleted.order('type DESC', 'name ASC').reject { |g| g.memberships.empty? }
|
||||
= f.input :private
|
||||
= f.input :subject, input_html: {class: 'input-xxlarge'}
|
||||
= f.input :body, input_html: {class: 'input-xxlarge', rows: 13}
|
||||
.form-actions
|
||||
= f.submit class: 'btn btn-primary'
|
||||
= link_to t('ui.or_cancel'), :back
|
||||
21
plugins/messages/app/views/messages/show.haml
Normal file
21
plugins/messages/app/views/messages/show.haml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
- title t('.title')
|
||||
|
||||
%div{:style => "width:40em"}
|
||||
%table{:style => "width:25em"}
|
||||
%tr
|
||||
%td= t '.from'
|
||||
%td=h @message.sender_name
|
||||
%tr
|
||||
%td= t '.subject'
|
||||
%td
|
||||
%b=h @message.subject
|
||||
%tr
|
||||
%td= t '.sent_on'
|
||||
%td= format_time(@message.created_at)
|
||||
%hr/
|
||||
%p= simple_format(h(@message.body))
|
||||
%hr/
|
||||
%p
|
||||
= link_to t('.reply'), new_message_path(:message => {:reply_to => @message.id}), class: 'btn'
|
||||
|
|
||||
= link_to t('.all_messages'), messages_path
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
= raw @message.body
|
||||
======================================================================
|
||||
\
|
||||
= raw t '.footer', reply_url: new_message_url('message[reply_to]' => @message.id), msg_url: message_url(@message), profile_url: my_profile_url
|
||||
8
plugins/messages/app/workers/message_notifier.rb
Normal file
8
plugins/messages/app/workers/message_notifier.rb
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
class MessageNotifier < UserNotifier
|
||||
@queue = :foodsoft_notifier
|
||||
|
||||
def self.message_deliver(args)
|
||||
message_id = args.first
|
||||
Message.find(message_id).deliver
|
||||
end
|
||||
end
|
||||
86
plugins/messages/config/locales/en.yml
Normal file
86
plugins/messages/config/locales/en.yml
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
en:
|
||||
activerecord:
|
||||
attributes:
|
||||
message:
|
||||
body: Body
|
||||
group_id: Group
|
||||
private: Private
|
||||
recipient_tokens: Recipients
|
||||
sent_to_all: Send to all members
|
||||
subject: Subject
|
||||
models:
|
||||
message: Message
|
||||
admin:
|
||||
ordergroups:
|
||||
show:
|
||||
send_message: Send message
|
||||
users:
|
||||
show:
|
||||
send_message: Send message
|
||||
config:
|
||||
hints:
|
||||
mailing_list: Mailing-list email address to use instead of the messaging system for mail to all members.
|
||||
mailing_list_subscribe: Email address where members can send an email to for subscribing.
|
||||
use_messages: Allow members to communicate with each other within Foodsoft.
|
||||
keys:
|
||||
use_messages: Messages
|
||||
mailing_list: Mailing-list
|
||||
mailing_list_subscribe: Mailing-list subscribe
|
||||
helpers:
|
||||
messages:
|
||||
write_message: Write message
|
||||
submit:
|
||||
message:
|
||||
create: send message
|
||||
home:
|
||||
index:
|
||||
messages:
|
||||
title: Newest Messages
|
||||
view_all: See all messages
|
||||
start_nav:
|
||||
write_message: Write message
|
||||
messages:
|
||||
create:
|
||||
notice: Message is saved and will be sent.
|
||||
index:
|
||||
new: New message
|
||||
title: Messages
|
||||
messages:
|
||||
reply: Reply
|
||||
model:
|
||||
reply_header: ! '%{user} wrote on %{when}:'
|
||||
reply_indent: ! '> %{line}'
|
||||
reply_subject: ! 'Re: %{subject}'
|
||||
new:
|
||||
list:
|
||||
desc: ! 'Please send messages to all using the mailing-list: %{list}'
|
||||
mail: for example with an email to %{email}.
|
||||
subscribe: You can find more about the mailing-list at %{link}.
|
||||
subscribe_msg: You may have to subscribe to the mailing-list first.
|
||||
wiki: Wiki (page Mailing-List)
|
||||
no_user_found: No user found
|
||||
search: Search ...
|
||||
search_user: Search user
|
||||
title: New message
|
||||
show:
|
||||
all_messages: All messages
|
||||
from: ! 'From:'
|
||||
reply: Reply
|
||||
sent_on: ! 'Sent:'
|
||||
subject: ! 'Subject:'
|
||||
title: Show message
|
||||
messages_mailer:
|
||||
foodsoft_message:
|
||||
footer: ! 'Reply: %{reply_url}
|
||||
|
||||
See message online: %{msg_url}
|
||||
|
||||
Messaging options: %{profile_url}
|
||||
|
||||
'
|
||||
navigation:
|
||||
messages: Messages
|
||||
simple_form:
|
||||
hints:
|
||||
message:
|
||||
private: Message doesn’t show in Foodsoft mail inbox
|
||||
5
plugins/messages/config/routes.rb
Normal file
5
plugins/messages/config/routes.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
Rails.application.routes.draw do
|
||||
scope '/:foodcoop' do
|
||||
resources :messages, :only => [:index, :show, :new, :create]
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# This migration has a ".skip" suffix to prevent it from being recognised as
|
||||
# a migration. While this migration is relevant for the messages plugin, it
|
||||
# was already included in stock foodsoft when messages were part of its core.
|
||||
# `rake db:install:migrations` would install this migration, resulting in an
|
||||
# attempt to create an already existing messages table.
|
||||
#
|
||||
# extracted from 20090120184410_road_to_version_three.rb
|
||||
class CreateMessages < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :messages do |t|
|
||||
t.references :sender
|
||||
t.text :recipients_ids
|
||||
t.string :subject, :null => false
|
||||
t.text :body
|
||||
t.integer :email_state, :default => 0, :null => false
|
||||
t.boolean :private, :default => false
|
||||
t.datetime :created_at
|
||||
end
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :messages
|
||||
end
|
||||
end
|
||||
23
plugins/messages/foodsoft_messages.gemspec
Normal file
23
plugins/messages/foodsoft_messages.gemspec
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
$:.push File.expand_path("../lib", __FILE__)
|
||||
|
||||
# Maintain your gem's version:
|
||||
require "foodsoft_messages/version"
|
||||
|
||||
# Describe your gem and declare its dependencies:
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "foodsoft_messages"
|
||||
s.version = FoodsoftMessages::VERSION
|
||||
s.authors = ["robwa"]
|
||||
s.email = ["foodsoft-messages@ini.tiative.net"]
|
||||
s.homepage = "https://github.com/foodcoops/foodsoft"
|
||||
s.summary = "Messaging plugin for foodsoft."
|
||||
s.description = "Adds the ability to exchange messages to foodsoft."
|
||||
|
||||
s.files = Dir["{app,config,db,lib}/**/*"] + ["Rakefile", "README.md"]
|
||||
s.test_files = Dir["test/**/*"]
|
||||
|
||||
s.add_dependency "rails"
|
||||
s.add_dependency "deface", "~> 1.0.0"
|
||||
|
||||
s.add_development_dependency "sqlite3"
|
||||
end
|
||||
11
plugins/messages/lib/foodsoft_messages.rb
Normal file
11
plugins/messages/lib/foodsoft_messages.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
require "foodsoft_messages/engine"
|
||||
require "foodsoft_messages/user_link"
|
||||
require "deface"
|
||||
|
||||
module FoodsoftMessages
|
||||
# Return whether messages are used or not.
|
||||
# Enabled by default in {FoodsoftConfig} since it used to be part of the foodsoft core.
|
||||
def self.enabled?
|
||||
FoodsoftConfig[:use_messages]
|
||||
end
|
||||
end
|
||||
19
plugins/messages/lib/foodsoft_messages/engine.rb
Normal file
19
plugins/messages/lib/foodsoft_messages/engine.rb
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
module FoodsoftMessages
|
||||
class Engine < ::Rails::Engine
|
||||
def navigation(primary, context)
|
||||
return unless FoodsoftMessages.enabled?
|
||||
return if primary[:foodcoop].nil?
|
||||
sub_nav = primary[:foodcoop].sub_navigation
|
||||
sub_nav.items <<
|
||||
SimpleNavigation::Item.new(primary, :messages, I18n.t('navigation.messages'), context.messages_path)
|
||||
# move to right before tasks item
|
||||
if i = sub_nav.items.index(sub_nav[:tasks])
|
||||
sub_nav.items.insert(i, sub_nav.items.delete_at(-1))
|
||||
end
|
||||
end
|
||||
|
||||
def default_foodsoft_config(cfg)
|
||||
cfg[:use_messages] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
26
plugins/messages/lib/foodsoft_messages/user_link.rb
Normal file
26
plugins/messages/lib/foodsoft_messages/user_link.rb
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
module FoodsoftMessages
|
||||
|
||||
module UserLink
|
||||
def self.included(base) # :nodoc:
|
||||
base.class_eval do
|
||||
|
||||
# modify user presentation link to writing a message for the user
|
||||
def show_user_link(user=@current_user)
|
||||
if user.nil? or not FoodsoftMessages.enabled?
|
||||
show_user user
|
||||
else
|
||||
link_to show_user(user), new_message_path('message[mail_to]' => user.id),
|
||||
:title => I18n.t('helpers.messages.write_message')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# modify existing helper
|
||||
ActiveSupport.on_load(:after_initialize) do
|
||||
ApplicationHelper.send :include, FoodsoftMessages::UserLink
|
||||
end
|
||||
3
plugins/messages/lib/foodsoft_messages/version.rb
Normal file
3
plugins/messages/lib/foodsoft_messages/version.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module FoodsoftMessages
|
||||
VERSION = "0.0.1"
|
||||
end
|
||||
21
plugins/wiki/README.md
Normal file
21
plugins/wiki/README.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
FoodsoftWiki
|
||||
============
|
||||
|
||||
This plugin adds wiki pages to foodsoft. A new 'Wiki' menu is added next to
|
||||
the 'Foodcoops' menu in the navigation bar.
|
||||
|
||||
This plugin is enabled by default in foodsoft, so you don't need to do anything
|
||||
to install it. If you still want to, for example when it has been disabled,
|
||||
add the following to foodsoft's Gemfile:
|
||||
|
||||
```Gemfile
|
||||
# we use the git version of acts_as_versioned, so this needs to be in foodsoft's Gemfile
|
||||
gem 'acts_as_versioned', git: 'git://github.com/technoweenie/acts_as_versioned.git'
|
||||
gem 'foodsoft_wiki', path: 'lib/foodsoft_wiki'
|
||||
```
|
||||
|
||||
This plugin introduces the foodcoop config option `use_wiki`, which can be set
|
||||
to `false` to disable the wiki. May be useful in multicoop deployments.
|
||||
|
||||
This plugin is part of the foodsoft package and uses the GPL-3 license (see
|
||||
foodsoft's LICENSE for the full license text).
|
||||
40
plugins/wiki/Rakefile
Normal file
40
plugins/wiki/Rakefile
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
#!/usr/bin/env rake
|
||||
begin
|
||||
require 'bundler/setup'
|
||||
rescue LoadError
|
||||
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
||||
end
|
||||
begin
|
||||
require 'rdoc/task'
|
||||
rescue LoadError
|
||||
require 'rdoc/rdoc'
|
||||
require 'rake/rdoctask'
|
||||
RDoc::Task = Rake::RDocTask
|
||||
end
|
||||
|
||||
RDoc::Task.new(:rdoc) do |rdoc|
|
||||
rdoc.rdoc_dir = 'rdoc'
|
||||
rdoc.title = 'FoodsoftWiki'
|
||||
rdoc.options << '--line-numbers'
|
||||
rdoc.rdoc_files.include('README.rdoc')
|
||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
||||
end
|
||||
|
||||
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
||||
load 'rails/tasks/engine.rake'
|
||||
|
||||
|
||||
|
||||
Bundler::GemHelper.install_tasks
|
||||
|
||||
require 'rake/testtask'
|
||||
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.libs << 'lib'
|
||||
t.libs << 'test'
|
||||
t.pattern = 'test/**/*_test.rb'
|
||||
t.verbose = false
|
||||
end
|
||||
|
||||
|
||||
task :default => :test
|
||||
BIN
plugins/wiki/app/assets/images/icons/feed-icon-14x14.png
Executable file
BIN
plugins/wiki/app/assets/images/icons/feed-icon-14x14.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 689 B |
BIN
plugins/wiki/app/assets/images/icons/feed-icon-28x28.png
Executable file
BIN
plugins/wiki/app/assets/images/icons/feed-icon-28x28.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
143
plugins/wiki/app/controllers/pages_controller.rb
Normal file
143
plugins/wiki/app/controllers/pages_controller.rb
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
# encoding: utf-8
|
||||
class PagesController < ApplicationController
|
||||
before_filter -> { require_plugin_enabled FoodsoftWiki }
|
||||
|
||||
skip_before_filter :authenticate, :only => :all
|
||||
before_filter :only => :all do
|
||||
authenticate_or_token(['wiki', 'all'])
|
||||
end
|
||||
before_filter do
|
||||
content_for :head, view_context.rss_meta_tag
|
||||
end
|
||||
|
||||
def index
|
||||
@page = Page.find_by_permalink "Home"
|
||||
|
||||
if @page
|
||||
render :action => 'show'
|
||||
else
|
||||
redirect_to all_pages_path
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
if params[:permalink]
|
||||
@page = Page.find_by_permalink(params[:permalink])
|
||||
elsif params[:id]
|
||||
page = Page.find_by_id(params[:id])
|
||||
if page.nil?
|
||||
flash[:error] = I18n.t('pages.cshow.error_noexist')
|
||||
redirect_to all_pages_path and return
|
||||
else
|
||||
redirect_to wiki_page_path(page.permalink) and return
|
||||
end
|
||||
end
|
||||
|
||||
if @page.nil?
|
||||
redirect_to new_page_path(:title => params[:permalink])
|
||||
elsif @page.redirect?
|
||||
page = Page.find_by_id(@page.redirect)
|
||||
unless page.nil?
|
||||
flash[:notice] = I18n.t('pages.cshow.redirect_notice', :page => @page.title)
|
||||
redirect_to wiki_page_path(page.permalink)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
@page = Page.new
|
||||
@page.title = params[:title].gsub("_", " ") if params[:title]
|
||||
@page.parent = Page.find_by_permalink(params[:parent]) if params[:parent]
|
||||
|
||||
respond_to do |format|
|
||||
format.html # new.html.erb
|
||||
format.xml { render :xml => @page }
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@page = Page.find(params[:id])
|
||||
end
|
||||
|
||||
def create
|
||||
@page = Page.new(params[:page].merge({:user => current_user}))
|
||||
|
||||
if params[:preview]
|
||||
render :action => 'new'
|
||||
else
|
||||
if @page.save
|
||||
flash[:notice] = I18n.t('pages.create.notice')
|
||||
redirect_to(wiki_page_path(@page.permalink))
|
||||
else
|
||||
render :action => "new"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
@page = Page.find(params[:id])
|
||||
@page.attributes = params[:page].merge({:user => current_user})
|
||||
|
||||
if params[:preview]
|
||||
@page.attributes = params[:page]
|
||||
render :action => 'edit'
|
||||
else
|
||||
if @page.save
|
||||
@page.parent_id = parent_id if (!params[:parent_id].blank? \
|
||||
and params[:parent_id] != @page_id)
|
||||
flash[:notice] = I18n.t('pages.update.notice')
|
||||
redirect_to wiki_page_path(@page.permalink)
|
||||
else
|
||||
render :action => "edit"
|
||||
end
|
||||
end
|
||||
|
||||
rescue ActiveRecord::StaleObjectError
|
||||
flash[:error] = I18n.t('pages.error_stale_object')
|
||||
redirect_to wiki_page_path(@page.permalink)
|
||||
end
|
||||
|
||||
def destroy
|
||||
@page = Page.find(params[:id])
|
||||
@page.destroy
|
||||
|
||||
flash[:notice] = I18n.t('pages.destroy.notice', :page => @page.title)
|
||||
redirect_to wiki_path
|
||||
end
|
||||
|
||||
def all
|
||||
@pages = Page.non_redirected
|
||||
@partial = params[:view] || 'recent_changes'
|
||||
|
||||
if params[:name]
|
||||
@pages = @pages.where("title LIKE ?", "%#{params[:name]}%").limit(20).order('updated_at DESC')
|
||||
@partial = 'title_list'
|
||||
else
|
||||
order = case @partial
|
||||
when 'recent_changes' then
|
||||
'updated_at DESC'
|
||||
when 'site_map' then
|
||||
'created_at DESC'
|
||||
when 'title_list' then
|
||||
'title DESC'
|
||||
end
|
||||
@pages.order(order)
|
||||
end
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.rss { render :layout => false }
|
||||
end
|
||||
end
|
||||
|
||||
def version
|
||||
@page = Page.find(params[:id])
|
||||
@version = Page::Version.find_by_page_id_and_lock_version params[:id], params[:version]
|
||||
end
|
||||
|
||||
def revert
|
||||
@page = Page.find(params[:id])
|
||||
@page.revert_to!(params[:version].to_i)
|
||||
|
||||
redirect_to wiki_page_path(@page.permalink)
|
||||
end
|
||||
end
|
||||
82
plugins/wiki/app/helpers/pages_helper.rb
Normal file
82
plugins/wiki/app/helpers/pages_helper.rb
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
module PagesHelper
|
||||
include WikiCloth
|
||||
|
||||
def rss_meta_tag
|
||||
tag('link', :rel => "alternate", :type => "application/rss+xml", :title => "RSS", :href => all_pages_rss_url).html_safe
|
||||
end
|
||||
|
||||
def wikified_body(body, title = nil)
|
||||
WikiCloth.new(:data => body+"\n",
|
||||
:link_handler => Wikilink.new,
|
||||
:params => {:referer => title})
|
||||
.to_html(wikicloth_render_options)
|
||||
.html_safe
|
||||
rescue => e
|
||||
"<span class='alert alert-error'>#{t('.wikicloth_exception', :msg => e)}</span>".html_safe # try the following with line breaks: === one === == two == = three =
|
||||
end
|
||||
|
||||
def link_to_wikipage(page, text = nil)
|
||||
if text == nil
|
||||
link_to page.title, wiki_page_path(:permalink => page.permalink)
|
||||
else
|
||||
link_to text, wiki_page_path(:permalink => page.permalink)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def link_to_wikipage_by_permalink(permalink, text = nil)
|
||||
unless permalink.blank?
|
||||
page = Page.find_by_permalink(permalink)
|
||||
if page.nil?
|
||||
if text.nil?
|
||||
link_to permalink, new_page_path(:title => permalink)
|
||||
else
|
||||
link_to text, new_page_path(:title => permalink)
|
||||
end
|
||||
else
|
||||
link_to_wikipage(page, text)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def generate_toc(body)
|
||||
toc = String.new
|
||||
body.gsub(/^([=]{1,6})\s*(.*?)\s*(\1)/) do
|
||||
number = $1.length - 1
|
||||
name = $2
|
||||
|
||||
toc << "*" * number + " #{name}\n"
|
||||
end
|
||||
|
||||
unless toc.blank?
|
||||
WikiCloth.new(:data => toc,
|
||||
:link_handler => Wikilink.new)
|
||||
.to_html(wikicloth_render_options)
|
||||
.gsub(/<li>([^<>\n]*)/) do
|
||||
name = $1
|
||||
anchor = name.gsub(/\s/, '_').gsub(/[^a-zA-Z_]/, '')
|
||||
"<li><a href='##{anchor}'>#{name.truncate(20)}</a>"
|
||||
end.html_safe
|
||||
end
|
||||
end
|
||||
|
||||
def parent_pages_to_select(current_page)
|
||||
unless current_page.homepage? # Homepage is the page trees root!
|
||||
Page.non_redirected.reject { |p| p == current_page or p.ancestors.include?(current_page) }
|
||||
else
|
||||
Array.new
|
||||
end
|
||||
end
|
||||
|
||||
# return url for all_pages rss feed
|
||||
def all_pages_rss_url(options={})
|
||||
token = TokenVerifier.new(['wiki', 'all']).generate
|
||||
all_pages_url({:format => 'rss', :token => token}.merge(options))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def wikicloth_render_options
|
||||
{:locale => I18n.locale} # workaround for wikicloth 0.8.0 https://github.com/nricciar/wikicloth/pull/59
|
||||
end
|
||||
end
|
||||
74
plugins/wiki/app/models/page.rb
Normal file
74
plugins/wiki/app/models/page.rb
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
class Page < ActiveRecord::Base
|
||||
include ActsAsTree
|
||||
|
||||
belongs_to :user, :foreign_key => 'updated_by'
|
||||
|
||||
acts_as_versioned version_column: :lock_version, limit: 20
|
||||
self.non_versioned_columns += %w(permalink created_at title)
|
||||
|
||||
acts_as_tree :order => "title"
|
||||
|
||||
attr_accessor :old_title # Save title to create redirect page when editing title
|
||||
|
||||
validates_presence_of :title, :body
|
||||
validates_uniqueness_of :permalink, :title
|
||||
|
||||
before_validation :set_permalink, :on => :create
|
||||
before_validation :update_permalink, :on => :update
|
||||
after_update :create_redirect
|
||||
|
||||
scope :non_redirected, -> { where(:redirect => nil) }
|
||||
scope :no_parent, -> { where(:parent_id => nil) }
|
||||
|
||||
def self.permalink(title)
|
||||
title.gsub(/[\/\.,;@\s]/, "_").gsub(/[\"\']/, "")
|
||||
end
|
||||
|
||||
def homepage?
|
||||
permalink == "Home"
|
||||
end
|
||||
|
||||
def set_permalink
|
||||
unless title.blank?
|
||||
self.permalink = Page.count == 0 ? "Home" : Page.permalink(title)
|
||||
end
|
||||
end
|
||||
|
||||
def diff
|
||||
current = versions.latest
|
||||
old = versions.where(["page_id = ? and lock_version < ?", current.page_id, current.lock_version]).order('lock_version DESC').first
|
||||
|
||||
if old
|
||||
o = ''
|
||||
Diffy::Diff.new(old.body, current.body).each do |line|
|
||||
case line
|
||||
when /^\+/ then o += "#{line.chomp}<br />" unless line.chomp == "+"
|
||||
when /^-/ then o += "#{line.chomp}<br />" unless line.chomp == "-"
|
||||
end
|
||||
end
|
||||
o
|
||||
else
|
||||
current.body
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def update_permalink
|
||||
if changed.include?("title")
|
||||
set_permalink
|
||||
self.old_title = changes["title"].first # Save title for creating redirect
|
||||
end
|
||||
end
|
||||
|
||||
def create_redirect
|
||||
unless old_title.blank?
|
||||
Page.create :redirect => id,
|
||||
:title => old_title,
|
||||
:body => I18n.t('model.page.redirect', :title => title),
|
||||
:permalink => Page.permalink(old_title),
|
||||
:updated_by => updated_by
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
9
plugins/wiki/app/views/pages/_body.html.haml
Normal file
9
plugins/wiki/app/views/pages/_body.html.haml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
- content = wikified_body @page.body, @page.title
|
||||
- toc = generate_toc @page.body
|
||||
|
||||
- unless toc.blank? or params[:preview]
|
||||
- content_for :sidebar do
|
||||
#wikitoc.well.well-small
|
||||
%h3= t '.title_toc'
|
||||
= toc
|
||||
= content
|
||||
85
plugins/wiki/app/views/pages/_form.html.haml
Normal file
85
plugins/wiki/app/views/pages/_form.html.haml
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
- if params[:preview]
|
||||
%section#wikiContent
|
||||
= render 'body'
|
||||
|
||||
.row-fluid
|
||||
.span8
|
||||
= simple_form_for @page do |f|
|
||||
= f.hidden_field :lock_version
|
||||
= f.input :title, input_html: {class: 'input-xxlarge'}
|
||||
= f.input :body, input_html: {class: 'input-xxlarge', rows: 20}
|
||||
= f.input :parent_id, as: :select, collection: parent_pages_to_select(@page)
|
||||
.form-actions
|
||||
= button_tag :name => 'preview', class: 'btn' do
|
||||
%i.icon-search= t '.preview'
|
||||
= button_tag class: 'btn' do
|
||||
%i.icon-save= t 'ui.save'
|
||||
= link_to t('ui.or_cancel'), @page
|
||||
|
||||
.span4
|
||||
%h3= t '.help.title'
|
||||
%table.table
|
||||
%tbody
|
||||
%tr
|
||||
%td(colspan=2)
|
||||
%b= t '.help.section_character'
|
||||
%tr
|
||||
%td
|
||||
%i= t '.help.italic'
|
||||
%td
|
||||
%pre
|
||||
''#{t '.help.italic'}''<br />
|
||||
%tr
|
||||
%td
|
||||
%b= t '.help.bold'
|
||||
%td
|
||||
%pre '''#{t '.help.bold'}'''<br />
|
||||
%tr
|
||||
%td= t '.help.noformat'
|
||||
%td
|
||||
%pre <nowiki>#{t '.help.text'}</nowiki>
|
||||
%tr
|
||||
%td(colspan=2)
|
||||
%b= t '.help.section_block'
|
||||
%tr
|
||||
%td= t '.help.headings'
|
||||
%td
|
||||
%pre
|
||||
\== #{t '.help.heading', level: 1} ==
|
||||
%pre
|
||||
\=== #{t '.help.heading', level: 2} ===
|
||||
%pre
|
||||
\==== #{t '.help.heading', level: 3} ====
|
||||
%tr
|
||||
%td= t '.help.unordered_list'
|
||||
%td
|
||||
%pre
|
||||
* #{t '.help.list_item_1'}
|
||||
%pre
|
||||
** #{t '.help.list_item_2'}
|
||||
%tr
|
||||
%td= t '.help.ordered_list'
|
||||
%td
|
||||
%pre
|
||||
\# #{t '.help.list_item_1'}
|
||||
%pre
|
||||
\# #{t '.help.list_item_2'}
|
||||
%tr
|
||||
%td(colspan=2)
|
||||
%b= t '.help.section_link'
|
||||
%tr
|
||||
%td= t '.help.wiki_links'
|
||||
%td
|
||||
%pre
|
||||
[[#{t '.help.wiki_link_ex'}]]
|
||||
%tr
|
||||
%td= t '.help.external_links'
|
||||
%td
|
||||
%pre
|
||||
[http://example.net #{t '.help.external_link_ex'}]
|
||||
%tr
|
||||
%td(colspan=2)
|
||||
%b= t '.help.section_table'
|
||||
%tr
|
||||
%td!= t '.help.see_tables', tables_link: link_to(t('.help.tables_link'), "http://www.mediawiki.org/wiki/Help:Tables", :target => '_blank')
|
||||
|
||||
8
plugins/wiki/app/views/pages/_page_list_item.html.haml
Normal file
8
plugins/wiki/app/views/pages/_page_list_item.html.haml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
-ident = 20 * level
|
||||
%tr
|
||||
%td{:style => "padding-left: #{ident}px"}
|
||||
= link_to page.title, wiki_page_path(page.permalink)
|
||||
%td #{show_user page.user} (#{format_datetime_timespec(page.updated_at, t('.date_format'))})
|
||||
-if siteMap == 1
|
||||
-for child in page.children.all
|
||||
= render :partial => 'page_list_item', :locals => {:page => child, :level => level+1, :siteMap => 1}
|
||||
8
plugins/wiki/app/views/pages/_recent_changes.html.haml
Normal file
8
plugins/wiki/app/views/pages/_recent_changes.html.haml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
%table.table.table-striped
|
||||
%thead
|
||||
%tr
|
||||
%th= t 'pages.title'
|
||||
%th= t 'pages.last_updated'
|
||||
%tbody
|
||||
- for page in @pages
|
||||
= render :partial => "page_list_item", :locals => {:page => page, :level => 0, :siteMap => 0}
|
||||
12
plugins/wiki/app/views/pages/_site_map.html.haml
Normal file
12
plugins/wiki/app/views/pages/_site_map.html.haml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
%table.table.table-striped
|
||||
%thead
|
||||
%tr
|
||||
%th= t 'pages.title'
|
||||
%th= t 'pages.last_updated'
|
||||
- homepage = Page.find_by_permalink('Home')
|
||||
- unless homepage.nil?
|
||||
= render :partial => 'page_list_item', :locals => {:page => homepage, :level => 0, :siteMap => 1}
|
||||
%tbody
|
||||
- for page in @pages
|
||||
- if page.id != homepage.try(:id)
|
||||
= render :partial => 'page_list_item', :locals => {:page => page, :level => 0, :siteMap => 1}
|
||||
8
plugins/wiki/app/views/pages/_title_list.html.haml
Normal file
8
plugins/wiki/app/views/pages/_title_list.html.haml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
%table.table.table-striped
|
||||
%thead
|
||||
%tr
|
||||
%th= t 'pages.title'
|
||||
%th= t 'pages.last_updated'
|
||||
%tbody
|
||||
- for page in @pages
|
||||
= render :partial => "page_list_item", :locals => {:page => page, :level => 0, :siteMap => 0}
|
||||
18
plugins/wiki/app/views/pages/all.html.haml
Normal file
18
plugins/wiki/app/views/pages/all.html.haml
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
- title t('.title'), false
|
||||
|
||||
- content_for :sidebar do
|
||||
= link_to t('.new_page'), new_page_path, class: 'btn btn-primary'
|
||||
|
||||
.navbar
|
||||
.navbar-inner
|
||||
%ul.nav
|
||||
%li= link_to t('.recent_changes'), all_pages_path(:view => 'recent_changes')
|
||||
%li= link_to t('.title_list'), all_pages_path(:view => 'title_list')
|
||||
%li= link_to t('.site_map'), all_pages_path(:view => 'site_map')
|
||||
%li= link_to image_tag('icons/feed-icon-14x14.png', :alt => 'RSS Feed'), all_pages_rss_url
|
||||
= form_tag all_pages_path, method: :get, class: 'form-search pull-right' do
|
||||
= text_field_tag :name, params[:name], class: 'input-medium search-query',
|
||||
placeholder: t('.search.placeholder')
|
||||
= submit_tag t('.search.action'), class: 'btn'
|
||||
|
||||
= render @partial
|
||||
19
plugins/wiki/app/views/pages/all.rss.builder
Normal file
19
plugins/wiki/app/views/pages/all.rss.builder
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
xml.instruct! :xml, :version => "1.0"
|
||||
xml.rss :version => "2.0" do
|
||||
xml.channel do
|
||||
xml.title FoodsoftConfig[:name] + " Wiki"
|
||||
xml.description ""
|
||||
xml.link FoodsoftConfig[:homepage]
|
||||
|
||||
for page in @pages
|
||||
xml.item do
|
||||
xml.title page.title
|
||||
xml.description page.diff, :type => "html"
|
||||
xml.author User.find_by_id(page.updated_by).try(:display)
|
||||
xml.pubDate page.updated_at.to_s(:rfc822)
|
||||
xml.link wiki_page_path(page.permalink)
|
||||
xml.guid page.updated_at.to_i
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
3
plugins/wiki/app/views/pages/edit.html.haml
Normal file
3
plugins/wiki/app/views/pages/edit.html.haml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
- title t('.title')
|
||||
|
||||
= render 'form'
|
||||
3
plugins/wiki/app/views/pages/new.html.haml
Normal file
3
plugins/wiki/app/views/pages/new.html.haml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
- title t('.title')
|
||||
|
||||
= render 'form'
|
||||
51
plugins/wiki/app/views/pages/show.html.haml
Normal file
51
plugins/wiki/app/views/pages/show.html.haml
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
- title @page.title, false
|
||||
|
||||
- content_for :sidebar do
|
||||
%p
|
||||
= link_to edit_page_path(@page), class: 'btn btn-primary' do
|
||||
%i.icon-edit= t '.edit'
|
||||
.well.well-small
|
||||
%ul.nav.nav-list
|
||||
%li
|
||||
%li= link_to t('.versions', count: @page.versions.count), "#versions", 'data-toggle-this' => '#versions'
|
||||
- unless @page.children.empty?
|
||||
%li= link_to t('.subpages'), "#subpages", 'data-toggle-this' => '#subpages'
|
||||
|
||||
#versions.well.well-small{:style => "display:none"}
|
||||
%h3= t '.title_versions'
|
||||
%ul.unstyled
|
||||
- @page.versions.reverse.each do |version|
|
||||
%li
|
||||
= link_to I18n.l(version.updated_at, :format => t('.date_format')), version_page_path(@page, :version => version.lock_version)
|
||||
= "(#{show_user(User.find_by_id(version.updated_by))})"
|
||||
|
||||
- unless @page.children.empty?
|
||||
#subpages.well.well-small{:style => "display:none"}
|
||||
%h3= t '.subpages'
|
||||
%ul.unstyled
|
||||
- @page.children.each do |page|
|
||||
%li= link_to_wikipage(page)
|
||||
|
||||
%ul.breadcrumb
|
||||
%li
|
||||
= link_to_wikipage_by_permalink("Home", "Foodcoop-Wiki")
|
||||
%span.divider /
|
||||
- for page in @page.ancestors.reverse
|
||||
%li
|
||||
= link_to_wikipage(page)
|
||||
%span.divider /
|
||||
%li.active= @page.title
|
||||
|
||||
|
||||
#wikiContent
|
||||
.page-header
|
||||
%h1= @page.title
|
||||
= render :partial => 'body'
|
||||
|
||||
%hr.clear/
|
||||
%p
|
||||
= link_to edit_page_path(@page), class: 'btn btn-primary' do
|
||||
%i.icon-edit= t '.edit'
|
||||
= link_to t('.delete'), @page, class: 'btn btn-danger', :method => :delete,
|
||||
:data => {:confirm => t('.delete_confirm')}
|
||||
!= '| ' + t('.last_updated', user: show_user(@page.user), when: format_datetime(@page.updated_at))
|
||||
11
plugins/wiki/app/views/pages/version.html.haml
Normal file
11
plugins/wiki/app/views/pages/version.html.haml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
- title t('.title', title: @page.title, version: @version.lock_version)
|
||||
|
||||
- content_for :sidebar do
|
||||
%h3= t '.title_version'
|
||||
%b= "#{format_datetime_timespec(@version.updated_at, t('.date_format'))}"
|
||||
%ul
|
||||
%li= t '.author', user: show_user(User.find(@version.updated_by))
|
||||
%li= link_to t('.view_current'), wiki_page_path(:permalink => @page.permalink)
|
||||
%li= link_to t('.revert'), revert_page_path(@page, :version => @version.lock_version)
|
||||
|
||||
= wikified_body @version.body
|
||||
85
plugins/wiki/config/locales/en.yml
Normal file
85
plugins/wiki/config/locales/en.yml
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
en:
|
||||
activerecord:
|
||||
attributes:
|
||||
page:
|
||||
body: Body
|
||||
parent_id: Parent page
|
||||
title: Title
|
||||
model:
|
||||
page:
|
||||
redirect: Redirect to [[%{title}]]...
|
||||
navigation:
|
||||
wiki:
|
||||
all_pages: All Pages
|
||||
home: Home
|
||||
title: Wiki
|
||||
pages:
|
||||
all:
|
||||
new_page: Create new page
|
||||
recent_changes: Recent changes
|
||||
search:
|
||||
action: Search
|
||||
placeholder: Page title ..
|
||||
site_map: Sitemap
|
||||
title: All Wiki pages
|
||||
title_list: List of pages
|
||||
body:
|
||||
title_toc: Content
|
||||
create:
|
||||
notice: Page was created
|
||||
cshow:
|
||||
error_noexist: Page doesn’t exist!
|
||||
redirect_notice: Redirected from %{page} ...
|
||||
destroy:
|
||||
notice: The page '%{page}' and all subpages have been deleted successfully.
|
||||
edit:
|
||||
title: Edit page
|
||||
error_stale_object: Warning, the page has just been edited by someone else. Please try again.
|
||||
form:
|
||||
help:
|
||||
bold: bold
|
||||
external_link_ex: External page
|
||||
external_links: External links
|
||||
heading: level %{level}
|
||||
headings: Heading
|
||||
italic: italic
|
||||
list_item_1: First list item
|
||||
list_item_2: Second list item
|
||||
noformat: No wiki-formatting
|
||||
ordered_list: Numbered list
|
||||
section_block: Block formatting
|
||||
section_character: Character formatting
|
||||
section_link: Link formatting
|
||||
section_table: Table formatting
|
||||
see_tables: see %{tables_link}
|
||||
tables_link: Tables
|
||||
text: text
|
||||
title: Quick formatting help
|
||||
unordered_list: Item list
|
||||
wiki_link_ex: Foodsoft Wiki Page
|
||||
wiki_links: Wiki-links
|
||||
preview: Preview
|
||||
last_updated: Last updated
|
||||
new:
|
||||
title: Create new wiki page
|
||||
page_list_item:
|
||||
date_format: ! '%a, %d %B %Y %H:%M:%S'
|
||||
show:
|
||||
date_format: ! '%d-%m-%y %H:%M'
|
||||
delete: Delete page
|
||||
delete_confirm: ! 'Warning: all subpages will be deleted as well. Are you sure?'
|
||||
edit: Edit page
|
||||
last_updated: Last updated by <b>%{user}</b> on %{when}
|
||||
subpages: subpages
|
||||
title_versions: Versions
|
||||
versions: Versions (%{count})
|
||||
title: Title
|
||||
update:
|
||||
notice: Page was updated
|
||||
version:
|
||||
author: ! 'Author: %{user}'
|
||||
date_format: ! '%a, %d-%m-%Y, %H:%M'
|
||||
revert: Revert to this version
|
||||
title: ! '%{title} - version %{version}'
|
||||
title_version: Version
|
||||
view_current: See current version
|
||||
15
plugins/wiki/config/routes.rb
Normal file
15
plugins/wiki/config/routes.rb
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
Rails.application.routes.draw do
|
||||
|
||||
scope '/:foodcoop' do
|
||||
|
||||
resources :pages do
|
||||
get :all, :on => :collection
|
||||
get :version, :on => :member
|
||||
get :revert, :on => :member
|
||||
end
|
||||
get '/wiki/:permalink' => 'pages#show', :as => 'wiki_page' # , :constraints => {:permalink => /[^\s]+/}
|
||||
get '/wiki' => 'pages#show', :defaults => {:permalink => 'Home'}, :as => 'wiki'
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
23
plugins/wiki/db/migrate/20090325175756_create_pages.rb
Normal file
23
plugins/wiki/db/migrate/20090325175756_create_pages.rb
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
class CreatePages < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :pages do |t|
|
||||
t.string :title
|
||||
t.text :body
|
||||
t.string :permalink
|
||||
t.integer :lock_version, :default => 0
|
||||
t.integer :updated_by
|
||||
t.integer :redirect
|
||||
t.integer :parent_id
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
add_index :pages, :title
|
||||
add_index :pages, :permalink
|
||||
Page.create_versioned_table # Automaticly creates pages_versions table
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :pages
|
||||
Page.drop_versioned_table
|
||||
end
|
||||
end
|
||||
25
plugins/wiki/foodsoft_wiki.gemspec
Normal file
25
plugins/wiki/foodsoft_wiki.gemspec
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
$:.push File.expand_path("../lib", __FILE__)
|
||||
|
||||
# Maintain your gem's version:
|
||||
require "foodsoft_wiki/version"
|
||||
|
||||
# Describe your gem and declare its dependencies:
|
||||
Gem::Specification.new do |s|
|
||||
s.name = "foodsoft_wiki"
|
||||
s.version = FoodsoftWiki::VERSION
|
||||
s.authors = ["wvengen"]
|
||||
s.email = ["dev-foodsoft@willem.engen.nl"]
|
||||
s.homepage = "https://github.com/foodcoops/foodsoft"
|
||||
s.summary = "Wiki plugin for foodsoft."
|
||||
s.description = "Adds a wiki to foodsoft."
|
||||
|
||||
s.files = Dir["{app,config,db,lib}/**/*"] + ["Rakefile", "README.md"]
|
||||
s.test_files = Dir["test/**/*"]
|
||||
|
||||
s.add_dependency "rails"
|
||||
s.add_dependency 'wikicloth'
|
||||
s.add_dependency 'acts_as_versioned' # need git version, make sure that is included in foodsoft's Gemfile
|
||||
s.add_dependency 'diffy'
|
||||
s.add_dependency 'content_for_in_controllers'
|
||||
s.add_development_dependency "sqlite3"
|
||||
end
|
||||
13
plugins/wiki/lib/foodsoft_wiki.rb
Normal file
13
plugins/wiki/lib/foodsoft_wiki.rb
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
require 'wikicloth'
|
||||
require 'acts_as_versioned'
|
||||
require 'diffy'
|
||||
require 'content_for_in_controllers'
|
||||
require 'foodsoft_wiki/engine'
|
||||
|
||||
module FoodsoftWiki
|
||||
# Return whether the wiki is used or not.
|
||||
# Enabled by default in {FoodsoftConfig} since it used to be part of the foodsoft core.
|
||||
def self.enabled?
|
||||
FoodsoftConfig[:use_wiki]
|
||||
end
|
||||
end
|
||||
19
plugins/wiki/lib/foodsoft_wiki/engine.rb
Normal file
19
plugins/wiki/lib/foodsoft_wiki/engine.rb
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
module FoodsoftWiki
|
||||
class Engine < ::Rails::Engine
|
||||
def navigation(primary, ctx)
|
||||
return unless FoodsoftWiki.enabled?
|
||||
primary.item :wiki, I18n.t('navigation.wiki.title'), '#', id: nil do |subnav|
|
||||
subnav.item :wiki_home, I18n.t('navigation.wiki.home'), ctx.wiki_path, id: nil
|
||||
subnav.item :all_pages, I18n.t('navigation.wiki.all_pages'), ctx.all_pages_path, id: nil
|
||||
end
|
||||
# move this last added item to just after the foodcoop menu
|
||||
if i = primary.items.index(primary[:foodcoop])
|
||||
primary.items.insert(i+1, primary.items.delete_at(-1))
|
||||
end
|
||||
end
|
||||
|
||||
def default_foodsoft_config(cfg)
|
||||
cfg[:use_wiki] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
3
plugins/wiki/lib/foodsoft_wiki/version.rb
Normal file
3
plugins/wiki/lib/foodsoft_wiki/version.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
module FoodsoftWiki
|
||||
VERSION = "0.0.1"
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue