adds an RSS feed for pages/all
This commit is contained in:
parent
b4dfa50409
commit
0d0ff90a64
16 changed files with 170 additions and 6 deletions
|
@ -23,6 +23,8 @@ PATH
|
||||||
specs:
|
specs:
|
||||||
foodsoft_wiki (0.0.1)
|
foodsoft_wiki (0.0.1)
|
||||||
acts_as_versioned
|
acts_as_versioned
|
||||||
|
content_for_in_controllers
|
||||||
|
diffy
|
||||||
rails (~> 3.2.15)
|
rails (~> 3.2.15)
|
||||||
wikicloth
|
wikicloth
|
||||||
|
|
||||||
|
@ -102,6 +104,7 @@ GEM
|
||||||
execjs
|
execjs
|
||||||
coffee-script-source (1.6.3)
|
coffee-script-source (1.6.3)
|
||||||
commonjs (0.2.7)
|
commonjs (0.2.7)
|
||||||
|
content_for_in_controllers (0.0.2)
|
||||||
coveralls (0.7.0)
|
coveralls (0.7.0)
|
||||||
multi_json (~> 1.3)
|
multi_json (~> 1.3)
|
||||||
rest-client
|
rest-client
|
||||||
|
@ -112,6 +115,7 @@ GEM
|
||||||
database_cleaner (1.2.0)
|
database_cleaner (1.2.0)
|
||||||
debug_inspector (0.0.2)
|
debug_inspector (0.0.2)
|
||||||
diff-lcs (1.2.5)
|
diff-lcs (1.2.5)
|
||||||
|
diffy (3.0.1)
|
||||||
docile (1.1.1)
|
docile (1.1.1)
|
||||||
erubis (2.7.0)
|
erubis (2.7.0)
|
||||||
eventmachine (1.0.3)
|
eventmachine (1.0.3)
|
||||||
|
|
|
@ -30,7 +30,7 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def authenticate(role = 'any')
|
def authenticate(role = 'any')
|
||||||
# Attempt to retrieve authenticated user from controller instance or session...
|
# Attempt to retrieve authenticated user from controller instance or session...
|
||||||
if !current_user
|
if !current_user
|
||||||
|
@ -87,6 +87,18 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def authenticate_or_token(prefix, role = 'any')
|
||||||
|
if not params[:token].blank?
|
||||||
|
begin
|
||||||
|
TokenVerifier.new(prefix).verify(params[:token])
|
||||||
|
rescue ActiveSupport::MessageVerifier::InvalidSignature
|
||||||
|
redirect_to root_path, alert: I18n.t('application.controller.error_token')
|
||||||
|
end
|
||||||
|
else
|
||||||
|
authenticate(role)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Stores this controller instance as a thread local varibale to be accessible from outside ActionController/ActionView.
|
# Stores this controller instance as a thread local varibale to be accessible from outside ActionController/ActionView.
|
||||||
def store_controller
|
def store_controller
|
||||||
Thread.current[:application_controller] = self
|
Thread.current[:application_controller] = self
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
= csrf_meta_tags
|
= csrf_meta_tags
|
||||||
= stylesheet_link_tag "application", :media => "all"
|
= stylesheet_link_tag "application", :media => "all"
|
||||||
//%link(href="images/favicon.ico" rel="shortcut icon")
|
//%link(href="images/favicon.ico" rel="shortcut icon")
|
||||||
|
|
||||||
= yield(:head)
|
= yield(:head)
|
||||||
|
|
||||||
%body
|
%body
|
||||||
|
|
|
@ -271,6 +271,7 @@ en:
|
||||||
error_authn: Authentication required!
|
error_authn: Authentication required!
|
||||||
error_denied: Access denied!
|
error_denied: Access denied!
|
||||||
error_members_only: This action is only available to members of the group!
|
error_members_only: This action is only available to members of the group!
|
||||||
|
error_token: Access denied (invalid token)!
|
||||||
article_categories:
|
article_categories:
|
||||||
create:
|
create:
|
||||||
notice: Category was stored
|
notice: Category was stored
|
||||||
|
|
BIN
lib/foodsoft_wiki/app/assets/images/icons/feed-icon-14x14.png
Executable file
BIN
lib/foodsoft_wiki/app/assets/images/icons/feed-icon-14x14.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 689 B |
BIN
lib/foodsoft_wiki/app/assets/images/icons/feed-icon-28x28.png
Executable file
BIN
lib/foodsoft_wiki/app/assets/images/icons/feed-icon-28x28.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.7 KiB |
|
@ -1,6 +1,14 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
class PagesController < ApplicationController
|
class PagesController < ApplicationController
|
||||||
|
|
||||||
|
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
|
def index
|
||||||
@page = Page.find_by_permalink "Home"
|
@page = Page.find_by_permalink "Home"
|
||||||
|
|
||||||
|
@ -114,6 +122,10 @@ class PagesController < ApplicationController
|
||||||
end
|
end
|
||||||
@pages.order(order)
|
@pages.order(order)
|
||||||
end
|
end
|
||||||
|
respond_to do |format|
|
||||||
|
format.html
|
||||||
|
format.rss { render :layout => false }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def version
|
def version
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
module PagesHelper
|
module PagesHelper
|
||||||
include WikiCloth
|
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)
|
def wikified_body(body, title = nil)
|
||||||
render_opts = {:locale => I18n.locale} # workaround for wikicloth 0.8.0 https://github.com/nricciar/wikicloth/pull/59
|
render_opts = {:locale => I18n.locale} # workaround for wikicloth 0.8.0 https://github.com/nricciar/wikicloth/pull/59
|
||||||
WikiCloth.new({:data => body+"\n", :link_handler => Wikilink.new, :params => {:referer => title}}).to_html(render_opts).html_safe
|
WikiCloth.new({:data => body+"\n", :link_handler => Wikilink.new, :params => {:referer => title}}).to_html(render_opts).html_safe
|
||||||
|
@ -57,4 +61,10 @@ module PagesHelper
|
||||||
Array.new
|
Array.new
|
||||||
end
|
end
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -33,6 +33,24 @@ class Page < ActiveRecord::Base
|
||||||
self.permalink = Page.count == 0 ? "Home" : Page.permalink(title)
|
self.permalink = Page.count == 0 ? "Home" : Page.permalink(title)
|
||||||
end
|
end
|
||||||
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
|
protected
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
%li= link_to t('.recent_changes'), all_pages_path(:view => 'recent_changes')
|
%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('.title_list'), all_pages_path(:view => 'title_list')
|
||||||
%li= link_to t('.site_map'), all_pages_path(:view => 'site_map')
|
%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
|
= form_tag all_pages_path, method: :get, class: 'form-search pull-right' do
|
||||||
= text_field_tag :name, params[:name], class: 'input-medium search-query',
|
= text_field_tag :name, params[:name], class: 'input-medium search-query',
|
||||||
placeholder: t('.search.placeholder')
|
placeholder: t('.search.placeholder')
|
||||||
|
|
19
lib/foodsoft_wiki/app/views/pages/all.rss.builder
Normal file
19
lib/foodsoft_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(page.updated_by).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
|
|
@ -19,6 +19,7 @@ Gem::Specification.new do |s|
|
||||||
s.add_dependency "rails", "~> 3.2.15"
|
s.add_dependency "rails", "~> 3.2.15"
|
||||||
s.add_dependency 'wikicloth'
|
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 '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"
|
s.add_development_dependency "sqlite3"
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
require 'wikicloth'
|
require 'wikicloth'
|
||||||
require 'acts_as_versioned'
|
require 'acts_as_versioned'
|
||||||
|
require "diffy"
|
||||||
require 'foodsoft_wiki/engine'
|
require 'foodsoft_wiki/engine'
|
||||||
|
|
||||||
module FoodsoftWiki
|
module FoodsoftWiki
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
require 'stringio'
|
||||||
|
|
||||||
# put in here all foodsoft tasks
|
# put in here all foodsoft tasks
|
||||||
# => :environment loads the environment an gives easy access to the application
|
# => :environment loads the environment an gives easy access to the application
|
||||||
|
|
||||||
|
@ -23,8 +25,6 @@ module Colors
|
||||||
end
|
end
|
||||||
include Colors
|
include Colors
|
||||||
|
|
||||||
require 'stringio'
|
|
||||||
|
|
||||||
namespace :foodsoft do
|
namespace :foodsoft do
|
||||||
desc "Setup foodsoft"
|
desc "Setup foodsoft"
|
||||||
task :setup_development do
|
task :setup_development do
|
||||||
|
@ -82,10 +82,11 @@ end
|
||||||
|
|
||||||
def setup_app_config
|
def setup_app_config
|
||||||
file = 'config/app_config.yml'
|
file = 'config/app_config.yml'
|
||||||
|
sample = Rails.root.join("#{file}.SAMPLE")
|
||||||
return nil if skip?(file)
|
return nil if skip?(file)
|
||||||
|
|
||||||
puts yellow "Copying #{file}..."
|
puts yellow "Copying #{file}..."
|
||||||
%x( cp #{Rails.root.join("#{file}.SAMPLE")} #{Rails.root.join(file)} )
|
%x( cp #{sample} #{Rails.root.join(file)} )
|
||||||
reminder(file)
|
reminder(file)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -120,6 +121,8 @@ def start_server
|
||||||
puts blue "Start your server running 'bundle exec rails s' and visit http://localhost:3000"
|
puts blue "Start your server running 'bundle exec rails s' and visit http://localhost:3000"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Helper Methods
|
||||||
|
|
||||||
def ask(question, answers = false)
|
def ask(question, answers = false)
|
||||||
puts question
|
puts question
|
||||||
input = STDIN.gets.chomp
|
input = STDIN.gets.chomp
|
||||||
|
@ -149,3 +152,4 @@ def capture_stdout
|
||||||
ensure
|
ensure
|
||||||
$stdout = STDOUT
|
$stdout = STDOUT
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
37
lib/token_verifier.rb
Normal file
37
lib/token_verifier.rb
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
class TokenVerifier < ActiveSupport::MessageVerifier
|
||||||
|
|
||||||
|
def initialize(prefix)
|
||||||
|
super(self.class.secret)
|
||||||
|
@_prefix = prefix.is_a?(Array) ? prefix.join(':') : prefix.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
def generate(message=nil)
|
||||||
|
fullmessage = [FoodsoftConfig.scope, @_prefix]
|
||||||
|
fullmessage.append(message) unless message.nil?
|
||||||
|
super(fullmessage)
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify(message)
|
||||||
|
r = super(message)
|
||||||
|
raise InvalidMessage unless r.is_a?(Array) and r.length >= 2 and r.length <= 3
|
||||||
|
raise InvalidScope unless r[0] == FoodsoftConfig.scope
|
||||||
|
raise InvalidPrefix unless r[1] == @_prefix
|
||||||
|
# return original message
|
||||||
|
if r.length > 2
|
||||||
|
r[2]
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class InvalidMessage < ActiveSupport::MessageVerifier::InvalidSignature; end
|
||||||
|
class InvalidScope < ActiveSupport::MessageVerifier::InvalidSignature; end
|
||||||
|
class InvalidPrefix < ActiveSupport::MessageVerifier::InvalidSignature; end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def self.secret
|
||||||
|
Foodsoft::Application.config.secret_token
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
44
spec/lib/token_verifier_spec.rb
Normal file
44
spec/lib/token_verifier_spec.rb
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
require_relative '../spec_helper'
|
||||||
|
|
||||||
|
describe TokenVerifier do
|
||||||
|
let (:prefix) { 'xyz' }
|
||||||
|
let (:v) { TokenVerifier.new(prefix) }
|
||||||
|
let (:msg) { v.generate }
|
||||||
|
|
||||||
|
it 'validates' do
|
||||||
|
expect{ v.verify(msg) }.to_not raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'validates when recreated' do
|
||||||
|
v2 = TokenVerifier.new(prefix)
|
||||||
|
expect{ v2.verify(msg) }.to_not raise_error
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not validate with a different prefix' do
|
||||||
|
v2 = TokenVerifier.new('abc')
|
||||||
|
expect { v2.verify(msg) }.to raise_error(TokenVerifier::InvalidPrefix)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not validate in a different foodcoop scope' do
|
||||||
|
msg
|
||||||
|
oldscope = FoodsoftConfig.scope
|
||||||
|
begin
|
||||||
|
FoodsoftConfig.scope = Faker::Lorem.words(1)
|
||||||
|
v2 = TokenVerifier.new(prefix)
|
||||||
|
expect{ v2.verify(msg) }.to raise_error(TokenVerifier::InvalidScope)
|
||||||
|
ensure
|
||||||
|
FoodsoftConfig.scope = oldscope
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not validate a random string' do
|
||||||
|
expect{ v.verify(Faker::Lorem.characters(100)) }.to raise_error(ActiveSupport::MessageVerifier::InvalidSignature)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns the message' do
|
||||||
|
data = [5, {'hi' => :there}, 'bye', []]
|
||||||
|
msg = v.generate(data)
|
||||||
|
expect(v.verify(msg)).to eq data
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in a new issue