Soks 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.txt +5 -4
- data/bin/soks-create-wiki.rb +153 -19
- data/contrib/easyprompt.rb +58 -0
- data/contrib/easyprompt_licence.txt +504 -0
- data/contrib/redcloth-2.0.11.rb +3 -1
- data/lib/authenticators.rb +18 -2
- data/lib/soks-helpers.rb +207 -157
- data/lib/soks-model.rb +131 -114
- data/lib/soks-servlet.rb +54 -35
- data/lib/soks-storage.rb +134 -0
- data/lib/soks-upgrade-0.0.2.rb +70 -0
- data/lib/soks-utils.rb +129 -19
- data/lib/soks-view.rb +136 -62
- data/lib/soks.rb +3 -1
- data/{template → templates/default}/attachment/logo.png +0 -0
- data/templates/default/attachment/logo.tiff +0 -0
- data/templates/default/attachment/newpage.js +41 -0
- data/templates/default/attachment/print_stylesheet.css +7 -0
- data/templates/default/attachment/rss.png +0 -0
- data/{template → templates/default}/attachment/stylesheet.css +44 -17
- data/templates/default/banned_titles.txt +31 -0
- data/templates/default/content/Bug%3A%20In%20a%20list%20of%20links%2C%20the%20last%20link%20is%20sometimes%20not%20linked.textile +10 -0
- data/templates/default/content/Bug%3A%20Symbols%20are%20not%20always%20correctly%20rendered%20in%20html.textile +3 -0
- data/templates/default/content/Bug%3A%20Uploads%20are%20not%20password%20protected.textile +3 -0
- data/templates/default/content/How%20to%20administrate%20this%20wiki.textile +62 -0
- data/templates/default/content/How%20to%20change%20the%20way%20this%20wiki%20looks.textile +30 -0
- data/templates/default/content/How%20to%20export%20a%20site%20from%20this%20wiki.textile +60 -0
- data/{template → templates/default}/content/How%20to%20hack%20soks.textile +3 -2
- data/{template → templates/default}/content/How%20to%20import%20a%20site%20from%20instiki.textile +1 -1
- data/templates/default/content/How%20to%20use%20this%20wiki.textile +27 -0
- data/templates/default/content/List%20of%20changes.textile +35 -0
- data/{template → templates/default}/content/Picture%20of%20a%20pair%20of%20soks.textile +0 -0
- data/{template → templates/default}/content/Soks%20Licence.textile +0 -0
- data/templates/default/content/home%20page.textile +17 -0
- data/templates/default/start.rb +94 -0
- data/templates/default/version.txt +1 -0
- data/{template → templates/default}/views/Page_content.rhtml +0 -0
- data/templates/default/views/Page_edit.rhtml +61 -0
- data/templates/default/views/Page_meta.rhtml +40 -0
- data/templates/default/views/Page_print.rhtml +6 -0
- data/templates/default/views/Page_revisions.rhtml +19 -0
- data/templates/default/views/Page_rss.rhtml +55 -0
- data/{template → templates/default}/views/Page_search_results.rhtml +1 -1
- data/templates/default/views/Page_view.rhtml +4 -0
- data/templates/default/views/UploadPage_edit.rhtml +38 -0
- data/templates/default/views/frame.rhtml +41 -0
- data/templates/default/views/messages.yaml +6 -0
- data/templates/instiki/attachment/header_backdrop.png +0 -0
- data/templates/instiki/attachment/instiki_style_sheet.css +199 -0
- data/templates/instiki/attachment/logo.tiff +0 -0
- data/templates/instiki/attachment/logotext.png +0 -0
- data/templates/instiki/attachment/newpage.js +41 -0
- data/templates/instiki/attachment/rss.png +0 -0
- data/templates/instiki/banned_titles.txt +31 -0
- data/templates/instiki/content/AutomaticSummary.textile +24 -0
- data/templates/instiki/content/How%20to%20export%20a%20site%20from%20this%20wiki.textile +60 -0
- data/templates/instiki/content/How%20to%20hack%20soks.textile +61 -0
- data/templates/instiki/content/How%20to%20import%20a%20site%20from%20instiki.textile +13 -0
- data/{template → templates/instiki}/content/Improving%20the%20style%20of%20this%20wiki.textile +2 -2
- data/templates/instiki/content/Known%20bugs.textile +8 -0
- data/templates/instiki/content/List%20of%20changes.textile +34 -0
- data/templates/instiki/content/Picture%20of%20a%20pair%20of%20soks.textile +1 -0
- data/templates/instiki/content/Pointers%20on%20adjusting%20the%20settings.textile +62 -0
- data/templates/instiki/content/Pointers%20on%20how%20to%20use%20this%20wiki.textile +27 -0
- data/templates/instiki/content/Recent%20Blog%20Entries.textile +3 -0
- data/templates/instiki/content/Recent%20Changes%20to%20This%20Site.textile +48 -0
- data/templates/instiki/content/Site%20Index.textile +16 -0
- data/templates/instiki/content/Soks%20Licence.textile +64 -0
- data/{template → templates/instiki}/content/home%20page.textile +9 -4
- data/templates/instiki/start.rb +85 -0
- data/templates/instiki/version.txt +1 -0
- data/templates/instiki/views/Page_content.rhtml +1 -0
- data/templates/instiki/views/Page_edit.rhtml +8 -0
- data/templates/instiki/views/Page_meta.rhtml +34 -0
- data/templates/instiki/views/Page_print.rhtml +6 -0
- data/templates/instiki/views/Page_revisions.rhtml +17 -0
- data/templates/instiki/views/Page_rss.rhtml +55 -0
- data/templates/instiki/views/Page_search_results.rhtml +18 -0
- data/templates/instiki/views/Page_view.rhtml +2 -0
- data/templates/instiki/views/UploadPage_edit.rhtml +16 -0
- data/templates/instiki/views/frame.rhtml +90 -0
- data/templates/instiki/views/messages.yaml +6 -0
- data/templates/rails/attachment/2colheader.css +77 -0
- data/templates/rails/attachment/basics.css +98 -0
- data/templates/rails/attachment/header_backdrop.png +0 -0
- data/templates/rails/attachment/logo.tiff +0 -0
- data/templates/rails/attachment/logotext.png +0 -0
- data/templates/rails/attachment/newpage.js +41 -0
- data/templates/rails/attachment/rss.png +0 -0
- data/templates/rails/banned_titles.txt +31 -0
- data/templates/rails/content/AutomaticSummary.textile +24 -0
- data/templates/rails/content/How%20to%20export%20a%20site%20from%20this%20wiki.textile +60 -0
- data/templates/rails/content/How%20to%20hack%20soks.textile +61 -0
- data/templates/rails/content/How%20to%20import%20a%20site%20from%20instiki.textile +13 -0
- data/templates/rails/content/Improving%20the%20style%20of%20this%20wiki.textile +30 -0
- data/templates/rails/content/Known%20bugs.textile +8 -0
- data/templates/rails/content/List%20of%20changes.textile +34 -0
- data/templates/rails/content/Picture%20of%20a%20pair%20of%20soks.textile +1 -0
- data/templates/rails/content/Pointers%20on%20adjusting%20the%20settings.textile +62 -0
- data/templates/rails/content/Pointers%20on%20how%20to%20use%20this%20wiki.textile +27 -0
- data/templates/rails/content/Recent%20Blog%20Entries.textile +3 -0
- data/templates/rails/content/Recent%20Changes%20to%20This%20Site.textile +48 -0
- data/templates/rails/content/Site%20Index.textile +16 -0
- data/templates/rails/content/Soks%20Licence.textile +64 -0
- data/templates/rails/content/home%20page.textile +23 -0
- data/templates/rails/start.rb +85 -0
- data/templates/rails/version.txt +1 -0
- data/templates/rails/views/Page_content.rhtml +1 -0
- data/templates/rails/views/Page_edit.rhtml +61 -0
- data/templates/rails/views/Page_meta.rhtml +38 -0
- data/templates/rails/views/Page_print.rhtml +6 -0
- data/templates/rails/views/Page_revisions.rhtml +19 -0
- data/templates/rails/views/Page_rss.rhtml +55 -0
- data/templates/rails/views/Page_search_results.rhtml +19 -0
- data/templates/rails/views/Page_view.rhtml +3 -0
- data/templates/rails/views/UploadPage_edit.rhtml +38 -0
- data/templates/rails/views/frame.rhtml +60 -0
- data/templates/rails/views/messages.yaml +6 -0
- metadata +122 -28
- data/template/content/How%20to%20export%20a%20site%20from%20this%20wiki.textile +0 -5
- data/template/content/Pointers%20on%20adjusting%20the%20settings.textile +0 -39
- data/template/content/Pointers%20on%20how%20to%20use%20this%20wiki.textile +0 -21
- data/template/content/Recent%20Changes%20to%20This%20Site.textile +0 -203
- data/template/start.rb +0 -74
- data/template/views/AttachmentPage_edit.rhtml +0 -36
- data/template/views/ImagePage_edit.rhtml +0 -36
- data/template/views/Page_edit.rhtml +0 -34
- data/template/views/Page_print.rhtml +0 -5
- data/template/views/Page_revisions.rhtml +0 -18
- data/template/views/Page_rss.rhtml +0 -34
- data/template/views/Page_view.rhtml +0 -3
- data/template/views/frame.rhtml +0 -34
data/lib/soks-model.rb
CHANGED
|
@@ -1,90 +1,122 @@
|
|
|
1
1
|
# Revision stores changes as a diff against the more recent content version
|
|
2
2
|
class Revision
|
|
3
|
-
attr_reader
|
|
3
|
+
attr_reader :number, :author, :page
|
|
4
|
+
attr_reader :changes, :created_on
|
|
5
|
+
alias :revised_on :created_on
|
|
4
6
|
|
|
5
|
-
def initialize( number, changes, author )
|
|
6
|
-
@number, @changes, @author = number, changes, author
|
|
7
|
-
@created_at = Time.now
|
|
7
|
+
def initialize( page, number, changes, author, created_on = Time.now )
|
|
8
|
+
@page, @number, @changes, @author, @created_on = page, number, changes, author, created_on
|
|
8
9
|
end
|
|
9
10
|
|
|
10
|
-
# Recreates the content of the page
|
|
11
|
-
# to more recent versions.
|
|
12
|
-
def content
|
|
13
|
-
|
|
14
|
-
page.revision( @number + 1 ) ? page.revision( @number + 1 ).previous_content( page ) : page.content
|
|
11
|
+
# Recreates the content of the page AFTER this revision had been made.
|
|
12
|
+
# Done by recursively applying diffs to more recent versions.
|
|
13
|
+
def content
|
|
14
|
+
page.revision( @number + 1 ) ? page.revision( @number + 1 ).previous_content : page.content
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
# Recreateds the content of the page BEFORE this revision had been made
|
|
18
|
+
def previous_content
|
|
19
|
+
content.split("\n").unpatch!(@changes).join("\n")
|
|
19
20
|
end
|
|
21
|
+
|
|
22
|
+
# Delegates to the Page object so that can see previous versions
|
|
23
|
+
def textile( content = self.content ) page.textile( content ) end
|
|
24
|
+
|
|
25
|
+
def method_missing( symbol, *args )
|
|
26
|
+
raise(ArgumentError, "Revision does not respond to #{symbol}", caller) unless @page && @page.respond_to?( symbol )
|
|
27
|
+
@page.send symbol, *args
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# To allow the contents to be dumped in a class independent way.
|
|
31
|
+
# Must match the order of the variables used in initialize
|
|
32
|
+
def to_a() [@number, @changes, @author, @created_on] end
|
|
20
33
|
end
|
|
21
34
|
|
|
22
35
|
class Page
|
|
23
|
-
|
|
36
|
+
attr_accessor :name, :content, :revisions
|
|
24
37
|
attr_accessor :links_from, :links_to, :inserted_into
|
|
25
|
-
|
|
38
|
+
alias :to_s :name
|
|
39
|
+
|
|
26
40
|
# Returns an empty version of itself.
|
|
27
41
|
def self.empty( name )
|
|
28
|
-
empty = self.new( name
|
|
42
|
+
empty = self.new( name )
|
|
43
|
+
empty.revise( $MESSAGES[:Type_what_you_want_here_and_click_save], "NoOne" )
|
|
29
44
|
class << empty
|
|
30
|
-
def textile; "[[
|
|
45
|
+
def textile; "[[#{$MESSAGES[:Create]} #{name} => /edit/#{name} ]]" end
|
|
31
46
|
def empty?; true; end
|
|
32
47
|
end
|
|
33
48
|
empty
|
|
34
49
|
end
|
|
35
50
|
|
|
36
|
-
def initialize( name
|
|
51
|
+
def initialize( name )
|
|
37
52
|
@name, @content, @revisions = name, "", []
|
|
38
53
|
@links_from, @links_to = [], []
|
|
39
|
-
@inserted_into
|
|
40
|
-
revise content, author
|
|
54
|
+
@inserted_into = []
|
|
41
55
|
end
|
|
42
|
-
|
|
43
|
-
alias :textile :content
|
|
44
|
-
alias :name_for_index :name
|
|
45
|
-
alias :to_s :name
|
|
46
56
|
|
|
47
57
|
# Revises the content of this page, creating a new revision class that stores the changes
|
|
48
|
-
def revise(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@revisions
|
|
52
|
-
|
|
58
|
+
def revise( new_content, author )
|
|
59
|
+
if the_same_author_recently_revised_this_page( author )
|
|
60
|
+
changes = changes_between( previous_content, new_content )
|
|
61
|
+
@revisions[-1] = Revision.new( self, @revisions.length, changes , author )
|
|
62
|
+
else
|
|
63
|
+
changes = changes_between( @content, new_content )
|
|
64
|
+
return nil if changes.empty?
|
|
65
|
+
@revisions << Revision.new( self, @revisions.length, changes , author )
|
|
53
66
|
end
|
|
67
|
+
@content = new_content
|
|
68
|
+
@revisions.last
|
|
54
69
|
end
|
|
55
70
|
|
|
56
71
|
# Returns the content of this page to that of a previous version
|
|
57
72
|
def rollback( number, author )
|
|
58
|
-
|
|
59
|
-
revise( "page deleted", author )
|
|
60
|
-
else
|
|
61
|
-
revise( @revisions[ number ].content( self ), author )
|
|
62
|
-
end
|
|
73
|
+
revise( ( number < 0 ) ? $MESSAGES[:page_deleted] : @revisions[ number ].content, author )
|
|
63
74
|
end
|
|
64
75
|
|
|
65
|
-
def revision( number )
|
|
76
|
+
def revision( number ) @revisions[ number ] end
|
|
66
77
|
|
|
67
78
|
def deleted?
|
|
68
|
-
( content.strip.downcase ==
|
|
69
|
-
( content =~
|
|
79
|
+
( content.strip.downcase == $MESSAGES[:page_deleted] ) ||
|
|
80
|
+
( content =~ /^#{$MESSAGES[:content_moved_to]} /i )
|
|
70
81
|
end
|
|
71
82
|
|
|
72
83
|
def empty?; @revisions.empty? end
|
|
84
|
+
|
|
85
|
+
def <=>( otherpage ) self.score <=> otherpage.score end
|
|
86
|
+
|
|
87
|
+
def score; @links_from.size + @links_to.size end
|
|
88
|
+
|
|
89
|
+
def created_on; @revisions.first.created_on end
|
|
73
90
|
|
|
74
|
-
def
|
|
91
|
+
def is_inserted_into( page )
|
|
92
|
+
@inserted_into << page unless @inserted_into.include? page
|
|
93
|
+
end
|
|
75
94
|
|
|
76
|
-
def
|
|
95
|
+
def textile( content = @content ) content end
|
|
96
|
+
|
|
97
|
+
def name_for_index; name.downcase end
|
|
77
98
|
|
|
78
|
-
def watch( person ) ( @watchers << person ).uniq! end
|
|
79
|
-
def watching?( person ) @watchers.include? person end
|
|
80
|
-
def unwatch( person ) @watchers.delete( person ) end
|
|
81
|
-
|
|
82
|
-
def is_inserted_into( page ) (@inserted_into << page).uniq! end
|
|
83
|
-
|
|
84
99
|
# Any unhandled calls are passed onto the latest revision (e.g. author, creation time etc)
|
|
85
|
-
def method_missing(
|
|
86
|
-
@revisions.last.
|
|
87
|
-
|
|
100
|
+
def method_missing( symbol, *args )
|
|
101
|
+
if @revisions.last && @revisions.last.respond_to?(symbol)
|
|
102
|
+
@revisions.last.send symbol, *args
|
|
103
|
+
else
|
|
104
|
+
raise ArgumentError,"Page does not respond to #{symbol}", caller
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
private
|
|
109
|
+
|
|
110
|
+
def changes_between( old_content, new_content )
|
|
111
|
+
old_content.split("\n").diff( new_content.split("\n") ).map { |changeset| changeset.map { |change| change.to_a } }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def the_same_author_recently_revised_this_page( author )
|
|
115
|
+
return false if empty?
|
|
116
|
+
return false unless author == self.author
|
|
117
|
+
((Time.now - self.revised_on) < (60*5) ) # 5 Minutes
|
|
118
|
+
end
|
|
119
|
+
|
|
88
120
|
end
|
|
89
121
|
|
|
90
122
|
#Serves as a marker, so ImagePage and AttachmentPage can re-use the same view templates
|
|
@@ -92,40 +124,45 @@ class UploadPage < Page
|
|
|
92
124
|
end
|
|
93
125
|
|
|
94
126
|
class ImagePage < UploadPage
|
|
95
|
-
def textile()
|
|
127
|
+
def textile( content = @content )
|
|
96
128
|
deleted? ? content : "!#{content}(#{@name})!:/#{@name.url_encode}\n"
|
|
97
129
|
end
|
|
98
130
|
|
|
99
|
-
def name_for_index; @name[
|
|
131
|
+
def name_for_index; @name[10..-1].strip.downcase end
|
|
100
132
|
end
|
|
101
133
|
|
|
102
134
|
class AttachmentPage < UploadPage
|
|
103
|
-
def textile()
|
|
135
|
+
def textile( content = @content )
|
|
104
136
|
deleted? ? content : %Q{"#{@name}":#{content}\n}
|
|
105
137
|
end
|
|
106
|
-
def name_for_index; @name[ 9..-1].strip
|
|
138
|
+
def name_for_index; @name[ 9..-1].strip.downcase end
|
|
107
139
|
end
|
|
108
140
|
|
|
141
|
+
# This class has turned into a behmoth, need to refactor.
|
|
109
142
|
class Wiki
|
|
143
|
+
include WikiFlatFileStore
|
|
110
144
|
include Enumerable
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
@pages = Hash.new
|
|
115
|
-
@page_classes = [
|
|
145
|
+
include Notify # Will notify any watchers if underlying files change
|
|
146
|
+
|
|
147
|
+
PAGE_CLASSES = [
|
|
116
148
|
[ /^picture of/i, ImagePage ],
|
|
117
149
|
[ /^attached/i, AttachmentPage ],
|
|
118
150
|
[ /.*/, Page ]
|
|
119
151
|
]
|
|
120
|
-
|
|
152
|
+
|
|
153
|
+
def initialize( folder )
|
|
154
|
+
@folder = folder
|
|
155
|
+
@pages = {}
|
|
156
|
+
load_all_pages
|
|
157
|
+
start_watching_files
|
|
121
158
|
end
|
|
122
159
|
|
|
123
160
|
def page( name )
|
|
124
|
-
|
|
161
|
+
page_named( name )|| new_page( name, :empty )
|
|
125
162
|
end
|
|
126
163
|
|
|
127
|
-
def each
|
|
128
|
-
@pages.each { |name, page| yield [name, page] unless page.deleted? }
|
|
164
|
+
def each( exclude_deleted = true )
|
|
165
|
+
@pages.each { |name, page| yield [name, page] unless exclude_deleted && page.deleted? }
|
|
129
166
|
end
|
|
130
167
|
|
|
131
168
|
def exists?( name )
|
|
@@ -133,76 +170,56 @@ class Wiki
|
|
|
133
170
|
end
|
|
134
171
|
|
|
135
172
|
def revise( pagename, content, author )
|
|
136
|
-
mutate( pagename
|
|
173
|
+
mutate( pagename ) { |page| page.revise( content, author ) }
|
|
137
174
|
end
|
|
138
175
|
|
|
139
176
|
def rollback( pagename, number, author )
|
|
140
177
|
mutate( pagename ) { |page| page.rollback( number, author ) }
|
|
141
178
|
end
|
|
142
179
|
|
|
143
|
-
def watch( pagename, person )
|
|
144
|
-
mutate( pagename ) { |page| page.watch( person ) }
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
def unwatch( pagename, person )
|
|
148
|
-
mutate( pagename ) { |page| page.unwatch( person ) }
|
|
149
|
-
end
|
|
150
|
-
|
|
151
180
|
private
|
|
152
181
|
|
|
153
|
-
def
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def load_all_pages_in( folder )
|
|
165
|
-
Dir.foreach( folder ) do |filename|
|
|
166
|
-
$stderr.puts "Loading #{filename}"
|
|
167
|
-
load_page( filename ) if filename =~ /\.textile$/
|
|
168
|
-
end
|
|
169
|
-
$stderr.puts "All loaded"
|
|
182
|
+
def start_watching_files
|
|
183
|
+
return unless $SETTINGS[:check_files_every]
|
|
184
|
+
Thread.new do
|
|
185
|
+
loop do
|
|
186
|
+
sleep $SETTINGS[:check_files_every]
|
|
187
|
+
load_all_pages
|
|
188
|
+
end
|
|
189
|
+
end.priority = -5
|
|
170
190
|
end
|
|
171
|
-
|
|
172
|
-
def
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
content = IO.readlines( File.join( @folder, filename ) ).join
|
|
176
|
-
revisions = load_revisions_for( filename )
|
|
177
|
-
|
|
178
|
-
page = class_for( page_name ).new( page_name, content, 'imported' )
|
|
179
|
-
page.revisions.replace( revisions ) if revisions
|
|
180
|
-
@pages[ page.name.downcase ] = page
|
|
191
|
+
|
|
192
|
+
def new_page( name, initializer = :new )
|
|
193
|
+
PAGE_CLASSES.each do |regex,klass|
|
|
194
|
+
return klass.send( initializer, name) if name =~ regex
|
|
181
195
|
end
|
|
182
196
|
end
|
|
183
|
-
|
|
184
|
-
def
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
197
|
+
|
|
198
|
+
def mutate( pagename )
|
|
199
|
+
didexist = exists? pagename
|
|
200
|
+
check_disk_for_updated_page pagename
|
|
201
|
+
page = page_named( pagename ) || new_page( pagename )
|
|
202
|
+
revision = yield page
|
|
203
|
+
if revision
|
|
204
|
+
save page
|
|
205
|
+
notify :page_revised, page, revision
|
|
206
|
+
if page.deleted?
|
|
207
|
+
notify :page_deleted, page, revision
|
|
208
|
+
elsif !didexist
|
|
209
|
+
notify :page_created, page, revision
|
|
210
|
+
end
|
|
190
211
|
end
|
|
191
|
-
return nil
|
|
192
212
|
end
|
|
193
213
|
|
|
194
|
-
def
|
|
195
|
-
|
|
196
|
-
|
|
214
|
+
def add_page_to_index( page )
|
|
215
|
+
@pages[ page.name.downcase ] = page
|
|
216
|
+
page
|
|
197
217
|
end
|
|
198
218
|
|
|
199
|
-
def
|
|
200
|
-
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
def class_for( name )
|
|
204
|
-
@page_classes.each do |regex,klass|
|
|
205
|
-
return klass if name =~ regex
|
|
206
|
-
end
|
|
219
|
+
def page_named( pagename )
|
|
220
|
+
@pages[ pagename.downcase ]
|
|
207
221
|
end
|
|
222
|
+
|
|
208
223
|
end
|
|
224
|
+
|
|
225
|
+
|
data/lib/soks-servlet.rb
CHANGED
|
@@ -1,40 +1,69 @@
|
|
|
1
1
|
#!/usr/local/bin/ruby
|
|
2
2
|
require 'authenticators'
|
|
3
|
+
require 'yaml'
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
$SETTINGS = {
|
|
6
|
+
:name => 'test',
|
|
7
|
+
:description => 'A Soks Wiki',
|
|
8
|
+
:root_directory => 'soks-wiki',
|
|
9
|
+
:check_files_every => 60, # Seconds
|
|
10
|
+
:url => 'http://localhost:8000',
|
|
11
|
+
:port => 8000,
|
|
12
|
+
:dont_frame_templates => ['print','rss'],
|
|
13
|
+
:strict_html_removal => true, # True to prevent users from adding html.
|
|
14
|
+
:authenticators => [ [ %r{/(view|rss|print|find|meta)/.*}, WEBrick::HTTPAuth::NoAuthenticationRequired.new ],
|
|
15
|
+
# [ %r{/upload/.*}, WEBrick::HTTPAuth::NotPermitted.new ],
|
|
16
|
+
# [ %r{/(edit|save)/home page}, WEBrick::HTTPAuth::SiteWidePassword.new('password','You need to enter the site wide password to edit the home page') ],
|
|
17
|
+
# [ %r{/(view|edit|save)/private.*},WEBrick::HTTPAuth::BasicAuth.new( :UserDB => htpasswd, :Realm => realm ) ], # See webrick documentation
|
|
18
|
+
[ %r{.*}, WEBrick::HTTPAuth::AskForUserName.new( 'No password, just enter a name') ]
|
|
19
|
+
]
|
|
20
|
+
}
|
|
6
21
|
|
|
7
22
|
class WikiServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
8
23
|
|
|
9
|
-
def initialize( server, wiki,
|
|
10
|
-
@server, @wiki, @name, @wikiurl, @
|
|
24
|
+
def initialize( server, wiki, settings )
|
|
25
|
+
@server, @wiki, @name, @wikiurl, @authenticators = server, wiki, settings[:name] , settings[:url] , settings[:authenticators]
|
|
11
26
|
end
|
|
12
27
|
|
|
13
28
|
def service( request, response )
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
29
|
+
case request.path
|
|
30
|
+
when /\/(\w+?)\/(.+)/
|
|
31
|
+
verb, pagename = $1, $2
|
|
32
|
+
authenticate request, response
|
|
33
|
+
if self.respond_to?( "do#{verb.capitalize}" )
|
|
34
|
+
self.send( "do#{verb.capitalize}", request, response, pagename, request.user )
|
|
35
|
+
else
|
|
36
|
+
response.body = @wiki.view( pagename, verb, request.user )
|
|
37
|
+
end
|
|
38
|
+
when /\/(.+)/ ; redirect( response, $1, 'view' ) # No command given
|
|
39
|
+
when "/" ; redirect( response, "Home Page", 'view' ) # No page or command given
|
|
20
40
|
end
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if self.respond_to?( "do#{verb.capitalize}" )
|
|
24
|
-
self.send( "do#{verb.capitalize}", request, response, pagename.join('/'), request.user )
|
|
25
|
-
else
|
|
26
|
-
response.body = @wiki.view( pagename.join('/'), verb, request.user )
|
|
27
|
-
end
|
|
41
|
+
|
|
28
42
|
response['Content-Type'] ||= "text/html"
|
|
43
|
+
response['Cache-control'] ||= 'no-cache'
|
|
44
|
+
response['Pragma'] ||= 'no-cache'
|
|
29
45
|
end
|
|
30
46
|
|
|
47
|
+
def authenticate( request, response )
|
|
48
|
+
@authenticators.each do |path_regex,authenticator|
|
|
49
|
+
if request.path.downcase =~ path_regex
|
|
50
|
+
authenticator.authenticate( request, response )
|
|
51
|
+
break
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
31
56
|
def redirect( response, pagename, verb = 'view' )
|
|
32
57
|
pagename = pagename.url_encode # Reformat into url encoding
|
|
33
58
|
response.set_redirect(WEBrick::HTTPStatus::Found, verb ? "#{@wikiurl}/#{verb}/#{pagename}" : "#{@wikiurl}/#{pagename}")
|
|
34
59
|
end
|
|
60
|
+
|
|
61
|
+
def doWiki( request, response, pagename, person )
|
|
62
|
+
redirect( response, pagename.gsub(/([a-z])([A-Z])/,'\1 \2') )
|
|
63
|
+
end
|
|
35
64
|
|
|
36
65
|
def doFind( request, response, pagename, person )
|
|
37
|
-
response.body = @wiki.find(
|
|
66
|
+
response.body = @wiki.find( request.query['regex'] )
|
|
38
67
|
end
|
|
39
68
|
|
|
40
69
|
def doSave( request, response, pagename, person )
|
|
@@ -75,7 +104,7 @@ class WikiServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
|
75
104
|
def upload( filename, filedata )
|
|
76
105
|
path = "#{$SETTINGS[:root_directory]}/attachment/"
|
|
77
106
|
filename = unique_filename( path ,filename )
|
|
78
|
-
File.open( File.join( path, filename ), '
|
|
107
|
+
File.open( File.join( path, filename ), 'wb' ) { |file| filedata.list.each { |data| file << data } }
|
|
79
108
|
"/attachment/#{filename}"
|
|
80
109
|
end
|
|
81
110
|
|
|
@@ -93,31 +122,21 @@ class WikiServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
|
93
122
|
end
|
|
94
123
|
end
|
|
95
124
|
|
|
96
|
-
$SETTINGS = {
|
|
97
|
-
:name => 'test',
|
|
98
|
-
:description => 'A Soks Wiki',
|
|
99
|
-
:root_directory => 'wiki',
|
|
100
|
-
:url => 'http://localhost:8000',
|
|
101
|
-
:port => 8000,
|
|
102
|
-
:authenticator => WEBrick::HTTPAuth::NotAuthentication.new( 'No password, just enter a name'),
|
|
103
|
-
:dont_authenticate => ['view','rss']
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
125
|
def start_wiki( settings = {}, &automatic_agents )
|
|
109
|
-
$SETTINGS.merge! settings
|
|
110
126
|
|
|
127
|
+
$SETTINGS.merge! settings
|
|
128
|
+
$MESSAGES = YAML.load( IO.readlines("#{$SETTINGS[:root_directory]}/views/messages.yaml").join )
|
|
129
|
+
|
|
111
130
|
wiki = Wiki.new( "#{$SETTINGS[:root_directory]}/content" )
|
|
112
131
|
view = View.new( wiki, $SETTINGS[:name] )
|
|
113
132
|
|
|
114
|
-
Thread.new( automatic_agents, view ) do |block, view|
|
|
115
|
-
block.call( view )
|
|
133
|
+
Thread.new( automatic_agents, wiki, view ) do |block, wiki, view|
|
|
134
|
+
block.call( wiki, view )
|
|
116
135
|
end.priority = -2
|
|
117
136
|
|
|
118
137
|
server = WEBrick::HTTPServer.new( { :Port => $SETTINGS[:port] } )
|
|
119
138
|
server.mount("/attachment", WEBrick::HTTPServlet::FileHandler, "#{ $SETTINGS[:root_directory] }/attachment", true)
|
|
120
|
-
server.mount("/", WikiServlet, view, $SETTINGS
|
|
139
|
+
server.mount("/", WikiServlet, view, $SETTINGS )
|
|
121
140
|
|
|
122
141
|
trap("INT") { server.shutdown }
|
|
123
142
|
|