Soks 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. data/README.txt +5 -4
  2. data/bin/soks-create-wiki.rb +153 -19
  3. data/contrib/easyprompt.rb +58 -0
  4. data/contrib/easyprompt_licence.txt +504 -0
  5. data/contrib/redcloth-2.0.11.rb +3 -1
  6. data/lib/authenticators.rb +18 -2
  7. data/lib/soks-helpers.rb +207 -157
  8. data/lib/soks-model.rb +131 -114
  9. data/lib/soks-servlet.rb +54 -35
  10. data/lib/soks-storage.rb +134 -0
  11. data/lib/soks-upgrade-0.0.2.rb +70 -0
  12. data/lib/soks-utils.rb +129 -19
  13. data/lib/soks-view.rb +136 -62
  14. data/lib/soks.rb +3 -1
  15. data/{template → templates/default}/attachment/logo.png +0 -0
  16. data/templates/default/attachment/logo.tiff +0 -0
  17. data/templates/default/attachment/newpage.js +41 -0
  18. data/templates/default/attachment/print_stylesheet.css +7 -0
  19. data/templates/default/attachment/rss.png +0 -0
  20. data/{template → templates/default}/attachment/stylesheet.css +44 -17
  21. data/templates/default/banned_titles.txt +31 -0
  22. data/templates/default/content/Bug%3A%20In%20a%20list%20of%20links%2C%20the%20last%20link%20is%20sometimes%20not%20linked.textile +10 -0
  23. data/templates/default/content/Bug%3A%20Symbols%20are%20not%20always%20correctly%20rendered%20in%20html.textile +3 -0
  24. data/templates/default/content/Bug%3A%20Uploads%20are%20not%20password%20protected.textile +3 -0
  25. data/templates/default/content/How%20to%20administrate%20this%20wiki.textile +62 -0
  26. data/templates/default/content/How%20to%20change%20the%20way%20this%20wiki%20looks.textile +30 -0
  27. data/templates/default/content/How%20to%20export%20a%20site%20from%20this%20wiki.textile +60 -0
  28. data/{template → templates/default}/content/How%20to%20hack%20soks.textile +3 -2
  29. data/{template → templates/default}/content/How%20to%20import%20a%20site%20from%20instiki.textile +1 -1
  30. data/templates/default/content/How%20to%20use%20this%20wiki.textile +27 -0
  31. data/templates/default/content/List%20of%20changes.textile +35 -0
  32. data/{template → templates/default}/content/Picture%20of%20a%20pair%20of%20soks.textile +0 -0
  33. data/{template → templates/default}/content/Soks%20Licence.textile +0 -0
  34. data/templates/default/content/home%20page.textile +17 -0
  35. data/templates/default/start.rb +94 -0
  36. data/templates/default/version.txt +1 -0
  37. data/{template → templates/default}/views/Page_content.rhtml +0 -0
  38. data/templates/default/views/Page_edit.rhtml +61 -0
  39. data/templates/default/views/Page_meta.rhtml +40 -0
  40. data/templates/default/views/Page_print.rhtml +6 -0
  41. data/templates/default/views/Page_revisions.rhtml +19 -0
  42. data/templates/default/views/Page_rss.rhtml +55 -0
  43. data/{template → templates/default}/views/Page_search_results.rhtml +1 -1
  44. data/templates/default/views/Page_view.rhtml +4 -0
  45. data/templates/default/views/UploadPage_edit.rhtml +38 -0
  46. data/templates/default/views/frame.rhtml +41 -0
  47. data/templates/default/views/messages.yaml +6 -0
  48. data/templates/instiki/attachment/header_backdrop.png +0 -0
  49. data/templates/instiki/attachment/instiki_style_sheet.css +199 -0
  50. data/templates/instiki/attachment/logo.tiff +0 -0
  51. data/templates/instiki/attachment/logotext.png +0 -0
  52. data/templates/instiki/attachment/newpage.js +41 -0
  53. data/templates/instiki/attachment/rss.png +0 -0
  54. data/templates/instiki/banned_titles.txt +31 -0
  55. data/templates/instiki/content/AutomaticSummary.textile +24 -0
  56. data/templates/instiki/content/How%20to%20export%20a%20site%20from%20this%20wiki.textile +60 -0
  57. data/templates/instiki/content/How%20to%20hack%20soks.textile +61 -0
  58. data/templates/instiki/content/How%20to%20import%20a%20site%20from%20instiki.textile +13 -0
  59. data/{template → templates/instiki}/content/Improving%20the%20style%20of%20this%20wiki.textile +2 -2
  60. data/templates/instiki/content/Known%20bugs.textile +8 -0
  61. data/templates/instiki/content/List%20of%20changes.textile +34 -0
  62. data/templates/instiki/content/Picture%20of%20a%20pair%20of%20soks.textile +1 -0
  63. data/templates/instiki/content/Pointers%20on%20adjusting%20the%20settings.textile +62 -0
  64. data/templates/instiki/content/Pointers%20on%20how%20to%20use%20this%20wiki.textile +27 -0
  65. data/templates/instiki/content/Recent%20Blog%20Entries.textile +3 -0
  66. data/templates/instiki/content/Recent%20Changes%20to%20This%20Site.textile +48 -0
  67. data/templates/instiki/content/Site%20Index.textile +16 -0
  68. data/templates/instiki/content/Soks%20Licence.textile +64 -0
  69. data/{template → templates/instiki}/content/home%20page.textile +9 -4
  70. data/templates/instiki/start.rb +85 -0
  71. data/templates/instiki/version.txt +1 -0
  72. data/templates/instiki/views/Page_content.rhtml +1 -0
  73. data/templates/instiki/views/Page_edit.rhtml +8 -0
  74. data/templates/instiki/views/Page_meta.rhtml +34 -0
  75. data/templates/instiki/views/Page_print.rhtml +6 -0
  76. data/templates/instiki/views/Page_revisions.rhtml +17 -0
  77. data/templates/instiki/views/Page_rss.rhtml +55 -0
  78. data/templates/instiki/views/Page_search_results.rhtml +18 -0
  79. data/templates/instiki/views/Page_view.rhtml +2 -0
  80. data/templates/instiki/views/UploadPage_edit.rhtml +16 -0
  81. data/templates/instiki/views/frame.rhtml +90 -0
  82. data/templates/instiki/views/messages.yaml +6 -0
  83. data/templates/rails/attachment/2colheader.css +77 -0
  84. data/templates/rails/attachment/basics.css +98 -0
  85. data/templates/rails/attachment/header_backdrop.png +0 -0
  86. data/templates/rails/attachment/logo.tiff +0 -0
  87. data/templates/rails/attachment/logotext.png +0 -0
  88. data/templates/rails/attachment/newpage.js +41 -0
  89. data/templates/rails/attachment/rss.png +0 -0
  90. data/templates/rails/banned_titles.txt +31 -0
  91. data/templates/rails/content/AutomaticSummary.textile +24 -0
  92. data/templates/rails/content/How%20to%20export%20a%20site%20from%20this%20wiki.textile +60 -0
  93. data/templates/rails/content/How%20to%20hack%20soks.textile +61 -0
  94. data/templates/rails/content/How%20to%20import%20a%20site%20from%20instiki.textile +13 -0
  95. data/templates/rails/content/Improving%20the%20style%20of%20this%20wiki.textile +30 -0
  96. data/templates/rails/content/Known%20bugs.textile +8 -0
  97. data/templates/rails/content/List%20of%20changes.textile +34 -0
  98. data/templates/rails/content/Picture%20of%20a%20pair%20of%20soks.textile +1 -0
  99. data/templates/rails/content/Pointers%20on%20adjusting%20the%20settings.textile +62 -0
  100. data/templates/rails/content/Pointers%20on%20how%20to%20use%20this%20wiki.textile +27 -0
  101. data/templates/rails/content/Recent%20Blog%20Entries.textile +3 -0
  102. data/templates/rails/content/Recent%20Changes%20to%20This%20Site.textile +48 -0
  103. data/templates/rails/content/Site%20Index.textile +16 -0
  104. data/templates/rails/content/Soks%20Licence.textile +64 -0
  105. data/templates/rails/content/home%20page.textile +23 -0
  106. data/templates/rails/start.rb +85 -0
  107. data/templates/rails/version.txt +1 -0
  108. data/templates/rails/views/Page_content.rhtml +1 -0
  109. data/templates/rails/views/Page_edit.rhtml +61 -0
  110. data/templates/rails/views/Page_meta.rhtml +38 -0
  111. data/templates/rails/views/Page_print.rhtml +6 -0
  112. data/templates/rails/views/Page_revisions.rhtml +19 -0
  113. data/templates/rails/views/Page_rss.rhtml +55 -0
  114. data/templates/rails/views/Page_search_results.rhtml +19 -0
  115. data/templates/rails/views/Page_view.rhtml +3 -0
  116. data/templates/rails/views/UploadPage_edit.rhtml +38 -0
  117. data/templates/rails/views/frame.rhtml +60 -0
  118. data/templates/rails/views/messages.yaml +6 -0
  119. metadata +122 -28
  120. data/template/content/How%20to%20export%20a%20site%20from%20this%20wiki.textile +0 -5
  121. data/template/content/Pointers%20on%20adjusting%20the%20settings.textile +0 -39
  122. data/template/content/Pointers%20on%20how%20to%20use%20this%20wiki.textile +0 -21
  123. data/template/content/Recent%20Changes%20to%20This%20Site.textile +0 -203
  124. data/template/start.rb +0 -74
  125. data/template/views/AttachmentPage_edit.rhtml +0 -36
  126. data/template/views/ImagePage_edit.rhtml +0 -36
  127. data/template/views/Page_edit.rhtml +0 -34
  128. data/template/views/Page_print.rhtml +0 -5
  129. data/template/views/Page_revisions.rhtml +0 -18
  130. data/template/views/Page_rss.rhtml +0 -34
  131. data/template/views/Page_view.rhtml +0 -3
  132. 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 :number, :changes, :created_at, :author
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 when this revision was created, by recursively applying diffs
11
- # to more recent versions.
12
- def content( page )
13
- $stderr.puts "#{number} #{page}"
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
- def previous_content( page )
18
- content( page ).split("\n").unpatch!(@changes).join("\n")
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
- attr_reader :name, :content, :revisions
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, "Type what you want here and click save", "NoOne" )
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; "[[Create #{name} (#{self.class}) : /edit/#{name} ]]" end
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, content, author )
51
+ def initialize( name )
37
52
  @name, @content, @revisions = name, "", []
