yodel_production_environment 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/lib/layouts/common.html +23 -0
- data/lib/layouts/common/site.html +79 -0
- data/lib/layouts/common/sites.html +13 -0
- data/lib/layouts/common/user.html +10 -0
- data/lib/layouts/common/users.html +30 -0
- data/lib/layouts/home.html +49 -0
- data/lib/layouts/production_login_page.html +131 -0
- data/lib/migrations/site/01_users_model.rb +23 -0
- data/lib/migrations/site/02_page_structure.rb +58 -0
- data/lib/migrations/site/03_security_and_home_page.rb +103 -0
- data/lib/migrations/yodel/01_record_model.rb +29 -0
- data/lib/migrations/yodel/02_page_model.rb +45 -0
- data/lib/migrations/yodel/03_layout_model.rb +38 -0
- data/lib/migrations/yodel/04_group_model.rb +61 -0
- data/lib/migrations/yodel/05_user_model.rb +23 -0
- data/lib/migrations/yodel/06_snippet_model.rb +13 -0
- data/lib/migrations/yodel/07_search_page_model.rb +32 -0
- data/lib/migrations/yodel/08_default_site_options.rb +21 -0
- data/lib/migrations/yodel/09_security_page_models.rb +36 -0
- data/lib/migrations/yodel/10_record_proxy_page_model.rb +17 -0
- data/lib/migrations/yodel/11_email_model.rb +28 -0
- data/lib/migrations/yodel/12_api_call_model.rb +23 -0
- data/lib/migrations/yodel/13_redirect_page_model.rb +13 -0
- data/lib/migrations/yodel/14_menu_model.rb +20 -0
- data/lib/models/git_http.rb +326 -0
- data/lib/models/git_page.rb +38 -0
- data/lib/models/production_login_page.rb +13 -0
- data/lib/models/production_sites_page.rb +127 -0
- data/lib/models/production_user.rb +17 -0
- data/lib/public/css/screen.css +64 -0
- data/lib/yodel_production_environment.rb +3 -0
- data/yodel_production_environment.gemspec +22 -0
- metadata +80 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
class SecurityAndHomePageMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
# existing pages
|
4
|
+
home = site.pages.where(path: '/').first
|
5
|
+
sites_page = site.pages.where(path: '/sites').first
|
6
|
+
|
7
|
+
# change home page to a normal page until editable production sites are ready
|
8
|
+
home.model = site.pages
|
9
|
+
home.page_layout = 'home'
|
10
|
+
home.save
|
11
|
+
|
12
|
+
# login page
|
13
|
+
site.login_pages.create_model :production_login_page do |production_login_pages|
|
14
|
+
production_login_pages.record_class_name = 'ProductionLoginPage'
|
15
|
+
end
|
16
|
+
|
17
|
+
login_page = site.production_login_pages.new
|
18
|
+
login_page.title = 'Login'
|
19
|
+
login_page.redirect_to = sites_page
|
20
|
+
login_page.parent = home
|
21
|
+
login_page.save
|
22
|
+
|
23
|
+
# remove login from the nav menu
|
24
|
+
nav = site.menus.first(name: 'nav')
|
25
|
+
login_ex = nav.exceptions.new
|
26
|
+
login_ex.page = login_page
|
27
|
+
login_ex.show = false
|
28
|
+
login_ex.save
|
29
|
+
nav.save
|
30
|
+
|
31
|
+
# logout page
|
32
|
+
logout_page = site.logout_pages.new
|
33
|
+
logout_page.title = 'Logout'
|
34
|
+
logout_page.redirect_to = home
|
35
|
+
logout_page.parent = home
|
36
|
+
logout_page.save
|
37
|
+
|
38
|
+
# prevent guest html requests; the sites and git pages implement their
|
39
|
+
# own auth for json requests
|
40
|
+
site.sites_pages.modify do |sites_pages|
|
41
|
+
sites_pages.view_group = site.groups['Administrators']
|
42
|
+
sites_pages.create_group = site.groups['Administrators']
|
43
|
+
sites_pages.update_group = site.groups['Administrators']
|
44
|
+
sites_pages.delete_group = site.groups['No One']
|
45
|
+
end
|
46
|
+
|
47
|
+
site.users.modify do |users|
|
48
|
+
users.view_group = site.groups['Administrators']
|
49
|
+
users.create_group = site.groups['Administrators']
|
50
|
+
users.update_group = site.groups['Administrators']
|
51
|
+
users.delete_group = site.groups['Administrators']
|
52
|
+
end
|
53
|
+
|
54
|
+
users_page = site.pages.where(path: '/users').first
|
55
|
+
users_page.model.modify do |users_page|
|
56
|
+
users_page.view_group = site.groups['Administrators']
|
57
|
+
users_page.create_group = site.groups['Administrators']
|
58
|
+
users_page.update_group = site.groups['Administrators']
|
59
|
+
users_page.delete_group = site.groups['No One']
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.down(site)
|
64
|
+
# remove the login nav menu exception
|
65
|
+
nav = site.menus.first(name: 'nav')
|
66
|
+
login_ex = nav.exceptions.select {|ex| ex.page.path == '/login'}
|
67
|
+
login_ex.destroy
|
68
|
+
nav.save
|
69
|
+
|
70
|
+
# login/logout pages
|
71
|
+
site.pages.where(path: '/login').destroy
|
72
|
+
site.pages.where(path: '/logout').destroy
|
73
|
+
|
74
|
+
# reset homepage to a redirect page
|
75
|
+
home = site.pages.where(path: '/').first
|
76
|
+
home.model = site.redirect_pages
|
77
|
+
home.url = '/users'
|
78
|
+
home.save
|
79
|
+
|
80
|
+
# remove auth
|
81
|
+
site.sites_pages.modify do |sites_pages|
|
82
|
+
sites_pages.view_group = site.groups['Guests']
|
83
|
+
sites_pages.create_group = site.groups['Guests']
|
84
|
+
sites_pages.update_group = site.groups['Guests']
|
85
|
+
sites_pages.delete_group = site.groups['Guests']
|
86
|
+
end
|
87
|
+
|
88
|
+
site.users.modify do |users|
|
89
|
+
sites_pages.view_group = site.groups['Guests']
|
90
|
+
sites_pages.create_group = site.groups['Guests']
|
91
|
+
sites_pages.update_group = site.groups['Guests']
|
92
|
+
sites_pages.delete_group = site.groups['Guests']
|
93
|
+
end
|
94
|
+
|
95
|
+
users_page = site.pages.where(path: '/users').first
|
96
|
+
users_page.model.modify do |users_page|
|
97
|
+
sites_pages.view_group = site.groups['Guests']
|
98
|
+
sites_pages.create_group = site.groups['Guests']
|
99
|
+
sites_pages.update_group = site.groups['Guests']
|
100
|
+
sites_pages.delete_group = site.groups['Guests']
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class RecordModelMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
records = Model.new(site, name: 'Record')
|
4
|
+
records.modify do |records|
|
5
|
+
# identity, hierarchy and search
|
6
|
+
add_many :children, model: :record, foreign_key: 'parent', order: 'index asc', display: false
|
7
|
+
add_field :index, :integer, validations: {required: {}}, display: false
|
8
|
+
add_one :owner, model: :user, display: false
|
9
|
+
add_field :name, :string
|
10
|
+
add_field :show_in_search, :boolean, default: true, section: 'Options'
|
11
|
+
add_field :search_keywords, :array, of: :string, display: false
|
12
|
+
add_field :search_title, :string, display: false
|
13
|
+
|
14
|
+
# modelling
|
15
|
+
add_one :eigenmodel, model: :model, destroy: true, display: false
|
16
|
+
add_one :parent, model: :record, index: true, display: false
|
17
|
+
add_one :model, index: true, display: false
|
18
|
+
records.descendants = [records]
|
19
|
+
end
|
20
|
+
|
21
|
+
site.model_types['records'] = records.id
|
22
|
+
site.model_plural_names['Record'] = 'records'
|
23
|
+
site.save
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.down(site)
|
27
|
+
site.records.destroy
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class PageModelMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
site.records.create_model :pages do |pages|
|
4
|
+
# core page attributes
|
5
|
+
add_field :permalink, :string, validations: {required: {}}, index: true, searchable: false, display: false
|
6
|
+
add_field :path, :string, validations: {required: {}}, index: true, searchable: false, display: false
|
7
|
+
add_field :created_at, :time, display: false
|
8
|
+
add_field :title, :string, validations: {required: {}}
|
9
|
+
add_field :content, :html
|
10
|
+
|
11
|
+
# options section
|
12
|
+
add_field :show_in_menus, :boolean, default: true, section: 'Options'
|
13
|
+
add_field :description, :text, section: 'Options', searchable: false
|
14
|
+
add_field :keywords, :text, section: 'Options', searchable: false
|
15
|
+
add_field :custom_meta_tags, :text, section: 'Options', searchable: false
|
16
|
+
add_one :new_child_page, model: :page, section: 'Options', show_blank: true, blank_text: 'None'
|
17
|
+
|
18
|
+
# layout
|
19
|
+
add_field :page_layout, :string, section: 'Options', default: nil, searchable: false
|
20
|
+
add_one :page_layout_record, model: :layout, display: false
|
21
|
+
add_field :edit_layout, :string, searchable: false, section: 'Options'
|
22
|
+
add_one :edit_layout_record, model: :layout, display: false
|
23
|
+
|
24
|
+
add_field :name, :alias, of: :title
|
25
|
+
pages.default_child_model = pages.id
|
26
|
+
pages.allowed_children = [pages]
|
27
|
+
pages.allowed_parents = [pages]
|
28
|
+
pages.record_class_name = 'Page'
|
29
|
+
end
|
30
|
+
|
31
|
+
# glob pages are normal pages, but match paths with components at the end
|
32
|
+
# of the page's path, e.g /git/HEAD would match the glob page /git
|
33
|
+
site.pages.create_model :glob_pages do |glob_pages|
|
34
|
+
end
|
35
|
+
|
36
|
+
# default root page
|
37
|
+
page = site.pages.new
|
38
|
+
page.title = "Home"
|
39
|
+
page.save
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.down(site)
|
43
|
+
site.pages.destroy
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class LayoutModelMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
site.records.create_model :layouts do |layouts|
|
4
|
+
add_field :name, :string, validations: {required: {}}, index: true
|
5
|
+
add_field :mime_type, :string, validations: {required: {}}, index: true
|
6
|
+
|
7
|
+
layouts.allowed_children = []
|
8
|
+
layouts.allowed_parents = []
|
9
|
+
layouts.searchable = false
|
10
|
+
layouts.record_class_name = 'Layout'
|
11
|
+
end
|
12
|
+
|
13
|
+
site.layouts.create_model :persistent_layouts do |persistent_layouts|
|
14
|
+
add_field :markup, :html, validations: {required: {}}
|
15
|
+
add_many :pages, foreign_key: 'page_layout_record'
|
16
|
+
|
17
|
+
persistent_layouts.allowed_children = [persistent_layouts]
|
18
|
+
persistent_layouts.allowed_parents = [persistent_layouts]
|
19
|
+
persistent_layouts.searchable = false
|
20
|
+
persistent_layouts.record_class_name = 'PersistentLayout'
|
21
|
+
end
|
22
|
+
|
23
|
+
site.layouts.create_model :file_layouts do |file_layouts|
|
24
|
+
add_field :path, :string, validations: {required: {}}
|
25
|
+
|
26
|
+
file_layouts.allowed_children = [file_layouts]
|
27
|
+
file_layouts.allowed_parents = [file_layouts]
|
28
|
+
file_layouts.searchable = false
|
29
|
+
file_layouts.record_class_name = 'FileLayout'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.down(site)
|
34
|
+
site.layouts.destroy
|
35
|
+
site.persistent_layouts.destroy
|
36
|
+
site.file_layouts.destroy
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class GroupModelMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
site.records.create_model :groups do |groups|
|
4
|
+
add_field :name, :string, validations: {required: {}}
|
5
|
+
add_many :users, store: false
|
6
|
+
groups.icon = '/admin/images/group_icon.png'
|
7
|
+
groups.record_class_name = 'Group'
|
8
|
+
end
|
9
|
+
site.reload
|
10
|
+
|
11
|
+
# a special singleton group representing an 'owner' of a record
|
12
|
+
site.groups.create_model :owner_groups do |group|
|
13
|
+
group.record_class_name = 'OwnerGroup'
|
14
|
+
end
|
15
|
+
site.reload
|
16
|
+
|
17
|
+
# a special singleton group representing no one
|
18
|
+
site.groups.create_model :noone_groups do |group|
|
19
|
+
group.record_class_name = 'NooneGroup'
|
20
|
+
end
|
21
|
+
site.reload
|
22
|
+
|
23
|
+
# a special singleton group representing 'everyone'
|
24
|
+
site.groups.create_model :guest_groups do |group|
|
25
|
+
group.record_class_name = 'GuestsGroup'
|
26
|
+
end
|
27
|
+
site.reload
|
28
|
+
|
29
|
+
|
30
|
+
# permissions are based on a hierarchy of groups. branches are permitted.
|
31
|
+
noone = site.noone_groups.new(name: 'No One')
|
32
|
+
noone.save
|
33
|
+
|
34
|
+
devs = site.groups.new(name: 'Developers')
|
35
|
+
devs.parent = noone
|
36
|
+
devs.save
|
37
|
+
|
38
|
+
admins = site.groups.new(name: 'Administrators')
|
39
|
+
admins.parent = devs
|
40
|
+
admins.save
|
41
|
+
|
42
|
+
owner = site.owner_groups.new(name: 'Owner')
|
43
|
+
owner.parent = admins
|
44
|
+
owner.save
|
45
|
+
|
46
|
+
users = site.groups.new(name: 'Users')
|
47
|
+
users.parent = owner
|
48
|
+
users.save
|
49
|
+
|
50
|
+
guests = site.guest_groups.new(name: 'Guests')
|
51
|
+
guests.parent = users
|
52
|
+
guests.save
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.down(site)
|
56
|
+
site.groups.destroy
|
57
|
+
site.owner_groups.destroy
|
58
|
+
site.noone_groups.destroy
|
59
|
+
site.guest_groups.destroy
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class UserModelMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
site.records.create_model :users do |users|
|
4
|
+
add_field :first_name, :string
|
5
|
+
add_field :last_name, :string
|
6
|
+
add_field :email, :email, validations: {required: {}, unique: {}}, searchable: false
|
7
|
+
add_field :oauth_id, :string, index: true, searchable: false
|
8
|
+
add_field :username, :string, index: true, validations: {required: {}, unique: {}}, searchable: false
|
9
|
+
add_field :password, :password, validations: {required: {}}, searchable: false
|
10
|
+
add_field :password_salt, :string, display: false, searchable: false
|
11
|
+
add_many :groups, default: [site.groups['Users'].id]
|
12
|
+
add_field :owner, :self
|
13
|
+
|
14
|
+
add_field :name, :function, fn: 'format("{{first_name}} {{last_name}}").strip()'
|
15
|
+
users.icon = '/admin/images/user_icon.png'
|
16
|
+
users.record_class_name = 'User'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.down(site)
|
21
|
+
site.users.destroy
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class SnippetModelMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
site.records.create_model :snippets do |snippets|
|
4
|
+
add_field :name, :string, validations: {required: {}}, index: true
|
5
|
+
add_field :content, :text
|
6
|
+
snippets.searchable = false
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.down(site)
|
11
|
+
site.snippets.destroy
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class SearchPageModelMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
operators = [ 'Equals', 'Not Equal', 'Greater Than',
|
4
|
+
'Less Than', 'Greater Than or Equal To',
|
5
|
+
'Less Than or Equal To', 'In']
|
6
|
+
|
7
|
+
site.pages.create_model :search_pages do |search_pages|
|
8
|
+
add_field :sort, :string, searchable: false
|
9
|
+
add_field :limit, :integer
|
10
|
+
add_field :skip, :integer
|
11
|
+
add_one :type, model: :model
|
12
|
+
|
13
|
+
add_embed_many :conditions do
|
14
|
+
add_field :name, :string
|
15
|
+
add_field :value, :string
|
16
|
+
add_field :operator, :enum, options: operators
|
17
|
+
end
|
18
|
+
|
19
|
+
add_embed_many :user_conditions, default: [{name: 'search_keywords', as: 'query', operator: 'In'}] do
|
20
|
+
add_field :name, :string
|
21
|
+
add_field :as, :string
|
22
|
+
add_field :operator, :enum, options: operators
|
23
|
+
end
|
24
|
+
|
25
|
+
search_pages.record_class_name = 'SearchPage'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.down(site)
|
30
|
+
site.search_pages.destroy
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class DefaultSiteOptionsMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
site.options = {
|
4
|
+
pages: {
|
5
|
+
permalink_character: {
|
6
|
+
description: 'When Yodel creates a URL for a page by using the title of the page, there are sometimes characters (such as spaces) that need to be replaced. This character will be used in their place. e.g "About Us" would become "about-us".',
|
7
|
+
type: 'String',
|
8
|
+
default: '-',
|
9
|
+
value: '-'
|
10
|
+
}
|
11
|
+
},
|
12
|
+
icon: nil
|
13
|
+
}
|
14
|
+
site.save
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.down(site)
|
18
|
+
site.options = {}
|
19
|
+
site.save
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class SecurityPageModelsMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
site.pages.create_model :login_pages do |login_pages|
|
4
|
+
add_field :username_field, :string, validations: {required: {}}, default: 'username'
|
5
|
+
add_field :password_field, :string, validations: {required: {}}, default: 'password'
|
6
|
+
add_one :redirect_to, model: :page
|
7
|
+
login_pages.record_class_name = 'LoginPage'
|
8
|
+
end
|
9
|
+
|
10
|
+
site.pages.create_model :logout_pages do |logout_pages|
|
11
|
+
add_one :redirect_to, model: :page
|
12
|
+
logout_pages.record_class_name = 'LogoutPage'
|
13
|
+
end
|
14
|
+
|
15
|
+
site.pages.create_model :password_reset_pages do |password_reset_pages|
|
16
|
+
add_field :success, :html, default: 'Thank you, your password has been emailed to your email address.'
|
17
|
+
add_field :email_field, :string, validations: {required: {}}, default: 'email'
|
18
|
+
password_reset_pages.record_class_name = 'PasswordResetPage'
|
19
|
+
end
|
20
|
+
|
21
|
+
site.pages.create_model :facebook_login_pages do |facebook_login_pages|
|
22
|
+
add_field :callback_uri, :string
|
23
|
+
add_field :app_id, :string
|
24
|
+
add_field :app_secret, :string
|
25
|
+
add_one :join_page, model: :page
|
26
|
+
add_one :after_login_page, model: :page
|
27
|
+
facebook_login_pages.record_class_name = 'FacebookLoginPage'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.down(site)
|
32
|
+
site.login_pages.destroy
|
33
|
+
site.logout_pages.destroy
|
34
|
+
site.password_reset_pages.destroy
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class RecordProxyPageModelMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
site.pages.create_model :record_proxy_pages do |record_proxy_pages|
|
4
|
+
add_one :record_model, model: :model
|
5
|
+
add_one :after_create_page, model: :page
|
6
|
+
add_one :after_delete_page, model: :page
|
7
|
+
add_one :after_update_page, model: :page
|
8
|
+
add_field :show_record_layout, :string
|
9
|
+
add_one :show_record_layout_record, model: :layout, display: false
|
10
|
+
record_proxy_pages.record_class_name = 'RecordProxyPage'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.down(site)
|
15
|
+
site.record_proxy_pages.destroy
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class EmailModelMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
site.records.create_model :emails do |emails|
|
4
|
+
add_field :name, :string
|
5
|
+
add_field :from, :string
|
6
|
+
add_field :to, :string
|
7
|
+
add_field :cc, :string
|
8
|
+
add_field :bcc, :string
|
9
|
+
add_field :subject, :string
|
10
|
+
add_field :text_body, :text
|
11
|
+
add_field :html_body, :html
|
12
|
+
add_field :html_layout, :string
|
13
|
+
emails.record_class_name = 'Email'
|
14
|
+
end
|
15
|
+
|
16
|
+
# template password reset email
|
17
|
+
password_reset_email = site.emails.new
|
18
|
+
password_reset_email.name = 'password_reset'
|
19
|
+
password_reset_email.from = 'admin@site.com'
|
20
|
+
password_reset_email.subject = 'Password Reset'
|
21
|
+
password_reset_email.text_body = 'Hi <%= options["first_name"] %>, your password has been reset and is now: <%= options["new_password"] %>.'
|
22
|
+
password_reset_email.save
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.down(site)
|
26
|
+
site.emails.destroy
|
27
|
+
end
|
28
|
+
end
|