yodel 0.0.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 (200) hide show
  1. data/.document +5 -0
  2. data/.gitignore +9 -0
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +63 -0
  5. data/LICENSE +1 -0
  6. data/README.rdoc +20 -0
  7. data/Rakefile +1 -0
  8. data/bin/yodel +4 -0
  9. data/lib/yodel.rb +22 -0
  10. data/lib/yodel/application/application.rb +44 -0
  11. data/lib/yodel/application/extension.rb +59 -0
  12. data/lib/yodel/application/request_handler.rb +48 -0
  13. data/lib/yodel/application/yodel.rb +25 -0
  14. data/lib/yodel/command/command.rb +94 -0
  15. data/lib/yodel/command/deploy.rb +67 -0
  16. data/lib/yodel/command/dns_server.rb +16 -0
  17. data/lib/yodel/command/installer.rb +229 -0
  18. data/lib/yodel/config/config.rb +30 -0
  19. data/lib/yodel/config/environment.rb +16 -0
  20. data/lib/yodel/config/yodel.rb +21 -0
  21. data/lib/yodel/exceptions/destroyed_record.rb +2 -0
  22. data/lib/yodel/exceptions/domain_not_found.rb +16 -0
  23. data/lib/yodel/exceptions/duplicate_layout.rb +2 -0
  24. data/lib/yodel/exceptions/exceptions.rb +3 -0
  25. data/lib/yodel/exceptions/inconsistent_lock_state.rb +2 -0
  26. data/lib/yodel/exceptions/invalid_field.rb +2 -0
  27. data/lib/yodel/exceptions/invalid_index.rb +2 -0
  28. data/lib/yodel/exceptions/invalid_mixin.rb +2 -0
  29. data/lib/yodel/exceptions/invalid_model_field.rb +2 -0
  30. data/lib/yodel/exceptions/layout_not_found.rb +2 -0
  31. data/lib/yodel/exceptions/mass_assignment.rb +2 -0
  32. data/lib/yodel/exceptions/missing_migration.rb +2 -0
  33. data/lib/yodel/exceptions/missing_root_directory.rb +15 -0
  34. data/lib/yodel/exceptions/unable_to_acquire_lock.rb +2 -0
  35. data/lib/yodel/exceptions/unauthorised.rb +2 -0
  36. data/lib/yodel/exceptions/unknown_field.rb +2 -0
  37. data/lib/yodel/middleware/development_server.rb +180 -0
  38. data/lib/yodel/middleware/error_pages.rb +72 -0
  39. data/lib/yodel/middleware/public_assets.rb +78 -0
  40. data/lib/yodel/middleware/request.rb +16 -0
  41. data/lib/yodel/middleware/site_detector.rb +22 -0
  42. data/lib/yodel/mime_types/default_mime_set.rb +28 -0
  43. data/lib/yodel/mime_types/mime_type.rb +68 -0
  44. data/lib/yodel/mime_types/mime_type_set.rb +41 -0
  45. data/lib/yodel/mime_types/mime_types.rb +6 -0
  46. data/lib/yodel/mime_types/yodel.rb +15 -0
  47. data/lib/yodel/models/api/api.rb +1 -0
  48. data/lib/yodel/models/api/api_call.rb +87 -0
  49. data/lib/yodel/models/core/associations/association.rb +37 -0
  50. data/lib/yodel/models/core/associations/associations.rb +22 -0
  51. data/lib/yodel/models/core/associations/counts/many_association.rb +18 -0
  52. data/lib/yodel/models/core/associations/counts/one_association.rb +22 -0
  53. data/lib/yodel/models/core/associations/embedded/embedded_association.rb +47 -0
  54. data/lib/yodel/models/core/associations/embedded/embedded_record_array.rb +12 -0
  55. data/lib/yodel/models/core/associations/embedded/many_embedded_association.rb +62 -0
  56. data/lib/yodel/models/core/associations/embedded/one_embedded_association.rb +49 -0
  57. data/lib/yodel/models/core/associations/query/many_query_association.rb +10 -0
  58. data/lib/yodel/models/core/associations/query/one_query_association.rb +10 -0
  59. data/lib/yodel/models/core/associations/query/query_association.rb +64 -0
  60. data/lib/yodel/models/core/associations/record_association.rb +38 -0
  61. data/lib/yodel/models/core/associations/store/many_store_association.rb +32 -0
  62. data/lib/yodel/models/core/associations/store/one_store_association.rb +14 -0
  63. data/lib/yodel/models/core/associations/store/store_association.rb +51 -0
  64. data/lib/yodel/models/core/attachments/attachment.rb +73 -0
  65. data/lib/yodel/models/core/attachments/image.rb +38 -0
  66. data/lib/yodel/models/core/core.rb +15 -0
  67. data/lib/yodel/models/core/fields/alias_field.rb +32 -0
  68. data/lib/yodel/models/core/fields/array_field.rb +64 -0
  69. data/lib/yodel/models/core/fields/attachment_field.rb +42 -0
  70. data/lib/yodel/models/core/fields/boolean_field.rb +28 -0
  71. data/lib/yodel/models/core/fields/change_sensitive_array.rb +96 -0
  72. data/lib/yodel/models/core/fields/change_sensitive_hash.rb +53 -0
  73. data/lib/yodel/models/core/fields/color_field.rb +4 -0
  74. data/lib/yodel/models/core/fields/date_field.rb +35 -0
  75. data/lib/yodel/models/core/fields/decimal_field.rb +19 -0
  76. data/lib/yodel/models/core/fields/email_field.rb +10 -0
  77. data/lib/yodel/models/core/fields/enum_field.rb +33 -0
  78. data/lib/yodel/models/core/fields/field.rb +154 -0
  79. data/lib/yodel/models/core/fields/fields.rb +29 -0
  80. data/lib/yodel/models/core/fields/fields_field.rb +31 -0
  81. data/lib/yodel/models/core/fields/filter_mixin.rb +9 -0
  82. data/lib/yodel/models/core/fields/filtered_string_field.rb +5 -0
  83. data/lib/yodel/models/core/fields/filtered_text_field.rb +5 -0
  84. data/lib/yodel/models/core/fields/function_field.rb +28 -0
  85. data/lib/yodel/models/core/fields/hash_field.rb +54 -0
  86. data/lib/yodel/models/core/fields/html_field.rb +15 -0
  87. data/lib/yodel/models/core/fields/image_field.rb +11 -0
  88. data/lib/yodel/models/core/fields/integer_field.rb +25 -0
  89. data/lib/yodel/models/core/fields/password_field.rb +21 -0
  90. data/lib/yodel/models/core/fields/self_field.rb +27 -0
  91. data/lib/yodel/models/core/fields/string_field.rb +15 -0
  92. data/lib/yodel/models/core/fields/tags_field.rb +7 -0
  93. data/lib/yodel/models/core/fields/text_field.rb +7 -0
  94. data/lib/yodel/models/core/fields/time_field.rb +36 -0
  95. data/lib/yodel/models/core/functions/function.rb +471 -0
  96. data/lib/yodel/models/core/functions/functions.rb +2 -0
  97. data/lib/yodel/models/core/functions/trigger.rb +14 -0
  98. data/lib/yodel/models/core/log/log.rb +33 -0
  99. data/lib/yodel/models/core/log/log_entry.rb +12 -0
  100. data/lib/yodel/models/core/model/abstract_model.rb +59 -0
  101. data/lib/yodel/models/core/model/model.rb +460 -0
  102. data/lib/yodel/models/core/model/mongo_model.rb +25 -0
  103. data/lib/yodel/models/core/model/site_model.rb +17 -0
  104. data/lib/yodel/models/core/mongo/mongo.rb +3 -0
  105. data/lib/yodel/models/core/mongo/primary_key_factory.rb +12 -0
  106. data/lib/yodel/models/core/mongo/query.rb +68 -0
  107. data/lib/yodel/models/core/mongo/record_index.rb +89 -0
  108. data/lib/yodel/models/core/record/abstract_record.rb +411 -0
  109. data/lib/yodel/models/core/record/embedded_record.rb +47 -0
  110. data/lib/yodel/models/core/record/mongo_record.rb +83 -0
  111. data/lib/yodel/models/core/record/record.rb +386 -0
  112. data/lib/yodel/models/core/record/section.rb +21 -0
  113. data/lib/yodel/models/core/record/site_record.rb +31 -0
  114. data/lib/yodel/models/core/site/migration.rb +52 -0
  115. data/lib/yodel/models/core/site/remote.rb +61 -0
  116. data/lib/yodel/models/core/site/site.rb +202 -0
  117. data/lib/yodel/models/core/validations/email_address_validation.rb +24 -0
  118. data/lib/yodel/models/core/validations/embedded_records_validation.rb +31 -0
  119. data/lib/yodel/models/core/validations/errors.rb +51 -0
  120. data/lib/yodel/models/core/validations/excluded_from_validation.rb +10 -0
  121. data/lib/yodel/models/core/validations/excludes_combinations_validation.rb +18 -0
  122. data/lib/yodel/models/core/validations/format_validation.rb +10 -0
  123. data/lib/yodel/models/core/validations/included_in_validation.rb +10 -0
  124. data/lib/yodel/models/core/validations/includes_combinations_validation.rb +14 -0
  125. data/lib/yodel/models/core/validations/length_validation.rb +28 -0
  126. data/lib/yodel/models/core/validations/password_confirmation_validation.rb +11 -0
  127. data/lib/yodel/models/core/validations/required_validation.rb +9 -0
  128. data/lib/yodel/models/core/validations/unique_validation.rb +9 -0
  129. data/lib/yodel/models/core/validations/validation.rb +39 -0
  130. data/lib/yodel/models/core/validations/validations.rb +15 -0
  131. data/lib/yodel/models/email/email.rb +79 -0
  132. data/lib/yodel/models/migrations/01_record_model.rb +29 -0
  133. data/lib/yodel/models/migrations/02_page_model.rb +45 -0
  134. data/lib/yodel/models/migrations/03_layout_model.rb +38 -0
  135. data/lib/yodel/models/migrations/04_group_model.rb +61 -0
  136. data/lib/yodel/models/migrations/05_user_model.rb +24 -0
  137. data/lib/yodel/models/migrations/06_snippet_model.rb +13 -0
  138. data/lib/yodel/models/migrations/07_search_page_model.rb +32 -0
  139. data/lib/yodel/models/migrations/08_default_site_options.rb +21 -0
  140. data/lib/yodel/models/migrations/09_security_page_models.rb +36 -0
  141. data/lib/yodel/models/migrations/10_record_proxy_page_model.rb +17 -0
  142. data/lib/yodel/models/migrations/11_email_model.rb +28 -0
  143. data/lib/yodel/models/migrations/12_api_call_model.rb +23 -0
  144. data/lib/yodel/models/migrations/13_redirect_page_model.rb +13 -0
  145. data/lib/yodel/models/migrations/14_menu_model.rb +20 -0
  146. data/lib/yodel/models/models.rb +8 -0
  147. data/lib/yodel/models/pages/form_builder.rb +379 -0
  148. data/lib/yodel/models/pages/html_decorator.rb +132 -0
  149. data/lib/yodel/models/pages/layout.rb +120 -0
  150. data/lib/yodel/models/pages/menu.rb +32 -0
  151. data/lib/yodel/models/pages/page.rb +378 -0
  152. data/lib/yodel/models/pages/pages.rb +7 -0
  153. data/lib/yodel/models/pages/record_proxy_page.rb +188 -0
  154. data/lib/yodel/models/pages/redirect_page.rb +11 -0
  155. data/lib/yodel/models/search/search.rb +1 -0
  156. data/lib/yodel/models/search/search_page.rb +58 -0
  157. data/lib/yodel/models/security/facebook_login_page.rb +55 -0
  158. data/lib/yodel/models/security/group.rb +10 -0
  159. data/lib/yodel/models/security/guests_group.rb +5 -0
  160. data/lib/yodel/models/security/login_page.rb +20 -0
  161. data/lib/yodel/models/security/logout_page.rb +13 -0
  162. data/lib/yodel/models/security/noone_group.rb +5 -0
  163. data/lib/yodel/models/security/owner_group.rb +8 -0
  164. data/lib/yodel/models/security/password.rb +5 -0
  165. data/lib/yodel/models/security/password_reset_page.rb +47 -0
  166. data/lib/yodel/models/security/security.rb +10 -0
  167. data/lib/yodel/models/security/user.rb +33 -0
  168. data/lib/yodel/public/core/css/core.css +257 -0
  169. data/lib/yodel/public/core/css/reset.css +48 -0
  170. data/lib/yodel/public/core/images/cross.png +0 -0
  171. data/lib/yodel/public/core/images/spinner.gif +0 -0
  172. data/lib/yodel/public/core/images/tick.png +0 -0
  173. data/lib/yodel/public/core/images/yodel.png +0 -0
  174. data/lib/yodel/public/core/js/jquery.min.js +18 -0
  175. data/lib/yodel/public/core/js/json2.js +480 -0
  176. data/lib/yodel/public/core/js/yodel_jquery.js +238 -0
  177. data/lib/yodel/request/authentication.rb +76 -0
  178. data/lib/yodel/request/flash.rb +28 -0
  179. data/lib/yodel/request/request.rb +4 -0
  180. data/lib/yodel/requires.rb +47 -0
  181. data/lib/yodel/task_queue/queue_daemon.rb +33 -0
  182. data/lib/yodel/task_queue/queue_worker.rb +32 -0
  183. data/lib/yodel/task_queue/stats_thread.rb +27 -0
  184. data/lib/yodel/task_queue/task.rb +62 -0
  185. data/lib/yodel/task_queue/task_queue.rb +40 -0
  186. data/lib/yodel/types/date.rb +5 -0
  187. data/lib/yodel/types/object_id.rb +11 -0
  188. data/lib/yodel/types/time.rb +5 -0
  189. data/lib/yodel/version.rb +3 -0
  190. data/system/Library/LaunchDaemons/com.yodelcms.dns.plist +26 -0
  191. data/system/Library/LaunchDaemons/com.yodelcms.server.plist +26 -0
  192. data/system/etc/resolver/yodel +2 -0
  193. data/system/usr/local/bin/yodel_command_runner +2 -0
  194. data/system/usr/local/etc/yodel/development_settings.rb +28 -0
  195. data/system/usr/local/etc/yodel/production_settings.rb +27 -0
  196. data/system/var/log/yodel.log +0 -0
  197. data/test/helper.rb +18 -0
  198. data/test/test_yodel.rb +4 -0
  199. data/yodel.gemspec +47 -0
  200. metadata +501 -0
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,9 @@
1
+ coverage
2
+ rdoc
3
+ doc
4
+ .yardoc
5
+ .bundle
6
+ pkg
7
+ .DS_Store
8
+ *.swp
9
+
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'http://rubygems.org'
2
+ gemspec
@@ -0,0 +1,63 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ yodel (0.0.1)
5
+ activesupport (~> 3.0.3)
6
+ bson (~> 1.3.1)
7
+ bson_ext (~> 1.3.1)
8
+ bundler (~> 1.0.21)
9
+ ember (~> 0.3.1)
10
+ git (~> 1.2.5)
11
+ highline (~> 1.6.2)
12
+ hpricot (~> 0.8.4)
13
+ json (~> 1.6.1)
14
+ mail (~> 2.3.0)
15
+ mini_magick (~> 3.3)
16
+ mongo (~> 1.3.1)
17
+ plucky (~> 0.4.1)
18
+ rack (~> 1.3.3)
19
+ rack-contrib (~> 1.1.0)
20
+ rubydns (~> 0.3.3)
21
+
22
+ GEM
23
+ remote: http://rubygems.org/
24
+ specs:
25
+ activesupport (3.0.11)
26
+ bson (1.3.1)
27
+ bson_ext (1.3.1)
28
+ ember (0.3.1)
29
+ eventmachine (0.12.10)
30
+ git (1.2.5)
31
+ highline (1.6.8)
32
+ hpricot (0.8.4)
33
+ i18n (0.6.0)
34
+ json (1.6.1)
35
+ mail (2.3.0)
36
+ i18n (>= 0.4.0)
37
+ mime-types (~> 1.16)
38
+ treetop (~> 1.4.8)
39
+ mime-types (1.17.2)
40
+ mini_magick (3.3)
41
+ subexec (~> 0.1.0)
42
+ mongo (1.3.1)
43
+ bson (>= 1.3.1)
44
+ plucky (0.4.3)
45
+ mongo (~> 1.3)
46
+ polyglot (0.3.3)
47
+ rack (1.3.5)
48
+ rack-contrib (1.1.0)
49
+ rack (>= 0.9.1)
50
+ rexec (1.4.1)
51
+ rubydns (0.3.3)
52
+ eventmachine
53
+ rexec
54
+ subexec (0.1.0)
55
+ treetop (1.4.10)
56
+ polyglot
57
+ polyglot (>= 0.3.1)
58
+
59
+ PLATFORMS
60
+ ruby
61
+
62
+ DEPENDENCIES
63
+ yodel!
data/LICENSE ADDED
@@ -0,0 +1 @@
1
+ Public Domain
@@ -0,0 +1,20 @@
1
+ = Yodel
2
+
3
+ Rack based Ruby CMS.
4
+
5
+
6
+ == Contributing to yodel
7
+
8
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
9
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
10
+ * Fork the project
11
+ * Start a feature/bugfix branch
12
+ * Commit and push until you are happy with your contribution
13
+ * Make sure you add tests for it
14
+ * Please try not to mess with the Rakefile, version, or history.
15
+
16
+
17
+ == Areas to clean
18
+
19
+ * Adding/deleting/iterating over fields of models, eigenmodels and embedded models
20
+ * embedded model to_json/to_html field etc, is essentially the same as a normal record
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ Dir.chdir(File.dirname(__FILE__))
3
+ require '../lib/yodel/command/command'
4
+ CommandRunner.run
@@ -0,0 +1,22 @@
1
+ Dir.chdir(File.join(File.dirname(__FILE__), 'yodel')) do
2
+ # ensure gem dependencies are loaded
3
+ require './requires'
4
+
5
+ # rack extensions
6
+ require './middleware/request'
7
+ require './middleware/error_pages'
8
+ require './middleware/site_detector'
9
+
10
+ # type extensions
11
+ require './types/date'
12
+ require './types/object_id'
13
+ require './types/time'
14
+
15
+ # core yodel
16
+ require './application/application'
17
+ require './exceptions/exceptions'
18
+ require './mime_types/mime_types'
19
+ require './request/request'
20
+ require './models/models'
21
+ require './task_queue/task_queue'
22
+ end
@@ -0,0 +1,44 @@
1
+ Dir.chdir(File.dirname(__FILE__)) do
2
+ require './request_handler'
3
+ require './extension'
4
+ require './yodel'
5
+ require '../middleware/public_assets' if Yodel.env.development?
6
+ end
7
+
8
+ class Application < Rack::Builder
9
+ def initialize
10
+ super
11
+
12
+ # boot
13
+ Yodel.config.logger.info "Yodel starting up" if Yodel.env.production?
14
+ Dir.chdir(Yodel.config.sites_root)
15
+ Yodel.load_extensions
16
+
17
+ # setup middleware
18
+ use Rack::ShowExceptions if Yodel.env.development?
19
+ use ErrorPages
20
+ use Rack::Session::Cookie, key: Yodel.config.session_key, secret: Yodel.config.session_secret
21
+ use Rack::NestedParams
22
+ use Rack::MethodOverride
23
+ use SiteDetector
24
+ use PublicAssets if Yodel.env.development?
25
+
26
+ # FIXME: for production, load layouts once
27
+ if Yodel.env.production?
28
+ Site.all.each {|site| Layout.reload_layouts(site)}
29
+ end
30
+
31
+ # initialise a rack endpoint
32
+ run RequestHandler.new
33
+ @app = to_app
34
+
35
+ # boot complete
36
+ unless Yodel.env.development?
37
+ Yodel.config.logger.info "Yodel startup complete"
38
+ end
39
+ end
40
+
41
+ def call(env)
42
+ @app.call(env)
43
+ end
44
+ end
@@ -0,0 +1,59 @@
1
+ class Extension
2
+ attr_reader :name, :lib_dir, :migrations_dir, :public_dir, :layouts_dir, :models_dir
3
+
4
+ def initialize
5
+ @environment = @name.end_with?('environment')
6
+ @migrations_dir = File.join(@lib_dir, Yodel::MIGRATIONS_DIRECTORY_NAME)
7
+ @public_dir = File.join(@lib_dir, Yodel::PUBLIC_DIRECTORY_NAME)
8
+ @layouts_dir = File.join(@lib_dir, Yodel::LAYOUTS_DIRECTORY_NAME)
9
+ @models_dir = File.join(@lib_dir, Yodel::MODELS_DIRECTORY_NAME)
10
+ Yodel.extensions[@name] = self
11
+ end
12
+
13
+ def load!
14
+ unless @environment
15
+ require_extension
16
+ Yodel.config.public_directories << @public_dir if File.directory?(@public_dir)
17
+ Yodel.config.layout_directories << @layouts_dir if File.directory?(@layouts_dir)
18
+ Yodel.config.extensions << self
19
+ end
20
+
21
+ # load any models. if the init.rb file exists it will be loaded instead,
22
+ # allowing extensions to specify the order models are loaded.
23
+ if File.exist?(@models_dir)
24
+ init_file = File.join(@models_dir, 'init.rb')
25
+ if File.exist?(init_file)
26
+ require init_file
27
+ else
28
+ Dir[File.join(@models_dir, '**')].sort.each do |model|
29
+ next if model.start_with?('.')
30
+ require File.realpath(model, @models_dir)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ class GemExtension < Extension
38
+ def initialize(gem)
39
+ @name = gem.name
40
+ @lib_dir = File.join(gem.full_gem_path, Yodel::EXTENSION_LIB_DIRECTORY_NAME)
41
+ super()
42
+ end
43
+
44
+ def require_extension
45
+ require @name
46
+ end
47
+ end
48
+
49
+ class FolderExtension < Extension
50
+ def initialize(path)
51
+ @name = File.basename(path)
52
+ @lib_dir = File.join(path, Yodel::EXTENSION_LIB_DIRECTORY_NAME)
53
+ super()
54
+ end
55
+
56
+ def require_extension
57
+ require File.join(@lib_dir, @name)
58
+ end
59
+ end
@@ -0,0 +1,48 @@
1
+ class RequestHandler
2
+ PATH_FORMAT_REGEX = /^(?<path>.*?)(\.(?<format>\w+))?$/
3
+
4
+ def call(env)
5
+ # find the site this request is for
6
+ request = Rack::Request.new(env)
7
+ response = Rack::Response.new
8
+ site = env['yodel.site']
9
+
10
+ # temporary workaround to force rack to write the session out to a cookie
11
+ env['rack.session']['a'] = 1
12
+
13
+ # split the request path into a standard path and trailing file extension if present
14
+ components = PATH_FORMAT_REGEX.match(request.path)
15
+ return fail_with "Unable to parse request path: #{request.path}" if components.nil?
16
+ path, format = components.captures
17
+ path = path[0...-1] if path.end_with?('/') && path.length != 1
18
+
19
+ # match the request to the closest mime type we're aware of
20
+ mime_type = Yodel.mime_types.mime_type_for_request(format, request.env['HTTP_ACCEPT'])
21
+
22
+ # attempt to find a matching page for this request
23
+ page = site.pages.where(path: path).first
24
+ if page.nil?
25
+ site.glob_pages.all.each do |glob_page|
26
+ if path.start_with?(glob_page.path)
27
+ page = glob_page
28
+ request.params['glob'] = path[glob_page.path.length..-1]
29
+ break
30
+ end
31
+ end
32
+ return fail_with "File (#{request.path}) not found." if page.nil?
33
+ end
34
+
35
+ # respond
36
+ Layout.reload_layouts(site) if Yodel.env.development? # FIXME: implement production caching
37
+ page.respond_to_request(request, response, mime_type)
38
+ if page.response.respond_to?(:finish)
39
+ page.response.finish
40
+ else
41
+ page.response
42
+ end
43
+ end
44
+
45
+ def fail_with(message)
46
+ [404, {'Content-Type' => 'text/plain'}, [message]]
47
+ end
48
+ end
@@ -0,0 +1,25 @@
1
+ module Yodel
2
+ def self.db
3
+ @db ||= Mongo::Connection.new(Yodel.config.database_hostname, Yodel.config.database_port).db(Yodel.config.database)
4
+ end
5
+
6
+ def self.extensions
7
+ @extensions ||= {}
8
+ end
9
+
10
+ def self.load_extensions
11
+ if Yodel.config.extensions_folder
12
+ Dir[File.join(Yodel.config.extensions_folder, '/*')].each do |path|
13
+ next unless File.directory?(path) && File.basename(path).start_with?('yodel_')
14
+ extension = FolderExtension.new(path)
15
+ extension.load!
16
+ end
17
+ else
18
+ Gem::Specification.find_all do |gem|
19
+ next unless gem.name.start_with?('yodel_')
20
+ extension = GemExtension.new(gem)
21
+ extension.load!
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,94 @@
1
+ require 'optparse'
2
+ Dir.chdir(File.dirname(__FILE__))
3
+ Encoding.default_external = "utf-8"
4
+
5
+ class CommandRunner
6
+ def self.run
7
+ OptionParser.new do |opts|
8
+ opts.banner = "Usage: yodel [options] server|dns|console|migrate|setup|deploy"
9
+ opts.on('-p', '--port PORT', Integer, 'Override the default web server port') do |port|
10
+ $web_port = port
11
+ end
12
+
13
+ opts.on('-e', '--environment ENV', 'Web server environment (default development)', 'development', 'production') do |env|
14
+ $env = env
15
+ end
16
+
17
+ opts.on('-s', '--settings FILE', 'Load this settings file (default: /usr/local/etc/yodel/settings.rb)') do |settings|
18
+ $settings = settings
19
+ end
20
+
21
+ opts.on('-x', '--extensions PATH', 'Load extensions from the supplied folder, rather than from installed gems') do |path|
22
+ $extensions_folder = path
23
+ end
24
+
25
+ opts.on('-r', '--reload', 'Reloads the server whenever any framework source files are modified') do
26
+ $reload = true
27
+ end
28
+
29
+ opts.on('-h', '--help', 'Display this screen') do
30
+ puts opts
31
+ exit
32
+ end
33
+ end.parse!
34
+
35
+ command = ARGV.shift
36
+
37
+
38
+ case command
39
+ when 'server'
40
+ require '../requires'
41
+ require '../middleware/development_server'
42
+
43
+ Yodel.config.extensions_folder = $extensions_folder if $extensions_folder
44
+ Yodel.config.web_port = $web_port if $web_port
45
+
46
+ if $env == 'production'
47
+ Yodel.env.production!
48
+ else
49
+ Yodel.env.development!
50
+ end
51
+
52
+ if $reload
53
+ Rack::Server.start(app: DevelopmentServer.new, Port: Yodel.config.web_port)
54
+ else
55
+ require File.expand_path('../../yodel')
56
+ Rack::Server.start(app: Application.new, Port: Yodel.config.web_port)
57
+ end
58
+
59
+ when 'dns'
60
+ require '../requires'
61
+ require './dns_server'
62
+ DNSServer.start
63
+
64
+ when 'console'
65
+ require '../../yodel'
66
+ require 'irb'
67
+
68
+ Yodel.config.extensions_folder = $extensions_folder if $extensions_folder
69
+ $application = Application.new
70
+ IRB.start(__FILE__)
71
+
72
+ when 'migrate'
73
+ require '../../yodel'
74
+ Yodel.config.extensions_folder = $extensions_folder if $extensions_folder
75
+ $application = Application.new
76
+ Site.all.each do |site|
77
+ Migration.run_migrations(site)
78
+ end
79
+
80
+ when 'deploy'
81
+ require '../../yodel'
82
+ Yodel.config.extensions_folder = $extensions_folder if $extensions_folder
83
+ require './deploy'
84
+ Deploy.new.deploy_site
85
+
86
+ when 'setup'
87
+ require './installer'
88
+ Installer.new.install_system_files
89
+
90
+ else
91
+ puts "Unknown command: #{command}"
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,67 @@
1
+ class Deploy
2
+ def initialize
3
+ @application = Application.new
4
+ @site_id = ARGV.shift
5
+ end
6
+
7
+ def deploy_site
8
+ puts "A site ID must be supplied as the last parameter to deploy" and return if @site_id.blank?
9
+ site = Site.where(_id: BSON::ObjectId.from_string(@site_id)).first
10
+ puts "Site could not be found" and return if site.nil?
11
+ new_site = site.migrations.empty?
12
+
13
+ # store the list of domains associated with this site; once the site has been reloaded from
14
+ # the updated yaml file, deleted domains need to have their corresponding folders removed
15
+ old_domains = site.domains.dup
16
+
17
+ # read site.yml and update db record
18
+ site.reload_from_site_yaml
19
+
20
+ # FIXME: it's possible for one site to take control of another's domains at the moment;
21
+ # process "should" be that the first site with a domain owns that domain. Only it can
22
+ # add subdomains to it; yodelcms.com etc. is an exception to this.
23
+ # remove "bad" domain names
24
+ site.domains = site.remote_domains
25
+
26
+ # link public directories so a fronting web server can serve public assets easily
27
+ site.domains.each do |domain|
28
+ path = File.join(Yodel.config.public_directory, domain)
29
+ FileUtils.ln_s(site.public_directory, path) unless File.exists?(path)
30
+ end
31
+
32
+ # remove folders associated with deleted domains
33
+ old_domains -= site.domains
34
+ old_domains.each do |domain|
35
+ path = File.join(Yodel.config.public_directory, domain)
36
+ FileUtils.rm(path) if File.exists?(path)
37
+ end
38
+
39
+ # migrate (taking the site live)
40
+ Migration.run_migrations(site)
41
+
42
+ # reload layouts from disk
43
+ Layout.reload_layouts(site)
44
+
45
+ # the first time a site is created, all users with access to the site (1 at this stage
46
+ # in most cases) are copied as administrators of the new site. As users are added and
47
+ # removed, their corresponding administrator records are updated in the site.
48
+ if new_site
49
+ production_site = Site.where(name: 'yodel').first
50
+ production_site.users.where(sites: site.id).all.each do |admin|
51
+ user = site.users.new
52
+ user.first_name = admin.name
53
+ user.email = admin.email
54
+ user.username = admin.email
55
+ user.password = admin.password
56
+ user.groups << site.groups['Developers']
57
+ user.save
58
+
59
+ # because of the before_create callback, we need to override
60
+ # the salt and password manually by saving again
61
+ user.password_salt = nil
62
+ user.password = admin.password
63
+ user.save_without_validation
64
+ end
65
+ end
66
+ end
67
+ end