openstax_connect 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +70 -0
  3. data/Rakefile +49 -0
  4. data/app/algorithms/openstax/connect/search_users.rb +47 -0
  5. data/app/assets/javascripts/openstax/connect/application.js +15 -0
  6. data/app/assets/javascripts/openstax/connect/sessions.js +2 -0
  7. data/app/assets/stylesheets/openstax/connect/application.css +13 -0
  8. data/app/assets/stylesheets/openstax/connect/dev.css.scss +31 -0
  9. data/app/assets/stylesheets/openstax/connect/sessions.css +4 -0
  10. data/app/controllers/openstax/connect/application_controller.rb +9 -0
  11. data/app/controllers/openstax/connect/dev/dev_controller.rb +16 -0
  12. data/app/controllers/openstax/connect/dev/sessions_controller.rb +21 -0
  13. data/app/controllers/openstax/connect/dev/users_controller.rb +28 -0
  14. data/app/controllers/openstax/connect/sessions_controller.rb +44 -0
  15. data/app/handlers/openstax/connect/dev/users_create.rb +31 -0
  16. data/app/handlers/openstax/connect/dev/users_generate.rb +36 -0
  17. data/app/handlers/openstax/connect/dev/users_search.rb +64 -0
  18. data/app/handlers/openstax/connect/sessions_omniauth_authenticated.rb +35 -0
  19. data/app/helpers/openstax/connect/application_helper.rb +20 -0
  20. data/app/helpers/openstax/connect/sessions_helper.rb +4 -0
  21. data/app/models/anonymous_user.rb +40 -0
  22. data/app/models/user.rb +21 -0
  23. data/app/views/layouts/openstax/connect/application.html.erb +14 -0
  24. data/app/views/openstax/connect/dev/users/index.html.erb +31 -0
  25. data/app/views/openstax/connect/dev/users/search.js.erb +21 -0
  26. data/app/views/openstax/connect/sessions/create.html.erb +10 -0
  27. data/app/views/openstax/connect/shared/_attention.html.erb +3 -0
  28. data/app/views/openstax/connect/users/_action_create_form.html.erb +9 -0
  29. data/app/views/openstax/connect/users/_action_dialog.html.erb +10 -0
  30. data/app/views/openstax/connect/users/_action_list.html.erb +33 -0
  31. data/app/views/openstax/connect/users/_action_search.html.erb +25 -0
  32. data/app/views/openstax/connect/users/action_search.js.erb +8 -0
  33. data/config/initializers/02_extend_builtins.rb +48 -0
  34. data/config/routes.rb +32 -0
  35. data/db/migrate/20130729213800_create_users.rb +9 -0
  36. data/db/migrate/20130909215452_add_fields_to_user.rb +11 -0
  37. data/lib/omniauth/strategies/openstax.rb +28 -0
  38. data/lib/openstax/connect/action_list.rb +40 -0
  39. data/lib/openstax/connect/engine.rb +34 -0
  40. data/lib/openstax/connect/route_helper.rb +34 -0
  41. data/lib/openstax/connect/utilities.rb +12 -0
  42. data/lib/openstax/connect/version.rb +5 -0
  43. data/lib/openstax_connect.rb +72 -0
  44. data/lib/tasks/connect-rails_tasks.rake +4 -0
  45. metadata +191 -0
