rethoth 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +26 -0
  3. data/bin/thoth +233 -0
  4. data/lib/proto/config.ru +45 -0
  5. data/lib/proto/thoth.conf.sample +206 -0
  6. data/lib/thoth/cache.rb +53 -0
  7. data/lib/thoth/config.rb +158 -0
  8. data/lib/thoth/controller/admin.rb +75 -0
  9. data/lib/thoth/controller/api/comment.rb +73 -0
  10. data/lib/thoth/controller/api/page.rb +134 -0
  11. data/lib/thoth/controller/api/post.rb +122 -0
  12. data/lib/thoth/controller/api/tag.rb +59 -0
  13. data/lib/thoth/controller/archive.rb +50 -0
  14. data/lib/thoth/controller/comment.rb +173 -0
  15. data/lib/thoth/controller/main.rb +193 -0
  16. data/lib/thoth/controller/media.rb +172 -0
  17. data/lib/thoth/controller/page.rb +167 -0
  18. data/lib/thoth/controller/post.rb +310 -0
  19. data/lib/thoth/controller/search.rb +86 -0
  20. data/lib/thoth/controller/tag.rb +107 -0
  21. data/lib/thoth/controller.rb +48 -0
  22. data/lib/thoth/errors.rb +35 -0
  23. data/lib/thoth/helper/admin.rb +86 -0
  24. data/lib/thoth/helper/cookie.rb +45 -0
  25. data/lib/thoth/helper/error.rb +122 -0
  26. data/lib/thoth/helper/pagination.rb +131 -0
  27. data/lib/thoth/helper/wiki.rb +77 -0
  28. data/lib/thoth/helper/ysearch.rb +89 -0
  29. data/lib/thoth/importer/pants.rb +81 -0
  30. data/lib/thoth/importer/poseidon.rb +54 -0
  31. data/lib/thoth/importer/thoth.rb +103 -0
  32. data/lib/thoth/importer.rb +131 -0
  33. data/lib/thoth/layout/default.rhtml +47 -0
  34. data/lib/thoth/middleware/minify.rb +82 -0
  35. data/lib/thoth/migrate/001_create_schema.rb +108 -0
  36. data/lib/thoth/migrate/002_add_media_size.rb +37 -0
  37. data/lib/thoth/migrate/003_add_post_draft.rb +38 -0
  38. data/lib/thoth/migrate/004_add_comment_email.rb +37 -0
  39. data/lib/thoth/migrate/005_add_page_position.rb +37 -0
  40. data/lib/thoth/migrate/006_add_comment_close_delete.rb +43 -0
  41. data/lib/thoth/migrate/007_add_comment_summary.rb +37 -0
  42. data/lib/thoth/model/comment.rb +216 -0
  43. data/lib/thoth/model/media.rb +87 -0
  44. data/lib/thoth/model/page.rb +204 -0
  45. data/lib/thoth/model/post.rb +262 -0
  46. data/lib/thoth/model/tag.rb +80 -0
  47. data/lib/thoth/model/tags_posts_map.rb +34 -0
  48. data/lib/thoth/monkeypatch/sequel/model/errors.rb +37 -0
  49. data/lib/thoth/plugin/thoth_delicious.rb +105 -0
  50. data/lib/thoth/plugin/thoth_flickr.rb +86 -0
  51. data/lib/thoth/plugin/thoth_pinboard.rb +98 -0
  52. data/lib/thoth/plugin/thoth_tags.rb +68 -0
  53. data/lib/thoth/plugin/thoth_twitter.rb +175 -0
  54. data/lib/thoth/plugin.rb +59 -0
  55. data/lib/thoth/public/css/admin.css +223 -0
  56. data/lib/thoth/public/css/thoth.css +592 -0
  57. data/lib/thoth/public/images/admin-sprite.png +0 -0
  58. data/lib/thoth/public/images/thoth-sprite.png +0 -0
  59. data/lib/thoth/public/js/admin/comments.js +116 -0
  60. data/lib/thoth/public/js/admin/name.js +244 -0
  61. data/lib/thoth/public/js/admin/tagcomplete.js +332 -0
  62. data/lib/thoth/public/js/lazyload-min.js +4 -0
  63. data/lib/thoth/public/js/thoth.js +203 -0
  64. data/lib/thoth/public/robots.txt +5 -0
  65. data/lib/thoth/version.rb +37 -0
  66. data/lib/thoth/view/admin/index.rhtml +1 -0
  67. data/lib/thoth/view/admin/login.rhtml +23 -0
  68. data/lib/thoth/view/admin/toolbar.rhtml +117 -0
  69. data/lib/thoth/view/admin/welcome.rhtml +58 -0
  70. data/lib/thoth/view/archive/index.rhtml +24 -0
  71. data/lib/thoth/view/comment/comment.rhtml +47 -0
  72. data/lib/thoth/view/comment/delete.rhtml +15 -0
  73. data/lib/thoth/view/comment/form.rhtml +81 -0
  74. data/lib/thoth/view/comment/index.rhtml +68 -0
  75. data/lib/thoth/view/comment/list.rhtml +48 -0
  76. data/lib/thoth/view/media/delete.rhtml +15 -0
  77. data/lib/thoth/view/media/edit.rhtml +12 -0
  78. data/lib/thoth/view/media/form.rhtml +7 -0
  79. data/lib/thoth/view/media/list.rhtml +35 -0
  80. data/lib/thoth/view/media/media.rhtml +44 -0
  81. data/lib/thoth/view/media/new.rhtml +7 -0
  82. data/lib/thoth/view/page/delete.rhtml +15 -0
  83. data/lib/thoth/view/page/edit.rhtml +15 -0
  84. data/lib/thoth/view/page/form.rhtml +57 -0
  85. data/lib/thoth/view/page/index.rhtml +9 -0
  86. data/lib/thoth/view/page/list.rhtml +49 -0
  87. data/lib/thoth/view/page/new.rhtml +15 -0
  88. data/lib/thoth/view/post/comments.rhtml +12 -0
  89. data/lib/thoth/view/post/compact.rhtml +48 -0
  90. data/lib/thoth/view/post/delete.rhtml +15 -0
  91. data/lib/thoth/view/post/edit.rhtml +15 -0
  92. data/lib/thoth/view/post/form.rhtml +83 -0
  93. data/lib/thoth/view/post/index.rhtml +48 -0
  94. data/lib/thoth/view/post/list.rhtml +61 -0
  95. data/lib/thoth/view/post/new.rhtml +15 -0
  96. data/lib/thoth/view/post/tiny.rhtml +4 -0
  97. data/lib/thoth/view/search/index.rhtml +45 -0
  98. data/lib/thoth/view/tag/index.rhtml +34 -0
  99. data/lib/thoth/view/thoth/css.rhtml +9 -0
  100. data/lib/thoth/view/thoth/footer.rhtml +15 -0
  101. data/lib/thoth/view/thoth/header.rhtml +23 -0
  102. data/lib/thoth/view/thoth/index.rhtml +11 -0
  103. data/lib/thoth/view/thoth/js.rhtml +6 -0
  104. data/lib/thoth/view/thoth/sidebar.rhtml +38 -0
  105. data/lib/thoth/view/thoth/util/pager.rhtml +23 -0
  106. data/lib/thoth/view/thoth/util/simple_pager.rhtml +15 -0
  107. data/lib/thoth/view/thoth/util/table_sortheader.rhtml +20 -0
  108. data/lib/thoth.rb +394 -0
  109. metadata +409 -0
