start writing tests

This commit is contained in:
Josh 2018-05-09 16:31:52 -04:00
parent e6d01ef1b9
commit 5347d902c0
24 changed files with 370 additions and 192 deletions

View File

@ -30,7 +30,7 @@ gem 'jbuilder', '~> 2.5'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 3.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
gem 'bcrypt', '~> 3.1.7'
# Authentication.
gem 'omniauth'

View File

@ -39,6 +39,7 @@ GEM
minitest (~> 5.1)
tzinfo (~> 1.1)
arel (7.1.4)
bcrypt (3.1.11)
bigbluebutton-api-ruby (1.6.0)
xml-simple (~> 1.1)
bindex (0.5.0)
@ -201,6 +202,7 @@ PLATFORMS
ruby
DEPENDENCIES
bcrypt (~> 3.1.7)
bigbluebutton-api-ruby
bootstrap-sass (= 3.3.0.0)
bootstrap-social-rails (~> 4.12)

View File

@ -86,7 +86,8 @@ class MeetingsController < ApplicationController
private
def meeting_params(room)
params.require(:meeting).permit(:name).merge!(room_id: room.id)
params.require(:meeting).permit(:name).merge!(room: room)
#params.require(:meeting).permit(:name).merge!(room_id: room.id)
end
def default_meeting_options

View File

@ -6,17 +6,35 @@ class SessionsController < ApplicationController
# GET /logout
def destroy
logout
logout if current_user
end
# POST /login
def create
user = User.find_by(email: session_params[:email])
if user && user.authenticate(session_params[:password])
login(user)
else
# Login unsuccessful, display error message.
render :new
end
end
# GET/POST /auth/:provider/callback
def create
def omniauth_session
user = User.from_omniauth(request.env['omniauth.auth'])
login(user)
end
# POST /auth/failure
def fail
redirect_to root_path
end
private
def session_params
params.require(:session).permit(:email, :password)
end
end

View File

@ -1,2 +1,23 @@
class UsersController < ApplicationController
# GET /signup
def new
@user = User.new
end
# POST /signup
def create
user = User.new(user_params)
if user.save
login(user)
else
render :new
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end

View File

@ -1,149 +0,0 @@
module BigBlueHelper
META_LISTED = "gl-listed"
META_TOKEN = "gl-token"
def bbb_endpoint
Rails.configuration.bigbluebutton_endpoint
end
def bbb_secret
Rails.configuration.bigbluebutton_secret
end
def bbb
@bbb ||= BigBlueButton::BigBlueButtonApi.new(bbb_endpoint + "api", bbb_secret, "0.8")
end
# Generates a BigBlueButton meeting id from a meeting token.
def bbb_meeting_id(id)
Digest::SHA1.hexdigest(Rails.application.secrets[:secret_key_base] + id).to_s
end
# Generates a random password for a meeting.
def random_password(length)
o = ([('a'..'z'), ('A'..'Z')].map do |i| i.to_a end).flatten
((0...length).map do o[rand(o.length)] end).join
end
# Checks if a meeting is running on the BigBlueButton server.
def meeting_is_running?(id)
begin
bbb.get_meeting_info(id, nil)
return true
rescue BigBlueButton::BigBlueButtonException => exc
return false
end
end
def start_meeting(options)
meeting_id = bbb_meeting_id(name)
# Need to create the meeting on the BigBlueButton server.
create_options = {
record: options[:meeting_recorded].to_s,
#logoutURL: options[:meeting_logout_url] || request.base_url,
moderatorPW: random_password(12),
attendeePW: random_password(12),
moderatorOnlyMessage: options[:moderator_message],
"meta_#{BigBlueHelper::META_LISTED}": false,
"meta_#{BigBlueHelper::META_TOKEN}": name
}
#meeting_options.merge!(
#{ "meta_room-id": options[:room_owner],
# "meta_meeting-name": options[:meeting_name]}
#) if options[:room_owner]
# Send the create request.
begin
bbb.create_meeting(name, meeting_id, create_options)
rescue BigBlueButton::BigBlueButtonException => exc
puts "BigBlueButton failed on create: #{exc.key}: #{exc.message}"
end
# Get the meeting info.
#bbb_meeting_info = bbb.get_meeting_info(meeting_id, nil)
meeting_id
end
# Generates a URL to join a BigBlueButton session.
def join_url(meeting_id, username, options = {})
options[:meeting_recorded] ||= false
options[:user_is_moderator] ||= false
options[:wait_for_moderator] ||= false
options[:meeting_logout_url] ||= nil
options[:meeting_name] ||= name
options[:room_owner] ||= nil
options[:moderator_message] ||= ''
return call_invalid_res if !bbb
# Get the meeting info.
meeting_info = bbb.get_meeting_info(meeting_id, nil)
# Determine the password to use when joining.
password = if options[:user_is_moderator]
meeting_info[:moderatorPW]
else
meeting_info[:attendeePW]
end
# Generate the join URL.
bbb.join_meeting_url(meeting_id, username, password)
end
# Generates a URL to join a BigBlueButton session.
def join_url_old(meeting_token, full_name, options={})
options[:meeting_recorded] ||= false
options[:user_is_moderator] ||= false
options[:wait_for_moderator] ||= false
options[:meeting_logout_url] ||= nil
options[:meeting_name] ||= meeting_token
options[:room_owner] ||= nil
options[:moderator_message] ||= ''
return call_invalid_res if !bbb
meeting_id = bbb_meeting_id(meeting_token)
unless meeting_is_running?(meeting_id)
# Need to create the meeting on the BigBlueButton server.
create_options = {
record: options[:meeting_recorded].to_s,
logoutURL: options[:meeting_logout_url] || request.base_url,
moderatorPW: random_password(12),
attendeePW: random_password(12),
moderatorOnlyMessage: options[:moderator_message],
"meta_#{BigBlueHelper::META_LISTED}": false,
"meta_#{BigBlueHelper::META_TOKEN}": meeting_token
}
#meeting_options.merge!(
#{ "meta_room-id": options[:room_owner],
# "meta_meeting-name": options[:meeting_name]}
#) if options[:room_owner]
# Send the create request.
begin
bbb.create_meeting(options[:meeting_name], meeting_id, create_options)
rescue BigBlueButton::BigBlueButtonException => exc
puts "BigBlueButton failed on create: #{exc.key}: #{exc.message}"
end
# Get the meeting info.
bbb_meeting_info = bbb.get_meeting_info(meeting_id, nil)
end
# Determine the password to use when joining.
password = if options[:user_is_moderator]
bbb_meeting_info[:moderatorPW]
else
bbb_meeting_info[:attendeePW]
end
# Generate the join URL.
bbb.join_meeting_url(meeting_id, full_name, password)
end
end

