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 ...@@ -35,6 +35,7 @@ gem 'sdoc', '~> 0.4.0', group: :doc
gem 'httparty' gem 'httparty'
gem 'rack-cors' gem 'rack-cors'
gem 'devise_token_auth' gem 'devise_token_auth'
gem 'devise_invitable'
gem 'omniauth' gem 'omniauth'
gem 'oj' # fast json gem 'oj' # fast json
......
...@@ -109,6 +109,9 @@ GEM ...@@ -109,6 +109,9 @@ GEM
railties (>= 4.1.0, < 5.1) railties (>= 4.1.0, < 5.1)
responders responders
warden (~> 1.2.3) warden (~> 1.2.3)
devise_invitable (1.7.2)
actionmailer (>= 4.1.0)
devise (>= 4.0.0)
devise_token_auth (0.1.40) devise_token_auth (0.1.40)
devise (> 3.5.2, <= 4.2) devise (> 3.5.2, <= 4.2)
rails (< 6) rails (< 6)
...@@ -347,6 +350,7 @@ DEPENDENCIES ...@@ -347,6 +350,7 @@ DEPENDENCIES
coffee-rails (~> 4.1.0) coffee-rails (~> 4.1.0)
cucumber-rails cucumber-rails
database_cleaner database_cleaner
devise_invitable
devise_token_auth devise_token_auth
factory_girl_rails factory_girl_rails
faker 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 ...@@ -46,6 +46,24 @@ class PermissionsController < ApplicationController
render :create, status: @service.success? ? :ok : :unprocessable_entity render :create, status: @service.success? ? :ok : :unprocessable_entity
end 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 private
......
...@@ -61,14 +61,20 @@ class UserGroupsController < ApplicationController ...@@ -61,14 +61,20 @@ class UserGroupsController < ApplicationController
# PATCH/PUT /user_groups/1/invite_member.json # PATCH/PUT /user_groups/1/invite_member.json
def invite_member def invite_member
@service = InviteUser.new invitation_service = InviteUser.new()
@service.run(params[:email]) invitation_service.run(
if @service.success? current_user,
@user_group.users << @service.user params[:email],
render :show params[:redirect_url])
else unless invitation_service.success?
render :show, status: :unprocessable_entity @service = invitation_service
end 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 end
# PATCH/PUT /user_groups/1/remove_member.json # PATCH/PUT /user_groups/1/remove_member.json
......
...@@ -3,7 +3,9 @@ class UsersController < ApplicationController ...@@ -3,7 +3,9 @@ class UsersController < ApplicationController
# GET /users.json # GET /users.json
def index 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 end
# note: update is handled by devise # note: update is handled by devise
......
class Membership < ApplicationRecord
belongs_to :user
belongs_to :user_group
end
...@@ -17,7 +17,11 @@ class Permission < ApplicationRecord ...@@ -17,7 +17,11 @@ class Permission < ApplicationRecord
def target_name def target_name
if self.user_id? if self.user_id?
if self.user.name.empty?
return self.user.email
else
return self.user.name return self.user.name
end
elsif self.user_group_id? elsif self.user_group_id?
return self.user_group.name return self.user_group.name
else else
......
...@@ -2,13 +2,14 @@ class User < ActiveRecord::Base ...@@ -2,13 +2,14 @@ class User < ActiveRecord::Base
#---Attributes------ #---Attributes------
devise :database_authenticatable, :registerable, devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :recoverable, :rememberable, :trackable, :validatable,
:confirmable, :omniauthable :omniauthable, :invitable
include DeviseTokenAuth::Concerns::User include DeviseTokenAuth::Concerns::User
#---Associations---- #---Associations----
has_many :permissions has_many :permissions
has_many :nilms, through: :permissions has_many :nilms, through: :permissions
has_and_belongs_to_many :user_groups has_many :memberships
has_many :user_groups, through: :memberships
#---Validations----- #---Validations-----
validates :first_name, :last_name, :email, :presence => true validates :first_name, :last_name, :email, :presence => true
...@@ -82,7 +83,15 @@ class User < ActiveRecord::Base ...@@ -82,7 +83,15 @@ class User < ActiveRecord::Base
end end
def name 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 end
protected protected
......
...@@ -13,7 +13,8 @@ ...@@ -13,7 +13,8 @@
# #
class UserGroup < ApplicationRecord class UserGroup < ApplicationRecord
#---Associations---- #---Associations----
has_and_belongs_to_many :users has_many :memberships
has_many :users, through: :memberships
belongs_to :owner, class_name: "User" belongs_to :owner, class_name: "User"
has_many :permissions, dependent: :destroy has_many :permissions, dependent: :destroy
has_many :nilms, through: :permissions has_many :nilms, through: :permissions
...@@ -30,4 +31,8 @@ class UserGroup < ApplicationRecord ...@@ -30,4 +31,8 @@ class UserGroup < ApplicationRecord
[:id, :name, :description] [:id, :name, :description]
end end
def accepted_users
self.users.select{|u| u.accepted_or_not_invited?}
end
end end
...@@ -35,8 +35,8 @@ class LoadStreamData ...@@ -35,8 +35,8 @@ class LoadStreamData
) )
elements = db_stream.db_elements.order(:column) elements = db_stream.db_elements.order(:column)
if plottable_decim.nil? if plottable_decim.nil?
#check if its nil becuase the nilm isn't available # check if its nil becuase the nilm isn't available
return self unless self.success? return self unless success?
# data is not sufficiently decimated, get intervals from # data is not sufficiently decimated, get intervals from
# the valid decimation level (highest resolution) # the valid decimation level (highest resolution)
path = __build_path(db_stream, valid_decim.level) path = __build_path(db_stream, valid_decim.level)
...@@ -58,8 +58,8 @@ class LoadStreamData ...@@ -58,8 +58,8 @@ class LoadStreamData
@data = __build_raw_data(elements, resp) @data = __build_raw_data(elements, resp)
else else
@data_type = 'decimated' @data_type = 'decimated'
decimateable_elements = elements.where(display_type: ["continuous","discrete"]) decimateable_elements = elements.where(display_type: %w(continuous discrete))
interval_elements = elements.where(display_type: "event") interval_elements = elements.where(display_type: 'event')
@data = __build_decimated_data(decimateable_elements, resp) + @data = __build_decimated_data(decimateable_elements, resp) +
__build_intervals_from_decimated_data(interval_elements, resp) __build_intervals_from_decimated_data(interval_elements, resp)
end end
...@@ -163,10 +163,10 @@ class LoadStreamData ...@@ -163,10 +163,10 @@ class LoadStreamData
end end
ts = row[0] ts = row[0]
elements.each_with_index do |elem, i| 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
end end
return data data
end end
def __build_decimated_data(elements, resp) def __build_decimated_data(elements, resp)
...@@ -178,46 +178,44 @@ class LoadStreamData ...@@ -178,46 +178,44 @@ class LoadStreamData
end end
ts = row[0] ts = row[0]
elements.each_with_index do |elem, i| 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 mean_offset = 0
min_offset = elem.db_stream.db_elements.length min_offset = elem.db_stream.db_elements.length
max_offset = elem.db_stream.db_elements.length*2 max_offset = elem.db_stream.db_elements.length * 2
mean = __scale_value(row[1+elem.column+mean_offset],elem) mean = __scale_value(row[1 + elem.column + mean_offset], elem)
min = __scale_value(row[1+elem.column+min_offset], elem) min = __scale_value(row[1 + elem.column + min_offset], elem)
max = __scale_value(row[1+elem.column+max_offset], elem) max = __scale_value(row[1 + elem.column + max_offset], elem)
tmp_min = [min,max].min tmp_min = [min, max].min
max = [min,max].max max = [min, max].max
min = tmp_min min = tmp_min
data[i][:values].push([ts,mean,min,max]) data[i][:values].push([ts, mean, min, max])
end end
end end
return data data
end end
def __build_interval_data(elements, resp) def __build_interval_data(elements, resp)
elements.map { |e| { id: e.id, type: 'interval', values: resp } } elements.map { |e| { id: e.id, type: 'interval', values: resp } }
end 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 # eg: events, compute intervals from the actual decimated data
def __build_intervals_from_decimated_data(elements, resp) def __build_intervals_from_decimated_data(elements, resp)
#compute intervals from resp # compute intervals from resp
if(resp.empty?) return { id: e.id, type: 'interval', values: [] } if resp.empty?
return {id: e.id, type: 'interval', values: []}
end
intervals = [] intervals = []
interval_start = nil interval_start = nil
interval_end = nil interval_end = nil
resp.each do |row| resp.each do |row|
if row.nil? if row.nil?
if !interval_start.nil? && !interval_end.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] intervals += [[interval_start, 0], [interval_end, 0], nil]
end
interval_start = nil interval_start = nil
end
next next
end end
if interval_start == nil if interval_start.nil?
interval_start = row[0] interval_start = row[0]
next next
end end
...@@ -234,7 +232,7 @@ class LoadStreamData ...@@ -234,7 +232,7 @@ class LoadStreamData
end end
end end
def __scale_value(value,element) def __scale_value(value, element)
(value.to_f-element.offset)*element.scale_factor (value.to_f - element.offset) * element.scale_factor
end end
end end
...@@ -38,7 +38,7 @@ class CreatePermission ...@@ -38,7 +38,7 @@ class CreatePermission
add_errors(@permission.errors.full_messages) add_errors(@permission.errors.full_messages)
return self return self
end end
set_notice("Created permission") add_notice("Created permission")
self self
end end
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 ...@@ -19,8 +19,10 @@ class AddGroupMember
return self return self
end end
# ok, this user is new to the group, add them # ok, this user is new to the group, add them
@user_group.users << user # create the Membership directly to avoid validation of
set_notice("added user to group") # invited users who do not have all attributes set
Membership.create(user: user, user_group: user_group)
add_notice("added user to group")
self self
end end
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.owner do
json.array! @owned_groups do |group| json.array! @owned_groups do |group|
json.extract! group, *UserGroup.json_keys 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 json.extract! user, *User.json_keys
end end
end end
......
json.data do json.data do
json.extract! @user_group, *UserGroup.json_keys json.extract! @user_group, *UserGroup.json_keys
if(@user_group.owner==current_user) 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 json.extract! user, *User.json_keys
end end
end end
......
...@@ -13,7 +13,7 @@ module ControlPanel ...@@ -13,7 +13,7 @@ module ControlPanel
# -- all .rb files in that directory are automatically loaded. # -- all .rb files in that directory are automatically loaded.
config.api_only = true config.api_only = true
# Add folders under the services and adapters directory # 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}") config.autoload_paths << Rails.root.join("app/services/#{service}")
end end
config.autoload_paths << Rails.root.join("app/adapters") config.autoload_paths << Rails.root.join("app/adapters")
......
...@@ -33,7 +33,7 @@ Rails.application.configure do ...@@ -33,7 +33,7 @@ Rails.application.configure do
# The :test delivery method accumulates sent emails in the # The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array. # ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test config.action_mailer.delivery_method = :test
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
# Print deprecation notices to the stderr. # Print deprecation notices to the stderr.
config.active_support.deprecation = :stderr config.active_support.deprecation = :stderr
......
...@@ -7,4 +7,44 @@ Devise.setup do |config| ...@@ -7,4 +7,44 @@ Devise.setup do |config|
# middleware b/c rails-api does not include it. # middleware b/c rails-api does not include it.
# See: http://stackoverflow.com/q/19600905/806956 # See: http://stackoverflow.com/q/19600905/806956
config.navigational_formats = [:json] 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 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 ...@@ -14,7 +14,12 @@ Rails.application.routes.draw do
end end
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 :users, only: [:index, :create, :destroy]
resources :user_groups, only: [:index, :update, :create, :destroy] do resources :user_groups, only: [:index, :update, :create, :destroy] do
member 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 @@ ...@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # 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| create_table "db_decimations", force: :cascade do |t|
t.integer "start_time", limit: 8 t.integer "start_time", limit: 8
...@@ -86,6 +86,13 @@ ActiveRecord::Schema.define(version: 20170422184639) do ...@@ -86,6 +86,13 @@ ActiveRecord::Schema.define(version: 20170422184639) do
t.boolean "available" t.boolean "available"
end 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| create_table "nilms", force: :cascade do |t|
t.string "name" t.string "name"
t.string "description" t.string "description"
...@@ -111,17 +118,10 @@ ActiveRecord::Schema.define(version: 20170422184639) do ...@@ -111,17 +118,10 @@ ActiveRecord::Schema.define(version: 20170422184639) do
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
end 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| create_table "users", force: :cascade do |t|
t.string "provider", default: "email", null: false t.string "provider", default: "email", null: false
t.string "uid", default: "", 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.string "reset_password_token"
t.datetime "reset_password_sent_at" t.datetime "reset_password_sent_at"
t.datetime "remember_created_at" t.datetime "remember_created_at"
...@@ -140,8 +140,17 @@ ActiveRecord::Schema.define(version: 20170422184639) do ...@@ -140,8 +140,17 @@ ActiveRecord::Schema.define(version: 20170422184639) do
t.text "tokens" t.text "tokens"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_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 ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
t.index ["email"], name: "index_users_on_email", 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 ["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 t.index ["uid", "provider"], name: "index_users_on_uid_and_provider", unique: true
end end
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe DbElementsController, type: :request do RSpec.describe DbElementsController, type: :request do
let(:user1) { create(:confirmed_user, first_name: 'John') } let(:user1) { create(:user, first_name: 'John') }
let(:user2) { create(:confirmed_user, first_name: 'Sam') } let(:user2) { create(:user, first_name: 'Sam') }
describe 'GET #data' do describe 'GET #data' do
# retrieve data for elements listed by array of ids # retrieve data for elements listed by array of ids
context 'with authenticated user' do context 'with authenticated user' do
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe DbFoldersController, type: :request do RSpec.describe DbFoldersController, type: :request do
let(:john) { create(:confirmed_user, first_name: 'John') } let(:john) { create(:user, first_name: 'John') }
let(:steve) { create(:confirmed_user, first_name: 'Steve') } let(:steve) { create(:user, first_name: 'Steve') }
let(:john_nilm) { create(:nilm, name: "John's NILM", admins: [john]) } let(:john_nilm) { create(:nilm, name: "John's NILM", admins: [john]) }
let(:john_folder) do let(:john_folder) do
create(:db_folder, name: 'John Folder', create(:db_folder, name: 'John Folder',
......
...@@ -17,8 +17,6 @@ RSpec.describe DbStreamsController, type: :request do ...@@ -17,8 +17,6 @@ RSpec.describe DbStreamsController, type: :request do
describe 'PUT update' do describe 'PUT update' do
before do before do
john.confirm
steve.confirm
@mock_adapter = double(DbAdapter) # MockDbAdapter.new #instance_double(DbAdapter) @mock_adapter = double(DbAdapter) # MockDbAdapter.new #instance_double(DbAdapter)
@db_success = { error: false, msg: 'success' } @db_success = { error: false, msg: 'success' }
@db_failure = { error: true, msg: 'dberror' } @db_failure = { error: true, msg: 'dberror' }
......
...@@ -12,10 +12,6 @@ RSpec.describe DbsController, type: :request do ...@@ -12,10 +12,6 @@ RSpec.describe DbsController, type: :request do
# index action does not exist # index action does not exist
describe 'GET show' do describe 'GET show' do
before do
john.confirm
steve.confirm
end
context 'with any permissions' do context 'with any permissions' do
it 'returns the db as json' do it 'returns the db as json' do
# john has some permission on all 3 nilms # john has some permission on all 3 nilms
...@@ -50,10 +46,6 @@ RSpec.describe DbsController, type: :request do ...@@ -50,10 +46,6 @@ RSpec.describe DbsController, type: :request do
describe 'PUT update' do describe 'PUT update' do
before do
john.confirm
steve.confirm
end
context 'with owner permissions' do context 'with owner permissions' do
it 'returns 422 on invalid parameters' do it 'returns 422 on invalid parameters' do
# max points must be a positive number # max points must be a positive number
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe NilmsController, type: :request do RSpec.describe NilmsController, type: :request do
let(:john) { create(:confirmed_user, first_name: 'John') } let(:john) { create(:user, first_name: 'John') }
let(:nicky) {create(:confirmed_user, first_name: 'Nicky')} let(:nicky) {create(:user, first_name: 'Nicky')}
let(:steve) { create(:confirmed_user, first_name: 'Steve') } let(:steve) { create(:user, first_name: 'Steve') }
let(:john_nilm) { create(:nilm, name: "John's NILM", admins: [john], owners: [nicky]) } let(:john_nilm) { create(:nilm, name: "John's NILM", admins: [john], owners: [nicky]) }
let(:lab_nilm) { create(:nilm, name: 'Lab NILM', owners: [john]) } let(:lab_nilm) { create(:nilm, name: 'Lab NILM', owners: [john]) }
let(:pete_nilm) { create(:nilm, name: "Pete's NILM", viewers: [john])} let(:pete_nilm) { create(:nilm, name: "Pete's NILM", viewers: [john])}
......
# frozen_string_literal: true
require 'rails_helper' require 'rails_helper'
RSpec.describe PermissionsController, type: :request do RSpec.describe PermissionsController, type: :request do
let(:john) { create(:confirmed_user, first_name: 'John') } let(:john) { create(:user, first_name: 'John') }
let(:nicky) { create(:confirmed_user, first_name: 'Nicky')} let(:nicky) { create(:user, first_name: 'Nicky') }
let(:steve) { create(:confirmed_user, first_name: 'Steve') } let(:steve) { create(:user, first_name: 'Steve') }
let(:pete) { create(:confirmed_user, first_name: 'Pete') } let(:pete) { create(:user, first_name: 'Pete') }
let(:john_nilm) { create(:nilm, name: "John's NILM", let(:john_nilm) do
create(:nilm, name: "John's NILM",
admins: [john], admins: [john],
owners: [nicky], owners: [nicky],
viewers: [steve]) } viewers: [steve])
end
describe 'GET #index' do describe 'GET #index' do
# list permissions by nilm # list permissions by nilm
context 'with admin privileges' do context 'with admin privileges' do
it 'returns nilm permissions' do it 'returns nilm permissions' do
@auth_headers = john.create_new_auth_token @auth_headers = john.create_new_auth_token
get "/permissions.json", get '/permissions.json',
params: {nilm_id: john_nilm.id}, params: { nilm_id: john_nilm.id },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
expect(response.header['Content-Type']).to include('application/json') expect(response.header['Content-Type']).to include('application/json')
...@@ -26,10 +29,10 @@ RSpec.describe PermissionsController, type: :request do ...@@ -26,10 +29,10 @@ RSpec.describe PermissionsController, type: :request do
end end
context 'without admin privileges' do context 'without admin privileges' do
it 'returns unauthorized' do it 'returns unauthorized' do
[nicky,steve].each do |user| [nicky, steve].each do |user|
@auth_headers = user.create_new_auth_token @auth_headers = user.create_new_auth_token
get "/permissions.json", get '/permissions.json',
params: {nilm_id: john_nilm.id}, params: { nilm_id: john_nilm.id },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
end end
...@@ -37,8 +40,8 @@ RSpec.describe PermissionsController, type: :request do ...@@ -37,8 +40,8 @@ RSpec.describe PermissionsController, type: :request do
it 'returns not found on bad nilm id' do it 'returns not found on bad nilm id' do
# nilm 99 does not exist # nilm 99 does not exist
@auth_headers = steve.create_new_auth_token @auth_headers = steve.create_new_auth_token
get "/permissions.json", get '/permissions.json',
params: {nilm_id: 99}, params: { nilm_id: 99 },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:not_found) expect(response).to have_http_status(:not_found)
end end
...@@ -46,7 +49,7 @@ RSpec.describe PermissionsController, type: :request do ...@@ -46,7 +49,7 @@ RSpec.describe PermissionsController, type: :request do
context 'without sign-in' do context 'without sign-in' do
it 'returns unauthorized' do it 'returns unauthorized' do
# no headers: nobody is signed in, deny all # no headers: nobody is signed in, deny all
get "/permissions.json" get '/permissions.json'
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
end end
end end
...@@ -57,11 +60,11 @@ RSpec.describe PermissionsController, type: :request do ...@@ -57,11 +60,11 @@ RSpec.describe PermissionsController, type: :request do
context 'with admin privileges' do context 'with admin privileges' do
it 'adds new permission' do it 'adds new permission' do
@auth_headers = john.create_new_auth_token @auth_headers = john.create_new_auth_token
post "/permissions.json", post '/permissions.json',
params: {nilm_id: john_nilm.id, params: { nilm_id: john_nilm.id,
role: 'viewer', role: 'viewer',
target: 'user', target: 'user',
target_id: pete.id}, target_id: pete.id },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
expect(response.header['Content-Type']).to include('application/json') expect(response.header['Content-Type']).to include('application/json')
...@@ -71,11 +74,11 @@ RSpec.describe PermissionsController, type: :request do ...@@ -71,11 +74,11 @@ RSpec.describe PermissionsController, type: :request do
it 'returns errors on invalid request' do it 'returns errors on invalid request' do
# steve already has permissions on this nilm # steve already has permissions on this nilm
@auth_headers = john.create_new_auth_token @auth_headers = john.create_new_auth_token
post "/permissions.json", post '/permissions.json',
params: {nilm_id: john_nilm.id, params: { nilm_id: john_nilm.id,
role: 'owner', role: 'owner',
target: 'user', target: 'user',
target_id: steve.id}, target_id: steve.id },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:unprocessable_entity)
expect(response.header['Content-Type']).to include('application/json') expect(response.header['Content-Type']).to include('application/json')
...@@ -84,10 +87,10 @@ RSpec.describe PermissionsController, type: :request do ...@@ -84,10 +87,10 @@ RSpec.describe PermissionsController, type: :request do
end end
context 'without admin privileges' do context 'without admin privileges' do
it 'returns unauthorized' do it 'returns unauthorized' do
[nicky,steve].each do |user| [nicky, steve].each do |user|
@auth_headers = user.create_new_auth_token @auth_headers = user.create_new_auth_token
post "/permissions.json", post '/permissions.json',
params: {nilm_id: john_nilm.id}, params: { nilm_id: john_nilm.id },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
end end
...@@ -96,7 +99,7 @@ RSpec.describe PermissionsController, type: :request do ...@@ -96,7 +99,7 @@ RSpec.describe PermissionsController, type: :request do
context 'without sign-in' do context 'without sign-in' do
it 'returns unauthorized' do it 'returns unauthorized' do
# no headers: nobody is signed in, deny all # no headers: nobody is signed in, deny all
post "/permissions.json" post '/permissions.json'
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
end end
end end
...@@ -106,12 +109,12 @@ RSpec.describe PermissionsController, type: :request do ...@@ -106,12 +109,12 @@ RSpec.describe PermissionsController, type: :request do
context 'with admin privileges' do context 'with admin privileges' do
it 'creates user with specified permission' do it 'creates user with specified permission' do
@auth_headers = john.create_new_auth_token @auth_headers = john.create_new_auth_token
put "/permissions/create_user.json", put '/permissions/create_user.json',
params: {nilm_id: john_nilm.id, params: { nilm_id: john_nilm.id,
role: 'viewer', role: 'viewer',
first_name: 'bill', last_name: 'will', first_name: 'bill', last_name: 'will',
email: 'valid@url.com', password: 'poorchoice', email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'poorchoice'}, password_confirmation: 'poorchoice' },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
expect(response).to have_notice_message expect(response).to have_notice_message
...@@ -119,14 +122,14 @@ RSpec.describe PermissionsController, type: :request do ...@@ -119,14 +122,14 @@ RSpec.describe PermissionsController, type: :request do
expect(user.views_nilm?(john_nilm)).to be true expect(user.views_nilm?(john_nilm)).to be true
end end
it 'returns error if user cannot be created' do 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 @auth_headers = john.create_new_auth_token
put "/permissions/create_user.json", put '/permissions/create_user.json',
params: {nilm_id: john_nilm.id, params: { nilm_id: john_nilm.id,
role: 'viewer', role: 'viewer',
first_name: 'bill', last_name: 'will', first_name: 'bill', last_name: 'will',
email: 'valid@url.com', password: 'poorchoice', email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'error'}, password_confirmation: 'error' },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:unprocessable_entity)
expect(response).to have_error_message expect(response).to have_error_message
...@@ -136,14 +139,14 @@ RSpec.describe PermissionsController, type: :request do ...@@ -136,14 +139,14 @@ RSpec.describe PermissionsController, type: :request do
end end
context 'with anyone else' do context 'with anyone else' do
it 'returns unauthorized' do it 'returns unauthorized' do
#password does not match confirmation # password does not match confirmation
@auth_headers = steve.create_new_auth_token @auth_headers = steve.create_new_auth_token
put "/permissions/create_user.json", put '/permissions/create_user.json',
params: {nilm_id: john_nilm.id, params: { nilm_id: john_nilm.id,
role: 'viewer', role: 'viewer',
first_name: 'bill', last_name: 'will', first_name: 'bill', last_name: 'will',
email: 'valid@url.com', password: 'poorchoice', email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'error'}, password_confirmation: 'error' },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
user = User.find_by_email('valid@url.com') user = User.find_by_email('valid@url.com')
...@@ -152,13 +155,13 @@ RSpec.describe PermissionsController, type: :request do ...@@ -152,13 +155,13 @@ RSpec.describe PermissionsController, type: :request do
end end
context 'without signin' do context 'without signin' do
it 'returns unauthorized' do it 'returns unauthorized' do
#password does not match confirmation # password does not match confirmation
put "/permissions/create_user.json", put '/permissions/create_user.json',
params: {nilm_id: john_nilm.id, params: { nilm_id: john_nilm.id,
role: 'viewer', role: 'viewer',
first_name: 'bill', last_name: 'will', first_name: 'bill', last_name: 'will',
email: 'valid@url.com', password: 'poorchoice', email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'error'} password_confirmation: 'error' }
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
user = User.find_by_email('valid@url.com') user = User.find_by_email('valid@url.com')
expect(user).to be nil expect(user).to be nil
...@@ -166,6 +169,73 @@ RSpec.describe PermissionsController, type: :request do ...@@ -166,6 +169,73 @@ RSpec.describe PermissionsController, type: :request do
end end
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 describe 'DELETE #destroy' do
# removes specified permission from nilm # removes specified permission from nilm
...@@ -175,7 +245,7 @@ RSpec.describe PermissionsController, type: :request do ...@@ -175,7 +245,7 @@ RSpec.describe PermissionsController, type: :request do
expect(steve.views_nilm?(john_nilm)).to be true expect(steve.views_nilm?(john_nilm)).to be true
@auth_headers = john.create_new_auth_token @auth_headers = john.create_new_auth_token
delete "/permissions/#{p.id}.json", delete "/permissions/#{p.id}.json",
params: {nilm_id: john_nilm.id}, params: { nilm_id: john_nilm.id },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
expect(response.header['Content-Type']).to include('application/json') expect(response.header['Content-Type']).to include('application/json')
...@@ -187,7 +257,7 @@ RSpec.describe PermissionsController, type: :request do ...@@ -187,7 +257,7 @@ RSpec.describe PermissionsController, type: :request do
p = Permission.where(nilm: john_nilm, user: john).first p = Permission.where(nilm: john_nilm, user: john).first
@auth_headers = john.create_new_auth_token @auth_headers = john.create_new_auth_token
delete "/permissions/#{p.id}.json", delete "/permissions/#{p.id}.json",
params: {nilm_id: john_nilm.id}, params: { nilm_id: john_nilm.id },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:unprocessable_entity)
expect(response.header['Content-Type']).to include('application/json') expect(response.header['Content-Type']).to include('application/json')
...@@ -197,10 +267,10 @@ RSpec.describe PermissionsController, type: :request do ...@@ -197,10 +267,10 @@ RSpec.describe PermissionsController, type: :request do
end end
context 'without admin privileges' do context 'without admin privileges' do
it 'returns unauthorized' do it 'returns unauthorized' do
[nicky,steve].each do |user| [nicky, steve].each do |user|
@auth_headers = user.create_new_auth_token @auth_headers = user.create_new_auth_token
delete "/permissions/99.json", delete '/permissions/99.json',
params: {nilm_id: john_nilm.id}, params: { nilm_id: john_nilm.id },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
end end
...@@ -209,12 +279,9 @@ RSpec.describe PermissionsController, type: :request do ...@@ -209,12 +279,9 @@ RSpec.describe PermissionsController, type: :request do
context 'without sign-in' do context 'without sign-in' do
it 'returns unauthorized' do it 'returns unauthorized' do
# no headers: nobody is signed in, deny all # no headers: nobody is signed in, deny all
delete "/permissions/99.json" delete '/permissions/99.json'
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
end end
end end
end end
end end
...@@ -10,77 +10,77 @@ RSpec.describe UserGroupsController, type: :request do ...@@ -10,77 +10,77 @@ RSpec.describe UserGroupsController, type: :request do
create(:user_group, create(:user_group,
owner: owner, owner: owner,
members: [member1, member2]) members: [member1, member2])
end end
describe 'GET index' do describe 'GET index' do
let(:grp1) { create(:user_group, name: 'Group1') } let(:grp1) { create(:user_group, name: 'Group1') }
let(:grp2) { create(:user_group, name: 'Group2') } let(:grp2) { create(:user_group, name: 'Group2') }
let(:donnals) { create(:user_group, name: 'Donnals', let(:donnals) do
owner: john, members: [nicky])} create(:user_group, name: 'Donnals',
let(:john) { create(:confirmed_user, first_name: 'Jonh') } owner: john, members: [nicky])
let(:nicky) { create(:confirmed_user, first_name: 'Nicky')} end
let(:steve) { create(:confirmed_user, first_name: 'Steve')} let(:john) { create(:user, first_name: 'Jonh') }
let(:nicky) { create(:user, first_name: 'Nicky') }
let(:steve) { create(:user, first_name: 'Steve') }
before do before do
# force lazy evaluation of let to build groups # force lazy evaluation of let to build groups
grp1; grp2; donnals; grp1; grp2; donnals
end end
context 'with john' do context 'with john' do
it 'returns 1 owner, 0 members, 2 others' do it 'returns 1 owner, 0 members, 2 others' do
@auth_headers = john.create_new_auth_token @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') expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body) body = JSON.parse(response.body)
expect(body["owner"].length).to eq(1) expect(body['owner'].length).to eq(1)
expect(body["owner"][0]["members"].length).to eq(1) expect(body['owner'][0]['members'].length).to eq(1)
expect(body["member"].length).to eq(0) expect(body['member'].length).to eq(0)
expect(body["other"].length).to eq(2) expect(body['other'].length).to eq(2)
end end
end end
context 'with nicky' do context 'with nicky' do
it 'returns 0 owners, 1 member, 2 others' do it 'returns 0 owners, 1 member, 2 others' do
@auth_headers = nicky.create_new_auth_token @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') expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body) body = JSON.parse(response.body)
expect(body["owner"].length).to eq(0) expect(body['owner'].length).to eq(0)
expect(body["member"].length).to eq(1) expect(body['member'].length).to eq(1)
expect(body["other"].length).to eq(2) expect(body['other'].length).to eq(2)
end end
end end
context 'with steve' do context 'with steve' do
it 'returns 0 owners, 0 members, 3 others' do it 'returns 0 owners, 0 members, 3 others' do
@auth_headers = steve.create_new_auth_token @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') expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body) body = JSON.parse(response.body)
expect(body["owner"].length).to eq(0) expect(body['owner'].length).to eq(0)
expect(body["member"].length).to eq(0) expect(body['member'].length).to eq(0)
expect(body["other"].length).to eq(3) expect(body['other'].length).to eq(3)
end end
end end
context 'without sign-in' do context 'without sign-in' do
it 'returns unauthorized' do it 'returns unauthorized' do
get "/user_groups.json" get '/user_groups.json'
expect(response.status).to eq(401) expect(response.status).to eq(401)
end end
end end
end end
describe 'PUT add_member' do describe 'PUT add_member' do
context 'with owner' do context 'with owner' do
it 'adds a member' do it 'adds a member' do
@auth_headers = owner.create_new_auth_token @auth_headers = owner.create_new_auth_token
put "/user_groups/#{group.id}/add_member.json", put "/user_groups/#{group.id}/add_member.json",
params: { user_id: other_user.id}, params: { user_id: other_user.id },
headers: @auth_headers headers: @auth_headers
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(group.reload.users.include?(other_user)).to be true expect(group.reload.users.include?(other_user)).to be true
expect(response).to have_notice_message 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) body = JSON.parse(response.body)
expect(body['data']['members'].count).to eq group.users.count expect(body['data']['members'].count).to eq group.users.count
end end
...@@ -88,7 +88,7 @@ end ...@@ -88,7 +88,7 @@ end
@auth_headers = owner.create_new_auth_token @auth_headers = owner.create_new_auth_token
# member1 is already a member # member1 is already a member
put "/user_groups/#{group.id}/add_member.json", put "/user_groups/#{group.id}/add_member.json",
params: { user_id: member1.id}, params: { user_id: member1.id },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:unprocessable_entity)
expect(response).to have_error_message expect(response).to have_error_message
...@@ -98,7 +98,7 @@ end ...@@ -98,7 +98,7 @@ end
it 'returns unauthorized' do it 'returns unauthorized' do
@auth_headers = member1.create_new_auth_token @auth_headers = member1.create_new_auth_token
put "/user_groups/#{group.id}/add_member.json", put "/user_groups/#{group.id}/add_member.json",
params: { user_id: other_user.id}, params: { user_id: other_user.id },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
end end
...@@ -106,7 +106,7 @@ end ...@@ -106,7 +106,7 @@ end
context 'without sign-in' do context 'without sign-in' do
it 'returns unauthorized' do it 'returns unauthorized' do
put "/user_groups/#{group.id}/add_member.json", 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) expect(response).to have_http_status(:unauthorized)
end end
end end
...@@ -118,24 +118,24 @@ end ...@@ -118,24 +118,24 @@ end
members = group.users.length members = group.users.length
@auth_headers = owner.create_new_auth_token @auth_headers = owner.create_new_auth_token
put "/user_groups/#{group.id}/create_member.json", 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', email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'poorchoice'}, password_confirmation: 'poorchoice' },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
expect(User.find_by_email('valid@url.com')).to_not be nil expect(User.find_by_email('valid@url.com')).to_not be nil
expect(response).to have_notice_message 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') expect(response.header['Content-Type']).to include('application/json')
body = JSON.parse(response.body) body = JSON.parse(response.body)
expect(body["data"]["members"].length).to eq(members+1) expect(body['data']['members'].length).to eq(members + 1)
end end
it 'returns error message if user has errors' do it 'returns error message if user has errors' do
@auth_headers = owner.create_new_auth_token @auth_headers = owner.create_new_auth_token
put "/user_groups/#{group.id}/create_member.json", 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', email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'nomatch'}, password_confirmation: 'nomatch' },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:unprocessable_entity)
expect(User.find_by_email('valid@url.com')).to be nil expect(User.find_by_email('valid@url.com')).to be nil
...@@ -146,9 +146,9 @@ end ...@@ -146,9 +146,9 @@ end
it 'returns unauthorized' do it 'returns unauthorized' do
@auth_headers = member1.create_new_auth_token @auth_headers = member1.create_new_auth_token
put "/user_groups/#{group.id}/create_member.json", 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', email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'poorchoice'}, password_confirmation: 'poorchoice' },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
expect(User.find_by_email('valid@url.com')).to be nil expect(User.find_by_email('valid@url.com')).to be nil
...@@ -157,9 +157,9 @@ end ...@@ -157,9 +157,9 @@ end
context 'without sigin' do context 'without sigin' do
it 'returns unauthorized' do it 'returns unauthorized' do
put "/user_groups/#{group.id}/create_member.json", 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', email: 'valid@url.com', password: 'poorchoice',
password_confirmation: 'poorchoice'} password_confirmation: 'poorchoice' }
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
expect(User.find_by_email('valid@url.com')).to be nil expect(User.find_by_email('valid@url.com')).to be nil
end end
...@@ -168,14 +168,56 @@ end ...@@ -168,14 +168,56 @@ end
describe 'PUT invite_member' do describe 'PUT invite_member' do
context 'with owner' do context 'with owner' do
it 'invites a user and adds him to the group' before do
it 'adds existing members to the group' @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 end
context 'with anyone else' do 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 end
context 'without sigin' do 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
end end
...@@ -184,12 +226,12 @@ end ...@@ -184,12 +226,12 @@ end
it 'removes a member' do it 'removes a member' do
@auth_headers = owner.create_new_auth_token @auth_headers = owner.create_new_auth_token
put "/user_groups/#{group.id}/remove_member.json", put "/user_groups/#{group.id}/remove_member.json",
params: { user_id: member1.id}, params: { user_id: member1.id },
headers: @auth_headers headers: @auth_headers
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(group.reload.users.include?(member1)).to be false expect(group.reload.users.include?(member1)).to be false
expect(response).to have_notice_message 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) body = JSON.parse(response.body)
expect(body['data']['members'].count).to eq group.users.count expect(body['data']['members'].count).to eq group.users.count
end end
...@@ -197,7 +239,7 @@ end ...@@ -197,7 +239,7 @@ end
@auth_headers = owner.create_new_auth_token @auth_headers = owner.create_new_auth_token
# other_user is not a member # other_user is not a member
put "/user_groups/#{group.id}/remove_member.json", put "/user_groups/#{group.id}/remove_member.json",
params: { user_id: other_user.id}, params: { user_id: other_user.id },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:unprocessable_entity)
expect(response).to have_error_message expect(response).to have_error_message
...@@ -207,7 +249,7 @@ end ...@@ -207,7 +249,7 @@ end
it 'returns unauthorized' do it 'returns unauthorized' do
@auth_headers = member1.create_new_auth_token @auth_headers = member1.create_new_auth_token
put "/user_groups/#{group.id}/remove_member.json", put "/user_groups/#{group.id}/remove_member.json",
params: { user_id: member2.id}, params: { user_id: member2.id },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
end end
...@@ -215,7 +257,7 @@ end ...@@ -215,7 +257,7 @@ end
context 'without sign-in' do context 'without sign-in' do
it 'returns unauthorized' do it 'returns unauthorized' do
put "/user_groups/#{group.id}/remove_member.json", 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) expect(response).to have_http_status(:unauthorized)
end end
end end
...@@ -225,13 +267,13 @@ end ...@@ -225,13 +267,13 @@ end
context 'with authenticated user' do context 'with authenticated user' do
it 'creates a group' do it 'creates a group' do
@auth_headers = other_user.create_new_auth_token @auth_headers = other_user.create_new_auth_token
post "/user_groups.json", post '/user_groups.json',
params: {name: 'test_group', description: 'some text'}, params: { name: 'test_group', description: 'some text' },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
expect(response).to have_notice_message expect(response).to have_notice_message
expect(UserGroup.find_by_name('test_group').owner).to eq other_user 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) body = JSON.parse(response.body)
# no members yet # no members yet
expect(body['data']['members'].count).to eq 0 expect(body['data']['members'].count).to eq 0
...@@ -239,8 +281,8 @@ end ...@@ -239,8 +281,8 @@ end
it 'returns error if unsuccesful' do it 'returns error if unsuccesful' do
@auth_headers = other_user.create_new_auth_token @auth_headers = other_user.create_new_auth_token
create(:user_group, name: 'CanOnlyBeOne') create(:user_group, name: 'CanOnlyBeOne')
post "/user_groups.json", post '/user_groups.json',
params: {name: 'CanOnlyBeOne', description: 'some text'}, params: { name: 'CanOnlyBeOne', description: 'some text' },
headers: @auth_headers headers: @auth_headers
# can't have duplicate name # can't have duplicate name
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:unprocessable_entity)
...@@ -250,8 +292,8 @@ end ...@@ -250,8 +292,8 @@ end
end end
context 'without sign-in' do context 'without sign-in' do
it 'returns unauthorized' do it 'returns unauthorized' do
post "/user_groups.json", post '/user_groups.json',
params: { name: 'test', description: 'something'} params: { name: 'test', description: 'something' }
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
end end
end end
...@@ -269,7 +311,7 @@ end ...@@ -269,7 +311,7 @@ end
expect(response).to have_notice_message expect(response).to have_notice_message
expect(UserGroup.exists?(group.id)).to be false expect(UserGroup.exists?(group.id)).to be false
# make sure the associated permissions are destroyed # make sure the associated permissions are destroyed
expect(Permission.count).to eq(pCount-1) expect(Permission.count).to eq(pCount - 1)
end end
end end
context 'with anybody else' do context 'with anybody else' do
...@@ -295,13 +337,13 @@ end ...@@ -295,13 +337,13 @@ end
it 'updates the group' do it 'updates the group' do
@auth_headers = owner.create_new_auth_token @auth_headers = owner.create_new_auth_token
put "/user_groups/#{group.id}.json", put "/user_groups/#{group.id}.json",
params: {name: 'new', description: 'changed'}, params: { name: 'new', description: 'changed' },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
expect(response).to have_notice_message expect(response).to have_notice_message
expect(group.reload.name).to eq('new') expect(group.reload.name).to eq('new')
expect(group.description).to eq('changed') 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) body = JSON.parse(response.body)
expect(body['data']['members'].count).to eq group.users.count expect(body['data']['members'].count).to eq group.users.count
end end
...@@ -310,7 +352,7 @@ end ...@@ -310,7 +352,7 @@ end
orig_name = group.name orig_name = group.name
# name cannot be blank # name cannot be blank
put "/user_groups/#{group.id}.json", put "/user_groups/#{group.id}.json",
params: {name: '', description: 'changed'}, params: { name: '', description: 'changed' },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:unprocessable_entity) expect(response).to have_http_status(:unprocessable_entity)
expect(response).to have_error_message expect(response).to have_error_message
...@@ -322,7 +364,7 @@ end ...@@ -322,7 +364,7 @@ end
@auth_headers = member1.create_new_auth_token @auth_headers = member1.create_new_auth_token
orig_name = group.name orig_name = group.name
put "/user_groups/#{group.id}.json", put "/user_groups/#{group.id}.json",
params: {name: 'new', description: 'changed'}, params: { name: 'new', description: 'changed' },
headers: @auth_headers headers: @auth_headers
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
expect(group.reload.name).to eq orig_name expect(group.reload.name).to eq orig_name
...@@ -332,7 +374,7 @@ end ...@@ -332,7 +374,7 @@ end
it 'returns unauthorized' do it 'returns unauthorized' do
orig_name = group.name orig_name = group.name
put "/user_groups/#{group.id}.json", put "/user_groups/#{group.id}.json",
params: {name: 'new', description: 'changed'} params: { name: 'new', description: 'changed' }
expect(response).to have_http_status(:unauthorized) expect(response).to have_http_status(:unauthorized)
expect(group.reload.name).to eq orig_name expect(group.reload.name).to eq orig_name
end end
......
...@@ -4,17 +4,13 @@ require 'rails_helper' ...@@ -4,17 +4,13 @@ require 'rails_helper'
RSpec.describe UsersController, type: :request do RSpec.describe UsersController, type: :request do
let(:steve) { create(:user, first_name: 'Steve')} let(:steve) { create(:user, first_name: 'Steve')}
let(:john) { create(:user, first_name: 'Jonh') } let(:john) { create(:user, first_name: 'Jonh') }
let(:newguy) { create(:user, first_name: 'Unconfirmed')}
describe 'GET index' do describe 'GET index' do
before do
john.confirm
steve.confirm
end
context 'with authenticated user' do 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 # 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 @auth_headers = john.create_new_auth_token
get "/users.json", headers: @auth_headers get "/users.json", headers: @auth_headers
expect(response.header['Content-Type']).to include('application/json') expect(response.header['Content-Type']).to include('application/json')
......
...@@ -4,10 +4,6 @@ FactoryGirl.define do ...@@ -4,10 +4,6 @@ FactoryGirl.define do
last_name {Faker::Name.first_name} last_name {Faker::Name.first_name}
email {Faker::Internet.unique.email} email {Faker::Internet.unique.email}
password {Faker::Lorem.characters(10)} password {Faker::Lorem.characters(10)}
factory :confirmed_user do
confirmed_at {Time.now}
end
end end
......
...@@ -67,7 +67,7 @@ RSpec.describe 'LoadStreamData' do ...@@ -67,7 +67,7 @@ RSpec.describe 'LoadStreamData' do
else else
i_count += 1 i_count += 1
expect(data[:type]).to eq 'interval' 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
end end
expect(d_count).to eq 2 #2 decimated Streams expect(d_count).to eq 2 #2 decimated Streams
......
...@@ -12,7 +12,7 @@ RSpec.describe 'CreateNilm' do ...@@ -12,7 +12,7 @@ RSpec.describe 'CreateNilm' do
errors: ['cannot contact database'], errors: ['cannot contact database'],
warnings: []) warnings: [])
allow(UpdateDb).to receive(:new).and_return(service) 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 # run the NILM creation
nilm_creator = CreateNilm.new nilm_creator = CreateNilm.new
nilm_creator.run( nilm_creator.run(
......
...@@ -17,7 +17,7 @@ describe 'AddGroupMember service' do ...@@ -17,7 +17,7 @@ describe 'AddGroupMember service' do
service.run(group, other_user.id) service.run(group, other_user.id)
expect(service.success?).to be true expect(service.success?).to be true
expect(group.users.count).to eq(3) 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 end
it 'errors if user is the owner' do it 'errors if user is the owner' do
service = AddGroupMember.new 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