Merge pull request #245 from fsmanuel/rss_feed + 1

This commit is contained in:
wvengen 2014-01-06 13:55:32 +01:00
commit 69a29b8296
16 changed files with 171 additions and 6 deletions

View File

@ -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)

View File

@ -30,7 +30,7 @@ class ApplicationController < ActionController::Base
end
private
def authenticate(role = 'any')
# Attempt to retrieve authenticated user from controller instance or session...
if !current_user
@ -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

View File

@ -8,7 +8,7 @@
= csrf_meta_tags
= stylesheet_link_tag "application", :media => "all"
//%link(href="images/favicon.ico" rel="shortcut icon")
= yield(:head)
%body

View File

@ -277,6 +277,7 @@ en:
error_denied: You are not allowed to view the requested page. If you think you should, ask an administrator to give you appropriate permissions. If you have access to multiple user accounts, you might want to %{sign_in}.
error_denied_sign_in: sign in as another user
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

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -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

View File

@ -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
@ -59,4 +63,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

View File

@ -33,6 +33,24 @@ class Page < ActiveRecord::Base
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

View File

@ -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')

View 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

View File

@ -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

View File

@ -1,5 +1,7 @@
require 'wikicloth'
require 'acts_as_versioned'
require 'diffy'
require 'content_for_in_controllers'
require 'foodsoft_wiki/engine'
module FoodsoftWiki

View File

@ -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
View 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

View 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