Soks 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|