Skip to content

Commit

Permalink
Merge pull request #25 from silinternational/develop
Browse files Browse the repository at this point in the history
Release 3.1.0
  • Loading branch information
briskt authored Nov 18, 2019
2 parents e104eb2 + dc98afa commit f799e1f
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 114 deletions.
38 changes: 33 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,20 @@ to be updated.
|------------|-----------------|---------------------|--------------|
| id | externalIds | value | organization |
| area | locations | area | desk |
| building | locations | buildingId | desk |
| costCenter | organizations | costCenter | (not set) |
| department | organizations | department | (not set) |
| title | organizations | title | (not set) |
| costCenter | organizations* | costCenter | (not set) |
| department | organizations* | department | (not set) |
| title | organizations* | title | (not set) |
| phone | phones | value | work |
| manager | relations | value | manager |
| familyName | name | familyName | n/a |
| givenName | name | givenName | n/a |

Custom schema properties can be added using dot notation. For example, a
custom property with Field name `Building` in the custom schema `Location`
is represented as `Location.Building`.

__\* CAUTION:__ updating any field in `organizations` will overwrite all
existing organizations

Following is an example configuration listing all available fields:

Expand Down Expand Up @@ -204,7 +210,7 @@ Following is an example configuration listing all available fields:
},
{
"Source": "building",
"Destination": "building",
"Destination": "Location.Building",
"required": false
},
{
Expand Down Expand Up @@ -318,3 +324,25 @@ as the `DelegatedAdminEmail` value under `Destination`/`ExtraJSON`.
```

`ListClientsPageLimit` and `BatchSizePerMinute` are optional. Their defaults are as shown in the example config.

### Exporting logs from CloudWatch

The log messages in CloudWatch can be viewed on the AWS Management Console. If
an exported text or json file is needed, the AWS CLI tool can be used as
follows:

```shell script
aws configure
aws logs get-log-events \
--log-group-name "/aws/lambda/lambda-name" \
--log-stream-name '2019/11/14/[$LATEST]0123456789abcdef0123456789abcdef' \
--output text \
--query 'events[*].message'
```

Replace `/aws/lambda/lambda-name` with the actual log group name and
`2019/11/14/[$LATEST]0123456789abcdef0123456789abcdef` with the actual log
stream. Note the single quotes around the log stream name to prevent the shell
from interpreting the `$` character. `--output text` can be changed to
`--output json` if desired. Timestamps are available if needed, but omitted
in this example by the `--query` string.
130 changes: 87 additions & 43 deletions googledest/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import (
"sync"
"sync/atomic"

admin "google.golang.org/api/admin/directory/v1"

personnel_sync "github.com/silinternational/personnel-sync"
"golang.org/x/net/context"
admin "google.golang.org/api/admin/directory/v1"
"google.golang.org/api/googleapi"
)

type GoogleUsersConfig struct {
Expand Down Expand Up @@ -74,7 +74,6 @@ func extractData(user admin.User) personnel_sync.Person {

if found := findFirstMatchingType(user.Locations, "desk"); found != nil {
setStringFromInterface(found["area"], newPerson.Attributes, "area")
setStringFromInterface(found["buildingId"], newPerson.Attributes, "building")
}

if found := findFirstMatchingType(user.Organizations, ""); found != nil {
Expand All @@ -96,6 +95,14 @@ func extractData(user admin.User) personnel_sync.Person {
newPerson.Attributes["givenName"] = user.Name.GivenName
}

for schemaKey, schemaVal := range user.CustomSchemas {
var schema map[string]string
_ = json.Unmarshal(schemaVal, &schema)
for propertyKey, propertyVal := range schema {
newPerson.Attributes[schemaKey+"."+propertyKey] = propertyVal
}
}

return newPerson
}

Expand Down Expand Up @@ -139,7 +146,8 @@ func setStringFromInterface(i interface{}, m map[string]string, key string) {
func (g *GoogleUsers) ListUsers() ([]personnel_sync.Person, error) {
var usersList []*admin.User
usersListCall := g.AdminService.Users.List()
usersListCall.Customer("my_customer")
usersListCall.Customer("my_customer") // query all domains in this GSuite
usersListCall.Projection("full") // include custom fields
err := usersListCall.Pages(context.TODO(), func(users *admin.Users) error {
usersList = append(usersList, users.Users...)
return nil
Expand Down Expand Up @@ -181,44 +189,81 @@ func (g *GoogleUsers) ApplyChangeSet(
func newUserForUpdate(person personnel_sync.Person, oldUser admin.User) (admin.User, error) {
user := admin.User{}
var err error

newName := admin.UserName{
GivenName: person.Attributes["givenName"],
FamilyName: person.Attributes["familyName"],
}
user.Name = &newName

if person.Attributes["id"] != "" {
user.ExternalIds, err = updateIDs(person.Attributes["id"], oldUser.ExternalIds)
if err != nil {
return admin.User{}, err
var organization admin.UserOrganization
isOrgModified := false

for key, val := range person.Attributes {
switch key {
case "givenName":
if user.Name == nil {
user.Name = &admin.UserName{GivenName: val}
} else {
user.Name.GivenName = val
}

case "familyName":
if user.Name == nil {
user.Name = &admin.UserName{FamilyName: val}
} else {
user.Name.FamilyName = val
}

case "id":
user.ExternalIds, err = updateIDs(val, oldUser.ExternalIds)
if err != nil {
return admin.User{}, err
}

case "area":
user.Locations, err = updateLocations(val, oldUser.Locations)
if err != nil {
return admin.User{}, err
}

case "costCenter":
organization.CostCenter = val
isOrgModified = true

case "department":
organization.Department = val
isOrgModified = true

case "title":
organization.Title = val
isOrgModified = true

case "phone":
user.Phones, err = updatePhones(val, oldUser.Phones)
if err != nil {
return admin.User{}, err
}

case "manager":
user.Relations, err = updateRelations(val, oldUser.Relations)
if err != nil {
return admin.User{}, err
}

default:
keys := strings.SplitN(key, ".", 2)
if len(keys) < 2 {
continue
}

j, err := json.Marshal(&map[string]string{keys[1]: val})
if err != nil {
return admin.User{}, fmt.Errorf("error marshaling custom schema, %s", err)
}

user.CustomSchemas = map[string]googleapi.RawMessage{
keys[0]: j,
}
}
}

user.Locations, err = updateLocations(person.Attributes["area"], person.Attributes["building"], oldUser.Locations)
if err != nil {
return admin.User{}, err
}

// NOTICE: this will overwrite any and all existing Organizations
user.Organizations = []admin.UserOrganization{{
CostCenter: person.Attributes["costCenter"],
Department: person.Attributes["department"],
Title: person.Attributes["title"],
}}

if person.Attributes["phone"] != "" {
user.Phones, err = updatePhones(person.Attributes["phone"], oldUser.Phones)
if err != nil {
return admin.User{}, err
}
}

if person.Attributes["manager"] != "" {
user.Relations, err = updateRelations(person.Attributes["manager"], oldUser.Relations)
if err != nil {
return admin.User{}, err
}
if isOrgModified {
// NOTICE: this will overwrite any and all existing Organizations
user.Organizations = []admin.UserOrganization{organization}
}

return user, nil
Expand Down Expand Up @@ -317,11 +362,10 @@ func updateIDs(newID string, oldIDs interface{}) ([]admin.UserExternalId, error)
return IDs, nil
}

func updateLocations(newArea, newBuilding string, oldLocations interface{}) ([]admin.UserLocation, error) {
func updateLocations(newArea string, oldLocations interface{}) ([]admin.UserLocation, error) {
locations := []admin.UserLocation{{
Type: "desk",
Area: newArea,
BuildingId: newBuilding,
Type: "desk",
Area: newArea,
}}

if oldLocations == nil {
Expand Down
Loading

0 comments on commit f799e1f

Please sign in to comment.