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