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,7 @@
1
+ require './pages/html_decorator'
2
+ require './pages/page'
3
+ require './pages/layout'
4
+ require './pages/form_builder'
5
+ require './pages/record_proxy_page'
6
+ require './pages/redirect_page'
7
+ require './pages/menu'
@@ -0,0 +1,188 @@
1
+ class RecordProxyPage < Page
2
+ def record
3
+ @record ||= decorate_record(find_record(BSON::ObjectId.from_string(params['id'])))
4
+ end
5
+
6
+ def records
7
+ @records ||= all_records.map {|record| decorate_record(record)}
8
+ end
9
+
10
+ def new_record
11
+ decorate_record(construct_record)
12
+ end
13
+
14
+ def record=(record)
15
+ @record = record
16
+ end
17
+
18
+ def form_for(record, options={}, &block)
19
+ if record.new?
20
+ options[:method] = 'post'
21
+ action = path
22
+ if after_create_page
23
+ options[:success] = "window.location = '#{after_create_page.path}';"
24
+ else
25
+ options[:success] = "window.location = '#{path}';"
26
+ end
27
+ else
28
+ options[:method] = 'put'
29
+ action = "#{path}?id=#{record.id}"
30
+ if after_update_page
31
+ options[:success] = "window.location = '#{after_update_page.path}';"
32
+ else
33
+ options[:success] = "window.location = '#{path}';"
34
+ end
35
+ end
36
+ super(record, action, options, &block)
37
+ end
38
+
39
+ def form_for_new_record(options={}, &block)
40
+ form_for(new_record, options, &block)
41
+ end
42
+
43
+ # FIXME: a lot of this code is duplicated between html/json, need a way to
44
+ # extract common code to something like
45
+ # respond_to :delete do
46
+ # record.destroy
47
+ #
48
+ # with :html do
49
+ # ...
50
+
51
+ # FIXME: all json requests should be standardised to {success: true/false}
52
+ # i.e get needs to change from record.to_json to {success: true, record: record}
53
+
54
+ # FIXME: change get to pass record through format_record
55
+
56
+ # show
57
+ respond_to :get do
58
+ # FIXME: security check
59
+ with :html do
60
+ if params['id']
61
+ render_layout(show_record_layout, :html)
62
+ else
63
+ super()
64
+ end
65
+ end
66
+
67
+ with :json do
68
+ record.to_json
69
+ end
70
+ end
71
+
72
+ # destroy
73
+ respond_to :delete do
74
+ # FIXME: security check
75
+ with :html do
76
+ record.destroy
77
+ response.redirect after_delete_page.try(:path) || request.referrer || path
78
+ end
79
+
80
+ with :json do
81
+ record.destroy
82
+ {success: true}
83
+ end
84
+ end
85
+
86
+ # update
87
+ respond_to :put do
88
+ # FIXME: security check
89
+ with :html do
90
+ raise "Unimplemented"
91
+ end
92
+
93
+ with :json do
94
+ status 404 and return unless record
95
+ if params.key?('record')
96
+ values = JSON.parse(params['record'])
97
+ else
98
+ values = params
99
+ end
100
+
101
+ if record.from_json(values)
102
+ format_record(record).merge({success: true})
103
+ else
104
+ {success: false, errors: record.errors}
105
+ end
106
+ end
107
+ end
108
+
109
+ # create
110
+ respond_to :post do
111
+ # FIXME: security check
112
+ with :html do
113
+ raise "Unimplemented"
114
+ end
115
+
116
+ with :json do
117
+ record = new_record
118
+
119
+ if params.key?('record')
120
+ vaues = JSON.parse(params['record'])
121
+ else
122
+ values = params
123
+ end
124
+
125
+ if record.from_json(values)
126
+ format_record(record).merge({success: true})
127
+ else
128
+ {success: false, errors: record.errors}
129
+ end
130
+ end
131
+
132
+ end
133
+
134
+
135
+ # record interaction and decoration. all_records, find_record and
136
+ # construct_record can be overriden for records which can't be
137
+ # retrieved from a record_model (such as Site or Task)
138
+ # override format_record to change the way records are returned
139
+ # to json requests, either reformatting the record itself, or
140
+ # adding new keys to the response object
141
+ private
142
+ def decorate_record(record)
143
+ record.tap do |record|
144
+ # if the record mixes in another model which has already
145
+ # included HTMLDecorator, undef these methods so record
146
+ # proxy page can handle them instead. When a model is
147
+ # mixed in, forwardable creates
148
+ if record.methods(false).include?(:delete_link)
149
+ class << record
150
+ HTMLDecorator.instance_methods.each do |method_name|
151
+ remove_method method_name
152
+ end
153
+ end
154
+ end
155
+
156
+ record.instance_variable_set('@record_proxy', self)
157
+ record.extend HTMLDecorator
158
+ record.instance_eval "
159
+ class << self
160
+ def path
161
+ \"#{path}?id=#{record.id}\"
162
+ end
163
+ alias :path_was :path
164
+
165
+ def form_for(record, options={}, &block)
166
+ @record_proxy.form_for(record, options, &block)
167
+ end
168
+ end
169
+ "
170
+ end
171
+ end
172
+
173
+ def all_records
174
+ record_model.all
175
+ end
176
+
177
+ def find_record(id)
178
+ record_model.find(id)
179
+ end
180
+
181
+ def construct_record
182
+ record_model.new
183
+ end
184
+
185
+ def format_record(record)
186
+ {record: record}
187
+ end
188
+ end
@@ -0,0 +1,11 @@
1
+ class RedirectPage < Page
2
+ respond_to :get do
3
+ with :html do
4
+ if url?
5
+ response.redirect url
6
+ else
7
+ response.redirect page.path
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1 @@
1
+ require './search/search_page'
@@ -0,0 +1,58 @@
1
+ class SearchPage < Page
2
+ OPERATOR_METHODS = {
3
+ 'Equals' => nil,
4
+ 'Not Equal' => :ne,
5
+ 'Greater Than' => :gt,
6
+ 'Less Than' => :lt,
7
+ 'Greater Than or Equal To' => :gte,
8
+ 'Less Than or Equal To' => :lte,
9
+ 'In' => :in
10
+ }
11
+
12
+ def query
13
+ q = (type || site.records).where(show_in_search: true)
14
+
15
+ # constant constraints
16
+ conditions.each do |condition|
17
+ q = add_condition(q, type, condition.name, condition.operator, condition.value)
18
+ end
19
+
20
+ # user conditions
21
+ user_conditions.each do |condition|
22
+ param_name = condition.as || condition.name
23
+ q = add_condition(q, type, condition.name, condition.operator, params[param_name])
24
+ end
25
+
26
+ # add other optional search parameters
27
+ q = q.sort(sort || params['sort']) if sort || params['sort']
28
+ q = q.limit(limit || params['limit'].to_i) if limit || params['limit']
29
+ q = q.skip(skip || params['skip'].to_i) if skip || params['skip']
30
+ q
31
+ end
32
+
33
+ def add_condition(q, type, field, operator, value)
34
+ return q if value.blank?
35
+ operator = OPERATOR_METHODS[operator]
36
+ field = field.to_sym
37
+
38
+ if type && type.all_record_fields[field.to_s]
39
+ value = type.all_record_fields[field.to_s].from_json(value, type)
40
+ end
41
+
42
+ # the in operator works on arrays
43
+ #if operator == :in
44
+ # value = value.to_s.split(' ').reject(&:blank?).collect(&:downcase)
45
+ #end
46
+
47
+ if operator
48
+ q.where(field.send(operator) => value)
49
+ else
50
+ q.where(field => value)
51
+ end
52
+ end
53
+
54
+ # True if the request contains any of the parameters
55
+ def user_query?
56
+ user_conditions.any? {|condition| params[condition.as ? condition.as : condition.name].present?}
57
+ end
58
+ end
@@ -0,0 +1,55 @@
1
+ class FacebookLoginPage < Page
2
+ GRAPH_DOMAIN = 'graph.facebook.com'
3
+ ACCESS_URL = "/oauth/access_token?"
4
+ USER_URL = "/me?"
5
+
6
+ respond_to :get do
7
+ with :html do
8
+ begin
9
+ if params['code']
10
+ auth_code = params['code']
11
+ access_url = ACCESS_URL
12
+ access_url += "client_id=#{app_id}"
13
+ access_url += "&redirect_uri=#{callback_uri}"
14
+ access_url += "&client_secret=#{app_secret}"
15
+ access_url += "&code=#{auth_code}"
16
+ access_code = get_https(access_url)
17
+
18
+ # read user details
19
+ if access_code
20
+ user_response = get_https("#{USER_URL}#{access_code}")
21
+ user_details = JSON.parse(user_response)
22
+ if user_details['id']
23
+ user = site.users.where(oauth_id: user_details['id']).first
24
+ if user
25
+ # login
26
+ store_authenticated_user(user)
27
+ @path = after_login_page.path
28
+ else
29
+ # register with details
30
+ @path = join_page.path + '?'
31
+ @path += "first_name=#{CGI.escape(user_details['first_name'])}"
32
+ @path += "&last_name=#{CGI.escape(user_details['last_name'])}"
33
+ @path += "&email=#{CGI.escape(user_details['email'])}"
34
+ @path += "&oauth_id=#{CGI.escape(user_details['id'])}"
35
+ end
36
+ end
37
+ end
38
+ end
39
+ ensure
40
+ @path = join_page.path if @path.nil?
41
+ return "<html><script>window.opener.location.href = '#{@path}';window.close();</script></html>"
42
+ end
43
+ end
44
+ end
45
+
46
+ def get_https(path)
47
+ https = Net::HTTP.new(GRAPH_DOMAIN, 443)
48
+ https.use_ssl = true
49
+ https.verify_mode = OpenSSL::SSL::VERIFY_PEER
50
+ https.start do
51
+ req = Net::HTTP::Get.new(path)
52
+ return https.request(req).read_body
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,10 @@
1
+ class Group < Record
2
+ def match_user_on_record?(user, record)
3
+ return false if user.nil?
4
+ user.values['groups'].include? id
5
+ end
6
+
7
+ def permitted?(user, record)
8
+ match_user_on_record?(user, record) || parent.try(:match_user_on_record?, user, record)
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ class GuestsGroup < Group
2
+ def match_user_on_record?(user, record)
3
+ true
4
+ end
5
+ end
@@ -0,0 +1,20 @@
1
+ class LoginPage < Page
2
+ respond_to :post do
3
+ with :html do
4
+ credentials = {username_field => params[username_field], password_field => params[password_field]}
5
+
6
+ if login(credentials)
7
+ path = redirect_to.try(:path) || session.delete(:redirect_to_after_login) || request.referrer || '/'
8
+ response.redirect path
9
+ else
10
+ flash.now(:login_failed, true)
11
+ render_or_default(:html) { raise LayoutNotFound }
12
+ end
13
+ end
14
+
15
+ with :json do
16
+ credentials = {username_field => params[username_field], password_field => params[password_field]}
17
+ {success: login(credentials)}
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ class LogoutPage < Page
2
+ respond_to :get do
3
+ with :html do
4
+ logout
5
+ response.redirect redirect_to.try(:path) || '/'
6
+ end
7
+
8
+ with :json do
9
+ logout
10
+ {success: true}
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ class NooneGroup < Group
2
+ def match_user_on_record?(user, record)
3
+ false
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ class OwnerGroup < Group
2
+ def match_user_on_record?(user, record)
3
+ return false if user.nil?
4
+ user == record.owner
5
+ rescue
6
+ false
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module Password
2
+ def self.hashed_password(password_salt, password)
3
+ Digest::SHA1.hexdigest("#{password_salt}:#{password}")
4
+ end
5
+ end
@@ -0,0 +1,47 @@
1
+ class PasswordResetPage < Page
2
+ def reset?
3
+ !!@reset
4
+ end
5
+
6
+ def reset=(reset)
7
+ @reset = reset
8
+ end
9
+
10
+ def failed_email_lookup?
11
+ !!@failed_email_lookup
12
+ end
13
+
14
+ def failed_email_lookup=(failed)
15
+ @failed_email_lookup = failed
16
+ end
17
+
18
+ respond_to :get do
19
+ with :html do
20
+ @email = params['email']
21
+ render_or_default(:html) { raise LayoutNotFound }
22
+ end
23
+ end
24
+
25
+ respond_to :post do
26
+ with :html do
27
+ email = params[email_field]
28
+ user = site.users.where(email: email).first
29
+
30
+ if user
31
+ name = user.name
32
+ new_password = user.reset_password
33
+ site.emails[:password_reset].deliver to: user.email, new_password: new_password, first_name: user.first_name
34
+ self.reset = true
35
+ else
36
+ self.failed_email_lookup = true
37
+ end
38
+
39
+ @email = email
40
+ render_or_default(:html) { raise LayoutNotFound }
41
+ end
42
+
43
+ with :json do
44
+ # FIXME: implement json page for this
45
+ end
46
+ end
47
+ end