yodel 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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