data/lib/thoth.rb ADDED
@@ -0,0 +1,394 @@
1
+ #--
2
+ # Copyright (c) 2017 John Pagonis <john@pagonis.org>
3
+ # Copyright (c) 2009 Ryan Grove <ryan@wonko.com>
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # * Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ # * Redistributions in binary form must reproduce the above copyright notice,
12
+ # this list of conditions and the following disclaimer in the documentation
13
+ # and/or other materials provided with the distribution.
14
+ # * Neither the name of this project nor the names of its contributors may be
15
+ # used to endorse or promote products derived from this software without
16
+ # specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
22
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ #++
29
+
30
+ # Prepend this file's directory to the include path if it's not there already.
31
+ $:.unshift(File.dirname(File.expand_path(__FILE__)))
32
+ $:.uniq!
33
+
34
+ require 'fileutils'
35
+
36
+ require 'builder'
37
+ require 'cssmin'
38
+ require 'erubis'
39
+ require 'jsmin'
40
+ require 'json'
41
+ require 'ramaze'
42
+ require 'redcloth'
43
+ require 'sanitize'
44
+ require 'sequel'
45
+ require 'sequel/extensions/migration'
46
+ require 'sequel/extensions/pagination'
47
+ require 'time'
48
+ require 'yaml'
49
+
50
+ # The main Thoth namespace.
51
+ module Thoth
52
+ HOME_DIR = ENV['THOTH_HOME'] || File.expand_path('.') unless const_defined?(:HOME_DIR)
53
+ LIB_DIR = File.join(File.dirname(File.expand_path(__FILE__)), 'thoth')
54
+ PUBLIC_DIR = File.join(LIB_DIR, 'public') unless const_defined?(:PUBLIC_DIR)
55
+ VIEW_DIR = File.join(LIB_DIR, 'view') unless const_defined?(:VIEW_DIR)
56
+
57
+ # Thoth Helper namespace.
58
+ module Helper; end
59
+ end
60
+
61
+ module Thoth
62
+ # LIFTED from old Ramaze.acquire
63
+ # Require all .rb and .so files on the given globs, utilizes Dir::[].
64
+ #
65
+ # Examples:
66
+ # # Given following directory structure:
67
+ # # src/foo.rb
68
+ # # src/bar.so
69
+ # # src/foo.yaml
70
+ # # src/foobar/baz.rb
71
+ # # src/foobar/README
72
+ #
73
+ # # requires all files in 'src':
74
+ # Ramaze.acquire 'src/*'
75
+ #
76
+ # # requires all files in 'src' recursive:
77
+ # Ramaze.acquire 'src/**/*'
78
+ #
79
+ # # require 'src/foo.rb' and 'src/bar.so' and 'src/foobar/baz.rb'
80
+ # Ramaze.acquire 'src/*', 'src/foobar/*'
81
+ def self.acquire(*globs)
82
+ globs.flatten.each do |glob|
83
+ Dir[glob].each do |file|
84
+ require file if file =~ /\.(rb|so)$/
85
+ puts "#{file} loaded"
86
+ end
87
+ end
88
+ end
89
+
90
+
91
+ # Lifted from old Ramaze, which was also lifter by Rack::Directory
92
+ # Stolen from Ramaze
93
+ FILESIZE_FORMAT = [
94
+ ['%.1fT', 1 << 40],
95
+ ['%.1fG', 1 << 30],
96
+ ['%.1fM', 1 << 20],
97
+ ['%.1fK', 1 << 10],
98
+ ]
99
+
100
+ def self.filesize_format(int)
101
+ FILESIZE_FORMAT.each do |format, size|
102
+ return format % (int.to_f / size) if int >= size
103
+ end
104
+
105
+ "#{int}B"
106
+ end
107
+
108
+ end
109
+
110
+ require 'thoth/errors'
111
+ require 'thoth/config'
112
+ require 'thoth/version'
113
+ require 'thoth/plugin'
114
+ require 'thoth/middleware/minify'
115
+
116
+ # Monkeypatchery!
117
+ require 'thoth/monkeypatch/sequel/model/errors'
118
+
119
+ module Thoth
120
+ include Innate::Traited
121
+
122
+ # This is only here because assignments like trait[:foo] ||= :bar will fail if
123
+ # the trait hash hasn't been created yet.
124
+ trait(:traits_broken => true)
125
+
126
+ # Ramaze adapter to use.
127
+ trait[:adapter] ||= nil
128
+
129
+ # Path to the config file.
130
+ trait[:config_file] ||= ENV['THOTH_CONF'] || File.join(HOME_DIR, 'thoth.conf')
131
+
132
+ # Daemon command to execute (:start, :stop, :restart) or nil.
133
+ trait[:daemon] ||= nil
134
+
135
+ # IP address this Thoth instance should attach to.
136
+ trait[:ip] ||= nil
137
+
138
+ # Whether or not to start Thoth within an IRB session.
139
+ trait[:irb] ||= false
140
+
141
+ # What mode we're running in (either :devel or :production).
142
+ trait[:mode] ||= :production
143
+
144
+ # Port number this Thoth instance should attach to.
145
+ trait[:port] ||= nil
146
+
147
+ # Path to the daemon process id file.
148
+ trait[:pidfile] ||= File.join(HOME_DIR, "thoth_#{trait[:ip]}_#{trait[:port]}.pid")
149
+
150
+ # Filename to which all SQL commands should be logged, or nil to disable
151
+ # SQL logging.
152
+ trait[:sql_log] ||= nil
153
+
154
+ class << self
155
+ attr_reader :db
156
+
157
+ # Creates a new Thoth home directory with a sample config file at the
158
+ # specified path.
159
+ def create(path)
160
+ path = File.expand_path(path)
161
+
162
+ if File.exist?(path)
163
+ raise "specified path already exists: #{path}"
164
+ end
165
+
166
+ FileUtils.mkdir_p(File.join(path, 'log'))
167
+ FileUtils.mkdir(File.join(path, 'media'))
168
+ FileUtils.mkdir(File.join(path, 'plugin'))
169
+ FileUtils.mkdir(File.join(path, 'public'))
170
+ FileUtils.mkdir(File.join(path, 'view'))
171
+ FileUtils.mkdir(File.join(path, 'tmp'))
172
+
173
+ FileUtils.cp(File.join(LIB_DIR, '..', 'proto', 'config.ru'), File.join(path, 'config.ru'))
174
+ FileUtils.cp(File.join(LIB_DIR, '..', 'proto', 'thoth.conf.sample'), File.join(path, 'thoth.conf'))
175
+
176
+ File.chmod(0750, File.join(path, 'log'))
177
+ File.chmod(0750, File.join(path, 'media'))
178
+ File.chmod(0750, File.join(path, 'plugin'))
179
+ File.chmod(0755, File.join(path, 'public'))
180
+ File.chmod(0750, File.join(path, 'view'))
181
+ File.chmod(0750, File.join(path, 'tmp'))
182
+
183
+ File.chmod(0640, File.join(path, 'config.ru'))
184
+ File.chmod(0640, File.join(path, 'thoth.conf'))
185
+ end
186
+
187
+ # Opens a connection to the Thoth database and loads helpers, controllers,
188
+ # models and plugins.
189
+ def init_thoth
190
+ trait[:ip] ||= Config.server['address']
191
+ trait[:port] ||= Config.server['port']
192
+
193
+ open_db
194
+
195
+ # Ensure that the database schema is up to date.
196
+ #
197
+ # TODO: need to rethink how migration works since newer versions of Sequel
198
+ # don't expose the migration versions.
199
+ #
200
+ # unless Sequel::Migrator.get_current_migration_version(@db) ==
201
+ # Sequel::Migrator.latest_migration_version(File.join(LIB_DIR, 'migrate'))
202
+ #
203
+ # if trait[:mode] == :production
204
+ # raise SchemaError, "Database schema is missing or out of date. " <<
205
+ # "Please run `thoth --migrate`."
206
+ # else
207
+ # raise SchemaError, "Database schema is missing or out of date. " <<
208
+ # "Please run `thoth --devel --migrate`."
209
+ # end
210
+ # end
211
+
212
+ # If caching is disabled, replace the default cache store with a no-op
213
+ # API.
214
+ if Config.server['enable_cache']
215
+ # Cache templates once read to prevent unnecessary disk thrashing.
216
+ Innate::View.options.read_cache = true
217
+
218
+ if Config.server['memcache']['enabled']
219
+ Ramaze::Cache::MemCache::OPTIONS[:servers] = Config.server['memcache']['servers']
220
+ Ramaze::Cache.options.default = Ramaze::Cache::MemCache
221
+ end
222
+ else
223
+ require 'thoth/cache'
224
+ Ramaze::Cache.options.default = Thoth::Cache::Noop
225
+ end
226
+
227
+ # Create a cache for plugins to use.
228
+ Ramaze::Cache.add(:plugin)
229
+
230
+ # Tell Innate where to find Thoth's helpers.
231
+ Innate::HelpersHelper.options.paths << LIB_DIR
232
+ Innate::HelpersHelper.options.namespaces << Thoth::Helper
233
+
234
+ # Load Thoth controllers.
235
+ require File.join(LIB_DIR, 'controller')
236
+
237
+ # Load Thoth models.
238
+ require File.join(LIB_DIR, 'helper/wiki')
239
+ Thoth.acquire(File.join(LIB_DIR, 'model', '*'))
240
+
241
+ # Load startup plugins.
242
+ Config.plugins.each {|plugin| Plugin.load(plugin)}
243
+
244
+ Ramaze::Log.info "Thoth home: #{HOME_DIR}"
245
+ Ramaze::Log.info "Thoth lib : #{LIB_DIR}"
246
+ Ramaze::Log.info "Running in #{trait[:mode] == :production ? 'live' : 'dev'} mode"
247
+
248
+ Ramaze.options.setup << self
249
+ end
250
+
251
+ # Opens a Sequel database connection to the Thoth database.
252
+ def open_db
253
+ if Config.db =~ /^sqlite:\/{3}(.+)$/
254
+ dir = File.dirname($1)
255
+ FileUtils.mkdir_p(dir) unless File.directory?(dir)
256
+ end
257
+
258
+ Sequel.datetime_class = Time
259
+
260
+ @db = Sequel.connect(Config.db, :encoding => 'utf8')
261
+ @db.test_connection
262
+
263
+ if trait[:sql_log]
264
+ require 'logger'
265
+ @db.logger = Logger.new(trait[:sql_log])
266
+ end
267
+
268
+ @db.extension(:pagination)
269
+
270
+ rescue => e
271
+ Ramaze::Log.error("Unable to connect to database: #{e}")
272
+ exit(1)
273
+ end
274
+
275
+ # Restarts the running Thoth daemon (if any).
276
+ def restart
277
+ stop
278
+ sleep(1)
279
+ start
280
+ end
281
+
282
+ # Runs Thoth.
283
+ def run
284
+ init_thoth
285
+
286
+ begin
287
+ Ramaze.start(
288
+ :adapter => trait[:adapter],
289
+ :host => trait[:ip],
290
+ :port => trait[:port],
291
+ :root => LIB_DIR
292
+ )
293
+ rescue LoadError => ex
294
+ Ramaze::Log.error("Unable to start Ramaze due to LoadError: #{ex}")
295
+ exit(1)
296
+ end
297
+ end
298
+
299
+ # Initializes Ramaze.
300
+ def setup
301
+ Ramaze.options.merge!(
302
+ :mode => trait[:mode] == :production ? :live : :dev,
303
+ :roots => [HOME_DIR, LIB_DIR]
304
+ )
305
+
306
+ case trait[:mode]
307
+ when :devel
308
+ Ramaze.middleware :dev do
309
+ use Rack::Lint
310
+ use Rack::CommonLogger, Ramaze::Log
311
+ use Rack::ShowExceptions
312
+ use Rack::ShowStatus
313
+ use Rack::RouteExceptions
314
+ use Rack::ConditionalGet
315
+ use Rack::ETag
316
+ use Rack::Head
317
+ use Ramaze::Reloader
318
+ use Thoth::Minify if Config.server['enable_minify']
319
+ run Ramaze::AppMap
320
+ end
321
+
322
+ when :production
323
+ Ramaze.middleware :live do
324
+ use Rack::CommonLogger, Ramaze::Log
325
+ use Rack::RouteExceptions
326
+ use Rack::ShowStatus
327
+ use Rack::ConditionalGet
328
+ use Rack::ETag
329
+ use Rack::Head
330
+ use Thoth::Minify if Config.server['enable_minify']
331
+ run Ramaze::AppMap
332
+ end
333
+
334
+ # Ensure that exceptions result in an HTTP 500 response.
335
+ Rack::RouteExceptions.route(Exception, '/error_500')
336
+
337
+ # Log all errors to the error log file if one is configured.
338
+ if Config.server['error_log'].empty?
339
+ Ramaze::Log.loggers = []
340
+ else
341
+ log_dir = File.dirname(Config.server['error_log'])
342
+
343
+ unless File.directory?(log_dir)
344
+ FileUtils.mkdir_p(log_dir)
345
+ File.chmod(0750, log_dir)
346
+ end
347
+
348
+ Ramaze::Log.loggers = [Logger.new(Config.server['error_log'])]
349
+ Ramaze::Log.level = Logger::Severity::ERROR
350
+ end
351
+ end
352
+ end
353
+
354
+ # Starts Thoth as a daemon.
355
+ def start
356
+ if File.file?(trait[:pidfile])
357
+ pid = File.read(trait[:pidfile], 20).strip
358
+ abort("thoth already running? (pid=#{pid})")
359
+ end
360
+
361
+ puts "Starting thoth."
362
+
363
+ fork do
364
+ Process.setsid
365
+ exit if fork
366
+
367
+ File.open(trait[:pidfile], 'w') {|file| file << Process.pid}
368
+ at_exit {FileUtils.rm(trait[:pidfile]) if File.exist?(trait[:pidfile])}
369
+
370
+ Dir.chdir(HOME_DIR)
371
+ File.umask(0000)
372
+
373
+ STDIN.reopen('/dev/null')
374
+ STDOUT.reopen('/dev/null', 'a')
375
+ STDERR.reopen(STDOUT)
376
+
377
+ run
378
+ end
379
+ end
380
+
381
+ # Stops the running Thoth daemon (if any).
382
+ def stop
383
+ unless File.file?(trait[:pidfile])
384
+ abort("thoth not running? (check #{trait[:pidfile]}).")
385
+ end
386
+
387
+ puts "Stopping thoth."
388
+
389
+ pid = File.read(trait[:pidfile], 20).strip
390
+ FileUtils.rm(trait[:pidfile]) if File.exist?(trait[:pidfile])
391
+ pid && Process.kill('TERM', pid.to_i)
392
+ end
393
+ end
394
+ end