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
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 YOURNAME
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,70 @@
1
+ connect-rails
2
+ =============
3
+
4
+ A rails engine for interfacing with OpenStax's common services 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::Connect::Engine, at: "/connect"
16
+ ...
17
+ end
18
+
19
+ You can use whatever path you want instead of `/connect`, just make sure to make the appropriate changes below.
20
+
21
+ Create an `openstax_connect.rb` initializer in `config/initializers`, with the following contents:
22
+
23
+ OpenStax::Connect.configure do |config|
24
+ config.openstax_application_id = 'value_from_openstax_services_here'
25
+ config.openstax_application_secret = 'value_from_openstax_services_here'
26
+ end
27
+
28
+ If you're running OpenStax Services in a dev instance on your machine, you can specify that instance's local URL with:
29
+
30
+ config.openstax_services_url = 'http://localhost:2999/'
31
+
32
+ To have users login, direct them to `/connect/sessions/new`. This is also available through the `openstax_connect.login` route helper, e.g. `<%= link_to 'Sign in!', openstax_connect.login_path %>`.
33
+
34
+ There is also a logout path helper for `/connect/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
+ Make sure to install the engine's migrations:
39
+
40
+ rake openstax_connect:install:migrations
41
+
42
+ Example Application
43
+ -------------------
44
+
45
+ There is an example application included in the gem in the `example` folder. Here are steps
46
+ to follow:
47
+
48
+ 1. Download (clone) the OpenStax Services site from github.com/openstax/services.
49
+ 1. In the site's `config` folder put a `secret_settings.yml` file that has values for the
50
+ following keys: `facebook_app_id`, `facebook_app_secret`, `twitter_consumer_key`, `twitter_consumer_secret`. If you
51
+ don't have access to these values, you can always make dummy apps on facebook and twitter.
52
+ 2. Do the normal steps to get this site online:
53
+ 1. Run `bundle install --without production`
54
+ 2. Run `bundle exec rake db:migrate`
55
+ 3. Run `bundle exec rails server`
56
+ 2. Open this services site in a web browser (defaults to http://localhost:2999)
57
+ 3. Navigate to http://localhost:2999/oauth/applications
58
+ 4. Click `New application`
59
+ 5. Set the callback URL to `http://localhost:4000/connect/auth/openstax/callback`.
60
+ Port 4000 is where you'll be running the example application.
61
+ 1. The name can be whatever.
62
+ 2. Click the `Trusted?` checkbox.
63
+ 3. Click `Submit`.
64
+ 4. Keep this window open so you can copy the application ID and secret into the example app
65
+ 5. Leave the services app running
66
+ 6. Download (clone) the OpenStax Connect gem from github.com/openstax/connect-rails. The
67
+ example application is in the `example` folder. In that folder's config folder, create a `secret_settings.yml` file
68
+ according to the instructions in `secret_settings.yml.example`. Run the example server in the normal way (bundle install..., migrate db, rails server).
69
+ 7. Navigate to the home page, http://localhost:4000. Click log in and play around. You can also refresh the services site and see yourself logged in, log out, etc.
70
+ 8. For fun, change example/config/openstax_connect.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,49 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'bundler/gem_tasks'
4
+
5
+ # begin
6
+ # require 'bundler/setup'
7
+ # rescue LoadError
8
+ # puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
9
+ # end
10
+ # begin
11
+ # require 'rdoc/task'
12
+ # rescue LoadError
13
+ # require 'rdoc/rdoc'
14
+ # require 'rake/rdoctask'
15
+ # RDoc::Task = Rake::RDocTask
16
+ # end
17
+
18
+ # RDoc::Task.new(:rdoc) do |rdoc|
19
+ # rdoc.rdoc_dir = 'rdoc'
20
+ # rdoc.title = 'OpenstaxConnect'
21
+ # rdoc.options << '--line-numbers'
22
+ # rdoc.rdoc_files.include('README.rdoc')
23
+ # rdoc.rdoc_files.include('lib/**/*.rb')
24
+ # end
25
+
26
+ # APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
27
+ # load 'rails/tasks/engine.rake'
28
+
29
+
30
+
31
+ # Bundler::GemHelper.install_tasks
32
+
33
+ # require 'rake/testtask'
34
+
35
+ # Rake::TestTask.new(:test) do |t|
36
+ # t.libs << 'lib'
37
+ # t.libs << 'test'
38
+ # t.pattern = 'test/**/*_test.rb'
39
+ # t.verbose = false
40
+ # end
41
+
42
+
43
+ # task :default => :test
44
+
45
+ require 'rspec/core/rake_task'
46
+
47
+ RSpec::Core::RakeTask.new('spec')
48
+
49
+ task :default => :spec
@@ -0,0 +1,47 @@
1
+ module OpenStax::Connect
2
+
3
+ class SearchUsers
4
+ include Lev::Algorithm
5
+
6
+ protected
7
+
8
+ def exec(terms, type=:any)
9
+ # Return empty results if no search terms
10
+ return User.where{id == nil}.where{id != nil} if terms.blank?
11
+
12
+ # Note: % is the wildcard. This allows the user to search
13
+ # for stuff that "begins with" but not "ends with".
14
+ case type
15
+ when :name
16
+ users = User.scoped
17
+ terms.gsub(/[%,]/, '').split.each do |t|
18
+ next if t.blank?
19
+ query = t + '%'
20
+ users = users.where{(first_name =~ query) | (last_name =~ query)}
21
+ end
22
+ when :username
23
+ query = terms.gsub('%', '') + '%'
24
+ users = where{username =~ query}
25
+ when :any
26
+ users = User.scoped
27
+ terms.gsub(/[%,]/, '').split.each do |t|
28
+ next if t.blank?
29
+ query = t + '%'
30
+ users = users.where{(first_name =~ query) |
31
+ (last_name =~ query) |
32
+ (username =~ query)}
33
+ end
34
+ else
35
+ raise IllegalArgument, "Unknown user search type: #{type.to_s}"
36
+ end
37
+
38
+ return users
39
+ end
40
+
41
+ def self.default_transaction_isolation
42
+ Lev::TransactionIsolation.serializable
43
+ end
44
+
45
+ end
46
+
47
+ end
@@ -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,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -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,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,9 @@
1
+ # References:
2
+ # http://edgeguides.rubyonrails.org/engines.html#using-a-class-provided-by-the-application
3
+
4
+ # Inherit from the applications ApplicationController to share some methods
5
+ class OpenStax::Connect::ApplicationController < ApplicationController
6
+
7
+ include Lev::HandleWith
8
+
9
+ end
@@ -0,0 +1,16 @@
1
+ require_dependency "openstax/connect/application_controller"
2
+
3
+ module OpenStax
4
+ module Connect
5
+ module Dev
6
+ class DevController < ApplicationController
7
+
8
+ before_filter Proc.new{
9
+ raise SecurityTransgression unless !Rails.env.production? ||
10
+ current_user.is_administrator?
11
+ }
12
+
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ module OpenStax
2
+ module Connect
3
+ module Dev
4
+ class SessionsController < DevController
5
+
6
+ # def new
7
+
8
+ # end
9
+
10
+ # def create; end
11
+
12
+ # def search
13
+ # handle_with(Dev::SessionsUserSearch,
14
+ # params: params,
15
+ # complete: lambda { render 'search' })
16
+ # end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ module OpenStax
2
+ module Connect
3
+ module Dev
4
+ class UsersController < DevController
5
+
6
+ def index; end
7
+
8
+ def create
9
+ handle_with(Dev::UsersCreate,
10
+ success: lambda { redirect_to dev_users_path, notice: 'Success!'},
11
+ failure: lambda { render 'index', alert: 'Error' })
12
+ end
13
+
14
+ def generate
15
+ handle_with(Dev::UsersGenerate,
16
+ success: lambda { redirect_to dev_users_path, notice: 'Success!'},
17
+ failure: lambda { render 'index', alert: 'Error' })
18
+ end
19
+
20
+ def search
21
+ handle_with(Dev::UsersSearch,
22
+ complete: lambda { render 'search' })
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,44 @@
1
+ require_dependency "openstax/connect/application_controller"
2
+
3
+ module OpenStax
4
+ module Connect
5
+ class SessionsController < ApplicationController
6
+
7
+ def new
8
+ session[:return_to] = request.referrer
9
+ redirect_to RouteHelper.get_path(:login)
10
+ end
11
+
12
+ def omniauth_authenticated
13
+ handle_with(SessionsOmniauthAuthenticated,
14
+ complete: lambda {
15
+ sign_in(@results[:user_to_sign_in])
16
+ redirect_to return_path(true)
17
+ })
18
+ end
19
+
20
+ def destroy
21
+ sign_out!
22
+ redirect_to return_path, notice: "Signed out!"
23
+ end
24
+
25
+ def failure
26
+ redirect_to return_path, alert: "Authentication failed, please try again."
27
+ end
28
+
29
+ def become
30
+ raise SecurityTransgression unless !Rails.env.production? || current_user.is_administrator?
31
+ sign_in(User.find(params[:user_id]))
32
+ redirect_to return_path(true)
33
+ end
34
+
35
+ protected
36
+
37
+ def return_path(include_referrer=false)
38
+ referrer = include_referrer ? request.referrer : nil
39
+ params[:return_to] || session.delete(:return_to) || referrer || main_app.root_path
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,31 @@
1
+ class OpenStax::Connect::Dev::UsersCreate
2
+ include Lev::Handler
3
+
4
+ protected
5
+
6
+ def setup
7
+ end
8
+
9
+ def authorized?
10
+ !Rails.env.production?
11
+ end
12
+
13
+ def exec
14
+ u = User.create do |user|
15
+ user.first_name = params[:register][:first_name]
16
+ user.last_name = params[:register][:last_name]
17
+ user.username = params[:register][:username]
18
+ user.is_administrator = params[:register][:is_administrator]
19
+ user.openstax_uid = available_openstax_uid
20
+ end
21
+
22
+ transfer_errors_from(u, :register)
23
+
24
+ results[:user] = u
25
+ end
26
+
27
+ def available_openstax_uid
28
+ (User.order("openstax_uid DESC").first.try(:openstax_uid) || 0) + 1
29
+ end
30
+
31
+ end
@@ -0,0 +1,36 @@
1
+ module OpenStax::Connect::Dev
2
+ class UsersGenerate
3
+ include Lev::Handler
4
+
5
+ protected
6
+
7
+ paramify :generate do
8
+ attribute :count, type: Integer
9
+ validates :count, numericality: { only_integer: true,
10
+ greater_than_or_equal_to: 0 }
11
+ end
12
+
13
+ def authorized?
14
+ !Rails.env.production?
15
+ end
16
+
17
+ def exec
18
+ generate_params.count.times do
19
+ while !(User.where(:username => (username = SecureRandom.hex(4))).empty?) do; end
20
+
21
+ u = User.create do |user|
22
+ user.first_name = "Jane#{username}"
23
+ user.last_name = "Doe#{username}"
24
+ user.username = username
25
+ user.is_administrator = false
26
+ user.openstax_uid = available_openstax_uid
27
+ end
28
+ end
29
+ end
30
+
31
+ def available_openstax_uid
32
+ (User.order("openstax_uid DESC").first.try(:openstax_uid) || 0) + 1
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,64 @@
1
+ module OpenStax::Connect::Dev
2
+ class UsersSearch
3
+
4
+ include Lev::Handler
5
+
6
+ paramify :search do
7
+ attribute :search_type, type: String
8
+ validates :search_type, presence: true,
9
+ inclusion: { in: %w(Name Username Any),
10
+ message: "is not valid" }
11
+
12
+ attribute :search_terms, type: String
13
+ validates :search_terms, presence: true
14
+ end
15
+
16
+ uses_routine OpenStax::Connect::SearchUsers, as: :search_users
17
+
18
+ protected
19
+
20
+ def authorized?
21
+ !Rails.env.production? || caller.is_administrator?
22
+ end
23
+
24
+ def exec
25
+ terms = search_params.search_terms
26
+ type = search_params.search_type
27
+
28
+ # results[:users] = run(OpenStax::Connect::SearchUsers, terms, type.downcase.to_sym)
29
+ # results[:users] = run(:openstax_connect_search_users, terms, type.downcase.to_sym)
30
+ results[:users] = run(:search_users, terms, type.downcase.to_sym)
31
+
32
+ # if terms.blank?
33
+ # users = User.where{id == nil}.where{id != nil} # Empty
34
+ # else
35
+ # # Note: % is the wildcard. This allows the user to search
36
+ # # for stuff that "begins with" but not "ends with".
37
+ # case type
38
+ # when 'Name'
39
+ # users = User.scoped
40
+ # terms.gsub(/[%,]/, '').split.each do |t|
41
+ # next if t.blank?
42
+ # query = t + '%'
43
+ # users = users.where{(first_name =~ query) | (last_name =~ query)}
44
+ # end
45
+ # when 'Username'
46
+ # query = terms.gsub('%', '') + '%'
47
+ # users = where{username =~ query}
48
+ # else # Any
49
+ # users = User.scoped
50
+ # terms.gsub(/[%,]/, '').split.each do |t|
51
+ # next if t.blank?
52
+ # query = t + '%'
53
+ # users = users.where{(first_name =~ query) |
54
+ # (last_name =~ query) |
55
+ # (username =~ query)}
56
+ # end
57
+ # end
58
+ # end
59
+
60
+ # results[:users] = users
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,35 @@
1
+ module OpenStax::Connect
2
+
3
+ class SessionsOmniauthAuthenticated
4
+ include Lev::Handler
5
+
6
+ protected
7
+
8
+ def setup
9
+ @auth_data = request.env['omniauth.auth']
10
+ end
11
+
12
+ def authorized?
13
+ @auth_data.provider == "openstax"
14
+ end
15
+
16
+ def exec
17
+ results[:user_to_sign_in] = user_to_sign_in
18
+ end
19
+
20
+ def user_to_sign_in
21
+ return caller if
22
+ !caller.nil? &&
23
+ !caller.is_anonymous? &&
24
+ caller.openstax_uid == @auth_data.uid
25
+
26
+ existing_user = User.where(openstax_uid: @auth_data.uid).first
27
+ return existing_user if !existing_user.nil?
28
+
29
+ return User.create do |user|
30
+ user.openstax_uid = @auth_data.uid
31
+ end
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,20 @@
1
+ module OpenStax
2
+ module Connect
3
+ module ApplicationHelper
4
+
5
+ def unless_errors(options={}, &block)
6
+ options[:errors] ||= @errors
7
+ options[:errors_html_id] ||= OpenStax::Connect.configuration.default_errors_html_id
8
+ options[:errors_partial] ||= OpenStax::Connect.configuration.default_errors_partial
9
+ options[:trigger] ||= OpenStax::Connect.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,4 @@
1
+ module OpenStax::Connect
2
+ module SessionsHelper
3
+ end
4
+ end
@@ -0,0 +1,40 @@
1
+ require 'singleton'
2
+
3
+ class AnonymousUser
4
+ include Singleton
5
+
6
+ def is_administrator?
7
+ false
8
+ end
9
+
10
+ def is_anonymous?
11
+ true
12
+ end
13
+
14
+ def id
15
+ nil
16
+ end
17
+
18
+ # Necessary if an anonymous user ever runs into an Exception
19
+ # or else the developer email doesn't work
20
+ def username
21
+ 'anonymous'
22
+ end
23
+
24
+ def first_name
25
+ 'Guest User'
26
+ end
27
+
28
+ def last_name
29
+ 'Guest User'
30
+ end
31
+
32
+ def name
33
+ 'Guest User'
34
+ end
35
+
36
+ def openstax_uid
37
+ nil
38
+ end
39
+
40
+ end
@@ -0,0 +1,21 @@
1
+ class User < ActiveRecord::Base
2
+
3
+ validates :username, uniqueness: true
4
+ validates :username, presence: true
5
+ validates :openstax_uid, presence: true
6
+ validates :first_name, presence: true
7
+ validates :last_name, presence: true
8
+
9
+ def is_administrator?
10
+ self.is_administrator
11
+ end
12
+
13
+ def is_anonymous?
14
+ false
15
+ end
16
+
17
+ def name
18
+ "#{first_name} #{last_name}"
19
+ end
20
+
21
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>ConnectRails</title>
5
+ <%= stylesheet_link_tag "openstax/connect/application", :media => "all" %>
6
+ <%= javascript_include_tag "openstax/connect/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>