Ejemplo n.º 1
0
def action_setAutoScheduleMode(store, record, autoScheduleMode):
    if record.recordType == RecordType.group:
        print(
            "Setting auto-schedule-mode for {record} is not allowed.".format(
                record=prettyRecord(record)
            )
        )

    elif (
        record.recordType == RecordType.user and
        not config.Scheduling.Options.AutoSchedule.AllowUsers
    ):
        print(
            "Setting auto-schedule-mode for {record} is not allowed.".format(
                record=prettyRecord(record)
            )
        )

    else:
        print(
            "Setting auto-schedule-mode to {mode} for {record}".format(
                mode=autoScheduleMode.description,
                record=prettyRecord(record),
            )
        )

        # Get original fields
        newFields = record.fields.copy()

        # Set new values
        newFields[record.service.fieldName.autoScheduleMode] = autoScheduleMode

        updatedRecord = DirectoryRecord(record.service, newFields)
        yield record.service.updateRecords([updatedRecord], create=False)
Ejemplo n.º 2
0
def action_setAutoScheduleMode(store, record, autoScheduleMode):
    if record.recordType == RecordType.group:
        print(
            "Setting auto-schedule-mode for {record} is not allowed.".format(
                record=prettyRecord(record)
            )
        )

    elif (
        record.recordType == RecordType.user and
        not config.Scheduling.Options.AutoSchedule.AllowUsers
    ):
        print(
            "Setting auto-schedule-mode for {record} is not allowed.".format(
                record=prettyRecord(record)
            )
        )

    else:
        print(
            "Setting auto-schedule-mode to {mode} for {record}".format(
                mode=("default" if autoScheduleMode is None else autoScheduleMode.description),
                record=prettyRecord(record),
            )
        )

        yield record.setAutoScheduleMode(autoScheduleMode)
Ejemplo n.º 3
0
def action_setAutoScheduleMode(store, record, autoScheduleMode):
    if record.recordType == RecordType.group:
        print(
            "Setting auto-schedule-mode for {record} is not allowed.".format(
                record=prettyRecord(record)
            )
        )

    elif (
        record.recordType == RecordType.user and
        not config.Scheduling.Options.AutoSchedule.AllowUsers
    ):
        print(
            "Setting auto-schedule-mode for {record} is not allowed.".format(
                record=prettyRecord(record)
            )
        )

    else:
        print(
            "Setting auto-schedule-mode to {mode} for {record}".format(
                mode=autoScheduleMode.description,
                record=prettyRecord(record),
            )
        )

        # Get original fields
        newFields = record.fields.copy()

        # Set new values
        newFields[record.service.fieldName.autoScheduleMode] = autoScheduleMode

        updatedRecord = DirectoryRecord(record.service, newFields)
        yield record.service.updateRecords([updatedRecord], create=False)
Ejemplo n.º 4
0
def action_listProxyFor(store, record, *proxyTypes):
    directory = store.directoryService()

    if record.recordType != directory.recordType.user:
        print("You must pass a user principal to this command")
        returnValue(None)

    for proxyType in proxyTypes:

        groupRecordType = {
            "read": directory.recordType.readDelegatorGroup,
            "write": directory.recordType.writeDelegatorGroup,
        }.get(proxyType)

        pseudoGroup = yield directory.recordWithShortName(
            groupRecordType, record.uid)
        proxies = yield pseudoGroup.members()
        if proxies:
            print("%s is a %s proxy for:" % (prettyRecord(record), {
                "read": "Read-only",
                "write": "Read/write"
            }[proxyType]))
            printRecordList(proxies)
            print("")
        else:
            print("{r} is not a {t} proxy for anyone".format(
                r=prettyRecord(record),
                t={
                    "read": "Read-only",
                    "write": "Read/write"
                }[proxyType]))
