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:
|
||||
foodsoft_wiki (0.0.1)
|
||||
acts_as_versioned
|
||||
content_for_in_controllers
|
||||
diffy
|
||||
rails (~> 3.2.15)
|
||||
wikicloth
|
||||
|
||||
|
@ -102,6 +104,7 @@ GEM
|
|||
execjs
|
||||
coffee-script-source (1.6.3)
|
||||
commonjs (0.2.7)
|
||||
content_for_in_controllers (0.0.2)
|
||||
coveralls (0.7.0)
|
||||
multi_json (~> 1.3)
|
||||
rest-client
|
||||
|
@ -112,6 +115,7 @@ GEM
|
|||
database_cleaner (1.2.0)
|
||||
debug_inspector (0.0.2)
|
||||
diff-lcs (1.2.5)
|
||||
diffy (3.0.1)
|
||||
docile (1.1.1)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.0.3)
|
||||
|
|
|
@ -87,6 +87,18 @@ class ApplicationController < ActionController::Base
|
|||
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.
|
||||
def store_controller
|
||||
Thread.current[:application_controller] = self
|
||||
|
|
|
@ -271,6 +271,7 @@ en:
|
|||
error_authn: Authentication required!
|
||||
error_denied: Access denied!
|
||||
error_members_only: This action is only available to members of the group!
|
||||
error_token: Access denied (invalid token)!
|
||||
article_categories:
|
||||
create:
|
||||
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
|
||||
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
|
||||
@page = Page.find_by_permalink "Home"
|
||||
|
||||
|
@ -114,6 +122,10 @@ class PagesController < ApplicationController
|
|||
end
|
||||
@pages.order(order)
|
||||
end
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.rss { render :layout => false }
|
||||
end
|
||||
end
|
||||
|
||||
def version
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
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)
|
||||
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
|
||||
|
@ -57,4 +61,10 @@ module PagesHelper
|
|||
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
|
||||
end
|
||||
|
|
|
@ -34,6 +34,24 @@ class Page < ActiveRecord::Base
|
|||
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
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
%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')
|
||||
|
|
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 '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
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
require 'wikicloth'
|
||||
require 'acts_as_versioned'
|
||||
require "diffy"
|
||||
require 'foodsoft_wiki/engine'
|
||||
|
||||
module FoodsoftWiki
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
require 'stringio'
|
||||
|
||||
# put in here all foodsoft tasks
|
||||
# => :environment loads the environment an gives easy access to the application
|
||||
|
||||
|
@ -23,8 +25,6 @@ module Colors
|
|||
end
|
||||
include Colors
|
||||
|
||||
require 'stringio'
|
||||
|
||||
namespace :foodsoft do
|
||||
desc "Setup foodsoft"
|
||||
task :setup_development do
|
||||
|
@ -82,10 +82,11 @@ end
|
|||
|
||||
def setup_app_config
|
||||
file = 'config/app_config.yml'
|
||||
sample = Rails.root.join("#{file}.SAMPLE")
|
||||
return nil if skip?(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)
|
||||
end
|
||||
|
||||
|
@ -120,6 +121,8 @@ def start_server
|
|||
puts blue "Start your server running 'bundle exec rails s' and visit http://localhost:3000"
|
||||
end
|
||||
|
||||
# Helper Methods
|
||||
|
||||
def ask(question, answers = false)
|
||||
puts question
|
||||
input = STDIN.gets.chomp
|
||||
|
@ -149,3 +152,4 @@ def capture_stdout
|
|||
ensure
|
||||
$stdout = STDOUT
|
||||
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