yodel 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +9 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +63 -0
- data/LICENSE +1 -0
- data/README.rdoc +20 -0
- data/Rakefile +1 -0
- data/bin/yodel +4 -0
- data/lib/yodel.rb +22 -0
- data/lib/yodel/application/application.rb +44 -0
- data/lib/yodel/application/extension.rb +59 -0
- data/lib/yodel/application/request_handler.rb +48 -0
- data/lib/yodel/application/yodel.rb +25 -0
- data/lib/yodel/command/command.rb +94 -0
- data/lib/yodel/command/deploy.rb +67 -0
- data/lib/yodel/command/dns_server.rb +16 -0
- data/lib/yodel/command/installer.rb +229 -0
- data/lib/yodel/config/config.rb +30 -0
- data/lib/yodel/config/environment.rb +16 -0
- data/lib/yodel/config/yodel.rb +21 -0
- data/lib/yodel/exceptions/destroyed_record.rb +2 -0
- data/lib/yodel/exceptions/domain_not_found.rb +16 -0
- data/lib/yodel/exceptions/duplicate_layout.rb +2 -0
- data/lib/yodel/exceptions/exceptions.rb +3 -0
- data/lib/yodel/exceptions/inconsistent_lock_state.rb +2 -0
- data/lib/yodel/exceptions/invalid_field.rb +2 -0
- data/lib/yodel/exceptions/invalid_index.rb +2 -0
- data/lib/yodel/exceptions/invalid_mixin.rb +2 -0
- data/lib/yodel/exceptions/invalid_model_field.rb +2 -0
- data/lib/yodel/exceptions/layout_not_found.rb +2 -0
- data/lib/yodel/exceptions/mass_assignment.rb +2 -0
- data/lib/yodel/exceptions/missing_migration.rb +2 -0
- data/lib/yodel/exceptions/missing_root_directory.rb +15 -0
- data/lib/yodel/exceptions/unable_to_acquire_lock.rb +2 -0
- data/lib/yodel/exceptions/unauthorised.rb +2 -0
- data/lib/yodel/exceptions/unknown_field.rb +2 -0
- data/lib/yodel/middleware/development_server.rb +180 -0
- data/lib/yodel/middleware/error_pages.rb +72 -0
- data/lib/yodel/middleware/public_assets.rb +78 -0
- data/lib/yodel/middleware/request.rb +16 -0
- data/lib/yodel/middleware/site_detector.rb +22 -0
- data/lib/yodel/mime_types/default_mime_set.rb +28 -0
- data/lib/yodel/mime_types/mime_type.rb +68 -0
- data/lib/yodel/mime_types/mime_type_set.rb +41 -0
- data/lib/yodel/mime_types/mime_types.rb +6 -0
- data/lib/yodel/mime_types/yodel.rb +15 -0
- data/lib/yodel/models/api/api.rb +1 -0
- data/lib/yodel/models/api/api_call.rb +87 -0
- data/lib/yodel/models/core/associations/association.rb +37 -0
- data/lib/yodel/models/core/associations/associations.rb +22 -0
- data/lib/yodel/models/core/associations/counts/many_association.rb +18 -0
- data/lib/yodel/models/core/associations/counts/one_association.rb +22 -0
- data/lib/yodel/models/core/associations/embedded/embedded_association.rb +47 -0
- data/lib/yodel/models/core/associations/embedded/embedded_record_array.rb +12 -0
- data/lib/yodel/models/core/associations/embedded/many_embedded_association.rb +62 -0
- data/lib/yodel/models/core/associations/embedded/one_embedded_association.rb +49 -0
- data/lib/yodel/models/core/associations/query/many_query_association.rb +10 -0
- data/lib/yodel/models/core/associations/query/one_query_association.rb +10 -0
- data/lib/yodel/models/core/associations/query/query_association.rb +64 -0
- data/lib/yodel/models/core/associations/record_association.rb +38 -0
- data/lib/yodel/models/core/associations/store/many_store_association.rb +32 -0
- data/lib/yodel/models/core/associations/store/one_store_association.rb +14 -0
- data/lib/yodel/models/core/associations/store/store_association.rb +51 -0
- data/lib/yodel/models/core/attachments/attachment.rb +73 -0
- data/lib/yodel/models/core/attachments/image.rb +38 -0
- data/lib/yodel/models/core/core.rb +15 -0
- data/lib/yodel/models/core/fields/alias_field.rb +32 -0
- data/lib/yodel/models/core/fields/array_field.rb +64 -0
- data/lib/yodel/models/core/fields/attachment_field.rb +42 -0
- data/lib/yodel/models/core/fields/boolean_field.rb +28 -0
- data/lib/yodel/models/core/fields/change_sensitive_array.rb +96 -0
- data/lib/yodel/models/core/fields/change_sensitive_hash.rb +53 -0
- data/lib/yodel/models/core/fields/color_field.rb +4 -0
- data/lib/yodel/models/core/fields/date_field.rb +35 -0
- data/lib/yodel/models/core/fields/decimal_field.rb +19 -0
- data/lib/yodel/models/core/fields/email_field.rb +10 -0
- data/lib/yodel/models/core/fields/enum_field.rb +33 -0
- data/lib/yodel/models/core/fields/field.rb +154 -0
- data/lib/yodel/models/core/fields/fields.rb +29 -0
- data/lib/yodel/models/core/fields/fields_field.rb +31 -0
- data/lib/yodel/models/core/fields/filter_mixin.rb +9 -0
- data/lib/yodel/models/core/fields/filtered_string_field.rb +5 -0
- data/lib/yodel/models/core/fields/filtered_text_field.rb +5 -0
- data/lib/yodel/models/core/fields/function_field.rb +28 -0
- data/lib/yodel/models/core/fields/hash_field.rb +54 -0
- data/lib/yodel/models/core/fields/html_field.rb +15 -0
- data/lib/yodel/models/core/fields/image_field.rb +11 -0
- data/lib/yodel/models/core/fields/integer_field.rb +25 -0
- data/lib/yodel/models/core/fields/password_field.rb +21 -0
- data/lib/yodel/models/core/fields/self_field.rb +27 -0
- data/lib/yodel/models/core/fields/string_field.rb +15 -0
- data/lib/yodel/models/core/fields/tags_field.rb +7 -0
- data/lib/yodel/models/core/fields/text_field.rb +7 -0
- data/lib/yodel/models/core/fields/time_field.rb +36 -0
- data/lib/yodel/models/core/functions/function.rb +471 -0
- data/lib/yodel/models/core/functions/functions.rb +2 -0
- data/lib/yodel/models/core/functions/trigger.rb +14 -0
- data/lib/yodel/models/core/log/log.rb +33 -0
- data/lib/yodel/models/core/log/log_entry.rb +12 -0
- data/lib/yodel/models/core/model/abstract_model.rb +59 -0
- data/lib/yodel/models/core/model/model.rb +460 -0
- data/lib/yodel/models/core/model/mongo_model.rb +25 -0
- data/lib/yodel/models/core/model/site_model.rb +17 -0
- data/lib/yodel/models/core/mongo/mongo.rb +3 -0
- data/lib/yodel/models/core/mongo/primary_key_factory.rb +12 -0
- data/lib/yodel/models/core/mongo/query.rb +68 -0
- data/lib/yodel/models/core/mongo/record_index.rb +89 -0
- data/lib/yodel/models/core/record/abstract_record.rb +411 -0
- data/lib/yodel/models/core/record/embedded_record.rb +47 -0
- data/lib/yodel/models/core/record/mongo_record.rb +83 -0
- data/lib/yodel/models/core/record/record.rb +386 -0
- data/lib/yodel/models/core/record/section.rb +21 -0
- data/lib/yodel/models/core/record/site_record.rb +31 -0
- data/lib/yodel/models/core/site/migration.rb +52 -0
- data/lib/yodel/models/core/site/remote.rb +61 -0
- data/lib/yodel/models/core/site/site.rb +202 -0
- data/lib/yodel/models/core/validations/email_address_validation.rb +24 -0
- data/lib/yodel/models/core/validations/embedded_records_validation.rb +31 -0
- data/lib/yodel/models/core/validations/errors.rb +51 -0
- data/lib/yodel/models/core/validations/excluded_from_validation.rb +10 -0
- data/lib/yodel/models/core/validations/excludes_combinations_validation.rb +18 -0
- data/lib/yodel/models/core/validations/format_validation.rb +10 -0
- data/lib/yodel/models/core/validations/included_in_validation.rb +10 -0
- data/lib/yodel/models/core/validations/includes_combinations_validation.rb +14 -0
- data/lib/yodel/models/core/validations/length_validation.rb +28 -0
- data/lib/yodel/models/core/validations/password_confirmation_validation.rb +11 -0
- data/lib/yodel/models/core/validations/required_validation.rb +9 -0
- data/lib/yodel/models/core/validations/unique_validation.rb +9 -0
- data/lib/yodel/models/core/validations/validation.rb +39 -0
- data/lib/yodel/models/core/validations/validations.rb +15 -0
- data/lib/yodel/models/email/email.rb +79 -0
- data/lib/yodel/models/migrations/01_record_model.rb +29 -0
- data/lib/yodel/models/migrations/02_page_model.rb +45 -0
- data/lib/yodel/models/migrations/03_layout_model.rb +38 -0
- data/lib/yodel/models/migrations/04_group_model.rb +61 -0
- data/lib/yodel/models/migrations/05_user_model.rb +24 -0
- data/lib/yodel/models/migrations/06_snippet_model.rb +13 -0
- data/lib/yodel/models/migrations/07_search_page_model.rb +32 -0
- data/lib/yodel/models/migrations/08_default_site_options.rb +21 -0
- data/lib/yodel/models/migrations/09_security_page_models.rb +36 -0
- data/lib/yodel/models/migrations/10_record_proxy_page_model.rb +17 -0
- data/lib/yodel/models/migrations/11_email_model.rb +28 -0
- data/lib/yodel/models/migrations/12_api_call_model.rb +23 -0
- data/lib/yodel/models/migrations/13_redirect_page_model.rb +13 -0
- data/lib/yodel/models/migrations/14_menu_model.rb +20 -0
- data/lib/yodel/models/models.rb +8 -0
- data/lib/yodel/models/pages/form_builder.rb +379 -0
- data/lib/yodel/models/pages/html_decorator.rb +132 -0
- data/lib/yodel/models/pages/layout.rb +120 -0
- data/lib/yodel/models/pages/menu.rb +32 -0
- data/lib/yodel/models/pages/page.rb +378 -0
- data/lib/yodel/models/pages/pages.rb +7 -0
- data/lib/yodel/models/pages/record_proxy_page.rb +188 -0
- data/lib/yodel/models/pages/redirect_page.rb +11 -0
- data/lib/yodel/models/search/search.rb +1 -0
- data/lib/yodel/models/search/search_page.rb +58 -0
- data/lib/yodel/models/security/facebook_login_page.rb +55 -0
- data/lib/yodel/models/security/group.rb +10 -0
- data/lib/yodel/models/security/guests_group.rb +5 -0
- data/lib/yodel/models/security/login_page.rb +20 -0
- data/lib/yodel/models/security/logout_page.rb +13 -0
- data/lib/yodel/models/security/noone_group.rb +5 -0
- data/lib/yodel/models/security/owner_group.rb +8 -0
- data/lib/yodel/models/security/password.rb +5 -0
- data/lib/yodel/models/security/password_reset_page.rb +47 -0
- data/lib/yodel/models/security/security.rb +10 -0
- data/lib/yodel/models/security/user.rb +33 -0
- data/lib/yodel/public/core/css/core.css +257 -0
- data/lib/yodel/public/core/css/reset.css +48 -0
- data/lib/yodel/public/core/images/cross.png +0 -0
- data/lib/yodel/public/core/images/spinner.gif +0 -0
- data/lib/yodel/public/core/images/tick.png +0 -0
- data/lib/yodel/public/core/images/yodel.png +0 -0
- data/lib/yodel/public/core/js/jquery.min.js +18 -0
- data/lib/yodel/public/core/js/json2.js +480 -0
- data/lib/yodel/public/core/js/yodel_jquery.js +238 -0
- data/lib/yodel/request/authentication.rb +76 -0
- data/lib/yodel/request/flash.rb +28 -0
- data/lib/yodel/request/request.rb +4 -0
- data/lib/yodel/requires.rb +47 -0
- data/lib/yodel/task_queue/queue_daemon.rb +33 -0
- data/lib/yodel/task_queue/queue_worker.rb +32 -0
- data/lib/yodel/task_queue/stats_thread.rb +27 -0
- data/lib/yodel/task_queue/task.rb +62 -0
- data/lib/yodel/task_queue/task_queue.rb +40 -0
- data/lib/yodel/types/date.rb +5 -0
- data/lib/yodel/types/object_id.rb +11 -0
- data/lib/yodel/types/time.rb +5 -0
- data/lib/yodel/version.rb +3 -0
- data/system/Library/LaunchDaemons/com.yodelcms.dns.plist +26 -0
- data/system/Library/LaunchDaemons/com.yodelcms.server.plist +26 -0
- data/system/etc/resolver/yodel +2 -0
- data/system/usr/local/bin/yodel_command_runner +2 -0
- data/system/usr/local/etc/yodel/development_settings.rb +28 -0
- data/system/usr/local/etc/yodel/production_settings.rb +27 -0
- data/system/var/log/yodel.log +0 -0
- data/test/helper.rb +18 -0
- data/test/test_yodel.rb +4 -0
- data/yodel.gemspec +47 -0
- metadata +501 -0
@@ -0,0 +1,238 @@
|
|
1
|
+
var Yodel = {};
|
2
|
+
|
3
|
+
// Security
|
4
|
+
Yodel.Security = {
|
5
|
+
login: function(credentials, path) {
|
6
|
+
var action = (path ? path : '/login');
|
7
|
+
var form = jQuery('<form action="' + action + '" metod="post"/>');
|
8
|
+
jQuery.each(credentials, function(key, value) {
|
9
|
+
form.append(jQuery('<input type="hidden" name="' + key + '" value="' + value + '"/>'));
|
10
|
+
});
|
11
|
+
form.submit();
|
12
|
+
},
|
13
|
+
|
14
|
+
remote_login: function(credentials, fns, path) {
|
15
|
+
path = path ? path : '/login.json';
|
16
|
+
var request = jQuery.post(path, credentials, 'json');
|
17
|
+
request.success(function(data, textStatus, jqXHR) {
|
18
|
+
if(fns.success)
|
19
|
+
fns.success(data);
|
20
|
+
});
|
21
|
+
request.error(function(jqXHR, textStatus, errorThrown) {
|
22
|
+
if(fns.failure) {
|
23
|
+
var json = {};
|
24
|
+
try {
|
25
|
+
json = jQuery.parseJSON(jqXHR.responseText);
|
26
|
+
} catch(err) {}
|
27
|
+
fns.failure(json);
|
28
|
+
}
|
29
|
+
});
|
30
|
+
},
|
31
|
+
|
32
|
+
Facebook: {
|
33
|
+
Window: {
|
34
|
+
width: 1000,
|
35
|
+
height: 480,
|
36
|
+
title: 'Login'
|
37
|
+
},
|
38
|
+
redirectPath: '/facebook',
|
39
|
+
redirectURI: null,
|
40
|
+
clientID: '',
|
41
|
+
scope: null
|
42
|
+
},
|
43
|
+
|
44
|
+
facebook_login: function() {
|
45
|
+
var Options = Yodel.Security.Facebook;
|
46
|
+
var url = 'https://www.facebook.com/dialog/oauth?client_id=' + Options.clientID;
|
47
|
+
|
48
|
+
if(Options.redirectURI) {
|
49
|
+
url += '&redirect_uri=' + Options.redirectURI;
|
50
|
+
} else {
|
51
|
+
url += '&redirect_uri=' + window.location.protocol + '//' + window.location.host + Options.redirectPath;
|
52
|
+
}
|
53
|
+
|
54
|
+
if(Options.scope) {
|
55
|
+
url += '&scope=' + Options.scope;
|
56
|
+
}
|
57
|
+
|
58
|
+
var windowOptionsString = 'width=' + Options.Window.width + ',height=' + Options.Window.height;
|
59
|
+
window.open(url, Options.Window.title, windowOptionsString);
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
jQuery('*[data-oauth-login=facebook]').live('click', function(event, element) {
|
64
|
+
Yodel.Security.facebook_login();
|
65
|
+
event.preventDefault();
|
66
|
+
});
|
67
|
+
|
68
|
+
|
69
|
+
// Record interaction
|
70
|
+
Yodel.Records = {
|
71
|
+
update: function(path, fields) {
|
72
|
+
if((path.length <= 5) || (path.substr(-5,5) != '.json'))
|
73
|
+
path = path + '.json';
|
74
|
+
jQuery.post(path, {_method: 'put', record: JSON.stringify(fields)});
|
75
|
+
}
|
76
|
+
};
|
77
|
+
|
78
|
+
jQuery('.yodel-remote-action').live('click', function(event, element) {
|
79
|
+
var action = element.attr('data-action');
|
80
|
+
if(action)
|
81
|
+
eval(action);
|
82
|
+
});
|
83
|
+
|
84
|
+
|
85
|
+
// Remote form submission
|
86
|
+
Yodel.Forms = {
|
87
|
+
clearStatusStates: function(form) {
|
88
|
+
jQuery(form).find('span[data-handles]').each(function(index, statusData) {
|
89
|
+
var status = jQuery(statusData).children().first();
|
90
|
+
if(status) {
|
91
|
+
status.html('');
|
92
|
+
status.removeClass('new');
|
93
|
+
status.removeClass('valid');
|
94
|
+
status.removeClass('invalid');
|
95
|
+
}
|
96
|
+
});
|
97
|
+
},
|
98
|
+
|
99
|
+
setState: function(fieldName, form, state, message) {
|
100
|
+
// FIXME: assumes all fields have a status element as well
|
101
|
+
// check the form contains a field element for this message
|
102
|
+
var field = jQuery(form).find('*[data-field=' + fieldName + ']').first();
|
103
|
+
if(!field[0]) {
|
104
|
+
console.log("Form does not contain a field for: " + fieldName);
|
105
|
+
return;
|
106
|
+
}
|
107
|
+
|
108
|
+
var statusData = jQuery(form).find('span[data-handles*=' + fieldName + ']').first();
|
109
|
+
var status = statusData.children().first();
|
110
|
+
|
111
|
+
// submission of a form never transitions a field to the new state
|
112
|
+
status.removeClass('new');
|
113
|
+
|
114
|
+
if(state == 'valid') {
|
115
|
+
if(!status.hasClass('invalid')) {
|
116
|
+
status.removeClass('invalid');
|
117
|
+
status.addClass('valid');
|
118
|
+
}
|
119
|
+
field.removeClass('invalid');
|
120
|
+
field.addClass('valid');
|
121
|
+
} else {
|
122
|
+
status.addClass('invalid');
|
123
|
+
status.removeClass('valid');
|
124
|
+
field.addClass('invalid');
|
125
|
+
field.removeClass('valid');
|
126
|
+
}
|
127
|
+
|
128
|
+
// either use the supplied message, or override it with
|
129
|
+
// a static message provided in the layout
|
130
|
+
var staticMessage = statusData.attr('data-' + state + '-text');
|
131
|
+
if(staticMessage)
|
132
|
+
message = staticMessage;
|
133
|
+
else
|
134
|
+
message = message || '';
|
135
|
+
|
136
|
+
// set data-errors on the field
|
137
|
+
field.attr('data-errors', message);
|
138
|
+
|
139
|
+
// insert or replace the status element's text. Statuses may
|
140
|
+
// correspond to more than one field, hence concatenating msgs.
|
141
|
+
if(message)
|
142
|
+
if(status.html() == '')
|
143
|
+
status.html(message);
|
144
|
+
else
|
145
|
+
status.html(status.html() + ', ' + message);
|
146
|
+
},
|
147
|
+
|
148
|
+
handleFailure: function(activityElement, form, data) {
|
149
|
+
var failureFunction = Yodel.Forms.callbackFunction(form, 'failure');
|
150
|
+
Yodel.Forms.hideActivityElement(activityElement);
|
151
|
+
if(failureFunction)
|
152
|
+
failureFunction(data);
|
153
|
+
},
|
154
|
+
|
155
|
+
callbackFunction: function(form, name) {
|
156
|
+
var functionName = form.attr('data-' + name + '-function');
|
157
|
+
if(functionName) {
|
158
|
+
var functionReference = eval(functionName);
|
159
|
+
if(functionReference)
|
160
|
+
return functionReference;
|
161
|
+
}
|
162
|
+
return null;
|
163
|
+
},
|
164
|
+
|
165
|
+
hideActivityElement: function(activityElement) {
|
166
|
+
if(activityElement)
|
167
|
+
activityElement.css('visibility', 'hidden');
|
168
|
+
},
|
169
|
+
|
170
|
+
submit: function(event, element) {
|
171
|
+
var form = jQuery(element);
|
172
|
+
|
173
|
+
// show the activity indicator if present
|
174
|
+
var activityElement = form.find('.yodel-form-activity')
|
175
|
+
activityElement.css('visibility', 'visible');
|
176
|
+
|
177
|
+
// create an iframe to handle the submission if necessary. iframes
|
178
|
+
// are used instead of ajax calls so file uploads can be supported
|
179
|
+
var iframeID = 'form_' + form.attr('id') + '_iframe';
|
180
|
+
var iframe = jQuery('#' + iframeID);
|
181
|
+
if(iframe.length == 0) {
|
182
|
+
form.after('<iframe id="' + iframeID + '" name="' + iframeID + '" style="display:none"></iframe>');
|
183
|
+
form.attr('target', iframeID);
|
184
|
+
iframe = jQuery('#' + iframeID);
|
185
|
+
|
186
|
+
// FIXME: handle timeouts, failed requests
|
187
|
+
iframe.load(function() {
|
188
|
+
var iframeBody = iframe.contents().find('body');
|
189
|
+
var jsonText = iframeBody.find(':contains("{")').html();
|
190
|
+
var json = jQuery.parseJSON(jsonText);
|
191
|
+
setTimeout(function () { iframeBody.html(''); }, 1);
|
192
|
+
|
193
|
+
if(json.success) {
|
194
|
+
Yodel.Forms.hideActivityElement(activityElement);
|
195
|
+
var successFunction = Yodel.Forms.callbackFunction(form, 'success');
|
196
|
+
var record = json.record;
|
197
|
+
|
198
|
+
if(successFunction)
|
199
|
+
successFunction(record);
|
200
|
+
|
201
|
+
} else {
|
202
|
+
Yodel.Forms.hideActivityElement(activityElement);
|
203
|
+
var errorsFunction = Yodel.Forms.callbackFunction(form, 'errors');
|
204
|
+
var errors = json.errors;
|
205
|
+
|
206
|
+
if(errorsFunction) {
|
207
|
+
errorsFunction(errors);
|
208
|
+
} else {
|
209
|
+
Yodel.Forms.clearStatusStates(form);
|
210
|
+
form.find('*[data-field]').each(function(index, element) {
|
211
|
+
var fieldName = jQuery(element).attr('data-field');
|
212
|
+
if(json.errors[fieldName])
|
213
|
+
Yodel.Forms.setState(fieldName, form, 'invalid', json.errors[fieldName]);
|
214
|
+
else
|
215
|
+
Yodel.Forms.setState(fieldName, form, 'valid');
|
216
|
+
});
|
217
|
+
}
|
218
|
+
}
|
219
|
+
});
|
220
|
+
}
|
221
|
+
}
|
222
|
+
}
|
223
|
+
|
224
|
+
if(jQuery.browser.msie) {
|
225
|
+
jQuery('form').live('focusin', function(focusEvent) {
|
226
|
+
var form = focusEvent.target;
|
227
|
+
if(jQuery(form).attr('data-remote') == 'true' && !form.builtSubmitEvent) {
|
228
|
+
jQuery(form).submit(function(submitEvent) {
|
229
|
+
Yodel.Forms.submit(submitEvent, submitEvent.target);
|
230
|
+
});
|
231
|
+
form.builtSubmitEvent = true;
|
232
|
+
}
|
233
|
+
});
|
234
|
+
} else {
|
235
|
+
jQuery('form[data-remote=true]').live('submit', function(event) {
|
236
|
+
Yodel.Forms.submit(event, event.target);
|
237
|
+
});
|
238
|
+
}
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# some of the basic auth code taken from an inspired by rack/auth/basic
|
2
|
+
module Authentication
|
3
|
+
AUTHORIZATION_KEYS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION']
|
4
|
+
|
5
|
+
def logged_in?(auth_type=nil)
|
6
|
+
!current_user(auth_type).nil?
|
7
|
+
end
|
8
|
+
|
9
|
+
def current_user(auth_type=nil)
|
10
|
+
unless defined?(@current_user)
|
11
|
+
@current_user = nil
|
12
|
+
auth_type ||= mime_type.auth_type
|
13
|
+
|
14
|
+
if auth_type == :page || session['current_user_id']
|
15
|
+
@current_user = site.users.find(session['current_user_id'])
|
16
|
+
session.delete('current_user_id') if @current_user.nil?
|
17
|
+
|
18
|
+
elsif auth_type == :basic
|
19
|
+
unless authorization_key.nil? || !basic?
|
20
|
+
user = site.users.first(username: credentials.first)
|
21
|
+
@current_user = user if user.try(:passwords_match?, credentials.last)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
@current_user
|
26
|
+
end
|
27
|
+
|
28
|
+
def prompt_login(auth_type=nil)
|
29
|
+
auth_type ||= mime_type.auth_type
|
30
|
+
case auth_type
|
31
|
+
when :page
|
32
|
+
session[:redirect_to_after_login] = self.path
|
33
|
+
response.redirect site.login_pages.first.path
|
34
|
+
when :basic
|
35
|
+
response['Content-Type'] = 'text/plain'
|
36
|
+
response['WWW-Authenticate'] = "Basic realm=\"#{title}\""
|
37
|
+
response.status = 401
|
38
|
+
response.body = []
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def login(credentials)
|
43
|
+
password = credentials.delete('password')
|
44
|
+
user = site.users.first(credentials)
|
45
|
+
if user && user.passwords_match?(password)
|
46
|
+
store_authenticated_user(user)
|
47
|
+
end
|
48
|
+
!@current_user.nil?
|
49
|
+
end
|
50
|
+
|
51
|
+
def logout
|
52
|
+
session.delete('current_user_id')
|
53
|
+
end
|
54
|
+
|
55
|
+
def store_authenticated_user(user)
|
56
|
+
session['current_user_id'] = user.id
|
57
|
+
@current_user = user
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
def authorization_key
|
62
|
+
@authorization_key ||= AUTHORIZATION_KEYS.find {|key| env.has_key?(key)}
|
63
|
+
end
|
64
|
+
|
65
|
+
def basic?
|
66
|
+
parts.first.downcase == 'basic'
|
67
|
+
end
|
68
|
+
|
69
|
+
def credentials
|
70
|
+
@credentials ||= parts.last.unpack("m*").first.split(/:/, 2)
|
71
|
+
end
|
72
|
+
|
73
|
+
def parts
|
74
|
+
@parts ||= env[authorization_key].split(' ', 2)
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Flash
|
2
|
+
def initialize(session)
|
3
|
+
@session = session
|
4
|
+
@last_request = @session['flash'] || {}
|
5
|
+
@this_request = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def finalize
|
9
|
+
@session['flash'] = @this_request
|
10
|
+
end
|
11
|
+
|
12
|
+
def [](key)
|
13
|
+
@this_request[key] || @last_request[key]
|
14
|
+
end
|
15
|
+
|
16
|
+
def now(key, value)
|
17
|
+
@last_request[key] = value
|
18
|
+
end
|
19
|
+
|
20
|
+
def []=(key, value)
|
21
|
+
@this_request[key] = value
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete(key)
|
25
|
+
@this_request.delete(key)
|
26
|
+
@last_request.delete(key)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'bigdecimal'
|
4
|
+
require 'date'
|
5
|
+
require 'ostruct'
|
6
|
+
require 'net/http'
|
7
|
+
require 'open-uri'
|
8
|
+
require 'fileutils'
|
9
|
+
require 'uri'
|
10
|
+
|
11
|
+
# load bundled gems
|
12
|
+
require 'rubygems'
|
13
|
+
require 'bundler'
|
14
|
+
require 'rack'
|
15
|
+
require 'plucky' # requires mongo
|
16
|
+
require 'ember'
|
17
|
+
require 'mail'
|
18
|
+
require 'hpricot'
|
19
|
+
require 'json'
|
20
|
+
require 'rack/contrib'
|
21
|
+
require 'rubydns'
|
22
|
+
require 'git'
|
23
|
+
require 'highline'
|
24
|
+
require 'mini_magick'
|
25
|
+
require 'linguistics'
|
26
|
+
|
27
|
+
# manually load active support extensions
|
28
|
+
require 'active_support/core_ext/object/blank'
|
29
|
+
require 'active_support/core_ext/object/try'
|
30
|
+
require 'active_support/inflector'
|
31
|
+
require 'active_support/core_ext/hash/keys'
|
32
|
+
require 'active_support/core_ext/array/conversions'
|
33
|
+
require 'active_support/core_ext/time/calculations'
|
34
|
+
|
35
|
+
# for consistency, default to syck for YAML dumps/loads
|
36
|
+
# psych and syck have incompatible nil representations
|
37
|
+
YAML::ENGINE.yamler = 'syck'
|
38
|
+
|
39
|
+
# config and environment are loaded separately
|
40
|
+
# from yodel, so a configuration can be created
|
41
|
+
# before loading the server or console
|
42
|
+
require File.join(File.dirname(__FILE__), 'config', 'config')
|
43
|
+
if $settings
|
44
|
+
require $settings
|
45
|
+
else
|
46
|
+
require '/usr/local/etc/yodel/settings.rb'
|
47
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module QueueDaemon
|
2
|
+
IMMEDIATE_WORKERS = 1
|
3
|
+
DELAYED_WORKERS = 1
|
4
|
+
|
5
|
+
def self.run
|
6
|
+
immediate_queue = TaskQueue.new(true)
|
7
|
+
delayed_queue = TaskQueue.new(false)
|
8
|
+
|
9
|
+
immediate_workers = []
|
10
|
+
delayed_workers = []
|
11
|
+
|
12
|
+
puts "Starting Workers..."
|
13
|
+
stats_thread = StatsThread.new
|
14
|
+
IMMEDIATE_WORKERS.times do
|
15
|
+
immediate_workers << QueueWorker.new(immediate_queue, stats_thread)
|
16
|
+
end
|
17
|
+
|
18
|
+
DELAYED_WORKERS.times do
|
19
|
+
delayed_workers << QueueWorker.new(delayed_queue, stats_thread)
|
20
|
+
end
|
21
|
+
|
22
|
+
Signal.trap('INT') do
|
23
|
+
puts("Shutting down...")
|
24
|
+
stats_thread.stop
|
25
|
+
immediate_workers.each(&:stop)
|
26
|
+
delayed_workers.each(&:stop)
|
27
|
+
end
|
28
|
+
|
29
|
+
immediate_workers.each {|worker| worker.join}
|
30
|
+
delayed_workers.each {|worker| worker.join}
|
31
|
+
puts "Shutdown complete"
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class QueueWorker
|
2
|
+
PAUSE_DURATION = 1
|
3
|
+
def initialize(queue, stats_thread)
|
4
|
+
@stats_thread = stats_thread
|
5
|
+
@queue = queue
|
6
|
+
run
|
7
|
+
end
|
8
|
+
|
9
|
+
def run
|
10
|
+
@running = true
|
11
|
+
@thread = Thread.new do
|
12
|
+
while @running
|
13
|
+
task = @queue.pop
|
14
|
+
sleep(PAUSE_DURATION) and next if task.nil?
|
15
|
+
task.execute
|
16
|
+
@stats_thread.processed_task
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def stop
|
22
|
+
@running = false
|
23
|
+
end
|
24
|
+
|
25
|
+
def kill
|
26
|
+
@thread.kill
|
27
|
+
end
|
28
|
+
|
29
|
+
def join
|
30
|
+
@thread.join
|
31
|
+
end
|
32
|
+
end
|