openstax_accounts 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.md +123 -0
- data/Rakefile +22 -0
- data/app/assets/javascripts/openstax/accounts/application.js +15 -0
- data/app/assets/stylesheets/openstax/accounts/application.css +13 -0
- data/app/assets/stylesheets/openstax/accounts/dev.css.scss +31 -0
- data/app/controllers/openstax/accounts/application_controller.rb +24 -0
- data/app/controllers/openstax/accounts/dev/dev_controller.rb +13 -0
- data/app/controllers/openstax/accounts/dev/users_controller.rb +21 -0
- data/app/controllers/openstax/accounts/sessions_controller.rb +41 -0
- data/app/handlers/openstax/accounts/dev/users_search.rb +38 -0
- data/app/handlers/openstax/accounts/sessions_omniauth_authenticated.rb +47 -0
- data/app/helpers/openstax/accounts/application_helper.rb +20 -0
- data/app/models/openstax/accounts/user.rb +42 -0
- data/app/routines/openstax/accounts/dev/create_user.rb +37 -0
- data/app/routines/openstax/accounts/search_users.rb +47 -0
- data/app/views/layouts/openstax/accounts/application.html.erb +14 -0
- data/app/views/openstax/accounts/dev/users/login.html.erb +17 -0
- data/app/views/openstax/accounts/dev/users/search.js.erb +21 -0
- data/app/views/openstax/accounts/shared/_attention.html.erb +3 -0
- data/app/views/openstax/accounts/users/_action_create_form.html.erb +9 -0
- data/app/views/openstax/accounts/users/_action_dialog.html.erb +10 -0
- data/app/views/openstax/accounts/users/_action_list.html.erb +33 -0
- data/app/views/openstax/accounts/users/_action_search.html.erb +25 -0
- data/app/views/openstax/accounts/users/action_search.js.erb +8 -0
- data/config/initializers/extend_builtins.rb +42 -0
- data/config/routes.rb +25 -0
- data/db/migrate/0_create_openstax_accounts_users.rb +18 -0
- data/lib/omniauth/strategies/openstax.rb +39 -0
- data/lib/openstax/accounts/action_list.rb +42 -0
- data/lib/openstax/accounts/current_user_manager.rb +103 -0
- data/lib/openstax/accounts/engine.rb +35 -0
- data/lib/openstax/accounts/route_helper.rb +34 -0
- data/lib/openstax/accounts/user_provider.rb +15 -0
- data/lib/openstax/accounts/version.rb +5 -0
- data/lib/openstax_accounts.rb +130 -0
- data/spec/controllers/openstax/accounts/dev/users_controller_spec.rb +20 -0
- data/spec/controllers/openstax/accounts/sessions_controller_spec.rb +29 -0
- data/spec/dummy/README.md +1 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/api/application_users_controller.rb +7 -0
- data/spec/dummy/app/controllers/api/dummy_controller.rb +11 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/config/application.rb +53 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +69 -0
- data/spec/dummy/config/environments/test.rb +35 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/openstax_accounts.rb +11 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +11 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/schema.rb +31 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/factories/openstax_accounts_user.rb +6 -0
- data/spec/lib/openstax_accounts_spec.rb +24 -0
- data/spec/models/openstax/accounts/user_spec.rb +13 -0
- data/spec/spec_helper.rb +41 -0
- metadata +401 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 Rice University
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
accounts-rails
|
2
|
+
=============
|
3
|
+
|
4
|
+
A rails engine for interfacing with OpenStax's accounts server.
|
5
|
+
|
6
|
+
Usage
|
7
|
+
-----
|
8
|
+
|
9
|
+
Add the engine to your Gemfile and then run `bundle install`.
|
10
|
+
|
11
|
+
Mount the engine your application's `routes.rb` file:
|
12
|
+
|
13
|
+
MyApplication::Application.routes.draw do
|
14
|
+
...
|
15
|
+
mount OpenStax::Accounts::Engine, at: "/accounts"
|
16
|
+
...
|
17
|
+
end
|
18
|
+
|
19
|
+
You can use whatever path you want instead of `/accounts`, just make sure to make the appropriate changes below.
|
20
|
+
|
21
|
+
Create an `openstax_accounts.rb` initializer in `config/initializers`, with the following contents:
|
22
|
+
|
23
|
+
OpenStax::Accounts.configure do |config|
|
24
|
+
config.openstax_application_id = 'value_from_openstax_accounts_here'
|
25
|
+
config.openstax_application_secret = 'value_from_openstax_accounts_here'
|
26
|
+
end
|
27
|
+
|
28
|
+
If you're running OpenStax Accounts in a dev instance on your machine, you can specify that instance's local URL with:
|
29
|
+
|
30
|
+
config.openstax_accounts_url = 'http://localhost:2999/'
|
31
|
+
|
32
|
+
To have users login, direct them to `/accounts/sessions/new`. This is also available through the `openstax_accounts.login` route helper, e.g. `<%= link_to 'Sign in!', openstax_accounts.login_path %>`.
|
33
|
+
|
34
|
+
There is also a logout path helper for `/accounts/sessions/destroy`, given by `logout_path`. By default this expects a `GET` request. If you'd prefer a `DELETE` request, add this configuration:
|
35
|
+
|
36
|
+
config.logout_via = :delete
|
37
|
+
|
38
|
+
OpenStax Accounts provides you with an `OpenStax::Accounts::User` object. You can
|
39
|
+
use this as your app's User object without modification, you can modify it to suit
|
40
|
+
your app's needs (not recommended), or you can provide your own custom User object
|
41
|
+
that references the OpenStax Accounts User object.
|
42
|
+
|
43
|
+
OpenStax Accounts also provides you methods for getting and setting the current
|
44
|
+
signed in user (`current_user` and `current_user=` methods). If you choose to create
|
45
|
+
your own custom User object that references the User object provided by Accounts,
|
46
|
+
you can teach OpenStax Accounts how to translate between your app's custom User
|
47
|
+
object and OpenStax Accounts's built-in User object.
|
48
|
+
|
49
|
+
To do this, you need to set a `user_provider` in this configuration.
|
50
|
+
|
51
|
+
config.user_provider = MyUserProvider
|
52
|
+
|
53
|
+
The user_provider is a class that provides two class methods:
|
54
|
+
|
55
|
+
def self.accounts_user_to_app_user(accounts_user)
|
56
|
+
# Converts the given accounts user to an app user.
|
57
|
+
# If you want to cache the accounts_user in the app user,
|
58
|
+
# this is the place to do it.
|
59
|
+
# If no app user exists for this accounts user, one should
|
60
|
+
# be created.
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.app_user_to_accounts_user(app_user)
|
64
|
+
# Converts the given app user to an accounts user.
|
65
|
+
end
|
66
|
+
|
67
|
+
Accounts users are never nil. When a user is signed out, the current accounts user
|
68
|
+
is an anonymous user (responding true to `is_anonymous?`). You can follow the same
|
69
|
+
pattern in your app or you can use nil for the current user. Just remember to check
|
70
|
+
the anonymous status of accounts users when doing your accounts <-> app translations.
|
71
|
+
|
72
|
+
The default `user_provider` just uses OpenStax::Accounts::User as the app user.
|
73
|
+
|
74
|
+
Make sure to install the engine's migrations:
|
75
|
+
|
76
|
+
rake openstax_accounts:install:migrations
|
77
|
+
|
78
|
+
Accounts API
|
79
|
+
------------
|
80
|
+
|
81
|
+
OpenStax::Accounts provides convenience methods for accessing the OpenStax Accounts API.
|
82
|
+
|
83
|
+
`OpenStax:: Accounts.create_application_user(accounts_user, version = nil)` takes
|
84
|
+
an OpenStax::Accounts::User and, optionally, an API version argument, and creates
|
85
|
+
an ApplicationUser for the configured application and the given user. Call this method
|
86
|
+
when users finish the registration process in your app. This lets Accounts know that the given user is using your app, allowing Accounts to push user information to it whenever it changes.
|
87
|
+
|
88
|
+
`OpenStax::Accounts.api_call(http_method, url, options = {})` provides a generic
|
89
|
+
convenience method capable of making API calls to Accounts. `http_method` can be
|
90
|
+
any valid HTTP method, and `url` is the desired API URL, without the 'api/' prefix.
|
91
|
+
Options is a hash that can contain any option that OAuth2 requests accept, such
|
92
|
+
as :headers, :params, :body, etc, plus the optional values :api_version (to specify
|
93
|
+
an API version) and :access_token (to specify an OAuth access token).
|
94
|
+
|
95
|
+
Example Application
|
96
|
+
-------------------
|
97
|
+
|
98
|
+
There is an example application included in the gem in the `example` folder.
|
99
|
+
Here are the steps to follow:
|
100
|
+
|
101
|
+
1. Download (clone) the OpenStax Accounts site from github.com/openstax/accounts.
|
102
|
+
1. In the site's `config` folder put a `secret_settings.yml` file that has values for the
|
103
|
+
following keys: `facebook_app_id`, `facebook_app_secret`, `twitter_consumer_key`, `twitter_consumer_secret`. If you don't have access to these values, you can always make dummy apps on facebook and twitter.
|
104
|
+
2. Do the normal steps to get this site online:
|
105
|
+
1. Run `bundle install --without production`
|
106
|
+
2. Run `bundle exec rake db:migrate`
|
107
|
+
3. Run `bundle exec rails server`
|
108
|
+
2. Open this accounts site in a web browser (defaults to http://localhost:2999)
|
109
|
+
3. Navigate to http://localhost:2999/oauth/applications
|
110
|
+
4. Click `New application`
|
111
|
+
5. Set the callback URL to `http://localhost:4000/accounts/auth/openstax/callback`.
|
112
|
+
Port 4000 is where you'll be running the example application.
|
113
|
+
1. The name can be whatever.
|
114
|
+
2. Click the `Trusted?` checkbox.
|
115
|
+
3. Click `Submit`.
|
116
|
+
4. Keep this window open so you can copy the application ID and secret into the example app
|
117
|
+
5. Leave the accounts app running
|
118
|
+
6. Download (clone) the OpenStax Accounts gem from github.com/openstax/accounts-rails.
|
119
|
+
The example application is in the `example` folder.
|
120
|
+
In that folder's config folder, create a `secret_settings.yml` file according to the
|
121
|
+
instructions in `secret_settings.yml.example`. Run the example server in the normal way (bundle install..., migrate db, rails server).
|
122
|
+
7. Navigate to the home page, http://localhost:4000. Click log in and play around. You can also refresh the accounts site and see yourself logged in, log out, etc.
|
123
|
+
8. For fun, change example/config/openstax_accounts.rb to set `enable_stubbing` to `true`. Now when you click login you'll be taken to a developer-only page where you can login as other users, generate new users, create new users, etc.
|
data/Rakefile
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
rescue LoadError
|
6
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
7
|
+
end
|
8
|
+
|
9
|
+
APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__)
|
10
|
+
load 'rails/tasks/engine.rake'
|
11
|
+
|
12
|
+
Bundler::GemHelper.install_tasks
|
13
|
+
|
14
|
+
Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
|
15
|
+
|
16
|
+
require 'rspec/core'
|
17
|
+
require 'rspec/core/rake_task'
|
18
|
+
|
19
|
+
desc 'Run all specs in spec directory (excluding plugin specs)'
|
20
|
+
RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
|
21
|
+
|
22
|
+
task :default => :spec
|
@@ -0,0 +1,15 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
+
// listed below.
|
3
|
+
//
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
6
|
+
//
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
+
// the compiled file.
|
9
|
+
//
|
10
|
+
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
11
|
+
// GO AFTER THE REQUIRES BELOW.
|
12
|
+
//
|
13
|
+
//= require jquery
|
14
|
+
//= require jquery_ujs
|
15
|
+
//= require_tree .
|
@@ -0,0 +1,13 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require_self
|
12
|
+
*= require_tree .
|
13
|
+
*/
|
@@ -0,0 +1,31 @@
|
|
1
|
+
@mixin section-block-base($heading_font_size) {
|
2
|
+
margin: 5px 0px;
|
3
|
+
|
4
|
+
.section-block-heading {
|
5
|
+
|
6
|
+
color: black;
|
7
|
+
font-size: $heading_font_size;
|
8
|
+
|
9
|
+
a {
|
10
|
+
font-size: $heading_font_size;
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
.section-block-body {
|
15
|
+
margin: $heading_font_size/2 0px 0px;
|
16
|
+
padding: 0px 0px 0px $heading_font_size;
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
.section-block-section {
|
21
|
+
@include section-block-base(22px);
|
22
|
+
}
|
23
|
+
|
24
|
+
|
25
|
+
.section-block-section.nesting-2 {
|
26
|
+
@include section-block-base(14px);
|
27
|
+
|
28
|
+
.section-block-heading {
|
29
|
+
font-style: italic;
|
30
|
+
}
|
31
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
|
4
|
+
class ApplicationController < ActionController::Base
|
5
|
+
include Lev::HandleWith
|
6
|
+
|
7
|
+
# Override current_user to always return an OpenStax::Accounts::User
|
8
|
+
def current_user
|
9
|
+
current_user_manager.accounts_current_user
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def return_url(include_referrer=false)
|
15
|
+
referrer = include_referrer ? request.referrer : nil
|
16
|
+
# Always clear the session
|
17
|
+
session_return_to = session.delete(:return_to)
|
18
|
+
params[:return_to] || session_return_to || referrer || main_app.root_url
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
module Dev
|
4
|
+
class UsersController < OpenStax::Accounts::Dev::DevController
|
5
|
+
|
6
|
+
def login; end
|
7
|
+
|
8
|
+
def search
|
9
|
+
handle_with(OpenStax::Accounts::Dev::UsersSearch,
|
10
|
+
complete: lambda { render 'search' })
|
11
|
+
end
|
12
|
+
|
13
|
+
def become
|
14
|
+
sign_in(User.find(params[:user_id]))
|
15
|
+
redirect_to return_url(true)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
class SessionsController < OpenStax::Accounts::ApplicationController
|
4
|
+
|
5
|
+
def new
|
6
|
+
session[:return_to] ||= request.referrer
|
7
|
+
redirect_to RouteHelper.get_path(:login)
|
8
|
+
end
|
9
|
+
|
10
|
+
def omniauth_authenticated
|
11
|
+
handle_with(SessionsOmniauthAuthenticated,
|
12
|
+
success: lambda {
|
13
|
+
sign_in(@handler_result.outputs[:accounts_user_to_sign_in])
|
14
|
+
# referrer is in Accounts, so don't include it
|
15
|
+
redirect_to return_url
|
16
|
+
},
|
17
|
+
failure: lambda {
|
18
|
+
failure
|
19
|
+
})
|
20
|
+
end
|
21
|
+
|
22
|
+
def destroy
|
23
|
+
sign_out!
|
24
|
+
|
25
|
+
# If we're using the Accounts server, need to sign out of it so can't
|
26
|
+
# log back in automagically
|
27
|
+
redirect_to OpenStax::Accounts.configuration.enable_stubbing? ?
|
28
|
+
return_url :
|
29
|
+
OpenStax::Utilities.generate_url(
|
30
|
+
OpenStax::Accounts.configuration.openstax_accounts_url + "/logout",
|
31
|
+
return_to: return_url
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def failure
|
36
|
+
redirect_to return_url, alert: "Authentication failed, please try again."
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
module Dev
|
4
|
+
class UsersSearch
|
5
|
+
|
6
|
+
lev_handler transaction: :no_transaction
|
7
|
+
|
8
|
+
paramify :search do
|
9
|
+
attribute :search_type, type: String
|
10
|
+
validates :search_type, presence: true,
|
11
|
+
inclusion: { in: %w(Name Username Any),
|
12
|
+
message: "is not valid" }
|
13
|
+
|
14
|
+
attribute :search_terms, type: String
|
15
|
+
validates :search_terms, presence: true
|
16
|
+
end
|
17
|
+
|
18
|
+
uses_routine OpenStax::Accounts::SearchUsers,
|
19
|
+
as: :search_users,
|
20
|
+
translations: { outputs: {type: :verbatim} }
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
def authorized?
|
25
|
+
!Rails.env.production? || caller.is_administrator?
|
26
|
+
end
|
27
|
+
|
28
|
+
def handle
|
29
|
+
terms = search_params.search_terms
|
30
|
+
type = search_params.search_type
|
31
|
+
|
32
|
+
run(:search_users, terms, type.downcase.to_sym)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
|
4
|
+
class SessionsOmniauthAuthenticated
|
5
|
+
lev_handler
|
6
|
+
|
7
|
+
protected
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@auth_data = request.env['omniauth.auth']
|
11
|
+
end
|
12
|
+
|
13
|
+
def authorized?
|
14
|
+
@auth_data.provider == "openstax"
|
15
|
+
end
|
16
|
+
|
17
|
+
def handle
|
18
|
+
outputs[:accounts_user_to_sign_in] = user_to_sign_in
|
19
|
+
end
|
20
|
+
|
21
|
+
def user_to_sign_in
|
22
|
+
return caller if
|
23
|
+
!caller.nil? &&
|
24
|
+
!caller.is_anonymous? &&
|
25
|
+
caller.openstax_uid == @auth_data.uid
|
26
|
+
|
27
|
+
existing_user = User.where(openstax_uid: @auth_data.uid).first
|
28
|
+
return existing_user if !existing_user.nil?
|
29
|
+
|
30
|
+
new_user = User.create do |user|
|
31
|
+
user.openstax_uid = @auth_data.uid
|
32
|
+
user.username = @auth_data.info.nickname
|
33
|
+
user.first_name = @auth_data.info.first_name
|
34
|
+
user.last_name = @auth_data.info.last_name
|
35
|
+
user.full_name = @auth_data.info.name
|
36
|
+
user.title = @auth_data.info.title
|
37
|
+
user.access_token = @auth_data.credentials.token
|
38
|
+
end
|
39
|
+
|
40
|
+
transfer_errors_from(new_user, {type: :verbatim})
|
41
|
+
|
42
|
+
new_user
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
module ApplicationHelper
|
4
|
+
|
5
|
+
def unless_errors(options={}, &block)
|
6
|
+
options[:errors] ||= @handler_result.errors
|
7
|
+
options[:errors_html_id] ||= OpenStax::Accounts.configuration.default_errors_html_id
|
8
|
+
options[:errors_partial] ||= OpenStax::Accounts.configuration.default_errors_partial
|
9
|
+
options[:trigger] ||= OpenStax::Accounts.configuration.default_errors_added_trigger
|
10
|
+
|
11
|
+
if options[:errors].any? || flash[:alert]
|
12
|
+
"$('##{options[:errors_html_id]}').html('#{ j(render options[:errors_partial], errors: options[:errors]) }').trigger('#{options[:trigger]}');".html_safe
|
13
|
+
else
|
14
|
+
("$('##{options[:errors_html_id]}').html('');" + capture(&block)).html_safe
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
class User < ActiveRecord::Base
|
4
|
+
|
5
|
+
validates :username, uniqueness: true
|
6
|
+
validates :username, presence: true
|
7
|
+
validates :openstax_uid, presence: true
|
8
|
+
|
9
|
+
# first and last names are not required
|
10
|
+
|
11
|
+
def name
|
12
|
+
(first_name || last_name) ? [first_name, last_name].compact.join(" ") : username
|
13
|
+
end
|
14
|
+
|
15
|
+
def casual_name
|
16
|
+
first_name || username
|
17
|
+
end
|
18
|
+
|
19
|
+
def is_anonymous?
|
20
|
+
is_anonymous == true
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_accessor :is_anonymous
|
24
|
+
|
25
|
+
def self.anonymous
|
26
|
+
@@anonymous ||= AnonymousUser.new
|
27
|
+
end
|
28
|
+
|
29
|
+
class AnonymousUser < User
|
30
|
+
before_save { false }
|
31
|
+
def initialize(attributes=nil)
|
32
|
+
super
|
33
|
+
self.is_anonymous = true
|
34
|
+
self.first_name = 'Guest'
|
35
|
+
self.last_name = 'User'
|
36
|
+
self.openstax_uid = nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module OpenStax
|
2
|
+
module Accounts
|
3
|
+
module Dev
|
4
|
+
class CreateUser
|
5
|
+
lev_routine
|
6
|
+
|
7
|
+
protected
|
8
|
+
|
9
|
+
def exec(inputs={})
|
10
|
+
|
11
|
+
username = inputs[:username]
|
12
|
+
|
13
|
+
if username.nil? || inputs[:ensure_no_errors]
|
14
|
+
loop do
|
15
|
+
break if !username.nil? && OpenStax::Accounts::User.where(username: username).none?
|
16
|
+
username = "#{inputs[:username] || 'user'}#{rand(1000000)}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
outputs[:user] = OpenStax::Accounts::User.create do |user|
|
21
|
+
user.first_name = inputs[:first_name]
|
22
|
+
user.last_name = inputs[:last_name]
|
23
|
+
user.username = username
|
24
|
+
user.openstax_uid = available_negative_openstax_uid
|
25
|
+
end
|
26
|
+
|
27
|
+
transfer_errors_from(outputs[:user], {type: :verbatim})
|
28
|
+
end
|
29
|
+
|
30
|
+
def available_negative_openstax_uid
|
31
|
+
(OpenStax::Accounts::User.order("openstax_uid DESC").last.try(:openstax_uid) || 0) - 1
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'squeel'
|
2
|
+
|
3
|
+
module OpenStax
|
4
|
+
module Accounts
|
5
|
+
|
6
|
+
class SearchUsers
|
7
|
+
lev_routine transaction: :no_transaction
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
def exec(terms, type=:any)
|
12
|
+
# Return empty results if no search terms
|
13
|
+
return User.where{id == nil}.where{id != nil} if terms.blank?
|
14
|
+
|
15
|
+
# Note: % is the wildcard. This allows the user to search
|
16
|
+
# for stuff that "begins with" but not "ends with".
|
17
|
+
case type
|
18
|
+
when :name
|
19
|
+
users = User.scoped
|
20
|
+
terms.gsub(/[%,]/, '').split.each do |t|
|
21
|
+
next if t.blank?
|
22
|
+
query = t + '%'
|
23
|
+
users = users.where{(first_name =~ query) | (last_name =~ query)}
|
24
|
+
end
|
25
|
+
when :username
|
26
|
+
query = terms.gsub('%', '') + '%'
|
27
|
+
users = User.where{username =~ query}
|
28
|
+
when :any
|
29
|
+
users = User.scoped
|
30
|
+
terms.gsub(/[%,]/, '').split.each do |t|
|
31
|
+
next if t.blank?
|
32
|
+
query = t + '%'
|
33
|
+
users = users.where{(first_name =~ query) |
|
34
|
+
(last_name =~ query) |
|
35
|
+
(username =~ query)}
|
36
|
+
end
|
37
|
+
else
|
38
|
+
fatal_error(:unknown_user_search_type, data: type)
|
39
|
+
end
|
40
|
+
|
41
|
+
outputs[:users] = users
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Accounts</title>
|
5
|
+
<%= stylesheet_link_tag "openstax/accounts/application", :media => "all" %>
|
6
|
+
<%= javascript_include_tag "openstax/accounts/application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
|
11
|
+
<%= yield %>
|
12
|
+
|
13
|
+
</body>
|
14
|
+
</html>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
<div class="openstax-accounts development-login">
|
3
|
+
|
4
|
+
<% handler_errors.each do |error| %>
|
5
|
+
<%= error.translate %>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<%= osu.section_block "Development Login" do %>
|
9
|
+
|
10
|
+
<p>You need to login, but we're not connected to the Accounts server. Search for a user below
|
11
|
+
and click the sign in link next to him or her.</p>
|
12
|
+
|
13
|
+
<%= render 'openstax/accounts/users/action_search', action_search_path: search_dev_users_path %>
|
14
|
+
|
15
|
+
<% end %>
|
16
|
+
|
17
|
+
</div>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
|
2
|
+
<%= render template: 'openstax/accounts/users/action_search',
|
3
|
+
locals: {
|
4
|
+
users: @handler_result.outputs[:users],
|
5
|
+
list: OpenStax::Accounts::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
|
+
become_dev_users_path(:user_id => user.id),
|
16
|
+
method: :post
|
17
|
+
}
|
18
|
+
]
|
19
|
+
)
|
20
|
+
}
|
21
|
+
%>
|
@@ -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>
|