Ejemplo n.º 5
0
def action_setAutoAcceptGroup(store, record, autoAcceptGroup):
    if record.recordType == RecordType.group:
        print("Setting auto-accept-group for {record} is not allowed.".format(
            record=prettyRecord(record)))

    elif (record.recordType == RecordType.user
          and not config.Scheduling.Options.AutoSchedule.AllowUsers):
        print("Setting auto-accept-group for {record} is not allowed.".format(
            record=prettyRecord(record)))

    else:
        groupRecord = yield recordForPrincipalID(record.service,
                                                 autoAcceptGroup)
        if groupRecord is None or groupRecord.recordType != RecordType.group:
            print("Invalid principal ID: {id}".format(id=autoAcceptGroup))
        else:
            print("Setting auto-accept-group to {group} for {record}".format(
                group=prettyRecord(groupRecord),
                record=prettyRecord(record),
            ))

            # Get original fields
            newFields = record.fields.copy()

            # Set new values
            newFields[
                record.service.fieldName.autoAcceptGroup] = groupRecord.uid

            updatedRecord = DirectoryRecord(record.service, newFields)
            yield record.service.updateRecords([updatedRecord], create=False)
Ejemplo n.º 6
0
def action_listProxyFor(store, record, *proxyTypes):
    directory = store.directoryService()
    for proxyType in proxyTypes:

        groupRecordType = {
            "read": directory.recordType.readDelegatorGroup,
            "write": directory.recordType.writeDelegatorGroup,
        }.get(proxyType)

        pseudoGroup = yield directory.recordWithShortName(
            groupRecordType,
            record.uid
        )
        proxies = yield pseudoGroup.members()
        if proxies:
            print("%s is a %s proxy for:" % (
                prettyRecord(record),
                {"read": "Read-only", "write": "Read/write"}[proxyType]
            ))
            printRecordList(proxies)
            print("")
        else:
            print(
                "{r} is not a {t} proxy for anyone".format(
                    r=prettyRecord(record),
                    t={"read": "Read-only", "write": "Read/write"}[proxyType]
                )
            )
Ejemplo n.º 7
0
def printGroupCacherInfo(service, store):
    """
    Print all groups that have been delegated to, their cached members, and
    who delegated to those groups.
    """
    directory = store.directoryService()
    txn = store.newTransaction()
    groupUIDs = yield txn.allGroupDelegates()
    for groupUID in groupUIDs:
        groupID, name, _ignore_membershipHash, modified = yield txn.groupByUID(
            groupUID
        )
        print("Group: \"{name}\" ({uid})".format(name=name, uid=groupUID))

        for txt, readWrite in (("read-only", False), ("read-write", True)):
            delegatorUIDs = yield txn.delegatorsToGroup(groupID, readWrite)
            for delegatorUID in delegatorUIDs:
                delegator = yield directory.recordWithUID(delegatorUID)
                print(
                    "...has {rw} access to {rec}".format(
                        rw=txt, rec=prettyRecord(delegator)
                    )
                )

        print("Group members:")
        memberUIDs = yield txn.membersOfGroup(groupID)
        for memberUID in memberUIDs:
            record = yield directory.recordWithUID(memberUID)
            print(prettyRecord(record))

        print("Last cached: {} GMT".format(modified))
        print()

    yield txn.commit()
Ejemplo n.º 8
0
def action_listGroupMembers(store, record):
    members = yield record.members()
    if members:
        print("Group members for %s:\n" % (prettyRecord(record)))
        printRecordList(members)
        print("")
    else:
        print("No group members for %s" % (prettyRecord(record), ))
Ejemplo n.º 9
0
def action_getValue(store, record, name):
    try:
        value = record.fields[record.service.fieldName.lookupByName(name)]
        print("{name} for {record} is {value}".format(
            name=name, record=prettyRecord(record), value=value))
    except KeyError:
        print("{name} is not set for {record}".format(
            name=name,
            record=prettyRecord(record),
        ))
Ejemplo n.º 10
0
def action_listGroupMembers(store, record):
    members = yield record.members()
    if members:
        print("Group members for %s:\n" % (
            prettyRecord(record)
        ))
        printRecordList(members)
        print("")
    else:
        print("No group members for %s" % (prettyRecord(record),))
Ejemplo n.º 11
0
def action_getValue(store, record, name):
    try:
        value = record.fields[record.service.fieldName.lookupByName(name)]
        print(
            "{name} for {record} is {value}".format(
                name=name, record=prettyRecord(record), value=value
            )
        )
    except KeyError:
        print(
            "{name} is not set for {record}".format(
                name=name, record=prettyRecord(record),
            )
        )
Ejemplo n.º 12
0
def action_getAutoAcceptGroup(store, record):
    if record.autoAcceptGroup:
        groupRecord = yield record.service.recordWithUID(
            record.autoAcceptGroup)
        if groupRecord is not None:
            print("Auto-accept-group for {record} is {group}".format(
                record=prettyRecord(record),
                group=prettyRecord(groupRecord),
            ))
        else:
            print("Invalid auto-accept-group assigned: {uid}".format(
                uid=record.autoAcceptGroup))
    else:
        print("No auto-accept-group assigned to {record}".format(
            record=prettyRecord(record)))
Ejemplo n.º 13
0
def _addRemoveProxy(msg, fn, store, record, proxyType, *proxyIDs):
    directory = store.directoryService()
    readWrite = (proxyType == "write")
    for proxyID in proxyIDs:
        proxyRecord = yield recordForPrincipalID(directory, proxyID)
        if proxyRecord is None:
            print("Invalid principal ID: %s" % (proxyID, ))
        else:
            txn = store.newTransaction()
            yield fn(txn, record, proxyRecord, readWrite)
            yield txn.commit()
            print("{msg} {proxy} as a {proxyType} proxy for {record}".format(
                msg=msg,
                proxy=prettyRecord(proxyRecord),
                proxyType=proxyType,
                record=prettyRecord(record)))
Ejemplo n.º 14
0
    def doIt(txn):
        home = yield txn.calendarHomeWithUID(principalUID)
        if home is None:
            print("No home for principal")
            returnValue(None)

        trash = yield home.getTrash()
        if trash is None:
            print("No trash available")
            returnValue(None)

        untrashedCollections = yield home.children(onlyInTrash=False)
        if len(untrashedCollections) == 0:
            print("No untrashed collections for:", prettyRecord(record))
            returnValue(None)

        for collection in untrashedCollections:
            displayName = displayNameForCollection(collection)
            children = yield trash.trashForCollection(collection._resourceID)
            if len(children) == 0:
                continue

            print("Trashed events in calendar \"{}\":".format(displayName.encode("utf-8")))
            for child in children:
                print()
                yield printEventDetails(child)
            print("")
Ejemplo n.º 15
0
    def doIt(txn):
        home = yield txn.calendarHomeWithUID(principalUID)
        if home is None:
            print("No home for principal")
            returnValue(None)

        trash = yield home.getTrash()
        if trash is None:
            print("No trash available")
            returnValue(None)

        untrashedCollections = yield home.children(onlyInTrash=False)
        if len(untrashedCollections) == 0:
            print("No untrashed collections for:", prettyRecord(record))
            returnValue(None)


        for collection in untrashedCollections:
            displayName = displayNameForCollection(collection)
            children = yield trash.trashForCollection(collection._resourceID)
            if len(children) == 0:
                continue

            print("Trashed events in calendar \"{}\":".format(displayName.encode("utf-8")))
            for child in children:
                print()
                yield printEventDetails(child)
            print("")
Ejemplo n.º 16
0
def _addRemoveProxy(msg, fn, store, record, proxyType, *proxyIDs):
    directory = store.directoryService()
    readWrite = (proxyType == "write")
    for proxyID in proxyIDs:
        proxyRecord = yield recordForPrincipalID(directory, proxyID)
        if proxyRecord is None:
            print("Invalid principal ID: %s" % (proxyID,))
        else:
            txn = store.newTransaction()
            yield fn(txn, record, proxyRecord, readWrite)
            yield txn.commit()
            print(
                "{msg} {proxy} as a {proxyType} proxy for {record}".format(
                    msg=msg, proxy=prettyRecord(proxyRecord),
                    proxyType=proxyType, record=prettyRecord(record)
                )
            )
Ejemplo n.º 17
0
def printGroupCacherInfo(service, store, principalIDs):
    """
    Print all groups that have been delegated to, their cached members, and
    who delegated to those groups.
    """
    directory = store.directoryService()
    txn = store.newTransaction()
    if not principalIDs:
        groupUIDs = yield txn.allGroupDelegates()
    else:
        groupUIDs = []
        for principalID in principalIDs:
            record = yield recordForPrincipalID(directory, principalID)
            if record:
                groupUIDs.append(record.uid)

    for groupUID in groupUIDs:
        (
            groupID, name, _ignore_membershipHash, modified, _ignore_extant
        ) = yield txn.groupByUID(
            groupUID
        )
        print("Group: \"{name}\" ({uid})".format(name=name, uid=groupUID))

        for txt, readWrite in (("read-only", False), ("read-write", True)):
            delegatorUIDs = yield txn.delegatorsToGroup(groupID, readWrite)
            for delegatorUID in delegatorUIDs:
                delegator = yield directory.recordWithUID(delegatorUID)
                print(
                    "...has {rw} access to {rec}".format(
                        rw=txt, rec=prettyRecord(delegator)
                    )
                )

        print("Group members:")
        memberUIDs = yield txn.groupMemberUIDs(groupID)
        for memberUID in memberUIDs:
            record = yield directory.recordWithUID(memberUID)
            print(prettyRecord(record))

        print("Last cached: {} GMT".format(modified))
        print()

    yield txn.commit()
Ejemplo n.º 18
0
def action_getAutoScheduleMode(store, record):
    print(
        "Auto-schedule mode for {record} is {mode}".format(
            record=prettyRecord(record),
            mode=(
                record.autoScheduleMode.description if record.autoScheduleMode
                else "Default"
            )
        )
    )
Ejemplo n.º 19
0
def action_getAutoScheduleMode(store, record):
    print(
        "Auto-schedule mode for {record} is {mode}".format(
            record=prettyRecord(record),
            mode=(
                record.autoScheduleMode.description if record.autoScheduleMode
                else "Default"
            )
        )
    )
Ejemplo n.º 20
0
def action_removeGroupMember(store, record, *memberIDs):
    directory = store.directoryService()
    existingMembers = yield record.members()
    existingMemberUIDs = set([member.uid for member in existingMembers])
    remove = set()
    for memberID in memberIDs:
        memberRecord = yield recordForPrincipalID(directory, memberID)
        if memberRecord is None:
            print("Invalid member ID: %s" % (memberID, ))
        elif memberRecord.uid not in existingMemberUIDs:
            print("Missing member ID: %s" % (memberID, ))
        else:
            remove.add(memberRecord)

    if remove:
        yield record.removeMembers(remove)
        for memberRecord in remove:
            print("Removed {member} for {record}".format(
                member=prettyRecord(memberRecord),
                record=prettyRecord(record)))
        yield record.service.updateRecords([record], create=False)
Ejemplo n.º 21
0
def action_addGroupMember(store, record, *memberIDs):
    directory = store.directoryService()
    existingMembers = yield record.members()
    existingMemberUIDs = set([member.uid for member in existingMembers])
    add = set()
    for memberID in memberIDs:
        memberRecord = yield recordForPrincipalID(directory, memberID)
        if memberRecord is None:
            print("Invalid member ID: %s" % (memberID, ))
        elif memberRecord.uid in existingMemberUIDs:
            print("Existing member ID: %s" % (memberID, ))
        else:
            add.add(memberRecord)

    if add:
        yield record.addMembers(add)
        for memberRecord in add:
            print("Added {member} for {record}".format(
                member=prettyRecord(memberRecord),
                record=prettyRecord(record)))
        yield record.service.updateRecords([record], create=False)
Ejemplo n.º 22
0
def action_listProxies(store, record, *proxyTypes):
    directory = store.directoryService()
    for proxyType in proxyTypes:

        groupRecordType = {
            "read": directory.recordType.readDelegateGroup,
            "write": directory.recordType.writeDelegateGroup,
        }.get(proxyType)

        pseudoGroup = yield directory.recordWithShortName(
            groupRecordType, record.uid)
        proxies = yield pseudoGroup.members()
        if proxies:
            print("%s proxies for %s:" % ({
                "read": "Read-only",
                "write": "Read/write"
            }[proxyType], prettyRecord(record)))
            printRecordList(proxies)
            print("")
        else:
            print("No %s proxies for %s" % (proxyType, prettyRecord(record)))
