Saves updates to an event in the store. Only request changes for attributes that have actually changed.

def update_item(event, updated_attributes, calendar_item_update_operation_type):
  """ Saves updates to an event in the store. Only request changes for attributes that have actually changed."""

  root = M.UpdateItem(
    M.ItemChanges(
      T.ItemChange(
        T.ItemId(Id=event.id, ChangeKey=event.change_key),
        T.Updates()
      )
    ),
    ConflictResolution=u"AlwaysOverwrite",
    MessageDisposition=u"SendAndSaveCopy",
    SendMeetingInvitationsOrCancellations=calendar_item_update_operation_type
  )

  update_node = root.xpath(u'/m:UpdateItem/m:ItemChanges/t:ItemChange/t:Updates', namespaces=NAMESPACES)[0]

  # if not send_only_to_changed_attendees:
  #   # We want to resend invites, which you do by setting an attribute to the same value it has. Right now, events
  #   # are always scheduled as Busy time, so we just set that again.
  #   update_node.append(
  #     update_property_node(field_uri="calendar:LegacyFreeBusyStatus", node_to_insert=T.LegacyFreeBusyStatus("Busy"))
  #   )

  if u'html_body' in updated_attributes:
    update_node.append(
      update_property_node(field_uri="item:Body", node_to_insert=T.Body(event.html_body, BodyType="HTML"))
    )

  if u'text_body' in updated_attributes:
    update_node.append(
      update_property_node(field_uri="item:Body", node_to_insert=T.Body(event.text_body, BodyType="Text"))
    )

  if u'subject' in updated_attributes:
    update_node.append(
      update_property_node(field_uri="item:Subject", node_to_insert=T.Subject(event.subject))
    )

  if u'start' in updated_attributes:
    start = convert_datetime_to_utc(event.start)

    update_node.append(
      update_property_node(field_uri="calendar:Start", node_to_insert=T.Start(start.strftime(EXCHANGE_DATETIME_FORMAT)))
    )

  if u'end' in updated_attributes:
    end = convert_datetime_to_utc(event.end)

    update_node.append(
      update_property_node(field_uri="calendar:End", node_to_insert=T.End(end.strftime(EXCHANGE_DATETIME_FORMAT)))
    )

  if u'location' in updated_attributes:
    update_node.append(
      update_property_node(field_uri="calendar:Location", node_to_insert=T.Location(event.location))
    )

  if u'attendees' in updated_attributes:

    if event.required_attendees:
      required = resource_node(element=T.RequiredAttendees(), resources=event.required_attendees)

      update_node.append(
        update_property_node(field_uri="calendar:RequiredAttendees", node_to_insert=required)
      )
    else:
      update_node.append(delete_field(field_uri="calendar:RequiredAttendees"))

    if event.optional_attendees:
      optional = resource_node(element=T.OptionalAttendees(), resources=event.optional_attendees)

      update_node.append(
        update_property_node(field_uri="calendar:OptionalAttendees", node_to_insert=optional)
      )
    else:
      update_node.append(delete_field(field_uri="calendar:OptionalAttendees"))

  if u'resources' in updated_attributes:
    if event.resources:
      resources = resource_node(element=T.Resources(), resources=event.resources)

      update_node.append(
        update_property_node(field_uri="calendar:Resources", node_to_insert=resources)
      )
    else:
      update_node.append(delete_field(field_uri="calendar:Resources"))

  if u'reminder_minutes_before_start' in updated_attributes:
    if event.reminder_minutes_before_start:
      update_node.append(
        update_property_node(field_uri="item:ReminderIsSet", node_to_insert=T.ReminderIsSet('true'))
      )
      update_node.append(
        update_property_node(
          field_uri="item:ReminderMinutesBeforeStart",
          node_to_insert=T.ReminderMinutesBeforeStart(str(event.reminder_minutes_before_start))
        )
      )
    else:
      update_node.append(
        update_property_node(field_uri="item:ReminderIsSet", node_to_insert=T.ReminderIsSet('false'))
      )

  if u'is_all_day' in updated_attributes:
    update_node.append(
      update_property_node(field_uri="calendar:IsAllDayEvent", node_to_insert=T.IsAllDayEvent(str(event.is_all_day).lower()))
    )

  for attr in event.RECURRENCE_ATTRIBUTES:
    if attr in updated_attributes:

      recurrence_node = T.Recurrence()

      if event.recurrence == 'daily':
        recurrence_node.append(
          T.DailyRecurrence(
            T.Interval(str(event.recurrence_interval)),
          )
        )
      elif event.recurrence == 'weekly':
        recurrence_node.append(
          T.WeeklyRecurrence(
            T.Interval(str(event.recurrence_interval)),
            T.DaysOfWeek(event.recurrence_days),
          )
        )
      elif event.recurrence == 'monthly':
        recurrence_node.append(
          T.AbsoluteMonthlyRecurrence(
            T.Interval(str(event.recurrence_interval)),
            T.DayOfMonth(str(event.start.day)),
          )
        )
      elif event.recurrence == 'yearly':
        recurrence_node.append(
          T.AbsoluteYearlyRecurrence(
            T.DayOfMonth(str(event.start.day)),
            T.Month(event.start.strftime("%B")),
          )
        )

      recurrence_node.append(
        T.EndDateRecurrence(
          T.StartDate(event.start.strftime(EXCHANGE_DATE_FORMAT)),
          T.EndDate(event.recurrence_end_date.strftime(EXCHANGE_DATE_FORMAT)),
        )
      )

      update_node.append(
        update_property_node(field_uri="calendar:Recurrence", node_to_insert=recurrence_node)
      )

  return root