38
53
  @links_from, @links_to = [], []
39
- @inserted_into, @watchers = [], []
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( content, author )
49
- changes = @content.split("\n").diff( content.split("\n") ).map { |changeset| changeset.map { |change| change.to_a } }
50
- unless changes.empty?
51
- @revisions << Revision.new( @revisions.length, changes, author )
52
- @content = content
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
- if number < 0
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 ) @revisions[ number ] end
76
+ def revision( number ) @revisions[ number ] end
66
77
 
67
78
  def deleted?
68
- ( content.strip.downcase == 'page deleted' ) ||
69
- ( content =~ /^content moved to /i )
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 score; @links_from.size + @links_to.size + @watchers.size end
91
+ def is_inserted_into( page )
92
+ @inserted_into << page unless @inserted_into.include? page
93
+ end
75
94
 
76
- def <=>( otherpage ) self.score <=> otherpage.score end
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(method_symbol, *args)
86
- @revisions.last.send( method_symbol, *args )
87
- end
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[ 10..-1].strip end
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 end
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
- def initialize( folder )
113
- @folder = folder
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
- load_all_pages_in( folder )
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
- @pages[ name.downcase ] || class_for( name ).empty( name )
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, content, author ) { |page| page.revise( content, author ) }
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 mutate( pagename, content = nil, author = nil )
154
- page = @pages[ pagename.downcase ]
155
- if page
156
- yield page
157
- save_page page
158
- elsif content && author
159
- @pages[ pagename.downcase ] = page = class_for( pagename ).new( pagename, content, author)
160
- save_page page
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 load_page( filename )
173
- if File.exists? File.join( @folder, filename )
174
- page_name = File.basename( filename, '.*').url_decode
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 load_revisions_for( page_filename )
185
- revision_filename = "#{File.basename( page_filename, '.*')}.marshal"
186
- if File.exists? File.join( @folder, revision_filename )
187
- File.open( File.join( @folder, revision_filename ) ) do |file|
188
- return Marshal.load( file )
189
- end
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 save_page( page )
195
- File.open( "#{filename_for( page )}.textile", 'w' ) { |file| file.puts page.content }
196
- File.open( "#{filename_for( page )}.marshal", 'w' ) { |file| Marshal.dump( page.revisions, file ) }
214
+ def add_page_to_index( page )
215
+ @pages[ page.name.downcase ] = page
216
+ page
197
217
  end
198
218
 
199
- def filename_for( page )
200
- File.join( @folder, "#{page.name.url_encode}" )
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
- Thread.abort_on_exception = true
5
- Socket.do_not_reverse_lookup = true
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, name, wikiurl, authenticator = nil, no_authentication_for= [] )
10
- @server, @wiki, @name, @wikiurl, @authenticator, @no_authentication_for = server, wiki, name, wikiurl, authenticator, no_authentication_for
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
- leadingslash, verb, *pagename = request.path.split('/')
15
- redirect( response, "Home Page" ) unless verb
16
- if verb == 'find' # The search term is from a form
17
- pagename = [ request.query['regex'] ]
18
- elsif pagename.empty? # There was no verb. Use the pagename instead
19
- verb, pagename = 'view', [ verb ]
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
- @authenticator.authenticate( request, response ) unless @no_authentication_for.include? verb
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( pagename )
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 ), 'w' ) { |file| filedata.list.each { |data| file << data } }
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[:name] , $SETTINGS[:url] , $SETTINGS[:authenticator] , $SETTINGS[:dont_authenticate] )
139
+ server.mount("/", WikiServlet, view, $SETTINGS )
121
140
 
122
141
  trap("INT") { server.shutdown }
123
142