Commit 9923f914 by John Doe

added user invitation and removed devise confirmable attribute from user model

parent 231f8fde
Showing with 623 additions and 194 deletions
......@@ -35,6 +35,7 @@ gem 'sdoc', '~> 0.4.0', group: :doc
gem 'httparty'
gem 'rack-cors'
gem 'devise_token_auth'
gem 'devise_invitable'
gem 'omniauth'
gem 'oj' # fast json
......
......@@ -109,6 +109,9 @@ GEM
railties (>= 4.1.0, < 5.1)
responders
warden (~> 1.2.3)
devise_invitable (1.7.2)
actionmailer (>= 4.1.0)
devise (>= 4.0.0)
devise_token_auth (0.1.40)
devise (> 3.5.2, <= 4.2)
rails (< 6)
......@@ -347,6 +350,7 @@ DEPENDENCIES
coffee-rails (~> 4.1.0)
cucumber-rails
database_cleaner
devise_invitable
devise_token_auth
factory_girl_rails
faker
......
module InvitableMethods
extend ActiveSupport::Concern
def authenticate_inviter!
# use authenticate_user! in before_action
end
def authenticate_user!
return if current_user
render json: {
errors: ['Authorized users only.']
}, status: :unauthorized
end
def resource_class(m = nil)
if m
mapping = Devise.mappings[m]
else
mapping = Devise.mappings[resource_name] || Devise.mappings.values.first
end
mapping.to
end
def resource_from_invitation_token
@user = User.find_by_invitation_token(params[:invitation_token], true)
return if params[:invitation_token] && @user
render json: { errors: ['Invalid token.'] }, status: :not_acceptable
end
end
class InvitationsController < Devise::InvitationsController
include InvitableMethods
before_action :authenticate_user!, only: :create
before_action :resource_from_invitation_token, only: [:edit, :update]
# no create or edit actions
def create
head status: :unprocessable_entity
end
def edit
head status: :unprocessable_entity
end
def update
user = User.accept_invitation!(accept_invitation_params)
if user.errors.empty?
render json: { success: ['User updated.'] }, status: :accepted
else
@service = StubService.new
@service.add_errors(user.errors.full_messages)
render 'helpers/empty_response', status: :unprocessable_entity
end
end
private
def accept_invitation_params
params.permit(:first_name, :last_name,
:email,
:password, :password_confirmation, :invitation_token)
end
end
......@@ -46,6 +46,24 @@ class PermissionsController < ApplicationController
render :create, status: @service.success? ? :ok : :unprocessable_entity
end
# PUT /permissions/invite_user.json
def invite_user
invitation_service = InviteUser.new()
invitation_service.run(
current_user,
params[:email],
params[:redirect_url])
unless invitation_service.success?
@service = invitation_service
render 'helpers/empty_response', status: :unprocessable_entity
return
end
@service = CreatePermission.new
@service.absorb_status(invitation_service)
@service.run(@nilm, params[:role], 'user', invitation_service.user.id)
@permission = @service.permission
render :create, status: @service.success? ? :ok : :unprocessable_entity
end
private
......
......@@ -61,14 +61,20 @@ class UserGroupsController < ApplicationController
# PATCH/PUT /user_groups/1/invite_member.json
def invite_member
@service = InviteUser.new
@service.run(params[:email])
if @service.success?
@user_group.users << @service.user
render :show
else
render :show, status: :unprocessable_entity
end
invitation_service = InviteUser.new()
invitation_service.run(
current_user,
params[:email],
params[:redirect_url])
unless invitation_service.success?
@service = invitation_service
render 'helpers/empty_response', status: :unprocessable_entity
end
user = invitation_service.user
@service = AddGroupMember.new
@service.absorb_status(invitation_service)
@service.run(@user_group, user.id)
render :show, status: @service.success? ? :ok : :unprocessable_entity
end
# PATCH/PUT /user_groups/1/remove_member.json
......
......@@ -3,7 +3,9 @@ class UsersController < ApplicationController
# GET /users.json
def index
@users = User.confirmed
#return all created or accepted users
@users = User.where(invitation_created_at: nil)
.or(User.where.not(invitation_accepted_at: nil))
end
# note: update is handled by devise
......
class Membership < ApplicationRecord
belongs_to :user
belongs_to :user_group
end
......@@ -17,7 +17,11 @@ class Permission < ApplicationRecord
def target_name
if self.user_id?
if self.user.name.empty?
return self.user.email
else
return self.user.name
end
elsif self.user_group_id?
return self.user_group.name
else
......
......@@ -2,13 +2,14 @@ class User < ActiveRecord::Base
#---Attributes------
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :omniauthable
:omniauthable, :invitable
include DeviseTokenAuth::Concerns::User
#---Associations----
has_many :permissions
has_many :nilms, through: :permissions
has_and_belongs_to_many :user_groups
has_many :memberships
has_many :user_groups, through: :memberships
#---Validations-----
validates :first_name, :last_name, :email, :presence => true
......@@ -82,7 +83,15 @@ class User < ActiveRecord::Base
end
def name
"#{self.first_name} #{self.last_name}"
if self.first_name.nil? && self.last_name.nil?
if self.email.nil?
return "UNKNOWN NAME"
else
return self.email
end
else
return "#{self.first_name} #{self.last_name}"
end
end
protected
......
......@@ -13,7 +13,8 @@
#
class UserGroup < ApplicationRecord
#---Associations----
has_and_belongs_to_many :users
has_many :memberships
has_many :users, through: :memberships
belongs_to :owner, class_name: "User"
has_many :permissions, dependent: :destroy
has_many :nilms, through: :permissions
......@@ -30,4 +31,8 @@ class UserGroup < ApplicationRecord
[:id, :name, :description]
end
def accepted_users
self.users.select{|u| u.accepted_or_not_invited?}
end
end
......@@ -35,8 +35,8 @@ class LoadStreamData
)
elements = db_stream.db_elements.order(:column)
if plottable_decim.nil?
#check if its nil becuase the nilm isn't available
return self unless self.success?
# check if its nil becuase the nilm isn't available
return self unless success?
# data is not sufficiently decimated, get intervals from
# the valid decimation level (highest resolution)
path = __build_path(db_stream, valid_decim.level)
......@@ -58,8 +58,8 @@ class LoadStreamData
@data = __build_raw_data(elements, resp)
else
@data_type = 'decimated'
decimateable_elements = elements.where(display_type: ["continuous","discrete"])
interval_elements = elements.where(display_type: "event")
decimateable_elements = elements.where(display_type: %w(continuous discrete))
interval_elements = elements.where(display_type: 'event')
@data = __build_decimated_data(decimateable_elements, resp) +
__build_intervals_from_decimated_data(interval_elements, resp)
end
......@@ -163,10 +163,10 @@ class LoadStreamData
end
ts = row[0]
elements.each_with_index do |elem, i|
data[i][:values].push([ts, __scale_value(row[1+i],elem)])
data[i][:values].push([ts, __scale_value(row[1 + i], elem)])
end
end
return data
data
end
def __build_decimated_data(elements, resp)
......@@ -178,46 +178,44 @@ class LoadStreamData
end
ts = row[0]
elements.each_with_index do |elem, i|
####TODO: fix offset calcs when elements is a subset
# ###TODO: fix offset calcs when elements is a subset
mean_offset = 0
min_offset = elem.db_stream.db_elements.length
max_offset = elem.db_stream.db_elements.length*2
mean = __scale_value(row[1+elem.column+mean_offset],elem)
min = __scale_value(row[1+elem.column+min_offset], elem)
max = __scale_value(row[1+elem.column+max_offset], elem)
tmp_min = [min,max].min
max = [min,max].max
max_offset = elem.db_stream.db_elements.length * 2
mean = __scale_value(row[1 + elem.column + mean_offset], elem)
min = __scale_value(row[1 + elem.column + min_offset], elem)
max = __scale_value(row[1 + elem.column + max_offset], elem)
tmp_min = [min, max].min
max = [min, max].max
min = tmp_min
data[i][:values].push([ts,mean,min,max])
data[i][:values].push([ts, mean, min, max])
end
end
return data
data
end
def __build_interval_data(elements, resp)
elements.map { |e| { id: e.id, type: 'interval', values: resp } }
end
#for data that cannot be represented as decimations
# for data that cannot be represented as decimations
# eg: events, compute intervals from the actual decimated data
def __build_intervals_from_decimated_data(elements, resp)
#compute intervals from resp
if(resp.empty?)
return {id: e.id, type: 'interval', values: []}
end
# compute intervals from resp
return { id: e.id, type: 'interval', values: [] } if resp.empty?
intervals = []
interval_start = nil
interval_end = nil
resp.each do |row|
if row.nil?
if !interval_start.nil? && !interval_end.nil?
#interval break and we know the start and end times
# interval break and we know the start and end times
intervals += [[interval_start, 0], [interval_end, 0], nil]
end
interval_start = nil
end
next
end
if interval_start == nil
if interval_start.nil?
interval_start = row[0]
next
end
......@@ -234,7 +232,7 @@ class LoadStreamData
end
end
def __scale_value(value,element)
(value.to_f-element.offset)*element.scale_factor
def __scale_value(value, element)
(value.to_f - element.offset) * element.scale_factor
end
end
......@@ -38,7 +38,7 @@ class CreatePermission
add_errors(@permission.errors.full_messages)
return self
end
set_notice("Created permission")
add_notice("Created permission")
self
end
end
# frozen_string_literal: true
# Invite new users by e-mail
class InviteUser
include ServiceStatus
attr_reader :user
def run(inviter, email, redirect_url)
# create a new user account for [email]
# if an account with [email] exists and is confirmed
# add a warning that the user exists
# if the account exists but is not confirmed send another email
# and add a success message that the e-mail was sent
#
@user = User.find_by_email(email)
if @user.nil? || !@user.accepted_or_not_invited?
#invite the user, they are new or have not accepted their invitation
@user = User.invite!({:email=>email}, inviter) do |u|
u.invitation_url = redirect_url
end
unless @user.errors.empty?
add_errors(@user.errors.full_messages)
return self
end
set_notice("sent invitation to [#{email}]")
else
# user exists already
add_warning("account exists for #{email}")
return self
end
self
end
end
......@@ -19,8 +19,10 @@ class AddGroupMember
return self
end
# ok, this user is new to the group, add them
@user_group.users << user
set_notice("added user to group")
# create the Membership directly to avoid validation of
# invited users who do not have all attributes set
Membership.create(user: user, user_group: user_group)
add_notice("added user to group")
self
end
end
Hello <%= @resource.email %>,<br/>
<p><%= @resource.invited_by.name %> has invited you to join Wattsworth.
Click the link below to create your account.</p>
<p><%= link_to "Accept Invitation",
"#{@resource.invitation_url}?invitation_token=#{@token}" %></p>
<p>If you don't want to accept the invitation, please ignore this email.<br />
<br/>
~wattsworth robot
Hello <%= @resource.email %>,
<%= @resource.invited_by.name %> has invited you to join Wattsworth.
Click the link below to create your account.
<%="#{@resource.invitation_url}?invitation_token=#{@token}" %>
If you don't want to accept the invitation, please ignore this email.
~Wattsworth robot
json.owner do
json.array! @owned_groups do |group|
json.extract! group, *UserGroup.json_keys
json.members group.users do |user|
json.members group.accepted_users do |user|
json.extract! user, *User.json_keys
end
end
......
json.data do
json.extract! @user_group, *UserGroup.json_keys
if(@user_group.owner==current_user)
json.members @user_group.users do |user|
json.members @user_group.users
.select {|u| u.accepted_or_not_invited? } do |user|
json.extract! user, *User.json_keys
end
end
......
......@@ -13,7 +13,7 @@ module ControlPanel
# -- all .rb files in that directory are automatically loaded.
config.api_only = true
# Add folders under the services and adapters directory
%w(data nilm db db_folder db_stream permission user_group).each do |service|
%w(data nilm db db_folder db_stream permission user_group user).each do |service|
config.autoload_paths << Rails.root.join("app/services/#{service}")
end
config.autoload_paths << Rails.root.join("app/adapters")
......
......@@ -33,7 +33,7 @@ Rails.application.configure do
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
# Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr
......
......@@ -7,4 +7,44 @@ Devise.setup do |config|
# middleware b/c rails-api does not include it.
# See: http://stackoverflow.com/q/19600905/806956
config.navigational_formats = [:json]
# ==> Configuration for :invitable
# The period the generated invitation token is valid, after
# this period, the invited resource won't be able to accept the invitation.
# When invite_for is 0 (the default), the invitation won't expire.
# config.invite_for = 2.weeks
# Number of invitations users can send.
# - If invitation_limit is nil, there is no limit for invitations, users can
# send unlimited invitations, invitation_limit column is not used.
# - If invitation_limit is 0, users can't send invitations by default.
# - If invitation_limit n > 0, users can send n invitations.
# You can change invitation_limit column for some users so they can send more
# or less invitations, even with global invitation_limit = 0
# Default: nil
# config.invitation_limit = 5
# The key to be used to check existing users when sending an invitation
# and the regexp used to test it when validate_on_invite is not set.
# config.invite_key = {:email => /\\A[^@]+@[^@]+\\z/}
# config.invite_key = {:email => /\\A[^@]+@[^@]+\\z/, :username => nil}
# Flag that force a record to be valid before being actually invited
# Default: false
# config.validate_on_invite = true
# Resend invitation if user with invited status is invited again
# Default: true
# config.resend_invitation = false
# The class name of the inviting model. If this is nil,
# the #invited_by association is declared to be polymorphic.
# Default: nil
# config.invited_by_class_name = 'User'
# The foreign key to the inviting model (if invited_by_class_name is set)
# Default: :invited_by_id
# config.invited_by_foreign_key = :invited_by_id
# The column name used for counter_cache column. If this is nil,
# the #invited_by association is declared without counter_cache.
# Default: nil
# config.invited_by_counter_cache = :invitations_count
# Auto-login after the user accepts the invite. If this is false,
# the user will need to manually log in after accepting the invite.
# Default: true
# config.allow_insecure_sign_in_after_accept = false
end
en:
devise:
failure:
invited: "You have a pending invitation, accept it to finish creating your account."
invitations:
send_instructions: "An invitation email has been sent to %{email}."
invitation_token_invalid: "The invitation token provided is not valid!"
updated: "Your password was set successfully. You are now signed in."
updated_not_active: "Your password was set successfully."
no_invitations_remaining: "No invitations remaining"
invitation_removed: "Your invitation was removed."
new:
header: "Send invitation"
submit_button: "Send an invitation"
edit:
header: "Set your password"
submit_button: "Set my password"
mailer:
invitation_instructions:
subject: "Invitation instructions"
hello: "Hello %{email}"
someone_invited_you: "Someone has invited you to Wattsworth, you can accept it through the link below."
accept: "Accept invitation"
accept_until: "This invitation will be due in %{due_date}."
ignore: "If you don't want to accept the invitation, please ignore this email.<br />\nYour account won't be created until you access the link above and set your password."
time:
formats:
devise:
mailer:
invitation_instructions:
accept_until_format: "%B %d, %Y %I:%M %p"
......@@ -14,7 +14,12 @@ Rails.application.routes.draw do
end
end
mount_devise_token_auth_for 'User', at: 'auth'
# fix for devise invitable from:
#http://gabrielhilal.com/2015/11/07/integrating-devise_invitable-into-devise_token_auth/
mount_devise_token_auth_for 'User', at: 'auth', skip: [:invitations]
devise_for :users, path: "auth", only: [:invitations],
controllers: { invitations: 'invitations' }
resources :users, only: [:index, :create, :destroy]
resources :user_groups, only: [:index, :update, :create, :destroy] do
member do
......
class AddInvitableToUser < ActiveRecord::Migration[5.0]
def change
add_column :users, :invitation_token, :string
add_column :users, :invitation_created_at, :datetime
add_column :users, :invitation_sent_at, :datetime
add_column :users, :invitation_accepted_at, :datetime
add_column :users, :invitation_limit, :integer
add_column :users, :invited_by_id, :integer
add_column :users, :invited_by_type, :string
add_index :users, :invitation_token, :unique => true
# Allow null encrypted_password
change_column_null :users, :encrypted_password, :string, true
# Allow null password_salt (add it if you are using Devise's encryptable module)
# change_column_null :users, :password_salt, :string, true
end
end
class AddInvitationUrlToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :invitation_url, :string
end
end
class RenameJoinTableToMemberships < ActiveRecord::Migration[5.0]
def change
rename_table :user_groups_users, :memberships
end
end
......@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170422184639) do
ActiveRecord::Schema.define(version: 20170506014329) do
create_table "db_decimations", force: :cascade do |t|
t.integer "start_time", limit: 8
......@@ -86,6 +86,13 @@ ActiveRecord::Schema.define(version: 20170422184639) do
t.boolean "available"
end
create_table "memberships", id: false, force: :cascade do |t|
t.integer "user_group_id"
t.integer "user_id"
t.index ["user_group_id"], name: "index_memberships_on_user_group_id"
t.index ["user_id"], name: "index_memberships_on_user_id"
end
create_table "nilms", force: :cascade do |t|
t.string "name"
t.string "description"
......@@ -111,17 +118,10 @@ ActiveRecord::Schema.define(version: 20170422184639) do
t.datetime "updated_at", null: false
end
create_table "user_groups_users", id: false, force: :cascade do |t|
t.integer "user_group_id"
t.integer "user_id"
t.index ["user_group_id"], name: "index_user_groups_users_on_user_group_id"
t.index ["user_id"], name: "index_user_groups_users_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "provider", default: "email", null: false
t.string "uid", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "encrypted_password", default: ""
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
......@@ -140,8 +140,17 @@ ActiveRecord::Schema.define(version: 20170422184639) do
t.text "tokens"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "invitation_token"
t.datetime "invitation_created_at"
t.datetime "invitation_sent_at"
t.datetime "invitation_accepted_at"
t.integer "invitation_limit"
t.integer "invited_by_id"
t.string "invited_by_type"
t.string "invitation_url"
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["invitation_token"], name: "index_users_on_invitation_token", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
t.index ["uid", "provider"], name: "index_users_on_uid_and_provider", unique: true
end
......
......@@ -2,8 +2,8 @@
require 'rails_helper'
RSpec.describe DbElementsController, type: :request do
let(:user1) { create(:confirmed_user, first_name: 'John') }
let(:user2) { create(:confirmed_user, first_name: 'Sam') }
let(:user1) { create(:user, first_name: 'John') }
let(:user2) { create(:user, first_name: 'Sam') }
describe 'GET #data' do
# retrieve data for elements listed by array of ids
context 'with authenticated user' do
......
......@@ -2,8 +2,8 @@
require 'rails_helper'
RSpec.describe DbFoldersController, type: :request do
let(:john) { create(:confirmed_user, first_name: 'John') }
let(:steve) { create(:confirmed_user, first_name: 'Steve') }
let(:john) { create(:user, first_name: 'John') }
let(:steve) { create(:user, first_name: 'Steve') }
let(:john_nilm) { create(:nilm, name: "John's NILM", admins: [john]) }
let(:john_folder) do
create(:db_folder, name: 'John Folder',
......
......@@ -17,8 +17,6 @@ RSpec.describe DbStreamsController, type: :request do
describe 'PUT update' do
before do
john.confirm
steve.confirm
@mock_adapter = double(DbAdapter) # MockDbAdapter.new #instance_double(DbAdapter)
@db_success = { error: false, msg: 'success' }
@db_failure = { error: true, msg: 'dberror' }
......
......@@ -12,10 +12,6 @@ RSpec.describe DbsController, type: :request do
# index action does not exist
describe 'GET show' do
before do
john.confirm
steve.confirm
end
context 'with any permissions' do
it 'returns the db as json' do
# john has some permission on all 3 nilms
......@@ -50,10 +46,6 @@ RSpec.describe DbsController, type: :request do
describe 'PUT update' do
before do
john.confirm
steve.confirm
end
context 'with owner permissions' do
it 'returns 422 on invalid parameters' do
# max points must be a positive number
......
......@@ -3,9 +3,9 @@
require 'rails_helper'
RSpec.describe NilmsController, type: :request do
let(:john) { create(:confirmed_user, first_name: 'John') }
let(:nicky) {create(:confirmed_user, first_name: 'Nicky')}
let(:steve) { create(:confirmed_user, first_name: 'Steve') }
let(:john) { create(:user, first_name: 'John') }
let(:nicky) {create(:user, first_name: 'Nicky')}
let(:steve) { create(:user, first_name: 'Steve') }
let(:john_nilm) { create(:nilm, name: "John's NILM", admins: [john], owners: [nicky]) }
let(:lab_nilm) { create(:nilm, name: 'Lab NILM', owners: [john]) }
let(:pete_nilm) { create(:nilm, name: "Pete's NILM", viewers: [john])}
......
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe PermissionsController, type: :request do
let(:john) { create(:confirmed_user, first_name: 'John') }
let(:nicky) { create(:confirmed_user, first_name: 'Nicky')}
let(:steve) { create(:confirmed_user, first_name: 'Steve') }
let(:pete) { create(:confirmed_user, first_name: 'Pete') }
let(:john_nilm) { create(:nilm, name: "John's NILM",
let(:john) { create(:user, first_name: 'John') }
let(:nicky) { create(:user, first_name: 'Nicky') }
let(:steve) { create(:user, first_name: 'Steve') }
let(:pete) { create(:user, first_name: 'Pete') }
let(:john_nilm) do
create(:nilm, name: "John's NILM",
admins: [john],
owners: [nicky],
viewers: [steve]) }
viewers: [steve])
end
describe 'GET #index' do
# list permissions by nilm
context 'with admin privileges' do
it 'returns nilm permissions' do
@auth_headers = john.create_new_auth_token
get "/permissions.json",
params: {nilm_id: john_nilm.id},
get '/permissions.json',
params: { nilm_id: john_nilm.id },
headers: @auth_headers
expect(response).to have_http_status(:ok)
expect(response.header['Content-Type']).to include('application/json')
......@@ -26,10 +29,10 @@ RSpec.describe PermissionsController, type: :request do
end
context 'without admin privileges' do
it 'returns unauthorized' do
[nicky,steve].each do |user|
[nicky, steve].each do |user|
@auth_headers = user.create_new_auth_token
get "/permissions.json",
params: {nilm_id: john_nilm.id},
get '/permissions.json',
params: { nilm_id: john_nilm.id },
headers: @auth_headers
expect(response).to have_http_status(:unauthorized)
end
......@@ -37,8 +40,8 @@ RSpec.describe PermissionsController, type: :request do
it 'returns not found on bad nilm id' do
# nilm 99 does not exist
@auth_headers = steve.create_new_auth_token
get "/permissions.json",
params: {nilm_id: 99},
get '/permissions.json',
params: { nilm_id: 99 },
headers: @auth_headers
expect(response).to have_http_status(:not_found)
end
......@@ -46,7 +49,7 @@ RSpec.describe PermissionsController, type: :request do
context 'without sign-in' do
it 'returns unauthorized' do
# no headers: nobody is signed in, deny all
get "/permissions.json"
get '/permissions.json'
expect(response).to have_http_status(:unauthorized)
end
end
......@@ -57,11 +60,11 @@ RSpec.describe PermissionsController, type: :request do
context 'with admin privileges' do
it 'adds new permission' do
@auth_headers = john.create_new_auth_token
post "/permissions.json",
params: {nilm_id: john_nilm.id,
post '/permissions.json',
params: { nilm_id: john_nilm.id,
role: 'viewer',
target: 'user',
target_id: pete.id},
target_id: pete.id },
headers: @auth_headers
expect(response).to have_http_status(:ok)
expect(response.header['Content-Type']).to include('application/json')
......@@ -71,11 +74,11 @@ RSpec.describe PermissionsController, type: :request do
it 'returns errors on invalid request' do
# steve already has permissions on this nilm
@auth_headers = john.create_new_auth_token
post "/permissions.json",
params: {nilm_id: john_nilm.id,
post '/permissions.json',
params: { nilm_id: john_nilm.id,
role: 'owner',
target: 'user',
target_id: steve.id},
target_id: steve.id },
headers: @auth_headers
expect(response).to have_http_status(:unprocessable_entity)
expect(response.header['Content-Type']).to include('application/json')
......@@ -84,10 +87,10 @@ RSpec.describe PermissionsController, type: :request do
end
context 'without admin privileges' do
it 'returns unauthorized' do
[nicky,steve].each do |user|
[nicky, steve].each do |user|
@auth_headers = user.create_new_auth_token
post "/permissions.json",
params: {nilm_id: john_nilm.id},
post '/permissions.json',
params: { nilm_id: john_nilm.id },
headers: @auth_headers
expect(response).to have_http_status(:unauthorized)
end
......@@ -96,7 +99,7 @@ RSpec.describe PermissionsController, type: :request do
context 'without sign-in' do
it 'returns unauthorized' do
# no headers: nobody is signed in, deny all
post "/permissions.json"
post '/permissions.json'
expect(response).to have_http_status(:unauthorized)
end
end
......@@ -106,12 +109,12 @@ RSpec.describe PermissionsController, type: :request do
context 'with admin privileges' do
it 'creates user with specified permission' do
@auth_headers = john.create_new_auth_token
put "/permissions/create_user.json",
params: {nilm_id: john_nilm.id,
put '/permissions/create_user.json',
params: { nilm_id: john_nilm.id,
role: 'viewer',
first_name: 'bill', last_name: 'will',
email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'poorchoice'},
password_confirmation: 'poorchoice' },
headers: @auth_headers
expect(response).to have_http_status(:ok)
expect(response).to have_notice_message
......@@ -119,14 +122,14 @@ RSpec.describe PermissionsController, type: :request do
expect(user.views_nilm?(john_nilm)).to be true
end
it 'returns error if user cannot be created' do
#password does not match confirmation
# password does not match confirmation
@auth_headers = john.create_new_auth_token
put "/permissions/create_user.json",
params: {nilm_id: john_nilm.id,
put '/permissions/create_user.json',
params: { nilm_id: john_nilm.id,
role: 'viewer',
first_name: 'bill', last_name: 'will',
email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'error'},
password_confirmation: 'error' },
headers: @auth_headers
expect(response).to have_http_status(:unprocessable_entity)
expect(response).to have_error_message
......@@ -136,14 +139,14 @@ RSpec.describe PermissionsController, type: :request do
end
context 'with anyone else' do
it 'returns unauthorized' do
#password does not match confirmation
# password does not match confirmation
@auth_headers = steve.create_new_auth_token
put "/permissions/create_user.json",
params: {nilm_id: john_nilm.id,
put '/permissions/create_user.json',
params: { nilm_id: john_nilm.id,
role: 'viewer',
first_name: 'bill', last_name: 'will',
email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'error'},
password_confirmation: 'error' },
headers: @auth_headers
expect(response).to have_http_status(:unauthorized)
user = User.find_by_email('valid@url.com')
......@@ -152,13 +155,13 @@ RSpec.describe PermissionsController, type: :request do
end
context 'without signin' do
it 'returns unauthorized' do
#password does not match confirmation
put "/permissions/create_user.json",
params: {nilm_id: john_nilm.id,
# password does not match confirmation
put '/permissions/create_user.json',
params: { nilm_id: john_nilm.id,
role: 'viewer',
first_name: 'bill', last_name: 'will',
email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'error'}
password_confirmation: 'error' }
expect(response).to have_http_status(:unauthorized)
user = User.find_by_email('valid@url.com')
expect(user).to be nil
......@@ -166,6 +169,73 @@ RSpec.describe PermissionsController, type: :request do
end
end
describe 'PUT #invite_user' do
context 'with admin' do
before do
@auth_headers = john.create_new_auth_token
end
it 'invites a user and grants specified permission' do
put '/permissions/invite_user.json',
params: { nilm_id: john_nilm.id,
role: 'owner',
email: 'test@test.com',
redirect_url: 'localhost' },
headers: @auth_headers
expect(response.status).to eq(200)
# new user is created
@invitee = User.find_by_email('test@test.com')
# invited by current user
expect(@invitee.invited_by).to eq john
# new user has permissions on nilm
expect(@invitee.owns_nilm?(john_nilm)).to be true
# new user is not included in permissions list
data = JSON.parse(response.body)['data']
expect(data['target_name']).to eq 'test@test.com'
end
it 'adds existing users to the group' do
user = create(:user, first_name: 'sam', last_name: 'davy',
email: 'member@test.com')
nilm = john_nilm
user_count = User.count
put '/permissions/invite_user.json',
params: { nilm_id: john_nilm.id,
role: 'viewer',
email: 'member@test.com',
redirect_url: 'localhost' },
headers: @auth_headers
expect(response.status).to eq(200)
# no new user is created
expect(User.count).to eq user_count
# user is a group member
expect(user.views_nilm?(john_nilm)).to be true
# user name is set as target name
data = JSON.parse(response.body)['data']
expect(data['target_name']).to eq 'sam davy'
end
end
context 'with anyone else' do
it 'returns unauthorized' do
@auth_headers = steve.create_new_auth_token
put '/permissions/invite_user.json',
params: { nilm_id: john_nilm.id,
role: 'viewer',
email: 'test@test.com',
redirect_url: 'localhost' },
headers: @auth_headers
expect(response).to have_http_status(:unauthorized)
end
end
context 'without sigin' do
it 'returns unauthorized' do
put '/permissions/invite_user.json',
params: { nilm_id: john_nilm.id,
role: 'viewer',
email: 'test@test.com',
redirect_url: 'localhost' }
expect(response).to have_http_status(:unauthorized)
end
end
end
describe 'DELETE #destroy' do
# removes specified permission from nilm
......@@ -175,7 +245,7 @@ RSpec.describe PermissionsController, type: :request do
expect(steve.views_nilm?(john_nilm)).to be true
@auth_headers = john.create_new_auth_token
delete "/permissions/#{p.id}.json",
params: {nilm_id: john_nilm.id},
params: { nilm_id: john_nilm.id },
headers: @auth_headers
expect(response).to have_http_status(:ok)
expect(response.header['Content-Type']).to include('application/json')
......@@ -187,7 +257,7 @@ RSpec.describe PermissionsController, type: :request do
p = Permission.where(nilm: john_nilm, user: john).first
@auth_headers = john.create_new_auth_token
delete "/permissions/#{p.id}.json",
params: {nilm_id: john_nilm.id},
params: { nilm_id: john_nilm.id },
headers: @auth_headers
expect(response).to have_http_status(:unprocessable_entity)
expect(response.header['Content-Type']).to include('application/json')
......@@ -197,10 +267,10 @@ RSpec.describe PermissionsController, type: :request do
end
context 'without admin privileges' do
it 'returns unauthorized' do
[nicky,steve].each do |user|
[nicky, steve].each do |user|
@auth_headers = user.create_new_auth_token
delete "/permissions/99.json",
params: {nilm_id: john_nilm.id},
delete '/permissions/99.json',
params: { nilm_id: john_nilm.id },
headers: @auth_headers
expect(response).to have_http_status(:unauthorized)
end
......@@ -209,12 +279,9 @@ RSpec.describe PermissionsController, type: :request do
context 'without sign-in' do
it 'returns unauthorized' do
# no headers: nobody is signed in, deny all
delete "/permissions/99.json"
delete '/permissions/99.json'
expect(response).to have_http_status(:unauthorized)
end
end
end
end
......@@ -10,77 +10,77 @@ RSpec.describe UserGroupsController, type: :request do
create(:user_group,
owner: owner,
members: [member1, member2])
end
end
describe 'GET index' do
let(:grp1) { create(:user_group, name: 'Group1') }
let(:grp2) { create(:user_group, name: 'Group2') }
let(:donnals) { create(:user_group, name: 'Donnals',
owner: john, members: [nicky])}
let(:john) { create(:confirmed_user, first_name: 'Jonh') }
let(:nicky) { create(:confirmed_user, first_name: 'Nicky')}
let(:steve) { create(:confirmed_user, first_name: 'Steve')}
let(:donnals) do
create(:user_group, name: 'Donnals',
owner: john, members: [nicky])
end
let(:john) { create(:user, first_name: 'Jonh') }
let(:nicky) { create(:user, first_name: 'Nicky') }
let(:steve) { create(:user, first_name: 'Steve') }
before do
# force lazy evaluation of let to build groups
grp1; grp2; donnals;
grp1; grp2; donnals
end
context 'with john' do
it 'returns 1 owner, 0 members, 2 others' do
@auth_headers = john.create_new_auth_token
get "/user_groups.json", headers: @auth_headers
get '/user_groups.json', headers: @auth_headers
expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body)
expect(body["owner"].length).to eq(1)
expect(body["owner"][0]["members"].length).to eq(1)
expect(body["member"].length).to eq(0)
expect(body["other"].length).to eq(2)
expect(body['owner'].length).to eq(1)
expect(body['owner'][0]['members'].length).to eq(1)
expect(body['member'].length).to eq(0)
expect(body['other'].length).to eq(2)
end
end
context 'with nicky' do
it 'returns 0 owners, 1 member, 2 others' do
@auth_headers = nicky.create_new_auth_token
get "/user_groups.json", headers: @auth_headers
get '/user_groups.json', headers: @auth_headers
expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body)
expect(body["owner"].length).to eq(0)
expect(body["member"].length).to eq(1)
expect(body["other"].length).to eq(2)
expect(body['owner'].length).to eq(0)
expect(body['member'].length).to eq(1)
expect(body['other'].length).to eq(2)
end
end
context 'with steve' do
it 'returns 0 owners, 0 members, 3 others' do
@auth_headers = steve.create_new_auth_token
get "/user_groups.json", headers: @auth_headers
get '/user_groups.json', headers: @auth_headers
expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body)
expect(body["owner"].length).to eq(0)
expect(body["member"].length).to eq(0)
expect(body["other"].length).to eq(3)
expect(body['owner'].length).to eq(0)
expect(body['member'].length).to eq(0)
expect(body['other'].length).to eq(3)
end
end
context 'without sign-in' do
it 'returns unauthorized' do
get "/user_groups.json"
get '/user_groups.json'
expect(response.status).to eq(401)
end
end
end
describe 'PUT add_member' do
context 'with owner' do
it 'adds a member' do
@auth_headers = owner.create_new_auth_token
put "/user_groups/#{group.id}/add_member.json",
params: { user_id: other_user.id},
params: { user_id: other_user.id },
headers: @auth_headers
expect(response.status).to eq(200)
expect(group.reload.users.include?(other_user)).to be true
expect(response).to have_notice_message
#check to make sure JSON renders the members
# check to make sure JSON renders the members
body = JSON.parse(response.body)
expect(body['data']['members'].count).to eq group.users.count
end
......@@ -88,7 +88,7 @@ end
@auth_headers = owner.create_new_auth_token
# member1 is already a member
put "/user_groups/#{group.id}/add_member.json",
params: { user_id: member1.id},
params: { user_id: member1.id },
headers: @auth_headers
expect(response).to have_http_status(:unprocessable_entity)
expect(response).to have_error_message
......@@ -98,7 +98,7 @@ end
it 'returns unauthorized' do
@auth_headers = member1.create_new_auth_token
put "/user_groups/#{group.id}/add_member.json",
params: { user_id: other_user.id},
params: { user_id: other_user.id },
headers: @auth_headers
expect(response).to have_http_status(:unauthorized)
end
......@@ -106,7 +106,7 @@ end
context 'without sign-in' do
it 'returns unauthorized' do
put "/user_groups/#{group.id}/add_member.json",
params: { user_id: other_user.id}
params: { user_id: other_user.id }
expect(response).to have_http_status(:unauthorized)
end
end
......@@ -118,24 +118,24 @@ end
members = group.users.length
@auth_headers = owner.create_new_auth_token
put "/user_groups/#{group.id}/create_member.json",
params: {first_name: 'bill', last_name: 'will',
params: { first_name: 'bill', last_name: 'will',
email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'poorchoice'},
password_confirmation: 'poorchoice' },
headers: @auth_headers
expect(response).to have_http_status(:ok)
expect(User.find_by_email('valid@url.com')).to_not be nil
expect(response).to have_notice_message
#make sure response contains the new user
# make sure response contains the new user
expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body)
expect(body["data"]["members"].length).to eq(members+1)
expect(body['data']['members'].length).to eq(members + 1)
end
it 'returns error message if user has errors' do
@auth_headers = owner.create_new_auth_token
put "/user_groups/#{group.id}/create_member.json",
params: {first_name: 'bill', last_name: 'will',
params: { first_name: 'bill', last_name: 'will',
email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'nomatch'},
password_confirmation: 'nomatch' },
headers: @auth_headers
expect(response).to have_http_status(:unprocessable_entity)
expect(User.find_by_email('valid@url.com')).to be nil
......@@ -146,9 +146,9 @@ end
it 'returns unauthorized' do
@auth_headers = member1.create_new_auth_token
put "/user_groups/#{group.id}/create_member.json",
params: {first_name: 'bill', last_name: 'will',
params: { first_name: 'bill', last_name: 'will',
email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'poorchoice'},
password_confirmation: 'poorchoice' },
headers: @auth_headers
expect(response).to have_http_status(:unauthorized)
expect(User.find_by_email('valid@url.com')).to be nil
......@@ -157,9 +157,9 @@ end
context 'without sigin' do
it 'returns unauthorized' do
put "/user_groups/#{group.id}/create_member.json",
params: {first_name: 'bill', last_name: 'will',
params: { first_name: 'bill', last_name: 'will',
email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'poorchoice'}
password_confirmation: 'poorchoice' }
expect(response).to have_http_status(:unauthorized)
expect(User.find_by_email('valid@url.com')).to be nil
end
......@@ -168,14 +168,56 @@ end
describe 'PUT invite_member' do
context 'with owner' do
it 'invites a user and adds him to the group'
it 'adds existing members to the group'
before do
@auth_headers = owner.create_new_auth_token
end
it 'invites a user and adds him to the group' do
put "/user_groups/#{group.id}/invite_member.json",
params: { email: 'test@test.com', redirect_url: 'localhost' },
headers: @auth_headers
expect(response.status).to eq(200)
# new user is created
@invitee = User.find_by_email('test@test.com')
# invited by current user
expect(@invitee.invited_by).to eq owner
# new user is a group member
expect(group.reload.users.include?(@invitee)).to be true
# new user is not included in group list
members = JSON.parse(response.body)['data']['members']
expect(members.select { |u| u == @invitee }).to be_empty
end
it 'adds existing users to the group' do
user = create(:user, email: 'member@test.com')
url = "/user_groups/#{group.id}/invite_member.json"
user_count = User.count
put url,
params: { email: 'member@test.com', redirect_url: 'localhost' },
headers: @auth_headers
expect(response.status).to eq(200)
# no new user is created
expect(User.count).to eq user_count
# user is a group member
expect(group.reload.users.include?(user)).to be true
# user is included in group list
members = JSON.parse(response.body)['data']['members']
expect(members.select { |u| u['id'] == user.id }).to_not be_empty
end
end
context 'with anyone else' do
it 'returns unauthorized'
it 'returns unauthorized' do
@auth_headers = member1.create_new_auth_token
put "/user_groups/#{group.id}/invite_member.json",
params: { email: 'member@test.com', redirect_url: 'localhost' },
headers: @auth_headers
expect(response).to have_http_status(:unauthorized)
end
end
context 'without sigin' do
it 'returns unauthorized'
it 'returns unauthorized' do
put "/user_groups/#{group.id}/invite_member.json",
params: { email: 'member@test.com', redirect_url: 'localhost' }
expect(response).to have_http_status(:unauthorized)
end
end
end
......@@ -184,12 +226,12 @@ end
it 'removes a member' do
@auth_headers = owner.create_new_auth_token
put "/user_groups/#{group.id}/remove_member.json",
params: { user_id: member1.id},
params: { user_id: member1.id },
headers: @auth_headers
expect(response.status).to eq(200)
expect(group.reload.users.include?(member1)).to be false
expect(response).to have_notice_message
#check to make sure JSON renders the members
# check to make sure JSON renders the members
body = JSON.parse(response.body)
expect(body['data']['members'].count).to eq group.users.count
end
......@@ -197,7 +239,7 @@ end
@auth_headers = owner.create_new_auth_token
# other_user is not a member
put "/user_groups/#{group.id}/remove_member.json",
params: { user_id: other_user.id},
params: { user_id: other_user.id },
headers: @auth_headers
expect(response).to have_http_status(:unprocessable_entity)
expect(response).to have_error_message
......@@ -207,7 +249,7 @@ end
it 'returns unauthorized' do
@auth_headers = member1.create_new_auth_token
put "/user_groups/#{group.id}/remove_member.json",
params: { user_id: member2.id},
params: { user_id: member2.id },
headers: @auth_headers
expect(response).to have_http_status(:unauthorized)
end
......@@ -215,7 +257,7 @@ end
context 'without sign-in' do
it 'returns unauthorized' do
put "/user_groups/#{group.id}/remove_member.json",
params: { user_id: other_user.id}
params: { user_id: other_user.id }
expect(response).to have_http_status(:unauthorized)
end
end
......@@ -225,13 +267,13 @@ end
context 'with authenticated user' do
it 'creates a group' do
@auth_headers = other_user.create_new_auth_token
post "/user_groups.json",
params: {name: 'test_group', description: 'some text'},
post '/user_groups.json',
params: { name: 'test_group', description: 'some text' },
headers: @auth_headers
expect(response).to have_http_status(:ok)
expect(response).to have_notice_message
expect(UserGroup.find_by_name('test_group').owner).to eq other_user
#check to make sure JSON renders the members
# check to make sure JSON renders the members
body = JSON.parse(response.body)
# no members yet
expect(body['data']['members'].count).to eq 0
......@@ -239,8 +281,8 @@ end
it 'returns error if unsuccesful' do
@auth_headers = other_user.create_new_auth_token
create(:user_group, name: 'CanOnlyBeOne')
post "/user_groups.json",
params: {name: 'CanOnlyBeOne', description: 'some text'},
post '/user_groups.json',
params: { name: 'CanOnlyBeOne', description: 'some text' },
headers: @auth_headers
# can't have duplicate name
expect(response).to have_http_status(:unprocessable_entity)
......@@ -250,8 +292,8 @@ end
end
context 'without sign-in' do
it 'returns unauthorized' do
post "/user_groups.json",
params: { name: 'test', description: 'something'}
post '/user_groups.json',
params: { name: 'test', description: 'something' }
expect(response).to have_http_status(:unauthorized)
end
end
......@@ -269,7 +311,7 @@ end
expect(response).to have_notice_message
expect(UserGroup.exists?(group.id)).to be false
# make sure the associated permissions are destroyed
expect(Permission.count).to eq(pCount-1)
expect(Permission.count).to eq(pCount - 1)
end
end
context 'with anybody else' do
......@@ -295,13 +337,13 @@ end
it 'updates the group' do
@auth_headers = owner.create_new_auth_token
put "/user_groups/#{group.id}.json",
params: {name: 'new', description: 'changed'},
params: { name: 'new', description: 'changed' },
headers: @auth_headers
expect(response).to have_http_status(:ok)
expect(response).to have_notice_message
expect(group.reload.name).to eq('new')
expect(group.description).to eq('changed')
#check to make sure JSON renders the members
# check to make sure JSON renders the members
body = JSON.parse(response.body)
expect(body['data']['members'].count).to eq group.users.count
end
......@@ -310,7 +352,7 @@ end
orig_name = group.name
# name cannot be blank
put "/user_groups/#{group.id}.json",
params: {name: '', description: 'changed'},
params: { name: '', description: 'changed' },
headers: @auth_headers
expect(response).to have_http_status(:unprocessable_entity)
expect(response).to have_error_message
......@@ -322,7 +364,7 @@ end
@auth_headers = member1.create_new_auth_token
orig_name = group.name
put "/user_groups/#{group.id}.json",
params: {name: 'new', description: 'changed'},
params: { name: 'new', description: 'changed' },
headers: @auth_headers
expect(response).to have_http_status(:unauthorized)
expect(group.reload.name).to eq orig_name
......@@ -332,7 +374,7 @@ end
it 'returns unauthorized' do
orig_name = group.name
put "/user_groups/#{group.id}.json",
params: {name: 'new', description: 'changed'}
params: { name: 'new', description: 'changed' }
expect(response).to have_http_status(:unauthorized)
expect(group.reload.name).to eq orig_name
end
......
......@@ -4,17 +4,13 @@ require 'rails_helper'
RSpec.describe UsersController, type: :request do
let(:steve) { create(:user, first_name: 'Steve')}
let(:john) { create(:user, first_name: 'Jonh') }
let(:newguy) { create(:user, first_name: 'Unconfirmed')}
describe 'GET index' do
before do
john.confirm
steve.confirm
end
context 'with authenticated user' do
it 'returns confirmed users' do
it 'returns accepted and created users' do
# force lazy evaluation of let to build users
newguy
newguy = User.invite!({:email=>'newguy@test.com'}, john)
steve
@auth_headers = john.create_new_auth_token
get "/users.json", headers: @auth_headers
expect(response.header['Content-Type']).to include('application/json')
......
......@@ -4,10 +4,6 @@ FactoryGirl.define do
last_name {Faker::Name.first_name}
email {Faker::Internet.unique.email}
password {Faker::Lorem.characters(10)}
factory :confirmed_user do
confirmed_at {Time.now}
end
end
......
......@@ -67,7 +67,7 @@ RSpec.describe 'LoadStreamData' do
else
i_count += 1
expect(data[:type]).to eq 'interval'
expect(data[:values]).to eq [[10,40],[50,90]]
expect(data[:values]).to eq [[40,0],[50,0]]
end
end
expect(d_count).to eq 2 #2 decimated Streams
......
......@@ -12,7 +12,7 @@ RSpec.describe 'CreateNilm' do
errors: ['cannot contact database'],
warnings: [])
allow(UpdateDb).to receive(:new).and_return(service)
user = create(:confirmed_user, first_name: "John")
user = create(:user, first_name: "John")
# run the NILM creation
nilm_creator = CreateNilm.new
nilm_creator.run(
......
......@@ -17,7 +17,7 @@ describe 'AddGroupMember service' do
service.run(group, other_user.id)
expect(service.success?).to be true
expect(group.users.count).to eq(3)
expect(group.users.include?(other_user)).to be(true)
expect(group.users.reload.include?(other_user)).to be(true)
end
it 'errors if user is the owner' do
service = AddGroupMember.new
......
# frozen_string_literal: true
require 'rails_helper'
describe 'InviteUser service' do
let(:inviter) { create(:user) }
let(:service) { InviteUser.new }
describe 'when email is not in database' do
before do
service.run(inviter,"test@test.com","http://redirect.url")
@invitee = service.user
end
it 'creates a new user' do
expect(@invitee).to be_invited_to_sign_up
expect(@invitee.invited_by).to eq inviter
end
it 'sends the user an invitation' do
invitation = ActionMailer::Base.deliveries.last
expect(invitation.to).to eq [@invitee.email]
expect(invitation.body.encoded).to include @invitee.raw_invitation_token
end
it 'adds notice message' do
expect(service.errors?).to be false
expect(service.warnings?).to be false
expect(service.notices.length).to eq 1
end
end
describe 'when email in database' do
before do
service.run(inviter,"test@test.com","http://redirect.url")
@invitee = service.user
end
it 'does not create a new user' do
#invite again
service.run(inviter,"test@test.com","http://redirect.url")
expect(service.user).to eq @invitee
end
it 'does not send an invitation if the user has already accepted' do
User.accept_invitation!(
invitation_token: @invitee.raw_invitation_token,
password: "ad97nwj3o2", first_name: "John Doe", last_name: "Doe")
email_count = ActionMailer::Base.deliveries.length
service.run(inviter,"test@test.com","http://redirect.url")
expect(ActionMailer::Base.deliveries.length).to eq email_count
expect(service.warnings.length).to eq 1
end
it 'resends invitation if user has not accepted yet' do
email_count = ActionMailer::Base.deliveries.length
service.run(inviter,"test@test.com","http://redirect.url")
expect(ActionMailer::Base.deliveries.length).to eq email_count+1
expect(service.notices.length).to eq 1
end
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment