Permalink
Browse files

initial commit

  • Loading branch information...
0 parents commit 0c02f203c52af6d60b389835900897e6cc8e1801 @jeffdonthemic jeffdonthemic committed Oct 19, 2011
Showing with 3,274 additions and 0 deletions.
  1. +6 −0 .gitignore
  2. +45 −0 Gemfile
  3. +239 −0 Gemfile.lock
  4. +46 −0 README.md
  5. +7 −0 Rakefile
  6. +9 −0 app/assets/javascripts/application.js
  7. +3 −0 app/assets/javascripts/challenges.js.coffee
  8. +3 −0 app/assets/javascripts/content.js.coffee
  9. +3 −0 app/assets/javascripts/sessions.js.coffee
  10. +3 −0 app/assets/javascripts/test.js.coffee
  11. +3 −0 app/assets/javascripts/users.js.coffee
  12. +176 −0 app/assets/stylesheets/application.css.sass
  13. +3 −0 app/assets/stylesheets/challenges.css.sass
  14. +18 −0 app/assets/stylesheets/content.css.sass
  15. +3 −0 app/assets/stylesheets/sessions.css.sass
  16. +3 −0 app/assets/stylesheets/test.css.scss
  17. +3 −0 app/assets/stylesheets/users.css.scss
  18. +55 −0 app/controllers/application_controller.rb
  19. +10 −0 app/controllers/challenges_controller.rb
  20. +9 −0 app/controllers/content_controller.rb
  21. +121 −0 app/controllers/sessions_controller.rb
  22. +30 −0 app/controllers/test_controller.rb
  23. +60 −0 app/controllers/users_controller.rb
  24. +7 −0 app/helpers/application_helper.rb
  25. +2 −0 app/helpers/challenges_helper.rb
  26. +2 −0 app/helpers/content_helper.rb
  27. +36 −0 app/helpers/sessions_helper.rb
  28. +2 −0 app/helpers/test_helper.rb
  29. +2 −0 app/helpers/users_helper.rb
  30. 0 app/mailers/.gitkeep
  31. 0 app/models/.gitkeep
  32. +3 −0 app/models/settings.rb
  33. +91 −0 app/models/user.rb
  34. +4 −0 app/views/challenges/index.html.erb
  35. +75 −0 app/views/content/about.html.erb
  36. +174 −0 app/views/content/faq.html.erb
  37. +20 −0 app/views/content/home.html.erb
  38. +80 −0 app/views/content/privacy.html.erb
  39. +348 −0 app/views/content/tos.html.erb
  40. +56 −0 app/views/layouts/application.html.erb
  41. +40 −0 app/views/sessions/login.html.erb
  42. +15 −0 app/views/sessions/new.html.erb
  43. +1 −0 app/views/sessions/signup_third_party_create.html.erb
  44. +17 −0 app/views/sessions/signup_third_party_no_email.html.erb
  45. +1 −0 app/views/test/auth_cloudspokes.html.erb
  46. 0 app/views/test/auth_thirdparty.html.erb
  47. +3 −0 app/views/test/get_current_access_token.html.erb
  48. +10 −0 app/views/test/index.html.erb
  49. +1 −0 app/views/test/service_new_member_cloudsppokes.html.erb
  50. +1 −0 app/views/test/service_sfdc_username.html.erb
  51. +23 −0 app/views/users/new.html.erb
  52. +1 −0 app/views/users/show.html.erb
  53. +4 −0 config.ru
  54. +48 −0 config/application.rb
  55. +6 −0 config/boot.rb
  56. +25 −0 config/database.yml
  57. +5 −0 config/databasedotcom.yml
  58. +7 −0 config/environment.rb
  59. +30 −0 config/environments/development.rb
  60. +60 −0 config/environments/production.rb
  61. +42 −0 config/environments/test.rb
  62. +7 −0 config/initializers/backtrace_silencers.rb
  63. +18 −0 config/initializers/development_settings.rb
  64. +10 −0 config/initializers/inflections.rb
  65. +5 −0 config/initializers/mime_types.rb
  66. +47 −0 config/initializers/omniauth.rb
  67. +7 −0 config/initializers/secret_token.rb
  68. +8 −0 config/initializers/session_store.rb
  69. +14 −0 config/initializers/wrap_parameters.rb
  70. +5 −0 config/locales/en.yml
  71. +32 −0 config/routes.rb
  72. +13 −0 db/migrate/20111011174646_create_users.rb
  73. +5 −0 db/migrate/20111012114651_add_sfdc_username_to_users.rb
  74. +5 −0 db/migrate/20111014164435_add_access_token_to_users.rb
  75. +9 −0 db/migrate/20111014173456_create_settings.rb
  76. +34 −0 db/schema.rb
  77. +7 −0 db/seeds.rb
  78. +2 −0 doc/README_FOR_APP
  79. 0 lib/assets/.gitkeep
  80. +28 −0 lib/auth.rb
  81. +13 −0 lib/challenges.rb
  82. +101 −0 lib/services.rb
  83. +67 −0 lib/sitesettings.rb
  84. 0 lib/tasks/.gitkeep
  85. 0 log/.gitkeep
  86. +26 −0 public/404.html
  87. +26 −0 public/422.html
  88. +26 −0 public/500.html
  89. BIN public/assets/facebook_128.png
  90. BIN public/assets/facebook_256.png
  91. BIN public/assets/facebook_32.png
  92. BIN public/assets/facebook_64.png
  93. BIN public/assets/github_128.png
  94. BIN public/assets/github_256.png
  95. BIN public/assets/github_32.png
  96. BIN public/assets/github_64.png
  97. BIN public/assets/google_128.png
  98. BIN public/assets/google_256.png
  99. BIN public/assets/google_32.png
  100. BIN public/assets/google_64.png
  101. BIN public/assets/linkedin_128.png
  102. BIN public/assets/linkedin_256.png
  103. BIN public/assets/linkedin_32.png
  104. BIN public/assets/linkedin_64.png
  105. BIN public/assets/openid_128.png
  106. BIN public/assets/openid_256.png
  107. BIN public/assets/openid_32.png
  108. BIN public/assets/openid_64.png
  109. BIN public/assets/salesforce_64.png
  110. BIN public/assets/twitter_128.png
  111. BIN public/assets/twitter_256.png
  112. BIN public/assets/twitter_32.png
  113. BIN public/assets/twitter_64.png
  114. 0 public/favicon.ico
  115. +5 −0 public/robots.txt
  116. +6 −0 script/rails
  117. +5 −0 spec/controllers/content_controller_spec.rb
  118. +12 −0 spec/controllers/sessions_controller_spec.rb
  119. +5 −0 spec/controllers/test_controller_spec.rb
  120. +19 −0 spec/controllers/users_controller_spec.rb
  121. +15 −0 spec/helpers/sessions_helper_spec.rb
  122. +15 −0 spec/helpers/test_helper_spec.rb
  123. +15 −0 spec/helpers/users_helper_spec.rb
  124. +5 −0 spec/models/settings_spec.rb
  125. +25 −0 spec/spec_helper.rb
  126. +5 −0 spec/views/sessions/new.html.erb_spec.rb
  127. +5 −0 spec/views/users/new.html.erb_spec.rb
  128. +5 −0 spec/views/users/show.html.erb_spec.rb
  129. 0 test/fixtures/.gitkeep
  130. +15 −0 test/fixtures/users.yml
  131. 0 test/functional/.gitkeep
  132. +9 −0 test/functional/challenges_controller_test.rb
  133. +9 −0 test/functional/content_controller_test.rb
  134. +9 −0 test/functional/sessions_controller_test.rb
  135. 0 test/integration/.gitkeep
  136. +12 −0 test/performance/browsing_test.rb
  137. +13 −0 test/test_helper.rb
  138. 0 test/unit/.gitkeep
  139. +4 −0 test/unit/helpers/challenges_helper_test.rb
  140. +4 −0 test/unit/helpers/content_helper_test.rb
  141. +4 −0 test/unit/helpers/sessions_helper_test.rb
  142. +7 −0 test/unit/user_test.rb
  143. 0 vendor/assets/stylesheets/.gitkeep
  144. +431 −0 vendor/assets/stylesheets/normalize.css
  145. 0 vendor/plugins/.gitkeep