View File

@ -2,6 +2,8 @@ class Meeting < ApplicationRecord
before_create :generate_meeting_id
validates :name, presence: true
belongs_to :room
# Creates a meeting on the BigBlueButton server.
@ -11,9 +13,7 @@ class Meeting < ApplicationRecord
logoutURL: options[:meeting_logout_url] || '',
moderatorPW: random_password(12),
attendeePW: random_password(12),
moderatorOnlyMessage: options[:moderator_message],
"meta_#{BigBlueHelper::META_LISTED}": false,
"meta_#{BigBlueHelper::META_TOKEN}": name
moderatorOnlyMessage: options[:moderator_message]
}
#meeting_options.merge!(

View File

@ -11,7 +11,10 @@ class Room < ApplicationRecord
private
# Generates a uid for the room.
def set_uid
self.uid = Digest::SHA1.hexdigest(user.uid + user.provider + user.username)[0..12]
digest = user.id.to_s + user.provider + user.username
digest += user.uid unless user.uid.nil?
self.uid = Digest::SHA1.hexdigest(digest)[0..12]
end
end

View File

@ -1,7 +1,23 @@
class User < ApplicationRecord
after_create :initialize_room
before_save { email.downcase! }
has_one :room
validates :name, length: { maximum: 24 }, presence: true
validates :username, presence: true
validates :provider, presence: true
validates :email, length: { maximum: 60 }, presence: true,
uniqueness: { case_sensitive: false },
format: {with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i }
validates :password, length: { minimum: 6 }, allow_nil: true
# We don't want to run the validations because they require a user
# to have a password. Users who authenticate via omniauth won't.
has_secure_password(validations: false)
class << self
# Generates a user from omniauth.
@ -10,10 +26,6 @@ class User < ApplicationRecord
user.name = send("#{auth['provider']}_name", auth)
user.username = send("#{auth['provider']}_username", auth)
user.email = send("#{auth['provider']}_email", auth)
#user.token = auth['credentials']['token']
# Create a room for the user if they don't have one.
user.room = Room.create unless user.room
user.save!
user
@ -48,4 +60,11 @@ class User < ApplicationRecord
end
private
# Initializes a room for the user.
def initialize_room
self.room = Room.new
self.save!
end
end

View File

