#!/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 time
import getopt
import traceback
import codecs
import locale
import urllib
import gdata.apps.client
import gdata.apps.groups.client
import gdata.apps.organization.client
import googleappsutils.domain
import googleappsutils.client

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()
      time.sleep(1)
    else:
      return entries

  sys.stderr.write(errmsg)
  sys.stderr.write("Failed to get user list.\n")
  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 Exception, e:
      if "EntityDoesNotExist" in googleappsutils.client.OrgError(e).returnErrorMessage():
        return "!NOW_REGISTERING!"
      else:
        errmsg = traceback.format_exc()
        time.sleep(1)
    else:
      return org

  sys.stderr.write(errmsg)
  sys.stderr.write("Failed to get organization for unknown reason.\n")
  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 Exception, e:
      if "EntityDoesNotExist" in googleappsutils.client.GroupError(e).returnErrorMessage():
        return ["!!FAILD_TO_GET_GROUPS!!"]
      else:
        errmsg = traceback.format_exc()
        time.sleep(1)
    else:
      return groups

  sys.stderr.write(errmsg)
  sys.stderr.write("Failed to get googleGroups for unknown reason.\n")
  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")
              )
        sys.stdout.flush()
        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)
              )
        sys.stdout.flush()
        username = e.login.user_name + "_"

sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout)
main()