6 .gitignore
@@ -0,0 +1,6 @@
+.bundle
+db/*.sqlite3
+log/*.log
+tmp/
+.sass-cache/
+.DS_Store
45 Gemfile
@@ -0,0 +1,45 @@
+source 'http://rubygems.org'
+
+gem 'rails', '3.1.0'
+
+gem 'sqlite3'
+gem 'compass', git: 'git://github.com/chriseppstein/compass.git'
+
+gem 'databasedotcom'
+
+group :development, :test do
+ gem 'rspec-rails', '~> 2.6'
+ gem 'annotate', '2.4.0'
+ gem 'guard'
+ gem 'guard-bundler'
+ gem 'guard-rspec'
+ gem 'growl'
+ gem 'rb-fsevent'
+end
+
+group :test do
+ # Pretty printed test output
+ gem 'turn', :require => false
+end
+
+# Gems used only for assets and not required
+# in production environments by default.
+group :assets do
+ gem 'sass-rails', " ~> 3.1.0"
+ gem 'coffee-rails', "~> 3.1.0"
+ gem 'uglifier'
+end
+
+gem 'jquery-rails'
+gem 'httparty'
+
+# Use unicorn as the web server
+# gem 'unicorn'
+
+# Deploy with Capistrano
+# gem 'capistrano'
+
+# To use debugger
+# gem 'ruby-debug19', :require => 'ruby-debug'
+
+gem 'omniauth'
239 Gemfile.lock
@@ -0,0 +1,239 @@
+GIT
+ remote: git://github.com/chriseppstein/compass.git
+ revision: ebb2e42acc8a49cd77a712e955cb349fe07f89ee
+ specs:
+ compass (0.12.alpha.0.ebb2e42)
+ chunky_png (~> 1.2)
+ fssm (>= 0.2.7)
+ sass (~> 3.1)
+
+GEM
+ remote: http://rubygems.org/
+ specs:
+ XMLCanonicalizer (1.0.1)
+ log4r (>= 1.0.4)
+ actionmailer (3.1.0)
+ actionpack (= 3.1.0)
+ mail (~> 2.3.0)
+ actionpack (3.1.0)
+ activemodel (= 3.1.0)
+ activesupport (= 3.1.0)
+ builder (~> 3.0.0)
+ erubis (~> 2.7.0)
+ i18n (~> 0.6)
+ rack (~> 1.3.2)
+ rack-cache (~> 1.0.3)
+ rack-mount (~> 0.8.2)
+ rack-test (~> 0.6.1)
+ sprockets (~> 2.0.0)
+ activemodel (3.1.0)
+ activesupport (= 3.1.0)
+ bcrypt-ruby (~> 3.0.0)
+ builder (~> 3.0.0)
+ i18n (~> 0.6)
+ activerecord (3.1.0)
+ activemodel (= 3.1.0)
+ activesupport (= 3.1.0)
+ arel (~> 2.2.1)
+ tzinfo (~> 0.3.29)
+ activeresource (3.1.0)
+ activemodel (= 3.1.0)
+ activesupport (= 3.1.0)
+ activesupport (3.1.0)
+ multi_json (~> 1.0)
+ addressable (2.2.6)
+ annotate (2.4.0)
+ ansi (1.3.0)
+ arel (2.2.1)
+ bcrypt-ruby (3.0.1)
+ builder (3.0.0)
+ chunky_png (1.2.5)
+ coffee-rails (3.1.1)
+ coffee-script (>= 2.2.0)
+ railties (~> 3.1.0)
+ coffee-script (2.2.0)
+ coffee-script-source
+ execjs
+ coffee-script-source (1.1.2)
+ databasedotcom (1.1.4)
+ json
+ multipart-post (~> 1.1)
+ diff-lcs (1.1.3)
+ erubis (2.7.0)
+ execjs (1.2.9)
+ multi_json (~> 1.0)
+ faraday (0.7.5)
+ addressable (~> 2.2.6)
+ multipart-post (~> 1.1.3)
+ rack (>= 1.1.0, < 2)
+ fssm (0.2.7)
+ growl (1.0.3)
+ guard (0.8.4)
+ thor (~> 0.14.6)
+ guard-bundler (0.1.3)
+ bundler (>= 1.0.0)
+ guard (>= 0.2.2)
+ guard-rspec (0.5.0)
+ guard (>= 0.8.4)
+ hike (1.2.1)
+ httparty (0.8.1)
+ multi_json
+ multi_xml
+ i18n (0.6.0)
+ jquery-rails (1.0.14)
+ railties (~> 3.0)
+ thor (~> 0.14)
+ json (1.6.1)
+ log4r (1.1.9)
+ macaddr (1.4.0)
+ systemu (~> 2.2.0)
+ mail (2.3.0)
+ i18n (>= 0.4.0)
+ mime-types (~> 1.16)
+ treetop (~> 1.4.8)
+ mime-types (1.16)
+ multi_json (1.0.3)
+ multi_xml (0.4.1)
+ multipart-post (1.1.3)
+ net-ldap (0.2.2)
+ nokogiri (1.5.0)
+ oa-basic (0.3.0)
+ oa-core (= 0.3.0)
+ rest-client (~> 1.6.0)
+ oa-core (0.3.0)
+ oa-enterprise (0.3.0)
+ XMLCanonicalizer (~> 1.0.1)
+ addressable (~> 2.2.6)
+ net-ldap (~> 0.2.2)
+ nokogiri (~> 1.5.0)
+ oa-core (= 0.3.0)
+ pyu-ruby-sasl (~> 0.0.3.1)
+ rubyntlm (~> 0.1.1)
+ uuid
+ oa-more (0.3.0)
+ multi_json (~> 1.0.0)
+ oa-core (= 0.3.0)
+ rest-client (~> 1.6.0)
+ oa-oauth (0.3.0)
+ faraday (~> 0.7.3)
+ multi_json (~> 1.0.0)
+ multi_xml (~> 0.4.0)
+ oa-core (= 0.3.0)
+ oauth (~> 0.4.0)
+ oauth2 (~> 0.5.0)
+ oa-openid (0.3.0)
+ oa-core (= 0.3.0)
+ rack-openid (~> 1.3.1)
+ ruby-openid-apps-discovery (~> 1.2.0)
+ oauth (0.4.5)
+ oauth2 (0.5.1)
+ faraday (~> 0.7.4)
+ multi_json (~> 1.0.3)
+ omniauth (0.3.0)
+ oa-basic (= 0.3.0)
+ oa-core (= 0.3.0)
+ oa-enterprise (= 0.3.0)
+ oa-more (= 0.3.0)
+ oa-oauth (= 0.3.0)
+ oa-openid (= 0.3.0)
+ polyglot (0.3.2)
+ pyu-ruby-sasl (0.0.3.3)
+ rack (1.3.4)
+ rack-cache (1.0.3)
+ rack (>= 0.4)
+ rack-mount (0.8.3)
+ rack (>= 1.0.0)
+ rack-openid (1.3.1)
+ rack (>= 1.1.0)
+ ruby-openid (>= 2.1.8)
+ rack-ssl (1.3.2)
+ rack
+ rack-test (0.6.1)
+ rack (>= 1.0)
+ rails (3.1.0)
+ actionmailer (= 3.1.0)
+ actionpack (= 3.1.0)
+ activerecord (= 3.1.0)
+ activeresource (= 3.1.0)
+ activesupport (= 3.1.0)
+ bundler (~> 1.0)
+ railties (= 3.1.0)
+ railties (3.1.0)
+ actionpack (= 3.1.0)
+ activesupport (= 3.1.0)
+ rack-ssl (~> 1.3.2)
+ rake (>= 0.8.7)
+ rdoc (~> 3.4)
+ thor (~> 0.14.6)
+ rake (0.9.2)
+ rb-fsevent (0.4.3.1)
+ rdoc (3.10)
+ json (~> 1.4)
+ rest-client (1.6.7)
+ mime-types (>= 1.16)
+ rspec (2.6.0)
+ rspec-core (~> 2.6.0)
+ rspec-expectations (~> 2.6.0)
+ rspec-mocks (~> 2.6.0)
+ rspec-core (2.6.4)
+ rspec-expectations (2.6.0)
+ diff-lcs (~> 1.1.2)
+ rspec-mocks (2.6.0)
+ rspec-rails (2.6.1)
+ actionpack (~> 3.0)
+ activesupport (~> 3.0)
+ railties (~> 3.0)
+ rspec (~> 2.6.0)
+ ruby-openid (2.1.8)
+ ruby-openid-apps-discovery (1.2.0)
+ ruby-openid (>= 2.1.7)
+ rubyntlm (0.1.1)
+ sass (3.1.10)
+ sass-rails (3.1.4)
+ actionpack (~> 3.1.0)
+ railties (~> 3.1.0)
+ sass (>= 3.1.4)
+ sprockets (~> 2.0.0)
+ tilt (~> 1.3.2)
+ sprockets (2.0.2)
+ hike (~> 1.2)
+ rack (~> 1.0)
+ tilt (!= 1.3.0, ~> 1.1)
+ sqlite3 (1.3.4)
+ systemu (2.2.0)
+ thor (0.14.6)
+ tilt (1.3.3)
+ treetop (1.4.10)
+ polyglot
+ polyglot (>= 0.3.1)
+ turn (0.8.3)
+ ansi
+ tzinfo (0.3.30)
+ uglifier (1.0.3)
+ execjs (>= 0.3.0)
+ multi_json (>= 1.0.2)
+ uuid (2.3.4)
+ macaddr (~> 1.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ annotate (= 2.4.0)
+ coffee-rails (~> 3.1.0)
+ compass!
+ databasedotcom
+ growl
+ guard
+ guard-bundler
+ guard-rspec
+ httparty
+ jquery-rails
+ omniauth
+ rails (= 3.1.0)
+ rb-fsevent
+ rspec-rails (~> 2.6)
+ sass-rails (~> 3.1.0)
+ sqlite3
+ turn
+ uglifier
46 README.md
@@ -0,0 +1,46 @@
+# CloudSpokes (on Rails!)
+
+This application is not a pixel-for-pixel or same-HTML remake of
+Cloudspokes. This was an intentional decision as it has been built with
+the same look and feel but using semantic HTML5 as well as Sprockets,
+SASS, and CSS3.
+
+The application is on a clean skeleton and is set up for RSpec testing.
+To run the application, you can simply run `rails server`. It is also
+complete with a Gemfile, Guardfile for test automation, and more.
+
+Basically this is a shell application that gives you everything you need
+to get up and running. It should deploy to Heroku great as-is.
+
+## Pages
+
+The pages that are available are:
+
+1. Home Page (dynamic content excluded)
+2. About Page ("how it works" link)
+3. FAQs
+4. Privacy Policy
+5. Terms of Service
+
+The required omniauth strategies have been added in config/initializers/omniauth.rb
+with the required consumer keys and consumer secrets from various OAuth providers.
+Change these values during deployment. Also there is a hard coded value of
+'OmniAuth.config.full_host' to a 'https' url of the app. This is to force the
+callback generated by omniauth to have a 'https' (required for Salesforce).
+
+Our OAuth module is at lib/auth.rb. It consumes the omniauth hash and generates
+a uniform hash for all providers with necessary values in a instance variable
+'authhash' which can be used by other modules/classes.
+
+The rails app has single controller: SessionController which has endpoints for
+/auth/<provider>/callback and passes on the omniauth hash and provider to our
+'lib/auth' module.
+
+The current homepage with links to various providers is a simple static file:
+'public/index.html'.
+
+May want to look into implementing the session store with Redis: https://github.com/mattmatt/redis-session-store
+
+Deployment Notes:
+- need to change the OAuth settings in congig/initializers/omniauth.rb
+- need to change the config/databasedotcom.yml if deploying for production sfdc org
7 Rakefile
@@ -0,0 +1,7 @@
+#!/usr/bin/env rake
+# Add your own tasks in files placed in lib/tasks ending in .rake,
+# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
+
+require File.expand_path('../config/application', __FILE__)
+
+CloudSpokes::Application.load_tasks
9 app/assets/javascripts/application.js
@@ -0,0 +1,9 @@
+// This is a manifest file that'll be compiled into including all the files listed below.
+// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
+// be included in the compiled file accessible from http://example.com/assets/application.js
+// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
+// the compiled file.
+//
+//= require jquery
+//= require jquery_ujs
+//= require_tree .
3 app/assets/javascripts/challenges.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
3 app/assets/javascripts/content.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
3 app/assets/javascripts/sessions.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
3 app/assets/javascripts/test.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
3 app/assets/javascripts/users.js.coffee
@@ -0,0 +1,3 @@
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
176 app/assets/stylesheets/application.css.sass
@@ -0,0 +1,176 @@
+//= require "normalize"
+//= require_self
+
+@import "compass"
+
+$bg-blue: #d1e7ed
+$border-blue: #456179
+$link-color: #09f
+$heading-blue: #6699C9
+
+=hide-text
+ text-indent: -999em
+ text-align: left
+
+html, body
+ min-height: 100%
+
+body
+ font-family: Arial, sans-serif
+ background: $bg-blue
+ font-size: 12px
+ color: #444
+ +background-image(linear-gradient(rgba(30,140,200,0.15), rgba(30,140,200,0) 50px))
+
+a
+ color: $link-color
+ text-decoration: none
+ &:hover
+ text-decoration: underline
+ &:visited
+ color: $link-color
+
+.upcase
+ text-transform: uppercase
+.downcase
+ text-transform: lowercase
+
+nav ul
+ padding: 0
+ margin: 0
+ list-style: none
+ li
+ padding: 0
+ margin: 0
+ display: inline-block
+
+#wrapper
+ width: 980px
+ margin: 0 auto
+
+#content
+ clear: both
+ background: white
+ border: 9px solid $border-blue
+ border-left: 0
+ border-right: 0
+
+#top
+ #logo
+ float: left
+ margin: 10px 10px 10px 20px
+ a
+ +hide-text
+ display: block
+ background: url(http://cloudspokes.s3.amazonaws.com/CloudSpokes.png) no-repeat top left
+ width: 125px
+ height: 97px
+ #menu
+ background: url(http://cloudspokes.s3.amazonaws.com/CloudSpokes2.png) no-repeat 5px 0px
+ padding-top: 42px
+ margin-top: 20px
+ float: left
+ a
+ display: block
+ background: #eee
+ color: adjust-saturation($link-color, -50)
+ text-decoration: none
+ font-size: 16px
+ padding: 8px 12px
+ margin: 0 4px
+ +border-radius(5px)
+ text-transform: lowercase
+ &:hover
+ background: adjust-saturation($link-color, -50)
+ color: #eee
+
+ #side_menu
+ float: right
+ padding-top: 65px
+ a
+ color: #888
+ text-decoration: none
+ text-transform: lowercase
+ font-size: 16px
+ display: block
+ padding: 6px 12px
+ &:hover
+ color: $link-color
+
+#bottom
+ line-height: 40px
+ height: 40px
+ img
+ vertical-align: middle
+ margin: 0 3px
+ .left
+ float: left
+ nav
+ display: inline-block
+ .right
+ float: right
+ a
+ color: #666
+ padding: 0 10px
+ border-right: 1px solid #666
+ li:last-child a
+ border-right: 0
+
+a.btn
+ +box-shadow(1px 1px 6px rgba(0,0,0,0.6))
+ display: inline-block
+ padding: 10px 20px
+ +border-radius(8px)
+ font-size: 16px
+ background: $link-color
+ color: white
+ +background-image(linear-gradient(rgba(100,200,255,0.3),rgba(100,200,255,0)))
+ &:hover
+ +background-image(linear-gradient(rgba(100,200,255,0),rgba(100,200,255,0.3)))
+ text-decoration: none
+ &.light
+ color: $link-color
+ background: white
+ +background-image(linear-gradient(#fff,#ddd))
+ &:hover
+ +background-image(linear-gradient(#eee,#fff))
+
+#heading
+ color: white
+ font-family: Marvel
+ font-weight: bold
+ font-size: 48px
+ padding: 15px 20px 15px
+ margin: -9px 0px 20px
+ background-color: $border-blue
+ +background-image(linear-gradient(rgba(200,255,255,0.25),rgba(200,255,255,0)))
+
+.page
+ padding: 20px
+ #heading
+ margin-left: -20px
+ margin-top: -29px
+ margin-right: -20px
+ h4
+ font-size: 16px
+ color: black
+ margin: 10px 0
+ font-weight: normal
+ h3
+ font-size: 18px
+ font-weight: normal
+ color: $heading-blue
+ margin: 5px 0 10px
+ p.big
+ font-size: 16px
+ color: black
+
+.col3
+ +clearfix
+ .col
+ +box-sizing(border-box)
+ width: 33%
+ float: left
+ padding: 15px 20px
+
+@import "content"
3 app/assets/stylesheets/challenges.css.sass
@@ -0,0 +1,3 @@
+// Place all the styles related to the challenges controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
18 app/assets/stylesheets/content.css.sass
@@ -0,0 +1,18 @@
+#dashboard
+ background: url(http://cloudspokes.s3.amazonaws.com/dashboard.gif)
+ color: white
+ padding: 30px
+ .join-us
+ background: rgba(0,0,0,0.3)
+ padding: 20px
+ +border-radius(12px)
+ h1
+ font-family: Marvel
+ font-size: 64px
+ margin: -10px 0 0
+ p
+ font-size: 14px
+ margin: 0 0 15px
+ a.btn
+ margin-right: 6px
+
3 app/assets/stylesheets/sessions.css.sass
@@ -0,0 +1,3 @@
+// Place all the styles related to the sessions controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
3 app/assets/stylesheets/test.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the test controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
3 app/assets/stylesheets/users.css.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the users controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
55 app/controllers/application_controller.rb
@@ -0,0 +1,55 @@
+class ApplicationController < ActionController::Base
+ protect_from_forgery
+ include SessionsHelper
+ require 'sitesettings'
+ require "auth"
+
+ def new_public_token
+ # temp method to fetch a new public token
+ SiteSettings.get_new_public_access_token
+ redirect_to root_path
+ end
+
+ # fetch the access token for this user or return the public access token from the database
+ def current_access_token
+ if current_user.nil?
+ p '======= returning the public access token'
+ return SiteSettings.public_access_token
+ else
+ p '======= returning the user access token'
+
+ # if the access token is nil or the access token hasn't been updated in an hour
+ if current_user.access_token.nil? || Time.now > current_user.updated_at.getlocal + (60*60)
+
+ p '======= current_user access token is nil or an hour old. fetching new access token'
+
+ config = YAML.load_file(File.join(::Rails.root, 'config', 'databasedotcom.yml'))
+ client = Databasedotcom::Client.new(config)
+ sfdc_username = current_user.username+'@'+ENV['sfdc_username_domain']
+ puts "--- logging into salesforce with #{sfdc_username} and #{current_user.password}"
+
+ begin
+
+ access_token = client.authenticate :username => sfdc_username, :password => current_user.password
+ current_user.access_token = access_token
+ current_user.save
+ return current_user.access_token
+
+ # seem to get this error for brand new users after they are created
+ # if we get an error, just return the public_access_token. it will check again on the
+ # next call to this method until it returns the access_token successfully
+ rescue Exception => exc
+ p '========= error getting the access_token for the user. returning public_access_token'
+ p exc.message
+ return SiteSettings.public_access_token
+ end
+
+ else
+ return current_user.access_token
+ end
+
+ end
+
+ end
+
+end
10 app/controllers/challenges_controller.rb
@@ -0,0 +1,10 @@
+require 'challenges'
+
+class ChallengesController < ApplicationController
+
+ def index
+ @challenges = Challenges.get_challenges(current_access_token)
+ puts @challenges
+ end
+
+end
9 app/controllers/content_controller.rb
@@ -0,0 +1,9 @@
+class ContentController < ApplicationController
+ def show
+ if File.exist?(Rails.root.to_s + "/app/views/content/#{params[:id]}.html.erb")
+ render template: "content/#{params[:id]}"
+ else
+ render file: Rails.root + '/public/404.html', status: 404
+ end
+ end
+end
121 app/controllers/sessions_controller.rb
@@ -0,0 +1,121 @@
+require "auth"
+require 'services'
+
+class SessionsController < ApplicationController
+
+ def login
+ # delete the session from their last login attempt
+ session.delete(:authsession)
+ end
+
+ # if the provider doesn't include an email, redirects them to this form
+ def signup_third_party_no_email
+ end
+
+ # once user enters email for provider, submits and create user & logs in
+ def signup_third_party_create
+
+ # add the email to the session hash
+ session[:authsession].get_hash[:email] = params[:session][:email]
+ # try and create the user in sfdc
+ new_member_create_results = Services.new_member(session[:authsession].get_hash)
+ # if the user was created successfully in sfdc
+ if new_member_create_results[:success].eql?('true')
+
+ # now authenticate the user with salesforce to get their auth token and save to db
+ user = User.authenticate_third_party(session[:authsession].get_hash[:provider],
+ session[:authsession].get_hash[:username])
+
+ # delete the session var that stored the auth variables
+ session.delete(:authsession)
+
+ if user.nil?
+ render :inline => "Whoops! Error. Hit the back button and try again."
+ else
+ sign_in user
+ redirect_to root_path
+ end
+
+ else
+ flash[:error] = new_member_create_results[:message]
+ redirect_to signup_complete_url
+ end
+ end
+
+ def callback
+
+ # pass on omniauth hash and provider to our auth module
+ as = AuthSession.new(request.env['omniauth.auth'], params[:provider])
+
+ # see if they exist as a member with these third party credentials
+ user_exists_results = Services.sfdc_username(as.get_hash[:provider], as.get_hash[:username])
+ p 'user exists?'
+ p user_exists_results
+
+ # if no user was returned, then create them
+ if user_exists_results[:success].eql?('false')
+
+ # if the provider does not send us an email, redirect them
+ if ['twitter','github'].include?(params[:provider])
+ session[:authsession] = as
+ redirect_to signup_complete_url
+ else
+ # try and create the user
+ new_member_create_results = Services.new_member(as.get_hash)
+ if new_member_create_results[:success].eql?('true')
+
+ user = User.new(:username => new_member_create_results[:username],
+ :sfdc_username => new_member_create_results[:sfdc_username],
+ :password => ENV['third_party_password'])
+ user.save
+ sign_in user
+ redirect_to root_path
+
+ else
+ flash[:error] = new_member_create_results[:message]
+ end
+ end
+
+ else
+
+ # log them in
+ user = User.authenticate_third_party(as.get_hash[:provider],as.get_hash[:username])
+ if user.nil?
+ flash[:error] = "Serious error loggin in!!"
+ else
+ sign_in user
+ redirect_to root_path
+ end
+
+ end
+
+ end
+ def callback_failure
+ render :inline => "Authentication failed"
+ end
+
+ # logging in with cloudspokes u/p
+ def create
+
+ user = User.authenticate(params[:session][:username],
+ params[:session][:password])
+
+ if user.nil?
+ flash[:error] = "Invalid email/password combination."
+ redirect_to '/signin'
+ else
+ sign_in user
+ redirect_to root_path
+ end
+ end
+
+ def destroy
+ sign_out
+ redirect_to root_path
+ end
+
+ def callback_test
+ render :inline => "<html><body><b>Our hash:</b><br>"+as.get_hash.to_s + "<br><br><b>Omniauth hash:</b><br>" + request.env['omniauth.auth'].to_s+"</body></html>"
+ end
+
+end
30 app/controllers/test_controller.rb
@@ -0,0 +1,30 @@
+class TestController < ApplicationController
+
+ require 'services'
+
+ def auth_cloudspokes
+ p '============ auth_cloudspokes'
+ @results = User.authenticate('testuser9-cs','!sbx9876')
+ end
+
+ def auth_thirdparty
+ p '============ auth_thirdparty'
+ @results = current_access_token
+ end
+
+ def service_sfdc_username
+ p '============ service_sfdc_username'
+ @results = Services.sfdc_username('github', 'jeffdonthemic')
+ end
+
+ def service_new_member_cloudsppokes
+ p '============ service_new_member_cloudsppokes'
+ @results = Services.new_member({:username => 'jeffdonthemic', :email => 'jeff@jeffdouglas.com', :password => 'changeme'})
+ end
+
+ def get_current_access_token
+ p '============ current_access_token'
+ @results = current_access_token
+ end
+
+end
60 app/controllers/users_controller.rb
@@ -0,0 +1,60 @@
+class UsersController < ApplicationController
+ require 'services'
+
+ def show
+ @user = User.find(params[:id])
+ end
+
+ # signing up with a cloudspokes u/p
+ def new
+ @user = User.new
+ end
+
+ # create the cloudspokes member in sfdc from 'new' form
+ def create
+
+ if params[:user][:password].eql?(params[:user][:password_confirmation])
+
+ # remove the password_confirmation key from the hash
+ params[:user].delete(:password_confirmation)
+
+ # create the member and user in sfdc
+ results = Services.new_member(params[:user])
+
+ p results
+ logger.info results
+
+ if results[:success].eql?('true')
+
+ # add the sfdc_username to the hash so we can insert locally
+ params[:user][:sfdc_username] = results[:sfdc_username]
+ @user = User.new(params[:user])
+
+ if @user.save
+ sign_in @user
+ redirect_to @user
+ else
+ # could not save the user in the database
+ flash[:error] = @user.errors.full_messages
+ @user = User.new
+ render 'new'
+ end
+
+ else
+ # could not create the user in sfdc.
+ p '=========== could not create the user in sfdc.'
+ logger.info results
+ flash[:error] = results[:message]
+ @user = User.new
+ render 'new'
+ end
+
+ else
+ @user = User.new
+ flash[:error] = 'Your passwords do not match'
+ redirect_to signup_url
+ end
+
+ end
+
+end
7 app/helpers/application_helper.rb
@@ -0,0 +1,7 @@
+module ApplicationHelper
+
+ def s3_image(path, options = {})
+ image_tag("http://cloudspokes.s3.amazonaws.com/#{path}", options)
+ end
+
+end
2 app/helpers/challenges_helper.rb
@@ -0,0 +1,2 @@
+module ChallengesHelper
+end
2 app/helpers/content_helper.rb
@@ -0,0 +1,2 @@
+module ContentHelper
+end
36 app/helpers/sessions_helper.rb
@@ -0,0 +1,36 @@
+module SessionsHelper
+
+ def signed_in?
+ !current_user.nil?
+ end
+
+ def sign_in(user)
+ cookies.permanent.signed[:remember_token] = [user.id]
+ self.current_user = user
+ end
+
+ def sign_out
+ current_user.destroy unless current_user.nil?
+ cookies.delete(:remember_token)
+ self.current_user = nil
+ end
+
+ def current_user
+ @current_user ||= user_from_remember_token
+ end
+
+ def current_user=(user)
+ @current_user = user
+ end
+
+ private
+
+ def user_from_remember_token
+ User.authenticate_with_salt(*remember_token)
+ end
+
+ def remember_token
+ cookies.signed[:remember_token] || [nil]
+ end
+
+end
2 app/helpers/test_helper.rb
@@ -0,0 +1,2 @@
+module TestHelper
+end
2 app/helpers/users_helper.rb
@@ -0,0 +1,2 @@
+module UsersHelper
+end
0 app/mailers/.gitkeep
No changes.
0 app/models/.gitkeep
No changes.
3 app/models/settings.rb
@@ -0,0 +1,3 @@
+class Settings < ActiveRecord::Base
+ validates :access_token, :presence => true
+end
91 app/models/user.rb
@@ -0,0 +1,91 @@
+class User < ActiveRecord::Base
+ require 'services'
+
+ validates :username, :presence => true,
+ :uniqueness => true
+ validates :password, :presence => true
+ validates :sfdc_username, :presence => true
+
+ # TODO -- encrypt password before save
+
+ def self.authenticate(username, password)
+
+ # make sure their sfdc credentials are correct
+ login_results = sfdc_login(username, password)
+ p login_results
+
+ if login_results[:success].eql?('true')
+ # check for an existing record in the database and delete it
+ user = find_by_username(username)
+ if !user.nil?
+ user.destroy
+ end
+ # create the new user in the database
+ user = User.new(:username => username, :sfdc_username => username+ENV['sfdc_username_domain'],
+ :password => password, :access_token => login_results[:access_token])
+ user.save
+ return user
+ else
+ # TODO pass the error back from login_results - 'message'
+ return nil
+ end
+ end
+
+ def self.authenticate_third_party(third_party_service, third_party_username)
+
+ # find their sfdc username and cloudspokes username
+ results = Services.sfdc_username(third_party_service, third_party_username)
+ p '======= sfdc_username'
+ p results
+ if results[:success].eql?('true')
+
+ # not make sure their credentials are correct and get their access token
+ login_results = sfdc_login(results[:username], ENV['third_party_password'])
+ p '========== sfdc_login results'
+ p login_results
+
+ # if they logged in successfully, then they are golden
+ if login_results[:success].eql?('true')
+
+ user = find_by_username(results[:username])
+ # TODO - change this so that access token is persisted each time
+ if user.nil?
+ user = User.new(:username => results[:username], :sfdc_username => results[:sfdc_username],
+ :password => ENV['third_party_password'], :access_token => login_results[:access_token])
+ user.save
+ end
+ return user
+
+ else
+ return nil
+ end
+ else
+ return nil
+ end
+ end
+
+ def self.sfdc_login(username, password)
+
+ p '============ running sfdc_login'
+
+ config = YAML.load_file(File.join(::Rails.root, 'config', 'databasedotcom.yml'))
+ client = Databasedotcom::Client.new(config)
+ sfdc_username = username+'@'+ENV['sfdc_username_domain']
+ puts "--- logging into salesforce with #{sfdc_username} and #{password}"
+
+ # log into sfdc with their credentials to return their access token
+ begin
+ access_token = client.authenticate :username => sfdc_username, :password => password
+ return {:success => 'true', :message => 'Successful sfdc login.', :access_token => access_token}
+ rescue Exception => exc
+ return {:success => 'false', :message => exc.message}
+ end
+
+ end
+
+ def self.authenticate_with_salt(id)
+ user = find_by_id(id)
+ # (user && user.salt == cookie_salt) ? user : nil
+ end
+
+end
4 app/views/challenges/index.html.erb
@@ -0,0 +1,4 @@
+<h1>Challenges</h1>
+<% @challenges.each do |record| %>
+ <%= record["Name"] %><br/>
+<% end %>
75 app/views/content/about.html.erb
@@ -0,0 +1,75 @@
+<div class="page">
+ <h1 id='heading'>How It Works</h1>
+ <!--
+ <h4>
+
+ Each challenge is
+ created to garner participation from community members with expertise in the
+ specific problem domain. If you feel you have the expertise to compete in a
+ challenge, follow these steps to get started!
+ </h4>-->
+ <div style="float: left; width:10%; padding-left:25px">
+ <img src="http://cloudspokes.s3.amazonaws.com/01Post.jpg" alt="Post">
+ </div>
+ <div style="width: 75%;">
+ <h3>Competition Posted</h3>
+ Carefully read the requirements
+ for the challenge to ensure that you feel comfortable that you will be able to
+ submit a solution.
+ </div>
+ <br>
+ <br>
+ <div style="float: left; width:10%; padding-left:25px">
+ <img src="http://cloudspokes.s3.amazonaws.com/02Register.jpg" alt="Post">
+ </div>
+ <div style="width: 75%;">
+ <h3>Register</h3>
+ Found your competition? Take note of the time
+ frame allotted for the challenge - you should register on or soon after the
+ start date to allow yourself enough time to complete the challenge.
+ </div>
+
+ <br>
+ <div style="clear:both"></div>
+ <div style="float: left; width:10%; padding-left:25px">
+ <img src="http://cloudspokes.s3.amazonaws.com/03Colaborate.jpg" alt="Post">
+ </div>
+ <div style="width: 75%;">
+ <h3>Collaborate</h3>
+ Carefully read the requirements
+ for the challenge to ensure that you feel comfortable that you will be able to
+ submit a solution. Make sure to use the forums to discuss any questions with
+ the community and the challenge posters.
+ </div>
+ <br>
+ <div style="clear:both"></div>
+ <div style="float: left; width:10%; padding-left:25px">
+ &nbsp;<img src="http://cloudspokes.s3.amazonaws.com/04Submit1.jpg" alt="Post"></div>
+ <div style="width: 75%;">
+ <h3>Submit</h3>
+ Also review the
+ deliverable requirements for the challenge - it's important to adhere to these
+ when you submit your solution. This includes requested file formats and any
+ other instructions pertinent to the submission of your work. Your
+ submissions must be uploaded by the due date - late submissions are not allowed.
+ </div>
+ <br>
+ <div style="float: left; width:10%; padding-left:25px">
+ <img src="http://cloudspokes.s3.amazonaws.com/05PeerReview.jpg" alt="Post">
+ </div>
+ <div style="width: 75%;">
+ <h3>Peer Review</h3>
+ Once your work has been submitted it is time to get it reviewed by your peers to determine the winner.
+ This is where the rubber hits the road. Did you comment your code? Is it readable? Does it implement all the requirements?
+ </div>
+ <br>
+ <div style="clear:both"></div>
+ <div style="float: left; width:10%; padding-left:25px">
+ <img src="http://cloudspokes.s3.amazonaws.com/06Winner.jpg" alt="Post">
+ </div>
+ <div style="width: 75%;">
+ <h3>Winning</h3>
+ Congratulations! You have won! Even if you didn't win, check out your profile to see if you have earned any achievements!</div>
+ <br>
+
+ </div>
174 app/views/content/faq.html.erb
@@ -0,0 +1,174 @@
+<div class='page'>
+ <h1 id='heading'>FAQs</h1>
+
+ <p class='big'>The Developer Community is now officially open for business! As a busy consultant trying to juggle life, projects and Facebook status updates, why on earth would you want to devote time to the community and its various challenges? You may be surprised by there are multitude of reasons why you should get involved in the community.</p>
+
+ <ol class="faqs">
+ <li>
+ <h4>
+ Why should I join CloudSpokes?</h4>
+ <br>
+ There are many reasons to join the industry’s first cross-cloud community. Just
+ to get you started, here are our top 15!<br>
+ <ul>
+ <li><span>Get into the cloud: </span>CloudSpokes and our partners work exclusively in
+ the cloud. If you have been looking for an opportunity to get deep into a cloud
+ environment, this is a good time to do so. </li>
+ <li><span>Earn money: </span>You will find that you have a lot in common with other
+ members. This is a great way to meet new people. </li>
+ <li><span>Earn money:</span>Who can’t use some extra cash? CoudSpokes challenges are
+ a great way to do what you love to do... and get paid for it. </li>
+ <li><span>Learn new stuff: </span>Been itching to try out something new but just don’t
+ have the opportunity to do so? Jump into a challenge involving something you’ve
+ never used before. Not only will you get hands-on practice, but you will also get
+ an invaluable review from peers experienced in that technology. </li>
+ <li><span>Get honest feedback:: </span>Any work you submit will be impartially reviewed
+ and scored. This is a great way to take your game to the next level. </li>
+ <li><span>Challenge yourself: </span>Are you good enough to win? Are you better than
+ your peers? Are you better than your boss? Challenge them on a head-to-head competition
+ and see who comes out ahead. </li>
+ <li><span>Overcome your limits: </span>In CloudSpokes, you can do meaningful work regardless
+ of educational background or geographic location - what matters is the work you
+ submit, not your credentials (or lack thereof). </li>
+ <li><span>Unleash your creativity: </span>Apply creativity and knowledge in ways that
+ you could only dream of in your day job. </li>
+ <li><span>Mad Props: </span>accumulate feedback, badges, and swag to show the world
+ that you’re a master of cross-cloud development. </li>
+ <li><span>Build Community: </span>participate in forums. The forums are the heart of
+ the community. Ask questions and search for answers. Chime-in on hot topics. Mentor
+ other members. </li>
+ <li><span>Become a reviewer: </span>Keep the world safe from bad code and learn even
+ more by reviewing other’s work. </li>
+ <li><span>Network: </span>You will find that you have a lot in common with other members.
+ This is a great way to meet new people. </li>
+ <li><span>Build your resume: </span>Reference winning challenges on your resume as proof
+ of skills / technology knowledge. </li>
+ <li><span>Find your next gig: </span>Become recognized as an expert on cross-cloud development,
+ and meet potential employers. </li>
+ <li><span>Recruit employees: </span>Your next employee (or startup cofounder) may be
+ a community member.</li>
+ <li><span>Be productive: </span>Stop wasting your time, drop that game console, and
+ jump into cloud design and development. Feel good about spending extra time developing
+ your skills, networking, and earning some extra money. </li>
+ </ul>
+ </li>
+ <br>
+ <li>
+ <h4>
+ How do I compete?</h4>
+ </li>
+ <br>
+ It is easy to get started. You just have to join the community, find a challenge
+ you’d like to compete in, do amazing work, and submit it. Its all right here in
+ our participant guide.
+ <br>
+ <br>
+ <li>
+ <h4>
+ What are the forums used for?</h4>
+ </li>
+ <br>
+ The forums are the primary means of communication
+ amongst members.Forums may be specific to a
+ particular challenge, or more general in nature on various cloud-focused topics.
+ Cloud Spokes is a competition-oriented community, but the
+ Forums are where we keep it collaborative.
+ <br>
+ <br>
+ <li>
+ <h4>
+ What does it mean to “submit” for a challenge?</h4>
+ </li>
+ <br>
+ This is where the rubber meets the road. The ultimate goal of this community is
+ to obtain quality submissions that satisfy the sponsor’s requirements. This results
+ in a win-win situation for all: sponsors obtain high-quality work in a timely fashion;
+ members earn prizes and other rewards for their work.
+ <br>
+ <br>
+ <li>
+ <h4>
+ What is a “review”?</h4>
+ </li>
+ <br>
+ Every competition will have a number of individuals identified as reviewers. Their
+ job is to examine each submission and conduct a quantitative and qualitative analysis
+ of the submission. This is done using standard scorecards as well as a comparison
+ with challenge’s requirements. Each submission is anonymized before the reviewer
+ examines it to ensure impartiality and fairness.
+ <br>
+ <br>
+ <li>
+ <h4>
+ How do I become a reviewer?</h4>
+ </li>
+ <br>
+ As you gain experience in this community and with winning submissions, you may be
+ invited to begin reviewing submissions for specific challenges. As a reviewer you
+ are not eligible to compete in challenges that you are reviewing. Once you become
+ a reviewer, you must periodically submit to existing competitions to maintain your
+ reviewer status.
+ <br>
+ <br>
+ <li>
+ <h4>
+ Are reviewers compensated?</h4>
+ </li>
+ <br>
+ Yes, each reviewer will be compensated for their efforts.
+ <br>
+ <br>
+ <li>
+ <h4>
+ How do I give you feedback?</h4>
+ </li>
+ <br>
+ Have something to share/say? Thoughts on a new technology, or new technique? Feel
+ free to write it up and share it with the community in the forums or email us at <a href="mailto:cloudspokes@appirio.com">cloudspokes@appirio.com</a>.
+ <br>
+ <br>
+ <li>
+ <h4>
+ Who is eligible to participate in CloudSpokes?</h4>
+ </li>
+ <br>
+ You must be 18 years of older and agree to our Terms of Service... but that’s about
+ it. CloudSpokes doesn’t screen for educational background or work experience-- we
+ let your work speak for itself.
+ <br>
+ <br>
+ <li>
+ <h4>
+ How do I get paid?</h4>
+ </li>
+ <br>
+ Currently we are offering payment by check. Check payments are processed once a
+ month. We will also work with you via email to complete the necessary paperwork
+ for payment.
+ <br>
+ <br>
+ <li>
+ <h4>
+ Can I request a payout?</h4>
+ </li>
+ <br>
+ No payouts are paid out on a schedule.
+ <br>
+ <br>
+ <li>
+ <h4>
+ What currency do I get paid in?</h4>
+ </li>
+ <br>
+ All prizes are paid out in US currency.
+ <br>
+ <br>
+ <li>
+ <h4>
+ How do I get started?</h4>
+ </li>
+ <br>
+ Again, it is easy to get started. You just have to join the community, find a challenge
+ you’d like to compete in, do amazing work, and submit it. Welcome to CloudSpokes!
+ </ol>
+</div>
20 app/views/content/home.html.erb
@@ -0,0 +1,20 @@
+<section id='dashboard'>
+ <aside class='join-us'>
+ <h1>Join Us</h1>
+ <p>Participate in challenges, build a diverse portfolio, learn something new, and earn a little cash money on the side too.</p>
+ <nav>
+ <%= link_to "Join Now", "#", class: 'btn' %>
+ <%= link_to "Learn More", "#", class: 'btn light' %>
+ </nav>
+ </aside>
+</section>
+<section class='col3'>
+ <div class='col'>
+ </div>
+ <div class='col'>
+ </div>
+ <div class='col'>
+ <iframe width="300" height="250" src="http://www.youtube.com/embed/abMDBbxpsGo?rel=0"
+ frameborder="0"></iframe>
+ </div>
+</section>
80 app/views/content/privacy.html.erb
@@ -0,0 +1,80 @@
+<div class="page">
+ <h1 id='heading'>Privacy Policy</h1>
+ This privacy statement covers the Web site <a href="http://www.CloudSpokes.com">www.CloudSpokes.com</a> ("Site") and personally identifiable information about users of our services and products ("Services") .
+If you have questions or concerns regarding this statement, you should first contact <a href="mailto:security@appirio.com">security@appirio.com</a>. Upon request and within 30 days, Appirio will grant individuals reasonable access to personal information that it holds about them. In addition, Appirio will take reasonable steps to permit individuals to correct, amend, or delete information that is demonstrated to be inaccurate or incomplete. Please contact <a href="mailto:security@appirio.com">security@appirio.com</a> to change your personal information gathered on the Site.
+<br><br>
+<h4>Safe Harbor</h4>
+<br>
+This Site follows the Safe Harbor Principles published by the United States Department of Commerce (the “Principles”) with respect to the transfer of personal data from the European Union to the United States of America. This Privacy Policy details certain policies implemented throughout Appirio implementing the Principles and governing the Site's use of personally identifiable information provided via this Site and through our services. If there is any conflict between the policies in this Privacy Policy and the Principles, the Principles will govern.
+
+<br><br>
+<h4>Privacy Policy Updates</h4>
+<br>
+Due to the Internet's rapidly evolving nature, CloudSpokes may need to make material changes to this policy or update this Privacy Policy from time to time. If so, CloudSpokes will post its updated Privacy Policy on our homepage with a prominent material change notice. If any modification is unacceptable to you, you shall cease using this Site. If you do not cease using this Site, you will be deemed to have accepted the change.
+Information Collection, Use, Choices and Data Integrity
+You can generally visit our Site without revealing any personally identifiable information about yourself. However, in certain sections of this Site, we may invite you to contact us with questions or comments, register for webinars or events, participate in contests and surveys, or request information or more information about our Services. Due to the nature of some of these activities, we may collect personally identifiable information, such as your name, address, email address and phone number, username, password and any other personally identifiable information you elect to include in your communications sent to us. In certain circumstances, we also may ask for your title, company name and additional company information such as annual revenues. We may also ask for demographic information in order to provide you with a more personalized experience.
+<br><br>If you request more information about our Services or participate in a contest, we may use your personally identifiable information to send you the information you have requested or information about the contest. We may use your personally identifiable information to register you to use our Site, deliver certain goods, services or information you have requested, provide you with notices regarding Services you have purchased or products and services of our partners you may want to purchase in the future and other CloudSpokes news, verify your authority to enter the Site and improve the content and general administration of the Site. You have the choice to opt-out of receiving emails from us about our Services or products and services of our partners, including promotions and events and other news. You can opt out of being contacted by us regarding our Services or products and services of our partners, including promotions and events as well as other news at any time by sending an email to <a href="mailto:remove@appirio.com">remove@appirio.com</a>.
+<br><br>We may receive a confirmation when you open an e-mail from CloudSpokes if your computer supports this type of program, in order to help us make e-mails more interesting and helpful.
+<br><br>In performing and providing our Services to you, we may have access to personally identifiable information that is included in the data that you provide to us so that we can provide our Services for you. For example, we may have access to certain usernames that you use to login to third party services and websites and data that you store in your accounts with such third party services. We do not store or use such personally identifiable information other than as necessary to perform our Services and provide our Services to you.
+<br><br>We use your personally identifiable information for the purposes for which it was collected as set forth above and not for promotional purposes or for use by third parties for promotional purposes.
+<br><br>
+<h4>Cookies</h4>
+<br>
+We may use small text files called cookies to improve overall Site experience. A cookie is a piece of data stored on the user's hard drive containing information about the user. Cookies generally do not permit us to personally identify you.
+<br><br>We use third-party tracking services that uses cookies to track non-personally identifiable information about vi
+
+<br><br>
+<h4>Clear Gifs (Web Beacons/Web Bugs)</h4>
+<br>
+We employ a software technology called clear gifs (a.k.a. Web Beacons/Web Bugs), that help us better manage content on our Site by informing us what content is effective. Clear gifs are tiny graphics with a unique identifier, similar in function to cookies, and are used to track the online movements of Site users. In contrast to cookies, which are stored on a user’s computer hard drive, clear gifs are embedded invisibly on Web pages and are about the size of the period at the end of this sentence. We do not tie the information gathered by clear gifs to our customers’ personally identifiable information.
+
+<br><br>
+<h4>Blogs, Forums and Chartrooms</h4>
+<br>
+If you use a bulletin board, blog, or chat room on this Site, you should be aware that any personally identifiable information you submit there can be read, collected, or used by other users of these forums, and could be used to send you unsolicited messages. We are not responsible for the personally identifiable information you choose to submit in these forums.
+
+<br><br>
+<h4>Aggregate Information</h4>
+<br>
+The Site may track the total number of visitors to our Site, IP addresses, the number of visitors to each page of our Site and items clicked on our Site. Additionally, when we provide our Services to you, we may track aggregate and anonymous data that you provide to use to provide our Services to benchmark and improve our Services and ensure you are complying with the terms of your license from us. We may use this data in the aggregate, but such information will be maintained, used and disclosed in aggregate form only and it will not contain personally identifiable information. We may use such aggregate information to diagnose server problems, analyze trends, administer and improve the Site, track users' movement, and gather broad demographic information for aggregate use.
+
+<br><br>
+<h4>Onward Transfer</h4>
+<br>
+We may provide or provide access to your personally identifiable information and the data generated by cookies and the aggregate information to the vendors and service agencies that we may engage to assist us. For example, a consultant may have access to your personally identifiable information while the consultant is performing services on our behalf if the services require access to your systems. Such third parties are required to agree to a confidentiality agreement with us regarding your personally identifiable information and we only authorize them to use your personally identifiable information that they may have access to as necessary to perform services on our behalf and not for their own marketing purposes. We also may provide your personally identifiable information to our third party business service partners and they may use your personally identifiable information to send you marketing and promotional information. You may opt-out of having your information shared with our third party business service partners by emailing us at: <a href="mailto:security@appirio.com">security@appirio.com</a>.
+<br><br>As part of our provision of Services to you, you may request us to publish your data which may contain personally identifiable information on third party websites.
+<br><br>Other people will be able to view such data if such data is published on third party websites.
+<br><br>We will also disclose your personally identifiable information and the aggregate information if we reasonably believe we are required to do so by law, court order, warrant, subpoena, legal process or regulation or in cooperation with any governmental investigation. We may transfer your personally identifiable information and the aggregate information to a successor entity upon a merger, consolidation or other corporate reorganization in which Appirio participates or to a purchaser of all or substantially all of Appirio's assets to which this Site relates.
+
+<br><br>
+<h4>Children's Privacy</h4>
+<br>
+CloudSpokes recognizes the privacy interests of children and we encourage parents and guardians to take an active role in their children's online activities and interests. Neither our Site nor our services are intended for children under the age of 13. CloudSpokes does not target its services or this Site to children under 13. CloudSpokes does not knowingly collect personally identifiable information from children under the age of 13.
+
+<br><br>
+<h4>Access</h4>
+<br>
+You may correct, amend or delete your personally identifiable information that CloudSpokes stores, except where the burden or expense to CloudSpokes of providing access would be disproportionate to the risks to your privacy or where the legitimate rights of persons other than you would be violated. Please email <a href="mailto:security@appirio.com">security@appirio.com</a> to correct, amend or delete your personally identifiable information.
+
+<br><br>
+<h4>Links to Third Party Sites</h4>
+<br>
+The Site may provide links to other Web sites or resources over which CloudSpokes does not have control ("External Web Sites"). Such links do not constitute an endorsement by CloudSpokes of those External Web Sites. You acknowledge that the Site is providing these links to you only as a convenience, and further agree that neither CloudSpokes nor Appirio is not responsible for the content of such External Web Sites. Your use of External Web Sites and any products purchased on such External Web Sites is subject to the terms of use and privacy policies located on the linked to External Web Sites.
+
+<br><br>
+<h4>Security</h4>
+<br>
+We may employ procedural and technological security measures that are reasonably designed to help protect your personally identifiable information from loss, unauthorized access, disclosure, alteration or destruction. The Site may use encryption, password protection and other security measures to help prevent unauthorized access to your personally identifiable information.
+
+<br><br>
+<h4>Questions</h4>
+<br>
+If you have any questions regarding this Privacy Policy please contact us via email at <a href="mailto:security@appirio.com">security@appirio.com</a> or at:
+<br><br>
+2207 Bridgepoint Parkway<br>
+Suite 300<br>
+San Mateo, CA 94404<br>
+Tel: (650) 268-9911<br>
+Toll Free: (888) 680-SaaS (7227)<br>
+Effective Date 10/06/2009
+</div>
348 app/views/content/tos.html.erb
@@ -0,0 +1,348 @@
+<div class="page"><h1 id='heading' class='upcase'>Cloudspokes Community Terms of Service</h1>
+ <br>
+ <br>
+ <center>
+ <h2>
+ Acceptance of Terms.</h2>
+ </center>
+ <br>
+ <br>
+ <div style="padding-left: 50px;">
+ <p>
+ Appirio, Inc. ("Appirio" or "us" or "we") welcomes you to (and related sub-domains
+ (the "Website"). By using or accessing any part of the Website, you are agreeing
+ to these Terms of Service, and all other policies or notices posted by us on our
+ websites.</p>
+ <p>
+ If you do not agree to these Terms of Service, do not use the Website. We can change
+ these Terms of Service at any time without any notice to you. It is your responsibility
+ to review these Terms of Service from time to time for any changes as it creates
+ a binding legal agreement between you and Appirio. If you use the Website after
+ we have changed any of the Terms of Service, you are agreeing to all of the changes.
+ </p>
+ <p>
+ <b>Permission to Use the Website.</b>
+ </p><div style="padding-left: 20px;">
+ You have our permission to use the Website, but only if:
+ <ul>
+ <li>You are over 18 years old</li>
+ <li>You are using the Website for your own personal use and not for commercial purposes</li>
+ <li>You do not copy the Website (or any part of it)</li>
+ <li>You do not modify the Website (or any part of it)</li>
+ <li>You follow these Terms of Service</li>
+ </ul>
+ <br>
+ <b>Account; Passwords, Security.</b>
+ <p>
+ You may need to set up an account in order to use some of the features of the Website.
+ You may not use a third party's account without permission. When you are setting
+ up your account, you must give us accurate and complete information. This means
+ that you cannot set up an account using a name or contact information that does
+ not apply to you, and you must provide accurate and current information on all registration
+ forms that are part of the Website. You have complete responsibility for your account
+ and everything that happens on your account. This means you need to be careful with
+ your password. If you find out that someone is using your account without your permission,
+ you must let us know immediately. You may not transfer your account to someone else.
+ We are not liable for any damages or losses caused by someone using your account
+ without your permission. However, if we (or anyone else) suffer any damage due to
+ the unauthorized use of your account, you may be liable.
+ </p>
+ <b>Personal Use Only.</b>
+ <p>
+ We are making the Website available to you for your information and personal use
+ only. You may not (and you agree not to) use, copy, distribute, transmit, broadcast,
+ sell, or do anything else with the Website for any other purpose.
+ </p>
+ <b>User Content. </b>
+ <p>
+ You are solely responsible for any User Content you post to the Website, and the
+ consequences of posting or publishing it. By "User Content", we mean any Content
+ you post to the Website. "Content" means information, data, text, software, music,
+ sound, photos, graphics, videos, messages, tags, interactive features, or any other
+ materials. When we say "post", we include posting, uploading, sharing, submitting
+ or otherwise providing User Content in any manner in connection with the Website.
+ </p>
+ <b>Restrictions on User Content and Your Conduct </b>
+ <p>
+ You may not:
+ </p><ul>
+ <li>Use our Website for any illegal purpose</li>
+ <li>Submit User Content that you don’t have the right to submit (including but not
+ limited to material covered by someone else’s copyright, patent, trade secret, privacy
+ policy, publicity policy, or any other proprietary pright</li>
+ <li>Disguise in any way the origin of any User Content you submit (including but not
+ limited to forging headers)</li>
+ <li>Submit any User Content that contains lies or misrepresentations that could damage
+ Us or anyone else</li>
+ <li>Submit User Content that is obscene, illegal, defamatory, libelous, threatening,
+ pornographic, harassing, hateful, or encourages criminal conduct, give rise to civil
+ liability, violate any law, or is otherwise inappropriate</li>
+ <li>Transmit any advertising, promotional materials, junk mail, spam, chain letters,
+ pyramid schemes or any other solicitation</li>
+ <li>Impersonate anyone else or misrepresent your affiliation with any other person or
+ entity</li>
+ <li>Use meta tage or any other hidden text utilizing any of our or our suppliers’ names,
+ products names, or trademarks</li>
+ <li>Upload, launch, post email or transmit any material (including any bot, worm, spider,
+ script, or virus) that may harm or corrupt this Website, or anyone else’s computer
+ systems or data</li>
+ <li>Use our Website to harm minors in any way</li>
+ <li>Collect or gather other people’s personal information (including account information)</li>
+ <li>Submit User Content that disparages us or our partners and affiliates</li>
+ <li>Solicit any users of our Website for any commercial purpose</li>
+ </ul>
+ <p>
+ We have the sole right, but not necessarily the obligation, to delete at any time
+ any User Content that violates these rules or that we believe to be inappropriate
+ for any reason.</p>
+ <p></p>
+ <b>Intellectual Property Rights in User Content.</b>
+ <p>
+ If you post User Content, you are making a guarantee to us that you either own all
+ the Content you are posting, or you have the right to post the Content. Furthermore,
+ you are guaranteeing that you have the right to allow us to make your User Content
+ available for others to view and use as part of the Website without requiring that
+ any such use be subject to additional obligations or terms. If you do not have these
+ rights, do not post the Content. By posting your User Content, you do not lose any
+ ownership rights you may have to it. However, unless otherwise governed by a specific
+ contest’s rules, you do grant us a worldwide, irrevocable, non-exclusive, royalty-free,
+ fully-paid, sublicenseable (through multiple tiers of distribution) and transferable
+ license to use, reproduce, modify, distribute, prepare derivative works of, display,
+ and perform your User Content in connection with the Website and our business, in
+ any media formats or in tangible form and through any media channels now known or
+ hereinafter developed. You also grant each user of the Website a non-exclusive royalty-free,
+ fully-paid, sublicenseable and transferable license to access your User Content
+ through the Website, and to use, reproduce, distribute, prepare derivative works
+ of, display and perform your User Content as permitted through the functionality
+ of the Website and under these Terms of Service.
+ </p>
+ <b>User Content you Share becomes Public.</b>
+ <p>
+ You understand that once you post User Content, your content becomes public. We
+ are not responsible for keeping any User Content confidential.
+ </p>
+ <b>We are Not Responsible for User Content.</b>
+ <p>
+ We generally do not review any of the User Content posted by our users. We do not
+ endorse any User Content or support any views, opinions, recommendations, or advice
+ that may be in user submissions. User Content comes from a variety of sources, and
+ we make no promises about the reliability of any source or the accuracy, usefulness,
+ safety, or intellectual property rights of any user submission. You may be offended
+ by User Content that you see on the Website. You may find some of it to be inaccurate,
+ offensive, indecent, or objectionable. However, you agree not to hold us responsible
+ in any way for your use of our Website, including your exposure to User Content.
+ </p>
+ <b>Proprietary Rights.</b>
+ <p>
+ Appirio and its suppliers retain all right, title and interest (including all copyright,
+ trade secret, patent and other rights) in and to the Website and Content which is
+ included in the Website (other than User Content, which is treated separately above).
+ If you give feedback on the Website, for example recommendations for improvements
+ or features, such feedback will be deemed non-confidential and non-proprietary,
+ and implementation of that feedback is owned by us and may become part of the Website
+ without compensation to you. We reserve all rights in and to the Website unless
+ we expressly state otherwise. The Website contains proprietary and confidential
+ information that is protected by applicable intellectual property and other laws.
+ </p>
+ <p>
+ You may not decompile, reverse engineer, disassemble, or otherwise reduce the Website
+ to a human-perceivable form, except and only to the extent that such activity is
+ expressly permitted by applicable law, and in that case, only if you notify us in
+ writing in advance. You may not copy, frameset, enclose or otherwise distribute
+ any part of the Website.</p>
+ <p>
+ All brand, product and service names used in the Website which identify Appirio
+ or our suppliers and our or their proprietary products and services are the trademarks
+ or service marks of Appirio or our suppliers. Nothing in the Website shall be deemed
+ to confer on any person any license or right on the part of Appirio or such supplier
+ with respect to any such image, logo or name.</p>
+ <p>
+ You agree not to disable, interfere, or try to get around any of the features of
+ the Website related to security, preventing or restricting use or copying of any
+ Content, or enforcing the limits on the use of the Website or the Content on the
+ Website.
+ </p>
+ <b>Enforcement of Copyrights.</b>
+ <p>
+ We respect the intellectual property rights of others. You may not use our Website
+ to infringe anyone else's copyright or other intellectual property right. If we
+ find out that you are infringing, we will remove your User Content. We do not have
+ to give you notice that we are removing your User Content. We may also terminate
+ your account if we decide that you are a repeat infringer. We consider a repeat
+ infringer to be a user who has been notified of infringing activity more than twice
+ or who has had User Content removed from our Website more than twice.
+ </p>
+ <b>Notify Us of Infringers</b>
+ <p>
+ If you believe that something on our Website violates your copyright, notify our
+ copyright agent in writing. The contact information for our copyright agent is at
+ the bottom of this section.</p>
+ <p>
+ In order for us to take action, you must do the following in your notice:</p>
+ <ul>
+ <li>provide your physical or electronic signature;</li>
+ <li>identify the copyrighted work that you believe is being infringed;</li>
+ <li>identify the item on our Website that you think is infringing your work and include
+ sufficient information about where the material is located on our Website (including
+ which website) so that we can find it;</li>
+ <li>provide us with a way to contact you, such as your address, telephone number, or
+ e-mail;</li>
+ <li>provide a statement that you believe in good faith that the item you have identified
+ as infringing is not authorized by the copyright owner, its agent, or the law to
+ be used on our Website; and</li>
+ <li>provide a statement that the information you provide in your notice is accurate,
+ and that (under penalty of perjury), you are authorized to act on behalf of the
+ copyright owner whose work is being infringed.</li>
+ <li>Here is the contact information for our copyright agent: GC@appirio.com</li>
+ </ul>
+ <p>
+ Again, we cannot take action unless you give us all the required information.</p>
+ <b>How to Communicate with Us. </b>
+ <p>
+ Only notices about copyright infringement should go to our copyright enforcement
+ department. If you have anything else to communicate with us (like feedback, comments,
+ requests for technical support), you should contact us through our customer service
+ department at [email address]
+ </p>
+ <b>Storage and Availability. </b>
+ <p>
+ We are not a content-archiving service. We do not promise to store or make available
+ on our Website any User Content that you submit, or any other Content, for any length
+ of time. You are solely responsible for keeping back-ups of everything you post
+ on our Website.</p>
+ <p>
+ You acknowledge that temporary interruptions in the availability of the Website
+ may occur from time to time as normal events. Also, we may decide to cease making
+ available the Website or any portion of the Website at any time and for any reason.
+ Under no circumstances will Appirio or its suppliers be held liable for any damages
+ due to such interruptions or lack of availability.</p>
+ <b>Sale of Products</b>
+ <p>
+ We may offer you for sale or download certain Appirio products or services ("Products").
+ Your use of such Products will be subject to licensing terms applicable to such
+ Products, or a separate written agreement between you and Appirio.
+ </p>
+ <b>Links to Other Sites.</b>
+ <p>
+ Our Website may contain links to other websites that we do not own or control. We
+ are not responsible for any of these other websites and any links to these other
+ websites should not be interpreted as an endorsement of any company, content or
+ products. You will not hold us responsible for any aspect of these other websites,
+ including their content, privacy policies, or anything else. You may be exposed
+ to things on other websites that you do not like or that you find offensive. We
+ are not responsible for this, either. You must use your own discretion when you
+ go to other websites. You should also read the terms and conditions and privacy
+ policies of these other websites.
+ </p>
+ <b>Warranty Disclaimer.</b>
+ <p>
+ USE OF THE WEBSITE IS AT YOUR OWN RISK. THE WEBSITE IS PROVIDED ON A "AS IS" AND
+ "AS AVAILABLE" BASIS. APPIRIO AND ITS AFFILIATES, SUPPLIERS AND PARTNERS EXPRESSLY
+ DISCLAIM ALL WARRANTIES OF ANY KIND, WHETHER EXPRESS OR IMPLIED, INCLUDING, BUT
+ NOT LIMITED TO, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A
+ PARTICULAR PURPOSE AND NON-INFRINGEMENT.</p>
+ <p>
+ APPIRIO AND ITS AFFILIATES, SUPPLIERS AND PARTNERS MAKE NO WARRANTY THAT (i) THE
+ WEBSITE OR ANY PRODUCTS PURCHASED THROUGH THE WEBSITE WILL MEET YOUR REQUIREMENTS;
+ (ii) THE WEBSITE WILL BE UNINTERRUPTED, TIMELY, SECURE OR ERROR-FREE; OR (iii) THAT
+ THERE WILL BE NO ERRORS IN THE WEBSITE OR THAT APPIRIO WILL FIX ANY ERRORS. ANY
+ MATERIALS OBTAINED THROUGH USE OF THE WEBSITE ARE OBTAINED AT YOUR OWN DISCRETION
+ AND RISK AND APPIRIO SHALL NOT BE RESPONSIBLE FOR ANY DAMAGE CAUSED TO YOUR COMPUTER
+ OR DATA OR FOR ANY BUGS, VIRUSES, TROJAN HORSES OR OTHER DESTRUCTIVE CODE RESULTING
+ FROM USE OF THE WEBSITE OR ANY CONTENT OBTAINED FROM THE WEBSITE.</p>
+ <p>
+ SOME STATES DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION
+ MAY NOT APPLY TO YOU. YOU MAY ALSO HAVE OTHER LEGAL RIGHTS, WHICH VARY FROM STATE
+ TO STATE.</p>
+ <b>Limitation of Liability.</b>
+ <p>
+ TO THE FULLEST EXTENT PERMITTED UNDER LAW, APPIRIO AND ITS AFFILIATES, SUPPLIERS
+ AND PARTNERS HAVE NO OBLIGATION OR LIABILITY (WHETHER ARISING IN CONTRACT, WARRANTY,
+ TORT (INCLUDING NEGLIGENCE), PRODUCT LIABILITY OR OTHERWISE) FOR ANY INDIRECT, INCIDENTAL,
+ SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES OR LIABILITIES (INCLUDING, BUT NOT LIMITED
+ TO, ANY LOSS OF DATA, REVENUE OR PROFIT) ARISING FROM OR RELATED TO YOUR USE OF
+ THE WEBSITE OR ANY CONTENT PROVIDED BY OR THROUGH THE WEBSITE, EVEN IF WE HAVE BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGES IN ADVANCE, AND NOTWITHSTANDING ANY FAILURE
+ OF ESSENTIAL PURPOSE OF ANY KIND. THE FOREGOING LIMITATION APPLIES TO DAMAGES ARISING
+ FROM (I) YOUR USE OR INABILITY TO USE OUR WEBSITE; (II) COST OF PROCUREMENT OF SUBSTITUTE
+ GOODS AND SERVICES RESULTING FROM ANY GOODS OR SERVICES PURCHASED THROUGH OR FROM
+ OUR WEBSITE; (III) UNAUTHORIZED ACCESS TO OR ALTERATION OF YOUR USER CONTENT; (IV)
+ THIRD PARTY CONTENT MADE AVAILABLE TO YOU THROUGH THE WEBSITE; OR (V) ANY OTHER
+ MATTER RELATING TO THE WEBSITE.
+ </p>
+ <p>
+ NOTWITHSTANDING ANYTHING TO THE CONTRARY CONTAINED HEREIN, APPIRIO'S LIABILITY AND
+ THE LIABILITY OF EACH OF ITS OFFICERS, DIRECTORS, INVESTORS, EMPLOYEES, AGENTS,
+ ADVERTISERS, LICENSORS, SUPPLIERS, SERVICE PROVIDERS AND OTHER CONTRACTORS TO YOU
+ OR ANY THIRD PARTIES UNDER ANY CIRCUMSTANCE IS LIMITED TO A MAXIMUM AMOUNT OF $100.
+ </p>
+ <b>Indemnity.</b>
+ <p>
+ You agree to indemnify and hold harmless Appirio and its affiliates, suppliers,
+ partners, officers, agents, and employees from and against any claim, demand, losses,
+ damages or expenses (including reasonable attorney's fees) arising from any User
+ Content, your use of the Website, your connection to the Website, your violation
+ of these Terms of Service or your violation of any rights of any third-party. Your
+ indemnification obligation will survive the termination of these Terms of Service
+ and your use of the Website.</p>
+ <b>Termination and Suspension.</b>
+ <p>
+ We may terminate or suspend the Website or any part of the Website, terminate or
+ suspend your use of the Website, block any IP address, or remove any of your User
+ Content at any time without cause without any liability to you.
+ </p>
+ <p>
+ Further, we may terminate or suspend your permission to use the Website immediately
+ and without notice upon any violation of these Terms of Service, your failure to
+ pay any fees when due, upon the request of law enforcement or government agencies,
+ for extended periods of inactivity, for unexpected technical issues or problems
+ or for engagement by you in fraudulent or illegal activities. If we terminate your
+ use of the Website for any of these reasons or otherwise for cause, we will not
+ refund any fees you may have paid, whether for access to the Website or for Products
+ (if applicable).</p>
+ <p>
+ Upon any termination we may delete your account, passwords and User Content, and
+ we may bar you from further use of the Website. You understand that we may also
+ continue to make your User Content available on the Website even if your use of
+ the Website is terminated or suspended. You agree that we will have no liability
+ to you or any third party for termination of your account or access to the Website.</p>
+ <b>Export Control.</b>
+ <p>
+ You may not use, export or re-export any Content or any copy or adaptation of such
+ Content, or any product or service offered on the Website, in violation of any applicable
+ laws or regulations, including, without limitation, United States export laws and
+ regulations.
+ </p>
+ <b>Additional Terms.</b>
+ <p>
+ Portions of the Website may be accompanied by additional terms which apply to specific
+ features or areas of the Website. Those additional terms supplement these terms
+ with respect to your use of those features or areas.</p>
+ <b>General Terms.</b>
+ <p>
+ These Terms of Service are governed by laws of the state of California, without
+ regard to its conflict of laws rules. The sole jurisdiction and venue for any claim
+ arising from the Website and these Terms of Service shall be the state and federal
+ courts located in San Mateo, California and each party hereby consents to the exclusive
+ jurisdiction and venue of such courts. These Terms of Service, together with our
+ Privacy Policy and any other legal notices we have published on the Website, constitute
+ the entire agreement between you and us regarding this Website. If a court having
+ proper authority decides that any portion of these Terms of Service is invalid,
+ only the part that is invalid will not apply. The rest of these Terms of Service
+ will still be in effect. If we waive any of our rights under these Terms of Service
+ in any particular instance, it does not mean that we are waiving our rights generally
+ or in the future. Furthermore, just because we may not enforce all our rights all
+ of the time, it does not mean that we are waiving our rights. We may decide to enforce
+ them at a later date. These Terms of Service, and any rights and licenses granted
+ under these Terms of Service, may not be transferred or assigned by you, but may
+ be assigned by us without restriction.
+ </p>
+ <p>
+ </p><div style="text-transform: uppercase">
+ YOU AGREE THAT IF YOU WANT TO SUE US, YOU MUST FILE YOUR LAWSUIT WITHIN ONE YEAR
+ AFTER THE EVENT THAT GAVE RISE TO YOUR LAWSUIT. OTHERWISE, YOUR LAWSUIT WILL BE
+ PERMANENTLY BARRED.</div>
+ </div>
+ <p></p>
+ </div>
+ </div>
56 app/views/layouts/application.html.erb
@@ -0,0 +1,56 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>CloudSpokes</title>
+ <link href='http://fonts.googleapis.com/css?family=Marvel:400,400italic,700,700italic' rel='stylesheet' type='text/css'>
+ <%= stylesheet_link_tag "application" %>
+ <%= javascript_include_tag "application" %>
+ <%= csrf_meta_tags %>
+</head>
+<body id="<%= controller.controller_name %>_<%= controller.action_name %>" class="<%= controller.controller_name %>">
+ <div id='wrapper'>
+ <header id='top'>
+ <h1 id='logo'><%= link_to "CloudSpokes", "/" %></h1>
+ <nav id='menu'><ul>
+ <li><%= link_to "Members", "#" %></li>
+ <li><%= link_to "Challenges", "/challenges/index" %></li>
+ <li><%= link_to "Badges", "#" %></li>
+ <li><%= link_to "Account", "#" %></li>
+ </ul></nav>
+ <nav id='side_menu'><ul>
+ <li><%= link_to "How it Works", content_path("about") %></li>
+ <li><%= link_to "Blog", "http://blog.cloudspokes.com/" %></li>
+ <li><%= link_to "FAQ", content_path("faq") %></li>
+ </ul></nav>
+ </header>
+ <section id='content'>
+ <% flash.each do |key, value| %>
+ <div class="flash <%= key %>"><%= value %></div>
+ <% end %>
+ <%= yield %>
+ </section>
+ <footer id='bottom'>
+ <aside class='left'>
+ <span class='attribution'>created by <%= link_to "Appirio", "http://www.appirio.com/" %></span>
+ <nav class='social_links'><ul>
+ <li><%= link_to s3_image("icon-digg.gif"), "http://digg.com/CloudSpokes", target: '_blank' %></li>
+ <li><%= link_to s3_image("icon-delicious.gif"), "http://delicious.com/cloudspokes", target: '_blank' %></li>
+ <li><%= link_to s3_image("icon-technorati.gif"), "http://technorati.com/people/cloudspokes", target: '_blank' %></li>
+ <li><%= link_to s3_image("icon-twitter.gif"), "http://twitter.com/cloudspokes", target: '_blank' %></li>
+ <li><%= link_to s3_image("icon-facebook.gif"), "http://www.facebook.com/CloudSpokes", target: '_blank' %></li>
+ </ul></nav>
+ </aside>
+ <nav class='right'><ul>
+ <li><%= link_to "Privacy", content_path("privacy") %></li>
+ <li><%= link_to "Terms", content_path("tos") %></li>
+ <% if current_user.nil? %>
+ <li><%= link_to "Login", "/login" %></li>
+ <% else %>
+ <li><%= link_to "Logout", "/logout" %></li> (<%= current_user.username %>)
+ <% end %>
+ </ul></nav>
+ </footer>
+ </div>
+ <%= debug(params) if Rails.env.development? %>
+</body>
+</html>
40 app/views/sessions/login.html.erb
@@ -0,0 +1,40 @@
+<a href="/auth/twitter" class="auth_provider">
+ <%= image_tag "twitter_64.png", :size => "64x64", :alt => "Twitter" %>
+ Twitter
+</a>
+<a href="/auth/github" class="auth_provider">
+ <%= image_tag "github_64.png", :size => "64x64", :alt => "GitHub" %>
+ GitHub
+</a>
+<% if Rails.env.production? %>
+ <a href="/auth/facebook" class="auth_provider">
+ <%= image_tag "facebook_64.png", :size => "64x64", :alt => "Facebook" %>
+ Facebook
+ </a>
+<% else %>
+ <%= image_tag "facebook_64.png", :size => "64x64", :alt => "Facebook" %>
+ Facebook
+<% end %>
+
+<% if Rails.env.development? %>
+
+ <a href="/auth/google_apps" class="auth_provider">
+ <%= image_tag "google_64.png", :size => "64x64", :alt => "Google" %>
+ Google
+ </a>
+ <a href="/auth/linkedin" class="auth_provider">
+ <%= image_tag "linkedin_64.png", :size => "64x64", :alt => "LinkedIn" %>
+ LinkedIn
+ </a>
+ <a href="/auth/open_id" class="auth_provider">
+ <%= image_tag "openid_64.png", :size => "64x64", :alt => "OpenID" %>
+ OpenID
+ </a>
+ <a href="/auth/salesforce" class="auth_provider">
+ <%= image_tag "salesforce_64.png", :size => "64x64", :alt => "salesforce.com" %>
+ salesforce.com
+ </a> <%= "(localhost)" if Rails.env.development? %>
+
+<% end %>
+
+<p>Or you can <a href="/signin">login</a> or <a href="/signup">signup</a>.</p>
15 app/views/sessions/new.html.erb
@@ -0,0 +1,15 @@
+<h1>Sign in</h1>
+
+<%= form_for(:session, :url => sessions_path) do |f| %>
+ <div class="field">
+ <%= f.label :username %><br />
+ <%= f.text_field :username %>
+ </div>
+ <div class="field">
+ <%= f.label :password %><br />
+ <%= f.password_field :password %>
+ </div>
+ <div class="actions">
+ <%= f.submit "Sign in" %>
+ </div>
+<% end %>
1 app/views/sessions/signup_third_party_create.html.erb
@@ -0,0 +1 @@
+error!
17 app/views/sessions/signup_third_party_no_email.html.erb
@@ -0,0 +1,17 @@
+<h1>Sign in Third Party - No Email</h1>
+
+<p>Unfortunately <b><%= session[:authsession].get_hash[:provider]%></b> doesn't provide us with your email address. Please enter it.</p>
+
+<%= form_for(:session, :url => 'signup_third_party_create') do |f| %>
+ <div class="field">
+ <%= f.label :email %><br />
+ <%= f.text_field :email, :value => session[:authsession].get_hash[:email] %>
+ </div>
+ <div class="actions">
+ <%= f.submit "Sign in" %>
+ </div>
+<% end %>
+
+<hr>
+
+<%= debug session[:authsession] %>
1 app/views/test/auth_cloudspokes.html.erb
@@ -0,0 +1 @@
+<%= debug @results %>
0 app/views/test/auth_thirdparty.html.erb
No changes.
3 app/views/test/get_current_access_token.html.erb
@@ -0,0 +1,3 @@
+<p>Log in and out to see different values</p>
+
+<%= debug @results %>
10 app/views/test/index.html.erb
@@ -0,0 +1,10 @@
+<h1>Tests</h1>
+
+<ul>
+ <li><a href="auth_cloudspokes">Authenticate - CloudSpokes</a> (user)
+ <li><a href="auth_thirdparty">Authenticate - Third Party</a> (user)
+ <li><a href="get_current_access_token">Get current_access_token</a> (application controller)
+ <li><a href="/new_public_token">Get a new_public_token</a> (application controller)
+ <li><a href="service_sfdc_username">Test getting sfdc username from third party credentials</a> (service)
+ <li><a href="service_new_member_cloudsppokes">Create a new member with cloudspokes credentails</a>. Will always return duplicate user. (service)
+</ul>
1 app/views/test/service_new_member_cloudsppokes.html.erb
@@ -0,0 +1 @@
+<%= debug @results %>
1 app/views/test/service_sfdc_username.html.erb
@@ -0,0 +1 @@
+<%= debug @results %>
23 app/views/users/new.html.erb
@@ -0,0 +1,23 @@
+<h1>Sign up - CloudSpokes</h1>
+
+<%= form_for(@user) do |f| %>
+ <div class="field">
+ <%= f.label :username %><br />