@@ -0,0 +1,31 @@
1
+
2
+ <% handler_errors.each do |error| %>
3
+ <%= error.translate %>
4
+ <% end %>
5
+
6
+ <%= osu_section_block "Register a new user" do %>
7
+
8
+
9
+ <%= lev_form_for :register, url: dev_users_create_path do |f| %>
10
+
11
+ First name <%= f.text_field :first_name %><br/>
12
+ Last name <%= f.text_field :last_name %><br/>
13
+ Username <%= f.text_field :username %><br/>
14
+ Admin? <%= f.check_box :is_administrator %><br/>
15
+
16
+ <%= submit_tag 'Register' %>
17
+ <% end %>
18
+
19
+ <% end %>
20
+
21
+ <%= osu_section_block "Generate new users" do %>
22
+ <%= lev_form_for :generate, url: dev_users_generate_path do |f| %>
23
+ Generate <%= f.text_field :count, style: 'width:30px' %> user(s) <%= submit_tag 'Do it now!' %>
24
+ <% end %>
25
+ <% end %>
26
+
27
+ <%= osu_section_block "Login as an existing user" do %>
28
+
29
+ <%= render 'openstax/connect/users/action_search', action_search_path: dev_users_search_path %>
30
+
31
+ <% end %>
@@ -0,0 +1,21 @@
1
+
2
+ <%= render template: 'openstax/connect/users/action_search',
3
+ locals: {
4
+ users: @results[:users],
5
+ list: OpenStax::Connect::ActionList.new(
6
+ headings: ['First Name', 'Last Name', 'Username', ''],
7
+ widths: ['25%', '25%', '25%', '25%'],
8
+ data_procs:
9
+ [
10
+ Proc.new { |user| user.first_name },
11
+ Proc.new { |user| user.last_name },
12
+ Proc.new { |user| user.username },
13
+ Proc.new { |user|
14
+ link_to 'Sign in as',
15
+ sessions_become_path(:user_id => user.id),
16
+ method: :post
17
+ }
18
+ ]
19
+ )
20
+ }
21
+ %>
@@ -0,0 +1,10 @@
1
+ <h1>Sessions#create</h1>
2
+ <p>Find me in app/views/openstax/connect/sessions/create.html.erb</p>
3
+
4
+ <hr/>
5
+
6
+ <%= request.env['omniauth.auth'] %>
7
+
8
+ <hr/>
9
+
10
+ <%= session.inspect %>
@@ -0,0 +1,3 @@
1
+ <% handler_errors.each do |error| %>
2
+ <%= error.translate %>
3
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <%# Copyright 2011-2012 Rice University. Licensed under the Affero General Public
2
+ License version 3 or later. See the COPYRIGHT file for details. %>
3
+
4
+ <%# Callers must supply a 'user' local variable %>
5
+
6
+ <%= form_for target, :method => :post, :remote => true do |f| %>
7
+ <%= f.hidden_field :user_id, :value => user.id %>
8
+ <%= f.submit "Add", :onclick => please_wait_js %>
9
+ <% end %>
@@ -0,0 +1,10 @@
1
+ <%# Copyright 2011-2012 Rice University. Licensed under the Affero General Public
2
+ License version 3 or later. See the COPYRIGHT file for details. %>
3
+
4
+ <div id="user_action_dialog" style="display:none" title="<%= @action_dialog_title %>">
5
+ <div id="user_action_dialog_errors"></div>
6
+
7
+ <%= render :partial => 'users/action_search',
8
+ :locals => { :action_search_path => @action_search_path } %>
9
+
10
+ </div>
@@ -0,0 +1,33 @@
1
+ <%# Copyright 2011-2012 Rice University. Licensed under the Affero General Public
2
+ License version 3 or later. See the COPYRIGHT file for details. %>
3
+
4
+ <%
5
+ users ||= []
6
+ %>
7
+
8
+ <% if list.num_columns > 0 %>
9
+ <table class="list" width="100%">
10
+ <% if list.has_headings? %>
11
+ <tr>
12
+ <% for ii in 0..list.num_columns - 1 %>
13
+ <th><%= list.get_heading(ii) %></th>
14
+ <% end %>
15
+ </tr>
16
+ <% end %>
17
+
18
+ <% if users.empty? %>
19
+ <tr>
20
+ <td colspan="<%= list.num_columns %>">No results</td>
21
+ </tr>
22
+ <% else %>
23
+ <% users.all.each_with_index do |user, uu| %>
24
+ <tr>
25
+ <% for cc in 0..list.num_columns - 1 %>
26
+ <% width = uu == 0 ? list.get_width(cc) : nil %>
27
+ <td <%= "width=#{width}" if width %>><%= list.get_data(cc, user) %></td>
28
+ <% end %>
29
+ </tr>
30
+ <% end %>
31
+ <% end %>
32
+ </table>
33
+ <% end %>
@@ -0,0 +1,25 @@
1
+ <%# Copyright 2011-2012 Rice University. Licensed under the Affero General Public
2
+ License version 3 or later. See the COPYRIGHT file for details. %>
3
+
4
+ <%
5
+ # Clients of this partial must supply the following variables:
6
+ # action_search_path
7
+ %>
8
+
9
+ <div id="action-search-errors"></div>
10
+
11
+ <%= lev_form_for :search,
12
+ url: action_search_path,
13
+ id: 'action_search_form',
14
+ remote: true do |f| %>
15
+
16
+ Search for
17
+ <%= f.text_field :search_terms, style: 'width:300px' %>
18
+ in
19
+ <%= f.select :search_type, options_for_select(['Any', 'Name', 'Username']) %>
20
+
21
+ <%= submit_tag 'Search' %>
22
+
23
+ <% end %>
24
+
25
+ <div id="action-search-results-list"></div>
@@ -0,0 +1,8 @@
1
+ <%= unless_errors errors_html_id: (errors_html_id ||= 'action-search-errors') do %>
2
+ <% contents = render 'openstax/connect/users/action_list',
3
+ users: users,
4
+ list: list %>
5
+
6
+ $("#action-search-results-list").html("<%= j(contents) %>");
7
+ <% end %>
8
+
@@ -0,0 +1,48 @@
1
+ class ActionController::Base
2
+ # References:
3
+ # http://railscasts.com/episodes/356-dangers-of-session-hijacking
4
+
5
+ # Always return an object
6
+ def current_user
7
+ if !request.ssl? || cookies.signed[:secure_user_id] == "secure#{session[:user_id]}"
8
+ @current_user ||= AnonymousUser.instance
9
+
10
+ if @current_user.is_anonymous? && session[:user_id]
11
+ # Use current_user= to clear out bad state if any
12
+ self.current_user = User.where(id: session[:user_id]).first
13
+ end
14
+
15
+ @current_user
16
+ end
17
+ end
18
+
19
+ def current_user=(user)
20
+ @current_user = user || AnonymousUser.instance
21
+ if user.is_anonymous?
22
+ session[:user_id] = nil
23
+ cookies.delete(:secure_user_id)
24
+ else
25
+ session[:user_id] = user.id
26
+ cookies.signed[:secure_user_id] = {secure: true, value: "secure#{user.id}"}
27
+ end
28
+ @current_user
29
+ end
30
+
31
+ def sign_in(user)
32
+ self.current_user = user
33
+ end
34
+
35
+ def sign_out!
36
+ self.current_user = AnonymousUser.instance
37
+ end
38
+
39
+ def signed_in?
40
+ !current_user.is_anonymous?
41
+ end
42
+
43
+ protected
44
+
45
+ helper_method :current_user, :current_user=, :signed_in?
46
+
47
+ end
48
+
data/config/routes.rb ADDED
@@ -0,0 +1,32 @@
1
+ OpenStax::Connect::Engine.routes.draw do
2
+ match '/auth/openstax/callback', to: 'sessions#omniauth_authenticated' #omniauth route
3
+ get '/auth/openstax', :as => 'openstax_login'
4
+ get 'sessions/new', :as => 'login'
5
+ post 'sessions/become'
6
+
7
+ # See https://github.com/plataformatec/devise/commit/f3385e96abf50e80d2ae282e1fb9bdad87a83d3c
8
+ match 'sessions/destroy', :as => 'logout', :via => OpenStax::Connect.configuration.logout_via
9
+
10
+ if OpenStax::Connect.configuration.enable_stubbing?
11
+ namespace :dev do
12
+ # get 'sessions/new'
13
+ # post 'sessions/create'
14
+ # post 'sessions/search'
15
+ get 'users', to: 'users#index'
16
+ post 'users/create'
17
+ post 'users/generate'
18
+ post 'users/search'
19
+ end
20
+ end
21
+ end
22
+
23
+
24
+ module OpenStax
25
+ module Connect
26
+ hh = Engine.routes.url_helpers
27
+
28
+ RouteHelper.register_path(:login, hh.openstax_login_path) { hh.dev_users_path }
29
+ end
30
+ end
31
+
32
+
@@ -0,0 +1,9 @@
1
+ class CreateUsers < ActiveRecord::Migration
2
+ def change
3
+ create_table :users do |t|
4
+ t.integer :openstax_uid
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ class AddFieldsToUser < ActiveRecord::Migration
2
+ def change
3
+ add_column :users, :first_name, :string
4
+ add_column :users, :last_name, :string
5
+ add_column :users, :username, :string
6
+ add_column :users, :is_administrator, :boolean, :default => false
7
+
8
+ add_index :users, :openstax_uid, :unique => true
9
+ add_index :users, :username, :unique => true
10
+ end
11
+ end
@@ -0,0 +1,28 @@
1
+ require 'omniauth'
2
+ require 'omniauth-oauth2'
3
+
4
+ module OmniAuth
5
+ module Strategies
6
+ class Openstax < OAuth2
7
+ option :name, "openstax"
8
+
9
+ option :client_options, {
10
+ :site => OpenStax::Connect.configuration.openstax_services_url,
11
+ :authorize_url => "/oauth/authorize"
12
+ }
13
+
14
+ uid { raw_info["uid"] }
15
+
16
+ info do
17
+ {
18
+ :username => raw_info["username"]
19
+ # and anything else you want to return to your API consumers
20
+ }
21
+ end
22
+
23
+ def raw_info
24
+ @raw_info ||= access_token.get('/api/v1/me.json').parsed
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,40 @@
1
+ module OpenStax::Connect
2
+ class ActionList
3
+
4
+ def initialize(options={})
5
+ @options = options
6
+
7
+ raise IllegalArgument, "must supply data procs" if options[:data_procs].nil?
8
+
9
+ if options[:headings].present? && options[:data_procs].size != options[:headings].size
10
+ raise IllegalArgument, "if you supply headings, you must supply one for each column"
11
+ end
12
+
13
+ if options[:widths].present? && options[:data_procs].size != options[:widths].size
14
+ raise IllegalArgument, "if you supply widths, you must supply one for each column"
15
+ end
16
+
17
+ end
18
+
19
+ def num_columns
20
+ @options[:data_procs].size
21
+ end
22
+
23
+ def has_headings?
24
+ @options[:headings].present?
25
+ end
26
+
27
+ def get_heading(column)
28
+ @options[:headings].nil? ? nil : @options[:headings][column]
29
+ end
30
+
31
+ def get_width(column)
32
+ @options[:widths].nil? ? nil : @options[:widths][column]
33
+ end
34
+
35
+ def get_data(column, *args)
36
+ @options[:data_procs][column].call(*args)
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,34 @@
1
+ ActiveSupport::Inflector.inflections do |inflect|
2
+ inflect.acronym 'OpenStax'
3
+ end
4
+
5
+ require 'omniauth'
6
+ require 'squeel'
7
+
8
+ module OpenStax
9
+ module Connect
10
+ class Engine < ::Rails::Engine
11
+ isolate_namespace OpenStax::Connect
12
+
13
+ config.autoload_paths << File.expand_path("../../../app/algorithms", __FILE__)
14
+ config.autoload_paths << File.expand_path("../../../app/handlers", __FILE__)
15
+
16
+ config.generators do |g|
17
+ g.test_framework :rspec, :view_specs => false
18
+ end
19
+
20
+ # Doesn't work to put this omniauth code in an engine initializer, instead:
21
+ # https://gist.github.com/pablomarti/5243118
22
+ middleware.use ::OmniAuth::Builder do
23
+ provider :openstax,
24
+ OpenStax::Connect.configuration.openstax_application_id,
25
+ OpenStax::Connect.configuration.openstax_application_secret
26
+ end
27
+
28
+ config.after_initialize do
29
+ # The omniauth strategy requires values given during application init
30
+ require "omniauth/strategies/openstax"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,34 @@
1
+ require 'singleton'
2
+
3
+ module OpenStax
4
+ module Connect
5
+ class RouteHelper
6
+
7
+ include Singleton
8
+
9
+ # Registers a path against a canonical name. An optional
10
+ # block can be provided to give the stubbed path
11
+ def self.register_path(canonical_name, path, &block)
12
+ instance.paths[canonical_name] = path
13
+ if block.present? && OpenStax::Connect.configuration.enable_stubbing?
14
+ instance.stubbed_paths[canonical_name] = block.call
15
+ end
16
+ end
17
+
18
+ def self.get_path(canonical_name)
19
+ OpenStax::Connect.configuration.enable_stubbing? ?
20
+ instance.stubbed_paths[canonical_name] :
21
+ instance.paths[canonical_name]
22
+ end
23
+
24
+ def initialize
25
+ self.paths = {}
26
+ self.stubbed_paths = {}
27
+ end
28
+
29
+ attr_accessor :paths
30
+ attr_accessor :stubbed_paths
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,12 @@
1
+ module OpenStax
2
+ module Connect
3
+
4
+ class SecurityTransgression < StandardError; end
5
+ class AbstractMethodCalled < StandardError; end
6
+ class NotYetImplemented < StandardError; end
7
+ class IllegalArgument < StandardError; end
8
+ class IllegalState < StandardError; end
9
+ class IllegalOperation < StandardError; end
10
+
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ module OpenStax
2
+ module Connect
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,72 @@
1
+ require "openstax/connect/engine"
2
+ require "openstax/connect/version"
3
+ require "openstax/connect/utilities"
4
+ require "openstax/connect/route_helper"
5
+ require "openstax/connect/action_list"
6
+
7
+ module OpenStax
8
+ module Connect
9
+
10
+ class << self
11
+
12
+ ###########################################################################
13
+ #
14
+ # Configuration machinery.
15
+ #
16
+ # To configure OpenStax Utilities, put the following code in your applications
17
+ # initialization logic (eg. in the config/initializers in a Rails app)
18
+ #
19
+ # OpenStax::Connect.configure do |config|
20
+ # config.<parameter name> = <parameter value>
21
+ # ...
22
+ # end
23
+ #
24
+ # Set enable_stubbing to true iff you want this engine to fake all
25
+ # interaction with the services site.
26
+ #
27
+
28
+ def configure
29
+ yield configuration
30
+ end
31
+
32
+ def configuration
33
+ @configuration ||= Configuration.new
34
+ end
35
+
36
+ class Configuration
37
+ attr_accessor :openstax_application_id
38
+ attr_accessor :openstax_application_secret
39
+ attr_accessor :enable_stubbing
40
+ attr_reader :openstax_services_url
41
+ attr_accessor :logout_via
42
+ attr_accessor :default_errors_partial
43
+ attr_accessor :default_errors_html_id
44
+ attr_accessor :default_errors_added_trigger
45
+
46
+ def openstax_services_url=(url)
47
+ url.gsub!(/https|http/,'https') if !(url =~ /localhost/)
48
+ url = url + "/" if url[url.size-1] != '/'
49
+ @openstax_services_url = url
50
+ end
51
+
52
+ def initialize
53
+ @openstax_application_id = 'SET ME!'
54
+ @openstax_application_secret = 'SET ME!'
55
+ @openstax_services_url = 'https://services.openstax.org/'
56
+ @enable_stubbing = true
57
+ @logout_via = :get
58
+ @default_errors_partial = 'openstax/connect/shared/attention'
59
+ @default_errors_html_id = 'openstax-connect-attention'
60
+ @default_errors_added_trigger = 'openstax-connect-errors-added'
61
+ super
62
+ end
63
+
64
+ def enable_stubbing?
65
+ !Rails.env.production? && enable_stubbing
66
+ end
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :connect-rails do
3
+ # # Task goes here
4
+ # end