Removed outlook hook

This commit is contained in:
frikky
2020-05-23 20:06:39 +02:00
parent b6e14f91fe
commit d3187b16c0
7 changed files with 0 additions and 679 deletions
-57
View File
@@ -1,57 +0,0 @@
# Outlook trigger
Makes it possible to trigger a workflow based on an email
## Local testing - Same as ../webhook
```bash
mv ../main.go
go run main.go hook.go
```
# Deploy gcloud
gcloud functions deploy outlooktrigger --runtime go111 --entry-point Authorization --trigger-http --project shuffler --memory=128 --set-env-vars=FUNCTION_APIKEY=asdasd,CALLBACKURL=shuffler.io,TRIGGERID=test123,WORKFLOW_ID=YOUR_WORKFLOW_ID
# Build and deploy
1. Set hook.go line 1 from "package main" to "package function"
2. zip outlooktrigger.tar hook.go
3. Upload to bucket https://console.cloud.google.com/storage/browser/shuffler.appspot.com?project=shuffler
4. Go to the functions https://console.cloud.google.com/functions/list?project=shuffler
## How it works (from frontend to backend)
### Choose mailfolders
1. Use microsoft graph api to get the folders the user wants to listen to
* Have the user write their primary email (default) or another one
* Have it show the folders for the email with chooseable buttons somehow
|inbox
|-subinbox
|--subsubinbox <-- choose e.g. this one
|otherfolder
API:
// requestUrl := fmt.Sprintf("https://graph.microsoft.com/v1.0/users/me/mailfolders")
### Add callback subscription
2. Make an APIcall to ("https://outlook.office.com/api/v2.0/me/mailfolders('inbox')/messages") with callback url defined as "https://shuffler.io/api/v1/workflows/{key}/email/authorize"
* Should this be set up whenever the user clicked start or when the workflow is created?
* Start click ->
1. Add another cloud function for the item
2. When it's ready, deploy it to authorize
3. Show it as ready
### Remove a subscription
* Since everything is already generated above, one would need to
* https://docs.microsoft.com/en-us/graph/api/subscription-delete?view=graph-rest-1.0&tabs=http
* DELETE https://graph.microsoft.com/v1.0/subscriptions/{id}
## CREATE - Fixme: LIST all current subscriptions, and stop them if they're towards the same endpoint
* POST /api/v1/workflows/{key}/outlook
* createOutlookSub(resp, request)
* getOutlookSubscriptions(client) // Used to remove all existing for same endpoint
* makeOutlookSubscription(client, folderIds, notificationUrl)
* Add data from ^ to triggerAuth
## DELETE
* DELETE /api/v1/workflows/{key}/outlook/{triggerId}
* handleDeleteOutlookSub(resp, request)
* handleOutlookSubRemoval(workflowId, triggerId)
-222
View File
@@ -1,222 +0,0 @@
package function
// Shuffle:
// https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/Authentication/appId/e080cbf4-5dba-44b4-8643-a7c982189c16/isMSAApp//defaultBlade/Overview/servicePrincipalCreated/true
// Oauth playground:
// https://oauthplay.azurewebsites.net/
// APPS:
// https://apps.dev.microsoft.com
// REMOVE ACCESS:
// https://portal.office.com/account/#
// Developer:
// https://developer.microsoft.com/en-us/graph/docs/concepts/permissions_reference
// Bots:
// https://dev.botframework.com/bots
// Connectors
// https://outlook.office.com/connectors/home/login/#/new
// https://go.microsoft.com/fwlink/?linkid=857599
import (
//"encoding/json"
"bytes"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"time"
)
type Info struct {
Url string `json:"url" datastore:"url"`
Name string `json:"name" datastore:"name"`
Description string `json:"description" datastore:"description"`
}
// Actions to be done by webhooks etc
// Field is the actual field to use from json
type HookAction struct {
Type string `json:"type" datastore:"type"`
Name string `json:"name" datastore:"name"`
Id string `json:"id" datastore:"id"`
Field string `json:"field" datastore:"field"`
}
type Hook struct {
Id string `json:"id" datastore:"id"`
Info Info `json:"info" datastore:"info"`
Actions []HookAction `json:"actions" datastore:"actions"`
Type string `json:"type" datastore:"type"`
Status string `json:"status" datastore:"status"`
Running bool `json:"running" datastore:"running"`
}
type TeamsHook struct {
MembersAdded []struct {
ID string `json:"id"`
} `json:"membersAdded"`
Type string `json:"type"`
Timestamp time.Time `json:"timestamp"`
LocalTimestamp string `json:"localTimestamp"`
ID string `json:"id"`
ChannelID string `json:"channelId"`
ServiceURL string `json:"serviceUrl"`
From struct {
ID string `json:"id"`
Name string `json:"name"`
} `json:"from"`
Conversation struct {
IsGroup bool `json:"isGroup"`
ConversationType string `json:"conversationType"`
ID string `json:"id"`
TenantID string `json:"tenantId"`
} `json:"conversation"`
Recipient struct {
ID string `json:"id"`
Name string `json:"name"`
} `json:"recipient"`
ChannelData struct {
Team struct {
ID string `json:"id"`
} `json:"team"`
EventType string `json:"eventType"`
Tenant struct {
ID string `json:"id"`
} `json:"tenant"`
} `json:"channelData"`
}
var hook Hook
var baseUrl = "https://shuffler.io"
type OauthToken struct {
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
ExtExpiresIn int `json:"ext_expires_in"`
AccessToken string `json:"access_token"`
}
type TeamsResponse struct {
Conversation struct {
ID string `json:"id"`
} `json:"conversation"`
From struct {
ID string `json:"id"`
Name string `json:"name"`
} `json:"from"`
Recipient struct {
ID string `json:"id"`
Name string `json:"name"`
} `json:"recipient"`
ReplyToId string `json:"replyToId"`
Type string `json:"type"`
Text string `json:"text"`
}
type O365hook struct {
OdataContext string `json:"@odata.context"`
Value []struct {
OdataType string `json:"@odata.type"`
ID interface{} `json:"Id"`
SubscriptionID string `json:"SubscriptionId"`
SubscriptionExpirationDateTime time.Time `json:"SubscriptionExpirationDateTime"`
SequenceNumber int `json:"SequenceNumber"`
ChangeType string `json:"ChangeType"`
Resource string `json:"Resource"`
ResourceData struct {
OdataType string `json:"@odata.type"`
OdataID string `json:"@odata.id"`
OdataEtag string `json:"@odata.etag"`
ID string `json:"Id"`
} `json:"ResourceData"`
} `json:"value"`
}
func Authorization(resp http.ResponseWriter, request *http.Request) {
body, err := ioutil.ReadAll(request.Body)
if err != nil {
log.Printf("Body: %s", err)
resp.WriteHeader(403)
return
}
if len(body) > 0 {
// In here - get the email data
// Check who it belongs to and run those workflows
// This should be set from run.go with the callback
// userId: {subscriptionID: {workflowID}}
// E.g. workflow: {auth: {userId
// workflow: {trigger: {
err = forwardRequest(body)
if err != nil {
log.Printf("Failed unmarshal: %s", err)
resp.WriteHeader(403)
return
}
resp.WriteHeader(200)
resp.Write([]byte("OK"))
return
}
token := request.URL.Query().Get("validationToken")
if len(token) == 0 {
log.Println("Validation token is missing")
resp.WriteHeader(403)
return
}
resp.WriteHeader(200)
resp.Write([]byte(string(token)))
}
// GetUserDetails - Get one user's details from randomuser.me API
func forwardRequest(body []byte) error {
callbackUrl := os.Getenv("CALLBACKURL")
workflowId := os.Getenv("WORKFLOW_ID")
apikey := os.Getenv("FUNCTION_APIKEY")
fullUrl := fmt.Sprintf("%s/api/v1/workflows/%s/execute", callbackUrl, workflowId)
//log.Printf("Sending data to %s", fullUrl)
data := fmt.Sprintf(`{"execution_argument": "%s"}`, string(body))
req, err := http.NewRequest(
http.MethodPost,
fullUrl,
bytes.NewBuffer([]byte(data)),
)
if err != nil {
return err
}
req.Header.Add("Authorization", fmt.Sprintf(`Bearer %s`, apikey))
req.Header.Add("Content-Type", "application/json")
randomUserClient := http.Client{
Timeout: time.Second * 5,
}
res, err := randomUserClient.Do(req)
if err != nil {
return err
}
log.Printf("Status: %d", res.StatusCode)
returnbody, err := ioutil.ReadAll(res.Body)
if err != nil {
return err
}
log.Printf("New body: %s", string(returnbody))
//log.Println(string(newbody))
return nil
}
@@ -1,7 +0,0 @@
{
"clientID": "70e37005-c954-4290-b573-d4b94e484336",
"clientSecret": ".eNw/A[kQFB5zL.agvRputdEJENeJ392",
"RedirectURL": "https://44d84ee7.ngrok.io/functions/outlook/register",
"AuthURL": "https://login.microsoftonline.com/common/oauth2/authorize",
"TokenURL": "https://login.microsoftonline.com/common/oauth2/token"
}
@@ -1,21 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDYDCCAkigAwIBAgIJAOvgxcclM1eyMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAk5PMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTgwMzA1MTE1MTIwWhcNMjgwMzAyMTE1MTIwWjBF
MQswCQYDVQQGEwJOTzETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAowNqrvocJCLLcytYBfZhsqG3CkPsJ4PTicNyjuUGmlILPHlN1DE7jbDo
KuOKImfV4AfQANnttaPksZyuKJL8XGpC7YmF5mmInUWG48SmZjvRbBi1LnCrjJKS
ywh2lJqw4w30w2ItcpogDrYhh6+T3VyabcYngZjKSFgON3wo4I0c6aT19VVXGqnK
y1WEejZmiChV4iwEu4vMPIzt16QpIBr8NPSkBLLRDAGWMjFnIuYDEwgjVn6XYhM9
+NxhvY9es+qeqLQsZj2a1wcDGaw7G4iNZdltlPmlTCreRDBYBTsYCds/rJmPZ2xi
6jgiyNZj3xHG5Knw2YIw0OwHyT9mWQIDAQABo1MwUTAdBgNVHQ4EFgQUckr5tCzg
F1eBID7mtWTfeqyX4g0wHwYDVR0jBBgwFoAUckr5tCzgF1eBID7mtWTfeqyX4g0w
DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAAdH1aPcWBjJHF6n/
NgIiRSEU4mi5I6RUlPuR7dN7dcmF1Ho7quurNFzknXwks+a62oKSnkkFxxwrv/d6
dIH5kNibVs7oRxEpA3gUmXXKUW4RPrxAp2zN37t7zs5xbpTATxfJiIMP8Rjo0sOf
SilS22Sn0e0HxBi78t3DJEZvOQ9KSRuD1g9gOAY4lj/fni6rVJo8YCR2MyjmQoXB
luHDF4jTqi/TkXECfqQZu0pctx3maISpB1fAuaELwPDvqbLgoC97gl6bIEiKLkJ0
JkbGnb997K80ztFvFAKGyUtsvEDCupe/fdBPFqCruAQWI/BqVJFTdRD43dWEQANF
S8ApvA==
-----END CERTIFICATE-----
@@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAowNqrvocJCLLcytYBfZhsqG3CkPsJ4PTicNyjuUGmlILPHlN
1DE7jbDoKuOKImfV4AfQANnttaPksZyuKJL8XGpC7YmF5mmInUWG48SmZjvRbBi1
LnCrjJKSywh2lJqw4w30w2ItcpogDrYhh6+T3VyabcYngZjKSFgON3wo4I0c6aT1
9VVXGqnKy1WEejZmiChV4iwEu4vMPIzt16QpIBr8NPSkBLLRDAGWMjFnIuYDEwgj
Vn6XYhM9+NxhvY9es+qeqLQsZj2a1wcDGaw7G4iNZdltlPmlTCreRDBYBTsYCds/
rJmPZ2xi6jgiyNZj3xHG5Knw2YIw0OwHyT9mWQIDAQABAoIBABJ+9L/dyQuglwz+
QgKLLhKinq4fftAM+ReMgZcNDW69GGFIMjh9TZCKHg2fu7Cjr3S37jXqhDoz2mL8
sBYSd2fU9rsU+4hlOQb/OIrnaSn4Z46oTwZx6kUM7HL1Bt9dnexlTPxOS3HRYwnI
SI2oslJPi4YhEaJ2v5ztwM8y20B/E/zSW2onWz5gB8/bdxSmuJaWfHioIEoac8Gf
BE7jiYMnx9kKeVfgkKPMBKXhAyE2lbAz7N5nDS/4HkbUMh389RBvakc4gkv/QkSW
LNuXpbcSqJiG0FcVutjYS87a/ul3IdhAYmZDTuvRUhNsWBiY3LSY4C9NlHhiJihg
RU1kknECgYEA1dPT6n4hy/OK2mT3ThGQQFMJWsnmcHSsvuK31+UYZOI9kNtBVxc6
HSHkh0G53o6o2wZLr2gMXy35O5ZxSbectA1Q4MJDlYBs1MfHdOVyE4z6mmA9TLN1
c+9pYOC0qx+6NwPdO7j2xdUMEUfzocWOeay0AzJg20BQYmKuy3Kc+tcCgYEAwyn6
n+XS0vodfJdHhvbW/jocQlHQOBK5HklZfq2PMgpRRDaBOvHP/f07egLc2inec2sC
yPSCEfRMMhFcU5NoBt4Unzz2Y8pbpL1L5kbM6B4IqK/5vYcbvkmBkhL3AFT6Fg/3
3XCdygPW9Vf1nRKr2KhT9dDvB+XO2B75JmKwMk8CgYApKzGf8kz7gZZ4WfwrccI+
QD6K1lihyjUAQ5J15Mv/kHeeDjjUVcqAlWf0irkImpr0IJAt43COWsGjsWF6efmX
yQCLZZuxixppFVXXsd122ivd0S28OMkiWzQEzP67+83Ujc/okcIhcNVz9lB4ExtN
Xe0CuI5haE6RwsI4tYZ33QKBgFq6ckPRcOAZ3IlmPp9Us3/+fdKq/BSFR7/3s347
q11FBKCkghFoBxx5lCPVntxhKIQZlHLdkHZOTvnbrkNAPNUsewPIMHcVxOLiCZ3k
/i9OfxIEtSJR5CjjPTQuUtu5pYWKKN2uE/ytKkpmeM1rt64CGv4lAmp2gGFijMs2
h9jrAoGBANPQO6cKqtnxvst3lnljVBoftlJgeHamUac+xeYKA5Hocv5VwLXMTzzu
09tAhQFvFwCWWrfdgtvIM6k5Sl9F5MdiO9VNflI0IVudIcm9FKorWogH02mtwxsw
hvk5VUk3awiZ/Nu9t38ukeqCetjQEf6yupy/14ZPLndN5naSeEwo
-----END RSA PRIVATE KEY-----
-41
View File
@@ -1,41 +0,0 @@
package main
import (
"log"
"net/http"
"os"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
func webhook() {
// FIXME - remove static
port := ":8080"
baseFilePath := "/"
mux := mux.NewRouter()
mux.SkipClean(true)
// FIXME - Add path for updating the hook? Can be a specific POST requeuest from backend
mux.HandleFunc(baseFilePath, Authorization).Methods("POST")
mux.HandleFunc("/authorize", Authorization).Methods("POST")
handlers.LoggingHandler(os.Stdout, mux)
loggedRouter := handlers.LoggingHandler(os.Stdout, mux)
log.Printf("Starting on http://localhost%s", port)
err := http.ListenAndServe(
port,
loggedRouter,
)
if err != nil {
log.Fatal("ListenAndServer: ", err)
}
}
func main() {
webhook()
}
-304
View File
@@ -1,304 +0,0 @@
package main
// This entire script should be part of the API backend
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"time"
"golang.org/x/oauth2"
)
type Subscription struct {
ChangeType string `json:"changeType"`
NotificationURL string `json:"notificationUrl"`
Resource string `json:"resource"`
ExpirationDateTime string `json:"expirationDateTime"`
ClientState string `json:"clientState"`
}
// ClientState string `json:"ClientState,omitempty"`
// OdataType string `json:"@odata.type"`
//odata.type - Include "@odata.type":"#Microsoft.OutlookServices.PushSubscription". The PushSubscription entity defines NotificationURL.
//ChangeType- Specifies the types of events to monitor for that resource. See ChangeType for the supported types.
//ClientState - Optional property that indicates that each notification should be sent with a header by the same ClientState value. This lets the listener check the legitimacy of each notification.
//NotificationURL- Specifies where notifications should be sent to. This URL represents a web service typically implemented by the client.
//Resource- Specifies the resource to monitor and receive notifications on. You can use the optional query parameter $filter to refine the conditions for a notification, or use $select to include specific properties in a rich notification.
//https://outlook.office.com/mail.read
type Config struct {
ClientID string
ClientSecret string
RedirectUrl string
AuthUrl string
TokenUrl string
}
func getOfficeAppInfo() (Config, error) {
configpath := "integrations/config.json"
data, err := ioutil.ReadFile(configpath)
if err != nil {
//log.Fatal(err)
log.Printf("Error getting hive: %s\n", err)
}
config := Config{}
err = json.Unmarshal(data, &config)
if err != nil {
return Config{}, err
}
return config, nil
}
// This should be a popup for the user
func get_accesstoken() (*http.Client, OauthToken, error) {
ctx := context.Background()
config, err := getOfficeAppInfo()
if err != nil {
return nil, OauthToken{}, err
}
conf := &oauth2.Config{
ClientID: config.ClientID,
ClientSecret: config.ClientSecret,
Scopes: []string{
"Mail.Read",
"User.Read",
"https://outlook.office.com/mail.read",
},
RedirectURL: "https://localhost:8000",
Endpoint: oauth2.Endpoint{
AuthURL: config.AuthUrl,
TokenURL: config.TokenUrl,
},
}
//"Mail.Read.Shared",
//url := conf.AuthCodeURL("state", oauth2.SetAuthURLParam("resource", "https://outlook.office.com"))
// ADD DATA TO STATE HERE :O
url := conf.AuthCodeURL("workflow_id%3Dc2e0b50a-2957-427e-a97b-b989dc5a5408%26trigger_id%3D9e845679-5843-4959-a76c-a6d664e9df35%26username%3Drheyix.yt@gmail.com", oauth2.SetAuthURLParam("resource", "https://graph.microsoft.com"))
fmt.Printf("Visit the URL for the auth dialog: \n%v\n\n", url)
codechannel := make(chan string)
// Handles the server callback, listening on port 8000
go func() {
port := ":8000"
http.HandleFunc("/", func(response http.ResponseWriter, request *http.Request) {
tmpcode := request.URL.Query().Get("code")
if len(tmpcode) < 100 {
return
} else {
codechannel <- tmpcode
}
})
// FIX - might cause errors not being printed
err := http.ListenAndServeTLS(port, "integrations/server.crt", "integrations/server.key", nil)
if err != nil {
log.Printf("%s\n", err)
}
}()
code := <-codechannel
close(codechannel)
// https://stackoverflow.com/questions/52787420/multiple-resources-in-a-single-authorization-request
// Multi resource ^
access_token, err := conf.Exchange(ctx, code)
//log.Printf("%#v", access_token)
if err != nil {
return nil, OauthToken{}, err
}
//log.Printf("%#v", access_token)
outlookClient := conf.Client(ctx, access_token)
oauthToken := OauthToken{
AccessToken: access_token.AccessToken,
TokenType: access_token.TokenType,
RefreshToken: access_token.RefreshToken,
Expiry: access_token.Expiry,
}
return outlookClient, oauthToken, nil
}
type OauthToken struct {
AccessToken string `json:"AccessToken" datastore:"AccessToken,noindex"`
TokenType string `json:"TokenType" datastore:"TokenType,noindex"`
RefreshToken string `json:"RefreshToken" datastore:"RefreshToken,noindex"`
Expiry time.Time `json:"Expiry" datastore:"Expiry,noindex"`
}
type Mailfolders struct {
OdataContext string `json:"@odata.context"`
OdataNextLink string `json:"@odata.nextLink"`
Value []struct {
ID string `json:"id"`
DisplayName string `json:"displayName"`
ParentFolderID string `json:"parentFolderId"`
ChildFolderCount int `json:"childFolderCount"`
UnreadItemCount int `json:"unreadItemCount"`
TotalItemCount int `json:"totalItemCount"`
} `json:"value"`
}
func getFolders(client *http.Client) (Mailfolders, error) {
requestUrl := fmt.Sprintf("https://graph.microsoft.com/v1.0/users/frikky@shuffletest.onmicrosoft.com/mailfolders")
ret, err := client.Get(requestUrl)
if err != nil {
log.Printf("FolderErr: %s", err)
return Mailfolders{}, err
}
log.Printf("Status folders: %d", ret.StatusCode)
body, err := ioutil.ReadAll(ret.Body)
if err != nil {
log.Printf("Body: %s", err)
return Mailfolders{}, err
}
//log.Printf("Body: %s", string(body))
mailfolders := Mailfolders{}
err = json.Unmarshal(body, &mailfolders)
if err != nil {
log.Printf("Unmarshal: %s", err)
return Mailfolders{}, err
}
//fmt.Printf("%#v", mailfolders)
// FIXME - recursion for subfolders
// Recursive struct
// folderEndpoint := fmt.Sprintf("%s/%s/childfolders?$top=40", requestUrl, parentId)
for _, folder := range mailfolders.Value {
log.Println(folder.DisplayName)
}
return mailfolders, nil
}
// Subscribes to a mailbox based on some thingies
func makeSubscription(client *http.Client, folderIds []string) {
// FIXME - show the users folders from oauth and let them choose
fullUrl := "https://graph.microsoft.com/v1.0/subscriptions"
//resource := fmt.Sprintf("https://outlook.office.com/api/v2.0/me/mailfolders('inbox')/messages")
resource := fmt.Sprintf("me/mailfolders('inbox')/messages")
sub := Subscription{
ChangeType: "created",
NotificationURL: "https://de4fc12b.ngrok.io",
ExpirationDateTime: "2019-09-22T18:23:45.9356913Z",
ClientState: "This is a test",
Resource: resource,
}
data, err := json.Marshal(sub)
if err != nil {
log.Printf("Marshal: %s", err)
return
}
log.Printf(string(data))
req, err := http.NewRequest(
"POST",
fullUrl,
bytes.NewBuffer(data),
)
req.Header.Add("Content-Type", "application/json")
res, err := client.Do(req)
if err != nil {
log.Printf("Client: %s", err)
return
}
log.Printf("Status: %d", res.StatusCode)
body, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Printf("Body: %s", err)
return
}
fmt.Println(string(body))
log.Println("Shoooould be set up :)")
}
func getOutlookClient(code string, accessToken OauthToken, redirectUri string) (*http.Client, *oauth2.Token, error) {
ctx := context.Background()
conf := &oauth2.Config{
ClientID: "70e37005-c954-4290-b573-d4b94e484336",
ClientSecret: ".eNw/A[kQFB5zL.agvRputdEJENeJ392",
Scopes: []string{
"Mail.Read",
"User.Read",
"https://outlook.office.com/mail.read",
},
RedirectURL: redirectUri,
Endpoint: oauth2.Endpoint{
AuthURL: "https://login.microsoftonline.com/common/oauth2/authorize",
TokenURL: "https://login.microsoftonline.com/common/oauth2/token",
},
}
if len(code) > 0 {
access_token, err := conf.Exchange(ctx, code)
if err != nil {
log.Printf("Access_token issue: %s", err)
return &http.Client{}, access_token, err
}
client := conf.Client(ctx, access_token)
return client, access_token, nil
} else {
// Manually recreate the oauthtoken
access_token := &oauth2.Token{
AccessToken: accessToken.AccessToken,
TokenType: accessToken.TokenType,
RefreshToken: accessToken.RefreshToken,
Expiry: accessToken.Expiry,
}
client := conf.Client(ctx, access_token)
return client, access_token, nil
}
}
func main() {
graphclient, oauthToken, err := get_accesstoken()
if err != nil {
log.Printf("Oauth setup: %s", err)
return
}
// FIXME - make this possible for alternative users (shared)
folders, err := getFolders(graphclient)
if err != nil {
log.Printf("Folder get error: %s", err)
return
}
_ = folders
folderIds := []string{"inbox"}
//log.Println(folders)
//log.Printf("%#v", oauthToken)
// Use oauthToken to generate data for outlook
outlookclient, _, err := getOutlookClient("", oauthToken, "https://localhost:8000")
makeSubscription(outlookclient, folderIds)
}