#!/usr/bin/env ruby
# vim: sw=2 et ts=2:
# Export dev info from LDAP, code partially taken from the wiki group sync
# a3li@gentoo.org
# encoding: UTF-8

%w[ ldap json ].each {|lib| require lib }

class GentooLDAP
  LDAP_HOST = (1..5).map { |x| sprintf('ldap%d.gentoo.org', x) }.join(' ')
  LDAP_PORT = 389
  DEV_BASE = 'ou=devs,dc=gentoo,dc=org'
  SYSTEM_BASE = 'ou=system,dc=gentoo,dc=org'
  SCOPE = LDAP::LDAP_SCOPE_SUBTREE
  DEV_FILTER = '(objectClass=gentooDev)'
  @@ldap_host = LDAP_HOST
  @@ldap_port = LDAP_PORT

  def self.set_host(host)
    @@ldap_host = host
  end

  def self.set_port(port)
    @@ldap_port = port
  end

  def initialize
    @ldap = LDAP::SSLConn.new(@@ldap_host, @@ldap_port, true)
    @ldap.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
    @ldap.set_option(LDAP::LDAP_OPT_NETWORK_TIMEOUT, 3) # per server
    @ldap.bind
  end

  def get_devs
    devs = {}

    @ldap.search(DEV_BASE, SCOPE, DEV_FILTER) do |entry|
      devs[entry['uid'].first] = entry.to_hash
    end

    devs
  end

  def get_system_users
    users = {}

    @ldap.search(SYSTEM_BASE, SCOPE, DEV_FILTER) do |entry|
      users[entry['uid'].first] = entry.to_hash
    end

    users
  end
end

def gpgfp_format(input, nick)
  return nil if input == 'undefined'

  raw_fp = input.gsub(/\s/, '')

  unless raw_fp.length == 40
    $stderr.puts "Invalid GPG FP for #{nick}: #{input}"
    return nil
  end

  [36, 32, 28, 24, 20, 20, 16, 12, 8, 4].each {|pos| raw_fp = raw_fp.insert(pos, ' ') }
  raw_fp
end

def gpgfp_to_longid(input)
  "0x%s" % input.gsub(/\s/, '').split(//).last(16).join
end

def export(data)
  ret = {}

  # These are always here
  ret['name'] = data['cn'].first.force_encoding('UTF-8')
  ret['nick'] = data['uid'].first

  ret['roles'] = data['gentooRoles'].first if data.has_key? 'gentooRoles'
  ret['wiki'] = data['gentooWikiUser'].first if data.has_key? 'gentooWikiUser'
  ret['gpgfp'] = data['gpgfingerprint'].map {|fp| gpgfp_format(fp, ret['nick']) }.compact if data.has_key? 'gpgfingerprint'
  ret['gpg'] = ret['gpgfp'].map {|fp| gpgfp_to_longid fp } if data.has_key? 'gpgfingerprint'

  # Geolocation
  ret['location'] = data['gentooLocation'].first.force_encoding('UTF-8') if data.has_key? 'gentooLocation'

  if data.has_key? 'lat' and data.has_key? 'lon'
    ret['lat'] = data['lat'].first.to_f
    ret['lon'] = data['lon'].first.to_f
  end

  ret['commitaccess'] = ((data['gentooAccess'] or []).include? 'git.gentoo.org/repo/gentoo.git')

  ret
end

ldap = GentooLDAP.new
devs = ldap.get_devs
services = ldap.get_system_users

current_devs = {}
retired_devs = {}

devs.each do |dev, data|
  if data.has_key? 'gentooStatus' and data['gentooStatus'].first == 'active'
    current_devs[dev] = data
  else
    retired_devs[dev] = data
  end
end

data = { 'current' => {}, 'retired' => {}, 'system' => {} }

current_devs.keys.sort.each do |dev|
  data['current'][dev] = export(current_devs[dev])
end

retired_devs.keys.sort.each do |dev|
  data['retired'][dev] = export(retired_devs[dev])
end

services.keys.sort.each do |user|
  data['system'][user] = export(services[user])
end

puts data.to_json