chef-server-api 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/LICENSE +201 -0
  2. data/README.rdoc +92 -0
  3. data/Rakefile +59 -0
  4. data/app/controllers/application.rb +289 -0
  5. data/app/controllers/clients.rb +111 -0
  6. data/app/controllers/cookbooks.rb +213 -0
  7. data/app/controllers/data.rb +75 -0
  8. data/app/controllers/data_item.rb +108 -0
  9. data/app/controllers/exceptions.rb +40 -0
  10. data/app/controllers/main.rb +18 -0
  11. data/app/controllers/nodes.rb +102 -0
  12. data/app/controllers/roles.rb +73 -0
  13. data/app/controllers/search.rb +60 -0
  14. data/app/controllers/users.rb +77 -0
  15. data/app/helpers/application_helper.rb +163 -0
  16. data/app/helpers/exceptions_helper.rb +6 -0
  17. data/app/helpers/global_helpers.rb +25 -0
  18. data/app/helpers/nodes_helper.rb +26 -0
  19. data/app/helpers/roles_helper.rb +5 -0
  20. data/app/helpers/tarball_helper.rb +82 -0
  21. data/app/views/exceptions/bad_request.json.erb +1 -0
  22. data/app/views/exceptions/internal_server_error.html.erb +216 -0
  23. data/app/views/exceptions/not_acceptable.html.haml +5 -0
  24. data/app/views/exceptions/not_found.html.erb +47 -0
  25. data/app/views/exceptions/standard_error.html.erb +217 -0
  26. data/app/views/layout/chef_server_api.html.haml +23 -0
  27. data/app/views/main/index.html.haml +5 -0
  28. data/config/init.rb +45 -0
  29. data/config/router.rb +6 -0
  30. data/lib/chef-server-api.rb +158 -0
  31. data/lib/chef-server-api/merbtasks.rb +103 -0
  32. data/lib/chef-server-api/slicetasks.rb +20 -0
  33. data/lib/chef-server-api/spectasks.rb +53 -0
  34. data/public/images/avatar.png +0 -0
  35. data/public/images/indicator.gif +0 -0
  36. data/public/images/merb.jpg +0 -0
  37. data/public/stylesheets/base.css +336 -0
  38. data/public/stylesheets/chef.css +157 -0
  39. data/public/stylesheets/themes/bec-green/style.css +290 -0
  40. data/public/stylesheets/themes/bec/style.css +301 -0
  41. data/public/stylesheets/themes/blue/style.css +280 -0
  42. data/public/stylesheets/themes/default/style.css +267 -0
  43. data/public/stylesheets/themes/djime-cerulean/style.css +298 -0
  44. data/public/stylesheets/themes/kathleene/style.css +272 -0
  45. data/public/stylesheets/themes/orange/style.css +263 -0
  46. data/public/stylesheets/themes/reidb-greenish/style.css +301 -0
  47. data/stubs/app/controllers/application.rb +2 -0
  48. data/stubs/app/controllers/main.rb +2 -0
  49. metadata +193 -0