Ejemplo n.º 23
0
def printGroupCacherInfo(service, store, principalIDs):
    """
    Print all groups that have been delegated to, their cached members, and
    who delegated to those groups.
    """
    directory = store.directoryService()
    txn = store.newTransaction()
    if not principalIDs:
        groupUIDs = yield txn.allGroupDelegates()
    else:
        groupUIDs = []
        for principalID in principalIDs:
            record = yield recordForPrincipalID(directory, principalID)
            if record:
                groupUIDs.append(record.uid)

    for groupUID in groupUIDs:
        group = yield txn.groupByUID(groupUID)
        print("Group: \"{name}\" ({uid})".format(name=group.name, uid=group.groupUID))

        for txt, readWrite in (("read-only", False), ("read-write", True)):
            delegatorUIDs = yield txn.delegatorsToGroup(group.groupID, readWrite)
            for delegatorUID in delegatorUIDs:
                delegator = yield directory.recordWithUID(delegatorUID)
                print(
                    "...has {rw} access to {rec}".format(
                        rw=txt, rec=prettyRecord(delegator)
                    )
                )

        print("Group members:")
        memberUIDs = yield txn.groupMemberUIDs(group.groupID)
        for memberUID in memberUIDs:
            record = yield directory.recordWithUID(memberUID)
            print(prettyRecord(record))

        print("Last cached: {} GMT".format(group.modified))
        print()

    yield txn.commit()
Ejemplo n.º 24
0
    def doIt(txn):
        home = yield txn.calendarHomeWithUID(principalUID)
        if home is None:
            print("No home for principal")
            returnValue(None)

        trash = yield home.getTrash()
        if trash is None:
            print("No trash available")
            returnValue(None)

        trashedCollections = yield home.children(onlyInTrash=True)
        if len(trashedCollections) == 0:
            print("No trashed collections for:", prettyRecord(record))
            returnValue(None)

        print("Trashed collections for:", prettyRecord(record))

        nowDT = datetime.datetime.utcnow()

        for collection in trashedCollections:
            displayName = displayNameForCollection(collection)
            whenTrashed = collection.whenTrashed()
            ago = nowDT - whenTrashed
            print()
            print("   Trashed {}:".format(agoString(ago)))
            print(
                "      \"{}\" (collection)  Recovery ID = {}".format(
                    displayName.encode("utf-8"), collection._resourceID
                )
            )
            startTime = whenTrashed - datetime.timedelta(minutes=5)
            children = yield trash.trashForCollection(
                collection._resourceID, start=startTime
            )
            print("         ...containing events:")
            for child in children:
                component = yield child.component()
                summary = component.mainComponent().propertyValue("SUMMARY", "<no title>")
                print("            \"{}\"".format(summary.encode("utf-8")))
Ejemplo n.º 25
0
    def doIt(txn):
        home = yield txn.calendarHomeWithUID(principalUID)
        if home is None:
            print("No home for principal")
            returnValue(None)

        trash = yield home.getTrash()
        if trash is None:
            print("No trash available")
            returnValue(None)

        trashedCollections = yield home.children(onlyInTrash=True)
        if len(trashedCollections) == 0:
            print("No trashed collections for:", prettyRecord(record))
            returnValue(None)

        print("Trashed collections for:", prettyRecord(record))

        nowDT = datetime.datetime.utcnow()

        for collection in trashedCollections:
            displayName = displayNameForCollection(collection)
            whenTrashed = collection.whenTrashed()
            ago = nowDT - whenTrashed
            print()
            print("   Trashed {}:".format(agoString(ago)))
            print(
                "      \"{}\" (collection)  Recovery ID = {}".format(
                    displayName.encode("utf-8"), collection._resourceID
                )
            )
            startTime = whenTrashed - datetime.timedelta(minutes=5)
            children = yield trash.trashForCollection(
                collection._resourceID, start=startTime
            )
            print("         ...containing events:")
            for child in children:
                component = yield child.component()
                summary = component.mainComponent().propertyValue("SUMMARY", "<no title>")
                print("            \"{}\"".format(summary))
Ejemplo n.º 26
0
def action_setValue(store, record, name, value):
    print("Setting {name} to {value} for {record}".format(
        name=name,
        value=value,
        record=prettyRecord(record),
    ))
    # Get original fields
    newFields = record.fields.copy()

    # Set new value
    newFields[record.service.fieldName.lookupByName(name)] = value

    updatedRecord = DirectoryRecord(record.service, newFields)
    yield record.service.updateRecords([updatedRecord], create=False)
Ejemplo n.º 27
0
def action_listProxies(store, record, *proxyTypes):
    directory = store.directoryService()
    for proxyType in proxyTypes:

        groupRecordType = {
            "read": directory.recordType.readDelegateGroup,
            "write": directory.recordType.writeDelegateGroup,
        }.get(proxyType)

        pseudoGroup = yield directory.recordWithShortName(
            groupRecordType,
            record.uid
        )
        proxies = yield pseudoGroup.members()
        if proxies:
            print("%s proxies for %s:" % (
                {"read": "Read-only", "write": "Read/write"}[proxyType],
                prettyRecord(record)
            ))
            printRecordList(proxies)
            print("")
        else:
            print("No %s proxies for %s" % (proxyType, prettyRecord(record)))
