270 lines
7.2 KiB
Ruby
270 lines
7.2 KiB
Ruby
class DepartmentsController < ApplicationController
|
|
layout 'admin'
|
|
before_action :require_admin
|
|
before_action :find_department, only: [:show, :edit, :update, :destroy, :add_member, :remove_member, :set_leader, :set_acting_leader, :clear_leader]
|
|
|
|
def index
|
|
@departments = Department.roots.sorted.includes(:children, :leader, :acting_leader, :users)
|
|
end
|
|
|
|
def show
|
|
@members = @department.department_members.includes(:user).order(:position)
|
|
end
|
|
|
|
def new
|
|
@department = Department.new
|
|
@department.parent_id = params[:parent_id] if params[:parent_id]
|
|
@department.department_type = params[:type] || 'team'
|
|
load_parent_options
|
|
end
|
|
|
|
def create
|
|
@department = Department.new(department_params)
|
|
if @department.save
|
|
flash[:notice] = l(:notice_successful_create)
|
|
redirect_to '/org_chart'
|
|
else
|
|
load_parent_options
|
|
render :new
|
|
end
|
|
end
|
|
|
|
def edit
|
|
load_parent_options
|
|
end
|
|
|
|
def update
|
|
if @department.update(department_params)
|
|
flash[:notice] = l(:notice_successful_update)
|
|
redirect_to '/org_chart'
|
|
else
|
|
load_parent_options
|
|
render :edit
|
|
end
|
|
end
|
|
|
|
def destroy
|
|
@department.destroy
|
|
flash[:notice] = l(:notice_successful_delete)
|
|
redirect_to '/org_chart'
|
|
end
|
|
|
|
def add_member
|
|
user = find_or_create_user_from_ldap(params[:user_id], params[:ldap_uid], params[:ldap_id])
|
|
|
|
if user
|
|
member = @department.department_members.find_or_initialize_by(user: user)
|
|
member.role = 'member'
|
|
if member.save
|
|
flash[:notice] = "#{user.name} added to #{@department.name}"
|
|
else
|
|
flash[:error] = member.errors.full_messages.join(', ')
|
|
end
|
|
else
|
|
flash[:error] = 'User not found'
|
|
end
|
|
redirect_to department_path(@department)
|
|
end
|
|
|
|
def remove_member
|
|
member = @department.department_members.find_by(user_id: params[:user_id])
|
|
if member
|
|
@department.update(leader_id: nil) if @department.leader_id == member.user_id
|
|
@department.update(acting_leader_id: nil) if @department.acting_leader_id == member.user_id
|
|
member.destroy
|
|
flash[:notice] = 'Member removed'
|
|
end
|
|
redirect_to department_path(@department)
|
|
end
|
|
|
|
def set_leader
|
|
user = User.find(params[:user_id])
|
|
@department.department_members.find_or_create_by(user: user)
|
|
@department.update(leader_id: user.id, acting_leader_id: nil)
|
|
flash[:notice] = "#{user.name} is now the leader"
|
|
redirect_to department_path(@department)
|
|
end
|
|
|
|
def set_acting_leader
|
|
user = User.find(params[:user_id])
|
|
@department.department_members.find_or_create_by(user: user)
|
|
@department.update(acting_leader_id: user.id)
|
|
flash[:notice] = "#{user.name} is now the acting leader"
|
|
redirect_to department_path(@department)
|
|
end
|
|
|
|
def clear_leader
|
|
@department.update(leader_id: nil, acting_leader_id: nil)
|
|
flash[:notice] = 'Leader cleared'
|
|
redirect_to department_path(@department)
|
|
end
|
|
|
|
def org_chart
|
|
@ceo = Department.ceo.first
|
|
@departments = Department.roots.sorted.includes(:children, :leader, :acting_leader, :users)
|
|
render layout: 'base'
|
|
end
|
|
|
|
def search_ldap
|
|
query = params[:q].to_s.strip
|
|
if query.length < 2
|
|
render json: []
|
|
return
|
|
end
|
|
|
|
results = []
|
|
|
|
AuthSourceLdap.all.each do |ldap|
|
|
begin
|
|
ldap_users = search_ldap_users(ldap, query)
|
|
ldap_users.each do |entry|
|
|
uid = entry[ldap.attr_login]&.first
|
|
next unless uid
|
|
|
|
existing_user = User.find_by(login: uid)
|
|
|
|
results << {
|
|
uid: uid,
|
|
name: "#{entry[ldap.attr_firstname]&.first} #{entry[ldap.attr_lastname]&.first}".strip,
|
|
email: entry[ldap.attr_mail]&.first,
|
|
ldap_id: ldap.id,
|
|
exists: existing_user.present?,
|
|
user_id: existing_user&.id
|
|
}
|
|
end
|
|
rescue => e
|
|
Rails.logger.error "LDAP search error: #{e.message}"
|
|
end
|
|
end
|
|
|
|
render json: results.uniq { |r| r[:uid] }.first(20)
|
|
end
|
|
|
|
private
|
|
|
|
def find_department
|
|
@department = Department.find(params[:id])
|
|
rescue ActiveRecord::RecordNotFound
|
|
render_404
|
|
end
|
|
|
|
def department_params
|
|
params.require(:department).permit(:name, :parent_id, :position, :description, :department_type, :leader_id, :acting_leader_id)
|
|
end
|
|
|
|
def load_parent_options
|
|
if @department.new_record?
|
|
@parents = @department.available_parents.sorted
|
|
else
|
|
@parents = @department.available_parents.where.not(id: @department.self_and_descendants.map(&:id)).sorted
|
|
end
|
|
end
|
|
|
|
def search_ldap_users(ldap, query)
|
|
options = {
|
|
host: ldap.host,
|
|
port: ldap.port,
|
|
auth: {
|
|
method: :simple,
|
|
username: ldap.account,
|
|
password: ldap.account_password
|
|
}
|
|
}
|
|
|
|
if ldap.tls
|
|
if ldap.verify_peer
|
|
options[:encryption] = { method: :simple_tls }
|
|
else
|
|
options[:encryption] = { method: :simple_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }
|
|
end
|
|
end
|
|
|
|
conn = Net::LDAP.new(options)
|
|
|
|
filter = Net::LDAP::Filter.begins(ldap.attr_login, query) |
|
|
Net::LDAP::Filter.begins(ldap.attr_firstname, query) |
|
|
Net::LDAP::Filter.begins(ldap.attr_lastname, query)
|
|
|
|
if ldap.filter.present?
|
|
base_filter = Net::LDAP::Filter.construct(ldap.filter)
|
|
filter = base_filter & filter
|
|
end
|
|
|
|
conn.search(
|
|
base: ldap.base_dn,
|
|
filter: filter,
|
|
attributes: [ldap.attr_login, ldap.attr_firstname, ldap.attr_lastname, ldap.attr_mail],
|
|
size: 20
|
|
) || []
|
|
end
|
|
|
|
def find_or_create_user_from_ldap(user_id, ldap_uid, ldap_id)
|
|
return User.find(user_id) if user_id.present?
|
|
|
|
return nil if ldap_uid.blank?
|
|
|
|
user = User.find_by(login: ldap_uid)
|
|
return user if user
|
|
|
|
ldap = AuthSourceLdap.find_by(id: ldap_id)
|
|
return nil unless ldap
|
|
|
|
user_info = get_ldap_user_info(ldap, ldap_uid)
|
|
return nil unless user_info
|
|
|
|
user = User.new(
|
|
login: ldap_uid,
|
|
firstname: user_info[:firstname] || ldap_uid,
|
|
lastname: user_info[:lastname] || '-',
|
|
mail: user_info[:mail] || "#{ldap_uid}@example.com",
|
|
auth_source_id: ldap.id,
|
|
status: User::STATUS_ACTIVE
|
|
)
|
|
user.random_password
|
|
user.save ? user : nil
|
|
end
|
|
|
|
def get_ldap_user_info(ldap, uid)
|
|
options = {
|
|
host: ldap.host,
|
|
port: ldap.port,
|
|
auth: {
|
|
method: :simple,
|
|
username: ldap.account,
|
|
password: ldap.account_password
|
|
}
|
|
}
|
|
|
|
if ldap.tls
|
|
if ldap.verify_peer
|
|
options[:encryption] = { method: :simple_tls }
|
|
else
|
|
options[:encryption] = { method: :simple_tls, tls_options: { verify_mode: OpenSSL::SSL::VERIFY_NONE } }
|
|
end
|
|
end
|
|
|
|
conn = Net::LDAP.new(options)
|
|
|
|
filter = Net::LDAP::Filter.eq(ldap.attr_login, uid)
|
|
if ldap.filter.present?
|
|
base_filter = Net::LDAP::Filter.construct(ldap.filter)
|
|
filter = base_filter & filter
|
|
end
|
|
|
|
result = conn.search(
|
|
base: ldap.base_dn,
|
|
filter: filter,
|
|
attributes: [ldap.attr_login, ldap.attr_firstname, ldap.attr_lastname, ldap.attr_mail],
|
|
size: 1
|
|
)&.first
|
|
|
|
return nil unless result
|
|
|
|
{
|
|
firstname: result[ldap.attr_firstname]&.first,
|
|
lastname: result[ldap.attr_lastname]&.first,
|
|
mail: result[ldap.attr_mail]&.first
|
|
}
|
|
end
|
|
end
|