rethoth 0.4.1

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 (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
@@ -0,0 +1,158 @@
1
+ #--
2
+ # Copyright (c) 2009 Ryan Grove <ryan@wonko.com>
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of this project nor the names of its contributors may be
14
+ # used to endorse or promote products derived from this software without
15
+ # specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ #++
28
+
29
+ module Thoth
30
+
31
+ module Config; class << self
32
+
33
+ # Adds the specified config Hash to Thoth's config lookup chain. Any
34
+ # configuration values in _config_ will be used as defaults unless they're
35
+ # specified earlier in the lookup chain (i.e. in Thoth's config file).
36
+ def <<(config)
37
+ raise ArgumentError, "config must be a Hash" unless config.is_a?(Hash)
38
+
39
+ (@lookup ||= []) << config
40
+ cache_config
41
+
42
+ @lookup
43
+ end
44
+
45
+ # Loads the specified configuration file.
46
+ def load(file)
47
+ raise Thoth::Error, "Config file not found: #{file}" unless File.file?(file)
48
+
49
+ @live = {
50
+ 'db' => "sqlite:///#{HOME_DIR}/db/live.db",
51
+
52
+ 'site' => {
53
+ 'name' => "New Thoth Blog",
54
+ 'desc' => "Thoth is awesome.",
55
+ 'url' => "http://localhost:7000/",
56
+
57
+ 'core_js' => [
58
+ 'http://yui.yahooapis.com/2.8.0/build/yahoo-dom-event/yahoo-dom-event.js',
59
+ '/js/thoth.js'
60
+ ],
61
+
62
+ 'css' => [],
63
+ 'js' => [],
64
+
65
+ 'enable_comments' => true,
66
+ 'enable_sitemap' => true,
67
+
68
+ 'gravatar' => {
69
+ 'enabled' => true,
70
+ 'default' => "identicon",
71
+ 'rating' => "g",
72
+ 'size' => 32
73
+ }
74
+ },
75
+
76
+ 'admin' => {
77
+ 'name' => "John Doe",
78
+ 'email' => "",
79
+ 'user' => "thoth",
80
+ 'pass' => "thoth",
81
+ 'seed' => "6d552ac197a862b82b85868d6c245feb"
82
+ },
83
+
84
+ 'plugins' => [],
85
+
86
+ 'media' => File.join(HOME_DIR, 'media'),
87
+
88
+ 'server' => {
89
+ 'adapter' => 'webrick',
90
+ 'address' => '0.0.0.0',
91
+ 'port' => 7000,
92
+ 'enable_cache' => true,
93
+ 'enable_minify' => true,
94
+ 'error_log' => File.join(HOME_DIR, 'log', 'error.log'),
95
+
96
+ 'memcache' => {
97
+ 'enabled' => false,
98
+ 'servers' => ['localhost:11211:1']
99
+ }
100
+ },
101
+
102
+ 'timestamp' => {
103
+ 'long' => "%A %B %d, %Y @ %I:%M %p (%Z)",
104
+ 'short' => "%Y-%m-%d %I:%M"
105
+ }
106
+ }
107
+
108
+ @dev = {
109
+ 'db' => "sqlite:///#{HOME_DIR}/db/dev.db",
110
+
111
+ 'server' => {
112
+ 'enable_cache' => false,
113
+ 'enable_minify' => false
114
+ }
115
+ }
116
+
117
+ begin
118
+ config = YAML.load(Erubis::Eruby.new(File.read(file)).result(binding)) || {}
119
+ rescue => e
120
+ raise Thoth::ConfigError, "Config error in #{file}: #{e}"
121
+ end
122
+
123
+ @lookup ||= if Thoth.trait[:mode] == :production
124
+ [config['live'] || {}, @live]
125
+ else
126
+ [config['dev'] || {}, config['live'] || {}, @dev, @live]
127
+ end
128
+
129
+ cache_config
130
+ end
131
+
132
+ def method_missing(name)
133
+ (@cached || {})[name.to_s] || {}
134
+ end
135
+
136
+ private
137
+
138
+ # Merges configs such that those earlier in the lookup chain override those
139
+ # later in the chain.
140
+ def cache_config
141
+ @cached = {}
142
+
143
+ @lookup.reverse.each do |c|
144
+ c.each {|k, v| @cached[k] = config_merge(@cached[k] || {}, v) }
145
+ end
146
+ end
147
+
148
+ def config_merge(master, value)
149
+ if value.is_a?(Hash)
150
+ value.each {|k, v| master[k] = config_merge(master[k] || {}, v) }
151
+ return master
152
+ end
153
+
154
+ value
155
+ end
156
+
157
+ end; end
158
+ end
@@ -0,0 +1,75 @@
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
+ module Thoth
31
+ class AdminController < Controller
32
+ map '/admin'
33
+
34
+ def index
35
+ if auth_key_valid?
36
+ @title = 'Welcome to Thoth'
37
+ @public_root = PUBLIC_DIR
38
+ @view_root = VIEW_DIR
39
+ else
40
+ @title = 'Login'
41
+ end
42
+ end
43
+
44
+ # Authenticates an admin login by checking the _username_ and _password_
45
+ # request parameters against the +ADMIN_USER+ and +ADMIN_PASS+ values in the
46
+ # Thoth config file.
47
+ #
48
+ # On a successful login, an auth cookie named <em>thoth_auth</em> will be
49
+ # set and the user will be redirected to the referring URL. On an
50
+ # unsuccessful login attempt, a flash message named <em>login_error</em>
51
+ # will be set and the user will be redirected to the referring URL without
52
+ # an auth cookie.
53
+ def login
54
+ username, password = request[:username, :password]
55
+
56
+ if username == Config.admin['user'] && password == Config.admin['pass']
57
+ # Set an auth cookie that expires in two weeks.
58
+ response.set_cookie('thoth_auth', :expires => Time.now + 1209600,
59
+ :path => '/', :value => auth_key)
60
+
61
+ redirect_referrer
62
+ end
63
+
64
+ flash[:error] = 'Invalid username or password.'
65
+ redirect_referrer
66
+ end
67
+
68
+ # Deletes the <em>thoth_auth</em> cookie and redirects to the home page.
69
+ def logout
70
+ response.delete_cookie('thoth_auth', :path => '/')
71
+ redirect(MainController.r())
72
+ end
73
+
74
+ end
75
+ end
@@ -0,0 +1,73 @@
1
+ #--
2
+ # Copyright (c) 2009 Ryan Grove <ryan@wonko.com>
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of this project nor the names of its contributors may be
14
+ # used to endorse or promote products derived from this software without
15
+ # specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ #++
28
+
29
+ module Thoth
30
+ class CommentApiController < Controller
31
+ map '/api/comment'
32
+ layout nil
33
+
34
+ # Deletes the specified comment. Returns an HTTP 200 response on success, an
35
+ # HTTP 500 response on failure, or an HTTP 404 response if the specified
36
+ # comment does not exist.
37
+ #
38
+ # ==== Query Parameters (POST only)
39
+ #
40
+ # id:: comment id
41
+ # token:: form token
42
+ #
43
+ # ==== Sample Response
44
+ #
45
+ # ===== Success
46
+ #
47
+ # {"success":true}
48
+ #
49
+ # ===== Failure
50
+ #
51
+ # {"error":"The comment could not be deleted due to a database error."}
52
+ #
53
+ def delete
54
+ error_403 unless auth_key_valid? && form_token_valid?
55
+ error_405 unless request.post?
56
+ error_404 unless request[:id] && @comment = Comment[request[:id]]
57
+
58
+ response['Content-Type'] = 'application/json'
59
+
60
+ @comment.deleted = true
61
+
62
+ if @comment.save(:changed => true, :validate => false)
63
+ Ramaze::Cache.action.clear
64
+ Ramaze::Cache.cache_helper_value.clear
65
+ JSON.generate({:success => true})
66
+ else
67
+ respond(JSON.generate({
68
+ :error => 'The comment could not be deleted due to a database error.'
69
+ }, 500))
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,134 @@
1
+ #--
2
+ # Copyright (c) 2009 Ryan Grove <ryan@wonko.com>
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of this project nor the names of its contributors may be
14
+ # used to endorse or promote products derived from this software without
15
+ # specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ #++
28
+
29
+ module Thoth
30
+ class PageApiController < Controller
31
+ map '/api/page'
32
+ layout nil
33
+
34
+ # Returns a response indicating whether the specified page name is valid and
35
+ # not already taken. Returns an HTTP 200 response on success.
36
+ #
37
+ # ==== Query Parameters
38
+ #
39
+ # name:: page name to check
40
+ #
41
+ # ==== Sample Response
42
+ #
43
+ # {"valid":true,"unique":true}
44
+ #
45
+ def check_name
46
+ error_403 unless auth_key_valid?
47
+
48
+ unless request[:name] && request[:name].length > 0
49
+ error_400('Missing required parameter: name')
50
+ end
51
+
52
+ response['Content-Type'] = 'application/json'
53
+
54
+ name = request[:name].to_s
55
+
56
+ JSON.generate({
57
+ :valid => Page.name_valid?(name),
58
+ :unique => Page.name_unique?(name)
59
+ })
60
+ end
61
+
62
+ # Suggests a valid and unique name for the specified page title. Returns an
63
+ # HTTP 200 response on success.
64
+ #
65
+ # ==== Query Parameters
66
+ #
67
+ # title:: page title
68
+ #
69
+ # ==== Sample Response
70
+ #
71
+ # {"name":"ninjas-are-awesome"}
72
+ #
73
+ def suggest_name
74
+ error_403 unless auth_key_valid?
75
+
76
+ unless request[:title] && request[:title].length > 0
77
+ error_400('Missing required parameter: title')
78
+ end
79
+
80
+ response['Content-Type'] = 'application/json'
81
+
82
+ JSON.generate({"name" => Page.suggest_name(request[:title])})
83
+ end
84
+
85
+ # Sets the display position of the specified page. If the new position is
86
+ # already in use by another page, that page's position (and any others) will
87
+ # be adjusted as necessary. Returns an HTTP 200 response on success. This
88
+ # action only accepts POST requests.
89
+ #
90
+ # ==== POST Parameters
91
+ #
92
+ # id:: page id
93
+ # position:: new display position
94
+ #
95
+ # ==== Sample Response
96
+ #
97
+ # Indicates that the display position for page id 42 was successfully set to
98
+ # 3.
99
+ #
100
+ # {"id":42,"position":3}
101
+ #
102
+ def set_position
103
+ error_403 unless auth_key_valid?
104
+ error_405 unless request.post?
105
+
106
+ [:id, :position].each do |param|
107
+ unless request[param] && request[param].length > 0
108
+ error_400("Missing required parameter: #{param}")
109
+ end
110
+ end
111
+
112
+ id = request[:id].to_i
113
+ position = request[:position].to_i
114
+
115
+ unless page = Page[id]
116
+ error_400("Invalid page id: #{id}")
117
+ end
118
+
119
+ begin
120
+ Page.normalize_positions
121
+ Page.set_position(page, position)
122
+
123
+ rescue => e
124
+ error_400("Error setting page position: #{e}")
125
+ end
126
+
127
+ JSON.generate({
128
+ :id => id,
129
+ :position => position
130
+ })
131
+ end
132
+
133
+ end
134
+ end
@@ -0,0 +1,122 @@
1
+ #--
2
+ # Copyright (c) 2009 Ryan Grove <ryan@wonko.com>
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of this project nor the names of its contributors may be
14
+ # used to endorse or promote products derived from this software without
15
+ # specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ #++
28
+
29
+ module Thoth
30
+ class PostApiController < Controller
31
+ map '/api/post'
32
+ layout nil
33
+
34
+ # Returns a response indicating whether the specified post name is valid and
35
+ # not already taken. Returns an HTTP 200 response on success or an HTTP 500
36
+ # response on error.
37
+ #
38
+ # ==== Query Parameters
39
+ #
40
+ # name:: post name to check
41
+ #
42
+ # ==== Sample Response
43
+ #
44
+ # {"valid":true,"unique":true}
45
+ #
46
+ def check_name
47
+ error_403 unless auth_key_valid?
48
+
49
+ unless request[:name] && request[:name].length > 0
50
+ error_400('Missing required parameter: name')
51
+ end
52
+
53
+ response['Content-Type'] = 'application/json'
54
+
55
+ name = request[:name].to_s
56
+
57
+ JSON.generate({
58
+ :valid => Post.name_valid?(name),
59
+ :unique => Post.name_unique?(name)
60
+ })
61
+ end
62
+
63
+ # Deletes the specified comment. Returns an HTTP 200 response on success, an
64
+ # HTTP 500 response on error, or an HTTP 404 response if the specified
65
+ # comment does not exist.
66
+ #
67
+ # ==== Query Parameters (POST only)
68
+ #
69
+ # id:: comment id
70
+ # token:: form token
71
+ #
72
+ # ==== Sample Response
73
+ #
74
+ # ===== Success
75
+ #
76
+ # {"success":true}
77
+ #
78
+ # ===== Failure
79
+ #
80
+ # {"error":"The comment could not be deleted due to a database error."}
81
+ #
82
+ def delete
83
+ error_403 unless auth_key_valid? && form_token_valid?
84
+ error_405 unless request.post?
85
+ error_404 unless request[:id] && @comment = Comment[request[:id]]
86
+
87
+ response['Content-Type'] = 'application/json'
88
+
89
+ if @comment.destroy
90
+ Ramaze::Cache.action.clear
91
+ JSON.generate({:success => true})
92
+ else
93
+ respond(JSON.generate({
94
+ :error => 'The comment could not be deleted due to a database error.'
95
+ }, 500))
96
+ end
97
+ end
98
+
99
+ # Suggests a valid and unique name for the specified post title. Returns an
100
+ # HTTP 200 response on success or an HTTP 500 response on error.
101
+ #
102
+ # ==== Query Parameters
103
+ #
104
+ # title:: post title
105
+ #
106
+ # ==== Sample Response
107
+ #
108
+ # {"name":"ninjas-are-awesome"}
109
+ #
110
+ def suggest_name
111
+ error_403 unless auth_key_valid?
112
+
113
+ unless request[:title] && request[:title].length > 0
114
+ error_400('Missing required parameter: title')
115
+ end
116
+
117
+ response['Content-Type'] = 'application/json'
118
+
119
+ JSON.generate({"name" => Post.suggest_name(request[:title])})
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,59 @@
1
+ #--
2
+ # Copyright (c) 2009 Ryan Grove <ryan@wonko.com>
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of this project nor the names of its contributors may be
14
+ # used to endorse or promote products derived from this software without
15
+ # specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ #++
28
+
29
+ module Thoth
30
+ class TagApiController < Controller
31
+ map '/api/tag'
32
+ layout nil
33
+
34
+ # Returns a JSON array of existing tag names and usage counts for tags that
35
+ # begin with the specified query string.
36
+ #
37
+ # ==== Query Parameters
38
+ #
39
+ # q:: query string
40
+ # limit:: (optional) maximum number of tags to return
41
+ #
42
+ # ==== Sample Response
43
+ #
44
+ # [["foo",15],["foobar",11],["foosball",2]]
45
+ def suggest
46
+ error_403 unless auth_key_valid?
47
+
48
+ unless request[:q]
49
+ error_400('Missing required parameter: q')
50
+ end
51
+
52
+ query = request[:q].lstrip
53
+ limit = request[:limit] ? request[:limit].to_i : 1000
54
+
55
+ response['Content-Type'] = 'application/json'
56
+ JSON.generate(Tag.suggest(query, limit))
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,50 @@
1
+ #--
2
+ # Copyright (c) 2009 Ryan Grove <ryan@wonko.com>
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # * Redistributions of source code must retain the above copyright notice,
9
+ # this list of conditions and the following disclaimer.
10
+ # * Redistributions in binary form must reproduce the above copyright notice,
11
+ # this list of conditions and the following disclaimer in the documentation
12
+ # and/or other materials provided with the distribution.
13
+ # * Neither the name of this project nor the names of its contributors may be
14
+ # used to endorse or promote products derived from this software without
15
+ # specific prior written permission.
16
+ #
17
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ #++
28
+
29
+ module Thoth
30
+ class ArchiveController < Controller
31
+ map '/archive'
32
+ helper :cache, :pagination
33
+
34
+ cache_action(:method => :index, :ttl => 120) { auth_key_valid? }
35
+
36
+ def index(page = 1)
37
+ page = page.to_i
38
+ error_404 unless page >= 1
39
+
40
+ @posts = Post.recent(page, 10)
41
+
42
+ error_404 if page > @posts.page_count && @posts.page_count > 0
43
+
44
+ @title = "#{Config.site['name']} Archives (page #{page} of " <<
45
+ "#{@posts.page_count > 0 ? @posts.page_count : 1})"
46
+
47
+ @pager = pager(@posts)
48
+ end
49
+ end
50
+ end