Browse Source

Added user (agent & customer) invite feature in first steps.

Martin Edenhofer 9 years ago
parent
commit
c0fece6f0d

+ 21 - 1
app/assets/javascripts/app/controllers/_dashboard/first_steps.coffee

@@ -1,6 +1,8 @@
 class App.DashboardFirstSteps extends App.Controller
   events:
     'click a': 'scrollIntoView'
+    'click .js-inviteAgent': 'inviteAgent'
+    'click .js-inviteCustomer': 'inviteCustomer'
 
   constructor: ->
     super
@@ -8,7 +10,6 @@ class App.DashboardFirstSteps extends App.Controller
     @load()
 
   load: =>
-
     @ajax(
       id:    'first_steps'
       type:  'GET'
@@ -31,3 +32,22 @@ class App.DashboardFirstSteps extends App.Controller
       return if !element
       element.scrollIntoView()
     @delay(delay, 20)
+
+  inviteAgent: (e) =>
+    e.preventDefault()
+    new App.InviteUser(
+      container: @el.closest('.content')
+      head: 'Invite Colleagues'
+      screen: 'invite_agent'
+      role: 'Agent'
+    )
+
+  inviteCustomer: (e) =>
+    e.preventDefault()
+    new App.InviteUser(
+      container: @el.closest('.content')
+      head: 'Invite Customer'
+      screen: 'invite_customer'
+      role: 'Customer'
+    )
+

+ 76 - 0
app/assets/javascripts/app/controllers/widget/invite_user.coffee

@@ -0,0 +1,76 @@
+class App.InviteUser extends App.Wizard
+  className: 'modal fade'
+  events:
+    'click  .js-close':     'hide'
+    'submit .js-user':      'submit'
+    'click  .js-goToSlide': 'goToSlide'
+
+  constructor: ->
+    super
+
+    if @container
+      @el.addClass('modal--local')
+
+    @render()
+
+    @el.modal
+      keyboard:  true
+      show:      true
+      backdrop:  true
+      container: @container
+    .on
+      'hidden.bs.modal': =>
+        if @callback
+          @callback()
+        @el.remove()
+
+  render: =>
+    @html App.view('widget/invite_user')(
+      head: @head
+    )
+    new App.ControllerForm(
+      el:        @$('.js-form')
+      model:     App.User
+      screen:    @screen
+      autofocus: true
+    )
+
+  submit: (e) =>
+    e.preventDefault()
+    @showSlide('js-waiting')
+    @formDisable(e)
+    @params          = @formParam(e.target)
+    @params.role_ids = [0]
+
+    # set invite flag
+    @params.invite = true
+
+    # find agent role
+    role = App.Role.findByAttribute('name', @role)
+    if role
+      @params.role_ids = role.id
+
+    user = new App.User
+    user.load(@params)
+
+    errors = user.validate(
+      screen: @screen
+    )
+    if errors
+      @log 'error new', errors
+      @formValidate( form: e.target, errors: errors )
+      @formEnable(e)
+      @showSlide('js-user')
+      return false
+
+    # save user
+    user.save(
+      done: (r) =>
+        @showSlide('js-success')
+        @el.modal('hide')
+
+      fail: (settings, details) =>
+        @formEnable(e)
+        @showSlide('js-user')
+        @showAlert('js-user',  details.error_human || details.error)
+    )

+ 6 - 6
app/assets/javascripts/app/models/user.coffee

@@ -6,14 +6,14 @@ class App.User extends App.Model
 #  @hasMany 'roles', 'App.Role'
   @configure_attributes = [
     { name: 'login',            display: 'Login',         tag: 'input',    type: 'text',     limit: 100, null: false, autocapitalize: false, signup: false, quick: false },
-    { name: 'firstname',        display: 'Firstname',     tag: 'input',    type: 'text',     limit: 100, null: false, signup: true, info: true, invite_agent: true },
-    { name: 'lastname',         display: 'Lastname',      tag: 'input',    type: 'text',     limit: 100, null: false, signup: true, info: true, invite_agent: true },
-    { name: 'email',            display: 'Email',         tag: 'input',    type: 'email',    limit: 100, null: false, signup: true, info: true, invite_agent: true },
-    { name: 'organization_id',  display: 'Organization',  tag: 'select',   multiple: false, nulloption: true, null: true, relation: 'Organization', signup: false, info: true },
+    { name: 'firstname',        display: 'Firstname',     tag: 'input',    type: 'text',     limit: 100, null: false, signup: true, info: true, invite_agent: true, invite_customer: true },
+    { name: 'lastname',         display: 'Lastname',      tag: 'input',    type: 'text',     limit: 100, null: false, signup: true, info: true, invite_agent: true, invite_customer: true },
+    { name: 'email',            display: 'Email',         tag: 'input',    type: 'email',    limit: 100, null: false, signup: true, info: true, invite_agent: true, invite_customer: true },
+    { name: 'organization_id',  display: 'Organization',  tag: 'select',   multiple: false, nulloption: true, null: true, relation: 'Organization', signup: false, info: true, invite_customer: true },
     { name: 'password',         display: 'Password',      tag: 'input',    type: 'password', limit: 50,  null: true, autocomplete: 'off', signup: true, },
-    { name: 'note',             display: 'Note',          tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true, info: true },
+    { name: 'note',             display: 'Note',          tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true, info: true, invite_customer: true },
     { name: 'role_ids',         display: 'Roles',         tag: 'checkbox', multiple: true, null: false, relation: 'Role' },
-    { name: 'group_ids',        display: 'Groups',        tag: 'checkbox', multiple: true, null: true, relation: 'Group', invite_agent: true },
+    { name: 'group_ids',        display: 'Groups',        tag: 'checkbox', multiple: true, null: true, relation: 'Group', invite_agent: true, invite_customer: true },
     { name: 'active',           display: 'Active',        tag: 'active',   default: true },
     { name: 'created_at',       display: 'Created',       tag: 'datetime', readonly: 1 },
     { name: 'updated_at',       display: 'Updated',       tag: 'datetime', readonly: 1 },

+ 1 - 1
app/assets/javascripts/app/views/dashboard/first_steps.jst.eco

@@ -2,7 +2,7 @@
   <% for area in @data: %>
   <h3><%- @T(area.name) %></h3>
     <% for item in area.items: %>
-    <a class="todo <% if item.checked: %>is-done<% end %>" href="<%- item.location %>">
+    <a class="todo <% if item.checked: %>is-done<% end %> <% if item.class: %><%- item.class %><% end %>" href="<%- item.location %>">
       <% if item.checked: %>
         <%- @Icon('checkmark') %>
       <% else: %>

+ 6 - 3
app/controllers/first_steps_controller.rb

@@ -67,12 +67,14 @@ class FirstStepsController < ApplicationController
             {
               name: 'Invite Agents/Colleges to help working on Tickets',
               checked: invite_agents,
-              location: '#invite_agent',
+              location: '#',
+              class: 'js-inviteAgent',
             },
             {
               name: 'Invite Customers to create issues in Zammad',
               checked: invite_customers,
-              location: '#invite_customer',
+              location: '#',
+              class: 'js-inviteCustomer',
             },
           ],
         },