@@ -0,0 +1,23 @@
1
+ !!! XML
2
+ !!!
3
+ %html
4
+ %head
5
+ %meta{ "http-equiv" => "content-type", :content => "text/html; charset=utf-8" }
6
+ %title Chef Server
7
+ = css_include_tag "base", "themes/djime-cerulean/style", "chef"
8
+ %body
9
+ #container
10
+ #header
11
+ %h1= link_to "Chef REST API", absolute_slice_url(:top)
12
+ #main-navigation
13
+ .clear
14
+ #wrapper
15
+ #main
16
+ = catch_content :for_layout
17
+ #footer
18
+ .block
19
+ %p Copyright © 2009 Opscode, Inc.
20
+ #sidebar
21
+ .block.notice#sidebar_block_notice= catch_content :sidebar_block_notice
22
+ .block#sidebar_block= catch_content :sidebar_block
23
+ .clear
@@ -0,0 +1,5 @@
1
+ .block#block-text
2
+ .content
3
+ %h2.title The REST API
4
+ .inner
5
+ This is the top of the Chef Server REST API. It's not really explorable via a web browser.
data/config/init.rb ADDED
@@ -0,0 +1,45 @@
1
+ #
2
+ # ==== Standalone Chefserver configuration
3
+ #
4
+ # This configuration/environment file is only loaded by bin/slice, which can be
5
+ # used during development of the slice. It has no effect on this slice being
6
+ # loaded in a host application. To run your slice in standalone mode, just
7
+ # run 'slice' from its directory. The 'slice' command is very similar to
8
+ # the 'merb' command, and takes all the same options, including -i to drop
9
+ # into an irb session for example.
10
+ #
11
+ # The usual Merb configuration directives and init.rb setup methods apply,
12
+ # including use_orm and before_app_loads/after_app_loads.
13
+ #
14
+ # If you need need different configurations for different environments you can
15
+ # even create the specific environment file in config/environments/ just like
16
+ # in a regular Merb application.
17
+ #
18
+ # In fact, a slice is no different from a normal # Merb application - it only
19
+ # differs by the fact that seamlessly integrates into a so called 'host'
20
+ # application, which in turn can override or finetune the slice implementation
21
+ # code and views.
22
+ #
23
+
24
+ $: << File.join(File.dirname(__FILE__), "..", "..", "chef", "lib")
25
+ require 'chef'
26
+
27
+ merb_gems_version = " > 1.0"
28
+ dependency "merb-assets", merb_gems_version
29
+ dependency "merb-helpers", merb_gems_version
30
+ dependency "chef", :immediate=>true unless defined?(Chef)
31
+
32
+ require 'rubygems'
33
+
34
+ Merb::Config.use do |c|
35
+ c[:session_id_key] = '_chef_server_session_id'
36
+ c[:session_secret_key] = Chef::Config.manage_secret_key
37
+ c[:session_store] = 'cookie'
38
+ c[:exception_details] = true
39
+ c[:reload_classes] = true
40
+ c[:log_level] = Chef::Config[:log_level]
41
+ if Chef::Config[:log_location].kind_of?(String)
42
+ c[:log_file] = Chef::Config[:log_location]
43
+ end
44
+ end
45
+
data/config/router.rb ADDED
@@ -0,0 +1,6 @@
1
+ # This file is here so slice can be testing as a stand alone application.
2
+
3
+ #Merb::Router.prepare do
4
+ # resources :roles
5
+ # ...
6
+ #end
@@ -0,0 +1,158 @@
1
+ if defined?(Merb::Plugins)
2
+ $:.unshift File.dirname(__FILE__)
3
+ $:.unshift File.join(File.dirname(__FILE__), "..", "..", "chef-solr", "lib")
4
+ $:.unshift File.join(File.dirname(__FILE__), "..", "..", "chef", "lib")
5
+
6
+ dependency 'merb-slices', :immediate => true
7
+ dependency 'chef', :immediate=>true unless defined?(Chef)
8
+ dependency 'bunny', :immediate=>true
9
+ dependency 'uuidtools', :immediate=>true
10
+
11
+ require 'chef/role'
12
+ require 'chef/data_bag'
13
+ require 'chef/data_bag_item'
14
+ require 'chef/api_client'
15
+ require 'chef/webui_user'
16
+ require 'chef/certificate'
17
+
18
+ require 'mixlib/authentication'
19
+
20
+ require 'chef/data_bag'
21
+ require 'chef/data_bag_item'
22
+ require 'ohai'
23
+ require 'openssl'
24
+
25
+ Merb::Plugins.add_rakefiles "chef-server-api/merbtasks", "chef-server-api/slicetasks", "chef-server-api/spectasks"
26
+
27
+ # Register the Slice for the current host application
28
+ Merb::Slices::register(__FILE__)
29
+
30
+ Merb.disable :json
31
+
32
+ # Slice configuration - set this in a before_app_loads callback.
33
+ # By default a Slice uses its own layout, so you can switch to
34
+ # the main application layout or no layout at all if needed.
35
+ #
36
+ # Configuration options:
37
+ # :layout - the layout to use; defaults to :chefserverslice
38
+ # :mirror - which path component types to use on copy operations; defaults to all
39
+ Merb::Slices::config[:chef_server_api][:layout] ||= :chef_server_api
40
+
41
+ # All Slice code is expected to be namespaced inside a module
42
+ module ChefServerApi
43
+ # Slice metadata
44
+ self.description = "ChefServerApi.. serving up some piping hot infrastructure!"
45
+ self.version = Chef::VERSION
46
+ self.author = "Opscode"
47
+
48
+ # Stub classes loaded hook - runs before LoadClasses BootLoader
49
+ # right after a slice's classes have been loaded internally.
50
+ def self.loaded
51
+ Chef::Log.info("Compiling routes... (totally normal to see 'Cannot find resource model')")
52
+ end
53
+
54
+ # Initialization hook - runs before AfterAppLoads BootLoader
55
+ def self.init
56
+ end
57
+
58
+ # Activation hook - runs after AfterAppLoads BootLoader
59
+ def self.activate
60
+ Mixlib::Authentication::Log.logger = Ohai::Log.logger = Chef::Log.logger
61
+
62
+ unless Merb::Config.environment == "test"
63
+ # create the couch design docs for nodes, roles, and databags
64
+ Chef::CouchDB.new.create_id_map
65
+ Chef::Node.create_design_document
66
+ Chef::Role.create_design_document
67
+ Chef::DataBag.create_design_document
68
+ Chef::ApiClient.create_design_document
69
+ Chef::WebUIUser.create_design_document
70
+
71
+ Chef::Log.info('Loading roles')
72
+ Chef::Role.sync_from_disk_to_couchdb
73
+
74
+ # Create the signing key and certificate
75
+ Chef::Certificate.generate_signing_ca
76
+
77
+ # Generate the validation key
78
+ Chef::Certificate.gen_validation_key
79
+
80
+ # Generate the Web UI Key
81
+ Chef::Certificate.gen_validation_key(Chef::Config[:web_ui_client_name], Chef::Config[:web_ui_key])
82
+ end
83
+ end
84
+
85
+ # Deactivation hook - triggered by Merb::Slices.deactivate(Chefserver)
86
+ def self.deactivate
87
+ end
88
+
89
+ # Setup routes inside the host application
90
+ #
91
+ # @param scope<Merb::Router::Behaviour>
92
+ # Routes will be added within this scope (namespace). In fact, any
93
+ # router behaviour is a valid namespace, so you can attach
94
+ # routes at any level of your router setup.
95
+ #
96
+ # @note prefix your named routes with :chefserverslice_
97
+ # to avoid potential conflicts with global named routes.
98
+ def self.setup_router(scope)
99
+ # Users
100
+ scope.resources :users
101
+
102
+ # Nodes
103
+ scope.resources :nodes, :id => /[^\/]+/
104
+ scope.match('/nodes/:id/cookbooks',
105
+ :id => /[^\/]+/,
106
+ :method => 'get').
107
+ to(:controller => "nodes", :action => "cookbooks")
108
+ # Roles
109
+ scope.resources :roles
110
+
111
+ # Status
112
+ scope.match("/status").to(:controller => "status", :action => "index").name(:status)
113
+
114
+ # Clients
115
+ scope.match("/clients", :method=>"post").to(:controller=>'clients', :action=>'create')
116
+ scope.match("/clients", :method=>"get").to(:controller=>'clients', :action=>'index').name(:clients)
117
+ scope.match("/clients/:id", :id => /[\w\.-]+/, :method=>"get").to(:controller=>'clients', :action=>'show').name(:client)
118
+ scope.match("/clients/:id", :id => /[\w\.-]+/, :method=>"put").to(:controller=>'clients', :action=>'update')
119
+ scope.match("/clients/:id", :id => /[\w\.-]+/, :method=>"delete").to(:controller=>'clients', :action=>'destroy')
120
+
121
+ # Search
122
+ scope.resources :search
123
+ scope.match('/search/reindex', :method => 'post').to(:controller => "search", :action => "reindex")
124
+
125
+ # Cookbooks
126
+ scope.match('/nodes/:id/cookbooks', :method => 'get').to(:controller => "nodes", :action => "cookbooks")
127
+
128
+ scope.resources :cookbooks
129
+ scope.match("/cookbooks/:cookbook_id/_content", :method => 'get', :cookbook_id => /[\w\.]+/).to(:controller => "cookbooks", :action => "get_tarball")
130
+ scope.match("/cookbooks/:cookbook_id/_content", :method => 'put', :cookbook_id => /[\w\.]+/).to(:controller => "cookbooks", :action => "update")
131
+ scope.match("/cookbooks/:cookbook_id/:segment", :cookbook_id => /[\w\.]+/).to(:controller => "cookbooks", :action => "show_segment").name(:cookbook_segment)
132
+
133
+ # Data
134
+ scope.match("/data/:data_bag_id/:id", :method => 'get').to(:controller => "data_item", :action => "show").name("data_bag_item")
135
+ scope.match("/data/:data_bag_id", :method => 'post').to(:controller => "data_item", :action => "create").name("create_data_bag_item")
136
+ scope.match("/data/:data_bag_id/:id", :method => 'put').to(:controller => "data_item", :action => "update").name("update_data_bag_item")
137
+ scope.match("/data/:data_bag_id/:id", :method => 'delete').to(:controller => "data_item", :action => "destroy").name("destroy_data_bag_item")
138
+ scope.resources :data
139
+
140
+ scope.match('/').to(:controller => 'main', :action =>'index').name(:top)
141
+ end
142
+ end
143
+
144
+
145
+ # Setup the slice layout for ChefServerApi
146
+ #
147
+ # Use ChefServerApi.push_path and ChefServerApi.push_app_path
148
+ # to set paths to chefserver-level and app-level paths. Example:
149
+ #
150
+ # ChefServerApi.push_path(:application, ChefServerApi.root)
151
+ # ChefServerApi.push_app_path(:application, Merb.root / 'slices' / 'chefserverslice')
152
+ # ...
153
+ #
154
+ # Any component path that hasn't been set will default to ChefServerApi.root
155
+ #
156
+ # Or just call setup_default_structure! to setup a basic Merb MVC structure.
157
+ ChefServerApi.setup_default_structure!
158
+ end
@@ -0,0 +1,103 @@
1
+ namespace :slices do
2
+ namespace :chefserverslice do
3
+
4
+ desc "Install Chefserver"
5
+ task :install => [:preflight, :setup_directories, :copy_assets, :migrate]
6
+
7
+ desc "Test for any dependencies"
8
+ task :preflight do # see slicetasks.rb
9
+ end
10
+
11
+ desc "Setup directories"
12
+ task :setup_directories do
13
+ puts "Creating directories for host application"
14
+ ChefServerApi.mirrored_components.each do |type|
15
+ if File.directory?(ChefServerApi.dir_for(type))
16
+ if !File.directory?(dst_path = ChefServerApi.app_dir_for(type))
17
+ relative_path = dst_path.relative_path_from(Merb.root)
18
+ puts "- creating directory :#{type} #{File.basename(Merb.root) / relative_path}"
19
+ mkdir_p(dst_path)
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ # desc "Copy stub files to host application"
26
+ # task :stubs do
27
+ # puts "Copying stubs for ChefServerApi - resolves any collisions"
28
+ # copied, preserved = ChefServerApi.mirror_stubs!
29
+ # puts "- no files to copy" if copied.empty? && preserved.empty?
30
+ # copied.each { |f| puts "- copied #{f}" }
31
+ # preserved.each { |f| puts "! preserved override as #{f}" }
32
+ # end
33
+
34
+ # desc "Copy stub files and views to host application"
35
+ # task :patch => [ "stubs", "freeze:views" ]
36
+
37
+ desc "Copy public assets to host application"
38
+ task :copy_assets do
39
+ puts "Copying assets for ChefServerApi - resolves any collisions"
40
+ copied, preserved = ChefServerApi.mirror_public!
41
+ puts "- no files to copy" if copied.empty? && preserved.empty?
42
+ copied.each { |f| puts "- copied #{f}" }
43
+ preserved.each { |f| puts "! preserved override as #{f}" }
44
+ end
45
+
46
+ desc "Migrate the database"
47
+ task :migrate do # see slicetasks.rb
48
+ end
49
+
50
+ desc "Freeze ChefServerApi into your app (only chefserverslice/app)"
51
+ task :freeze => [ "freeze:app" ]
52
+
53
+ namespace :freeze do
54
+
55
+ # desc "Freezes ChefServerApi by installing the gem into application/gems"
56
+ # task :gem do
57
+ # ENV["GEM"] ||= "chefserverslice"
58
+ # Rake::Task['slices:install_as_gem'].invoke
59
+ # end
60
+
61
+ desc "Freezes ChefServerApi by copying all files from chefserverslice/app to your application"
62
+ task :app do
63
+ puts "Copying all chefserverslice/app files to your application - resolves any collisions"
64
+ copied, preserved = ChefServerApi.mirror_app!
65
+ puts "- no files to copy" if copied.empty? && preserved.empty?
66
+ copied.each { |f| puts "- copied #{f}" }
67
+ preserved.each { |f| puts "! preserved override as #{f}" }
68
+ end
69
+
70
+ desc "Freeze all views into your application for easy modification"
71
+ task :views do
72
+ puts "Copying all view templates to your application - resolves any collisions"
73
+ copied, preserved = ChefServerApi.mirror_files_for :view
74
+ puts "- no files to copy" if copied.empty? && preserved.empty?
75
+ copied.each { |f| puts "- copied #{f}" }
76
+ preserved.each { |f| puts "! preserved override as #{f}" }
77
+ end
78
+
79
+ desc "Freeze all models into your application for easy modification"
80
+ task :models do
81
+ puts "Copying all models to your application - resolves any collisions"
82
+ copied, preserved = ChefServerApi.mirror_files_for :model
83
+ puts "- no files to copy" if copied.empty? && preserved.empty?
84
+ copied.each { |f| puts "- copied #{f}" }
85
+ preserved.each { |f| puts "! preserved override as #{f}" }
86
+ end
87
+
88
+ desc "Freezes ChefServerApi as a gem and copies over chefserver/app"
89
+ task :app_with_gem => [:gem, :app]
90
+
91
+ desc "Freezes ChefServerApi by unpacking all files into your application"
92
+ task :unpack do
93
+ puts "Unpacking ChefServerApi files to your application - resolves any collisions"
94
+ copied, preserved = ChefServerApi.unpack_slice!
95
+ puts "- no files to copy" if copied.empty? && preserved.empty?
96
+ copied.each { |f| puts "- copied #{f}" }
97
+ preserved.each { |f| puts "! preserved override as #{f}" }
98
+ end
99
+
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,20 @@
1
+ namespace :slices do
2
+ namespace :chefserverslice do
3
+
4
+ # add your own chefserver tasks here
5
+
6
+ # # Uncomment the following lines and edit the pre defined tasks
7
+ #
8
+ # # implement this to test for structural/code dependencies
9
+ # # like certain directories or availability of other files
10
+ # desc "Test for any dependencies"
11
+ # task :preflight do
12
+ # end
13
+ #
14
+ # # implement this to perform any database related setup steps
15
+ # desc "Migrate the database"
16
+ # task :migrate do
17
+ # end
18
+
19
+ end
20
+ end
@@ -0,0 +1,53 @@
1
+ namespace :slices do
2
+ namespace :chefserverslice do
3
+
4
+ desc "Run slice specs within the host application context"
5
+ task :spec => [ "spec:explain", "spec:default" ]
6
+
7
+ namespace :spec do
8
+
9
+ slice_root = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
10
+
11
+ task :explain do
12
+ puts "\nNote: By running ChefServerApi specs inside the application context any\n" +
13
+ "overrides could break existing specs. This isn't always a problem,\n" +
14
+ "especially in the case of views. Use these spec tasks to check how\n" +
15
+ "well your application conforms to the original slice implementation."
16
+ end
17
+
18
+ Spec::Rake::SpecTask.new('default') do |t|
19
+ t.spec_opts = ["--format", "specdoc", "--colour"]
20
+ t.spec_files = Dir["#{slice_root}/spec/**/*_spec.rb"].sort
21
+ end
22
+
23
+ desc "Run all model specs, run a spec for a specific Model with MODEL=MyModel"
24
+ Spec::Rake::SpecTask.new('model') do |t|
25
+ t.spec_opts = ["--format", "specdoc", "--colour"]
26
+ if(ENV['MODEL'])
27
+ t.spec_files = Dir["#{slice_root}/spec/models/**/#{ENV['MODEL']}_spec.rb"].sort
28
+ else
29
+ t.spec_files = Dir["#{slice_root}/spec/models/**/*_spec.rb"].sort
30
+ end
31
+ end
32
+
33
+ desc "Run all request specs, run a spec for a specific request with REQUEST=MyRequest"
34
+ Spec::Rake::SpecTask.new('request') do |t|
35
+ t.spec_opts = ["--format", "specdoc", "--colour"]
36
+ if(ENV['REQUEST'])
37
+ t.spec_files = Dir["#{slice_root}/spec/requests/**/#{ENV['REQUEST']}_spec.rb"].sort
38
+ else
39
+ t.spec_files = Dir["#{slice_root}/spec/requests/**/*_spec.rb"].sort
40
+ end
41
+ end
42
+
43
+ desc "Run all specs and output the result in html"
44
+ Spec::Rake::SpecTask.new('html') do |t|
45
+ t.spec_opts = ["--format", "html"]
46
+ t.libs = ['lib', 'server/lib' ]
47
+ t.spec_files = Dir["#{slice_root}/spec/**/*_spec.rb"].sort
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+ end
Binary file
Binary file
Binary file
@@ -0,0 +1,336 @@
1
+ * {margin:0;padding:0}
2
+ .clear { clear: both; height: 0; }
3
+
4
+ h1 { margin: 15px 0; font-size: 22px; font-weight: normal; }
5
+ h2 { font-size: 22px; margin: 15px 0; font-weight: normal;}
6
+ h3 { font-size: 18px; margin: 10px 0; font-weight: normal;}
7
+ h4 { font-size: 16px; margin: 10px 0; font-weight: normal;}
8
+ hr {height: 1px; border: 0; }
9
+ p { margin: 15px 0;}
10
+ a img { border: none; }
11
+
12
+ body {
13
+ font-size: 12px;
14
+ font-family: sans-serif;
15
+ }
16
+
17
+ #container {
18
+ min-width: 960px;
19
+ }
20
+
21
+ #header, #wrapper {
22
+ padding: 0 20px;
23
+ }
24
+
25
+ #header {
26
+ position: relative;
27
+ padding-top: 1px;
28
+ }
29
+
30
+ #header h1 {
31
+ margin: 0;
32
+ padding: 10px 0;
33
+ font-size: 30px;
34
+ }
35
+
36
+ #header h1 a:link, #header h1 a:active, #header h1 a:hover, #header h1 a:visited {
37
+ text-decoration: none;
38
+ }
39
+
40
+ #main {
41
+ width: 80%;
42
+ float: left;
43
+ }
44
+
45
+ .actions-bar {
46
+ padding: 10px 1px;
47
+ }
48
+
49
+ .actions-bar .actions {
50
+ float: left;
51
+ }
52
+
53
+
54
+ .actions-bar .pagination {
55
+ float: right;
56
+ padding: 1px 0;
57
+ }
58
+
59
+ #sidebar {
60
+ width: 15%;
61
+ float: right;
62
+ }
63
+
64
+ #sidebar h3 {
65
+ padding: 10px 15px;
66
+ margin: 0;
67
+ font-size: 13px;
68
+ }
69
+
70
+ #sidebar .block {
71
+ margin-bottom: 20px;
72
+ padding-bottom: 10px;
73
+ }
74
+
75
+ #sidebar .block .content {
76
+ padding: 0 15px;
77
+ }
78
+
79
+ #sidebar ul.navigation li a:link, #sidebar ul.navigation li a:visited {
80
+ display: block;
81
+ padding: 10px 15px;
82
+ }
83
+
84
+ #sidebar .block .sidebar-block, #sidebar .notice {
85
+ padding:10px;
86
+ }
87
+
88
+ #wrapper {
89
+ padding-top: 20px;
90
+ }
91
+
92
+ #main .block {
93
+ margin-bottom: 20px;
94
+ padding-top: 1px;
95
+ }
96
+
97
+ #main .block .content .inner {
98
+ padding: 0 15px 15px;
99
+ }
100
+
101
+ #main .main p.first {
102
+ margin-top: 0;
103
+ }
104
+
105
+ #user-navigation {
106
+ position: absolute;
107
+ top: 0px;
108
+ right: 20px;
109
+ }
110
+
111
+ #main-navigation {
112
+ width: 100%;
113
+ }
114
+
115
+ #user-navigation ul, #main-navigation ul, .secondary-navigation ul, #sidebar ul.navigation {
116
+ margin: 0;
117
+ padding: 0;
118
+ list-style-type: none;
119
+ }
120
+
121
+ #user-navigation ul li, #main-navigation ul li, .secondary-navigation ul li {
122
+ float: left;
123
+ }
124
+
125
+ #main-navigation ul li {
126
+ margin-right: 5px;
127
+ }
128
+
129
+ #user-navigation ul li {
130
+ padding: 5px 10px;
131
+ }
132
+
133
+ #main-navigation ul li a:link, #main-navigation ul li a:visited, #main-navigation ul li a:hover, #main-navigation ul li a:active,
134
+ .secondary-navigation ul li a:link, .secondary-navigation ul li a:visited, .secondary-navigation ul li a:hover, .secondary-navigation ul li a:active,
135
+ #user-navigation ul li a:link, #user-navigation ul li a:visited, #user-navigation ul li a:hover, #user-navigation ul li a:active {
136
+ text-decoration: none;
137
+ }
138
+
139
+ #main-navigation ul li a {
140
+ font-size: 15px;
141
+ display: block;
142
+ padding: 8px 15px;
143
+ }
144
+
145
+ .secondary-navigation {
146
+ font-size: 13px;
147
+ border-bottom-width: 10px;
148
+ border-bottom-style: solid;
149
+ }
150
+
151
+ .secondary-navigation ul li a {
152
+ display: block;
153
+ padding: 10px 15px;
154
+ }
155
+
156
+ #footer {
157
+ padding-bottom: 20px;
158
+ }
159
+
160
+ /* pagination */
161
+
162
+ .pagination a, .pagination span {
163
+ padding: 2px 5px;
164
+ margin-right: 5px;
165
+ display: block;
166
+ float: left;
167
+ border-style: solid;
168
+ border-width: 1px;
169
+ }
170
+
171
+ .pagination span.current {
172
+ font-weight: bold;
173
+ }
174
+
175
+ .pagination a {
176
+ text-decoration: none;
177
+ }
178
+
179
+ /* tables */
180
+ .table {
181
+ width: 100%;
182
+ border-collapse: collapse;
183
+ margin-bottom: 15px;
184
+ }
185
+
186
+ .table th {
187
+ padding: 10px;
188
+ font-weight: bold;
189
+ text-align: left;
190
+ }
191
+
192
+ .table th.first {
193
+ width: 30px;
194
+ }
195
+
196
+ .table th.last {
197
+ width: 200px;
198
+ }
199
+
200
+ .table .checkbox {
201
+ margin-left: 10px;
202
+ }
203
+
204
+ .table td {
205
+ padding: 10px;
206
+ }
207
+
208
+ .table td.last {
209
+ text-align: right;
210
+ }
211
+
212
+ /* forms */
213
+
214
+ input.checkbox {
215
+ margin: 0;
216
+ padding: 0;
217
+ }
218
+
219
+ .form .group {
220
+ margin-bottom: 15px;
221
+ }
222
+
223
+ .form div.left {
224
+ width: 20%;
225
+ float: left;
226
+ }
227
+
228
+ .form div.right {
229
+ width: 75%;
230
+ float: right;
231
+ }
232
+
233
+ .form .columns .column {
234
+ width: 48%;
235
+ }
236
+
237
+ .form .columns .left {
238
+ float: left;
239
+ }
240
+
241
+ .form .columns .right {
242
+ float: right;
243
+ }
244
+
245
+ .form label.label, .form input.text_field, .form textarea.text_area {
246
+ font-size: 1.2em;
247
+ padding: 1px 0;
248
+ margin: 0;
249
+ }
250
+
251
+ .form label.right {
252
+ text-align: right;
253
+ }
254
+
255
+ .form input.checkbox, .form input.radio {
256
+ margin-right: 5px;
257
+ }
258
+
259
+ .form label.checkbox, .form label.radio {
260
+ line-height: 1.5em;
261
+ }
262
+
263
+ .form label.label {
264
+ display: block;
265
+ padding-bottom: 2px;
266
+ font-weight: bold;
267
+ }
268
+
269
+ .form div.fieldWithErrors label.label {
270
+ display: inline;
271
+ }
272
+
273
+ .form .fieldWithErrors .error {
274
+ color: red;
275
+ }
276
+
277
+ .form input.text_field, .form textarea.text_area {
278
+ width: 100%;
279
+ border-width: 1px;
280
+ border-style: solid;
281
+ }
282
+
283
+ /* lists */
284
+
285
+ ul.list {
286
+ margin: 0;
287
+ padding: 0;
288
+ list-style-type: none;
289
+ }
290
+
291
+ ul.list li {
292
+ clear: left;
293
+ padding-bottom: 5px;
294
+ }
295
+
296
+ ul.list li .left {
297
+ float: left;
298
+ }
299
+
300
+ ul.list li .left .avatar {
301
+ width: 50px;
302
+ height: 50px;
303
+ }
304
+
305
+ ul.list li .item {
306
+ margin-left: 80px;
307
+ }
308
+
309
+ ul.list li .item .avatar {
310
+ float: left;
311
+ margin: 0 5px 5px 0;
312
+ width: 30px;
313
+ height: 30px;
314
+ }
315
+
316
+ /* box */
317
+
318
+ #box {
319
+ width: 500px;
320
+ margin: 50px auto;
321
+ }
322
+
323
+ #box .block {
324
+ margin-bottom: 20px;
325
+ }
326
+
327
+ #box .block h2 {
328
+ padding: 10px 15px;
329
+ margin: 0;
330
+ }
331
+
332
+ #box .block .content {
333
+ padding: 10px 20px;
334
+ }
335
+
336
+