corso/src/cmd/getM365/getItem.go
Keepers 24911a358b
quick graph client refactor (#2301)
## Description

A couple minor refactors.  First, combines the
graph/service_helper.go and graph/service.go
files into a single file (just lift'n'shift, no logic
changes).  Second, renames CreateHTTPClient
to just HTTPClient.  Third, replaces the new
LargeItemClient constructor with extensible
options for the http client, starting with a
NoTimeout option.  This will provide longer
term maintenance over multiple constructors.

This change sets up QoL for building multiple services
and clients within api layer handlers, which will appear
in an immediately following PR.

## Does this PR need a docs update or release note?

- [x]  No 

## Type of change

- [x] 🧹 Tech Debt/Cleanup

## Issue(s)

* #2299

## Test Plan

- [x]  Unit test
- [x] 💚 E2E
2023-01-27 19:34:00 +00:00

188 lines
4.9 KiB
Go

// getItem.go is a source file designed to retrieve an m365 object from an
// existing M365 account. Data displayed is representative of the current
// serialization abstraction versioning used by Microsoft Graph and stored by Corso.
package main
import (
"context"
"fmt"
"os"
"github.com/microsoft/kiota-abstractions-go/serialization"
kw "github.com/microsoft/kiota-serialization-json-go"
"github.com/pkg/errors"
"github.com/spf13/cobra"
. "github.com/alcionai/corso/src/cli/print"
"github.com/alcionai/corso/src/cli/utils"
"github.com/alcionai/corso/src/internal/common"
"github.com/alcionai/corso/src/internal/connector"
"github.com/alcionai/corso/src/internal/connector/exchange/api"
"github.com/alcionai/corso/src/internal/connector/graph"
"github.com/alcionai/corso/src/pkg/account"
"github.com/alcionai/corso/src/pkg/backup/details"
"github.com/alcionai/corso/src/pkg/credentials"
"github.com/alcionai/corso/src/pkg/logger"
"github.com/alcionai/corso/src/pkg/path"
)
var getCmd = &cobra.Command{
Use: "get",
Short: "Get a M365ID item JSON",
RunE: handleGetCommand,
}
// Required inputs from user for command execution
var (
tenant, user, m365ID, category string
)
// main function will produce the JSON String for a given m365 object of a
// user. Displayed Objects can be used as inputs for Mockable data
// Supports:
// - exchange (contacts, email, and events)
// Input: go run ./getItem.go --user <user>
//
// --m365ID <m365ID> --category <oneof: contacts, email, events>
func main() {
ctx, _ := logger.SeedLevel(context.Background(), logger.Development)
ctx = SetRootCmd(ctx, getCmd)
defer logger.Flush(ctx)
fs := getCmd.PersistentFlags()
fs.StringVar(&user, "user", "", "m365 user id of M365 user")
fs.StringVar(&tenant, "tenant", "",
"m365 Tenant: m365 identifier for the tenant, not required if active in OS Environment")
fs.StringVar(&m365ID, "m365ID", "", "m365 identifier for object to be created")
fs.StringVar(&category, "category", "", "type of M365 data (contacts, email, events or files)") // files not supported
cobra.CheckErr(getCmd.MarkPersistentFlagRequired("user"))
cobra.CheckErr(getCmd.MarkPersistentFlagRequired("m365ID"))
cobra.CheckErr(getCmd.MarkPersistentFlagRequired("category"))
if err := getCmd.ExecuteContext(ctx); err != nil {
logger.Flush(ctx)
os.Exit(1)
}
}
func handleGetCommand(cmd *cobra.Command, args []string) error {
ctx := cmd.Context()
if utils.HasNoFlagsAndShownHelp(cmd) {
return nil
}
_, creds, err := getGC(ctx)
if err != nil {
return err
}
err = runDisplayM365JSON(ctx, creds, user, m365ID)
if err != nil {
return Only(ctx, errors.Wrapf(err, "unable to create mock from M365: %s", m365ID))
}
return nil
}
func runDisplayM365JSON(
ctx context.Context,
creds account.M365Config,
user, itemID string,
) error {
var (
bs []byte
err error
cat = path.ToCategoryType(category)
sw = kw.NewJsonSerializationWriter()
)
ac, err := api.NewClient(creds)
if err != nil {
return err
}
switch cat {
case path.EmailCategory:
bs, err = getItem(ctx, ac.Mail(), user, itemID)
case path.EventsCategory:
bs, err = getItem(ctx, ac.Events(), user, itemID)
case path.ContactsCategory:
bs, err = getItem(ctx, ac.Contacts(), user, itemID)
default:
return fmt.Errorf("unable to process category: %s", cat)
}
if err != nil {
return err
}
str := string(bs)
err = sw.WriteStringValue("", &str)
if err != nil {
return errors.Wrapf(err, "unable to %s to string value", itemID)
}
array, err := sw.GetSerializedContent()
if err != nil {
return errors.Wrapf(err, "unable to serialize new value from M365:%s", itemID)
}
fmt.Println(string(array))
return nil
}
type itemer interface {
GetItem(
ctx context.Context,
user, itemID string,
) (serialization.Parsable, *details.ExchangeInfo, error)
Serialize(
ctx context.Context,
item serialization.Parsable,
user, itemID string,
) ([]byte, error)
}
func getItem(
ctx context.Context,
itm itemer,
user, itemID string,
) ([]byte, error) {
sp, _, err := itm.GetItem(ctx, user, itemID)
if err != nil {
return nil, errors.Wrap(err, "getting item")
}
return itm.Serialize(ctx, sp, user, itemID)
}
//-------------------------------------------------------------------------------
// Helpers
//-------------------------------------------------------------------------------
func getGC(ctx context.Context) (*connector.GraphConnector, account.M365Config, error) {
// get account info
m365Cfg := account.M365Config{
M365: credentials.GetM365(),
AzureTenantID: common.First(tenant, os.Getenv(account.AzureTenantID)),
}
acct, err := account.NewAccount(account.ProviderM365, m365Cfg)
if err != nil {
return nil, m365Cfg, Only(ctx, errors.Wrap(err, "finding m365 account details"))
}
gc, err := connector.NewGraphConnector(ctx, graph.HTTPClient(graph.NoTimeout()), acct, connector.Users)
if err != nil {
return nil, m365Cfg, Only(ctx, errors.Wrap(err, "connecting to graph API"))
}
return gc, m365Cfg, nil
}