@ -19,4 +19,4 @@
<% end %>
<br>
<%= link_to 'Logout', user_logout_path %>
<%= link_to 'Logout', logout_path %>

View File

@ -24,6 +24,21 @@
<% end %>
<% end %>
<center><p>or...<br><br></p></center>
<%= form_for(:session, url: login_path) do |f| %>
<div class="input-field col s12">
<%= f.label :email, "Email Address" %>
<%= f.text_field :email %>
</div>
<div class="input-field col s12">
<%= f.label :password %>
<%= f.password_field :password %>
</div>
<br>
<%= f.submit "Login", class: "btn white-text light-green" %>
<%= link_to "Don't have an account? Sign up!", signup_path %>
<% end %>
</div>
<% end %>
</div>

View File

@ -6,12 +6,12 @@
<% else %>
<%= link_to(t('return_to_room'), room_path(current_user)) %>
<% end %>
<div><%= link_to t('logout'), user_logout_url %></div>
<div><%= link_to t('logout'), logout_url %></div>
</div>
<% else %>
<div class="text-center">
<span><%= t('login_description') %></span>
<div><%= link_to t('login'), user_login_url %></div>
<div><%= link_to t('login'), login_url %></div>
</div>
<% end %>
</span>

View File

View File

@ -9,10 +9,20 @@ Rails.application.routes.draw do
end
end
get '/login', to: 'sessions#new', as: :user_login
get '/logout', to: 'sessions#destroy', as: :user_logout
get '/signup', to: 'users#new'
post '/signup', to: 'users#create'
match '/auth/:provider/callback', to: 'sessions#create', via: [:get, :post]
# Login to Greenlight.
get '/login', to: 'sessions#new'
# Handles login of :greenlight provider account.
post '/login', to: 'sessions#create', as: :create_session
# Log the user out of the session.
get '/logout', to: 'sessions#destroy'
# Handles Omniauth authentication.
match '/auth/:provider/callback', to: 'sessions#omniauth_session', via: [:get, :post], as: :omniauth_session
get '/auth/failure', to: 'sessions#fail'
root to: 'main#index'

View File

@ -1,11 +1,12 @@
class CreateUsers < ActiveRecord::Migration[5.0]
def change
create_table :users do |t|
t.string :provider, null: false
t.string :uid, null: false
t.string :provider
t.string :uid
t.string :name
t.string :username
t.string :email
t.string :password_digest, index: { unique: true }
t.timestamps
end

View File

@ -2,7 +2,7 @@ class CreateMeetings < ActiveRecord::Migration[5.0]
def change
create_table :meetings do |t|
t.belongs_to :room, index: true
t.string :name, null: false
t.string :name, index: true
t.string :uid, index: true
t.timestamps

View File

@ -14,10 +14,11 @@ ActiveRecord::Schema.define(version: 20180504131713) do
create_table "meetings", force: :cascade do |t|
t.integer "room_id"
t.string "name", null: false
t.string "name"
t.string "uid"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["name"], name: "index_meetings_on_name"
t.index ["room_id"], name: "index_meetings_on_room_id"
t.index ["uid"], name: "index_meetings_on_uid"
end
@ -32,13 +33,15 @@ ActiveRecord::Schema.define(version: 20180504131713) do
end
create_table "users", force: :cascade do |t|
t.string "provider", null: false
t.string "uid", null: false
t.string "provider"
t.string "uid"
t.string "name"
t.string "username"
t.string "email"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["password_digest"], name: "index_users_on_password_digest", unique: true
end
end

View File

@ -5,3 +5,13 @@
#
# movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
# Character.create(name: 'Luke', movie: movies.first)
User.create(
provider: "greenlight",
name: "Test User",
uid: "someuid",
username: "testuser",
email: "test@user.com",
password: "test",
password_confirmation: "test",
)

View File

@ -1,7 +1,63 @@
require 'test_helper'
class SessionsControllerTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
def setup
@user = User.new(
name: "Example User",
username: "Username",
provider: "greenlight",
email: "user@example.com",
password: "example",
password_confirmation: "example"
)
@user.save!
end
test 'can signin with greenlight account.' do
post create_session_path, params: {session: {email: @user.email, password: @user.password}}
assert_redirected_to room_path(@user.room.uid)
assert @user.id, session[:user_id]
end
test 'can signup for greenlight account.' do
end
test 'can signup/login with omniauth.' do
email = "omniauth@test.com"
uid = "123456789"
OmniAuth.config.add_mock(:twitter, {
provider: "twitter",
uid: uid,
info: {
email: email,
name: "Omni User",
nickname: "username"
}
})
get "/auth/twitter"
request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:twitter]
get omniauth_session_path(provider: "twitter")
user = User.find_by(email: email, uid: uid)
assert_not_nil user
assert_redirected_to room_path(user.room.uid)
assert @user.id, session[:user_id]
end
test 'can logout.' do
post create_session_path, params: {session: {email: @user.email, password: @user.password}}
assert @user.id, session[:user_id]
get logout_path
assert_not_equal @user.id, session[:user_id]
end
end

