#!/opt/osstech/bin/python2.7
# -*- coding: utf-8 -*-
#
# googleapps-account-userlist.py
# - List users account from Google Apps
#
# Copyright (C) KAMEI Yutaka @ Open Source Solution Technology Co. Ltd.
# License: GNU General Public License version 2 or later
# Date: 2012-12-05
#
# -d                 domain name of Google Apps(Must)
# -g                 group list flag
# --no-organization  output without org

import re
import sys
import getopt
import traceback
import urllib
import gdata.apps.client
import gdata.apps.groups.client
import gdata.apps.organization.client
import googleappsutils.domain

def usage():
  sys.stderr.write(
    "Usage:" + sys.argv[0] + " [-g|--no-organization] -d domain\n"
    "\n"
    "Output format (without -g option):\n"
    "  --------------------------------\n"
    "  username,sn,givenName,org,active\n"
    "  --------------------------------\n"
    "  If --no-organization is specified, \"org\" will be ommited (fast output).\n"
    "\n"
    "Output format (with -g option):\n"
    "  --------------------------\n"
    "  username:group1,group2,...\n"
    "  --------------------------\n"
    "  --no-organization is ignored.\n"
    "\n"
  )
  sys.exit(1)

def userClientLogin(domain, admin_email, admin_password):
  try:
    userclient     = gdata.apps.client.AppsClient(domain=domain)
    userclient.ssl = True
    userclient.ClientLogin( email=admin_email
                          , password=admin_password
                          , source='apps'
                          )
  except:
    sys.stderr.write("Failed to connect to Googleapps\n")
    sys.exit(1)
  else:
    return userclient

def orgClientLogin(domain, admin_email, admin_password):
  try:
    orgclient     = ( gdata.apps.organization.client.
                      OrganizationUnitProvisioningClient(domain=domain)
                    )
    orgclient.ssl = True
    orgclient.ClientLogin( email=admin_email
                         , password=admin_password
                         , source='apps'
                         )
    customer_id = orgclient.RetrieveCustomerId().GetCustomerId()
  except:
    sys.stderr.write("Failed to connect to Googleapps\n")
    sys.exit(1)
  else:
    return (orgclient, customer_id)

def groupClientLogin(domain, admin_email, admin_password):
  try:
    groupclient     = ( gdata.apps.groups.client.
                        GroupsProvisioningClient(domain=domain)
                      )
    groupclient.ssl = True
    groupclient.ClientLogin( email=admin_email
                           , password=admin_password
                           , source='apps'
                           )
  except:
    sys.stderr.write("Failed to connect to Googleapps\n")
    sys.exit(1)
  else:
    return groupclient

def retrieve100Users(userclient, username):
  entries = []
  for count in range(10):
    try:
      entries = userclient.RetrievePageOfUsers(username).entry
    except:
      errmsg = traceback.format_exc()
    else:
      return entries

  sys.stderr.write(errmsg)
  sys.exit(1)

def retrieveOrgOfUser(orgclient, customer_id, user_email):
  org = ""
  for count in range(10):
    try:
      org = orgclient.RetrieveOrgUser(customer_id, user_email).GetOrgUnitPath()
      org = re.sub("^$", "/", org)
      org = unicode(urllib.unquote(org), "utf-8")
    except:
      errmsg = traceback.format_exc()
    else:
      return org

  sys.stderr.write(errmsg)
  sys.exit(1)

def retrieveGroupsOfUser(groupclient, user_email):
  groups   = []
  for count in range(10):
    try:
      for g in  groupclient.RetrieveGroups(user_email).entry:
        groups += [re.sub("@.+$", "", g.GetGroupId())]
    except:
      errmsg = traceback.format_exc()
    else:
      return groups

  sys.stderr.write(errmsg)
  sys.exit(1)

def main():
  try:
    # get options
    (options, rest_args) = getopt.getopt(sys.argv[1:], "d:g", ["no-organization"])
    options_             = dict(options)

    # set parameters
    domain          = options_["-d"]
    group_flag      = options_.has_key("-g")
    only_users_flag = options_.has_key("--no-organization")
  except:
    usage()

  # read config
  try:
    configClient = googleappsutils.domain.Domain()
    configClient.readConfig(domain)
  except:
    errmsg = "Failed to read config file [{0}]\n".format(domain + ".conf")
    sys.stderr.write(errmsg)
    sys.exit(1)

  # set admin parameters
  admin_email    = configClient.admin
  admin_password = configClient.adminPass

  # prepare client object
  userclient = userClientLogin(domain, admin_email, admin_password)
  if not group_flag:
    (orgclient, customer_id) = orgClientLogin(domain, admin_email, admin_password)
  else:
    groupclient = groupClientLogin(domain, admin_email, admin_password)

  # list with org
  if not group_flag:
    if only_users_flag:
      print "username,sn,givenName,active"
    else:
      print "username,sn,givenName,org,active"

    username = ""
    while True:
      es = retrieve100Users(userclient, username)
      if not es:
        break
      for e in es:
        username = e.login.user_name
        if only_users_flag:
          org = ""
        else:
          org = "," + retrieveOrgOfUser( orgclient, customer_id, username + "@" + domain)
        print (        e.login.user_name
              + "," +  e.name.family_name
              + "," +  e.name.given_name
              +        "%s" % org
              + "," +  ("True" if e.login.suspended == "false" else "False")
              )
        username = e.login.user_name + "_"

  # list with groups
  else:
    print "username:group1,group2,..."

    username = ""
    while True:
      es = retrieve100Users(userclient, username)
      if not es:
        break
      for e in es:
        username = e.login.user_name
        groups = retrieveGroupsOfUser(groupclient, username + "@" + domain)
        print (        e.login.user_name
              + ":" +  ",".join(groups)
              )
        username = e.login.user_name + "_"

main()