@@ -154,7 +156,8 @@ class FirstStepsController < ApplicationController
           {
             name: 'Invite Customers to create issues in Zammad',
             checked: invite_customers,
-            location: '#invite_customer',
+            location: '#',
+            class: 'js-inviteCustomer',
           },
         ],
       },

+ 22 - 2
app/controllers/users_controller.rb

@@ -103,7 +103,7 @@ class UsersController < ApplicationController
       else
 
         # permission check by role
-        return if !permission_check_by_role
+        return if !permission_check_by_role(params)
 
         if params[:role_ids]
           user.role_ids = params[:role_ids]
@@ -203,6 +203,9 @@ class UsersController < ApplicationController
 
     begin
 
+      # permission check by role
+      return if !permission_check_by_role(params)
+
       user.update_attributes( User.param_cleanup(params) )
 
       # only allow Admin's and Agent's
@@ -779,8 +782,25 @@ curl http://localhost/api/v1/users/avatar -v -u #{login}:#{password} -H "Content
     true
   end
 
-  def permission_check_by_role
+  def permission_check_by_role(params)
     return true if role?(Z_ROLENAME_ADMIN)
+
+    if !role?('Admin') && params[:role_ids]
+      params[:role_ids].each {|role_id|
+        role_name = Role.find(role_id).name
+        next if role_name != 'Admin' && role_name != 'Agent'
+        render json: { error_human: 'This role assignment is only allowed by admin!' }, status: :unauthorized
+        return false
+      }
+    end
+
+    if role?('Agent')
+      if params[:group_ids] && !params[:group_ids].empty?
+        render json: { error_human: 'Group relation is only allowed by admin!' }, status: :unauthorized
+        return false
+      end
+    end
+
     return true if role?('Agent')
 
     response_access_deny