Ejemplo n.º 28
0
def action_setValue(store, record, name, value):
    print(
        "Setting {name} to {value} for {record}".format(
            name=name, value=value, record=prettyRecord(record),
        )
    )
    # Get original fields
    newFields = record.fields.copy()

    # Set new value
    newFields[record.service.fieldName.lookupByName(name)] = value

    updatedRecord = DirectoryRecord(record.service, newFields)
    yield record.service.updateRecords([updatedRecord], create=False)
Ejemplo n.º 29
0
def action_getAutoAcceptGroup(store, record):
    if record.autoAcceptGroup:
        groupRecord = yield record.service.recordWithUID(
            record.autoAcceptGroup
        )
        if groupRecord is not None:
            print(
                "Auto-accept-group for {record} is {group}".format(
                    record=prettyRecord(record),
                    group=prettyRecord(groupRecord),
                )
            )
        else:
            print(
                "Invalid auto-accept-group assigned: {uid}".format(
                    uid=record.autoAcceptGroup
                )
            )
    else:
        print(
            "No auto-accept-group assigned to {record}".format(
                record=prettyRecord(record)
            )
        )
Ejemplo n.º 30
0
def action_removeGroupMember(store, record, *memberIDs):
    directory = store.directoryService()
    existingMembers = yield record.members()
    existingMemberUIDs = set([member.uid for member in existingMembers])
    remove = set()
    for memberID in memberIDs:
        memberRecord = yield recordForPrincipalID(directory, memberID)
        if memberRecord is None:
            print("Invalid member ID: %s" % (memberID,))
        elif memberRecord.uid not in existingMemberUIDs:
            print("Missing member ID: %s" % (memberID,))
        else:
            remove.add(memberRecord)

    if remove:
        yield record.removeMembers(remove)
        for memberRecord in remove:
            print(
                "Removed {member} for {record}".format(
                    member=prettyRecord(memberRecord),
                    record=prettyRecord(record)
                )
            )
        yield record.service.updateRecords([record], create=False)
Ejemplo n.º 31
0
def action_setAutoAcceptGroup(store, record, autoAcceptGroup):
    if record.recordType == RecordType.group:
        print(
            "Setting auto-accept-group for {record} is not allowed.".format(
                record=prettyRecord(record)
            )
        )

    elif (
        record.recordType == RecordType.user and
        not config.Scheduling.Options.AutoSchedule.AllowUsers
    ):
        print(
            "Setting auto-accept-group for {record} is not allowed.".format(
                record=prettyRecord(record)
            )
        )

    else:
        groupRecord = yield recordForPrincipalID(record.service, autoAcceptGroup)
        if groupRecord is None or groupRecord.recordType != RecordType.group:
            print("Invalid principal ID: {id}".format(id=autoAcceptGroup))
        else:
            print("Setting auto-accept-group to {group} for {record}".format(
                group=prettyRecord(groupRecord),
                record=prettyRecord(record),
            ))

            # Get original fields
            newFields = record.fields.copy()

            # Set new values
            newFields[record.service.fieldName.autoAcceptGroup] = groupRecord.uid

            updatedRecord = DirectoryRecord(record.service, newFields)
            yield record.service.updateRecords([updatedRecord], create=False)
Ejemplo n.º 32
0
def action_addGroupMember(store, record, *memberIDs):
    directory = store.directoryService()
    existingMembers = yield record.members()
    existingMemberUIDs = set([member.uid for member in existingMembers])
    add = set()
    for memberID in memberIDs:
        memberRecord = yield recordForPrincipalID(directory, memberID)
        if memberRecord is None:
            print("Invalid member ID: %s" % (memberID,))
        elif memberRecord.uid in existingMemberUIDs:
            print("Existing member ID: %s" % (memberID,))
        else:
            add.add(memberRecord)

    if add:
        yield record.addMembers(add)
        for memberRecord in add:
            print(
                "Added {member} for {record}".format(
                    member=prettyRecord(memberRecord),
                    record=prettyRecord(record)
                )
            )
        yield record.service.updateRecords([record], create=False)