diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7083e885b..170a63357 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,7 +41,7 @@ jobs: working-directory: src steps: - uses: actions/checkout@v3 - + # single setup and sum cache handling here. # the results will cascade onto both testing and linting. - name: Setup Golang with cache diff --git a/.gitignore b/.gitignore index 46f5189b8..911d91a10 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,9 @@ .corso_test.toml .corso.toml +# Logging +.corso.log + # Build directories /bin /docker/bin diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b18a4d04..7c029b8f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Document Corso's fault-tolerance and restartability features +- Add retries on timeouts and status code 500 for Exchange +- Increase page size preference for delta requests for Exchange to reduce number of roundtrips +- OneDrive file/folder permissions can now be backed up and restored +- Add `--restore-permissions` flag to toggle restoration of OneDrive permissions +- Add versions to backups so that we can understand/handle older backup formats + +### Fixed +- Backing up a calendar that has the same name as the default calendar +- Added additional backoff-retry to all OneDrive queries. +- Users with `null` userType values are no longer excluded from user queries. + +### Known Issues + +- When the same user has permissions to a file and the containing + folder, we only restore folder level permissions for the user and no + separate file only permission is restored. +- Link shares are not restored ## [v0.2.0] (alpha) - 2023-1-29 @@ -18,7 +35,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Check if the user specified for an exchange backup operation has a mailbox. ### Changed - +- Item.Attachments are disabled from being restored for the patching of ([#2353](https://github.com/alcionai/corso/issues/2353)) - BetaClient introduced. Enables Corso to be able to interact with SharePoint Page objects. Package located `/internal/connector/graph/betasdk` - Handle case where user's drive has not been initialized - Inline attachments (e.g. copy/paste ) are discovered and backed up correctly ([#2163](https://github.com/alcionai/corso/issues/2163)) diff --git a/src/cli/backup/onedrive.go b/src/cli/backup/onedrive.go index 60a055dce..9dfb20b79 100644 --- a/src/cli/backup/onedrive.go +++ b/src/cli/backup/onedrive.go @@ -79,6 +79,7 @@ func addOneDriveCommands(cmd *cobra.Command) *cobra.Command { switch cmd.Use { case createCommand: c, fs = utils.AddCommand(cmd, oneDriveCreateCmd()) + options.AddFeatureToggle(cmd, options.EnablePermissionsBackup()) c.Use = c.Use + " " + oneDriveServiceCommandCreateUseSuffix c.Example = oneDriveServiceCommandCreateExamples diff --git a/src/cli/backup/onedrive_integration_test.go b/src/cli/backup/onedrive_integration_test.go index e24cba34f..05231fd11 100644 --- a/src/cli/backup/onedrive_integration_test.go +++ b/src/cli/backup/onedrive_integration_test.go @@ -72,7 +72,13 @@ func (suite *NoBackupOneDriveIntegrationSuite) SetupSuite() { suite.m365UserID = tester.M365UserID(t) // init the repo first - suite.repo, err = repository.Initialize(ctx, suite.acct, suite.st, control.Options{}) + suite.repo, err = repository.Initialize( + ctx, + suite.acct, + suite.st, + control.Options{ + ToggleFeatures: control.Toggles{EnablePermissionsBackup: true}, + }) require.NoError(t, err) } @@ -152,7 +158,13 @@ func (suite *BackupDeleteOneDriveIntegrationSuite) SetupSuite() { defer flush() // init the repo first - suite.repo, err = repository.Initialize(ctx, suite.acct, suite.st, control.Options{}) + suite.repo, err = repository.Initialize( + ctx, + suite.acct, + suite.st, + control.Options{ + ToggleFeatures: control.Toggles{EnablePermissionsBackup: true}, + }) require.NoError(t, err) m365UserID := tester.M365UserID(t) diff --git a/src/cli/cli.go b/src/cli/cli.go index b67663d06..77a03b1a7 100644 --- a/src/cli/cli.go +++ b/src/cli/cli.go @@ -6,7 +6,9 @@ import ( "regexp" "strings" + "github.com/alcionai/clues" "github.com/spf13/cobra" + "golang.org/x/exp/slices" "github.com/alcionai/corso/src/cli/backup" "github.com/alcionai/corso/src/cli/config" @@ -50,6 +52,13 @@ func preRun(cc *cobra.Command, args []string) error { flagSl = append(flagSl, f) } + avoidTheseCommands := []string{ + "corso", "env", "help", "backup", "details", "list", "restore", "delete", "repo", "init", "connect", + } + if len(logger.LogFile) > 0 && !slices.Contains(avoidTheseCommands, cc.Use) { + print.Info(cc.Context(), "Logging to file: "+logger.LogFile) + } + log.Infow("cli command", "command", cc.CommandPath(), "flags", flagSl, "version", version.CurrentVersion()) return nil @@ -121,6 +130,9 @@ func Handle() { }() if err := corsoCmd.ExecuteContext(ctx); err != nil { + logger.Ctx(ctx). + With("err", err). + Errorw("cli execution", clues.InErr(err).Slice()...) os.Exit(1) } } diff --git a/src/cli/options/options.go b/src/cli/options/options.go index 4988c29ca..2b423836c 100644 --- a/src/cli/options/options.go +++ b/src/cli/options/options.go @@ -11,17 +11,11 @@ import ( func Control() control.Options { opt := control.Defaults() - if fastFail { - opt.FailFast = true - } - - if noStats { - opt.DisableMetrics = true - } - - if disableIncrementals { - opt.ToggleFeatures.DisableIncrementals = true - } + opt.FailFast = fastFail + opt.DisableMetrics = noStats + opt.RestorePermissions = restorePermissions + opt.ToggleFeatures.DisableIncrementals = disableIncrementals + opt.ToggleFeatures.EnablePermissionsBackup = enablePermissionsBackup return opt } @@ -31,8 +25,9 @@ func Control() control.Options { // --------------------------------------------------------------------------- var ( - fastFail bool - noStats bool + fastFail bool + noStats bool + restorePermissions bool ) // AddOperationFlags adds command-local operation flags @@ -49,11 +44,22 @@ func AddGlobalOperationFlags(cmd *cobra.Command) { fs.BoolVar(&noStats, "no-stats", false, "disable anonymous usage statistics gathering") } +// AddRestorePermissionsFlag adds OneDrive flag for restoring permissions +func AddRestorePermissionsFlag(cmd *cobra.Command) { + fs := cmd.Flags() + fs.BoolVar(&restorePermissions, "restore-permissions", false, "Restore permissions for files and folders") + // TODO: reveal this flag once backing up permissions becomes default + cobra.CheckErr(fs.MarkHidden("restore-permissions")) +} + // --------------------------------------------------------------------------- // Feature Flags // --------------------------------------------------------------------------- -var disableIncrementals bool +var ( + disableIncrementals bool + enablePermissionsBackup bool +) type exposeFeatureFlag func(*pflag.FlagSet) @@ -78,3 +84,16 @@ func DisableIncrementals() func(*pflag.FlagSet) { cobra.CheckErr(fs.MarkHidden("disable-incrementals")) } } + +// Adds the hidden '--enable-permissions-backup' cli flag which, when +// set, enables backing up permissions. +func EnablePermissionsBackup() func(*pflag.FlagSet) { + return func(fs *pflag.FlagSet) { + fs.BoolVar( + &enablePermissionsBackup, + "enable-permissions-backup", + false, + "Enable backing up item permissions for OneDrive") + cobra.CheckErr(fs.MarkHidden("enable-permissions-backup")) + } +} diff --git a/src/cli/restore/onedrive.go b/src/cli/restore/onedrive.go index 526db414b..bd8dc7816 100644 --- a/src/cli/restore/onedrive.go +++ b/src/cli/restore/onedrive.go @@ -63,6 +63,9 @@ func addOneDriveCommands(cmd *cobra.Command) *cobra.Command { utils.FileFN, nil, "Restore items by file name or ID") + // permissions restore flag + options.AddRestorePermissionsFlag(c) + // onedrive info flags fs.StringVar( @@ -97,6 +100,9 @@ const ( oneDriveServiceCommandRestoreExamples = `# Restore file with ID 98765abcdef corso restore onedrive --backup 1234abcd-12ab-cd34-56de-1234abcd --file 98765abcdef +# Restore file with ID 98765abcdef along with its associated permissions +corso restore onedrive --backup 1234abcd-12ab-cd34-56de-1234abcd --file 98765abcdef --restore-permissions + # Restore Alice's file named "FY2021 Planning.xlsx in "Documents/Finance Reports" from a specific backup corso restore onedrive --backup 1234abcd-12ab-cd34-56de-1234abcd \ --user alice@example.com --file "FY2021 Planning.xlsx" --folder "Documents/Finance Reports" diff --git a/src/cmd/factory/impl/common.go b/src/cmd/factory/impl/common.go index 0ea6835dd..78a5dca0e 100644 --- a/src/cmd/factory/impl/common.go +++ b/src/cmd/factory/impl/common.go @@ -16,6 +16,7 @@ import ( "github.com/alcionai/corso/src/internal/connector/mockconnector" "github.com/alcionai/corso/src/internal/data" "github.com/alcionai/corso/src/pkg/account" + "github.com/alcionai/corso/src/pkg/backup" "github.com/alcionai/corso/src/pkg/backup/details" "github.com/alcionai/corso/src/pkg/control" "github.com/alcionai/corso/src/pkg/credentials" @@ -50,6 +51,7 @@ func generateAndRestoreItems( tenantID, userID, destFldr string, howMany int, dbf dataBuilderFunc, + opts control.Options, ) (*details.Details, error) { items := make([]item, 0, howMany) @@ -74,7 +76,7 @@ func generateAndRestoreItems( items: items, }} - // TODO: fit the desination to the containers + // TODO: fit the destination to the containers dest := control.DefaultRestoreDestination(common.SimpleTimeTesting) dest.ContainerName = destFldr @@ -90,7 +92,7 @@ func generateAndRestoreItems( Infof(ctx, "Generating %d %s items in %s\n", howMany, cat, Destination) - return gc.RestoreDataCollections(ctx, acct, sel, dest, dataColls) + return gc.RestoreDataCollections(ctx, backup.Version, acct, sel, dest, opts, dataColls) } // ------------------------------------------------------------------------------------------ diff --git a/src/cmd/factory/impl/exchange.go b/src/cmd/factory/impl/exchange.go index 26f7eef09..39e3c13a1 100644 --- a/src/cmd/factory/impl/exchange.go +++ b/src/cmd/factory/impl/exchange.go @@ -6,6 +6,7 @@ import ( . "github.com/alcionai/corso/src/cli/print" "github.com/alcionai/corso/src/cli/utils" "github.com/alcionai/corso/src/internal/connector/mockconnector" + "github.com/alcionai/corso/src/pkg/control" "github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/selectors" ) @@ -67,6 +68,7 @@ func handleExchangeEmailFactory(cmd *cobra.Command, args []string) error { subject, body, body, now, now, now, now) }, + control.Options{}, ) if err != nil { return Only(ctx, err) @@ -107,6 +109,7 @@ func handleExchangeCalendarEventFactory(cmd *cobra.Command, args []string) error User, subject, body, body, now, now, false) }, + control.Options{}, ) if err != nil { return Only(ctx, err) @@ -152,6 +155,7 @@ func handleExchangeContactFactory(cmd *cobra.Command, args []string) error { "123-456-7890", ) }, + control.Options{}, ) if err != nil { return Only(ctx, err) diff --git a/src/go.mod b/src/go.mod index a8054ab0e..bf43f6494 100644 --- a/src/go.mod +++ b/src/go.mod @@ -4,8 +4,8 @@ go 1.19 require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.2.0 - github.com/alcionai/clues v0.0.0-20230120231953-1cf61dbafc40 - github.com/aws/aws-sdk-go v1.44.190 + github.com/alcionai/clues v0.0.0-20230131232239-cee86233b005 + github.com/aws/aws-sdk-go v1.44.192 github.com/aws/aws-xray-sdk-go v1.8.0 github.com/google/uuid v1.3.0 github.com/hashicorp/go-multierror v1.1.1 @@ -71,7 +71,6 @@ require ( github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect - github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.15.12 // indirect diff --git a/src/go.sum b/src/go.sum index 72af64b2d..17d6f25bd 100644 --- a/src/go.sum +++ b/src/go.sum @@ -52,8 +52,8 @@ github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1o github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= -github.com/alcionai/clues v0.0.0-20230120231953-1cf61dbafc40 h1:bvAwz0dcJeIyRjudVyzmmawOvc4SqlSerKd0B4dh0yw= -github.com/alcionai/clues v0.0.0-20230120231953-1cf61dbafc40/go.mod h1:UlAs8jkWIpsOMakiC8NxPgQQVQRdvyf1hYMszlYYLb4= +github.com/alcionai/clues v0.0.0-20230131232239-cee86233b005 h1:eTgICcmcydEWG8J+hgnidf0pzujV3Gd2XqmknykZkzA= +github.com/alcionai/clues v0.0.0-20230131232239-cee86233b005/go.mod h1:UlAs8jkWIpsOMakiC8NxPgQQVQRdvyf1hYMszlYYLb4= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -62,8 +62,8 @@ github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk5 github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/aws/aws-sdk-go v1.44.190 h1:QC+Pf/Ooj7Waf2obOPZbIQOqr00hy4h54j3ZK9mvHcc= -github.com/aws/aws-sdk-go v1.44.190/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= +github.com/aws/aws-sdk-go v1.44.192 h1:KL54vCxRd5v5XBGjnF3FelzXXwl+aWHDmDTihFmRNgM= +github.com/aws/aws-sdk-go v1.44.192/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-xray-sdk-go v1.8.0 h1:0xncHZ588wB/geLjbM/esoW3FOEThWy2TJyb4VXfLFY= github.com/aws/aws-xray-sdk-go v1.8.0/go.mod h1:7LKe47H+j3evfvS1+q0wzpoaGXGrF3mUsfM+thqVO+A= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= @@ -209,8 +209,6 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s= -github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= diff --git a/src/internal/connector/data_collections.go b/src/internal/connector/data_collections.go index 7d187a854..410a05462 100644 --- a/src/internal/connector/data_collections.go +++ b/src/internal/connector/data_collections.go @@ -83,7 +83,7 @@ func (gc *GraphConnector) DataCollections( return colls, excludes, nil case selectors.ServiceOneDrive: - return gc.OneDriveDataCollections(ctx, sels, ctrlOpts) + return gc.OneDriveDataCollections(ctx, sels, metadata, ctrlOpts) case selectors.ServiceSharePoint: colls, excludes, err := sharepoint.DataCollections( @@ -182,6 +182,7 @@ func (fm odFolderMatcher) Matches(dir string) bool { func (gc *GraphConnector) OneDriveDataCollections( ctx context.Context, selector selectors.Selector, + metadata []data.Collection, ctrlOpts control.Options, ) ([]data.Collection, map[string]struct{}, error) { odb, err := selector.ToOneDriveBackup() @@ -209,7 +210,7 @@ func (gc *GraphConnector) OneDriveDataCollections( gc.Service, gc.UpdateStatus, ctrlOpts, - ).Get(ctx) + ).Get(ctx, metadata) if err != nil { return nil, nil, support.WrapAndAppend(user, err, errs) } diff --git a/src/internal/connector/discovery/api/beta_service.go b/src/internal/connector/discovery/api/beta_service.go index df2b1533b..0208ace69 100644 --- a/src/internal/connector/discovery/api/beta_service.go +++ b/src/internal/connector/discovery/api/beta_service.go @@ -1,32 +1,33 @@ package api import ( - "github.com/alcionai/corso/src/internal/connector/graph/betasdk" absser "github.com/microsoft/kiota-abstractions-go/serialization" msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go" "github.com/pkg/errors" + + "github.com/alcionai/corso/src/internal/connector/graph/betasdk" ) // Service wraps BetaClient's functionality. // Abstraction created to comply loosely with graph.Servicer // methods for ease of switching between v1.0 and beta connnectors -type Service struct { +type BetaService struct { client *betasdk.BetaClient } -func (s Service) Client() *betasdk.BetaClient { +func (s BetaService) Client() *betasdk.BetaClient { return s.client } -func NewBetaService(adpt *msgraphsdk.GraphRequestAdapter) *Service { - return &Service{ +func NewBetaService(adpt *msgraphsdk.GraphRequestAdapter) *BetaService { + return &BetaService{ client: betasdk.NewBetaClient(adpt), } } // Seraialize writes an M365 parsable object into a byte array using the built-in // application/json writer within the adapter. -func (s Service) Serialize(object absser.Parsable) ([]byte, error) { +func (s BetaService) Serialize(object absser.Parsable) ([]byte, error) { writer, err := s.client.Adapter(). GetSerializationWriterFactory(). GetSerializationWriter("application/json") diff --git a/src/internal/connector/discovery/api/users.go b/src/internal/connector/discovery/api/users.go index ff41ee06f..c08297a9e 100644 --- a/src/internal/connector/discovery/api/users.go +++ b/src/internal/connector/discovery/api/users.go @@ -3,6 +3,7 @@ package api import ( "context" + absser "github.com/microsoft/kiota-abstractions-go" msgraphgocore "github.com/microsoftgraph/msgraph-sdk-go-core" "github.com/microsoftgraph/msgraph-sdk-go/models" "github.com/microsoftgraph/msgraph-sdk-go/users" @@ -58,14 +59,27 @@ const ( // require more fine-tuned controls in the future. // https://stackoverflow.com/questions/64044266/error-message-unsupported-or-invalid-query-filter-clause-specified-for-property // +// ne 'Guest' ensures we don't filter out users where userType = null, which can happen +// for user accounts created prior to 2014. In order to use the `ne` comparator, we +// MUST include $count=true and the ConsistencyLevel: eventual header. +// https://stackoverflow.com/questions/49340485/how-to-filter-users-by-usertype-null +// //nolint:lll -var userFilterNoGuests = "onPremisesSyncEnabled eq true OR userType eq 'Member'" +var userFilterNoGuests = "onPremisesSyncEnabled eq true OR userType ne 'Guest'" + +// I can't believe I have to do this. +var t = true func userOptions(fs *string) *users.UsersRequestBuilderGetRequestConfiguration { + headers := absser.NewRequestHeaders() + headers.Add("ConsistencyLevel", "eventual") + return &users.UsersRequestBuilderGetRequestConfiguration{ + Headers: headers, QueryParameters: &users.UsersRequestBuilderGetQueryParameters{ Select: []string{userSelectID, userSelectPrincipalName, userSelectDisplayName}, Filter: fs, + Count: &t, }, } } @@ -77,7 +91,13 @@ func (c Users) GetAll(ctx context.Context) ([]models.Userable, error) { return nil, err } - resp, err := service.Client().Users().Get(ctx, userOptions(&userFilterNoGuests)) + var resp models.UserCollectionResponseable + + err = graph.RunWithRetry(func() error { + resp, err = service.Client().Users().Get(ctx, userOptions(&userFilterNoGuests)) + return err + }) + if err != nil { return nil, support.ConnectorStackErrorTraceWrap(err, "getting all users") } @@ -114,22 +134,37 @@ func (c Users) GetAll(ctx context.Context) ([]models.Userable, error) { } func (c Users) GetByID(ctx context.Context, userID string) (models.Userable, error) { - user, err := c.stable.Client().UsersById(userID).Get(ctx, nil) + var ( + resp models.Userable + err error + ) + + err = graph.RunWithRetry(func() error { + resp, err = c.stable.Client().UsersById(userID).Get(ctx, nil) + return err + }) + if err != nil { return nil, support.ConnectorStackErrorTraceWrap(err, "getting user by id") } - return user, nil + return resp, err } func (c Users) GetInfo(ctx context.Context, userID string) (*UserInfo, error) { // Assume all services are enabled // then filter down to only services the user has enabled - userInfo := newUserInfo() + var ( + err error + userInfo = newUserInfo() + ) // TODO: OneDrive + err = graph.RunWithRetry(func() error { + _, err = c.stable.Client().UsersById(userID).MailFolders().Get(ctx, nil) + return err + }) - _, err := c.stable.Client().UsersById(userID).MailFolders().Get(ctx, nil) if err != nil { if !graph.IsErrExchangeMailFolderNotFound(err) { return nil, support.ConnectorStackErrorTraceWrap(err, "getting user's exchange mailfolders") diff --git a/src/internal/connector/exchange/api/contacts.go b/src/internal/connector/exchange/api/contacts.go index 0db1e964c..ac4afeb34 100644 --- a/src/internal/connector/exchange/api/contacts.go +++ b/src/internal/connector/exchange/api/contacts.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + "github.com/alcionai/clues" "github.com/hashicorp/go-multierror" "github.com/microsoft/kiota-abstractions-go/serialization" kioser "github.com/microsoft/kiota-serialization-json-go" @@ -16,6 +17,7 @@ import ( "github.com/alcionai/corso/src/internal/connector/graph/api" "github.com/alcionai/corso/src/internal/connector/support" "github.com/alcionai/corso/src/pkg/backup/details" + "github.com/alcionai/corso/src/pkg/selectors" ) // --------------------------------------------------------------------------- @@ -61,7 +63,16 @@ func (c Contacts) GetItem( ctx context.Context, user, itemID string, ) (serialization.Parsable, *details.ExchangeInfo, error) { - cont, err := c.stable.Client().UsersById(user).ContactsById(itemID).Get(ctx, nil) + var ( + cont models.Contactable + err error + ) + + err = graph.RunWithRetry(func() error { + cont, err = c.stable.Client().UsersById(user).ContactsById(itemID).Get(ctx, nil) + return err + }) + if err != nil { return nil, nil, err } @@ -81,7 +92,14 @@ func (c Contacts) GetAllContactFolderNamesForUser( return nil, err } - return c.stable.Client().UsersById(user).ContactFolders().Get(ctx, options) + var resp models.ContactFolderCollectionResponseable + + err = graph.RunWithRetry(func() error { + resp, err = c.stable.Client().UsersById(user).ContactFolders().Get(ctx, options) + return err + }) + + return resp, err } func (c Contacts) GetContainerByID( @@ -93,10 +111,14 @@ func (c Contacts) GetContainerByID( return nil, errors.Wrap(err, "options for contact folder") } - return c.stable.Client(). - UsersById(userID). - ContactFoldersById(dirID). - Get(ctx, ofcf) + var resp models.ContactFolderable + + err = graph.RunWithRetry(func() error { + resp, err = c.stable.Client().UsersById(userID).ContactFoldersById(dirID).Get(ctx, ofcf) + return err + }) + + return resp, err } // EnumerateContainers iterates through all of the users current @@ -117,6 +139,7 @@ func (c Contacts) EnumerateContainers( var ( errs *multierror.Error + resp models.ContactFolderCollectionResponseable fields = []string{"displayName", "parentFolderId"} ) @@ -131,7 +154,11 @@ func (c Contacts) EnumerateContainers( ChildFolders() for { - resp, err := builder.Get(ctx, ofcf) + err = graph.RunWithRetry(func() error { + resp, err = builder.Get(ctx, ofcf) + return err + }) + if err != nil { return errors.Wrap(err, support.ConnectorStackErrorTrace(err)) } @@ -174,7 +201,17 @@ type contactPager struct { } func (p *contactPager) getPage(ctx context.Context) (api.DeltaPageLinker, error) { - return p.builder.Get(ctx, p.options) + var ( + resp api.DeltaPageLinker + err error + ) + + err = graph.RunWithRetry(func() error { + resp, err = p.builder.Get(ctx, p.options) + return err + }) + + return resp, err } func (p *contactPager) setNext(nextLink string) { @@ -199,6 +236,11 @@ func (c Contacts) GetAddedAndRemovedItemIDs( resetDelta bool ) + ctx = clues.AddAll( + ctx, + "category", selectors.ExchangeContact, + "folder_id", directoryID) + options, err := optionsForContactFoldersItemDelta([]string{"parentFolderId"}) if err != nil { return nil, nil, DeltaUpdate{}, errors.Wrap(err, "getting query options") diff --git a/src/internal/connector/exchange/api/events.go b/src/internal/connector/exchange/api/events.go index e643c1f89..b9c16f319 100644 --- a/src/internal/connector/exchange/api/events.go +++ b/src/internal/connector/exchange/api/events.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + "github.com/alcionai/clues" "github.com/hashicorp/go-multierror" "github.com/microsoft/kiota-abstractions-go/serialization" kioser "github.com/microsoft/kiota-serialization-json-go" @@ -19,6 +20,7 @@ import ( "github.com/alcionai/corso/src/pkg/backup/details" "github.com/alcionai/corso/src/pkg/logger" "github.com/alcionai/corso/src/pkg/path" + "github.com/alcionai/corso/src/pkg/selectors" ) // --------------------------------------------------------------------------- @@ -73,7 +75,13 @@ func (c Events) GetContainerByID( return nil, errors.Wrap(err, "options for event calendar") } - cal, err := service.Client().UsersById(userID).CalendarsById(containerID).Get(ctx, ofc) + var cal models.Calendarable + + err = graph.RunWithRetry(func() error { + cal, err = service.Client().UsersById(userID).CalendarsById(containerID).Get(ctx, ofc) + return err + }) + if err != nil { return nil, err } @@ -86,12 +94,28 @@ func (c Events) GetItem( ctx context.Context, user, itemID string, ) (serialization.Parsable, *details.ExchangeInfo, error) { - event, err := c.stable.Client().UsersById(user).EventsById(itemID).Get(ctx, nil) + var ( + event models.Eventable + err error + ) + + err = graph.RunWithRetry(func() error { + event, err = c.stable.Client().UsersById(user).EventsById(itemID).Get(ctx, nil) + return err + }) + if err != nil { return nil, nil, err } - var errs *multierror.Error + var ( + errs *multierror.Error + options = &users.ItemEventsItemAttachmentsRequestBuilderGetRequestConfiguration{ + QueryParameters: &users.ItemEventsItemAttachmentsRequestBuilderGetQueryParameters{ + Expand: []string{"microsoft.graph.itemattachment/item"}, + }, + } + ) if *event.GetHasAttachments() || HasAttachments(event.GetBody()) { for count := 0; count < numberOfRetries; count++ { @@ -100,7 +124,7 @@ func (c Events) GetItem( UsersById(user). EventsById(itemID). Attachments(). - Get(ctx, nil) + Get(ctx, options) if err == nil { event.SetAttachments(attached.GetValue()) break @@ -128,7 +152,14 @@ func (c Client) GetAllCalendarNamesForUser( return nil, err } - return c.stable.Client().UsersById(user).Calendars().Get(ctx, options) + var resp models.CalendarCollectionResponseable + + err = graph.RunWithRetry(func() error { + resp, err = c.stable.Client().UsersById(user).Calendars().Get(ctx, options) + return err + }) + + return resp, err } // EnumerateContainers iterates through all of the users current @@ -147,7 +178,10 @@ func (c Events) EnumerateContainers( return err } - var errs *multierror.Error + var ( + resp models.CalendarCollectionResponseable + errs *multierror.Error + ) ofc, err := optionsForCalendars([]string{"name"}) if err != nil { @@ -157,7 +191,13 @@ func (c Events) EnumerateContainers( builder := service.Client().UsersById(userID).Calendars() for { - resp, err := builder.Get(ctx, ofc) + var err error + + err = graph.RunWithRetry(func() error { + resp, err = builder.Get(ctx, ofc) + return err + }) + if err != nil { return errors.Wrap(err, support.ConnectorStackErrorTrace(err)) } @@ -205,7 +245,16 @@ type eventPager struct { } func (p *eventPager) getPage(ctx context.Context) (api.DeltaPageLinker, error) { - resp, err := p.builder.Get(ctx, p.options) + var ( + resp api.DeltaPageLinker + err error + ) + + err = graph.RunWithRetry(func() error { + resp, err = p.builder.Get(ctx, p.options) + return err + }) + return resp, err } @@ -231,6 +280,11 @@ func (c Events) GetAddedAndRemovedItemIDs( errs *multierror.Error ) + ctx = clues.AddAll( + ctx, + "category", selectors.ExchangeEvent, + "calendar_id", calendarID) + if len(oldDelta) > 0 { builder := users.NewItemCalendarsItemEventsDeltaRequestBuilder(oldDelta, service.Adapter()) pgr := &eventPager{service, builder, nil} diff --git a/src/internal/connector/exchange/api/mail.go b/src/internal/connector/exchange/api/mail.go index bbac48a66..01a485fbb 100644 --- a/src/internal/connector/exchange/api/mail.go +++ b/src/internal/connector/exchange/api/mail.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + "github.com/alcionai/clues" "github.com/hashicorp/go-multierror" "github.com/microsoft/kiota-abstractions-go/serialization" kioser "github.com/microsoft/kiota-serialization-json-go" @@ -17,6 +18,7 @@ import ( "github.com/alcionai/corso/src/internal/connector/support" "github.com/alcionai/corso/src/pkg/backup/details" "github.com/alcionai/corso/src/pkg/logger" + "github.com/alcionai/corso/src/pkg/selectors" ) // --------------------------------------------------------------------------- @@ -95,7 +97,14 @@ func (c Mail) GetContainerByID( return nil, errors.Wrap(err, "options for mail folder") } - return service.Client().UsersById(userID).MailFoldersById(dirID).Get(ctx, ofmf) + var resp graph.Container + + err = graph.RunWithRetry(func() error { + resp, err = service.Client().UsersById(userID).MailFoldersById(dirID).Get(ctx, ofmf) + return err + }) + + return resp, err } // GetItem retrieves a Messageable item. If the item contains an attachment, that @@ -104,7 +113,16 @@ func (c Mail) GetItem( ctx context.Context, user, itemID string, ) (serialization.Parsable, *details.ExchangeInfo, error) { - mail, err := c.stable.Client().UsersById(user).MessagesById(itemID).Get(ctx, nil) + var ( + mail models.Messageable + err error + ) + + err = graph.RunWithRetry(func() error { + mail, err = c.stable.Client().UsersById(user).MessagesById(itemID).Get(ctx, nil) + return err + }) + if err != nil { return nil, nil, err } @@ -112,13 +130,18 @@ func (c Mail) GetItem( var errs *multierror.Error if *mail.GetHasAttachments() || HasAttachments(mail.GetBody()) { + options := &users.ItemMessagesItemAttachmentsRequestBuilderGetRequestConfiguration{ + QueryParameters: &users.ItemMessagesItemAttachmentsRequestBuilderGetQueryParameters{ + Expand: []string{"microsoft.graph.itemattachment/item"}, + }, + } for count := 0; count < numberOfRetries; count++ { attached, err := c.largeItem. Client(). UsersById(user). MessagesById(itemID). Attachments(). - Get(ctx, nil) + Get(ctx, options) if err == nil { mail.SetAttachments(attached.GetValue()) break @@ -154,6 +177,7 @@ func (c Mail) EnumerateContainers( } var ( + resp users.ItemMailFoldersDeltaResponseable errs *multierror.Error builder = service.Client(). UsersById(userID). @@ -162,7 +186,13 @@ func (c Mail) EnumerateContainers( ) for { - resp, err := builder.Get(ctx, nil) + var err error + + err = graph.RunWithRetry(func() error { + resp, err = builder.Get(ctx, nil) + return err + }) + if err != nil { return errors.Wrap(err, support.ConnectorStackErrorTrace(err)) } @@ -200,7 +230,17 @@ type mailPager struct { } func (p *mailPager) getPage(ctx context.Context) (api.DeltaPageLinker, error) { - return p.builder.Get(ctx, p.options) + var ( + page api.DeltaPageLinker + err error + ) + + err = graph.RunWithRetry(func() error { + page, err = p.builder.Get(ctx, p.options) + return err + }) + + return page, err } func (p *mailPager) setNext(nextLink string) { @@ -226,6 +266,11 @@ func (c Mail) GetAddedAndRemovedItemIDs( resetDelta bool ) + ctx = clues.AddAll( + ctx, + "category", selectors.ExchangeMail, + "folder_id", directoryID) + options, err := optionsForFolderMessagesDelta([]string{"isRead"}) if err != nil { return nil, nil, DeltaUpdate{}, errors.Wrap(err, "getting query options") diff --git a/src/internal/connector/exchange/api/options.go b/src/internal/connector/exchange/api/options.go index 49debf334..67725225f 100644 --- a/src/internal/connector/exchange/api/options.go +++ b/src/internal/connector/exchange/api/options.go @@ -3,6 +3,7 @@ package api import ( "fmt" + abstractions "github.com/microsoft/kiota-abstractions-go" "github.com/microsoftgraph/msgraph-sdk-go/users" ) @@ -53,6 +54,16 @@ var ( } ) +const ( + // headerKeyPrefer is used to set query preferences + headerKeyPrefer = "Prefer" + // maxPageSizeHeaderFmt is used to indicate max page size + // preferences + maxPageSizeHeaderFmt = "odata.maxpagesize=%d" + // deltaMaxPageSize is the max page size to use for delta queries + deltaMaxPageSize = 200 +) + // ----------------------------------------------------------------------- // exchange.Query Option Section // These functions can be used to filter a response on M365 @@ -71,8 +82,10 @@ func optionsForFolderMessagesDelta( requestParameters := &users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetQueryParameters{ Select: selecting, } + options := &users.ItemMailFoldersItemMessagesDeltaRequestBuilderGetRequestConfiguration{ QueryParameters: requestParameters, + Headers: buildDeltaRequestHeaders(), } return options, nil @@ -218,6 +231,7 @@ func optionsForContactFoldersItemDelta( options := &users.ItemContactFoldersItemContactsDeltaRequestBuilderGetRequestConfiguration{ QueryParameters: requestParameters, + Headers: buildDeltaRequestHeaders(), } return options, nil @@ -275,3 +289,11 @@ func buildOptions(fields []string, allowed map[string]struct{}) ([]string, error return append(returnedOptions, fields...), nil } + +// buildDeltaRequestHeaders returns the headers we add to delta page requests +func buildDeltaRequestHeaders() *abstractions.RequestHeaders { + headers := abstractions.NewRequestHeaders() + headers.Add(headerKeyPrefer, fmt.Sprintf(maxPageSizeHeaderFmt, deltaMaxPageSize)) + + return headers +} diff --git a/src/internal/connector/exchange/api/shared.go b/src/internal/connector/exchange/api/shared.go index d89ce7411..e4d563e90 100644 --- a/src/internal/connector/exchange/api/shared.go +++ b/src/internal/connector/exchange/api/shared.go @@ -8,6 +8,7 @@ import ( "github.com/alcionai/corso/src/internal/connector/graph" "github.com/alcionai/corso/src/internal/connector/graph/api" "github.com/alcionai/corso/src/internal/connector/support" + "github.com/alcionai/corso/src/pkg/logger" ) // --------------------------------------------------------------------------- @@ -64,6 +65,9 @@ func getItemsAddedAndRemovedFromContainer( deltaURL string ) + itemCount := 0 + page := 0 + for { // get the next page of data, check for standard errors resp, err := pager.getPage(ctx) @@ -82,6 +86,14 @@ func getItemsAddedAndRemovedFromContainer( return nil, nil, "", err } + itemCount += len(items) + page++ + + // Log every ~1000 items (the page size we use is 200) + if page%5 == 0 { + logger.Ctx(ctx).Infow("queried items", "count", itemCount) + } + // iterate through the items in the page for _, item := range items { // if the additional data conains a `@removed` key, the value will either @@ -114,5 +126,7 @@ func getItemsAddedAndRemovedFromContainer( pager.setNext(nextLink) } + logger.Ctx(ctx).Infow("completed enumeration", "count", itemCount) + return addedIDs, removedIDs, deltaURL, nil } diff --git a/src/internal/connector/exchange/attachment.go b/src/internal/connector/exchange/attachment.go index 5cbce271c..94e6dbc6a 100644 --- a/src/internal/connector/exchange/attachment.go +++ b/src/internal/connector/exchange/attachment.go @@ -8,6 +8,7 @@ import ( "github.com/microsoftgraph/msgraph-sdk-go/models" "github.com/pkg/errors" + "github.com/alcionai/corso/src/internal/connector/support" "github.com/alcionai/corso/src/internal/connector/uploadsession" "github.com/alcionai/corso/src/pkg/logger" ) @@ -44,8 +45,11 @@ func uploadAttachment( attachment models.Attachmentable, ) error { logger.Ctx(ctx).Debugf("uploading attachment with size %d", *attachment.GetSize()) - attachmentType := attachmentType(attachment) + var ( + attachmentType = attachmentType(attachment) + err error + ) // Reference attachments that are inline() do not need to be recreated. The contents are part of the body. if attachmentType == models.REFERENCE_ATTACHMENTTYPE && attachment.GetIsInline() != nil && *attachment.GetIsInline() { @@ -53,6 +57,30 @@ func uploadAttachment( return nil } + // item Attachments to be skipped until the completion of Issue #2353 + if attachmentType == models.ITEM_ATTACHMENTTYPE { + prev := attachment + + attachment, err = support.ToItemAttachment(attachment) + if err != nil { + name := "" + if prev.GetName() != nil { + name = *prev.GetName() + } + + // TODO: Update to support PII protection + logger.Ctx(ctx).Infow("item attachment uploads are not supported ", + "err", err, + "attachment_name", name, + "attachment_type", attachmentType, + "internal_item_type", getItemAttachmentItemType(prev), + "attachment_id", *prev.GetId(), + ) + + return nil + } + } + // For Item/Reference attachments *or* file attachments < 3MB, use the attachments endpoint if attachmentType != models.FILE_ATTACHMENTTYPE || *attachment.GetSize() < largeAttachmentSize { err := uploader.uploadSmallAttachment(ctx, attachment) @@ -90,3 +118,19 @@ func uploadLargeAttachment(ctx context.Context, uploader attachmentUploadable, return nil } + +func getItemAttachmentItemType(query models.Attachmentable) string { + empty := "" + attachment, ok := query.(models.ItemAttachmentable) + + if !ok { + return empty + } + + item := attachment.GetItem() + if item.GetOdataType() == nil { + return empty + } + + return *item.GetOdataType() +} diff --git a/src/internal/connector/exchange/container_resolver_test.go b/src/internal/connector/exchange/container_resolver_test.go index d7c6651f1..be0704f46 100644 --- a/src/internal/connector/exchange/container_resolver_test.go +++ b/src/internal/connector/exchange/container_resolver_test.go @@ -501,10 +501,11 @@ func (suite *FolderCacheIntegrationSuite) TestCreateContainerDestination() { directoryCaches = make(map[path.CategoryType]graph.ContainerResolver) folderName = tester.DefaultTestRestoreDestination().ContainerName tests = []struct { - name string - pathFunc1 func(t *testing.T) path.Path - pathFunc2 func(t *testing.T) path.Path - category path.CategoryType + name string + pathFunc1 func(t *testing.T) path.Path + pathFunc2 func(t *testing.T) path.Path + category path.CategoryType + folderPrefix string }{ { name: "Mail Cache Test", @@ -587,6 +588,7 @@ func (suite *FolderCacheIntegrationSuite) TestCreateContainerDestination() { require.NoError(t, err) return aPath }, + folderPrefix: calendarOthersFolder, }, } ) @@ -617,8 +619,9 @@ func (suite *FolderCacheIntegrationSuite) TestCreateContainerDestination() { _, err = resolver.IDToPath(ctx, secondID) require.NoError(t, err) - _, ok := resolver.PathInCache(folderName) - require.True(t, ok) + p := stdpath.Join(test.folderPrefix, folderName) + _, ok := resolver.PathInCache(p) + require.True(t, ok, "looking for path in cache: %s", p) }) } } diff --git a/src/internal/connector/exchange/data_collections_test.go b/src/internal/connector/exchange/data_collections_test.go index 70f413239..07eef5e7a 100644 --- a/src/internal/connector/exchange/data_collections_test.go +++ b/src/internal/connector/exchange/data_collections_test.go @@ -537,9 +537,9 @@ func (suite *DataCollectionsIntegrationSuite) TestEventsSerializationRegression( }, { name: "Birthday Calendar", - expected: "Birthdays", + expected: calendarOthersFolder + "/Birthdays", scope: selectors.NewExchangeBackup(users).EventCalendars( - []string{"Birthdays"}, + []string{calendarOthersFolder + "/Birthdays"}, selectors.PrefixMatch(), )[0], }, diff --git a/src/internal/connector/exchange/event_calendar_cache.go b/src/internal/connector/exchange/event_calendar_cache.go index e497a272a..0377433ee 100644 --- a/src/internal/connector/exchange/event_calendar_cache.go +++ b/src/internal/connector/exchange/event_calendar_cache.go @@ -64,7 +64,15 @@ func (ecc *eventCalendarCache) Populate( return errors.Wrap(err, "initializing") } - err := ecc.enumer.EnumerateContainers(ctx, ecc.userID, "", ecc.addFolder) + err := ecc.enumer.EnumerateContainers( + ctx, + ecc.userID, + "", + func(cf graph.CacheFolder) error { + cf.SetPath(path.Builder{}.Append(calendarOthersFolder, *cf.GetDisplayName())) + return ecc.addFolder(cf) + }, + ) if err != nil { return errors.Wrap(err, "enumerating containers") } @@ -83,7 +91,7 @@ func (ecc *eventCalendarCache) AddToCache(ctx context.Context, f graph.Container return errors.Wrap(err, "validating container") } - temp := graph.NewCacheFolder(f, path.Builder{}.Append(*f.GetDisplayName())) + temp := graph.NewCacheFolder(f, path.Builder{}.Append(calendarOthersFolder, *f.GetDisplayName())) if err := ecc.addFolder(temp); err != nil { return errors.Wrap(err, "adding container") diff --git a/src/internal/connector/exchange/exchange_vars.go b/src/internal/connector/exchange/exchange_vars.go index e45de0bf0..988d20330 100644 --- a/src/internal/connector/exchange/exchange_vars.go +++ b/src/internal/connector/exchange/exchange_vars.go @@ -38,4 +38,5 @@ const ( rootFolderAlias = "msgfolderroot" DefaultContactFolder = "Contacts" DefaultCalendar = "Calendar" + calendarOthersFolder = "Other Calendars" ) diff --git a/src/internal/connector/exchange/restore_test.go b/src/internal/connector/exchange/restore_test.go index 9c32fd530..360d15266 100644 --- a/src/internal/connector/exchange/restore_test.go +++ b/src/internal/connector/exchange/restore_test.go @@ -175,6 +175,30 @@ func (suite *ExchangeRestoreSuite) TestRestoreExchangeObject() { return *folder.GetId() }, }, + { + name: "Test Mail: Item Attachment_Event", + bytes: mockconnector.GetMockMessageWithItemAttachmentEvent("Event Item Attachment"), + category: path.EmailCategory, + destination: func(t *testing.T, ctx context.Context) string { + folderName := "TestRestoreEventItemAttachment: " + common.FormatSimpleDateTime(now) + folder, err := suite.ac.Mail().CreateMailFolder(ctx, userID, folderName) + require.NoError(t, err) + + return *folder.GetId() + }, + }, + { // Restore will upload the Message without uploading the attachment + name: "Test Mail: Item Attachment_NestedEvent", + bytes: mockconnector.GetMockMessageWithNestedItemAttachmentEvent("Nested Item Attachment"), + category: path.EmailCategory, + destination: func(t *testing.T, ctx context.Context) string { + folderName := "TestRestoreNestedEventItemAttachment: " + common.FormatSimpleDateTime(now) + folder, err := suite.ac.Mail().CreateMailFolder(ctx, userID, folderName) + require.NoError(t, err) + + return *folder.GetId() + }, + }, { name: "Test Mail: One Large Attachment", bytes: mockconnector.GetMockMessageWithLargeAttachment("Restore Large Attachment"), @@ -266,7 +290,7 @@ func (suite *ExchangeRestoreSuite) TestRestoreExchangeObject() { userID, ) assert.NoError(t, err, support.ConnectorStackErrorTrace(err)) - assert.NotNil(t, info, "item info is populated") + assert.NotNil(t, info, "item info was not populated") assert.NoError(t, deleters[test.category].DeleteContainer(ctx, userID, destination)) }) } diff --git a/src/internal/connector/exchange/service_restore.go b/src/internal/connector/exchange/service_restore.go index e1144249a..e6fa592f7 100644 --- a/src/internal/connector/exchange/service_restore.go +++ b/src/internal/connector/exchange/service_restore.go @@ -189,23 +189,32 @@ func RestoreMailMessage( // 1st: No transmission // 2nd: Send Date // 3rd: Recv Date + svlep := make([]models.SingleValueLegacyExtendedPropertyable, 0) sv1 := models.NewSingleValueLegacyExtendedProperty() sv1.SetId(&valueID) sv1.SetValue(&enableValue) + svlep = append(svlep, sv1) - sv2 := models.NewSingleValueLegacyExtendedProperty() - sendPropertyValue := common.FormatLegacyTime(*clone.GetSentDateTime()) - sendPropertyTag := MailSendDateTimeOverrideProperty - sv2.SetId(&sendPropertyTag) - sv2.SetValue(&sendPropertyValue) + if clone.GetSentDateTime() != nil { + sv2 := models.NewSingleValueLegacyExtendedProperty() + sendPropertyValue := common.FormatLegacyTime(*clone.GetSentDateTime()) + sendPropertyTag := MailSendDateTimeOverrideProperty + sv2.SetId(&sendPropertyTag) + sv2.SetValue(&sendPropertyValue) - sv3 := models.NewSingleValueLegacyExtendedProperty() - recvPropertyValue := common.FormatLegacyTime(*clone.GetReceivedDateTime()) - recvPropertyTag := MailReceiveDateTimeOverriveProperty - sv3.SetId(&recvPropertyTag) - sv3.SetValue(&recvPropertyValue) + svlep = append(svlep, sv2) + } + + if clone.GetReceivedDateTime() != nil { + sv3 := models.NewSingleValueLegacyExtendedProperty() + recvPropertyValue := common.FormatLegacyTime(*clone.GetReceivedDateTime()) + recvPropertyTag := MailReceiveDateTimeOverriveProperty + sv3.SetId(&recvPropertyTag) + sv3.SetValue(&recvPropertyValue) + + svlep = append(svlep, sv3) + } - svlep := []models.SingleValueLegacyExtendedPropertyable{sv1, sv2, sv3} clone.SetSingleValueExtendedProperties(svlep) // Switch workflow based on collision policy @@ -248,10 +257,9 @@ func SendMailToBackStore( errs error ) - if *message.GetHasAttachments() { - attached = message.GetAttachments() - message.SetAttachments([]models.Attachmentable{}) - } + // Item.Attachments --> HasAttachments doesn't always have a value populated when deserialized + attached = message.GetAttachments() + message.SetAttachments([]models.Attachmentable{}) sentMessage, err := service.Client().UsersById(user).MailFoldersById(destination).Messages().Post(ctx, message, nil) if err != nil { @@ -637,7 +645,11 @@ func establishEventsRestoreLocation( user string, isNewCache bool, ) (string, error) { - cached, ok := ecc.PathInCache(folders[0]) + // Need to prefix with the "Other Calendars" folder so lookup happens properly. + cached, ok := ecc.PathInCache(path.Builder{}.Append( + calendarOthersFolder, + folders[0], + ).String()) if ok { return cached, nil } diff --git a/src/internal/connector/graph/betasdk/beta_client.go b/src/internal/connector/graph/betasdk/beta_client.go index f33b110d6..795c85e2a 100644 --- a/src/internal/connector/graph/betasdk/beta_client.go +++ b/src/internal/connector/graph/betasdk/beta_client.go @@ -1,13 +1,14 @@ package betasdk import ( - i1a3c1a5501c5e41b7fd169f2d4c768dce9b096ac28fb5431bf02afcc57295411 "github.com/alcionai/corso/src/internal/connector/graph/betasdk/sites" absser "github.com/microsoft/kiota-abstractions-go" kioser "github.com/microsoft/kiota-abstractions-go/serialization" kform "github.com/microsoft/kiota-serialization-form-go" kw "github.com/microsoft/kiota-serialization-json-go" ktext "github.com/microsoft/kiota-serialization-text-go" msgraphsdk "github.com/microsoftgraph/msgraph-sdk-go" + + i1a3c1a5501c5e41b7fd169f2d4c768dce9b096ac28fb5431bf02afcc57295411 "github.com/alcionai/corso/src/internal/connector/graph/betasdk/sites" ) // BetaClient the main entry point of the SDK, exposes the configuration and the fluent API. diff --git a/src/internal/connector/graph/betasdk/models/horizontal_section_layout_type.go b/src/internal/connector/graph/betasdk/models/horizontal_section_layout_type.go index 43c2643a2..80e208ffe 100644 --- a/src/internal/connector/graph/betasdk/models/horizontal_section_layout_type.go +++ b/src/internal/connector/graph/betasdk/models/horizontal_section_layout_type.go @@ -1,52 +1,54 @@ package models + import ( - "errors" + "errors" ) + // Provides operations to call the remove method. type HorizontalSectionLayoutType int const ( - NONE_HORIZONTALSECTIONLAYOUTTYPE HorizontalSectionLayoutType = iota - ONECOLUMN_HORIZONTALSECTIONLAYOUTTYPE - TWOCOLUMNS_HORIZONTALSECTIONLAYOUTTYPE - THREECOLUMNS_HORIZONTALSECTIONLAYOUTTYPE - ONETHIRDLEFTCOLUMN_HORIZONTALSECTIONLAYOUTTYPE - ONETHIRDRIGHTCOLUMN_HORIZONTALSECTIONLAYOUTTYPE - FULLWIDTH_HORIZONTALSECTIONLAYOUTTYPE - UNKNOWNFUTUREVALUE_HORIZONTALSECTIONLAYOUTTYPE + NONE_HORIZONTALSECTIONLAYOUTTYPE HorizontalSectionLayoutType = iota + ONECOLUMN_HORIZONTALSECTIONLAYOUTTYPE + TWOCOLUMNS_HORIZONTALSECTIONLAYOUTTYPE + THREECOLUMNS_HORIZONTALSECTIONLAYOUTTYPE + ONETHIRDLEFTCOLUMN_HORIZONTALSECTIONLAYOUTTYPE + ONETHIRDRIGHTCOLUMN_HORIZONTALSECTIONLAYOUTTYPE + FULLWIDTH_HORIZONTALSECTIONLAYOUTTYPE + UNKNOWNFUTUREVALUE_HORIZONTALSECTIONLAYOUTTYPE ) func (i HorizontalSectionLayoutType) String() string { - return []string{"none", "oneColumn", "twoColumns", "threeColumns", "oneThirdLeftColumn", "oneThirdRightColumn", "fullWidth", "unknownFutureValue"}[i] + return []string{"none", "oneColumn", "twoColumns", "threeColumns", "oneThirdLeftColumn", "oneThirdRightColumn", "fullWidth", "unknownFutureValue"}[i] } func ParseHorizontalSectionLayoutType(v string) (interface{}, error) { - result := NONE_HORIZONTALSECTIONLAYOUTTYPE - switch v { - case "none": - result = NONE_HORIZONTALSECTIONLAYOUTTYPE - case "oneColumn": - result = ONECOLUMN_HORIZONTALSECTIONLAYOUTTYPE - case "twoColumns": - result = TWOCOLUMNS_HORIZONTALSECTIONLAYOUTTYPE - case "threeColumns": - result = THREECOLUMNS_HORIZONTALSECTIONLAYOUTTYPE - case "oneThirdLeftColumn": - result = ONETHIRDLEFTCOLUMN_HORIZONTALSECTIONLAYOUTTYPE - case "oneThirdRightColumn": - result = ONETHIRDRIGHTCOLUMN_HORIZONTALSECTIONLAYOUTTYPE - case "fullWidth": - result = FULLWIDTH_HORIZONTALSECTIONLAYOUTTYPE - case "unknownFutureValue": - result = UNKNOWNFUTUREVALUE_HORIZONTALSECTIONLAYOUTTYPE - default: - return 0, errors.New("Unknown HorizontalSectionLayoutType value: " + v) - } - return &result, nil + result := NONE_HORIZONTALSECTIONLAYOUTTYPE + switch v { + case "none": + result = NONE_HORIZONTALSECTIONLAYOUTTYPE + case "oneColumn": + result = ONECOLUMN_HORIZONTALSECTIONLAYOUTTYPE + case "twoColumns": + result = TWOCOLUMNS_HORIZONTALSECTIONLAYOUTTYPE + case "threeColumns": + result = THREECOLUMNS_HORIZONTALSECTIONLAYOUTTYPE + case "oneThirdLeftColumn": + result = ONETHIRDLEFTCOLUMN_HORIZONTALSECTIONLAYOUTTYPE + case "oneThirdRightColumn": + result = ONETHIRDRIGHTCOLUMN_HORIZONTALSECTIONLAYOUTTYPE + case "fullWidth": + result = FULLWIDTH_HORIZONTALSECTIONLAYOUTTYPE + case "unknownFutureValue": + result = UNKNOWNFUTUREVALUE_HORIZONTALSECTIONLAYOUTTYPE + default: + return 0, errors.New("Unknown HorizontalSectionLayoutType value: " + v) + } + return &result, nil } func SerializeHorizontalSectionLayoutType(values []HorizontalSectionLayoutType) []string { - result := make([]string, len(values)) - for i, v := range values { - result[i] = v.String() - } - return result + result := make([]string, len(values)) + for i, v := range values { + result[i] = v.String() + } + return result } diff --git a/src/internal/connector/graph/betasdk/models/meta_data_key_string_pair.go b/src/internal/connector/graph/betasdk/models/meta_data_key_string_pair.go index e7df06165..c79f17cfb 100644 --- a/src/internal/connector/graph/betasdk/models/meta_data_key_string_pair.go +++ b/src/internal/connector/graph/betasdk/models/meta_data_key_string_pair.go @@ -1,123 +1,134 @@ package models import ( - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" ) -// MetaDataKeyStringPair +// MetaDataKeyStringPair type MetaDataKeyStringPair struct { - // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. - additionalData map[string]interface{} - // Key of the meta data. - key *string - // The OdataType property - odataType *string - // Value of the meta data. - value *string + // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + additionalData map[string]interface{} + // Key of the meta data. + key *string + // The OdataType property + odataType *string + // Value of the meta data. + value *string } + // NewMetaDataKeyStringPair instantiates a new metaDataKeyStringPair and sets the default values. -func NewMetaDataKeyStringPair()(*MetaDataKeyStringPair) { - m := &MetaDataKeyStringPair{ - } - m.SetAdditionalData(make(map[string]interface{})); - return m +func NewMetaDataKeyStringPair() *MetaDataKeyStringPair { + m := &MetaDataKeyStringPair{} + m.SetAdditionalData(make(map[string]interface{})) + return m } + // CreateMetaDataKeyStringPairFromDiscriminatorValue creates a new instance of the appropriate class based on discriminator value -func CreateMetaDataKeyStringPairFromDiscriminatorValue(parseNode i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable, error) { - return NewMetaDataKeyStringPair(), nil +func CreateMetaDataKeyStringPairFromDiscriminatorValue(parseNode i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) (i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable, error) { + return NewMetaDataKeyStringPair(), nil } + // GetAdditionalData gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *MetaDataKeyStringPair) GetAdditionalData()(map[string]interface{}) { - return m.additionalData +func (m *MetaDataKeyStringPair) GetAdditionalData() map[string]interface{} { + return m.additionalData } + // GetFieldDeserializers the deserialization information for the current model -func (m *MetaDataKeyStringPair) GetFieldDeserializers()(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(error)) { - res := make(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(error)) - res["key"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetKey(val) - } - return nil - } - res["@odata.type"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetOdataType(val) - } - return nil - } - res["value"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetValue(val) - } - return nil - } - return res +func (m *MetaDataKeyStringPair) GetFieldDeserializers() map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + res := make(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error) + res["key"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetKey(val) + } + return nil + } + res["@odata.type"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetOdataType(val) + } + return nil + } + res["value"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetValue(val) + } + return nil + } + return res } + // GetKey gets the key property value. Key of the meta data. -func (m *MetaDataKeyStringPair) GetKey()(*string) { - return m.key +func (m *MetaDataKeyStringPair) GetKey() *string { + return m.key } + // GetOdataType gets the @odata.type property value. The OdataType property -func (m *MetaDataKeyStringPair) GetOdataType()(*string) { - return m.odataType +func (m *MetaDataKeyStringPair) GetOdataType() *string { + return m.odataType } + // GetValue gets the value property value. Value of the meta data. -func (m *MetaDataKeyStringPair) GetValue()(*string) { - return m.value +func (m *MetaDataKeyStringPair) GetValue() *string { + return m.value } + // Serialize serializes information the current object -func (m *MetaDataKeyStringPair) Serialize(writer i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.SerializationWriter)(error) { - { - err := writer.WriteStringValue("key", m.GetKey()) - if err != nil { - return err - } - } - { - err := writer.WriteStringValue("@odata.type", m.GetOdataType()) - if err != nil { - return err - } - } - { - err := writer.WriteStringValue("value", m.GetValue()) - if err != nil { - return err - } - } - { - err := writer.WriteAdditionalData(m.GetAdditionalData()) - if err != nil { - return err - } - } - return nil +func (m *MetaDataKeyStringPair) Serialize(writer i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.SerializationWriter) error { + { + err := writer.WriteStringValue("key", m.GetKey()) + if err != nil { + return err + } + } + { + err := writer.WriteStringValue("@odata.type", m.GetOdataType()) + if err != nil { + return err + } + } + { + err := writer.WriteStringValue("value", m.GetValue()) + if err != nil { + return err + } + } + { + err := writer.WriteAdditionalData(m.GetAdditionalData()) + if err != nil { + return err + } + } + return nil } + // SetAdditionalData sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *MetaDataKeyStringPair) SetAdditionalData(value map[string]interface{})() { - m.additionalData = value +func (m *MetaDataKeyStringPair) SetAdditionalData(value map[string]interface{}) { + m.additionalData = value } + // SetKey sets the key property value. Key of the meta data. -func (m *MetaDataKeyStringPair) SetKey(value *string)() { - m.key = value +func (m *MetaDataKeyStringPair) SetKey(value *string) { + m.key = value } + // SetOdataType sets the @odata.type property value. The OdataType property -func (m *MetaDataKeyStringPair) SetOdataType(value *string)() { - m.odataType = value +func (m *MetaDataKeyStringPair) SetOdataType(value *string) { + m.odataType = value } + // SetValue sets the value property value. Value of the meta data. -func (m *MetaDataKeyStringPair) SetValue(value *string)() { - m.value = value +func (m *MetaDataKeyStringPair) SetValue(value *string) { + m.value = value } diff --git a/src/internal/connector/graph/betasdk/models/meta_data_key_string_pairable.go b/src/internal/connector/graph/betasdk/models/meta_data_key_string_pairable.go index 49908469e..4168f4dce 100644 --- a/src/internal/connector/graph/betasdk/models/meta_data_key_string_pairable.go +++ b/src/internal/connector/graph/betasdk/models/meta_data_key_string_pairable.go @@ -1,17 +1,17 @@ package models import ( - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" ) -// MetaDataKeyStringPairable +// MetaDataKeyStringPairable type MetaDataKeyStringPairable interface { - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.AdditionalDataHolder - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable - GetKey()(*string) - GetOdataType()(*string) - GetValue()(*string) - SetKey(value *string)() - SetOdataType(value *string)() - SetValue(value *string)() + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.AdditionalDataHolder + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable + GetKey() *string + GetOdataType() *string + GetValue() *string + SetKey(value *string) + SetOdataType(value *string) + SetValue(value *string) } diff --git a/src/internal/connector/graph/betasdk/models/page_layout_type.go b/src/internal/connector/graph/betasdk/models/page_layout_type.go index 0338a5c30..fce795760 100644 --- a/src/internal/connector/graph/betasdk/models/page_layout_type.go +++ b/src/internal/connector/graph/betasdk/models/page_layout_type.go @@ -1,40 +1,42 @@ package models + import ( - "errors" + "errors" ) + // Provides operations to call the remove method. type PageLayoutType int const ( - MICROSOFTRESERVED_PAGELAYOUTTYPE PageLayoutType = iota - ARTICLE_PAGELAYOUTTYPE - HOME_PAGELAYOUTTYPE - UNKNOWNFUTUREVALUE_PAGELAYOUTTYPE + MICROSOFTRESERVED_PAGELAYOUTTYPE PageLayoutType = iota + ARTICLE_PAGELAYOUTTYPE + HOME_PAGELAYOUTTYPE + UNKNOWNFUTUREVALUE_PAGELAYOUTTYPE ) func (i PageLayoutType) String() string { - return []string{"microsoftReserved", "article", "home", "unknownFutureValue"}[i] + return []string{"microsoftReserved", "article", "home", "unknownFutureValue"}[i] } func ParsePageLayoutType(v string) (interface{}, error) { - result := MICROSOFTRESERVED_PAGELAYOUTTYPE - switch v { - case "microsoftReserved": - result = MICROSOFTRESERVED_PAGELAYOUTTYPE - case "article": - result = ARTICLE_PAGELAYOUTTYPE - case "home": - result = HOME_PAGELAYOUTTYPE - case "unknownFutureValue": - result = UNKNOWNFUTUREVALUE_PAGELAYOUTTYPE - default: - return 0, errors.New("Unknown PageLayoutType value: " + v) - } - return &result, nil + result := MICROSOFTRESERVED_PAGELAYOUTTYPE + switch v { + case "microsoftReserved": + result = MICROSOFTRESERVED_PAGELAYOUTTYPE + case "article": + result = ARTICLE_PAGELAYOUTTYPE + case "home": + result = HOME_PAGELAYOUTTYPE + case "unknownFutureValue": + result = UNKNOWNFUTUREVALUE_PAGELAYOUTTYPE + default: + return 0, errors.New("Unknown PageLayoutType value: " + v) + } + return &result, nil } func SerializePageLayoutType(values []PageLayoutType) []string { - result := make([]string, len(values)) - for i, v := range values { - result[i] = v.String() - } - return result + result := make([]string, len(values)) + for i, v := range values { + result[i] = v.String() + } + return result } diff --git a/src/internal/connector/graph/betasdk/models/page_promotion_type.go b/src/internal/connector/graph/betasdk/models/page_promotion_type.go index a8cbcd058..e78ce63f0 100644 --- a/src/internal/connector/graph/betasdk/models/page_promotion_type.go +++ b/src/internal/connector/graph/betasdk/models/page_promotion_type.go @@ -1,40 +1,42 @@ package models + import ( - "errors" + "errors" ) + // Provides operations to call the remove method. type PagePromotionType int const ( - MICROSOFTRESERVED_PAGEPROMOTIONTYPE PagePromotionType = iota - PAGE_PAGEPROMOTIONTYPE - NEWSPOST_PAGEPROMOTIONTYPE - UNKNOWNFUTUREVALUE_PAGEPROMOTIONTYPE + MICROSOFTRESERVED_PAGEPROMOTIONTYPE PagePromotionType = iota + PAGE_PAGEPROMOTIONTYPE + NEWSPOST_PAGEPROMOTIONTYPE + UNKNOWNFUTUREVALUE_PAGEPROMOTIONTYPE ) func (i PagePromotionType) String() string { - return []string{"microsoftReserved", "page", "newsPost", "unknownFutureValue"}[i] + return []string{"microsoftReserved", "page", "newsPost", "unknownFutureValue"}[i] } func ParsePagePromotionType(v string) (interface{}, error) { - result := MICROSOFTRESERVED_PAGEPROMOTIONTYPE - switch v { - case "microsoftReserved": - result = MICROSOFTRESERVED_PAGEPROMOTIONTYPE - case "page": - result = PAGE_PAGEPROMOTIONTYPE - case "newsPost": - result = NEWSPOST_PAGEPROMOTIONTYPE - case "unknownFutureValue": - result = UNKNOWNFUTUREVALUE_PAGEPROMOTIONTYPE - default: - return 0, errors.New("Unknown PagePromotionType value: " + v) - } - return &result, nil + result := MICROSOFTRESERVED_PAGEPROMOTIONTYPE + switch v { + case "microsoftReserved": + result = MICROSOFTRESERVED_PAGEPROMOTIONTYPE + case "page": + result = PAGE_PAGEPROMOTIONTYPE + case "newsPost": + result = NEWSPOST_PAGEPROMOTIONTYPE + case "unknownFutureValue": + result = UNKNOWNFUTUREVALUE_PAGEPROMOTIONTYPE + default: + return 0, errors.New("Unknown PagePromotionType value: " + v) + } + return &result, nil } func SerializePagePromotionType(values []PagePromotionType) []string { - result := make([]string, len(values)) - for i, v := range values { - result[i] = v.String() - } - return result + result := make([]string, len(values)) + for i, v := range values { + result[i] = v.String() + } + return result } diff --git a/src/internal/connector/graph/betasdk/models/publication_facet.go b/src/internal/connector/graph/betasdk/models/publication_facet.go index 87e59d34b..860b88bf3 100644 --- a/src/internal/connector/graph/betasdk/models/publication_facet.go +++ b/src/internal/connector/graph/betasdk/models/publication_facet.go @@ -1,123 +1,134 @@ package models import ( - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" ) -// PublicationFacet +// PublicationFacet type PublicationFacet struct { - // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. - additionalData map[string]interface{} - // The state of publication for this document. Either published or checkout. Read-only. - level *string - // The OdataType property - odataType *string - // The unique identifier for the version that is visible to the current caller. Read-only. - versionId *string + // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + additionalData map[string]interface{} + // The state of publication for this document. Either published or checkout. Read-only. + level *string + // The OdataType property + odataType *string + // The unique identifier for the version that is visible to the current caller. Read-only. + versionId *string } + // NewPublicationFacet instantiates a new publicationFacet and sets the default values. -func NewPublicationFacet()(*PublicationFacet) { - m := &PublicationFacet{ - } - m.SetAdditionalData(make(map[string]interface{})); - return m +func NewPublicationFacet() *PublicationFacet { + m := &PublicationFacet{} + m.SetAdditionalData(make(map[string]interface{})) + return m } + // CreatePublicationFacetFromDiscriminatorValue creates a new instance of the appropriate class based on discriminator value -func CreatePublicationFacetFromDiscriminatorValue(parseNode i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable, error) { - return NewPublicationFacet(), nil +func CreatePublicationFacetFromDiscriminatorValue(parseNode i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) (i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable, error) { + return NewPublicationFacet(), nil } + // GetAdditionalData gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *PublicationFacet) GetAdditionalData()(map[string]interface{}) { - return m.additionalData +func (m *PublicationFacet) GetAdditionalData() map[string]interface{} { + return m.additionalData } + // GetFieldDeserializers the deserialization information for the current model -func (m *PublicationFacet) GetFieldDeserializers()(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(error)) { - res := make(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(error)) - res["level"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetLevel(val) - } - return nil - } - res["@odata.type"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetOdataType(val) - } - return nil - } - res["versionId"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetVersionId(val) - } - return nil - } - return res +func (m *PublicationFacet) GetFieldDeserializers() map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + res := make(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error) + res["level"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetLevel(val) + } + return nil + } + res["@odata.type"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetOdataType(val) + } + return nil + } + res["versionId"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetVersionId(val) + } + return nil + } + return res } + // GetLevel gets the level property value. The state of publication for this document. Either published or checkout. Read-only. -func (m *PublicationFacet) GetLevel()(*string) { - return m.level +func (m *PublicationFacet) GetLevel() *string { + return m.level } + // GetOdataType gets the @odata.type property value. The OdataType property -func (m *PublicationFacet) GetOdataType()(*string) { - return m.odataType +func (m *PublicationFacet) GetOdataType() *string { + return m.odataType } + // GetVersionId gets the versionId property value. The unique identifier for the version that is visible to the current caller. Read-only. -func (m *PublicationFacet) GetVersionId()(*string) { - return m.versionId +func (m *PublicationFacet) GetVersionId() *string { + return m.versionId } + // Serialize serializes information the current object -func (m *PublicationFacet) Serialize(writer i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.SerializationWriter)(error) { - { - err := writer.WriteStringValue("level", m.GetLevel()) - if err != nil { - return err - } - } - { - err := writer.WriteStringValue("@odata.type", m.GetOdataType()) - if err != nil { - return err - } - } - { - err := writer.WriteStringValue("versionId", m.GetVersionId()) - if err != nil { - return err - } - } - { - err := writer.WriteAdditionalData(m.GetAdditionalData()) - if err != nil { - return err - } - } - return nil +func (m *PublicationFacet) Serialize(writer i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.SerializationWriter) error { + { + err := writer.WriteStringValue("level", m.GetLevel()) + if err != nil { + return err + } + } + { + err := writer.WriteStringValue("@odata.type", m.GetOdataType()) + if err != nil { + return err + } + } + { + err := writer.WriteStringValue("versionId", m.GetVersionId()) + if err != nil { + return err + } + } + { + err := writer.WriteAdditionalData(m.GetAdditionalData()) + if err != nil { + return err + } + } + return nil } + // SetAdditionalData sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *PublicationFacet) SetAdditionalData(value map[string]interface{})() { - m.additionalData = value +func (m *PublicationFacet) SetAdditionalData(value map[string]interface{}) { + m.additionalData = value } + // SetLevel sets the level property value. The state of publication for this document. Either published or checkout. Read-only. -func (m *PublicationFacet) SetLevel(value *string)() { - m.level = value +func (m *PublicationFacet) SetLevel(value *string) { + m.level = value } + // SetOdataType sets the @odata.type property value. The OdataType property -func (m *PublicationFacet) SetOdataType(value *string)() { - m.odataType = value +func (m *PublicationFacet) SetOdataType(value *string) { + m.odataType = value } + // SetVersionId sets the versionId property value. The unique identifier for the version that is visible to the current caller. Read-only. -func (m *PublicationFacet) SetVersionId(value *string)() { - m.versionId = value +func (m *PublicationFacet) SetVersionId(value *string) { + m.versionId = value } diff --git a/src/internal/connector/graph/betasdk/models/publication_facetable.go b/src/internal/connector/graph/betasdk/models/publication_facetable.go index 20d82ccf8..4098c89b1 100644 --- a/src/internal/connector/graph/betasdk/models/publication_facetable.go +++ b/src/internal/connector/graph/betasdk/models/publication_facetable.go @@ -1,17 +1,17 @@ package models import ( - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" ) -// PublicationFacetable +// PublicationFacetable type PublicationFacetable interface { - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.AdditionalDataHolder - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable - GetLevel()(*string) - GetOdataType()(*string) - GetVersionId()(*string) - SetLevel(value *string)() - SetOdataType(value *string)() - SetVersionId(value *string)() + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.AdditionalDataHolder + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable + GetLevel() *string + GetOdataType() *string + GetVersionId() *string + SetLevel(value *string) + SetOdataType(value *string) + SetVersionId(value *string) } diff --git a/src/internal/connector/graph/betasdk/models/reactions_facet.go b/src/internal/connector/graph/betasdk/models/reactions_facet.go index b298a9fe1..c971925dc 100644 --- a/src/internal/connector/graph/betasdk/models/reactions_facet.go +++ b/src/internal/connector/graph/betasdk/models/reactions_facet.go @@ -1,149 +1,162 @@ package models import ( - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" ) -// ReactionsFacet +// ReactionsFacet type ReactionsFacet struct { - // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. - additionalData map[string]interface{} - // Count of comments. - commentCount *int32 - // Count of likes. - likeCount *int32 - // The OdataType property - odataType *string - // Count of shares. - shareCount *int32 + // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + additionalData map[string]interface{} + // Count of comments. + commentCount *int32 + // Count of likes. + likeCount *int32 + // The OdataType property + odataType *string + // Count of shares. + shareCount *int32 } + // NewReactionsFacet instantiates a new reactionsFacet and sets the default values. -func NewReactionsFacet()(*ReactionsFacet) { - m := &ReactionsFacet{ - } - m.SetAdditionalData(make(map[string]interface{})); - return m +func NewReactionsFacet() *ReactionsFacet { + m := &ReactionsFacet{} + m.SetAdditionalData(make(map[string]interface{})) + return m } + // CreateReactionsFacetFromDiscriminatorValue creates a new instance of the appropriate class based on discriminator value -func CreateReactionsFacetFromDiscriminatorValue(parseNode i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable, error) { - return NewReactionsFacet(), nil +func CreateReactionsFacetFromDiscriminatorValue(parseNode i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) (i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable, error) { + return NewReactionsFacet(), nil } + // GetAdditionalData gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *ReactionsFacet) GetAdditionalData()(map[string]interface{}) { - return m.additionalData +func (m *ReactionsFacet) GetAdditionalData() map[string]interface{} { + return m.additionalData } + // GetCommentCount gets the commentCount property value. Count of comments. -func (m *ReactionsFacet) GetCommentCount()(*int32) { - return m.commentCount +func (m *ReactionsFacet) GetCommentCount() *int32 { + return m.commentCount } + // GetFieldDeserializers the deserialization information for the current model -func (m *ReactionsFacet) GetFieldDeserializers()(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(error)) { - res := make(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(error)) - res["commentCount"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetInt32Value() - if err != nil { - return err - } - if val != nil { - m.SetCommentCount(val) - } - return nil - } - res["likeCount"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetInt32Value() - if err != nil { - return err - } - if val != nil { - m.SetLikeCount(val) - } - return nil - } - res["@odata.type"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetOdataType(val) - } - return nil - } - res["shareCount"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetInt32Value() - if err != nil { - return err - } - if val != nil { - m.SetShareCount(val) - } - return nil - } - return res +func (m *ReactionsFacet) GetFieldDeserializers() map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + res := make(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error) + res["commentCount"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetInt32Value() + if err != nil { + return err + } + if val != nil { + m.SetCommentCount(val) + } + return nil + } + res["likeCount"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetInt32Value() + if err != nil { + return err + } + if val != nil { + m.SetLikeCount(val) + } + return nil + } + res["@odata.type"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetOdataType(val) + } + return nil + } + res["shareCount"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetInt32Value() + if err != nil { + return err + } + if val != nil { + m.SetShareCount(val) + } + return nil + } + return res } + // GetLikeCount gets the likeCount property value. Count of likes. -func (m *ReactionsFacet) GetLikeCount()(*int32) { - return m.likeCount +func (m *ReactionsFacet) GetLikeCount() *int32 { + return m.likeCount } + // GetOdataType gets the @odata.type property value. The OdataType property -func (m *ReactionsFacet) GetOdataType()(*string) { - return m.odataType +func (m *ReactionsFacet) GetOdataType() *string { + return m.odataType } + // GetShareCount gets the shareCount property value. Count of shares. -func (m *ReactionsFacet) GetShareCount()(*int32) { - return m.shareCount +func (m *ReactionsFacet) GetShareCount() *int32 { + return m.shareCount } + // Serialize serializes information the current object -func (m *ReactionsFacet) Serialize(writer i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.SerializationWriter)(error) { - { - err := writer.WriteInt32Value("commentCount", m.GetCommentCount()) - if err != nil { - return err - } - } - { - err := writer.WriteInt32Value("likeCount", m.GetLikeCount()) - if err != nil { - return err - } - } - { - err := writer.WriteStringValue("@odata.type", m.GetOdataType()) - if err != nil { - return err - } - } - { - err := writer.WriteInt32Value("shareCount", m.GetShareCount()) - if err != nil { - return err - } - } - { - err := writer.WriteAdditionalData(m.GetAdditionalData()) - if err != nil { - return err - } - } - return nil +func (m *ReactionsFacet) Serialize(writer i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.SerializationWriter) error { + { + err := writer.WriteInt32Value("commentCount", m.GetCommentCount()) + if err != nil { + return err + } + } + { + err := writer.WriteInt32Value("likeCount", m.GetLikeCount()) + if err != nil { + return err + } + } + { + err := writer.WriteStringValue("@odata.type", m.GetOdataType()) + if err != nil { + return err + } + } + { + err := writer.WriteInt32Value("shareCount", m.GetShareCount()) + if err != nil { + return err + } + } + { + err := writer.WriteAdditionalData(m.GetAdditionalData()) + if err != nil { + return err + } + } + return nil } + // SetAdditionalData sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *ReactionsFacet) SetAdditionalData(value map[string]interface{})() { - m.additionalData = value +func (m *ReactionsFacet) SetAdditionalData(value map[string]interface{}) { + m.additionalData = value } + // SetCommentCount sets the commentCount property value. Count of comments. -func (m *ReactionsFacet) SetCommentCount(value *int32)() { - m.commentCount = value +func (m *ReactionsFacet) SetCommentCount(value *int32) { + m.commentCount = value } + // SetLikeCount sets the likeCount property value. Count of likes. -func (m *ReactionsFacet) SetLikeCount(value *int32)() { - m.likeCount = value +func (m *ReactionsFacet) SetLikeCount(value *int32) { + m.likeCount = value } + // SetOdataType sets the @odata.type property value. The OdataType property -func (m *ReactionsFacet) SetOdataType(value *string)() { - m.odataType = value +func (m *ReactionsFacet) SetOdataType(value *string) { + m.odataType = value } + // SetShareCount sets the shareCount property value. Count of shares. -func (m *ReactionsFacet) SetShareCount(value *int32)() { - m.shareCount = value +func (m *ReactionsFacet) SetShareCount(value *int32) { + m.shareCount = value } diff --git a/src/internal/connector/graph/betasdk/models/reactions_facetable.go b/src/internal/connector/graph/betasdk/models/reactions_facetable.go index 4e5086047..acdefec37 100644 --- a/src/internal/connector/graph/betasdk/models/reactions_facetable.go +++ b/src/internal/connector/graph/betasdk/models/reactions_facetable.go @@ -1,19 +1,19 @@ package models import ( - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" ) -// ReactionsFacetable +// ReactionsFacetable type ReactionsFacetable interface { - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.AdditionalDataHolder - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable - GetCommentCount()(*int32) - GetLikeCount()(*int32) - GetOdataType()(*string) - GetShareCount()(*int32) - SetCommentCount(value *int32)() - SetLikeCount(value *int32)() - SetOdataType(value *string)() - SetShareCount(value *int32)() + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.AdditionalDataHolder + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable + GetCommentCount() *int32 + GetLikeCount() *int32 + GetOdataType() *string + GetShareCount() *int32 + SetCommentCount(value *int32) + SetLikeCount(value *int32) + SetOdataType(value *string) + SetShareCount(value *int32) } diff --git a/src/internal/connector/graph/betasdk/models/section_emphasis_type.go b/src/internal/connector/graph/betasdk/models/section_emphasis_type.go index 0016aec10..301ae839f 100644 --- a/src/internal/connector/graph/betasdk/models/section_emphasis_type.go +++ b/src/internal/connector/graph/betasdk/models/section_emphasis_type.go @@ -1,43 +1,45 @@ package models + import ( - "errors" + "errors" ) + // Provides operations to call the remove method. type SectionEmphasisType int const ( - NONE_SECTIONEMPHASISTYPE SectionEmphasisType = iota - NEUTRAL_SECTIONEMPHASISTYPE - SOFT_SECTIONEMPHASISTYPE - STRONG_SECTIONEMPHASISTYPE - UNKNOWNFUTUREVALUE_SECTIONEMPHASISTYPE + NONE_SECTIONEMPHASISTYPE SectionEmphasisType = iota + NEUTRAL_SECTIONEMPHASISTYPE + SOFT_SECTIONEMPHASISTYPE + STRONG_SECTIONEMPHASISTYPE + UNKNOWNFUTUREVALUE_SECTIONEMPHASISTYPE ) func (i SectionEmphasisType) String() string { - return []string{"none", "neutral", "soft", "strong", "unknownFutureValue"}[i] + return []string{"none", "neutral", "soft", "strong", "unknownFutureValue"}[i] } func ParseSectionEmphasisType(v string) (interface{}, error) { - result := NONE_SECTIONEMPHASISTYPE - switch v { - case "none": - result = NONE_SECTIONEMPHASISTYPE - case "neutral": - result = NEUTRAL_SECTIONEMPHASISTYPE - case "soft": - result = SOFT_SECTIONEMPHASISTYPE - case "strong": - result = STRONG_SECTIONEMPHASISTYPE - case "unknownFutureValue": - result = UNKNOWNFUTUREVALUE_SECTIONEMPHASISTYPE - default: - return 0, errors.New("Unknown SectionEmphasisType value: " + v) - } - return &result, nil + result := NONE_SECTIONEMPHASISTYPE + switch v { + case "none": + result = NONE_SECTIONEMPHASISTYPE + case "neutral": + result = NEUTRAL_SECTIONEMPHASISTYPE + case "soft": + result = SOFT_SECTIONEMPHASISTYPE + case "strong": + result = STRONG_SECTIONEMPHASISTYPE + case "unknownFutureValue": + result = UNKNOWNFUTUREVALUE_SECTIONEMPHASISTYPE + default: + return 0, errors.New("Unknown SectionEmphasisType value: " + v) + } + return &result, nil } func SerializeSectionEmphasisType(values []SectionEmphasisType) []string { - result := make([]string, len(values)) - for i, v := range values { - result[i] = v.String() - } - return result + result := make([]string, len(values)) + for i, v := range values { + result[i] = v.String() + } + return result } diff --git a/src/internal/connector/graph/betasdk/models/site_access_type.go b/src/internal/connector/graph/betasdk/models/site_access_type.go index 052a2efdb..2d4cedffe 100644 --- a/src/internal/connector/graph/betasdk/models/site_access_type.go +++ b/src/internal/connector/graph/betasdk/models/site_access_type.go @@ -1,37 +1,39 @@ package models + import ( - "errors" + "errors" ) + // Provides operations to call the remove method. type SiteAccessType int const ( - BLOCK_SITEACCESSTYPE SiteAccessType = iota - FULL_SITEACCESSTYPE - LIMITED_SITEACCESSTYPE + BLOCK_SITEACCESSTYPE SiteAccessType = iota + FULL_SITEACCESSTYPE + LIMITED_SITEACCESSTYPE ) func (i SiteAccessType) String() string { - return []string{"block", "full", "limited"}[i] + return []string{"block", "full", "limited"}[i] } func ParseSiteAccessType(v string) (interface{}, error) { - result := BLOCK_SITEACCESSTYPE - switch v { - case "block": - result = BLOCK_SITEACCESSTYPE - case "full": - result = FULL_SITEACCESSTYPE - case "limited": - result = LIMITED_SITEACCESSTYPE - default: - return 0, errors.New("Unknown SiteAccessType value: " + v) - } - return &result, nil + result := BLOCK_SITEACCESSTYPE + switch v { + case "block": + result = BLOCK_SITEACCESSTYPE + case "full": + result = FULL_SITEACCESSTYPE + case "limited": + result = LIMITED_SITEACCESSTYPE + default: + return 0, errors.New("Unknown SiteAccessType value: " + v) + } + return &result, nil } func SerializeSiteAccessType(values []SiteAccessType) []string { - result := make([]string, len(values)) - for i, v := range values { - result[i] = v.String() - } - return result + result := make([]string, len(values)) + for i, v := range values { + result[i] = v.String() + } + return result } diff --git a/src/internal/connector/graph/betasdk/models/site_page_collection_response.go b/src/internal/connector/graph/betasdk/models/site_page_collection_response.go index f66cdafdf..bbd79c3a4 100644 --- a/src/internal/connector/graph/betasdk/models/site_page_collection_response.go +++ b/src/internal/connector/graph/betasdk/models/site_page_collection_response.go @@ -2,7 +2,6 @@ package models import ( i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" - msmodel "github.com/microsoftgraph/msgraph-sdk-go/models" ) diff --git a/src/internal/connector/graph/betasdk/models/site_security_level.go b/src/internal/connector/graph/betasdk/models/site_security_level.go index d2733ce47..0c75c164e 100644 --- a/src/internal/connector/graph/betasdk/models/site_security_level.go +++ b/src/internal/connector/graph/betasdk/models/site_security_level.go @@ -1,52 +1,54 @@ package models + import ( - "errors" + "errors" ) + // Provides operations to call the add method. type SiteSecurityLevel int const ( - // User Defined, default value, no intent. - USERDEFINED_SITESECURITYLEVEL SiteSecurityLevel = iota - // Low. - LOW_SITESECURITYLEVEL - // Medium-low. - MEDIUMLOW_SITESECURITYLEVEL - // Medium. - MEDIUM_SITESECURITYLEVEL - // Medium-high. - MEDIUMHIGH_SITESECURITYLEVEL - // High. - HIGH_SITESECURITYLEVEL + // User Defined, default value, no intent. + USERDEFINED_SITESECURITYLEVEL SiteSecurityLevel = iota + // Low. + LOW_SITESECURITYLEVEL + // Medium-low. + MEDIUMLOW_SITESECURITYLEVEL + // Medium. + MEDIUM_SITESECURITYLEVEL + // Medium-high. + MEDIUMHIGH_SITESECURITYLEVEL + // High. + HIGH_SITESECURITYLEVEL ) func (i SiteSecurityLevel) String() string { - return []string{"userDefined", "low", "mediumLow", "medium", "mediumHigh", "high"}[i] + return []string{"userDefined", "low", "mediumLow", "medium", "mediumHigh", "high"}[i] } func ParseSiteSecurityLevel(v string) (interface{}, error) { - result := USERDEFINED_SITESECURITYLEVEL - switch v { - case "userDefined": - result = USERDEFINED_SITESECURITYLEVEL - case "low": - result = LOW_SITESECURITYLEVEL - case "mediumLow": - result = MEDIUMLOW_SITESECURITYLEVEL - case "medium": - result = MEDIUM_SITESECURITYLEVEL - case "mediumHigh": - result = MEDIUMHIGH_SITESECURITYLEVEL - case "high": - result = HIGH_SITESECURITYLEVEL - default: - return 0, errors.New("Unknown SiteSecurityLevel value: " + v) - } - return &result, nil + result := USERDEFINED_SITESECURITYLEVEL + switch v { + case "userDefined": + result = USERDEFINED_SITESECURITYLEVEL + case "low": + result = LOW_SITESECURITYLEVEL + case "mediumLow": + result = MEDIUMLOW_SITESECURITYLEVEL + case "medium": + result = MEDIUM_SITESECURITYLEVEL + case "mediumHigh": + result = MEDIUMHIGH_SITESECURITYLEVEL + case "high": + result = HIGH_SITESECURITYLEVEL + default: + return 0, errors.New("Unknown SiteSecurityLevel value: " + v) + } + return &result, nil } func SerializeSiteSecurityLevel(values []SiteSecurityLevel) []string { - result := make([]string, len(values)) - for i, v := range values { - result[i] = v.String() - } - return result + result := make([]string, len(values)) + for i, v := range values { + result[i] = v.String() + } + return result } diff --git a/src/internal/connector/graph/betasdk/models/site_settings.go b/src/internal/connector/graph/betasdk/models/site_settings.go index a2a36d94a..1f8930408 100644 --- a/src/internal/connector/graph/betasdk/models/site_settings.go +++ b/src/internal/connector/graph/betasdk/models/site_settings.go @@ -1,123 +1,134 @@ package models import ( - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" ) -// SiteSettings +// SiteSettings type SiteSettings struct { - // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. - additionalData map[string]interface{} - // The language tag for the language used on this site. - languageTag *string - // The OdataType property - odataType *string - // Indicates the time offset for the time zone of the site from Coordinated Universal Time (UTC). - timeZone *string + // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + additionalData map[string]interface{} + // The language tag for the language used on this site. + languageTag *string + // The OdataType property + odataType *string + // Indicates the time offset for the time zone of the site from Coordinated Universal Time (UTC). + timeZone *string } + // NewSiteSettings instantiates a new siteSettings and sets the default values. -func NewSiteSettings()(*SiteSettings) { - m := &SiteSettings{ - } - m.SetAdditionalData(make(map[string]interface{})); - return m +func NewSiteSettings() *SiteSettings { + m := &SiteSettings{} + m.SetAdditionalData(make(map[string]interface{})) + return m } + // CreateSiteSettingsFromDiscriminatorValue creates a new instance of the appropriate class based on discriminator value -func CreateSiteSettingsFromDiscriminatorValue(parseNode i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable, error) { - return NewSiteSettings(), nil +func CreateSiteSettingsFromDiscriminatorValue(parseNode i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) (i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable, error) { + return NewSiteSettings(), nil } + // GetAdditionalData gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *SiteSettings) GetAdditionalData()(map[string]interface{}) { - return m.additionalData +func (m *SiteSettings) GetAdditionalData() map[string]interface{} { + return m.additionalData } + // GetFieldDeserializers the deserialization information for the current model -func (m *SiteSettings) GetFieldDeserializers()(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(error)) { - res := make(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(error)) - res["languageTag"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetLanguageTag(val) - } - return nil - } - res["@odata.type"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetOdataType(val) - } - return nil - } - res["timeZone"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetTimeZone(val) - } - return nil - } - return res +func (m *SiteSettings) GetFieldDeserializers() map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + res := make(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error) + res["languageTag"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetLanguageTag(val) + } + return nil + } + res["@odata.type"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetOdataType(val) + } + return nil + } + res["timeZone"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetTimeZone(val) + } + return nil + } + return res } + // GetLanguageTag gets the languageTag property value. The language tag for the language used on this site. -func (m *SiteSettings) GetLanguageTag()(*string) { - return m.languageTag +func (m *SiteSettings) GetLanguageTag() *string { + return m.languageTag } + // GetOdataType gets the @odata.type property value. The OdataType property -func (m *SiteSettings) GetOdataType()(*string) { - return m.odataType +func (m *SiteSettings) GetOdataType() *string { + return m.odataType } + // GetTimeZone gets the timeZone property value. Indicates the time offset for the time zone of the site from Coordinated Universal Time (UTC). -func (m *SiteSettings) GetTimeZone()(*string) { - return m.timeZone +func (m *SiteSettings) GetTimeZone() *string { + return m.timeZone } + // Serialize serializes information the current object -func (m *SiteSettings) Serialize(writer i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.SerializationWriter)(error) { - { - err := writer.WriteStringValue("languageTag", m.GetLanguageTag()) - if err != nil { - return err - } - } - { - err := writer.WriteStringValue("@odata.type", m.GetOdataType()) - if err != nil { - return err - } - } - { - err := writer.WriteStringValue("timeZone", m.GetTimeZone()) - if err != nil { - return err - } - } - { - err := writer.WriteAdditionalData(m.GetAdditionalData()) - if err != nil { - return err - } - } - return nil +func (m *SiteSettings) Serialize(writer i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.SerializationWriter) error { + { + err := writer.WriteStringValue("languageTag", m.GetLanguageTag()) + if err != nil { + return err + } + } + { + err := writer.WriteStringValue("@odata.type", m.GetOdataType()) + if err != nil { + return err + } + } + { + err := writer.WriteStringValue("timeZone", m.GetTimeZone()) + if err != nil { + return err + } + } + { + err := writer.WriteAdditionalData(m.GetAdditionalData()) + if err != nil { + return err + } + } + return nil } + // SetAdditionalData sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *SiteSettings) SetAdditionalData(value map[string]interface{})() { - m.additionalData = value +func (m *SiteSettings) SetAdditionalData(value map[string]interface{}) { + m.additionalData = value } + // SetLanguageTag sets the languageTag property value. The language tag for the language used on this site. -func (m *SiteSettings) SetLanguageTag(value *string)() { - m.languageTag = value +func (m *SiteSettings) SetLanguageTag(value *string) { + m.languageTag = value } + // SetOdataType sets the @odata.type property value. The OdataType property -func (m *SiteSettings) SetOdataType(value *string)() { - m.odataType = value +func (m *SiteSettings) SetOdataType(value *string) { + m.odataType = value } + // SetTimeZone sets the timeZone property value. Indicates the time offset for the time zone of the site from Coordinated Universal Time (UTC). -func (m *SiteSettings) SetTimeZone(value *string)() { - m.timeZone = value +func (m *SiteSettings) SetTimeZone(value *string) { + m.timeZone = value } diff --git a/src/internal/connector/graph/betasdk/models/site_settingsable.go b/src/internal/connector/graph/betasdk/models/site_settingsable.go index 0423550ea..1b3825e05 100644 --- a/src/internal/connector/graph/betasdk/models/site_settingsable.go +++ b/src/internal/connector/graph/betasdk/models/site_settingsable.go @@ -1,17 +1,17 @@ package models import ( - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" ) -// SiteSettingsable +// SiteSettingsable type SiteSettingsable interface { - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.AdditionalDataHolder - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable - GetLanguageTag()(*string) - GetOdataType()(*string) - GetTimeZone()(*string) - SetLanguageTag(value *string)() - SetOdataType(value *string)() - SetTimeZone(value *string)() + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.AdditionalDataHolder + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable + GetLanguageTag() *string + GetOdataType() *string + GetTimeZone() *string + SetLanguageTag(value *string) + SetOdataType(value *string) + SetTimeZone(value *string) } diff --git a/src/internal/connector/graph/betasdk/models/standard_web_part.go b/src/internal/connector/graph/betasdk/models/standard_web_part.go index 0b7b4427a..4532e1d24 100644 --- a/src/internal/connector/graph/betasdk/models/standard_web_part.go +++ b/src/internal/connector/graph/betasdk/models/standard_web_part.go @@ -1,88 +1,96 @@ package models import ( - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" ) -// StandardWebPart +// StandardWebPart type StandardWebPart struct { - WebPart - // Data of the webPart. - data WebPartDataable - // A Guid which indicates the type of the webParts - webPartType *string + WebPart + // Data of the webPart. + data WebPartDataable + // A Guid which indicates the type of the webParts + webPartType *string } + // NewStandardWebPart instantiates a new StandardWebPart and sets the default values. -func NewStandardWebPart()(*StandardWebPart) { - m := &StandardWebPart{ - WebPart: *NewWebPart(), - } - odataTypeValue := "#microsoft.graph.standardWebPart"; - m.SetOdataType(&odataTypeValue); - return m +func NewStandardWebPart() *StandardWebPart { + m := &StandardWebPart{ + WebPart: *NewWebPart(), + } + odataTypeValue := "#microsoft.graph.standardWebPart" + m.SetOdataType(&odataTypeValue) + return m } + // CreateStandardWebPartFromDiscriminatorValue creates a new instance of the appropriate class based on discriminator value -func CreateStandardWebPartFromDiscriminatorValue(parseNode i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable, error) { - return NewStandardWebPart(), nil +func CreateStandardWebPartFromDiscriminatorValue(parseNode i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) (i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable, error) { + return NewStandardWebPart(), nil } + // GetData gets the data property value. Data of the webPart. -func (m *StandardWebPart) GetData()(WebPartDataable) { - return m.data +func (m *StandardWebPart) GetData() WebPartDataable { + return m.data } + // GetFieldDeserializers the deserialization information for the current model -func (m *StandardWebPart) GetFieldDeserializers()(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(error)) { - res := m.WebPart.GetFieldDeserializers() - res["data"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetObjectValue(CreateWebPartDataFromDiscriminatorValue) - if err != nil { - return err - } - if val != nil { - m.SetData(val.(WebPartDataable)) - } - return nil - } - res["webPartType"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetWebPartType(val) - } - return nil - } - return res +func (m *StandardWebPart) GetFieldDeserializers() map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + res := m.WebPart.GetFieldDeserializers() + res["data"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetObjectValue(CreateWebPartDataFromDiscriminatorValue) + if err != nil { + return err + } + if val != nil { + m.SetData(val.(WebPartDataable)) + } + return nil + } + res["webPartType"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetWebPartType(val) + } + return nil + } + return res } + // GetWebPartType gets the webPartType property value. A Guid which indicates the type of the webParts -func (m *StandardWebPart) GetWebPartType()(*string) { - return m.webPartType +func (m *StandardWebPart) GetWebPartType() *string { + return m.webPartType } + // Serialize serializes information the current object -func (m *StandardWebPart) Serialize(writer i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.SerializationWriter)(error) { - err := m.WebPart.Serialize(writer) - if err != nil { - return err - } - { - err = writer.WriteObjectValue("data", m.GetData()) - if err != nil { - return err - } - } - { - err = writer.WriteStringValue("webPartType", m.GetWebPartType()) - if err != nil { - return err - } - } - return nil +func (m *StandardWebPart) Serialize(writer i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.SerializationWriter) error { + err := m.WebPart.Serialize(writer) + if err != nil { + return err + } + { + err = writer.WriteObjectValue("data", m.GetData()) + if err != nil { + return err + } + } + { + err = writer.WriteStringValue("webPartType", m.GetWebPartType()) + if err != nil { + return err + } + } + return nil } + // SetData sets the data property value. Data of the webPart. -func (m *StandardWebPart) SetData(value WebPartDataable)() { - m.data = value +func (m *StandardWebPart) SetData(value WebPartDataable) { + m.data = value } + // SetWebPartType sets the webPartType property value. A Guid which indicates the type of the webParts -func (m *StandardWebPart) SetWebPartType(value *string)() { - m.webPartType = value +func (m *StandardWebPart) SetWebPartType(value *string) { + m.webPartType = value } diff --git a/src/internal/connector/graph/betasdk/models/standard_web_partable.go b/src/internal/connector/graph/betasdk/models/standard_web_partable.go index e09160b2b..b33c25f15 100644 --- a/src/internal/connector/graph/betasdk/models/standard_web_partable.go +++ b/src/internal/connector/graph/betasdk/models/standard_web_partable.go @@ -1,15 +1,15 @@ package models import ( - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" ) -// StandardWebPartable +// StandardWebPartable type StandardWebPartable interface { - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable - WebPartable - GetData()(WebPartDataable) - GetWebPartType()(*string) - SetData(value WebPartDataable)() - SetWebPartType(value *string)() + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable + WebPartable + GetData() WebPartDataable + GetWebPartType() *string + SetData(value WebPartDataable) + SetWebPartType(value *string) } diff --git a/src/internal/connector/graph/betasdk/models/text_web_part.go b/src/internal/connector/graph/betasdk/models/text_web_part.go index f607ffa31..1ae554671 100644 --- a/src/internal/connector/graph/betasdk/models/text_web_part.go +++ b/src/internal/connector/graph/betasdk/models/text_web_part.go @@ -1,62 +1,68 @@ package models import ( - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" ) -// TextWebPart +// TextWebPart type TextWebPart struct { - WebPart - // The HTML string in text web part. - innerHtml *string + WebPart + // The HTML string in text web part. + innerHtml *string } + // NewTextWebPart instantiates a new TextWebPart and sets the default values. -func NewTextWebPart()(*TextWebPart) { - m := &TextWebPart{ - WebPart: *NewWebPart(), - } - odataTypeValue := "#microsoft.graph.textWebPart"; - m.SetOdataType(&odataTypeValue); - return m +func NewTextWebPart() *TextWebPart { + m := &TextWebPart{ + WebPart: *NewWebPart(), + } + odataTypeValue := "#microsoft.graph.textWebPart" + m.SetOdataType(&odataTypeValue) + return m } + // CreateTextWebPartFromDiscriminatorValue creates a new instance of the appropriate class based on discriminator value -func CreateTextWebPartFromDiscriminatorValue(parseNode i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable, error) { - return NewTextWebPart(), nil +func CreateTextWebPartFromDiscriminatorValue(parseNode i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) (i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable, error) { + return NewTextWebPart(), nil } + // GetFieldDeserializers the deserialization information for the current model -func (m *TextWebPart) GetFieldDeserializers()(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(error)) { - res := m.WebPart.GetFieldDeserializers() - res["innerHtml"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetInnerHtml(val) - } - return nil - } - return res +func (m *TextWebPart) GetFieldDeserializers() map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + res := m.WebPart.GetFieldDeserializers() + res["innerHtml"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetInnerHtml(val) + } + return nil + } + return res } + // GetInnerHtml gets the innerHtml property value. The HTML string in text web part. -func (m *TextWebPart) GetInnerHtml()(*string) { - return m.innerHtml +func (m *TextWebPart) GetInnerHtml() *string { + return m.innerHtml } + // Serialize serializes information the current object -func (m *TextWebPart) Serialize(writer i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.SerializationWriter)(error) { - err := m.WebPart.Serialize(writer) - if err != nil { - return err - } - { - err = writer.WriteStringValue("innerHtml", m.GetInnerHtml()) - if err != nil { - return err - } - } - return nil +func (m *TextWebPart) Serialize(writer i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.SerializationWriter) error { + err := m.WebPart.Serialize(writer) + if err != nil { + return err + } + { + err = writer.WriteStringValue("innerHtml", m.GetInnerHtml()) + if err != nil { + return err + } + } + return nil } + // SetInnerHtml sets the innerHtml property value. The HTML string in text web part. -func (m *TextWebPart) SetInnerHtml(value *string)() { - m.innerHtml = value +func (m *TextWebPart) SetInnerHtml(value *string) { + m.innerHtml = value } diff --git a/src/internal/connector/graph/betasdk/models/text_web_partable.go b/src/internal/connector/graph/betasdk/models/text_web_partable.go index 45e21d92b..f58b6a0c8 100644 --- a/src/internal/connector/graph/betasdk/models/text_web_partable.go +++ b/src/internal/connector/graph/betasdk/models/text_web_partable.go @@ -1,13 +1,13 @@ package models import ( - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" ) -// TextWebPartable +// TextWebPartable type TextWebPartable interface { - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable - WebPartable - GetInnerHtml()(*string) - SetInnerHtml(value *string)() + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable + WebPartable + GetInnerHtml() *string + SetInnerHtml(value *string) } diff --git a/src/internal/connector/graph/betasdk/models/title_area_layout_type.go b/src/internal/connector/graph/betasdk/models/title_area_layout_type.go index 375b68874..3621288a4 100644 --- a/src/internal/connector/graph/betasdk/models/title_area_layout_type.go +++ b/src/internal/connector/graph/betasdk/models/title_area_layout_type.go @@ -1,43 +1,45 @@ package models + import ( - "errors" + "errors" ) + // Provides operations to call the remove method. type TitleAreaLayoutType int const ( - IMAGEANDTITLE_TITLEAREALAYOUTTYPE TitleAreaLayoutType = iota - PLAIN_TITLEAREALAYOUTTYPE - COLORBLOCK_TITLEAREALAYOUTTYPE - OVERLAP_TITLEAREALAYOUTTYPE - UNKNOWNFUTUREVALUE_TITLEAREALAYOUTTYPE + IMAGEANDTITLE_TITLEAREALAYOUTTYPE TitleAreaLayoutType = iota + PLAIN_TITLEAREALAYOUTTYPE + COLORBLOCK_TITLEAREALAYOUTTYPE + OVERLAP_TITLEAREALAYOUTTYPE + UNKNOWNFUTUREVALUE_TITLEAREALAYOUTTYPE ) func (i TitleAreaLayoutType) String() string { - return []string{"imageAndTitle", "plain", "colorBlock", "overlap", "unknownFutureValue"}[i] + return []string{"imageAndTitle", "plain", "colorBlock", "overlap", "unknownFutureValue"}[i] } func ParseTitleAreaLayoutType(v string) (interface{}, error) { - result := IMAGEANDTITLE_TITLEAREALAYOUTTYPE - switch v { - case "imageAndTitle": - result = IMAGEANDTITLE_TITLEAREALAYOUTTYPE - case "plain": - result = PLAIN_TITLEAREALAYOUTTYPE - case "colorBlock": - result = COLORBLOCK_TITLEAREALAYOUTTYPE - case "overlap": - result = OVERLAP_TITLEAREALAYOUTTYPE - case "unknownFutureValue": - result = UNKNOWNFUTUREVALUE_TITLEAREALAYOUTTYPE - default: - return 0, errors.New("Unknown TitleAreaLayoutType value: " + v) - } - return &result, nil + result := IMAGEANDTITLE_TITLEAREALAYOUTTYPE + switch v { + case "imageAndTitle": + result = IMAGEANDTITLE_TITLEAREALAYOUTTYPE + case "plain": + result = PLAIN_TITLEAREALAYOUTTYPE + case "colorBlock": + result = COLORBLOCK_TITLEAREALAYOUTTYPE + case "overlap": + result = OVERLAP_TITLEAREALAYOUTTYPE + case "unknownFutureValue": + result = UNKNOWNFUTUREVALUE_TITLEAREALAYOUTTYPE + default: + return 0, errors.New("Unknown TitleAreaLayoutType value: " + v) + } + return &result, nil } func SerializeTitleAreaLayoutType(values []TitleAreaLayoutType) []string { - result := make([]string, len(values)) - for i, v := range values { - result[i] = v.String() - } - return result + result := make([]string, len(values)) + for i, v := range values { + result[i] = v.String() + } + return result } diff --git a/src/internal/connector/graph/betasdk/models/title_area_text_alignment_type.go b/src/internal/connector/graph/betasdk/models/title_area_text_alignment_type.go index 27b1e1dba..a34f41dbe 100644 --- a/src/internal/connector/graph/betasdk/models/title_area_text_alignment_type.go +++ b/src/internal/connector/graph/betasdk/models/title_area_text_alignment_type.go @@ -1,37 +1,39 @@ package models + import ( - "errors" + "errors" ) + // Provides operations to call the remove method. type TitleAreaTextAlignmentType int const ( - LEFT_TITLEAREATEXTALIGNMENTTYPE TitleAreaTextAlignmentType = iota - CENTER_TITLEAREATEXTALIGNMENTTYPE - UNKNOWNFUTUREVALUE_TITLEAREATEXTALIGNMENTTYPE + LEFT_TITLEAREATEXTALIGNMENTTYPE TitleAreaTextAlignmentType = iota + CENTER_TITLEAREATEXTALIGNMENTTYPE + UNKNOWNFUTUREVALUE_TITLEAREATEXTALIGNMENTTYPE ) func (i TitleAreaTextAlignmentType) String() string { - return []string{"left", "center", "unknownFutureValue"}[i] + return []string{"left", "center", "unknownFutureValue"}[i] } func ParseTitleAreaTextAlignmentType(v string) (interface{}, error) { - result := LEFT_TITLEAREATEXTALIGNMENTTYPE - switch v { - case "left": - result = LEFT_TITLEAREATEXTALIGNMENTTYPE - case "center": - result = CENTER_TITLEAREATEXTALIGNMENTTYPE - case "unknownFutureValue": - result = UNKNOWNFUTUREVALUE_TITLEAREATEXTALIGNMENTTYPE - default: - return 0, errors.New("Unknown TitleAreaTextAlignmentType value: " + v) - } - return &result, nil + result := LEFT_TITLEAREATEXTALIGNMENTTYPE + switch v { + case "left": + result = LEFT_TITLEAREATEXTALIGNMENTTYPE + case "center": + result = CENTER_TITLEAREATEXTALIGNMENTTYPE + case "unknownFutureValue": + result = UNKNOWNFUTUREVALUE_TITLEAREATEXTALIGNMENTTYPE + default: + return 0, errors.New("Unknown TitleAreaTextAlignmentType value: " + v) + } + return &result, nil } func SerializeTitleAreaTextAlignmentType(values []TitleAreaTextAlignmentType) []string { - result := make([]string, len(values)) - for i, v := range values { - result[i] = v.String() - } - return result + result := make([]string, len(values)) + for i, v := range values { + result[i] = v.String() + } + return result } diff --git a/src/internal/connector/graph/betasdk/models/web_part_position.go b/src/internal/connector/graph/betasdk/models/web_part_position.go index f2f1c3c9e..f3be0e651 100644 --- a/src/internal/connector/graph/betasdk/models/web_part_position.go +++ b/src/internal/connector/graph/betasdk/models/web_part_position.go @@ -1,175 +1,190 @@ package models import ( - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" ) -// WebPartPosition +// WebPartPosition type WebPartPosition struct { - // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. - additionalData map[string]interface{} - // Indicates the identifier of the column where the web part is located. - columnId *float64 - // Indicates the horizontal section where the web part is located. - horizontalSectionId *float64 - // Indicates whether the web part is located in the vertical section. - isInVerticalSection *bool - // The OdataType property - odataType *string - // Index of the current web part. Represents the order of the web part in this column or section. - webPartIndex *float64 + // Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + additionalData map[string]interface{} + // Indicates the identifier of the column where the web part is located. + columnId *float64 + // Indicates the horizontal section where the web part is located. + horizontalSectionId *float64 + // Indicates whether the web part is located in the vertical section. + isInVerticalSection *bool + // The OdataType property + odataType *string + // Index of the current web part. Represents the order of the web part in this column or section. + webPartIndex *float64 } + // NewWebPartPosition instantiates a new webPartPosition and sets the default values. -func NewWebPartPosition()(*WebPartPosition) { - m := &WebPartPosition{ - } - m.SetAdditionalData(make(map[string]interface{})); - return m +func NewWebPartPosition() *WebPartPosition { + m := &WebPartPosition{} + m.SetAdditionalData(make(map[string]interface{})) + return m } + // CreateWebPartPositionFromDiscriminatorValue creates a new instance of the appropriate class based on discriminator value -func CreateWebPartPositionFromDiscriminatorValue(parseNode i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable, error) { - return NewWebPartPosition(), nil +func CreateWebPartPositionFromDiscriminatorValue(parseNode i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) (i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable, error) { + return NewWebPartPosition(), nil } + // GetAdditionalData gets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *WebPartPosition) GetAdditionalData()(map[string]interface{}) { - return m.additionalData +func (m *WebPartPosition) GetAdditionalData() map[string]interface{} { + return m.additionalData } + // GetColumnId gets the columnId property value. Indicates the identifier of the column where the web part is located. -func (m *WebPartPosition) GetColumnId()(*float64) { - return m.columnId +func (m *WebPartPosition) GetColumnId() *float64 { + return m.columnId } + // GetFieldDeserializers the deserialization information for the current model -func (m *WebPartPosition) GetFieldDeserializers()(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(error)) { - res := make(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode)(error)) - res["columnId"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetFloat64Value() - if err != nil { - return err - } - if val != nil { - m.SetColumnId(val) - } - return nil - } - res["horizontalSectionId"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetFloat64Value() - if err != nil { - return err - } - if val != nil { - m.SetHorizontalSectionId(val) - } - return nil - } - res["isInVerticalSection"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetBoolValue() - if err != nil { - return err - } - if val != nil { - m.SetIsInVerticalSection(val) - } - return nil - } - res["@odata.type"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetStringValue() - if err != nil { - return err - } - if val != nil { - m.SetOdataType(val) - } - return nil - } - res["webPartIndex"] = func (n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { - val, err := n.GetFloat64Value() - if err != nil { - return err - } - if val != nil { - m.SetWebPartIndex(val) - } - return nil - } - return res +func (m *WebPartPosition) GetFieldDeserializers() map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + res := make(map[string]func(i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error) + res["columnId"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetFloat64Value() + if err != nil { + return err + } + if val != nil { + m.SetColumnId(val) + } + return nil + } + res["horizontalSectionId"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetFloat64Value() + if err != nil { + return err + } + if val != nil { + m.SetHorizontalSectionId(val) + } + return nil + } + res["isInVerticalSection"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetBoolValue() + if err != nil { + return err + } + if val != nil { + m.SetIsInVerticalSection(val) + } + return nil + } + res["@odata.type"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetStringValue() + if err != nil { + return err + } + if val != nil { + m.SetOdataType(val) + } + return nil + } + res["webPartIndex"] = func(n i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.ParseNode) error { + val, err := n.GetFloat64Value() + if err != nil { + return err + } + if val != nil { + m.SetWebPartIndex(val) + } + return nil + } + return res } + // GetHorizontalSectionId gets the horizontalSectionId property value. Indicates the horizontal section where the web part is located. -func (m *WebPartPosition) GetHorizontalSectionId()(*float64) { - return m.horizontalSectionId +func (m *WebPartPosition) GetHorizontalSectionId() *float64 { + return m.horizontalSectionId } + // GetIsInVerticalSection gets the isInVerticalSection property value. Indicates whether the web part is located in the vertical section. -func (m *WebPartPosition) GetIsInVerticalSection()(*bool) { - return m.isInVerticalSection +func (m *WebPartPosition) GetIsInVerticalSection() *bool { + return m.isInVerticalSection } + // GetOdataType gets the @odata.type property value. The OdataType property -func (m *WebPartPosition) GetOdataType()(*string) { - return m.odataType +func (m *WebPartPosition) GetOdataType() *string { + return m.odataType } + // GetWebPartIndex gets the webPartIndex property value. Index of the current web part. Represents the order of the web part in this column or section. -func (m *WebPartPosition) GetWebPartIndex()(*float64) { - return m.webPartIndex +func (m *WebPartPosition) GetWebPartIndex() *float64 { + return m.webPartIndex } + // Serialize serializes information the current object -func (m *WebPartPosition) Serialize(writer i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.SerializationWriter)(error) { - { - err := writer.WriteFloat64Value("columnId", m.GetColumnId()) - if err != nil { - return err - } - } - { - err := writer.WriteFloat64Value("horizontalSectionId", m.GetHorizontalSectionId()) - if err != nil { - return err - } - } - { - err := writer.WriteBoolValue("isInVerticalSection", m.GetIsInVerticalSection()) - if err != nil { - return err - } - } - { - err := writer.WriteStringValue("@odata.type", m.GetOdataType()) - if err != nil { - return err - } - } - { - err := writer.WriteFloat64Value("webPartIndex", m.GetWebPartIndex()) - if err != nil { - return err - } - } - { - err := writer.WriteAdditionalData(m.GetAdditionalData()) - if err != nil { - return err - } - } - return nil +func (m *WebPartPosition) Serialize(writer i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.SerializationWriter) error { + { + err := writer.WriteFloat64Value("columnId", m.GetColumnId()) + if err != nil { + return err + } + } + { + err := writer.WriteFloat64Value("horizontalSectionId", m.GetHorizontalSectionId()) + if err != nil { + return err + } + } + { + err := writer.WriteBoolValue("isInVerticalSection", m.GetIsInVerticalSection()) + if err != nil { + return err + } + } + { + err := writer.WriteStringValue("@odata.type", m.GetOdataType()) + if err != nil { + return err + } + } + { + err := writer.WriteFloat64Value("webPartIndex", m.GetWebPartIndex()) + if err != nil { + return err + } + } + { + err := writer.WriteAdditionalData(m.GetAdditionalData()) + if err != nil { + return err + } + } + return nil } + // SetAdditionalData sets the additionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. -func (m *WebPartPosition) SetAdditionalData(value map[string]interface{})() { - m.additionalData = value +func (m *WebPartPosition) SetAdditionalData(value map[string]interface{}) { + m.additionalData = value } + // SetColumnId sets the columnId property value. Indicates the identifier of the column where the web part is located. -func (m *WebPartPosition) SetColumnId(value *float64)() { - m.columnId = value +func (m *WebPartPosition) SetColumnId(value *float64) { + m.columnId = value } + // SetHorizontalSectionId sets the horizontalSectionId property value. Indicates the horizontal section where the web part is located. -func (m *WebPartPosition) SetHorizontalSectionId(value *float64)() { - m.horizontalSectionId = value +func (m *WebPartPosition) SetHorizontalSectionId(value *float64) { + m.horizontalSectionId = value } + // SetIsInVerticalSection sets the isInVerticalSection property value. Indicates whether the web part is located in the vertical section. -func (m *WebPartPosition) SetIsInVerticalSection(value *bool)() { - m.isInVerticalSection = value +func (m *WebPartPosition) SetIsInVerticalSection(value *bool) { + m.isInVerticalSection = value } + // SetOdataType sets the @odata.type property value. The OdataType property -func (m *WebPartPosition) SetOdataType(value *string)() { - m.odataType = value +func (m *WebPartPosition) SetOdataType(value *string) { + m.odataType = value } + // SetWebPartIndex sets the webPartIndex property value. Index of the current web part. Represents the order of the web part in this column or section. -func (m *WebPartPosition) SetWebPartIndex(value *float64)() { - m.webPartIndex = value +func (m *WebPartPosition) SetWebPartIndex(value *float64) { + m.webPartIndex = value } diff --git a/src/internal/connector/graph/betasdk/models/web_part_positionable.go b/src/internal/connector/graph/betasdk/models/web_part_positionable.go index f0939db2e..9655ac285 100644 --- a/src/internal/connector/graph/betasdk/models/web_part_positionable.go +++ b/src/internal/connector/graph/betasdk/models/web_part_positionable.go @@ -1,21 +1,21 @@ package models import ( - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91 "github.com/microsoft/kiota-abstractions-go/serialization" ) -// WebPartPositionable +// WebPartPositionable type WebPartPositionable interface { - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.AdditionalDataHolder - i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable - GetColumnId()(*float64) - GetHorizontalSectionId()(*float64) - GetIsInVerticalSection()(*bool) - GetOdataType()(*string) - GetWebPartIndex()(*float64) - SetColumnId(value *float64)() - SetHorizontalSectionId(value *float64)() - SetIsInVerticalSection(value *bool)() - SetOdataType(value *string)() - SetWebPartIndex(value *float64)() + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.AdditionalDataHolder + i878a80d2330e89d26896388a3f487eef27b0a0e6c010c493bf80be1452208f91.Parsable + GetColumnId() *float64 + GetHorizontalSectionId() *float64 + GetIsInVerticalSection() *bool + GetOdataType() *string + GetWebPartIndex() *float64 + SetColumnId(value *float64) + SetHorizontalSectionId(value *float64) + SetIsInVerticalSection(value *bool) + SetOdataType(value *string) + SetWebPartIndex(value *float64) } diff --git a/src/internal/connector/graph/betasdk/sites/item_pages_item_web_parts_item_get_position_of_web_part_request_builder.go b/src/internal/connector/graph/betasdk/sites/item_pages_item_web_parts_item_get_position_of_web_part_request_builder.go index 4bb325673..9db79ace5 100644 --- a/src/internal/connector/graph/betasdk/sites/item_pages_item_web_parts_item_get_position_of_web_part_request_builder.go +++ b/src/internal/connector/graph/betasdk/sites/item_pages_item_web_parts_item_get_position_of_web_part_request_builder.go @@ -3,9 +3,10 @@ package sites import ( "context" - ifda19816f54f079134d70c11e75d6b26799300cf72079e282f1d3bb9a6750354 "github.com/alcionai/corso/src/internal/connector/graph/betasdk/models" i2ae4187f7daee263371cb1c977df639813ab50ffa529013b7437480d1ec0158f "github.com/microsoft/kiota-abstractions-go" i7ad325c11fbf3db4d761c429267362d8b24daa1eda0081f914ebc3cdc85181a0 "github.com/microsoftgraph/msgraph-sdk-go/models/odataerrors" + + ifda19816f54f079134d70c11e75d6b26799300cf72079e282f1d3bb9a6750354 "github.com/alcionai/corso/src/internal/connector/graph/betasdk/models" ) // ItemPagesItemWebPartsItemGetPositionOfWebPartRequestBuilder provides operations to call the getPositionOfWebPart method. diff --git a/src/internal/connector/graph/betasdk/sites/item_pages_item_web_parts_request_builder.go b/src/internal/connector/graph/betasdk/sites/item_pages_item_web_parts_request_builder.go index 0e349df74..e2e32c640 100644 --- a/src/internal/connector/graph/betasdk/sites/item_pages_item_web_parts_request_builder.go +++ b/src/internal/connector/graph/betasdk/sites/item_pages_item_web_parts_request_builder.go @@ -3,9 +3,10 @@ package sites import ( "context" - ifda19816f54f079134d70c11e75d6b26799300cf72079e282f1d3bb9a6750354 "github.com/alcionai/corso/src/internal/connector/graph/betasdk/models" i2ae4187f7daee263371cb1c977df639813ab50ffa529013b7437480d1ec0158f "github.com/microsoft/kiota-abstractions-go" i7ad325c11fbf3db4d761c429267362d8b24daa1eda0081f914ebc3cdc85181a0 "github.com/microsoftgraph/msgraph-sdk-go/models/odataerrors" + + ifda19816f54f079134d70c11e75d6b26799300cf72079e282f1d3bb9a6750354 "github.com/alcionai/corso/src/internal/connector/graph/betasdk/models" ) // ItemPagesItemWebPartsRequestBuilder provides operations to manage the webParts property of the microsoft.graph.sitePage entity. diff --git a/src/internal/connector/graph/betasdk/sites/item_pages_item_web_parts_web_part_item_request_builder.go b/src/internal/connector/graph/betasdk/sites/item_pages_item_web_parts_web_part_item_request_builder.go index 25dba98cf..1c16fc8df 100644 --- a/src/internal/connector/graph/betasdk/sites/item_pages_item_web_parts_web_part_item_request_builder.go +++ b/src/internal/connector/graph/betasdk/sites/item_pages_item_web_parts_web_part_item_request_builder.go @@ -3,10 +3,10 @@ package sites import ( "context" - ifda19816f54f079134d70c11e75d6b26799300cf72079e282f1d3bb9a6750354 "github.com/alcionai/corso/src/internal/connector/graph/betasdk/models" i2ae4187f7daee263371cb1c977df639813ab50ffa529013b7437480d1ec0158f "github.com/microsoft/kiota-abstractions-go" - i7ad325c11fbf3db4d761c429267362d8b24daa1eda0081f914ebc3cdc85181a0 "github.com/microsoftgraph/msgraph-sdk-go/models/odataerrors" + + ifda19816f54f079134d70c11e75d6b26799300cf72079e282f1d3bb9a6750354 "github.com/alcionai/corso/src/internal/connector/graph/betasdk/models" ) // ItemPagesItemWebPartsWebPartItemRequestBuilder provides operations to manage the webParts property of the microsoft.graph.sitePage entity. diff --git a/src/internal/connector/graph/betasdk/sites/item_pages_request_builder.go b/src/internal/connector/graph/betasdk/sites/item_pages_request_builder.go index 43f503439..6c82f58df 100644 --- a/src/internal/connector/graph/betasdk/sites/item_pages_request_builder.go +++ b/src/internal/connector/graph/betasdk/sites/item_pages_request_builder.go @@ -3,9 +3,10 @@ package sites import ( "context" - ifda19816f54f079134d70c11e75d6b26799300cf72079e282f1d3bb9a6750354 "github.com/alcionai/corso/src/internal/connector/graph/betasdk/models" i2ae4187f7daee263371cb1c977df639813ab50ffa529013b7437480d1ec0158f "github.com/microsoft/kiota-abstractions-go" i7ad325c11fbf3db4d761c429267362d8b24daa1eda0081f914ebc3cdc85181a0 "github.com/microsoftgraph/msgraph-sdk-go/models/odataerrors" + + ifda19816f54f079134d70c11e75d6b26799300cf72079e282f1d3bb9a6750354 "github.com/alcionai/corso/src/internal/connector/graph/betasdk/models" ) // ItemPagesRequestBuilder provides operations to manage the pages property of the microsoft.graph.site entity. diff --git a/src/internal/connector/graph/errors.go b/src/internal/connector/graph/errors.go index c75e4a6cb..21116057d 100644 --- a/src/internal/connector/graph/errors.go +++ b/src/internal/connector/graph/errors.go @@ -17,6 +17,7 @@ import ( // --------------------------------------------------------------------------- const ( + errCodeActivityLimitReached = "activityLimitReached" errCodeItemNotFound = "ErrorItemNotFound" errCodeEmailFolderNotFound = "ErrorSyncFolderNotFound" errCodeResyncRequired = "ResyncRequired" @@ -31,8 +32,10 @@ var ( // normally the graph client will catch this for us, but in case we // run our own client Do(), we need to translate it to a timeout type // failure locally. - Err429TooManyRequests = errors.New("429 too many requests") - Err503ServiceUnavailable = errors.New("503 Service Unavailable") + Err429TooManyRequests = errors.New("429 too many requests") + Err503ServiceUnavailable = errors.New("503 Service Unavailable") + Err504GatewayTimeout = errors.New("504 Gateway Timeout") + Err500InternalServerError = errors.New("500 Internal Server Error") ) // The folder or item was deleted between the time we identified @@ -113,6 +116,10 @@ func IsErrThrottled(err error) bool { return true } + if hasErrorCode(err, errCodeActivityLimitReached) { + return true + } + e := ErrThrottled{} return errors.As(err, &e) @@ -135,21 +142,18 @@ func IsErrUnauthorized(err error) bool { return errors.As(err, &e) } -type ErrServiceUnavailable struct { +type ErrInternalServerError struct { common.Err } -func IsSericeUnavailable(err error) bool { - if errors.Is(err, Err503ServiceUnavailable) { +func IsInternalServerError(err error) bool { + if errors.Is(err, Err500InternalServerError) { return true } - e := ErrUnauthorized{} - if errors.As(err, &e) { - return true - } + e := ErrInternalServerError{} - return true + return errors.As(err, &e) } // --------------------------------------------------------------------------- diff --git a/src/internal/connector/graph/errors_test.go b/src/internal/connector/graph/errors_test.go new file mode 100644 index 000000000..c7f889b83 --- /dev/null +++ b/src/internal/connector/graph/errors_test.go @@ -0,0 +1,248 @@ +package graph + +import ( + "context" + "testing" + + "github.com/microsoftgraph/msgraph-sdk-go/models/odataerrors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + + "github.com/alcionai/corso/src/internal/common" +) + +type GraphErrorsUnitSuite struct { + suite.Suite +} + +func TestGraphErrorsUnitSuite(t *testing.T) { + suite.Run(t, new(GraphErrorsUnitSuite)) +} + +func odErr(code string) *odataerrors.ODataError { + odErr := &odataerrors.ODataError{} + merr := odataerrors.MainError{} + merr.SetCode(&code) + odErr.SetError(&merr) + + return odErr +} + +func (suite *GraphErrorsUnitSuite) TestIsErrDeletedInFlight() { + table := []struct { + name string + err error + expect assert.BoolAssertionFunc + }{ + { + name: "nil", + err: nil, + expect: assert.False, + }, + { + name: "non-matching", + err: assert.AnError, + expect: assert.False, + }, + { + name: "as", + err: ErrDeletedInFlight{Err: *common.EncapsulateError(assert.AnError)}, + expect: assert.True, + }, + { + name: "non-matching oDataErr", + err: odErr("fnords"), + expect: assert.False, + }, + { + name: "not-found oDataErr", + err: odErr(errCodeItemNotFound), + expect: assert.True, + }, + { + name: "sync-not-found oDataErr", + err: odErr(errCodeSyncFolderNotFound), + expect: assert.True, + }, + } + for _, test := range table { + suite.T().Run(test.name, func(t *testing.T) { + test.expect(t, IsErrDeletedInFlight(test.err)) + }) + } +} + +func (suite *GraphErrorsUnitSuite) TestIsErrInvalidDelta() { + table := []struct { + name string + err error + expect assert.BoolAssertionFunc + }{ + { + name: "nil", + err: nil, + expect: assert.False, + }, + { + name: "non-matching", + err: assert.AnError, + expect: assert.False, + }, + { + name: "as", + err: ErrInvalidDelta{Err: *common.EncapsulateError(assert.AnError)}, + expect: assert.True, + }, + { + name: "non-matching oDataErr", + err: odErr("fnords"), + expect: assert.False, + }, + { + name: "resync-required oDataErr", + err: odErr(errCodeResyncRequired), + expect: assert.True, + }, + } + for _, test := range table { + suite.T().Run(test.name, func(t *testing.T) { + test.expect(t, IsErrInvalidDelta(test.err)) + }) + } +} + +func (suite *GraphErrorsUnitSuite) TestIsErrTimeout() { + table := []struct { + name string + err error + expect assert.BoolAssertionFunc + }{ + { + name: "nil", + err: nil, + expect: assert.False, + }, + { + name: "non-matching", + err: assert.AnError, + expect: assert.False, + }, + { + name: "as", + err: ErrTimeout{Err: *common.EncapsulateError(assert.AnError)}, + expect: assert.True, + }, + { + name: "context deadline", + err: context.DeadlineExceeded, + expect: assert.True, + }, + } + for _, test := range table { + suite.T().Run(test.name, func(t *testing.T) { + test.expect(t, IsErrTimeout(test.err)) + }) + } +} + +func (suite *GraphErrorsUnitSuite) TestIsErrThrottled() { + table := []struct { + name string + err error + expect assert.BoolAssertionFunc + }{ + { + name: "nil", + err: nil, + expect: assert.False, + }, + { + name: "non-matching", + err: assert.AnError, + expect: assert.False, + }, + { + name: "as", + err: ErrThrottled{Err: *common.EncapsulateError(assert.AnError)}, + expect: assert.True, + }, + { + name: "is429", + err: Err429TooManyRequests, + expect: assert.True, + }, + } + for _, test := range table { + suite.T().Run(test.name, func(t *testing.T) { + test.expect(t, IsErrThrottled(test.err)) + }) + } +} + +func (suite *GraphErrorsUnitSuite) TestIsErrUnauthorized() { + table := []struct { + name string + err error + expect assert.BoolAssertionFunc + }{ + { + name: "nil", + err: nil, + expect: assert.False, + }, + { + name: "non-matching", + err: assert.AnError, + expect: assert.False, + }, + { + name: "as", + err: ErrUnauthorized{Err: *common.EncapsulateError(assert.AnError)}, + expect: assert.True, + }, + { + name: "is429", + err: Err401Unauthorized, + expect: assert.True, + }, + } + for _, test := range table { + suite.T().Run(test.name, func(t *testing.T) { + test.expect(t, IsErrUnauthorized(test.err)) + }) + } +} + +func (suite *GraphErrorsUnitSuite) TestIsInternalServerError() { + table := []struct { + name string + err error + expect assert.BoolAssertionFunc + }{ + { + name: "nil", + err: nil, + expect: assert.False, + }, + { + name: "non-matching", + err: assert.AnError, + expect: assert.False, + }, + { + name: "as", + err: ErrInternalServerError{Err: *common.EncapsulateError(assert.AnError)}, + expect: assert.True, + }, + { + name: "is429", + err: Err500InternalServerError, + expect: assert.True, + }, + } + for _, test := range table { + suite.T().Run(test.name, func(t *testing.T) { + test.expect(t, IsInternalServerError(test.err)) + }) + } +} diff --git a/src/internal/connector/graph/service.go b/src/internal/connector/graph/service.go index 6c0e6dbc1..fd6142028 100644 --- a/src/internal/connector/graph/service.go +++ b/src/internal/connector/graph/service.go @@ -8,6 +8,7 @@ import ( "time" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + "github.com/alcionai/corso/src/internal/connector/support" "github.com/microsoft/kiota-abstractions-go/serialization" ka "github.com/microsoft/kiota-authentication-azure-go" khttp "github.com/microsoft/kiota-http-go" @@ -22,6 +23,7 @@ import ( const ( logGraphRequestsEnvKey = "LOG_GRAPH_REQUESTS" + numberOfRetries = 3 ) // AllMetadataFileNames produces the standard set of filenames used to store graph @@ -149,7 +151,7 @@ func HTTPClient(opts ...option) *http.Client { middlewares := msgraphgocore.GetDefaultMiddlewaresWithOptions(&clientOptions) middlewares = append(middlewares, &LoggingMiddleware{}) httpClient := msgraphgocore.GetDefaultClient(&clientOptions, middlewares...) - httpClient.Timeout = time.Second * 90 + httpClient.Timeout = time.Minute * 3 (&clientConfig{}). populate(opts...). @@ -250,7 +252,6 @@ func (handler *LoggingMiddleware) Intercept( respDump, _ := httputil.DumpResponse(resp, false) metadata := []any{ - "idx", middlewareIndex, "method", req.Method, "status", resp.Status, "statusCode", resp.StatusCode, @@ -273,7 +274,6 @@ func (handler *LoggingMiddleware) Intercept( respDump, _ := httputil.DumpResponse(resp, true) metadata := []any{ - "idx", middlewareIndex, "method", req.Method, "status", resp.Status, "statusCode", resp.StatusCode, @@ -296,3 +296,26 @@ func (handler *LoggingMiddleware) Intercept( return resp, err } + +// Run a function with retries +func RunWithRetry(run func() error) error { + var err error + + for i := 0; i < numberOfRetries; i++ { + err = run() + if err == nil { + return nil + } + + // only retry on timeouts and 500-internal-errors. + if !(IsErrTimeout(err) || IsInternalServerError(err)) { + break + } + + if i < numberOfRetries { + time.Sleep(time.Duration(3*(i+2)) * time.Second) + } + } + + return support.ConnectorStackErrorTraceWrap(err, "maximum retries or unretryable") +} diff --git a/src/internal/connector/graph/service_test.go b/src/internal/connector/graph/service_test.go index 14bdc9c36..c2ef2d699 100644 --- a/src/internal/connector/graph/service_test.go +++ b/src/internal/connector/graph/service_test.go @@ -53,7 +53,7 @@ func (suite *GraphUnitSuite) TestHTTPClient() { name: "no options", opts: []option{}, check: func(t *testing.T, c *http.Client) { - assert.Equal(t, 90*time.Second, c.Timeout, "default timeout") + assert.Equal(t, 3*time.Minute, c.Timeout, "default timeout") }, }, { diff --git a/src/internal/connector/graph_connector.go b/src/internal/connector/graph_connector.go index 3dbc0e60c..def430f14 100644 --- a/src/internal/connector/graph_connector.go +++ b/src/internal/connector/graph_connector.go @@ -266,9 +266,11 @@ func (gc *GraphConnector) UnionSiteIDsAndWebURLs(ctx context.Context, ids, urls // SideEffect: gc.status is updated at the completion of operation func (gc *GraphConnector) RestoreDataCollections( ctx context.Context, + backupVersion int, acct account.Account, selector selectors.Selector, dest control.RestoreDestination, + opts control.Options, dcs []data.Collection, ) (*details.Details, error) { ctx, end := D.Span(ctx, "connector:restore") @@ -289,9 +291,9 @@ func (gc *GraphConnector) RestoreDataCollections( case selectors.ServiceExchange: status, err = exchange.RestoreExchangeDataCollections(ctx, creds, gc.Service, dest, dcs, deets) case selectors.ServiceOneDrive: - status, err = onedrive.RestoreCollections(ctx, gc.Service, dest, dcs, deets) + status, err = onedrive.RestoreCollections(ctx, backupVersion, gc.Service, dest, opts, dcs, deets) case selectors.ServiceSharePoint: - status, err = sharepoint.RestoreCollections(ctx, gc.Service, dest, dcs, deets) + status, err = sharepoint.RestoreCollections(ctx, backupVersion, gc.Service, dest, dcs, deets) default: err = errors.Errorf("restore data from service %s not supported", selector.Service.String()) } diff --git a/src/internal/connector/graph_connector_helper_test.go b/src/internal/connector/graph_connector_helper_test.go index 698ee8527..539cbf501 100644 --- a/src/internal/connector/graph_connector_helper_test.go +++ b/src/internal/connector/graph_connector_helper_test.go @@ -2,9 +2,11 @@ package connector import ( "context" + "encoding/json" "io" "net/http" "reflect" + "strings" "testing" "github.com/microsoftgraph/msgraph-sdk-go/models" @@ -14,6 +16,7 @@ import ( "golang.org/x/exp/maps" "github.com/alcionai/corso/src/internal/connector/mockconnector" + "github.com/alcionai/corso/src/internal/connector/onedrive" "github.com/alcionai/corso/src/internal/connector/support" "github.com/alcionai/corso/src/internal/data" "github.com/alcionai/corso/src/internal/tester" @@ -169,6 +172,14 @@ type restoreBackupInfo struct { resource resource } +type restoreBackupInfoMultiVersion struct { + name string + service path.ServiceType + collectionsLatest []colInfo + collectionsPrevious []colInfo + resource resource +} + func attachmentEqual( expected models.Attachmentable, got models.Attachmentable, @@ -645,21 +656,52 @@ func compareOneDriveItem( t *testing.T, expected map[string][]byte, item data.Stream, + restorePermissions bool, ) { + name := item.UUID() + expectedData := expected[item.UUID()] - if !assert.NotNil(t, expectedData, "unexpected file with name %s", item.UUID) { + if !assert.NotNil(t, expectedData, "unexpected file with name %s", item.UUID()) { return } - // OneDrive items are just byte buffers of the data. Nothing special to - // interpret. May need to do chunked comparisons in the future if we test - // large item equality. buf, err := io.ReadAll(item.ToReader()) if !assert.NoError(t, err) { return } - assert.Equal(t, expectedData, buf) + if !strings.HasSuffix(name, onedrive.MetaFileSuffix) && !strings.HasSuffix(name, onedrive.DirMetaFileSuffix) { + // OneDrive data items are just byte buffers of the data. Nothing special to + // interpret. May need to do chunked comparisons in the future if we test + // large item equality. + assert.Equal(t, expectedData, buf) + return + } + + var ( + itemMeta onedrive.Metadata + expectedMeta onedrive.Metadata + ) + + err = json.Unmarshal(buf, &itemMeta) + assert.Nil(t, err) + + err = json.Unmarshal(expectedData, &expectedMeta) + assert.Nil(t, err) + + if !restorePermissions { + assert.Equal(t, 0, len(itemMeta.Permissions)) + return + } + + assert.Equal(t, len(expectedMeta.Permissions), len(itemMeta.Permissions), "number of permissions after restore") + + // FIXME(meain): The permissions before and after might not be in the same order. + for i, p := range expectedMeta.Permissions { + assert.Equal(t, p.Email, itemMeta.Permissions[i].Email) + assert.Equal(t, p.Roles, itemMeta.Permissions[i].Roles) + assert.Equal(t, p.Expiration, itemMeta.Permissions[i].Expiration) + } } func compareItem( @@ -668,6 +710,7 @@ func compareItem( service path.ServiceType, category path.CategoryType, item data.Stream, + restorePermissions bool, ) { if mt, ok := item.(data.StreamModTime); ok { assert.NotZero(t, mt.ModTime()) @@ -687,7 +730,7 @@ func compareItem( } case path.OneDriveService: - compareOneDriveItem(t, expected, item) + compareOneDriveItem(t, expected, item, restorePermissions) default: assert.FailNowf(t, "unexpected service: %s", service.String()) @@ -720,6 +763,7 @@ func checkCollections( expectedItems int, expected map[string]map[string][]byte, got []data.Collection, + restorePermissions bool, ) int { collectionsWithItems := []data.Collection{} @@ -754,7 +798,7 @@ func checkCollections( continue } - compareItem(t, expectedColData, service, category, item) + compareItem(t, expectedColData, service, category, item, restorePermissions) } if gotItems != startingItems { @@ -906,10 +950,63 @@ func collectionsForInfo( tenant, user string, dest control.RestoreDestination, allInfo []colInfo, -) (int, []data.Collection, map[string]map[string][]byte) { +) (int, int, []data.Collection, map[string]map[string][]byte) { collections := make([]data.Collection, 0, len(allInfo)) expectedData := make(map[string]map[string][]byte, len(allInfo)) totalItems := 0 + kopiaEntries := 0 + + for _, info := range allInfo { + pth := mustToDataLayerPath( + t, + service, + tenant, + user, + info.category, + info.pathElements, + false, + ) + c := mockconnector.NewMockExchangeCollection(pth, len(info.items)) + baseDestPath := backupOutputPathFromRestore(t, dest, pth) + + baseExpected := expectedData[baseDestPath.String()] + if baseExpected == nil { + expectedData[baseDestPath.String()] = make(map[string][]byte, len(info.items)) + baseExpected = expectedData[baseDestPath.String()] + } + + for i := 0; i < len(info.items); i++ { + c.Names[i] = info.items[i].name + c.Data[i] = info.items[i].data + + baseExpected[info.items[i].lookupKey] = info.items[i].data + + // We do not count metadata files against item count + if service != path.OneDriveService || + (service == path.OneDriveService && + strings.HasSuffix(info.items[i].name, onedrive.DataFileSuffix)) { + totalItems++ + } + } + + collections = append(collections, c) + kopiaEntries += len(info.items) + } + + return totalItems, kopiaEntries, collections, expectedData +} + +func collectionsForInfoVersion0( + t *testing.T, + service path.ServiceType, + tenant, user string, + dest control.RestoreDestination, + allInfo []colInfo, +) (int, int, []data.Collection, map[string]map[string][]byte) { + collections := make([]data.Collection, 0, len(allInfo)) + expectedData := make(map[string]map[string][]byte, len(allInfo)) + totalItems := 0 + kopiaEntries := 0 for _, info := range allInfo { pth := mustToDataLayerPath( @@ -939,9 +1036,10 @@ func collectionsForInfo( collections = append(collections, c) totalItems += len(info.items) + kopiaEntries += len(info.items) } - return totalItems, collections, expectedData + return totalItems, kopiaEntries, collections, expectedData } //nolint:deadcode diff --git a/src/internal/connector/graph_connector_test.go b/src/internal/connector/graph_connector_test.go index be1439c35..b3b55a15e 100644 --- a/src/internal/connector/graph_connector_test.go +++ b/src/internal/connector/graph_connector_test.go @@ -2,6 +2,8 @@ package connector import ( "context" + "encoding/base64" + "encoding/json" "strings" "testing" "time" @@ -15,10 +17,12 @@ import ( "github.com/alcionai/corso/src/internal/connector/discovery/api" "github.com/alcionai/corso/src/internal/connector/graph" "github.com/alcionai/corso/src/internal/connector/mockconnector" + "github.com/alcionai/corso/src/internal/connector/onedrive" "github.com/alcionai/corso/src/internal/connector/support" "github.com/alcionai/corso/src/internal/data" "github.com/alcionai/corso/src/internal/tester" "github.com/alcionai/corso/src/pkg/account" + "github.com/alcionai/corso/src/pkg/backup" "github.com/alcionai/corso/src/pkg/control" "github.com/alcionai/corso/src/pkg/path" "github.com/alcionai/corso/src/pkg/selectors" @@ -135,9 +139,10 @@ func (suite *GraphConnectorUnitSuite) TestUnionSiteIDsAndWebURLs() { type GraphConnectorIntegrationSuite struct { suite.Suite - connector *GraphConnector - user string - acct account.Account + connector *GraphConnector + user string + secondaryUser string + acct account.Account } func TestGraphConnectorIntegrationSuite(t *testing.T) { @@ -158,6 +163,7 @@ func (suite *GraphConnectorIntegrationSuite) SetupSuite() { suite.connector = loadConnector(ctx, suite.T(), graph.HTTPClient(graph.NoTimeout()), Users) suite.user = tester.M365UserID(suite.T()) + suite.secondaryUser = tester.SecondaryM365UserID(suite.T()) suite.acct = tester.NewM365Account(suite.T()) tester.LogTimeOfTest(suite.T()) @@ -226,7 +232,18 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreFailsBadService() { } ) - deets, err := suite.connector.RestoreDataCollections(ctx, acct, sel, dest, nil) + deets, err := suite.connector.RestoreDataCollections( + ctx, + backup.Version, + acct, + sel, + dest, + control.Options{ + RestorePermissions: true, + ToggleFeatures: control.Toggles{EnablePermissionsBackup: true}, + }, + nil, + ) assert.Error(t, err) assert.NotNil(t, deets) @@ -294,10 +311,16 @@ func (suite *GraphConnectorIntegrationSuite) TestEmptyCollections() { deets, err := suite.connector.RestoreDataCollections( ctx, + backup.Version, suite.acct, test.sel, dest, - test.col) + control.Options{ + RestorePermissions: true, + ToggleFeatures: control.Toggles{EnablePermissionsBackup: true}, + }, + test.col, + ) require.NoError(t, err) assert.NotNil(t, deets) @@ -344,11 +367,13 @@ func runRestoreBackupTest( test restoreBackupInfo, tenant string, resourceOwners []string, + opts control.Options, ) { var ( - collections []data.Collection - expectedData = map[string]map[string][]byte{} - totalItems = 0 + collections []data.Collection + expectedData = map[string]map[string][]byte{} + totalItems = 0 + totalKopiaItems = 0 // Get a dest per test so they're independent. dest = tester.DefaultTestRestoreDestination() ) @@ -357,7 +382,7 @@ func runRestoreBackupTest( defer flush() for _, owner := range resourceOwners { - numItems, ownerCollections, userExpectedData := collectionsForInfo( + numItems, kopiaItems, ownerCollections, userExpectedData := collectionsForInfo( t, test.service, tenant, @@ -368,6 +393,7 @@ func runRestoreBackupTest( collections = append(collections, ownerCollections...) totalItems += numItems + totalKopiaItems += kopiaItems maps.Copy(expectedData, userExpectedData) } @@ -383,10 +409,13 @@ func runRestoreBackupTest( restoreSel := getSelectorWith(t, test.service, resourceOwners, true) deets, err := restoreGC.RestoreDataCollections( ctx, + backup.Version, acct, restoreSel, dest, - collections) + opts, + collections, + ) require.NoError(t, err) assert.NotNil(t, deets) @@ -425,7 +454,15 @@ func runRestoreBackupTest( t.Logf("Selective backup of %s\n", backupSel) start = time.Now() - dcs, excludes, err := backupGC.DataCollections(ctx, backupSel, nil, control.Options{}) + dcs, excludes, err := backupGC.DataCollections( + ctx, + backupSel, + nil, + control.Options{ + RestorePermissions: true, + ToggleFeatures: control.Toggles{EnablePermissionsBackup: true}, + }, + ) require.NoError(t, err) // No excludes yet because this isn't an incremental backup. assert.Empty(t, excludes) @@ -434,7 +471,7 @@ func runRestoreBackupTest( // Pull the data prior to waiting for the status as otherwise it will // deadlock. - skipped := checkCollections(t, totalItems, expectedData, dcs) + skipped := checkCollections(t, totalKopiaItems, expectedData, dcs, opts.RestorePermissions) status = backupGC.AwaitStatus() @@ -446,6 +483,143 @@ func runRestoreBackupTest( "backup status.Successful; wanted %d items + %d skipped", totalItems, skipped) } +// runRestoreBackupTestVersion0 restores with data from an older +// version of the backup and check the restored data against the +// something that would be in the form of a newer backup. +func runRestoreBackupTestVersion0( + t *testing.T, + acct account.Account, + test restoreBackupInfoMultiVersion, + tenant string, + resourceOwners []string, + opts control.Options, +) { + var ( + collections []data.Collection + expectedData = map[string]map[string][]byte{} + totalItems = 0 + totalKopiaItems = 0 + // Get a dest per test so they're independent. + dest = tester.DefaultTestRestoreDestination() + ) + + ctx, flush := tester.NewContext() + defer flush() + + for _, owner := range resourceOwners { + _, _, ownerCollections, _ := collectionsForInfoVersion0( + t, + test.service, + tenant, + owner, + dest, + test.collectionsPrevious, + ) + + collections = append(collections, ownerCollections...) + } + + t.Logf( + "Restoring collections to %s for resourceOwners(s) %v\n", + dest.ContainerName, + resourceOwners, + ) + + start := time.Now() + + restoreGC := loadConnector(ctx, t, graph.HTTPClient(graph.NoTimeout()), test.resource) + restoreSel := getSelectorWith(t, test.service, resourceOwners, true) + deets, err := restoreGC.RestoreDataCollections( + ctx, + 0, // The OG version ;) + acct, + restoreSel, + dest, + opts, + collections, + ) + require.NoError(t, err) + assert.NotNil(t, deets) + + assert.NotNil(t, restoreGC.AwaitStatus()) + + runTime := time.Since(start) + + t.Logf("Restore complete in %v\n", runTime) + + // Run a backup and compare its output with what we put in. + for _, owner := range resourceOwners { + numItems, kopiaItems, _, userExpectedData := collectionsForInfo( + t, + test.service, + tenant, + owner, + dest, + test.collectionsLatest, + ) + + totalItems += numItems + totalKopiaItems += kopiaItems + + maps.Copy(expectedData, userExpectedData) + } + + cats := make(map[path.CategoryType]struct{}, len(test.collectionsLatest)) + for _, c := range test.collectionsLatest { + cats[c.category] = struct{}{} + } + + expectedDests := make([]destAndCats, 0, len(resourceOwners)) + for _, ro := range resourceOwners { + expectedDests = append(expectedDests, destAndCats{ + resourceOwner: ro, + dest: dest.ContainerName, + cats: cats, + }) + } + + backupGC := loadConnector(ctx, t, graph.HTTPClient(graph.NoTimeout()), test.resource) + backupSel := backupSelectorForExpected(t, test.service, expectedDests) + + start = time.Now() + dcs, excludes, err := backupGC.DataCollections( + ctx, + backupSel, + nil, + control.Options{ + RestorePermissions: true, + ToggleFeatures: control.Toggles{EnablePermissionsBackup: true}, + }, + ) + require.NoError(t, err) + // No excludes yet because this isn't an incremental backup. + assert.Empty(t, excludes) + + t.Logf("Backup enumeration complete in %v\n", time.Since(start)) + + // Pull the data prior to waiting for the status as otherwise it will + // deadlock. + skipped := checkCollections(t, totalKopiaItems, expectedData, dcs, opts.RestorePermissions) + + status := backupGC.AwaitStatus() + assert.Equal(t, totalItems+skipped, status.ObjectCount, "status.ObjectCount") + assert.Equal(t, totalItems+skipped, status.Successful, "status.Successful") +} + +func getTestMetaJSON(t *testing.T, user string, roles []string) []byte { + id := base64.StdEncoding.EncodeToString([]byte(user + strings.Join(roles, "+"))) + testMeta := onedrive.Metadata{Permissions: []onedrive.UserPermission{ + {ID: id, Roles: roles, Email: user}, + }} + + testMetaJSON, err := json.Marshal(testMeta) + if err != nil { + t.Fatal("unable to marshall test permissions", err) + } + + return testMetaJSON +} + func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() { bodyText := "This email has some text. However, all the text is on the same line." subjectText := "Test message for restore" @@ -564,7 +738,7 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() { }, }, { - name: "MultipleContactsMutlipleFolders", + name: "MultipleContactsMultipleFolders", service: path.ExchangeService, resource: Users, collections: []colInfo{ @@ -682,6 +856,226 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() { service: path.OneDriveService, resource: Users, collections: []colInfo{ + { + pathElements: []string{ + "drives", + driveID, + "root:", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("a", 33)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: []byte("{}"), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + { + name: "folder-a" + onedrive.DirMetaFileSuffix, + data: []byte("{}"), + lookupKey: "folder-a" + onedrive.DirMetaFileSuffix, + }, + { + name: "b" + onedrive.DirMetaFileSuffix, + data: []byte("{}"), + lookupKey: "b" + onedrive.DirMetaFileSuffix, + }, + }, + }, + { + pathElements: []string{ + "drives", + driveID, + "root:", + "folder-a", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("b", 65)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: []byte("{}"), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + { + name: "b" + onedrive.DirMetaFileSuffix, + data: []byte("{}"), + lookupKey: "b" + onedrive.DirMetaFileSuffix, + }, + }, + }, + { + pathElements: []string{ + "drives", + driveID, + "root:", + "folder-a", + "b", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("c", 129)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: []byte("{}"), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + { + name: "folder-a" + onedrive.DirMetaFileSuffix, + data: []byte("{}"), + lookupKey: "folder-a" + onedrive.DirMetaFileSuffix, + }, + }, + }, + { + pathElements: []string{ + "drives", + driveID, + "root:", + "folder-a", + "b", + "folder-a", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("d", 257)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: []byte("{}"), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + }, + }, + { + pathElements: []string{ + "drives", + driveID, + "root:", + "b", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("e", 257)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: []byte("{}"), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + }, + }, + }, + }, + { + name: "OneDriveFoldersAndFilesWithMetadata", + service: path.OneDriveService, + resource: Users, + collections: []colInfo{ + { + pathElements: []string{ + "drives", + driveID, + "root:", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("a", 33)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"write"}), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + { + name: "b" + onedrive.DirMetaFileSuffix, + data: getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"read"}), + lookupKey: "b" + onedrive.DirMetaFileSuffix, + }, + }, + }, + { + pathElements: []string{ + "drives", + driveID, + "root:", + "b", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("e", 66)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"read"}), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + }, + }, + }, + }, + } + + for _, test := range table { + suite.T().Run(test.name, func(t *testing.T) { + runRestoreBackupTest( + t, + suite.acct, + test, + suite.connector.tenant, + []string{suite.user}, + control.Options{ + RestorePermissions: true, + ToggleFeatures: control.Toggles{EnablePermissionsBackup: true}, + }, + ) + }) + } +} + +func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackupVersion0() { + ctx, flush := tester.NewContext() + defer flush() + + // Get the default drive ID for the test user. + driveID := mustGetDefaultDriveID( + suite.T(), + ctx, + suite.connector.Service, + suite.user, + ) + + table := []restoreBackupInfoMultiVersion{ + { + name: "OneDriveMultipleFoldersAndFiles", + service: path.OneDriveService, + resource: Users, + + collectionsPrevious: []colInfo{ { pathElements: []string{ "drives", @@ -765,12 +1159,152 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup() { }, }, }, + + collectionsLatest: []colInfo{ + { + pathElements: []string{ + "drives", + driveID, + "root:", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("a", 33)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: []byte("{}"), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + { + name: "folder-a" + onedrive.DirMetaFileSuffix, + data: []byte("{}"), + lookupKey: "folder-a" + onedrive.DirMetaFileSuffix, + }, + { + name: "b" + onedrive.DirMetaFileSuffix, + data: []byte("{}"), + lookupKey: "b" + onedrive.DirMetaFileSuffix, + }, + }, + }, + { + pathElements: []string{ + "drives", + driveID, + "root:", + "folder-a", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("b", 65)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: []byte("{}"), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + { + name: "b" + onedrive.DirMetaFileSuffix, + data: []byte("{}"), + lookupKey: "b" + onedrive.DirMetaFileSuffix, + }, + }, + }, + { + pathElements: []string{ + "drives", + driveID, + "root:", + "folder-a", + "b", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("c", 129)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: []byte("{}"), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + { + name: "folder-a" + onedrive.DirMetaFileSuffix, + data: []byte("{}"), + lookupKey: "folder-a" + onedrive.DirMetaFileSuffix, + }, + }, + }, + { + pathElements: []string{ + "drives", + driveID, + "root:", + "folder-a", + "b", + "folder-a", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("d", 257)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: []byte("{}"), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + }, + }, + { + pathElements: []string{ + "drives", + driveID, + "root:", + "b", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("e", 257)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: []byte("{}"), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + }, + }, + }, }, } for _, test := range table { suite.T().Run(test.name, func(t *testing.T) { - runRestoreBackupTest(t, suite.acct, test, suite.connector.tenant, []string{suite.user}) + runRestoreBackupTestVersion0( + t, + suite.acct, + test, + suite.connector.tenant, + []string{suite.user}, + control.Options{ + RestorePermissions: true, + ToggleFeatures: control.Toggles{EnablePermissionsBackup: true}, + }, + ) }) } } @@ -857,7 +1391,7 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames }, }) - totalItems, collections, expectedData := collectionsForInfo( + totalItems, _, collections, expectedData := collectionsForInfo( t, test.service, suite.connector.tenant, @@ -879,7 +1413,18 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames ) restoreGC := loadConnector(ctx, t, graph.HTTPClient(graph.NoTimeout()), test.resource) - deets, err := restoreGC.RestoreDataCollections(ctx, suite.acct, restoreSel, dest, collections) + deets, err := restoreGC.RestoreDataCollections( + ctx, + backup.Version, + suite.acct, + restoreSel, + dest, + control.Options{ + RestorePermissions: true, + ToggleFeatures: control.Toggles{EnablePermissionsBackup: true}, + }, + collections, + ) require.NoError(t, err) require.NotNil(t, deets) @@ -900,7 +1445,15 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames backupSel := backupSelectorForExpected(t, test.service, expectedDests) t.Log("Selective backup of", backupSel) - dcs, excludes, err := backupGC.DataCollections(ctx, backupSel, nil, control.Options{}) + dcs, excludes, err := backupGC.DataCollections( + ctx, + backupSel, + nil, + control.Options{ + RestorePermissions: true, + ToggleFeatures: control.Toggles{EnablePermissionsBackup: true}, + }, + ) require.NoError(t, err) // No excludes yet because this isn't an incremental backup. assert.Empty(t, excludes) @@ -909,7 +1462,7 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames // Pull the data prior to waiting for the status as otherwise it will // deadlock. - skipped := checkCollections(t, allItems, allExpectedData, dcs) + skipped := checkCollections(t, allItems, allExpectedData, dcs, true) status := backupGC.AwaitStatus() assert.Equal(t, allItems+skipped, status.ObjectCount, "status.ObjectCount") @@ -918,6 +1471,319 @@ func (suite *GraphConnectorIntegrationSuite) TestMultiFolderBackupDifferentNames } } +func (suite *GraphConnectorIntegrationSuite) TestPermissionsRestoreAndBackup() { + ctx, flush := tester.NewContext() + defer flush() + + // Get the default drive ID for the test user. + driveID := mustGetDefaultDriveID( + suite.T(), + ctx, + suite.connector.Service, + suite.user, + ) + + table := []restoreBackupInfo{ + { + name: "FilePermissionsRestore", + service: path.OneDriveService, + resource: Users, + collections: []colInfo{ + { + pathElements: []string{ + "drives", + driveID, + "root:", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("a", 33)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"write"}), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + }, + }, + }, + }, + + { + name: "FileInsideFolderPermissionsRestore", + service: path.OneDriveService, + resource: Users, + collections: []colInfo{ + { + pathElements: []string{ + "drives", + driveID, + "root:", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("a", 33)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: []byte("{}"), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + { + name: "b" + onedrive.DirMetaFileSuffix, + data: []byte("{}"), + lookupKey: "b" + onedrive.DirMetaFileSuffix, + }, + }, + }, + { + pathElements: []string{ + "drives", + driveID, + "root:", + "b", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("e", 66)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"read"}), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + }, + }, + }, + }, + + { + name: "FileAndFolderPermissionsResote", + service: path.OneDriveService, + resource: Users, + collections: []colInfo{ + { + pathElements: []string{ + "drives", + driveID, + "root:", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("a", 33)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"write"}), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + { + name: "b" + onedrive.DirMetaFileSuffix, + data: getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"read"}), + lookupKey: "b" + onedrive.DirMetaFileSuffix, + }, + }, + }, + { + pathElements: []string{ + "drives", + driveID, + "root:", + "b", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("e", 66)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"read"}), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + }, + }, + }, + }, + + { + name: "FileAndFolderSeparatePermissionsResote", + service: path.OneDriveService, + resource: Users, + collections: []colInfo{ + { + pathElements: []string{ + "drives", + driveID, + "root:", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "b" + onedrive.DirMetaFileSuffix, + data: getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"read"}), + lookupKey: "b" + onedrive.DirMetaFileSuffix, + }, + }, + }, + { + pathElements: []string{ + "drives", + driveID, + "root:", + "b", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("e", 66)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"write"}), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + }, + }, + }, + }, + + { + name: "FolderAndNoChildPermissionsResote", + service: path.OneDriveService, + resource: Users, + collections: []colInfo{ + { + pathElements: []string{ + "drives", + driveID, + "root:", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "b" + onedrive.DirMetaFileSuffix, + data: getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"read"}), + lookupKey: "b" + onedrive.DirMetaFileSuffix, + }, + }, + }, + { + pathElements: []string{ + "drives", + driveID, + "root:", + "b", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("e", 66)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: []byte("{}"), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + }, + }, + }, + }, + } + + for _, test := range table { + suite.T().Run(test.name, func(t *testing.T) { + runRestoreBackupTest(t, + suite.acct, + test, + suite.connector.tenant, + []string{suite.user}, + control.Options{ + RestorePermissions: true, + ToggleFeatures: control.Toggles{EnablePermissionsBackup: true}, + }, + ) + }) + } +} + +func (suite *GraphConnectorIntegrationSuite) TestPermissionsBackupAndNoRestore() { + ctx, flush := tester.NewContext() + defer flush() + + // Get the default drive ID for the test user. + driveID := mustGetDefaultDriveID( + suite.T(), + ctx, + suite.connector.Service, + suite.user, + ) + + table := []restoreBackupInfo{ + { + name: "FilePermissionsRestore", + service: path.OneDriveService, + resource: Users, + collections: []colInfo{ + { + pathElements: []string{ + "drives", + driveID, + "root:", + }, + category: path.FilesCategory, + items: []itemInfo{ + { + name: "test-file.txt" + onedrive.DataFileSuffix, + data: []byte(strings.Repeat("a", 33)), + lookupKey: "test-file.txt" + onedrive.DataFileSuffix, + }, + { + name: "test-file.txt" + onedrive.MetaFileSuffix, + data: getTestMetaJSON(suite.T(), suite.secondaryUser, []string{"write"}), + lookupKey: "test-file.txt" + onedrive.MetaFileSuffix, + }, + }, + }, + }, + }, + } + + for _, test := range table { + suite.T().Run(test.name, func(t *testing.T) { + runRestoreBackupTest( + t, + suite.acct, + test, + suite.connector.tenant, + []string{suite.user}, + control.Options{ + RestorePermissions: true, + ToggleFeatures: control.Toggles{EnablePermissionsBackup: true}, + }, + ) + }) + } +} + // TODO: this should only be run during smoke tests, not part of the standard CI. // That's why it's set aside instead of being included in the other test set. func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup_largeMailAttachment() { @@ -942,5 +1808,15 @@ func (suite *GraphConnectorIntegrationSuite) TestRestoreAndBackup_largeMailAttac }, } - runRestoreBackupTest(suite.T(), suite.acct, test, suite.connector.tenant, []string{suite.user}) + runRestoreBackupTest( + suite.T(), + suite.acct, + test, + suite.connector.tenant, + []string{suite.user}, + control.Options{ + RestorePermissions: true, + ToggleFeatures: control.Toggles{EnablePermissionsBackup: true}, + }, + ) } diff --git a/src/internal/connector/mockconnector/mock_data_collection_test.go b/src/internal/connector/mockconnector/mock_data_collection_test.go index 2af9236c4..f2ba4d08e 100644 --- a/src/internal/connector/mockconnector/mock_data_collection_test.go +++ b/src/internal/connector/mockconnector/mock_data_collection_test.go @@ -202,6 +202,15 @@ func (suite *MockExchangeDataSuite) TestMockByteHydration() { return err }, }, + { + name: "SharePoint: Page", + transformation: func(t *testing.T) error { + bytes := mockconnector.GetMockPage(subject) + _, err := support.CreatePageFromBytes(bytes) + + return err + }, + }, } for _, test := range tests { diff --git a/src/internal/connector/mockconnector/mock_data_message.go b/src/internal/connector/mockconnector/mock_data_message.go index 597447492..4c2e84235 100644 --- a/src/internal/connector/mockconnector/mock_data_message.go +++ b/src/internal/connector/mockconnector/mock_data_message.go @@ -336,3 +336,212 @@ func GetMockEventMessageRequest(subject string) []byte { return []byte(message) } + +func GetMockMessageWithItemAttachmentEvent(subject string) []byte { + //nolint:lll + message := "{\"id\":\"AAMkAGQ1NzViZTdhLTEwMTMtNGJjNi05YWI2LTg4NWRlZDA2Y2UxOABGAAAAAAAPvVwUramXT7jlSGpVU8_7BwB8wYc0thTTTYl3RpEYIUq_AAAAAAEMAAB8wYc0thTTTYl3RpEYIUq_AADFfThMAAA=\",\"@odata.type\":\"#microsoft.graph.message\"," + + "\"@odata.etag\":\"W/\\\"CQAAABYAAAB8wYc0thTTTYl3RpEYIUq+AADFK3BH\\\"\",\"@odata.context\":\"https://graph.microsoft.com/v1.0/$metadata#users('dustina%408qzvrj.onmicrosoft.com')/messages/$entity\",\"categories\":[]," + + "\"changeKey\":\"CQAAABYAAAB8wYc0thTTTYl3RpEYIUq+AADFK3BH\",\"createdDateTime\":\"2023-02-01T13:48:43Z\",\"lastModifiedDateTime\":\"2023-02-01T18:27:03Z\"," + + "\"attachments\":[{\"id\":\"AAMkAGQ1NzViZTdhLTEwMTMtNGJjNi05YWI2LTg4NWRlZDA2Y2UxOABGAAAAAAAPvVwUramXT7jlSGpVU8_7BwB8wYc0thTTTYl3RpEYIUq_AAAAAAEMAAB8wYc0thTTTYl3RpEYIUq_AADFfThMAAABEgAQAKHxTL6mNCZPo71dbwrfKYM=\"," + + "\"@odata.type\":\"#microsoft.graph.itemAttachment\",\"isInline\":false,\"lastModifiedDateTime\":\"2023-02-01T13:52:56Z\",\"name\":\"Holidayevent\",\"size\":2059,\"item\":{\"id\":\"\",\"@odata.type\":\"#microsoft.graph.event\"," + + "\"createdDateTime\":\"2023-02-01T13:52:56Z\",\"lastModifiedDateTime\":\"2023-02-01T13:52:56Z\",\"body\":{\"content\":\"
\\r\\n