View File

@ -1,7 +1,5 @@
require 'test_helper'
class UsersControllerTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
end

View File

@ -1,7 +1,32 @@
require 'test_helper'
class MeetingTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
def setup
@user = User.new(
name: "Example User",
username: "Username",
provider: "greenlight",
email: "user@example.com",
password: "example",
password_confirmation: "example"
)
@room = Room.new(user: @user)
@meeting = Meeting.new(
name: "Test Meeting",
room: @room
)
end
test "name should be present." do
@meeting.name = nil
assert_not @meeting.valid?
end
test "should set uid on creation." do
@meeting.save
assert @meeting.uid
end
end

View File

@ -1,7 +1,39 @@
require 'test_helper'
class RoomTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
def setup
@user = User.new(
name: "Example User",
username: "Username",
provider: "greenlight",
email: "user@example.com",
password: "example",
password_confirmation: "example"
)
@room = Room.new(
user: @user
)
end
test "#owned_by? should identify correct owner." do
assert @room.owned_by?(@user)
end
test "#owned_by? should identify incorrect owner." do
diff_user = User.new(
name: "Different User",
username: "Diffname",
provider: "greenlight",
email: "diff@example.com",
)
assert_not @room.owned_by?(diff_user)
end
test "should set uid on creation." do
@room.save
assert @room.uid
end
end

View File

@ -1,7 +1,120 @@
require 'test_helper'
class UserTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
def setup
@user = User.new(
name: "Example User",
username: "Username",
provider: "greenlight",
email: "user@example.com",
password: "example",
password_confirmation: "example"
)
end
test "should be valid." do
assert @user.valid?
end
test "name should be present." do
@user.name = nil
assert_not @user.valid?
end
test "email should be present." do
@user.email = nil
assert_not @user.valid?
end
test "username should be present." do
@user.username = nil
assert_not @user.valid?
end
test "provider should be present." do
@user.provider = nil
assert_not @user.valid?
end
test "should allow nil uid." do
@user.uid = nil
assert @user.valid?
end
test "should allow nil password." do
@user.password = @user.password_confirmation = nil
assert @user.valid?
end
test "should create user from omniauth" do
auth = {
"uid" => "123456789",
"provider" => "twitter",
"info" => {
"name" => "Test Name",
"nickname" => "username",
"email" => "test@example.com"
}
}
assert_difference 'User.count' do
User.from_omniauth(auth)
end
user = User.find_by(uid: auth["uid"], provider: auth["provider"])
assert user.username, auth["info"]["nickname"]
assert user.name, auth["info"]["name"]
end
test "email addresses should be saved as lower-case." do
mixed_case = "ExAmPlE@eXaMpLe.CoM"
@user.email = mixed_case
@user.save
assert_equal mixed_case.downcase, @user.email
end
test "email validation should reject invalid addresses." do
invalid_addresses = %w[user@example,com user_at_foo.org user.name@example. foo@bar_baz.com foo@bar+baz.com]
invalid_addresses.each do |invalid_address|
@user.email = invalid_address
assert_not @user.valid?, "#{invalid_address.inspect} should be invalid."
end
end
test "email should be unique." do
duplicate_user = @user.dup
duplicate_user.email = @user.email.upcase
@user.save
assert_not duplicate_user.valid?
end
test "name should not be too long." do
@user.name = "a" * 25
assert_not @user.valid?
end
test "email should not be too long." do
@user.email = "a" * 50 + "@example.com"
assert_not @user.valid?
end
test "password should have a minimum length." do
@user.password = @user.password_confirmation = "a" * 5
assert_not @user.valid?
end
test "should authenticate on valid password." do
assert_not_equal @user.authenticate('example'), false
end
test "should not authenticate on invalid password." do
assert_not @user.authenticate('incorrect')
end
test "should create room when saved." do
@user.save
assert @user.room
end
end

View File

@ -6,5 +6,5 @@ class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
# Add more helper methods to be used by all tests here...
end
OmniAuth.config.test_mode = true
end