From 84313f47a2ba04df190e29e535a5b79188fa77a2 Mon Sep 17 00:00:00 2001 From: David Archibald Date: Wed, 1 Sep 2021 11:18:59 -0700 Subject: [PATCH 1/3] Create the ability to send email messages --- Attachment.go | 15 ++++++ DateTimeTimeZone.go | 11 +++++ Extension.go | 8 +++ FollowupFlag.go | 11 +++++ ForwardMessageOptions.go | 9 ++++ Importance.go | 9 ++++ InternetMessageHeader.go | 9 ++++ ItemBody.go | 9 ++++ Message.go | 73 ++++++++++++++++++++++++++++ MessageClassification.go | 9 ++++ MessageReply.go | 9 ++++ Messages.go | 9 ++++ MultiValueLegacyExtendedProperty.go | 7 +++ Recipient.go | 8 +++ SingleValueLegacyExtendedProperty.go | 9 ++++ User.go | 26 ++++++++++ 16 files changed, 231 insertions(+) create mode 100644 Attachment.go create mode 100644 DateTimeTimeZone.go create mode 100644 Extension.go create mode 100644 FollowupFlag.go create mode 100644 ForwardMessageOptions.go create mode 100644 Importance.go create mode 100644 InternetMessageHeader.go create mode 100644 ItemBody.go create mode 100644 Message.go create mode 100644 MessageClassification.go create mode 100644 MessageReply.go create mode 100644 Messages.go create mode 100644 MultiValueLegacyExtendedProperty.go create mode 100644 Recipient.go create mode 100644 SingleValueLegacyExtendedProperty.go diff --git a/Attachment.go b/Attachment.go new file mode 100644 index 0000000..ba91476 --- /dev/null +++ b/Attachment.go @@ -0,0 +1,15 @@ +package msgraph + +import "time" + +// Attachment represents content related to a event, message, or group post. +// +// See https://docs.microsoft.com/en-us/graph/api/resources/Attachment +type Attachment struct { + ContentType string `json:"contentType,omitempty"` + ID string `json:"id,omitempty"` + IsInline bool `json:"isInline,omitempty"` + LastModifiedDateTime time.Time `json:"lastModifiedDateTime,omitempty"` + Name string `json:"name,omitempty"` + Size int32 `json:"size,omitempty"` +} diff --git a/DateTimeTimeZone.go b/DateTimeTimeZone.go new file mode 100644 index 0000000..5bbf07d --- /dev/null +++ b/DateTimeTimeZone.go @@ -0,0 +1,11 @@ +package msgraph + +import "time" + +// DateTimeTimeZone represents the date, time, and timezone for a given time. +// +// See https://docs.microsoft.com/en-us/graph/api/resources/DateTimeTimeZone?view=graph-rest-1.0 +type DateTimeTimeZone struct { + DateTime time.Time `json:"dateTime,omitempty"` + TimeZone *time.Location `json:"timeZone,omitempty"` +} diff --git a/Extension.go b/Extension.go new file mode 100644 index 0000000..a1f1d56 --- /dev/null +++ b/Extension.go @@ -0,0 +1,8 @@ +package msgraph + +// Extension is an abstract type to represent an open type extension. +// +// See https://docs.microsoft.com/en-us/graph/api/resources/Extension +type Extension struct { + ID string `json:"id,omitempty"` +} diff --git a/FollowupFlag.go b/FollowupFlag.go new file mode 100644 index 0000000..be15888 --- /dev/null +++ b/FollowupFlag.go @@ -0,0 +1,11 @@ +package msgraph + +// FollowupFlag are flags on a message that display how it should be followed up on. +// +// See https://docs.microsoft.com/en-us/graph/api/resources/FollowupFlag +type FollowupFlag struct { + CompletedDateTime DateTimeTimeZone `json:"completedDateTime,omitempty"` + DueDateTime DateTimeTimeZone `json:"dueDateTime,omitempty"` + FlagStatus string `json:"flagStatus,omitempty"` + StartDateTime DateTimeTimeZone `json:"startDateTime,omitempty"` +} diff --git a/ForwardMessageOptions.go b/ForwardMessageOptions.go new file mode 100644 index 0000000..839b36d --- /dev/null +++ b/ForwardMessageOptions.go @@ -0,0 +1,9 @@ +package msgraph + +// Structure to reply to messages. +// +// See https://docs.microsoft.com/en-us/graph/api/message-reply +type ForwardMessageOptions struct { + Comment string `json:"comment,omitempty"` // A comment to add. + ToRecipients []Recipient `json:"toRecipients,omitempty"` // Properties to be updated when repling. +} diff --git a/Importance.go b/Importance.go new file mode 100644 index 0000000..638340d --- /dev/null +++ b/Importance.go @@ -0,0 +1,9 @@ +package msgraph + +type MessageImportance string + +var ( + MessageImportanceLow MessageImportance = "low" + MessageImportanceNormal MessageImportance = "normal" + MessageImportanceHigh MessageImportance = "high" +) diff --git a/InternetMessageHeader.go b/InternetMessageHeader.go new file mode 100644 index 0000000..a5c5fa8 --- /dev/null +++ b/InternetMessageHeader.go @@ -0,0 +1,9 @@ +package msgraph + +// InternetMessageHeader is a key-value pair that represents an Internet message header that provides details of the network path taken from the message to the recipient. See RFC5322 for the definition. +// +// See https://docs.microsoft.com/en-us/graph/api/resources/InternetMessageHeader +type InternetMessageHeader struct { + Name string `json:"name,omitempty"` + Value string `json:"value,omitempty"` +} diff --git a/ItemBody.go b/ItemBody.go new file mode 100644 index 0000000..a3d233c --- /dev/null +++ b/ItemBody.go @@ -0,0 +1,9 @@ +package msgraph + +// ItemBody represents the body of an item, either a message, event, or group post. +// +// See https://docs.microsoft.com/en-us/graph/api/resources/ItemBody +type ItemBody struct { + Content string `json:"content,omitempty"` + ContentType string `json:"contentType,omitempty"` +} diff --git a/Message.go b/Message.go new file mode 100644 index 0000000..0b70b7b --- /dev/null +++ b/Message.go @@ -0,0 +1,73 @@ +package msgraph + +import ( + "time" +) + +// Message represents a single email message. +// +// See https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/resources/Message +type Message struct { + BCCRecipients []Recipient `json:"bccRecipients,omitempty"` + Body *ItemBody `json:"body,omitempty"` + BodyPreview string `json:"bodyPreview,omitempty"` + Categories []string `json:"categories,omitempty"` + CCRecipients []Recipient `json:"ccRecipients,omitempty"` + ChangeKey string `json:"changeKey,omitempty"` + ConversationID string `json:"conversationId,omitempty"` + ConversationIndex string `json:"conversationIndex,omitempty"` + CreatedDateTime time.Time `json:"createdDateTime,omitempty"` + Flag *FollowupFlag `json:"flag,omitempty"` + From *Recipient `json:"from,omitempty"` + HasAttachments *bool `json:"hasAttachments,omitempty"` + ID string `json:"id,omitempty"` + Importance MessageImportance `json:"importance,omitempty"` + InferenceClassification MessageClassification `json:"inferenceClassification,omitempty"` + InternetMessageHeaders []InternetMessageHeader `json:"internetMessageHeaders,omitempty"` + InternetMessageID string `json:"internetMessageId,omitempty"` + IsDeliveryReceiptRequested *bool `json:"isDeliveryReceiptRequested,omitempty"` + IsDraft *bool `json:"isDraft,omitempty"` + IsRead *bool `json:"isRead,omitempty"` + IsReadReceiptRequested *bool `json:"isReadReceiptRequested,omitempty"` + LastModifiedDateTime time.Time `json:"lastModifiedDateTime,omitempty"` + ParentFolderId string `json:"parentFolderId,omitempty"` + ReceivedDateTime time.Time `json:"receivedDateTime,omitempty"` + ReplyTo []Recipient `json:"replyTo,omitempty"` + Sender *Recipient `json:"sender,omitempty"` + SentDateTime time.Time `json:"sentDateTime,omitempty"` + Subject string `json:"subject,omitempty"` + ToRecipients []Recipient `json:"toRecipients,omitempty"` + UniqueBody *ItemBody `json:"uniqueBody,omitempty"` + WebLink string `json:"webLink,omitempty"` + Attachments []Attachment `json:"attachments,omitempty"` + Extensions []Extension `json:"extensions,omitempty"` + MultiValueExtendedProperties []MultiValueLegacyExtendedProperty `json:"multiValueExtendedProperties,omitempty"` + SingleValueExtendedProperties []SingleValueLegacyExtendedProperty `json:"singleValueExtendedProperties,omitempty"` + + graphClient *GraphClient +} + +// setGraphClient sets the graphClient instance in this instance and all child-instances (if any) +func (m *Message) setGraphClient(graphClient *GraphClient) { + m.graphClient = graphClient + + for _, bccRecipient := range m.BCCRecipients { + bccRecipient.setGraphClient(graphClient) + } + + for _, ccRecipient := range m.CCRecipients { + ccRecipient.setGraphClient(graphClient) + } + + m.From.setGraphClient(graphClient) + + for _, replyToRecipient := range m.ReplyTo { + replyToRecipient.setGraphClient(graphClient) + } + + m.Sender.setGraphClient(graphClient) + + for _, toRecipient := range m.ToRecipients { + toRecipient.setGraphClient(graphClient) + } +} diff --git a/MessageClassification.go b/MessageClassification.go new file mode 100644 index 0000000..c6417d1 --- /dev/null +++ b/MessageClassification.go @@ -0,0 +1,9 @@ +package msgraph + +// MessageClassification is the importance of a user's message either inferred or overridden. +type MessageClassification string + +var ( + MessageClassificationFocused MessageClassification = "focused" + MessageClassificationOther MessageClassification = "other" +) diff --git a/MessageReply.go b/MessageReply.go new file mode 100644 index 0000000..f97ffe6 --- /dev/null +++ b/MessageReply.go @@ -0,0 +1,9 @@ +package msgraph + +// Structure to reply to messages. +// +// See https://docs.microsoft.com/en-us/graph/api/message-reply +type MessageReply struct { + Comment string `json:"comment,omitempty"` // A comment to add. + Message Message `json:"message,omitempty"` // Properties to be updated when repling. +} diff --git a/Messages.go b/Messages.go new file mode 100644 index 0000000..2ce1ebc --- /dev/null +++ b/Messages.go @@ -0,0 +1,9 @@ +package msgraph + +type Messages []Message + +func (m Messages) setGraphClient(graphClient *GraphClient) { + for _, message := range m { + message.setGraphClient(graphClient) + } +} diff --git a/MultiValueLegacyExtendedProperty.go b/MultiValueLegacyExtendedProperty.go new file mode 100644 index 0000000..700417c --- /dev/null +++ b/MultiValueLegacyExtendedProperty.go @@ -0,0 +1,7 @@ +package msgraph + +// MultiValueLegacyExtendedProperty is an extended value that contains a slice of values. +type MultiValueLegacyExtendedProperty struct { + ID string `json:"id,omitempty"` + Value []string `json:"value,omitempty"` +} diff --git a/Recipient.go b/Recipient.go new file mode 100644 index 0000000..94cbc9b --- /dev/null +++ b/Recipient.go @@ -0,0 +1,8 @@ +package msgraph + +// Represents a user that has sent or been sent an event, message, or group post. +// +// See https://developer.microsoft.com/en-us/graph/docs/api-reference/v1.0/resources/Recipient +type Recipient struct { + EmailAddress `json:"emailAddress,omitempty"` +} diff --git a/SingleValueLegacyExtendedProperty.go b/SingleValueLegacyExtendedProperty.go new file mode 100644 index 0000000..71259bb --- /dev/null +++ b/SingleValueLegacyExtendedProperty.go @@ -0,0 +1,9 @@ +package msgraph + +// SingleValueLegacyExtendedProperty is an extended that contains a single value. +// +// See https://docs.microsoft.com/en-us/graph/api/resources/SingleValueLegacyExtendedProperty +type SingleValueLegacyExtendedProperty struct { + ID string `json:"id,omitempty"` + Value string `json:"value,omitempty"` +} diff --git a/User.go b/User.go index a23b92c..ff38cdd 100644 --- a/User.go +++ b/User.go @@ -105,6 +105,32 @@ func (u User) ListCalendarView(startDateTime, endDateTime time.Time, opts ...Lis return calendarEvents, u.graphClient.makeGETAPICall(resource, reqOpt, &calendarEvents) } +// SendMail sends a message. +// +// See https://docs.microsoft.com/en-us/graph/api/user-sendmail +func (u User) SendMail(message Message, saveToSentItems bool) error { + if u.graphClient == nil { + return ErrNotGraphClientSourced + } + + bodyBytes, err := json.Marshal(struct { + Message Message `json:"message,omitempty"` + SaveToSentItems bool `json:"saveToSentItems,omitempty"` + }{ + message, + saveToSentItems, + }) + if err != nil { + return fmt.Errorf("could not marshal message body: %w", err) + } + + reader := bytes.NewReader(bodyBytes) + + resource := fmt.Sprintf("/users/%v/sendMail", u.ID) + + return u.graphClient.makePOSTAPICall(resource, nil, reader, nil) +} + // getTimeZoneChoices grabs all supported time zones from microsoft for this user. // This should actually be the same for every user. Only used internally by this // msgraph package. From a2b6df674e14ce4866ae030f2088992040afd056 Mon Sep 17 00:00:00 2001 From: David Archibald Date: Thu, 2 Sep 2021 04:08:31 -0800 Subject: [PATCH 2/3] Update module path --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 6550fa3..2f0ff22 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ -module github.com/open-networks/go-msgraph +module github.com/mypricehealth/go-msgraph go 1.16 From 9905cba7bacb01d32c7e08a5e401f97633c39377 Mon Sep 17 00:00:00 2001 From: David Archibald Date: Thu, 2 Sep 2021 08:37:41 -0700 Subject: [PATCH 3/3] Move SendMail method into graphClient --- GraphClient.go | 26 ++++++++++++++++++++++++++ Message.go | 27 --------------------------- Messages.go | 9 --------- User.go | 26 -------------------------- 4 files changed, 26 insertions(+), 62 deletions(-) delete mode 100644 Messages.go diff --git a/GraphClient.go b/GraphClient.go index 69ecb27..d7633ae 100644 --- a/GraphClient.go +++ b/GraphClient.go @@ -304,6 +304,32 @@ func (g *GraphClient) CreateUser(userInput User, opts ...CreateQueryOption) (Use return user, err } +// SendMail sends a message. +// +// See https://docs.microsoft.com/en-us/graph/api/user-sendmail +func (g *GraphClient) SendMail(userID string, message Message, saveToSentItems bool) error { + if g == nil { + return ErrNotGraphClientSourced + } + + bodyBytes, err := json.Marshal(struct { + Message Message `json:"message,omitempty"` + SaveToSentItems bool `json:"saveToSentItems,omitempty"` + }{ + message, + saveToSentItems, + }) + if err != nil { + return fmt.Errorf("could not marshal message body: %w", err) + } + + reader := bytes.NewReader(bodyBytes) + + resource := fmt.Sprintf("/users/%v/sendMail", userID) + + return g.makePOSTAPICall(resource, compileCreateQueryOptions(nil), reader, nil) +} + // UnmarshalJSON implements the json unmarshal to be used by the json-library. // This method additionally to loading the TenantID, ApplicationID and ClientSecret // immediately gets a Token from msgraph (hence initialize this GraphAPI instance) diff --git a/Message.go b/Message.go index 0b70b7b..de3e392 100644 --- a/Message.go +++ b/Message.go @@ -43,31 +43,4 @@ type Message struct { Extensions []Extension `json:"extensions,omitempty"` MultiValueExtendedProperties []MultiValueLegacyExtendedProperty `json:"multiValueExtendedProperties,omitempty"` SingleValueExtendedProperties []SingleValueLegacyExtendedProperty `json:"singleValueExtendedProperties,omitempty"` - - graphClient *GraphClient -} - -// setGraphClient sets the graphClient instance in this instance and all child-instances (if any) -func (m *Message) setGraphClient(graphClient *GraphClient) { - m.graphClient = graphClient - - for _, bccRecipient := range m.BCCRecipients { - bccRecipient.setGraphClient(graphClient) - } - - for _, ccRecipient := range m.CCRecipients { - ccRecipient.setGraphClient(graphClient) - } - - m.From.setGraphClient(graphClient) - - for _, replyToRecipient := range m.ReplyTo { - replyToRecipient.setGraphClient(graphClient) - } - - m.Sender.setGraphClient(graphClient) - - for _, toRecipient := range m.ToRecipients { - toRecipient.setGraphClient(graphClient) - } } diff --git a/Messages.go b/Messages.go deleted file mode 100644 index 2ce1ebc..0000000 --- a/Messages.go +++ /dev/null @@ -1,9 +0,0 @@ -package msgraph - -type Messages []Message - -func (m Messages) setGraphClient(graphClient *GraphClient) { - for _, message := range m { - message.setGraphClient(graphClient) - } -} diff --git a/User.go b/User.go index ff38cdd..a23b92c 100644 --- a/User.go +++ b/User.go @@ -105,32 +105,6 @@ func (u User) ListCalendarView(startDateTime, endDateTime time.Time, opts ...Lis return calendarEvents, u.graphClient.makeGETAPICall(resource, reqOpt, &calendarEvents) } -// SendMail sends a message. -// -// See https://docs.microsoft.com/en-us/graph/api/user-sendmail -func (u User) SendMail(message Message, saveToSentItems bool) error { - if u.graphClient == nil { - return ErrNotGraphClientSourced - } - - bodyBytes, err := json.Marshal(struct { - Message Message `json:"message,omitempty"` - SaveToSentItems bool `json:"saveToSentItems,omitempty"` - }{ - message, - saveToSentItems, - }) - if err != nil { - return fmt.Errorf("could not marshal message body: %w", err) - } - - reader := bytes.NewReader(bodyBytes) - - resource := fmt.Sprintf("/users/%v/sendMail", u.ID) - - return u.graphClient.makePOSTAPICall(resource, nil, reader, nil) -} - // getTimeZoneChoices grabs all supported time zones from microsoft for this user. // This should actually be the same for every user. Only used internally by this // msgraph package.