+ 691 - 0
db/migrate/20160217000001_object_manager_update_user.rb

@@ -0,0 +1,691 @@
+class ObjectManagerUpdateUser < ActiveRecord::Migration
+  def up
+    UserInfo.current_user_id = 1
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'login',
+      display: 'Login',
+      data_type: 'input',
+      data_option: {
+        type: 'text',
+        maxlength: 100,
+        null: true,
+        autocapitalize: false,
+        item_class: 'formGroup--halfSize',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {},
+        invite_agent: {},
+        invite_customer: {},
+        edit: {},
+        view: {
+          '-all-' => {
+            shown: false,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 100,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'firstname',
+      display: 'Firstname',
+      data_type: 'input',
+      data_option: {
+        type: 'text',
+        maxlength: 150,
+        null: false,
+        item_class: 'formGroup--halfSize',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {
+          '-all-' => {
+            null: false,
+          },
+        },
+        invite_agent: {
+          '-all-' => {
+            null: false,
+          },
+        },
+        invite_customer: {
+          '-all-' => {
+            null: false,
+          },
+        },
+        edit: {
+          '-all-' => {
+            null: false,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: true,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 200,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'lastname',
+      display: 'Lastname',
+      data_type: 'input',
+      data_option: {
+        type: 'text',
+        maxlength: 150,
+        null: false,
+        item_class: 'formGroup--halfSize',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {
+          '-all-' => {
+            null: false,
+          },
+        },
+        invite_agent: {
+          '-all-' => {
+            null: false,
+          },
+        },
+        invite_customer: {
+          '-all-' => {
+            null: false,
+          },
+        },
+        edit: {
+          '-all-' => {
+            null: false,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: true,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 300,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'email',
+      display: 'Email',
+      data_type: 'input',
+      data_option: {
+        type: 'email',
+        maxlength: 150,
+        null: false,
+        item_class: 'formGroup--halfSize',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {
+          '-all-' => {
+            null: false,
+          },
+        },
+        invite_agent: {
+          '-all-' => {
+            null: false,
+          },
+        },
+        invite_customer: {
+          '-all-' => {
+            null: false,
+          },
+        },
+        edit: {
+          '-all-' => {
+            null: false,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: true,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 400,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'web',
+      display: 'Web',
+      data_type: 'input',
+      data_option: {
+        type: 'url',
+        maxlength: 250,
+        null: true,
+        item_class: 'formGroup--halfSize',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {},
+        invite_agent: {},
+        invite_customer: {},
+        edit: {
+          '-all-' => {
+            null: true,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: true,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 500,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'phone',
+      display: 'Phone',
+      data_type: 'input',
+      data_option: {
+        type: 'phone',
+        maxlength: 100,
+        null: true,
+        item_class: 'formGroup--halfSize',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {},
+        invite_agent: {},
+        invite_customer: {},
+        edit: {
+          '-all-' => {
+            null: true,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: true,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 600,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'mobile',
+      display: 'Mobile',
+      data_type: 'input',
+      data_option: {
+        type: 'phone',
+        maxlength: 100,
+        null: true,
+        item_class: 'formGroup--halfSize',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {},
+        invite_agent: {},
+        invite_customer: {},
+        edit: {
+          '-all-' => {
+            null: true,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: true,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 700,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'fax',
+      display: 'Fax',
+      data_type: 'input',
+      data_option: {
+        type: 'phone',
+        maxlength: 100,
+        null: true,
+        item_class: 'formGroup--halfSize',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {},
+        invite_agent: {},
+        invite_customer: {},
+        edit: {
+          '-all-' => {
+            null: true,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: true,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 800,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'organization_id',
+      display: 'Organization',
+      data_type: 'autocompletion_ajax',
+      data_option: {
+        multiple: false,
+        nulloption: true,
+        null: true,
+        relation: 'Organization',
+        item_class: 'formGroup--halfSize',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {},
+        invite_agent: {},
+        invite_customer: {
+          '-all-' => {
+            null: true,
+          },
+        },
+        edit: {
+          '-all-' => {
+            null: true,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: true,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 900,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'department',
+      display: 'Department',
+      data_type: 'input',
+      data_option: {
+        type: 'text',
+        maxlength: 200,
+        null: true,
+        item_class: 'formGroup--halfSize',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {},
+        invite_agent: {},
+        invite_customer: {},
+        edit: {
+          '-all-' => {
+            null: true,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: true,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 1000,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'street',
+      display: 'Street',
+      data_type: 'input',
+      data_option: {
+        type: 'text',
+        maxlength: 100,
+        null: true,
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {},
+        invite_agent: {},
+        invite_customer: {},
+        edit: {
+          '-all-' => {
+            null: true,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: true,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 1100,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'zip',
+      display: 'Zip',
+      data_type: 'input',
+      data_option: {
+        type: 'text',
+        maxlength: 100,
+        null: true,
+        item_class: 'formGroup--halfSize',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {},
+        invite_agent: {},
+        invite_customer: {},
+        edit: {
+          '-all-' => {
+            null: true,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: true,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 1200,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'city',
+      display: 'City',
+      data_type: 'input',
+      data_option: {
+        type: 'text',
+        maxlength: 100,
+        null: true,
+        item_class: 'formGroup--halfSize',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {},
+        invite_agent: {},
+        invite_customer: {},
+        edit: {
+          '-all-' => {
+            null: true,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: true,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 1300,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'address',
+      display: 'Address',
+      data_type: 'textarea',
+      data_option: {
+        type: 'text',
+        maxlength: 500,
+        null: true,
+        item_class: 'formGroup--halfSize',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {},
+        invite_agent: {},
+        invite_customer: {},
+        edit: {
+          '-all-' => {
+            null: true,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: true,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 1350,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'password',
+      display: 'Password',
+      data_type: 'input',
+      data_option: {
+        type: 'password',
+        maxlength: 100,
+        null: true,
+        autocomplete: 'off',
+        item_class: 'formGroup--halfSize',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {
+          '-all-' => {
+            null: false,
+          },
+        },
+        invite_agent: {},
+        invite_customer: {},
+        edit: {
+          Admin: {
+            null: true,
+          },
+        },
+        view: {}
+      },
+      pending_migration: false,
+      position: 1400,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'vip',
+      display: 'VIP',
+      data_type: 'boolean',
+      data_option: {
+        null: true,
+        default: false,
+        item_class: 'formGroup--halfSize',
+        options: {
+          false: 'no',
+          true: 'yes',
+        },
+        translate: true,
+      },
+      editable: false,
+      active: true,
+      screens: {
+        edit: {
+          Admin: {
+            null: true,
+          },
+          Agent: {
+            null: true,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: false,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 1490,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'note',
+      display: 'Note',
+      data_type: 'richtext',
+      data_option: {
+        type: 'text',
+        maxlength: 250,
+        null: true,
+        note: 'Notes are visible to agents only, never to customers.',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {},
+        invite_agent: {},
+        invite_customer: {
+          '-all-' => {
+            null: true,
+          },
+        },
+        edit: {
+          '-all-' => {
+            null: true,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: true,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 1500,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'role_ids',
+      display: 'Roles',
+      data_type: 'checkbox',
+      data_option: {
+        multiple: true,
+        null: false,
+        relation: 'Role',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {},
+        invite_agent: {},
+        invite_customer: {},
+        edit: {
+          Admin: {
+            null: false,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: false,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 1600,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'group_ids',
+      display: 'Groups',
+      data_type: 'checkbox',
+      data_option: {
+        multiple: true,
+        null: true,
+        relation: 'Group',
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {},
+        invite_agent: {
+          '-all-' => {
+            null: false,
+          },
+        },
+        invite_customer: {},
+        edit: {
+          Admin: {
+            null: true,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: false,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 1700,
+    )
+
+    ObjectManager::Attribute.add(
+      object: 'User',
+      name: 'active',
+      display: 'Active',
+      data_type: 'active',
+      data_option: {
+        default: true,
+      },
+      editable: false,
+      active: true,
+      screens: {
+        signup: {},
+        invite_agent: {},
+        invite_customer: {},
+        edit: {
+          Admin: {
+            null: false,
+          },
+        },
+        view: {
+          '-all-' => {
+            shown: false,
+          },
+        },
+      },
+      pending_migration: false,
+      position: 1800,
+    )
+
+  end
+
+end

+ 39 - 0
db/seeds.rb

@@ -2508,6 +2508,7 @@ ObjectManager::Attribute.add(
   screens: {
     signup: {},
     invite_agent: {},
+    invite_customer: {},
     edit: {},
     view: {
       '-all-' => {
@@ -2543,6 +2544,11 @@ ObjectManager::Attribute.add(
         null: false,
       },
     },
+    invite_customer: {
+      '-all-' => {
+        null: false,
+      },
+    },
     edit: {
       '-all-' => {
         null: false,
@@ -2582,6 +2588,11 @@ ObjectManager::Attribute.add(
         null: false,
       },
     },
+    invite_customer: {
+      '-all-' => {
+        null: false,
+      },
+    },
     edit: {
       '-all-' => {
         null: false,
@@ -2621,6 +2632,11 @@ ObjectManager::Attribute.add(
         null: false,
       },
     },
+    invite_customer: {
+      '-all-' => {
+        null: false,
+      },
+    },
     edit: {
       '-all-' => {
         null: false,
@@ -2652,6 +2668,7 @@ ObjectManager::Attribute.add(
   screens: {
     signup: {},
     invite_agent: {},
+    invite_customer: {},
     edit: {
       '-all-' => {
         null: true,
@@ -2683,6 +2700,7 @@ ObjectManager::Attribute.add(
   screens: {
     signup: {},
     invite_agent: {},
+    invite_customer: {},
     edit: {
       '-all-' => {
         null: true,
@@ -2714,6 +2732,7 @@ ObjectManager::Attribute.add(
   screens: {
     signup: {},
     invite_agent: {},
+    invite_customer: {},
     edit: {
       '-all-' => {
         null: true,
@@ -2745,6 +2764,7 @@ ObjectManager::Attribute.add(
   screens: {
     signup: {},
     invite_agent: {},
+    invite_customer: {},
     edit: {
       '-all-' => {
         null: true,
@@ -2777,6 +2797,11 @@ ObjectManager::Attribute.add(
   screens: {
     signup: {},
     invite_agent: {},
+    invite_customer: {
+      '-all-' => {
+        null: true,
+      },
+    },
     edit: {
       '-all-' => {
         null: true,
@@ -2808,6 +2833,7 @@ ObjectManager::Attribute.add(
   screens: {
     signup: {},
     invite_agent: {},
+    invite_customer: {},
     edit: {
       '-all-' => {
         null: true,
@@ -2838,6 +2864,7 @@ ObjectManager::Attribute.add(
   screens: {
     signup: {},
     invite_agent: {},
+    invite_customer: {},
     edit: {
       '-all-' => {
         null: true,
@@ -2869,6 +2896,7 @@ ObjectManager::Attribute.add(
   screens: {
     signup: {},
     invite_agent: {},
+    invite_customer: {},
     edit: {
       '-all-' => {
         null: true,
@@ -2900,6 +2928,7 @@ ObjectManager::Attribute.add(
   screens: {
     signup: {},
     invite_agent: {},
+    invite_customer: {},
     edit: {
       '-all-' => {
         null: true,
@@ -2931,6 +2960,7 @@ ObjectManager::Attribute.add(
   screens: {
     signup: {},
     invite_agent: {},
+    invite_customer: {},
     edit: {
       '-all-' => {
         null: true,
@@ -2967,6 +2997,7 @@ ObjectManager::Attribute.add(
       },
     },
     invite_agent: {},
+    invite_customer: {},
     edit: {
       Admin: {
         null: true,
@@ -3030,6 +3061,11 @@ ObjectManager::Attribute.add(
   screens: {
     signup: {},
     invite_agent: {},
+    invite_customer: {
+      '-all-' => {
+        null: true,
+      },
+    },
     edit: {
       '-all-' => {
         null: true,
@@ -3060,6 +3096,7 @@ ObjectManager::Attribute.add(
   screens: {
     signup: {},
     invite_agent: {},
+    invite_customer: {},
     edit: {
       Admin: {
         null: false,
@@ -3094,6 +3131,7 @@ ObjectManager::Attribute.add(
         null: false,
       },
     },
+    invite_customer: {},
     edit: {
       Admin: {
         null: true,
@@ -3122,6 +3160,7 @@ ObjectManager::Attribute.add(
   screens: {
     signup: {},
     invite_agent: {},
+    invite_customer: {},
     edit: {
       Admin: {
         null: false,

+ 110 - 2
test/controllers/user_organization_controller_test.rb

@@ -104,6 +104,30 @@ class UserOrganizationControllerTest < ActionDispatch::IntegrationTest
     assert_equal('new_here@example.com', result['login'])
     assert_equal('new_here@example.com', result['email'])
 
+    # create user with admin role
+    role = Role.lookup(name: 'Admin')
+    params = { firstname: 'Admin First', lastname: 'Admin Last', email: 'new_admin@example.com', role_ids: [ role.id ] }
+    post '/api/v1/users', params.to_json, @headers
+    assert_response(201)
+    result = JSON.parse(@response.body)
+    assert(result)
+    user = User.find(result['id'])
+    assert_not(user.role?('Admin'))
+    assert_not(user.role?('Agent'))
+    assert(user.role?('Customer'))
+
+    # create user with agent role
+    role = Role.lookup(name: 'Agent')
+    params = { firstname: 'Agent First', lastname: 'Agent Last', email: 'new_agent@example.com', role_ids: [ role.id ] }
+    post '/api/v1/users', params.to_json, @headers
+    assert_response(201)
+    result = JSON.parse(@response.body)
+    assert(result)
+    user = User.find(result['id'])
+    assert_not(user.role?('Admin'))
+    assert_not(user.role?('Agent'))
+    assert(user.role?('Customer'))
+
     # no user
     get '/api/v1/users', {}, @headers
     assert_response(401)
@@ -156,7 +180,7 @@ class UserOrganizationControllerTest < ActionDispatch::IntegrationTest
     assert(result)
   end
 
-  test 'user index with admin' do
+  test 'user index and create with admin' do
 
     # email auth
     credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-admin@example.com', 'adminpw')
@@ -190,9 +214,81 @@ class UserOrganizationControllerTest < ActionDispatch::IntegrationTest
     assert_equal(result.class, Hash)
     assert_equal(result['email'], 'rest-customer1@example.com')
 
+    # create user with admin role
+    role = Role.lookup(name: 'Admin')
+    params = { firstname: 'Admin First', lastname: 'Admin Last', email: 'new_admin_by_admin@example.com', role_ids: [ role.id ] }
+    post '/api/v1/users', params.to_json, @headers
+    assert_response(201)
+    result = JSON.parse(@response.body)
+    assert(result)
+    user = User.find(result['id'])
+    assert(user.role?('Admin'))
+    assert_not(user.role?('Agent'))
+    assert_not(user.role?('Customer'))
+
+    # create user with agent role
+    role = Role.lookup(name: 'Agent')
+    params = { firstname: 'Agent First', lastname: 'Agent Last', email: 'new_agent_by_admin@example.com', role_ids: [ role.id ] }
+    post '/api/v1/users', params.to_json, @headers
+    assert_response(201)
+    result = JSON.parse(@response.body)
+    assert(result)
+    user = User.find(result['id'])
+    assert_not(user.role?('Admin'))
+    assert(user.role?('Agent'))
+    assert_not(user.role?('Customer'))
+
+  end
+
+  test 'user index and create with agent' do
+
+    credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-agent@example.com', 'agentpw')
+
+    # index
+    get '/api/v1/users', {}, @headers.merge('Authorization' => credentials)
+    assert_response(200)
+    result = JSON.parse(@response.body)
+    assert(result)
+
+    # index
+    get '/api/v1/users', {}, @headers.merge('Authorization' => credentials)
+    assert_response(200)
+    result = JSON.parse(@response.body)
+    assert(result)
+    assert_equal(result.class, Array)
+    assert(result.length >= 3)
+
+    # create user with admin role
+    role = Role.lookup(name: 'Admin')
+    params = { firstname: 'Admin First', lastname: 'Admin Last', email: 'new_admin_by_agent@example.com', role_ids: [ role.id ] }
+    post '/api/v1/users', params.to_json, @headers
+    assert_response(401)
+    result = JSON.parse(@response.body)
+    assert(result)
+
+    # create user with agent role
+    role = Role.lookup(name: 'Agent')
+    params = { firstname: 'Agent First', lastname: 'Agent Last', email: 'new_agent_by_agent@example.com', role_ids: [ role.id ] }
+    post '/api/v1/users', params.to_json, @headers
+    assert_response(401)
+    result = JSON.parse(@response.body)
+    assert(result)
+
+    # create user with customer role
+    role = Role.lookup(name: 'Customer')
+    params = { firstname: 'Agent First', lastname: 'Agent Last', email: 'new_agent_by_agent@example.com', role_ids: [ role.id ] }
+    post '/api/v1/users', params.to_json, @headers
+    assert_response(201)
+    result = JSON.parse(@response.body)
+    assert(result)
+    user = User.find(result['id'])
+    assert_not(user.role?('Admin'))
+    assert_not(user.role?('Agent'))
+    assert(user.role?('Customer'))
+
   end
 
-  test 'user index with customer1' do
+  test 'user index and create with customer1' do
 
     credentials = ActionController::HttpAuthentication::Basic.encode_credentials('rest-customer1@example.com', 'customer1pw')
 
@@ -216,6 +312,18 @@ class UserOrganizationControllerTest < ActionDispatch::IntegrationTest
     assert_equal(result.class, Hash)
     assert(result.empty?)
 
+    # create user with admin role
+    role = Role.lookup(name: 'Admin')
+    params = { firstname: 'Admin First', lastname: 'Admin Last', email: 'new_admin_by_customer1@example.com', role_ids: [ role.id ] }
+    post '/api/v1/users', params.to_json, @headers
+    assert_response(401)
+
+    # create user with agent role
+    role = Role.lookup(name: 'Agent')
+    params = { firstname: 'Agent First', lastname: 'Agent Last', email: 'new_agent_by_customer1@example.com', role_ids: [ role.id ] }
+    post '/api/v1/users', params.to_json, @headers
+    assert_response(401)
+
   end
 
   test 'user index with customer2' do