├── .gitignore
├── O365-Win-Snippets.sln
├── README.md
├── Readme-images
├── ConnectedServices.PNG
├── LaunchScreen.png
└── MainPage.png
└── src
├── App.xaml
├── App.xaml.cs
├── Assets
├── Logo.scale-100.png
├── Run.png
├── SmallLogo.scale-100.png
├── SplashScreen.scale-100.png
└── StoreLogo.scale-100.png
├── AuthenticationHelper.cs
├── Calendar
├── CalendarSnippets.cs
└── CalendarStories.cs
├── Contacts
├── ContactsSnippets.cs
└── ContactsStories.cs
├── DurationToDurationStringConverter.cs
├── Email
├── EmailSnippets.cs
└── EmailStories.cs
├── Files
├── FilesSnippets.cs
└── FilesStories.cs
├── MainPage.xaml
├── MainPage.xaml.cs
├── O365-Win-Snippets.csproj
├── OdataProxy exceptions.txt
├── Package.appxmanifest
├── Properties
└── AssemblyInfo.cs
├── ResultToBrushConverter.cs
├── StoryDefinition.cs
├── UsersAndGroups
├── UsersAndGroupsSnippets.cs
└── UsersAndGroupsStories.cs
├── ViewModelBase.cs
└── packages.config
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studo 2015 cache/options directory
26 | .vs/
27 |
28 | # MSTest test Results
29 | [Tt]est[Rr]esult*/
30 | [Bb]uild[Ll]og.*
31 |
32 | # NUNIT
33 | *.VisualState.xml
34 | TestResult.xml
35 |
36 | # Build Results of an ATL Project
37 | [Dd]ebugPS/
38 | [Rr]eleasePS/
39 | dlldata.c
40 |
41 | *_i.c
42 | *_p.c
43 | *_i.h
44 | *.ilk
45 | *.meta
46 | *.obj
47 | *.pch
48 | *.pdb
49 | *.pgc
50 | *.pgd
51 | *.rsp
52 | *.sbr
53 | *.tlb
54 | *.tli
55 | *.tlh
56 | *.tmp
57 | *.tmp_proj
58 | *.log
59 | *.vspscc
60 | *.vssscc
61 | .builds
62 | *.pidb
63 | *.svclog
64 | *.scc
65 |
66 | # Chutzpah Test files
67 | _Chutzpah*
68 |
69 | # Visual C++ cache files
70 | ipch/
71 | *.aps
72 | *.ncb
73 | *.opensdf
74 | *.sdf
75 | *.cachefile
76 |
77 | # Visual Studio profiler
78 | *.psess
79 | *.vsp
80 | *.vspx
81 |
82 | # TFS 2012 Local Workspace
83 | $tf/
84 |
85 | # Guidance Automation Toolkit
86 | *.gpState
87 |
88 | # ReSharper is a .NET coding add-in
89 | _ReSharper*/
90 | *.[Rr]e[Ss]harper
91 | *.DotSettings.user
92 |
93 | # JustCode is a .NET coding addin-in
94 | .JustCode
95 |
96 | # TeamCity is a build add-in
97 | _TeamCity*
98 |
99 | # DotCover is a Code Coverage Tool
100 | *.dotCover
101 |
102 | # NCrunch
103 | _NCrunch_*
104 | .*crunch*.local.xml
105 |
106 | # MightyMoose
107 | *.mm.*
108 | AutoTest.Net/
109 |
110 | # Web workbench (sass)
111 | .sass-cache/
112 |
113 | # Installshield output folder
114 | [Ee]xpress/
115 |
116 | # DocProject is a documentation generator add-in
117 | DocProject/buildhelp/
118 | DocProject/Help/*.HxT
119 | DocProject/Help/*.HxC
120 | DocProject/Help/*.hhc
121 | DocProject/Help/*.hhk
122 | DocProject/Help/*.hhp
123 | DocProject/Help/Html2
124 | DocProject/Help/html
125 |
126 | # Click-Once directory
127 | publish/
128 |
129 | # Publish Web Output
130 | *.[Pp]ublish.xml
131 | *.azurePubxml
132 | # TODO: Comment the next line if you want to checkin your web deploy settings
133 | # but database connection strings (with potential passwords) will be unencrypted
134 | *.pubxml
135 | *.publishproj
136 |
137 | # NuGet Packages
138 | *.nupkg
139 | # The packages folder can be ignored because of Package Restore
140 | **/packages/*
141 | # except build/, which is used as an MSBuild target.
142 | !**/packages/build/
143 | # Uncomment if necessary however generally it will be regenerated when needed
144 | #!**/packages/repositories.config
145 |
146 | # Windows Azure Build Output
147 | csx/
148 | *.build.csdef
149 |
150 | # Windows Store app package directory
151 | AppPackages/
152 |
153 | # Others
154 | *.[Cc]ache
155 | ClientBin/
156 | [Ss]tyle[Cc]op.*
157 | ~$*
158 | *~
159 | *.dbmdl
160 | *.dbproj.schemaview
161 | *.pfx
162 | *.publishsettings
163 | node_modules/
164 | bower_components/
165 |
166 | # RIA/Silverlight projects
167 | Generated_Code/
168 |
169 | # Backup & report files from converting an old project file
170 | # to a newer Visual Studio version. Backup files are not needed,
171 | # because we have git ;-)
172 | _UpgradeReport_Files/
173 | Backup*/
174 | UpgradeLog*.XML
175 | UpgradeLog*.htm
176 |
177 | # SQL Server files
178 | *.mdf
179 | *.ldf
180 |
181 | # Business Intelligence projects
182 | *.rdl.data
183 | *.bim.layout
184 | *.bim_*.settings
185 |
186 | # Microsoft Fakes
187 | FakesAssemblies/
188 |
189 | # Node.js Tools for Visual Studio
190 | .ntvs_analysis.dat
191 |
192 | # Visual Studio 6 build log
193 | *.plg
194 |
195 | # Visual Studio 6 workspace options file
196 | *.opt
197 |
--------------------------------------------------------------------------------
/O365-Win-Snippets.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.31101.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "O365-Win-Snippets", "src\O365-Win-Snippets.csproj", "{186CF7AD-D3B3-478E-B08B-650E71DCA726}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Debug|ARM = Debug|ARM
12 | Debug|x64 = Debug|x64
13 | Debug|x86 = Debug|x86
14 | Release|Any CPU = Release|Any CPU
15 | Release|ARM = Release|ARM
16 | Release|x64 = Release|x64
17 | Release|x86 = Release|x86
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
23 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Debug|ARM.ActiveCfg = Debug|ARM
24 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Debug|ARM.Build.0 = Debug|ARM
25 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Debug|ARM.Deploy.0 = Debug|ARM
26 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Debug|x64.ActiveCfg = Debug|x64
27 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Debug|x64.Build.0 = Debug|x64
28 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Debug|x64.Deploy.0 = Debug|x64
29 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Debug|x86.ActiveCfg = Debug|x86
30 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Debug|x86.Build.0 = Debug|x86
31 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Debug|x86.Deploy.0 = Debug|x86
32 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Release|Any CPU.Deploy.0 = Release|Any CPU
35 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Release|ARM.ActiveCfg = Release|ARM
36 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Release|ARM.Build.0 = Release|ARM
37 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Release|ARM.Deploy.0 = Release|ARM
38 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Release|x64.ActiveCfg = Release|x64
39 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Release|x64.Build.0 = Release|x64
40 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Release|x64.Deploy.0 = Release|x64
41 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Release|x86.ActiveCfg = Release|x86
42 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Release|x86.Build.0 = Release|x86
43 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}.Release|x86.Deploy.0 = Release|x86
44 | EndGlobalSection
45 | GlobalSection(SolutionProperties) = preSolution
46 | HideSolutionNode = FALSE
47 | EndGlobalSection
48 | EndGlobal
49 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [ARCHIVED] Office 365 Code Snippets for Windows
2 |
3 | **Note:** This repo is archived and no longer actively maintained. Security vulnerabilities may exist in the project, or its dependencies. If you plan to reuse or run any code from this repo, be sure to perform appropriate security checks on the code or dependencies first. Do not use this project as the starting point of a production Office Add-in. Always start your production code by using the Office/SharePoint development workload in Visual Studio, or the [Yeoman generator for Office Add-ins](https://github.com/OfficeDev/generator-office), and follow security best practices as you develop the add-in.
4 |
5 | **Table of contents**
6 |
7 | * [Introduction](#introduction)
8 | * [Prerequisites](#prerequisites)
9 | * [Register and configure the app](#register)
10 | * [Build and debug](#build)
11 | * [How the sample affects your tenant data](#how-the-sample-affects-your-tenant-data)
12 | * [Add a snippet](#add-a-snippet)
13 | * [Troubleshooting](#troubleshooting)
14 | * [Questions and comments](#questions)
15 | * [Next steps](#next-steps)
16 | * [Additional resources](#additional-resources)
17 |
18 |
19 | ##Introduction
20 |
21 | The Office 365 Windows Snippets project contains a repository of code snippets that show you how to use the client libraries from the Office 365 API tools to interact with Office 365 objects, including users, groups, calendars, contacts, mail, files, and folders.
22 |
23 | These snippets are simple and self-contained, and you can copy and paste them into your own code, whenever appropriate, or use them as a resource for learning how to use the client libraries.
24 |
25 | The image below shows what you'll see when you launch the app.
26 |
27 | 
28 |
29 | You can choose to run all of the snippets, or just the ones you select. After you choose to run, you’ll be prompted to authenticate with your Office 365 account credentials, and the snippets will run.
30 |
31 | **Note:** This project contains code that authenticates and connects a user to Office 365, but if you want to learn about authentication specifically, look at the [Connecting to Office 365 in Windows Store, Phone, and universal apps](https://github.com/OfficeDev/O365-Win-Connect).
32 |
33 |
34 | ## Prerequisites ##
35 |
36 | This sample requires the following:
37 | - Visual Studio 2013 with Update 4.
38 | - [Office 365 API Tools version 1.4.50428.2](http://aka.ms/k0534n).
39 | - An Office 365 account. You can sign up for [an Office 365 Developer subscription](http://aka.ms/ro9c62) that includes the resources that you need to start building Office 365 apps.
40 |
41 |
42 |
43 | ###Register and configure the app
44 |
45 | You can register the app with the Office 365 API Tools for Visual Studio. Be sure to download and install the [Office 365 API tools](http://aka.ms/k0534n) from the Visual Studio Gallery.
46 |
47 | **Note:** If you see any errors while installing packages (for example, *Unable to find "Microsoft.IdentityModel.Clients.ActiveDirectory"*) make sure the local path where you placed the solution is not too long/deep. Moving the solution closer to the root of your drive resolves this issue.
48 |
49 | 1. Open the O365-Win-Snippets.sln file using Visual Studio 2013.
50 | 2. Build the solution. The NuGet Package Restore feature will load the assemblies listed in the packages.config file. You should do this before adding connected services in the following steps so that you don't get older versions of some assemblies.
51 | 3. In the Solution Explorer window, right-click each project name and select Add -> Connected Service.
52 | 4. A Services Manager dialog box will appear. Choose **Office 365** and then **Register your app**.
53 | 5. On the sign-in dialog box, enter the user name and password for your Office 365 tenant. This user name will often follow the pattern @.onmicrosoft.com. If you don't already have an Office 365 tenant, you can get a free Developer Site as part of your MSDN Benefits or sign up for a free trial. After you're signed in, you will see a list of all the services. No permissions will be selected, since the app is not registered to use any services yet.
54 |
55 | 6. To register for the services used in this sample, choose the following services and permissions:
56 |
57 | - **Calendar** - Read and write to your calendars.
58 | - **Contacts** - Read and write to your contacts.
59 | - **Mail** - Read and write to your mail. Send mail as you.
60 | - **My Files** - Read and write your files.
61 | - **Users and Groups** - Sign you in and read your profile. Access your organization's directory.
62 |
63 |
64 | The dialog will look like this:
65 | 
66 |
67 | After you click **OK** in the Services Manager dialog box, you can select **Build Solution** from the **Build menu** to load the Microsoft.IdentityModel.Clients.ActiveDirectory assembly, or you can wait until you debug.
68 |
69 |
70 |
71 | ## Build and debug ##
72 |
73 | After you've loaded the solution in Visual Studio, press F5 to build and debug.
74 | Run the solution and sign in with your organizational account to Office 365.
75 |
76 |
77 | ##How the sample affects your tenant data
78 | This sample runs REST commands that create, read, update, or delete data. When running commands that delete or edit data, the sample creates fake entities. The fake entities are deleted or edited so that your actual tenant data is unaffected. The sample will leave behind fake entities on your tenant.
79 |
80 |
81 | ##Add a snippet
82 |
83 | This project includes five snippets files: Calendar\CalendarSnippets.cs, Contacts\ContactsSnippets.cs, Email\EmailSnippets.cs, Files\FilesSnippets.cs, and UsersAndGroups\UsersAndGroupsSnippets.cs.
84 |
85 | If you have a snippet of your own and you would like to run it in this project, just follow these three steps:
86 |
87 | 1. **Add your snippet to the snippets file.** Be sure to include a try/catch block. The snippet below is an example of a simple snippet that gets one page of calendar events:
88 |
89 | public static async Task> GetCalendarEventsAsync()
90 | {
91 | try
92 | {
93 | // Make sure we have a reference to the Exchange client
94 | OutlookServicesClient client = await GetOutlookClientAsync();
95 |
96 | IPagedCollection eventsResults = await client.Me.Calendar.Events.ExecuteAsync();
97 |
98 | // You can access each event as follows.
99 | if (eventsResults.CurrentPage.Count > 0)
100 | {
101 | string eventId = eventsResults.CurrentPage[0].Id;
102 | Debug.WriteLine("First event:" + eventId);
103 | }
104 |
105 | return eventsResults.CurrentPage.ToList();
106 | }
107 | catch { return null; }
108 | }
109 | 2. **Create a story that uses your snippet and add it to the associated stories file.** For example, the `TryCreateCalendarEventAsync()` story uses the `AddCalendarEventAsync ()` snippet inside the Calendar\CalendarStories.cs file:
110 |
111 | public static async Task TryCreateCalendarEventAsync()
112 | {
113 | var newEventId = await CalendarSnippets.AddCalendarEventAsync();
114 |
115 | if (newEventId == null)
116 | return false;
117 |
118 | //Cleanup
119 | await CalendarSnippets.DeleteCalendarEventAsync(newEventId);
120 |
121 | return true;
122 | }
123 | Sometimes your story will need to run snippets in addition to the one that you're implementing. For example, if you want to update an event, you first need to use the `AddCalendarEventAsync()` method to create an event. Then you can update it. Always be sure to use snippets that already exist in the snippets file. If the operation you need doesn't exist, you'll have to create it and then include it in your story. It's a best practice to delete any entities that you create in a story, especially if you're working on anything other than a test or developer tenant.
124 |
125 | 3. **Add your story to the story collection in MainPageXaml.cs** (inside the `CreateTestList()` method):
126 |
127 | `StoryCollection.Add(new StoryDefinition() { GroupName = "Calendar", Title = "Create", RunStoryAsync = CalendarStories.TryCreateCalendarEventAsync });`
128 |
129 | Now you can test your snippet. When you run the app, your snippet will appear as a new box in the grid. Select the box for your snippet, and then run it. Use this as an opportunity to debug your snippet.
130 |
131 |
132 | ## Troubleshooting ##
133 |
134 | - You run the Windows App Certification Kit against the installed app, and the app fails the supported APIs test. This likely happened because the Visual Studio tools installed older versions of some assemblies. Check the entries for Microsoft.Azure.ActiveDirectory.GraphClient and the Microsoft.OData assemblies in your project's packages.config file. Make sure that the version numbers for those assemblies match the version numbers in [this repo's version of packages.config](https://github.com/OfficeDev/O365-Win-Snippets/blob/master/src/packages.config). When you rebuild and reinstall the solution with the updated assemblies, the app should pass the supported APIs test.
135 |
136 |
137 | ## Questions and comments
138 |
139 | We'd love to get your feedback on the O365 Windows Snippets project. You can send your questions and suggestions to us in the [Issues](https://github.com/OfficeDev/O365-Win-Snippets/issues) section of this repository.
140 |
141 | Questions about Office 365 development in general should be posted to [Stack Overflow](http://stackoverflow.com/questions/tagged/Office365+API). Make sure that your questions or comments are tagged with [Office365] and [API].
142 |
143 |
144 | ## Next steps ##
145 |
146 | - If you're interested in a sample that has a richer interface for interacting with the Office 365 services in a Windows app, look at the [Office 365 Starter Project for Windows Store App](https://github.com/OfficeDev/O365-Windows-Start).
147 | - For more details on what else you can do with the Office 365 services in your Windows app, start with the [Getting started](http://dev.office.com/getting-started) page on dev.office.com.
148 |
149 |
150 | ## Additional resources ##
151 |
152 | - [Office 365 APIs platform overview](https://msdn.microsoft.com/office/office365/howto/platform-development-overview)
153 | - [Office 365 API code samples and videos](https://msdn.microsoft.com/office/office365/howto/starter-projects-and-code-samples)
154 | - [Office developer code samples](http://dev.office.com/code-samples)
155 | - [Office dev center](http://dev.office.com/)
156 | - [Connecting to Office 365 in Windows Store, Phone, and universal apps](https://github.com/OfficeDev/O365-Win-Connect)
157 | - [Office 365 Starter Project for Windows Store App](https://github.com/OfficeDev/O365-Windows-Start)
158 | - [Office 365 Profile sample for Windows](https://github.com/OfficeDev/O365-Win-Profile)
159 | - [Office 365 REST API Explorer for Sites](https://github.com/OfficeDev/Office-365-REST-API-Explorer)
160 |
161 |
162 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information, see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
163 |
--------------------------------------------------------------------------------
/Readme-images/ConnectedServices.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/O365-Win-Snippets/9665c4fb551d015b3edcbf3d28c8750f1eb33ac4/Readme-images/ConnectedServices.PNG
--------------------------------------------------------------------------------
/Readme-images/LaunchScreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/O365-Win-Snippets/9665c4fb551d015b3edcbf3d28c8750f1eb33ac4/Readme-images/LaunchScreen.png
--------------------------------------------------------------------------------
/Readme-images/MainPage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/O365-Win-Snippets/9665c4fb551d015b3edcbf3d28c8750f1eb33ac4/Readme-images/MainPage.png
--------------------------------------------------------------------------------
/src/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Runtime.InteropServices.WindowsRuntime;
6 | using Windows.ApplicationModel;
7 | using Windows.ApplicationModel.Activation;
8 | using Windows.Foundation;
9 | using Windows.Foundation.Collections;
10 | using Windows.UI.Xaml;
11 | using Windows.UI.Xaml.Controls;
12 | using Windows.UI.Xaml.Controls.Primitives;
13 | using Windows.UI.Xaml.Data;
14 | using Windows.UI.Xaml.Input;
15 | using Windows.UI.Xaml.Media;
16 | using Windows.UI.Xaml.Navigation;
17 |
18 | // The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=234227
19 |
20 | namespace O365_Win_Snippets
21 | {
22 | ///
23 | /// Provides application-specific behavior to supplement the default Application class.
24 | ///
25 | sealed partial class App : Application
26 | {
27 | ///
28 | /// Initializes the singleton application object. This is the first line of authored code
29 | /// executed, and as such is the logical equivalent of main() or WinMain().
30 | ///
31 | public App()
32 | {
33 | this.InitializeComponent();
34 | this.Suspending += OnSuspending;
35 | }
36 |
37 | ///
38 | /// Invoked when the application is launched normally by the end user. Other entry points
39 | /// will be used such as when the application is launched to open a specific file.
40 | ///
41 | /// Details about the launch request and process.
42 | protected override void OnLaunched(LaunchActivatedEventArgs e)
43 | {
44 |
45 | #if DEBUG
46 | if (System.Diagnostics.Debugger.IsAttached)
47 | {
48 | this.DebugSettings.EnableFrameRateCounter = true;
49 | }
50 | #endif
51 |
52 | Frame rootFrame = Window.Current.Content as Frame;
53 |
54 | // Do not repeat app initialization when the Window already has content,
55 | // just ensure that the window is active
56 | if (rootFrame == null)
57 | {
58 | // Create a Frame to act as the navigation context and navigate to the first page
59 | rootFrame = new Frame();
60 | // Set the default language
61 | rootFrame.Language = Windows.Globalization.ApplicationLanguages.Languages[0];
62 |
63 | rootFrame.NavigationFailed += OnNavigationFailed;
64 |
65 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
66 | {
67 | //TODO: Load state from previously suspended application
68 | }
69 |
70 | // Place the frame in the current Window
71 | Window.Current.Content = rootFrame;
72 | }
73 |
74 | if (rootFrame.Content == null)
75 | {
76 | // When the navigation stack isn't restored navigate to the first page,
77 | // configuring the new page by passing required information as a navigation
78 | // parameter
79 | rootFrame.Navigate(typeof(MainPage), e.Arguments);
80 | }
81 | // Ensure the current window is active
82 | Window.Current.Activate();
83 | }
84 |
85 | ///
86 | /// Invoked when Navigation to a certain page fails
87 | ///
88 | /// The Frame which failed navigation
89 | /// Details about the navigation failure
90 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
91 | {
92 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
93 | }
94 |
95 | ///
96 | /// Invoked when application execution is being suspended. Application state is saved
97 | /// without knowing whether the application will be terminated or resumed with the contents
98 | /// of memory still intact.
99 | ///
100 | /// The source of the suspend request.
101 | /// Details about the suspend request.
102 | private void OnSuspending(object sender, SuspendingEventArgs e)
103 | {
104 | var deferral = e.SuspendingOperation.GetDeferral();
105 | //TODO: Save application state and stop any background activity
106 | deferral.Complete();
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/src/Assets/Logo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/O365-Win-Snippets/9665c4fb551d015b3edcbf3d28c8750f1eb33ac4/src/Assets/Logo.scale-100.png
--------------------------------------------------------------------------------
/src/Assets/Run.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/O365-Win-Snippets/9665c4fb551d015b3edcbf3d28c8750f1eb33ac4/src/Assets/Run.png
--------------------------------------------------------------------------------
/src/Assets/SmallLogo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/O365-Win-Snippets/9665c4fb551d015b3edcbf3d28c8750f1eb33ac4/src/Assets/SmallLogo.scale-100.png
--------------------------------------------------------------------------------
/src/Assets/SplashScreen.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/O365-Win-Snippets/9665c4fb551d015b3edcbf3d28c8750f1eb33ac4/src/Assets/SplashScreen.scale-100.png
--------------------------------------------------------------------------------
/src/Assets/StoreLogo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/O365-Win-Snippets/9665c4fb551d015b3edcbf3d28c8750f1eb33ac4/src/Assets/StoreLogo.scale-100.png
--------------------------------------------------------------------------------
/src/AuthenticationHelper.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file.
2 |
3 | using Microsoft.IdentityModel.Clients.ActiveDirectory;
4 | using Microsoft.Office365.Discovery;
5 | using Microsoft.Office365.OutlookServices;
6 | using System;
7 | using System.Diagnostics;
8 | using System.Net.Http;
9 | using System.Linq;
10 | using System.Threading.Tasks;
11 | using Windows.Security.Authentication.Web;
12 | using Windows.Storage;
13 |
14 | namespace O365_Win_Snippets
15 | {
16 | public static class AuthenticationHelper
17 | {
18 | // The ClientID is added as a resource in App.xaml when you register the app with Office 365.
19 | // As a convenience, we load that value into a variable called ClientID. This way the variable
20 | // will always be in sync with whatever client id is added to App.xaml.
21 | private static readonly string ClientID = App.Current.Resources["ida:ClientID"].ToString();
22 | private static Uri _returnUri = WebAuthenticationBroker.GetCurrentApplicationCallbackUri();
23 |
24 |
25 | // Properties used for communicating with your Windows Azure AD tenant.
26 | // The AuthorizationUri is added as a resource in App.xaml when you regiter the app with
27 | // Office 365. As a convenience, we load that value into a variable called _commonAuthority, adding _common to this Url to signify
28 | // multi-tenancy. This way it will always be in sync with whatever value is added to App.xaml.
29 | public static readonly string CommonAuthority = App.Current.Resources["ida:AADInstance"].ToString() + @"Common";
30 | public static readonly Uri DiscoveryServiceEndpointUri = new Uri("https://api.office.com/discovery/v1.0/me/");
31 | public const string DiscoveryResourceId = "https://api.office.com/discovery/";
32 |
33 |
34 | //Store login settings
35 | public static ApplicationDataContainer _settings = ApplicationData.Current.LocalSettings;
36 |
37 | //Property for storing and returning the authority used by the last authentication.
38 | //This value is populated when the user connects to the service and made null when the user signs out.
39 | public static string LastAuthority
40 | {
41 | get
42 | {
43 | if (_settings.Values.ContainsKey("LastAuthority") && _settings.Values["LastAuthority"] != null)
44 | {
45 | return _settings.Values["LastAuthority"].ToString();
46 | }
47 | else
48 | {
49 | return string.Empty;
50 | }
51 |
52 | }
53 |
54 | set
55 | {
56 | _settings.Values["LastAuthority"] = value;
57 | }
58 | }
59 |
60 | //Property for storing the tenant id so that we can pass it to the ActiveDirectoryClient constructor.
61 | //This value is populated when the user connects to the service and made null when the user signs out.
62 | static internal string TenantId
63 | {
64 | get
65 | {
66 | if (_settings.Values.ContainsKey("TenantId") && _settings.Values["TenantId"] != null)
67 | {
68 | return _settings.Values["TenantId"].ToString();
69 | }
70 | else
71 | {
72 | return string.Empty;
73 | }
74 |
75 | }
76 |
77 | set
78 | {
79 | _settings.Values["TenantId"] = value;
80 | }
81 | }
82 |
83 | // Property for storing the logged-in user so that we can display user properties later.
84 | //This value is populated when the user connects to the service.
85 | static internal string LoggedInUser
86 | {
87 | get
88 | {
89 | if (_settings.Values.ContainsKey("LoggedInUser") && _settings.Values["LoggedInUser"] != null)
90 | {
91 | return _settings.Values["LoggedInUser"].ToString();
92 | }
93 | else
94 | {
95 | return string.Empty;
96 | }
97 |
98 | }
99 |
100 | set
101 | {
102 | _settings.Values["LoggedInUser"] = value;
103 | }
104 | }
105 |
106 |
107 | // Property for storing the logged-in user email address so that we can display user properties later.
108 | //This value is populated when the user connects to the service.
109 | public static string LoggedInUserEmail
110 | {
111 | get
112 | {
113 | if (_settings.Values.ContainsKey("LoggedInUserEmail") && _settings.Values["LoggedInUserEmail"] != null)
114 | {
115 | return _settings.Values["LoggedInUserEmail"].ToString();
116 | }
117 | else
118 | {
119 | return string.Empty;
120 | }
121 |
122 | }
123 |
124 | set
125 | {
126 | _settings.Values["LoggedInUserEmail"] = value;
127 | }
128 | }
129 |
130 | //Property for storing the authentication context.
131 | public static AuthenticationContext _authenticationContext { get; set; }
132 |
133 |
134 | ///
135 | /// Signs the user out of the service.
136 | ///
137 | public static void SignOut()
138 | {
139 | //Handle case where user signs out without first running any snippets.
140 | if (_authenticationContext == null)
141 | {
142 | _authenticationContext = new AuthenticationContext(LastAuthority);
143 | }
144 |
145 | _authenticationContext.TokenCache.Clear();
146 |
147 | //Clean up all existing clients
148 | //Clear stored values from last authentication.
149 | _settings.Values["TenantId"] = null;
150 | _settings.Values["LastAuthority"] = null;
151 | _settings.Values["LoggedInUser"] = null;
152 | _settings.Values["LoggedInUserEmail"] = null;
153 |
154 | }
155 |
156 | // Get an access token for the given context and resourceId. An attempt is first made to
157 | // acquire the token silently. If that fails, then we try to acquire the token by prompting the user.
158 | public static async Task GetTokenHelperAsync(AuthenticationContext context, string resourceId)
159 | {
160 | string accessToken = null;
161 | AuthenticationResult result = null;
162 |
163 | result = await context.AcquireTokenAsync(resourceId, ClientID, _returnUri);
164 |
165 | if (result.Status == AuthenticationStatus.Success)
166 | {
167 | accessToken = result.AccessToken;
168 | //Store values for logged-in user, tenant id, and authority, so that
169 | //they can be re-used if the user re-opens the app without disconnecting.
170 | _settings.Values["LoggedInUser"] = result.UserInfo.GivenName;
171 | _settings.Values["LoggedInUserEmail"] = result.UserInfo.DisplayableId;
172 | _settings.Values["TenantId"] = result.TenantId;
173 | _settings.Values["LastAuthority"] = context.Authority;
174 |
175 | return accessToken;
176 | }
177 | else
178 | {
179 | return null;
180 | }
181 | }
182 |
183 | }
184 | }
185 |
186 |
187 |
188 | //*********************************************************
189 | //
190 | //O365-Win-Snippets, https://github.com/OfficeDev/O365-Win-Snippets
191 | //
192 | //Copyright (c) Microsoft Corporation
193 | //All rights reserved.
194 | //
195 | // MIT License:
196 | // Permission is hereby granted, free of charge, to any person obtaining
197 | // a copy of this software and associated documentation files (the
198 | // ""Software""), to deal in the Software without restriction, including
199 | // without limitation the rights to use, copy, modify, merge, publish,
200 | // distribute, sublicense, and/or sell copies of the Software, and to
201 | // permit persons to whom the Software is furnished to do so, subject to
202 | // the following conditions:
203 |
204 | // The above copyright notice and this permission notice shall be
205 | // included in all copies or substantial portions of the Software.
206 |
207 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
208 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
209 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
210 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
211 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
212 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
213 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
214 | //
215 | //*********************************************************
--------------------------------------------------------------------------------
/src/Calendar/CalendarSnippets.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file.
2 |
3 | using Microsoft.IdentityModel.Clients.ActiveDirectory;
4 | using Microsoft.OData.Core;
5 | using Microsoft.Office365.Discovery;
6 | using Microsoft.Office365.OutlookServices;
7 | using Microsoft.OData.ProxyExtensions;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Diagnostics;
11 | using System.Linq;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace O365_Win_Snippets
16 | {
17 | public static class CalendarSnippets
18 | {
19 | private static OutlookServicesClient _outlookClient = null;
20 |
21 | ///
22 | /// Checks that an OutlookServicesClient object is available.
23 | ///
24 | /// The OutlookServicesClient object.
25 | public static async Task GetOutlookClientAsync()
26 | {
27 | if (_outlookClient != null && !String.IsNullOrEmpty(AuthenticationHelper.LastAuthority))
28 | {
29 | Debug.WriteLine("Got an Outlook client for Calendar.");
30 | return _outlookClient;
31 | }
32 | else
33 | {
34 | try
35 | {
36 | //First, look for the authority used during the last authentication.
37 | //If that value is not populated, use CommonAuthority.
38 | string authority = null;
39 |
40 | if (String.IsNullOrEmpty(AuthenticationHelper.LastAuthority))
41 | {
42 | authority = AuthenticationHelper.CommonAuthority;
43 | }
44 | else
45 | {
46 | authority = AuthenticationHelper.LastAuthority;
47 | }
48 |
49 | // Create an AuthenticationContext using this authority.
50 | AuthenticationHelper._authenticationContext = new AuthenticationContext(authority);
51 |
52 | // Set the value of _authenticationContext.UseCorporateNetwork to true so that you
53 | // can use this app inside a corporate intranet. If the value of UseCorporateNetwork
54 | // is true, you also need to add the Enterprise Authentication, Private Networks, and
55 | // Shared User Certificates capabilities in the Package.appxmanifest file.
56 | AuthenticationHelper._authenticationContext.UseCorporateNetwork = true;
57 |
58 | //See the Discovery Service Sample (https://github.com/OfficeDev/Office365-Discovery-Service-Sample)
59 | //for an approach that improves performance by storing the discovery service information in a cache.
60 | DiscoveryClient discoveryClient = new DiscoveryClient(
61 | async () => await AuthenticationHelper.GetTokenHelperAsync(AuthenticationHelper._authenticationContext, AuthenticationHelper.DiscoveryResourceId));
62 |
63 | // Get the specified capability ("Calendar").
64 | CapabilityDiscoveryResult result =
65 | await discoveryClient.DiscoverCapabilityAsync("Calendar");
66 |
67 | var token = await AuthenticationHelper.GetTokenHelperAsync(AuthenticationHelper._authenticationContext, result.ServiceResourceId);
68 | // Check the token
69 | if (String.IsNullOrEmpty(token))
70 | {
71 | // User cancelled sign-in
72 | return null;
73 | }
74 | else
75 | {
76 |
77 | _outlookClient = new OutlookServicesClient(
78 | result.ServiceEndpointUri,
79 | async () => await AuthenticationHelper.GetTokenHelperAsync(AuthenticationHelper._authenticationContext, result.ServiceResourceId));
80 | Debug.WriteLine("Got an Outlook client for Calendar.");
81 | return _outlookClient;
82 | }
83 | }
84 | // The following is a list of exceptions you should consider handling in your app.
85 | // In the case of this sample, the exceptions are handled by returning null upstream.
86 | catch (DiscoveryFailedException dfe)
87 | {
88 | Debug.WriteLine(dfe.Message);
89 | }
90 | catch (ArgumentException ae)
91 | {
92 | Debug.WriteLine(ae.Message);
93 | }
94 |
95 | AuthenticationHelper._authenticationContext.TokenCache.Clear();
96 |
97 | return null;
98 | }
99 | }
100 |
101 | ///
102 | /// Gets a page of celendar events.
103 | ///
104 | /// A list of calendar events.
105 | public static async Task> GetCalendarEventsAsync()
106 | {
107 |
108 | // Make sure we have a reference to the Exchange client
109 | OutlookServicesClient client = await GetOutlookClientAsync();
110 |
111 | IPagedCollection eventsResults = await client.Me.Calendar.Events.ExecuteAsync();
112 |
113 | // You can access each event as follows.
114 | if (eventsResults.CurrentPage.Count > 0)
115 | {
116 | string eventId = eventsResults.CurrentPage[0].Id;
117 | Debug.WriteLine("First event:" + eventId);
118 | }
119 |
120 | return eventsResults.CurrentPage.ToList();
121 |
122 | }
123 |
124 | ///
125 | /// Adds a new event to user's default calendar
126 | ///
127 | public static async Task AddCalendarEventAsync()
128 | {
129 |
130 | // Make sure we have a reference to the Exchange client
131 | var client = await GetOutlookClientAsync();
132 |
133 | Location location = new Location
134 | {
135 | DisplayName = "Water cooler"
136 | };
137 | ItemBody body = new ItemBody
138 | {
139 | Content = "Status updates, blocking issues, and next steps",
140 | ContentType = BodyType.Text
141 | };
142 |
143 | Attendee[] attendees =
144 | {
145 | new Attendee
146 | {
147 | Type = AttendeeType.Required,
148 | EmailAddress = new EmailAddress
149 | {
150 | Address = "mara@fabrikam.com"
151 | },
152 | },
153 | };
154 |
155 | Event newEvent = new Event
156 | {
157 | Subject = "Weekly Sync",
158 | Location = location,
159 | Attendees = attendees,
160 | Start = new DateTimeOffset(new DateTime(2014, 12, 1, 9, 30, 0)),
161 | End = new DateTimeOffset(new DateTime(2014, 12, 1, 10, 0, 0)),
162 | Body = body
163 | };
164 |
165 | await client.Me.Calendar.Events.AddEventAsync(newEvent);
166 |
167 | // Get the ID of the event.
168 | string eventId = newEvent.Id;
169 |
170 | Debug.WriteLine("Added event: " + eventId);
171 | return eventId;
172 |
173 |
174 | }
175 |
176 | ///
177 | /// Adds a new event to user's default calendar
178 | ///
179 | /// string. The name of the event location
180 | /// string. The body of the event.
181 | /// string. semi-colon delimited list of invitee email addresses
182 | /// string. The subject of the event
183 | /// DateTimeOffset. The start date of the event
184 | /// DateTimeOffset. The end date of the event
185 | /// TimeSpan. The start hour:Min:Sec of the event
186 | /// TimeSpan. The end hour:Min:Sec of the event
187 | /// The Id of the event that was created; Otherwise, null.
188 | public static async Task AddCalendarEventWithArgsAsync(
189 | string LocationName,
190 | string BodyContent,
191 | string Attendees,
192 | string EventName,
193 | DateTimeOffset start,
194 | DateTimeOffset end,
195 | TimeSpan startTime,
196 | TimeSpan endTime)
197 | {
198 | string newEventId = string.Empty;
199 | Location location = new Location();
200 | location.DisplayName = LocationName;
201 | ItemBody body = new ItemBody();
202 | body.Content = BodyContent;
203 | body.ContentType = BodyType.Text;
204 | string[] splitter = { ";" };
205 | var splitAttendeeString = Attendees.Split(splitter, StringSplitOptions.RemoveEmptyEntries);
206 | Attendee[] attendees = new Attendee[splitAttendeeString.Length];
207 | for (int i = 0; i < splitAttendeeString.Length; i++)
208 | {
209 | attendees[i] = new Attendee();
210 | attendees[i].Type = AttendeeType.Required;
211 | attendees[i].EmailAddress = new EmailAddress() { Address = splitAttendeeString[i] };
212 | }
213 |
214 | Event newEvent = new Event
215 | {
216 | Subject = EventName,
217 | Location = location,
218 | Attendees = attendees,
219 | Start = start,
220 | End = end,
221 | Body = body,
222 | };
223 | //Add new times to start and end dates.
224 | newEvent.Start = (DateTimeOffset?)CalcNewTime(newEvent.Start, start, startTime);
225 | newEvent.End = (DateTimeOffset?)CalcNewTime(newEvent.End, end, endTime);
226 |
227 | // Make sure we have a reference to the calendar client
228 | var exchangeClient = await GetOutlookClientAsync();
229 |
230 | // This results in a call to the service.
231 | await exchangeClient.Me.Events.AddEventAsync(newEvent);
232 | Debug.WriteLine("Added event: " + newEvent.Id);
233 | return newEvent.Id;
234 |
235 | }
236 |
237 |
238 | ///
239 | /// Updates an existing event in the user's default calendar
240 | ///
241 | /// string. The unique Id of the event to update
242 | /// string. The name of the event location
243 | /// string. The body of the event.
244 | /// string. semi-colon delimited list of invitee email addresses
245 | /// string. The subject of the event
246 | /// DateTimeOffset. The start date of the event
247 | /// DateTimeOffset. The end date of the event
248 | /// TimeSpan. The start hour:Min:Sec of the event
249 | /// TimeSpan. The end hour:Min:Sec of the event
250 | /// IEvent. The updated event
251 | public static async Task UpdateCalendarEventAsync(string eventId,
252 | string LocationName,
253 | string BodyContent,
254 | string Attendees,
255 | string EventName,
256 | DateTimeOffset start,
257 | DateTimeOffset end,
258 | TimeSpan startTime,
259 | TimeSpan endTime)
260 | {
261 | // Make sure we have a reference to the Exchange client
262 | var client = await GetOutlookClientAsync();
263 |
264 | var eventToUpdate = await client.Me.Calendar.Events.GetById(eventId).ExecuteAsync();
265 | eventToUpdate.Attendees.Clear();
266 | string[] splitter = { ";" };
267 | var splitAttendeeString = Attendees.Split(splitter, StringSplitOptions.RemoveEmptyEntries);
268 | Attendee[] attendees = new Attendee[splitAttendeeString.Length];
269 | for (int i = 0; i < splitAttendeeString.Length; i++)
270 | {
271 | Attendee newAttendee = new Attendee();
272 | newAttendee.EmailAddress = new EmailAddress() { Address = splitAttendeeString[i] };
273 | newAttendee.Type = AttendeeType.Required;
274 | eventToUpdate.Attendees.Add(newAttendee);
275 | }
276 |
277 | eventToUpdate.Subject = EventName;
278 | Location location = new Location();
279 | location.DisplayName = LocationName;
280 | eventToUpdate.Location = location;
281 | eventToUpdate.Start = (DateTimeOffset?)CalcNewTime(eventToUpdate.Start, start, startTime);
282 | eventToUpdate.End = (DateTimeOffset?)CalcNewTime(eventToUpdate.End, end, endTime);
283 | ItemBody body = new ItemBody();
284 | body.ContentType = BodyType.Text;
285 | body.Content = BodyContent;
286 | eventToUpdate.Body = body;
287 |
288 | // Update the calendar event in Exchange
289 | await eventToUpdate.UpdateAsync();
290 |
291 | Debug.WriteLine("Updated event: " + eventToUpdate.Id);
292 | return eventToUpdate;
293 |
294 | // A note about Batch Updating
295 | // You can save multiple updates on the client and save them all at once (batch) by
296 | // implementing the following pattern:
297 | // 1. Call UpdateAsync(true) for each event you want to update. Setting the parameter dontSave to true
298 | // means that the updates are registered locally on the client, but won't be posted to the server.
299 | // 2. Call exchangeClient.Context.SaveChangesAsync() to post all event updates you have saved locally
300 | // using the preceding UpdateAsync(true) call to the server, i.e., the user's Office 365 calendar.
301 |
302 | }
303 |
304 | ///
305 | /// Removes an event from the user's default calendar.
306 | ///
307 | /// string. The unique Id of the event to delete.
308 | ///
309 | public static async Task DeleteCalendarEventAsync(string eventId)
310 | {
311 | try
312 | {
313 | // Make sure we have a reference to the Exchange client
314 | var exchangeClient = await GetOutlookClientAsync();
315 |
316 | // Get the event to be removed from the Exchange service. This results in a call to the service.
317 | var eventToDelete = await exchangeClient.Me.Calendar.Events.GetById(eventId).ExecuteAsync();
318 |
319 | // Delete the event. This results in a call to the service.
320 | await eventToDelete.DeleteAsync(false);
321 | Debug.WriteLine("Deleted event: " + eventToDelete.Id);
322 | return eventToDelete;
323 | }
324 | catch (ODataErrorException ex)
325 | {
326 | // GetById will throw an ODataErrorException when the
327 | // item with the specified Id can't be found in the contact store on the server.
328 | Debug.WriteLine(ex.Message);
329 | return null;
330 | }
331 |
332 | }
333 |
334 | //Helper method that creates a new DateTime for an updated meeting.
335 |
336 | ///
337 | /// Sets new time component of the datetimeoffset from the TimeSpan property of the UI
338 | ///
339 | /// DateTimeOffset. The original date
340 | /// DateTimeOffset. The new date
341 | /// TimeSpan. The new time
342 | /// DateTimeOffset. The new start date/time
343 | private static DateTimeOffset CalcNewTime(DateTimeOffset? OldDate, DateTimeOffset NewDate, TimeSpan newTime)
344 | {
345 | //Default return value to New start date
346 | DateTimeOffset returnValue = NewDate;
347 |
348 | //Get original time components
349 | int hour = OldDate.Value.ToLocalTime().TimeOfDay.Hours;
350 | int min = OldDate.Value.ToLocalTime().TimeOfDay.Minutes;
351 | int second = OldDate.Value.ToLocalTime().TimeOfDay.Seconds;
352 |
353 | //Get new time components from TimeSpan updated by UI
354 | int newHour = newTime.Hours;
355 | int newMin = newTime.Minutes;
356 | int newSec = newTime.Seconds;
357 |
358 | //Update the new datetime by the difference between old and new time components
359 | returnValue = returnValue.AddHours(newHour - hour);
360 | returnValue = returnValue.AddMinutes(newMin - min);
361 | returnValue = returnValue.AddSeconds(newSec - second);
362 |
363 | return returnValue;
364 | }
365 |
366 | }
367 | }
368 |
369 | //*********************************************************
370 | //
371 | //O365-Win-Snippets, https://github.com/OfficeDev/O365-Win-Snippets
372 | //
373 | //Copyright (c) Microsoft Corporation
374 | //All rights reserved.
375 | //
376 | // MIT License:
377 | // Permission is hereby granted, free of charge, to any person obtaining
378 | // a copy of this software and associated documentation files (the
379 | // ""Software""), to deal in the Software without restriction, including
380 | // without limitation the rights to use, copy, modify, merge, publish,
381 | // distribute, sublicense, and/or sell copies of the Software, and to
382 | // permit persons to whom the Software is furnished to do so, subject to
383 | // the following conditions:
384 |
385 | // The above copyright notice and this permission notice shall be
386 | // included in all copies or substantial portions of the Software.
387 |
388 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
389 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
390 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
391 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
392 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
393 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
394 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
395 | //
396 | //*********************************************************
--------------------------------------------------------------------------------
/src/Calendar/CalendarStories.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file.
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace O365_Win_Snippets
10 | {
11 | public class CalendarStories
12 | {
13 | private static readonly string STORY_DATA_IDENTIFIER = Guid.NewGuid().ToString();
14 |
15 | public static async Task TryGetOutlookClientAsync()
16 | {
17 | var outlookClient = await CalendarSnippets.GetOutlookClientAsync();
18 | return outlookClient != null;
19 | }
20 |
21 | public static async Task TryGetCalendarEventsAsync()
22 | {
23 | var events = await CalendarSnippets.GetCalendarEventsAsync();
24 |
25 | return events != null;
26 | }
27 |
28 | public static async Task TryCreateCalendarEventAsync()
29 | {
30 | var newEventId = await CalendarSnippets.AddCalendarEventAsync();
31 |
32 | if (newEventId == null)
33 | return false;
34 |
35 | //Cleanup
36 | await CalendarSnippets.DeleteCalendarEventAsync(newEventId);
37 |
38 | return true;
39 | }
40 |
41 | public static async Task TryCreateCalendarEventWithArgsAsync()
42 | {
43 | var newEventId = await CalendarSnippets.AddCalendarEventWithArgsAsync(
44 | Guid.NewGuid().ToString(),
45 | STORY_DATA_IDENTIFIER,
46 | string.Empty,
47 | Guid.NewGuid().ToString(),
48 | new DateTimeOffset(DateTime.Now),
49 | new DateTimeOffset(DateTime.Now),
50 | new TimeSpan(DateTime.Now.Ticks),
51 | new TimeSpan(DateTime.Now.Ticks)
52 | );
53 |
54 | if (newEventId == null)
55 | return false;
56 |
57 | //Cleanup
58 | await CalendarSnippets.DeleteCalendarEventAsync(newEventId);
59 |
60 | return true;
61 | }
62 |
63 | public static async Task TryUpdateCalendarEventAsync()
64 | {
65 |
66 | var newEventId = await CalendarSnippets.AddCalendarEventWithArgsAsync(
67 | "OrigLocationValue",
68 | STORY_DATA_IDENTIFIER,
69 | string.Empty,
70 | Guid.NewGuid().ToString(),
71 | new DateTimeOffset(DateTime.Now),
72 | new DateTimeOffset(DateTime.Now),
73 | new TimeSpan(DateTime.Now.Ticks),
74 | new TimeSpan(DateTime.Now.Ticks)
75 | );
76 |
77 | if (newEventId == null)
78 | return false;
79 |
80 | // Update our event
81 | var updatedEvent = await CalendarSnippets.UpdateCalendarEventAsync(newEventId,
82 | "NewLocationValue",
83 | STORY_DATA_IDENTIFIER,
84 | string.Empty,
85 | Guid.NewGuid().ToString(),
86 | new DateTimeOffset(DateTime.Now),
87 | new DateTimeOffset(DateTime.Now),
88 | new TimeSpan(DateTime.Now.Ticks),
89 | new TimeSpan(DateTime.Now.Ticks)
90 | );
91 |
92 | if (updatedEvent == null || updatedEvent.Id != newEventId)
93 | return false;
94 |
95 | //Cleanup
96 | await CalendarSnippets.DeleteCalendarEventAsync(newEventId);
97 |
98 |
99 | return true;
100 | }
101 |
102 | public static async Task TryDeleteCalendarEventAsync()
103 | {
104 | var newEventId = await CalendarSnippets.AddCalendarEventAsync();
105 |
106 | if (newEventId == null)
107 | return false;
108 |
109 | // Delete the event
110 | var deletedEvent = await CalendarSnippets.DeleteCalendarEventAsync(newEventId);
111 | if (deletedEvent == null)
112 | return false;
113 |
114 | return true;
115 | }
116 |
117 | }
118 | }
119 |
120 | //*********************************************************
121 | //
122 | //O365-Win-Snippets, https://github.com/OfficeDev/O365-Win-Snippets
123 | //
124 | //Copyright (c) Microsoft Corporation
125 | //All rights reserved.
126 | //
127 | // MIT License:
128 | // Permission is hereby granted, free of charge, to any person obtaining
129 | // a copy of this software and associated documentation files (the
130 | // ""Software""), to deal in the Software without restriction, including
131 | // without limitation the rights to use, copy, modify, merge, publish,
132 | // distribute, sublicense, and/or sell copies of the Software, and to
133 | // permit persons to whom the Software is furnished to do so, subject to
134 | // the following conditions:
135 |
136 | // The above copyright notice and this permission notice shall be
137 | // included in all copies or substantial portions of the Software.
138 |
139 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
140 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
141 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
142 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
143 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
144 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
145 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
146 | //
147 | //*********************************************************
--------------------------------------------------------------------------------
/src/Contacts/ContactsSnippets.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file.
2 |
3 | using Microsoft.IdentityModel.Clients.ActiveDirectory;
4 | using Microsoft.OData.Core;
5 | using Microsoft.Office365.Discovery;
6 | using Microsoft.Office365.OutlookServices;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Diagnostics;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 |
15 | namespace O365_Win_Snippets
16 | {
17 | public static class ContactsSnippets
18 | {
19 |
20 | private static OutlookServicesClient _outlookClient = null;
21 |
22 | ///
23 | /// Checks that an OutlookServicesClient object is available.
24 | ///
25 | /// The OutlookServicesClient object.
26 | public static async Task GetOutlookClientAsync()
27 | {
28 |
29 | if (_outlookClient != null && !String.IsNullOrEmpty(AuthenticationHelper.LastAuthority))
30 | {
31 | Debug.WriteLine("Got an Outlook client for Contacts.");
32 | return _outlookClient;
33 | }
34 | else
35 | {
36 | try
37 | {
38 | //First, look for the authority used during the last authentication.
39 | //If that value is not populated, use CommonAuthority.
40 | string authority = null;
41 |
42 | if (String.IsNullOrEmpty(AuthenticationHelper.LastAuthority))
43 | {
44 | authority = AuthenticationHelper.CommonAuthority;
45 | }
46 | else
47 | {
48 | authority = AuthenticationHelper.LastAuthority;
49 | }
50 |
51 | // Create an AuthenticationContext using this authority.
52 | AuthenticationHelper._authenticationContext = new AuthenticationContext(authority);
53 |
54 | // Set the value of _authenticationContext.UseCorporateNetwork to true so that you
55 | // can use this app inside a corporate intranet. If the value of UseCorporateNetwork
56 | // is true, you also need to add the Enterprise Authentication, Private Networks, and
57 | // Shared User Certificates capabilities in the Package.appxmanifest file.
58 | AuthenticationHelper._authenticationContext.UseCorporateNetwork = true;
59 |
60 | //See the Discovery Service Sample (https://github.com/OfficeDev/Office365-Discovery-Service-Sample)
61 | //for an approach that improves performance by storing the discovery service information in a cache.
62 | DiscoveryClient discoveryClient = new DiscoveryClient(
63 | async () => await AuthenticationHelper.GetTokenHelperAsync(AuthenticationHelper._authenticationContext, AuthenticationHelper.DiscoveryResourceId));
64 |
65 | // Get the specified capability ("Calendar").
66 | CapabilityDiscoveryResult result =
67 | await discoveryClient.DiscoverCapabilityAsync("Contacts");
68 |
69 | var token = await AuthenticationHelper.GetTokenHelperAsync(AuthenticationHelper._authenticationContext, result.ServiceResourceId);
70 | // Check the token
71 | if (String.IsNullOrEmpty(token))
72 | {
73 | // User cancelled sign-in
74 | return null;
75 | }
76 | else
77 | {
78 |
79 | _outlookClient = new OutlookServicesClient(
80 | result.ServiceEndpointUri,
81 | async () => await AuthenticationHelper.GetTokenHelperAsync(AuthenticationHelper._authenticationContext, result.ServiceResourceId));
82 | Debug.WriteLine("Got an Outlook client for Contacts");
83 | return _outlookClient;
84 | }
85 | }
86 | // The following is a list of exceptions you should consider handling in your app.
87 | // In the case of this sample, the exceptions are handled by returning null upstream.
88 | catch (DiscoveryFailedException dfe)
89 | {
90 | Debug.WriteLine(dfe.Message);
91 | }
92 | catch (ArgumentException ae)
93 | {
94 | Debug.WriteLine(ae.Message);
95 | }
96 |
97 | AuthenticationHelper._authenticationContext.TokenCache.Clear();
98 |
99 | return null;
100 | }
101 | }
102 |
103 | ///
104 | /// Retrieve a page of contacts from the server.
105 | ///
106 | /// A list of contacts.
107 | public static async Task> GetContactsPageAsync()
108 | {
109 | // Get exchangeclient
110 | var outlookClient = await GetOutlookClientAsync();
111 |
112 | // Get contacts
113 | var contactsResults = await outlookClient.Me.Contacts.ExecuteAsync();
114 |
115 | // You can access each contact as follows.
116 | if (contactsResults.CurrentPage.Count > 0)
117 | {
118 | string contactId = contactsResults.CurrentPage[0].Id;
119 |
120 | if (contactsResults.CurrentPage.Count > 0)
121 | {
122 | Debug.WriteLine("First contact:" + contactId);
123 | }
124 | }
125 |
126 | return contactsResults.CurrentPage.ToList();
127 | }
128 |
129 | public static async Task GetContactAsync(string Id)
130 | {
131 | try
132 | {
133 | var exchangeClient = await GetOutlookClientAsync();
134 | var contact = await exchangeClient.Me.Contacts.GetById(Id).ExecuteAsync();
135 |
136 | Debug.WriteLine("Got contact:" + contact.Id);
137 |
138 | return contact;
139 | }
140 | catch (ODataErrorException ex)
141 | {
142 | // GetById will throw an ODataErrorException when the
143 | // item with the specified Id can't be found in the contact store on the server.
144 | Debug.WriteLine(ex.Message);
145 | return null;
146 | }
147 | }
148 |
149 | ///
150 | /// Adds a new contact.
151 | ///
152 | public static async Task AddContactItemAsync(
153 | string fileAs,
154 | string givenName,
155 | string surname,
156 | string jobTitle,
157 | string email,
158 | string workPhone,
159 | string mobilePhone
160 | )
161 | {
162 | Contact newContact = new Contact
163 | {
164 | FileAs = fileAs,
165 | GivenName = givenName,
166 | Surname = surname,
167 | JobTitle = jobTitle,
168 | MobilePhone1 = mobilePhone
169 | };
170 |
171 | newContact.BusinessPhones.Add(workPhone);
172 |
173 |
174 | // Note: Setting EmailAddress1 to a null or empty string will throw an exception that
175 | // states the email address is invalid and the contact cannot be added.
176 | // Setting EmailAddress1 to a string that does not resemble an email address will not
177 | // cause an exception to be thrown, but the value is not stored in EmailAddress1.
178 | if (!string.IsNullOrEmpty(email))
179 | newContact.EmailAddresses.Add(new EmailAddress() { Address = email });
180 |
181 | // Make sure we have a reference to the Exchange client
182 | var outlookClient = await GetOutlookClientAsync();
183 |
184 | // This results in a call to the service.
185 | await outlookClient.Me.Contacts.AddContactAsync(newContact);
186 |
187 | Debug.WriteLine("Added contact: " + newContact.Id);
188 |
189 | return newContact;
190 |
191 | }
192 |
193 | ///
194 | /// Updates an existing contact.
195 | ///
196 | public static async Task UpdateContactItemAsync(string selectedContactId,
197 | string fileAs,
198 | string givenName,
199 | string surname,
200 | string jobTitle,
201 | string email,
202 | string workPhone,
203 | string mobilePhone,
204 | byte[] contactImage
205 | )
206 | {
207 |
208 | // Make sure we have a reference to the Exchange client
209 | var exchangeClient = await GetOutlookClientAsync();
210 |
211 | var contactToUpdate = await exchangeClient.Me.Contacts[selectedContactId].ExecuteAsync();
212 |
213 | contactToUpdate.FileAs = fileAs;
214 | contactToUpdate.GivenName = givenName;
215 | contactToUpdate.Surname = surname;
216 | contactToUpdate.JobTitle = jobTitle;
217 |
218 | contactToUpdate.MobilePhone1 = mobilePhone;
219 |
220 | // Note: Setting EmailAddress1 to a null or empty string will throw an exception that
221 | // states the email address is invalid and the contact cannot be added.
222 | // Setting EmailAddress1 to a string that does not resemble an email address will not
223 | // cause an exception to be thrown, but the value is not stored in EmailAddress1.
224 |
225 | if (!string.IsNullOrEmpty(email))
226 | {
227 | contactToUpdate.EmailAddresses.Clear();
228 | contactToUpdate.EmailAddresses.Add(new EmailAddress() { Address = email, Name = email });
229 | }
230 |
231 | // Update the contact in Exchange
232 | await contactToUpdate.UpdateAsync();
233 |
234 | Debug.WriteLine("Updated contact: " + contactToUpdate.Id);
235 |
236 | return contactToUpdate;
237 |
238 | // A note about Batch Updating
239 | // You can save multiple updates on the client and save them all at once (batch) by
240 | // implementing the following pattern:
241 | // 1. Call UpdateAsync(true) for each contact you want to update. Setting the parameter dontSave to true
242 | // means that the updates are registered locally on the client, but won't be posted to the server.
243 | // 2. Call exchangeClient.Context.SaveChangesAsync() to post all contact updates you have saved locally
244 | // using the preceding UpdateAsync(true) call to the server, i.e., the user's Office 365 contacts list.
245 |
246 | }
247 |
248 | ///
249 | /// Deletes a contact.
250 | ///
251 | /// The contact to delete.
252 | /// True if deleted;Otherwise, false.
253 | public static async Task DeleteContactAsync(string contactId)
254 | {
255 | try
256 | {
257 | // Make sure we have a reference to the Exchange client
258 | var outlookClient = await GetOutlookClientAsync();
259 |
260 | var contactToDelete = await outlookClient.Me.Contacts.GetById(contactId).ExecuteAsync();
261 |
262 | await contactToDelete.DeleteAsync();
263 |
264 | Debug.WriteLine("Deleted contact: " + contactToDelete.Id);
265 |
266 | return true;
267 | }
268 | catch (ODataErrorException ex)
269 | {
270 | // GetById will throw an ODataErrorException when the
271 | // item with the specified Id can't be found in the contact store on the server.
272 | Debug.WriteLine(ex.Message);
273 | return false;
274 | }
275 | }
276 |
277 | }
278 | }
279 |
280 | //*********************************************************
281 | //
282 | //O365-Win-Snippets, https://github.com/OfficeDev/O365-Win-Snippets
283 | //
284 | //Copyright (c) Microsoft Corporation
285 | //All rights reserved.
286 | //
287 | // MIT License:
288 | // Permission is hereby granted, free of charge, to any person obtaining
289 | // a copy of this software and associated documentation files (the
290 | // ""Software""), to deal in the Software without restriction, including
291 | // without limitation the rights to use, copy, modify, merge, publish,
292 | // distribute, sublicense, and/or sell copies of the Software, and to
293 | // permit persons to whom the Software is furnished to do so, subject to
294 | // the following conditions:
295 |
296 | // The above copyright notice and this permission notice shall be
297 | // included in all copies or substantial portions of the Software.
298 |
299 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
300 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
301 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
302 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
303 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
304 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
305 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
306 | //
307 | //*********************************************************
--------------------------------------------------------------------------------
/src/Contacts/ContactsStories.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file.
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace O365_Win_Snippets
10 | {
11 | public class ContactsStories
12 | {
13 | private static readonly string STORY_DATA_IDENTIFIER = Guid.NewGuid().ToString();
14 |
15 | public static async Task TryGetOutlookClientAsync()
16 | {
17 | var outlookClient = await ContactsSnippets.GetOutlookClientAsync();
18 | return outlookClient != null;
19 | }
20 |
21 | public static async Task TryGetContactsAsync()
22 | {
23 | var contacts = await ContactsSnippets.GetContactsPageAsync();
24 |
25 | return contacts != null;
26 | }
27 |
28 | public static async Task TryGetContactAsync()
29 | {
30 | var newContact = await ContactsSnippets.AddContactItemAsync(
31 | Guid.NewGuid().ToString(),
32 | Guid.NewGuid().ToString(),
33 | STORY_DATA_IDENTIFIER,
34 | Guid.NewGuid().ToString(),
35 | "a@b.com",
36 | Guid.NewGuid().ToString(),
37 | Guid.NewGuid().ToString());
38 |
39 | var contact = await ContactsSnippets.GetContactAsync(newContact.Id);
40 |
41 | //Cleanup
42 |
43 | await ContactsSnippets.DeleteContactAsync(newContact.Id);
44 |
45 | return contact != null;
46 | }
47 |
48 | public static async Task TryAddNewContactAsync()
49 | {
50 | var newContact = await ContactsSnippets.AddContactItemAsync(
51 | Guid.NewGuid().ToString(),
52 | Guid.NewGuid().ToString(),
53 | STORY_DATA_IDENTIFIER,
54 | Guid.NewGuid().ToString(),
55 | "a@b.com",
56 | Guid.NewGuid().ToString(),
57 | Guid.NewGuid().ToString());
58 |
59 | //Cleanup
60 |
61 | await ContactsSnippets.DeleteContactAsync(newContact.Id);
62 |
63 | return newContact != null;
64 | }
65 |
66 | public static async Task TryUpdateContactAsync()
67 | {
68 | var testContact = await ContactsSnippets.AddContactItemAsync(
69 | "FileAsValue",
70 | "FirstNameValue",
71 | STORY_DATA_IDENTIFIER,
72 | "JobTitleValue",
73 | "a@b.com",
74 | "WorkPhoneValue",
75 | "MobilePhoneValue");
76 |
77 | // Verify a valid contact id was returned
78 | if (testContact == null)
79 | return false;
80 |
81 |
82 | // Update our contact
83 | await ContactsSnippets.UpdateContactItemAsync(
84 | testContact.Id,
85 | "NewFileAsValue",
86 | "FirstNameValue",
87 | STORY_DATA_IDENTIFIER,
88 | "NewJobTitleValue",
89 | "a@b.com",
90 | "WorkPhoneValue",
91 | "MobilePhoneValue",
92 | null);
93 |
94 | var contactCheck = await ContactsSnippets.GetContactAsync(testContact.Id);
95 | if (contactCheck == null)
96 | return false;
97 |
98 | //Cleanup
99 |
100 | await ContactsSnippets.DeleteContactAsync(testContact.Id);
101 |
102 | return (contactCheck.FileAs == "NewFileAsValue" && contactCheck.JobTitle == "NewJobTitleValue");
103 |
104 |
105 | }
106 |
107 | public static async Task TryDeleteContactAsync()
108 | {
109 | var newContact = await ContactsSnippets.AddContactItemAsync(
110 | Guid.NewGuid().ToString(),
111 | Guid.NewGuid().ToString(),
112 | STORY_DATA_IDENTIFIER,
113 | Guid.NewGuid().ToString(),
114 | "a@b.com",
115 | Guid.NewGuid().ToString(),
116 | Guid.NewGuid().ToString());
117 |
118 | // Verify a valid contact id was returned
119 | if (newContact == null)
120 | return false;
121 |
122 | // Verify that count has increased by 1
123 | var contactCheck = await ContactsSnippets.GetContactAsync(newContact.Id);
124 | if (contactCheck == null)
125 | return false;
126 |
127 | // Delete contact we added
128 | var contactDeleted = await ContactsSnippets.DeleteContactAsync(newContact.Id);
129 | if (!contactDeleted)
130 | return false;
131 |
132 |
133 | contactCheck = await ContactsSnippets.GetContactAsync(newContact.Id);
134 | return (contactCheck == null);
135 |
136 | }
137 |
138 | }
139 | }
140 |
141 | //*********************************************************
142 | //
143 | //O365-Win-Snippets, https://github.com/OfficeDev/O365-Win-Snippets
144 | //
145 | //Copyright (c) Microsoft Corporation
146 | //All rights reserved.
147 | //
148 | // MIT License:
149 | // Permission is hereby granted, free of charge, to any person obtaining
150 | // a copy of this software and associated documentation files (the
151 | // ""Software""), to deal in the Software without restriction, including
152 | // without limitation the rights to use, copy, modify, merge, publish,
153 | // distribute, sublicense, and/or sell copies of the Software, and to
154 | // permit persons to whom the Software is furnished to do so, subject to
155 | // the following conditions:
156 |
157 | // The above copyright notice and this permission notice shall be
158 | // included in all copies or substantial portions of the Software.
159 |
160 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
161 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
162 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
163 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
164 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
165 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
166 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
167 | //
168 | //*********************************************************
--------------------------------------------------------------------------------
/src/DurationToDurationStringConverter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file.
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using Windows.UI.Xaml.Data;
9 |
10 | namespace O365_Win_Snippets
11 | {
12 | public class DurationToDurationStringConverter : IValueConverter
13 | {
14 | public object Convert(object value, Type targetType, object parameter, string language)
15 | {
16 | return String.Format("{0} ms", value);
17 | }
18 |
19 | public object ConvertBack(object value, Type targetType, object parameter, string language)
20 | {
21 | throw new NotImplementedException();
22 | }
23 | }
24 | }
25 |
26 | //*********************************************************
27 | //
28 | //O365-Win-Snippets, https://github.com/OfficeDev/O365-Win-Snippets
29 | //
30 | //Copyright (c) Microsoft Corporation
31 | //All rights reserved.
32 | //
33 | // MIT License:
34 | // Permission is hereby granted, free of charge, to any person obtaining
35 | // a copy of this software and associated documentation files (the
36 | // ""Software""), to deal in the Software without restriction, including
37 | // without limitation the rights to use, copy, modify, merge, publish,
38 | // distribute, sublicense, and/or sell copies of the Software, and to
39 | // permit persons to whom the Software is furnished to do so, subject to
40 | // the following conditions:
41 |
42 | // The above copyright notice and this permission notice shall be
43 | // included in all copies or substantial portions of the Software.
44 |
45 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
46 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
47 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
49 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
50 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
51 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 | //
53 | //*********************************************************
--------------------------------------------------------------------------------
/src/Email/EmailSnippets.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file.
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Threading.Tasks;
9 | using Microsoft.IdentityModel.Clients.ActiveDirectory;
10 | using Microsoft.OData.Core;
11 | using Microsoft.Office365.Discovery;
12 | using Microsoft.Office365.OutlookServices;
13 | using Microsoft.OData.ProxyExtensions;
14 |
15 |
16 | namespace O365_Win_Snippets
17 | {
18 | class EmailSnippets
19 | {
20 | private static OutlookServicesClient _outlookClient = null;
21 |
22 | ///
23 | /// Checks that an OutlookServicesClient object is available.
24 | ///
25 | /// The OutlookServicesClient object.
26 | public static async Task GetOutlookClientAsync()
27 | {
28 | if (_outlookClient != null && !String.IsNullOrEmpty(AuthenticationHelper.LastAuthority))
29 | {
30 | Debug.WriteLine("Got an Outlook client for Mail.");
31 | return _outlookClient;
32 | }
33 | else
34 | {
35 | try
36 | {
37 | //First, look for the authority used during the last authentication.
38 | //If that value is not populated, use CommonAuthority.
39 | string authority = null;
40 |
41 | if (String.IsNullOrEmpty(AuthenticationHelper.LastAuthority))
42 | {
43 | authority = AuthenticationHelper.CommonAuthority;
44 | }
45 | else
46 | {
47 | authority = AuthenticationHelper.LastAuthority;
48 | }
49 |
50 | // Create an AuthenticationContext using this authority.
51 | AuthenticationHelper._authenticationContext = new AuthenticationContext(authority);
52 |
53 | // Set the value of _authenticationContext.UseCorporateNetwork to true so that you
54 | // can use this app inside a corporate intranet. If the value of UseCorporateNetwork
55 | // is true, you also need to add the Enterprise Authentication, Private Networks, and
56 | // Shared User Certificates capabilities in the Package.appxmanifest file.
57 | AuthenticationHelper._authenticationContext.UseCorporateNetwork = true;
58 |
59 | //See the Discovery Service Sample (https://github.com/OfficeDev/Office365-Discovery-Service-Sample)
60 | //for an approach that improves performance by storing the discovery service information in a cache.
61 | DiscoveryClient discoveryClient = new DiscoveryClient(
62 | async () => await AuthenticationHelper.GetTokenHelperAsync(AuthenticationHelper._authenticationContext, AuthenticationHelper.DiscoveryResourceId));
63 |
64 | // Get the specified capability ("Calendar").
65 | CapabilityDiscoveryResult result =
66 | await discoveryClient.DiscoverCapabilityAsync("Mail");
67 |
68 | var token = await AuthenticationHelper.GetTokenHelperAsync(AuthenticationHelper._authenticationContext, result.ServiceResourceId);
69 | // Check the token
70 | if (String.IsNullOrEmpty(token))
71 | {
72 | // User cancelled sign-in
73 | return null;
74 | }
75 | else
76 | {
77 |
78 | _outlookClient = new OutlookServicesClient(
79 | result.ServiceEndpointUri,
80 | async () => await AuthenticationHelper.GetTokenHelperAsync(AuthenticationHelper._authenticationContext, result.ServiceResourceId));
81 | Debug.WriteLine("Got an Outlook client for Mail.");
82 | return _outlookClient;
83 | }
84 | }
85 | // The following is a list of exceptions you should consider handling in your app.
86 | // In the case of this sample, the exceptions are handled by returning null upstream.
87 | catch (DiscoveryFailedException dfe)
88 | {
89 | Debug.WriteLine(dfe.Message);
90 | }
91 | catch (ArgumentException ae)
92 | {
93 | Debug.WriteLine(ae.Message);
94 | }
95 |
96 | AuthenticationHelper._authenticationContext.TokenCache.Clear();
97 |
98 | return null;
99 | }
100 | }
101 |
102 | public static async Task> GetInboxMessagesAsync()
103 | {
104 |
105 | // Make sure we have a reference to the Exchange client
106 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
107 |
108 | //Get messages from a specific folder. Using Inbox this time because it is most likely to be populated.
109 | var results = await outlookClient.Me.Folders.GetById("Inbox").Messages.ExecuteAsync();
110 |
111 | if (results.CurrentPage.Count > 0)
112 | {
113 | Debug.WriteLine("First message from Inbox folder:" + results.CurrentPage[0].Id);
114 | }
115 |
116 | return results.CurrentPage.ToList();
117 |
118 | }
119 |
120 |
121 | public static async Task> GetMessagesAsync()
122 | {
123 |
124 | // Make sure we have a reference to the Exchange client
125 | var outlookClient = await GetOutlookClientAsync();
126 |
127 | //Get messages (from Inbox by default)
128 | var results = await outlookClient.Me.Messages.ExecuteAsync();
129 |
130 | if (results.CurrentPage.Count > 0)
131 | {
132 | Debug.WriteLine("First message from Inbox folder:" + results.CurrentPage[0].Id);
133 | }
134 |
135 | return results.CurrentPage.ToList();
136 |
137 | }
138 |
139 | public static async Task GetMessagesAsync(string subject, DateTimeOffset after)
140 | {
141 |
142 | // Make sure we have a reference to the Exchange client
143 | var outlookClient = await GetOutlookClientAsync();
144 |
145 | //Get messages (from Inbox by default).
146 | // Note: This query is not guaranteed to return 0 or 1 message, so
147 | // I need to use ExecuteAsync. Otherwise, ExecuteSingleAsync will throw
148 | // InvalidOperationException.
149 | var result = await outlookClient.Me.Messages
150 | .Where(m => m.Subject == subject && m.DateTimeReceived > after)
151 | .ExecuteAsync();
152 |
153 |
154 | return (result.CurrentPage.Count > 0) ? result.CurrentPage[0] : null;
155 |
156 | }
157 |
158 | public static async Task SendMessageAsync(
159 | string Subject,
160 | string Body,
161 | string RecipientAddress
162 | )
163 | {
164 |
165 | // Make sure we have a reference to the Outlook Services client
166 | var outlookClient = await GetOutlookClientAsync();
167 |
168 | //Create Body
169 | ItemBody body = new ItemBody
170 | {
171 | Content = Body,
172 | ContentType = BodyType.HTML
173 | };
174 | List toRecipients = new List();
175 | toRecipients.Add(new Recipient
176 | {
177 | EmailAddress = new EmailAddress
178 | {
179 | Address = RecipientAddress
180 | }
181 | });
182 |
183 | Message newMessage = new Message
184 | {
185 | Subject = Subject,
186 | Body = body,
187 | ToRecipients = toRecipients
188 | };
189 |
190 | // To send a message without saving to Sent Items, specify false for
191 | // the SavetoSentItems parameter.
192 | await outlookClient.Me.SendMailAsync(newMessage, true);
193 |
194 | Debug.WriteLine("Sent mail: " + newMessage.Id);
195 |
196 | return true;
197 |
198 | }
199 |
200 | public static async Task CreateDraftAsync(
201 | string Subject,
202 | string Body,
203 | string RecipientAddress)
204 | {
205 |
206 | // Make sure we have a reference to the Outlook Services client
207 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
208 |
209 | ItemBody body = new ItemBody
210 | {
211 | Content = Body,
212 | ContentType = BodyType.HTML
213 | };
214 | List toRecipients = new List();
215 | toRecipients.Add(new Recipient
216 | {
217 | EmailAddress = new EmailAddress
218 | {
219 | Address = RecipientAddress
220 | }
221 | });
222 | Message draftMessage = new Message
223 | {
224 | Subject = Subject,
225 | Body = body,
226 | ToRecipients = toRecipients,
227 | Importance = Importance.High
228 | };
229 |
230 | // Save the draft message. Saving to Me.Messages saves the message in the Drafts folder.
231 | await outlookClient.Me.Messages.AddMessageAsync(draftMessage);
232 |
233 | Debug.WriteLine("Created draft: " + draftMessage.Id);
234 |
235 | return draftMessage.Id;
236 |
237 | }
238 |
239 | public static async Task CreateDraftAndSendAsync(
240 | string Subject,
241 | string Body,
242 | string RecipientAddress)
243 | {
244 |
245 | // Make sure we have a reference to the Outlook Services client
246 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
247 |
248 | ItemBody body = new ItemBody
249 | {
250 | Content = Body,
251 | ContentType = BodyType.HTML
252 | };
253 | List toRecipients = new List();
254 | toRecipients.Add(new Recipient
255 | {
256 | EmailAddress = new EmailAddress
257 | {
258 | Address = RecipientAddress
259 | }
260 | });
261 | Message draftMessage = new Message
262 | {
263 | Subject = Subject,
264 | Body = body,
265 | ToRecipients = toRecipients,
266 | Importance = Importance.High
267 | };
268 |
269 | // Save the draft message. This ensures that we'll get a message Id to return.
270 | await outlookClient.Me.Messages.AddMessageAsync(draftMessage);
271 |
272 | //Send the message.
273 |
274 | await outlookClient.Me.Messages[draftMessage.Id].SendAsync();
275 |
276 | Debug.WriteLine("Created and sent draft: " + draftMessage.Id);
277 |
278 | return draftMessage.Id;
279 |
280 | }
281 |
282 | public static async Task UpdateMessageAsync(string MessageId, string UpdatedContent)
283 | {
284 | try
285 | {
286 | // Make sure we have a reference to the Outlook Services client
287 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
288 |
289 | // Get the message to update and set changed properties
290 | IMessage message = await outlookClient.Me.Messages.GetById(MessageId).ExecuteAsync();
291 | message.Body = new ItemBody
292 | {
293 | Content = UpdatedContent,
294 | ContentType = BodyType.HTML
295 | };
296 |
297 | await message.UpdateAsync();
298 |
299 | Debug.WriteLine("Updated message: " + message.Id);
300 |
301 | return true;
302 | }
303 | catch (ODataErrorException ex)
304 | {
305 | // GetById will throw an ODataErrorException when the
306 | // item with the specified Id can't be found in the contact store on the server.
307 | Debug.WriteLine(ex.Message);
308 | return false;
309 | }
310 | }
311 |
312 | public static async Task ReplyMessageAsync(string MessageId, string ReplyContent)
313 | {
314 | try
315 | {
316 | // Make sure we have a reference to the Outlook Services client
317 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
318 |
319 | IMessage message = await outlookClient.Me.Messages.GetById(MessageId).ExecuteAsync();
320 | await message.ReplyAsync(ReplyContent);
321 |
322 | Debug.WriteLine("Replied to message: " + message.Id);
323 |
324 | return true;
325 | }
326 | catch (ODataErrorException ex)
327 | {
328 | // GetById will throw an ODataErrorException when the
329 | // item with the specified Id can't be found in the contact store on the server.
330 | Debug.WriteLine(ex.Message);
331 | return false;
332 | }
333 | }
334 |
335 | public static async Task ReplyAllAsync(string MessageId, string ReplyContent)
336 | {
337 | try
338 | {
339 | // Make sure we have a reference to the Outlook Services client
340 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
341 |
342 | IMessage message = await outlookClient.Me.Messages.GetById(MessageId).ExecuteAsync();
343 | await message.ReplyAllAsync(ReplyContent);
344 |
345 | Debug.WriteLine("Replied all to message: " + message.Id);
346 |
347 |
348 | return true;
349 | }
350 | catch (ODataErrorException ex)
351 | {
352 | // GetById will throw an ODataErrorException when the
353 | // item with the specified Id can't be found in the contact store on the server.
354 | Debug.WriteLine(ex.Message);
355 | return false;
356 | }
357 | }
358 |
359 | public static async Task ForwardMessageAsync(
360 | string MessageId,
361 | string ForwardMessage,
362 | string RecipientAddress)
363 | {
364 |
365 | try
366 | {
367 | // Make sure we have a reference to the Outlook Services client
368 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
369 |
370 | List toRecipients = new List();
371 | toRecipients.Add(new Recipient
372 | {
373 | EmailAddress = new EmailAddress
374 | {
375 | Address = RecipientAddress
376 | }
377 | });
378 |
379 | await outlookClient.Me.Messages.GetById(MessageId).ForwardAsync(ForwardMessage, toRecipients);
380 |
381 | Debug.WriteLine("Forwarded message: " + MessageId);
382 |
383 | return true;
384 | }
385 | catch (ODataErrorException ex)
386 | {
387 | // GetById will throw an ODataErrorException when the
388 | // item with the specified Id can't be found in the contact store on the server.
389 | Debug.WriteLine(ex.Message);
390 | return false;
391 | }
392 | }
393 |
394 |
395 | public static async Task MoveMessageAsync(string MessageId, string OriginalFolder, string ToFolder)
396 | {
397 | try
398 | {
399 | // Make sure we have a reference to the Outlook Services client
400 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
401 |
402 | IMessage messageToMove = await outlookClient.Me.Messages.GetById(MessageId).ExecuteAsync();
403 | IMessage movedMessage = await messageToMove.MoveAsync(ToFolder);
404 |
405 | Debug.WriteLine("Moved message: " + MessageId + " from " + OriginalFolder + " to " + ToFolder);
406 |
407 | return true;
408 | }
409 | catch (ODataErrorException ex)
410 | {
411 | // GetById will throw an ODataErrorException when the
412 | // item with the specified Id can't be found in the contact store on the server.
413 | Debug.WriteLine(ex.Message);
414 | return false;
415 | }
416 | }
417 |
418 | public static async Task CopyMessageAsync(string MessageId, string OriginalFolder, string ToFolder)
419 | {
420 | try
421 | {
422 | // Make sure we have a reference to the Outlook Services client
423 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
424 |
425 | IMessage messageToMove = await outlookClient.Me.Messages.GetById(MessageId).ExecuteAsync();
426 | IMessage movedMessage = await messageToMove.CopyAsync(ToFolder);
427 |
428 | Debug.WriteLine("Copied message: " + MessageId + " from " + OriginalFolder + " to " + ToFolder);
429 |
430 | return true;
431 | }
432 | catch (ODataErrorException ex)
433 | {
434 | // GetById will throw an ODataErrorException when the
435 | // item with the specified Id can't be found in the contact store on the server.
436 | Debug.WriteLine(ex.Message);
437 | return false;
438 | }
439 | }
440 |
441 | public static async Task AddFileAttachmentAsync(string MessageId, MemoryStream fileContent)
442 | {
443 | // Make sure we have a reference to the Outlook Services client
444 |
445 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
446 |
447 | var attachment = new FileAttachment();
448 |
449 | attachment.ContentBytes = fileContent.ToArray();
450 | attachment.Name = "fileAttachment";
451 | attachment.Size = fileContent.ToArray().Length;
452 |
453 | try
454 | {
455 | var storedMessage = outlookClient.Me.Messages.GetById(MessageId);
456 | await storedMessage.Attachments.AddAttachmentAsync(attachment);
457 | await storedMessage.SendAsync();
458 | Debug.WriteLine("Added attachment to message: " + MessageId);
459 |
460 | return true;
461 | }
462 | catch (ODataErrorException ex)
463 | {
464 | // GetById will throw an ODataErrorException when the
465 | // item with the specified Id can't be found in the contact store on the server.
466 | Debug.WriteLine(ex.Message);
467 | return false;
468 | }
469 |
470 | }
471 |
472 | public static async Task GetFileAttachmentsAsync(string MessageId)
473 | {
474 |
475 | try
476 | {
477 | // Make sure we have a reference to the Outlook Services client
478 |
479 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
480 |
481 | var message = outlookClient.Me.Messages.GetById(MessageId);
482 | var attachmentsResult = await message.Attachments.ExecuteAsync();
483 | var attachments = attachmentsResult.CurrentPage.ToList();
484 |
485 | foreach (IFileAttachment attachment in attachments)
486 | {
487 | Debug.WriteLine("Attachment: " + attachment.Name);
488 | }
489 |
490 | return true;
491 | }
492 | catch (ODataErrorException ex)
493 | {
494 | // GetById will throw an ODataErrorException when the
495 | // item with the specified Id can't be found in the contact store on the server.
496 | Debug.WriteLine(ex.Message);
497 | return false;
498 | }
499 |
500 | }
501 |
502 | public static async Task GetMessageWebLinkAsync(string MessageId)
503 | {
504 | try
505 | {
506 | // Make sure we have a reference to the Outlook Services client
507 |
508 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
509 | var message = await outlookClient.Me.Messages.GetById(MessageId).ExecuteAsync();
510 | Debug.WriteLine("Web link for message " + message.Id + ": " + message.WebLink);
511 |
512 | return message.WebLink;
513 | }
514 | catch (ODataErrorException ex)
515 | {
516 | // GetById will throw an ODataErrorException when the
517 | // item with the specified Id can't be found in the contact store on the server.
518 | Debug.WriteLine(ex.Message);
519 | return null;
520 | }
521 | }
522 |
523 | public static async Task DeleteMessageAsync(string MessageId)
524 | {
525 | try
526 | {
527 | // Make sure we have a reference to the Outlook Services client
528 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
529 |
530 | // Get the message to delete.
531 | IMessage message = await outlookClient.Me.Messages.GetById(MessageId).ExecuteAsync();
532 | await message.DeleteAsync();
533 |
534 | Debug.WriteLine("Deleted message: " + MessageId)
535 | ;
536 | return true;
537 | }
538 | catch (ODataErrorException ex)
539 | {
540 | // GetById will throw an ODataErrorException when the
541 | // item with the specified Id can't be found in the contact store on the server.
542 | Debug.WriteLine(ex.Message);
543 | return false;
544 | }
545 | }
546 |
547 | //Mail Folders operations
548 |
549 | public static async Task> GetMailFoldersAsync()
550 | {
551 |
552 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
553 |
554 | IPagedCollection foldersResults = await outlookClient.Me.Folders.ExecuteAsync();
555 |
556 | string folderId = foldersResults.CurrentPage[0].Id;
557 |
558 | if (string.IsNullOrEmpty(folderId)) return null;
559 |
560 | Debug.WriteLine("First mail folder in the collection: " + folderId);
561 |
562 | return foldersResults;
563 |
564 | }
565 |
566 | public static async Task CreateMailFolderAsync(string ParentFolder, string NewFolderName)
567 | {
568 | try
569 | {
570 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
571 |
572 | Folder newFolder = new Folder
573 | {
574 | DisplayName = NewFolderName
575 | };
576 | await outlookClient.Me.Folders.GetById(ParentFolder).ChildFolders.AddFolderAsync(newFolder);
577 |
578 | Debug.WriteLine("Created folder: " + newFolder.Id);
579 |
580 | // Get the ID of the new folder.
581 | return newFolder.Id;
582 | }
583 | catch (ODataErrorException ex)
584 | {
585 | // GetById will throw an ODataErrorException when the
586 | // item with the specified Id can't be found in the contact store on the server.
587 | Debug.WriteLine(ex.Message);
588 | return null;
589 | }
590 | }
591 |
592 | public static async Task UpdateMailFolderAsync(string FolderId, string NewFolderName)
593 | {
594 | try
595 | {
596 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
597 |
598 | IFolder folder = await outlookClient.Me.Folders.GetById(FolderId).ExecuteAsync();
599 | folder.DisplayName = NewFolderName;
600 | await folder.UpdateAsync();
601 | string updatedName = folder.DisplayName;
602 |
603 | Debug.WriteLine("Updated folder name: " + FolderId + " " + NewFolderName);
604 |
605 | return true;
606 | }
607 | catch (ODataErrorException ex)
608 | {
609 | // GetById will throw an ODataErrorException when the
610 | // item with the specified Id can't be found in the contact store on the server.
611 | Debug.WriteLine(ex.Message);
612 | return false;
613 | }
614 | }
615 |
616 | public static async Task MoveMailFolderAsync(string folderId, string ToFolderName)
617 | {
618 | try
619 | {
620 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
621 |
622 | IFolder folderToMove = await outlookClient.Me.Folders.GetById(folderId).ExecuteAsync();
623 | await folderToMove.MoveAsync(ToFolderName);
624 | Debug.WriteLine("Moved folder: " + folderId + " to " + ToFolderName);
625 |
626 | return true;
627 | }
628 | catch (ODataErrorException ex)
629 | {
630 | // GetById will throw an ODataErrorException when the
631 | // item with the specified Id can't be found in the contact store on the server.
632 | Debug.WriteLine(ex.Message);
633 | return false;
634 | }
635 | }
636 |
637 | public static async Task CopyMailFolderAsync(string folderId, string ToFolderName)
638 | {
639 | try
640 | {
641 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
642 |
643 | IFolder folderToCopy = await outlookClient.Me.Folders.GetById(folderId).ExecuteAsync();
644 | IFolder copiedFolder = await folderToCopy.CopyAsync(ToFolderName);
645 |
646 | Debug.WriteLine("Copied folder: " + folderId + " to " + ToFolderName);
647 |
648 | return copiedFolder.Id;
649 | }
650 | catch (ODataErrorException ex)
651 | {
652 | // GetById will throw an ODataErrorException when the
653 | // item with the specified Id can't be found in the contact store on the server.
654 | Debug.WriteLine(ex.Message);
655 | return null;
656 | }
657 | }
658 |
659 |
660 | public static async Task DeleteMailFolderAsync(string folderId)
661 | {
662 | try
663 | {
664 | OutlookServicesClient outlookClient = await GetOutlookClientAsync();
665 |
666 | IFolder folder = await outlookClient.Me.Folders.GetById(folderId).ExecuteAsync();
667 | await folder.DeleteAsync();
668 |
669 | Debug.WriteLine("Deleted folder: " + folderId);
670 |
671 | return true;
672 | }
673 | catch (ODataErrorException ex)
674 | {
675 | // GetById will throw an ODataErrorException when the
676 | // item with the specified Id can't be found in the contact store on the server.
677 | Debug.WriteLine(ex.Message);
678 | return false;
679 | }
680 | }
681 |
682 | }
683 | }
684 |
685 | //*********************************************************
686 | //
687 | //O365-Win-Snippets, https://github.com/OfficeDev/O365-Win-Snippets
688 | //
689 | //Copyright (c) Microsoft Corporation
690 | //All rights reserved.
691 | //
692 | // MIT License:
693 | // Permission is hereby granted, free of charge, to any person obtaining
694 | // a copy of this software and associated documentation files (the
695 | // ""Software""), to deal in the Software without restriction, including
696 | // without limitation the rights to use, copy, modify, merge, publish,
697 | // distribute, sublicense, and/or sell copies of the Software, and to
698 | // permit persons to whom the Software is furnished to do so, subject to
699 | // the following conditions:
700 |
701 | // The above copyright notice and this permission notice shall be
702 | // included in all copies or substantial portions of the Software.
703 |
704 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
705 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
706 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
707 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
708 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
709 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
710 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
711 | //
712 | //*********************************************************
--------------------------------------------------------------------------------
/src/Email/EmailStories.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file.
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using System.Linq;
10 | using Microsoft.Office365.OutlookServices;
11 | using Microsoft.OData.ProxyExtensions;
12 | using Microsoft.OData.Client;
13 | using Microsoft.OData.Core;
14 |
15 |
16 | namespace O365_Win_Snippets
17 | {
18 | class EmailStories
19 | {
20 | private static readonly string STORY_DATA_IDENTIFIER = Guid.NewGuid().ToString();
21 | private static readonly string DEFAULT_MESSAGE_BODY = "This message was sent from the Office 365 Windows Snippets project";
22 |
23 | public static async Task TryGetOutlookClientAsync()
24 | {
25 | var exchangeClient = await EmailSnippets.GetOutlookClientAsync();
26 | return exchangeClient != null;
27 | }
28 |
29 | public static async Task TryGetInboxMessagesAsync()
30 | {
31 | var messages = await EmailSnippets.GetInboxMessagesAsync();
32 |
33 | return messages != null;
34 | }
35 |
36 | public static async Task TryGetMessagesAsync()
37 | {
38 | var messages = await EmailSnippets.GetMessagesAsync();
39 | return messages != null;
40 | }
41 |
42 | public static async Task TrySendMessageAsync()
43 | {
44 |
45 | bool isSent = await EmailSnippets.SendMessageAsync(
46 | STORY_DATA_IDENTIFIER,
47 | DEFAULT_MESSAGE_BODY,
48 | AuthenticationHelper.LoggedInUserEmail
49 | );
50 |
51 | return isSent;
52 |
53 | }
54 |
55 | public static async Task TryCreateDraftAsync()
56 | {
57 |
58 | // Create the draft message.
59 | var newMessageId = await EmailSnippets.CreateDraftAsync(
60 | STORY_DATA_IDENTIFIER,
61 | DEFAULT_MESSAGE_BODY,
62 | AuthenticationHelper.LoggedInUserEmail
63 | );
64 |
65 | if (newMessageId == null)
66 | return false;
67 |
68 | //Cleanup
69 | await EmailSnippets.DeleteMessageAsync(newMessageId);
70 |
71 | return true;
72 |
73 | }
74 |
75 | public static async Task TryReplyMessageAsync()
76 | {
77 |
78 | // Create a draft message and then send it. If you send the message without first creating a draft, you can't easily retrieve
79 | // the message Id.
80 |
81 | var newMessageId = await EmailSnippets.CreateDraftAndSendAsync(
82 | STORY_DATA_IDENTIFIER,
83 | DEFAULT_MESSAGE_BODY,
84 | AuthenticationHelper.LoggedInUserEmail
85 | );
86 |
87 | if (newMessageId == null)
88 | return false;
89 |
90 | // Find the sent message.
91 | var sentMessageId = await GetSentMessageIdAsync();
92 | if (String.IsNullOrEmpty(sentMessageId))
93 | return false;
94 |
95 | // Reply to the message.
96 | bool isReplied = await EmailSnippets.ReplyMessageAsync(
97 | sentMessageId,
98 | DEFAULT_MESSAGE_BODY);
99 |
100 | return isReplied;
101 | }
102 |
103 | public static async Task TryReplyAllAsync()
104 | {
105 |
106 | // Create a draft message and then send it. If you send the message without first creating a draft, you can't easily retrieve
107 | // the message Id.
108 |
109 | var newMessageId = await EmailSnippets.CreateDraftAndSendAsync(
110 | STORY_DATA_IDENTIFIER,
111 | DEFAULT_MESSAGE_BODY,
112 | AuthenticationHelper.LoggedInUserEmail
113 | );
114 |
115 | if (newMessageId == null)
116 | return false;
117 |
118 |
119 | // Find the sent message.
120 | var sentMessageId = await GetSentMessageIdAsync();
121 | if (String.IsNullOrEmpty(sentMessageId))
122 | return false;
123 |
124 | // Reply to the message.
125 | bool isReplied = await EmailSnippets.ReplyAllAsync(
126 | sentMessageId,
127 | DEFAULT_MESSAGE_BODY);
128 |
129 | return isReplied;
130 |
131 | }
132 |
133 | public static async Task TryForwardMessageAsync()
134 | {
135 |
136 | // Create a draft message and then send it. If you send the message without first creating a draft, you can't easily retrieve
137 | // the message Id.
138 |
139 | var newMessageId = await EmailSnippets.CreateDraftAndSendAsync(
140 | STORY_DATA_IDENTIFIER,
141 | DEFAULT_MESSAGE_BODY,
142 | AuthenticationHelper.LoggedInUserEmail
143 | );
144 |
145 | if (newMessageId == null)
146 | return false;
147 |
148 | // Find the sent message.
149 | var sentMessageId = await GetSentMessageIdAsync();
150 | if (String.IsNullOrEmpty(sentMessageId))
151 | return false;
152 |
153 | // Reply to the message.
154 | bool isReplied = await EmailSnippets.ForwardMessageAsync(
155 | sentMessageId,
156 | DEFAULT_MESSAGE_BODY,
157 | AuthenticationHelper.LoggedInUserEmail);
158 |
159 | return isReplied;
160 |
161 | }
162 |
163 | public static async Task TryUpdateMessageAsync()
164 | {
165 |
166 | // Create a draft message. If you send the message without first creating a draft, you can't easily retrieve the message Id.
167 | var newMessageId = await EmailSnippets.CreateDraftAsync(
168 | STORY_DATA_IDENTIFIER,
169 | DEFAULT_MESSAGE_BODY,
170 | AuthenticationHelper.LoggedInUserEmail
171 | );
172 |
173 | if (newMessageId == null)
174 | return false;
175 |
176 | // Update the message.
177 | bool isUpdated = await EmailSnippets.UpdateMessageAsync(
178 | newMessageId,
179 | DEFAULT_MESSAGE_BODY);
180 |
181 | //Cleanup. Comment if you want to verify the update in your Drafts folder.
182 | await EmailSnippets.DeleteMessageAsync(newMessageId);
183 |
184 | return isUpdated;
185 |
186 | }
187 |
188 | public static async Task TryMoveMessageAsync()
189 | {
190 |
191 | // Create a draft message and then send it. If you send the message without first creating a draft, you can't easily retrieve
192 | // the message Id.
193 |
194 | var newMessageId = await EmailSnippets.CreateDraftAndSendAsync(
195 | STORY_DATA_IDENTIFIER,
196 | DEFAULT_MESSAGE_BODY,
197 | AuthenticationHelper.LoggedInUserEmail
198 | );
199 |
200 | if (newMessageId == null)
201 | return false;
202 |
203 | // Find the sent message.
204 | var sentMessageId = await GetSentMessageIdAsync();
205 | if (String.IsNullOrEmpty(sentMessageId))
206 | return false;
207 |
208 | // Reply to the message.
209 | bool isReplied = await EmailSnippets.MoveMessageAsync(
210 | sentMessageId,
211 | "Inbox",
212 | "Drafts");
213 |
214 | return isReplied;
215 |
216 | }
217 |
218 | public static async Task TryCopyMessageAsync()
219 | {
220 |
221 | // Create a draft message and then send it. If you send the message without first creating a draft, you can't easily retrieve
222 | // the message Id.
223 |
224 | var newMessageId = await EmailSnippets.CreateDraftAndSendAsync(
225 | STORY_DATA_IDENTIFIER,
226 | DEFAULT_MESSAGE_BODY,
227 | AuthenticationHelper.LoggedInUserEmail
228 | );
229 |
230 | if (newMessageId == null)
231 | return false;
232 | // Find the sent message.
233 | var sentMessageId = await GetSentMessageIdAsync();
234 | if (String.IsNullOrEmpty(sentMessageId))
235 | return false;
236 |
237 | // Reply to the message.
238 | bool isReplied = await EmailSnippets.CopyMessageAsync(
239 | sentMessageId,
240 | "Inbox",
241 | "Drafts");
242 |
243 | return isReplied;
244 |
245 | }
246 |
247 | public static async Task TryGetFileAttachmentsAsync()
248 | {
249 |
250 | var newMessageId = await EmailSnippets.CreateDraftAsync(
251 | STORY_DATA_IDENTIFIER,
252 | DEFAULT_MESSAGE_BODY,
253 | AuthenticationHelper.LoggedInUserEmail
254 | );
255 |
256 | if (newMessageId == null)
257 | return false;
258 |
259 | await EmailSnippets.AddFileAttachmentAsync(newMessageId, new MemoryStream(Encoding.UTF8.GetBytes("TryAddMailAttachmentAsync")));
260 |
261 | // Find the sent message.
262 | var sentMessageId = await GetSentMessageIdAsync();
263 | if (String.IsNullOrEmpty(sentMessageId))
264 | return false;
265 |
266 | await EmailSnippets.GetFileAttachmentsAsync(sentMessageId);
267 |
268 | return true;
269 | }
270 |
271 | public static async Task TryGetMessageWebLinkAsync()
272 | {
273 | // Create a draft message and send it.
274 |
275 | var newMessageId = await EmailSnippets.CreateDraftAndSendAsync(
276 | STORY_DATA_IDENTIFIER,
277 | DEFAULT_MESSAGE_BODY,
278 | AuthenticationHelper.LoggedInUserEmail
279 | );
280 |
281 | if (newMessageId == null)
282 | return false;
283 | // Find the sent message.
284 | var sentMessageId = await GetSentMessageIdAsync();
285 | if (String.IsNullOrEmpty(sentMessageId))
286 | return false;
287 |
288 | var webLink = await EmailSnippets.GetMessageWebLinkAsync(sentMessageId);
289 |
290 | if (String.IsNullOrEmpty(webLink))
291 | return false;
292 |
293 | return true;
294 |
295 | }
296 |
297 | public static async Task TryDeleteMessageAsync()
298 | {
299 |
300 | // Create a draft message. If you send the message without first creating a draft, you can't easily retrieve the message Id.
301 | var newMessageId = await EmailSnippets.CreateDraftAsync(
302 | STORY_DATA_IDENTIFIER,
303 | DEFAULT_MESSAGE_BODY,
304 | AuthenticationHelper.LoggedInUserEmail
305 | );
306 |
307 | if (newMessageId == null)
308 | return false;
309 |
310 | // Delete the message.
311 | var isDeleted = await EmailSnippets.DeleteMessageAsync(newMessageId);
312 |
313 | return isDeleted;
314 |
315 | }
316 |
317 | public static async Task TryGetMailFoldersAsync()
318 | {
319 |
320 | // The example gets the Inbox and its siblings.
321 | var foldersResults = await EmailSnippets.GetMailFoldersAsync();
322 |
323 | foreach (var folder in foldersResults.CurrentPage)
324 | {
325 | if ((folder.DisplayName == "Inbox")
326 | || (folder.DisplayName == "Drafts")
327 | || (folder.DisplayName == "DeletedItems")
328 | || (folder.DisplayName == "SentItems"))
329 | return true;
330 | }
331 |
332 | return false;
333 |
334 | }
335 |
336 | public static async Task TryCreateMailFolderAsync()
337 | {
338 |
339 | var folderId = await EmailSnippets.CreateMailFolderAsync("Inbox", "FolderToDelete");
340 |
341 |
342 | if (!string.IsNullOrEmpty(folderId))
343 | {
344 | //Cleanup
345 | await EmailSnippets.DeleteMailFolderAsync(folderId);
346 |
347 | return true;
348 | }
349 |
350 | return false;
351 | }
352 |
353 | public static async Task TryUpdateMailFolderAsync()
354 | {
355 |
356 | var folderId = await EmailSnippets.CreateMailFolderAsync("Inbox", "FolderToUpdateAndDelete");
357 |
358 |
359 | if (!string.IsNullOrEmpty(folderId))
360 | {
361 |
362 | bool isFolderUpdated = await EmailSnippets.UpdateMailFolderAsync(folderId, "FolderToDelete");
363 |
364 | //Cleanup
365 | await EmailSnippets.DeleteMailFolderAsync(folderId);
366 |
367 | return isFolderUpdated;
368 | }
369 |
370 | return false;
371 | }
372 |
373 | public static async Task TryMoveMailFolderAsync()
374 | {
375 |
376 | var folderId = await EmailSnippets.CreateMailFolderAsync("Inbox", "FolderToDelete");
377 |
378 |
379 | if (!string.IsNullOrEmpty(folderId))
380 | {
381 |
382 | bool isFolderMoved = await EmailSnippets.MoveMailFolderAsync(folderId, "Drafts");
383 |
384 | //Cleanup
385 | await EmailSnippets.DeleteMailFolderAsync(folderId);
386 |
387 | return isFolderMoved;
388 | }
389 |
390 | return false;
391 |
392 | }
393 |
394 | public static async Task TryCopyMailFolderAsync()
395 | {
396 |
397 | var folderId = await EmailSnippets.CreateMailFolderAsync("Inbox", "FolderToCopyAndDelete");
398 |
399 |
400 | if (!string.IsNullOrEmpty(folderId))
401 | {
402 |
403 | string copiedFolderId = await EmailSnippets.CopyMailFolderAsync(folderId, "Drafts");
404 |
405 | if (!string.IsNullOrEmpty(copiedFolderId))
406 | {
407 |
408 | //Cleanup
409 | await EmailSnippets.DeleteMailFolderAsync(folderId);
410 | await EmailSnippets.DeleteMailFolderAsync(copiedFolderId);
411 |
412 | return true;
413 | }
414 | }
415 |
416 | return false;
417 | }
418 |
419 | public static async Task TryAddFileAttachmentAsync()
420 | {
421 |
422 | var newMessageId = await EmailSnippets.CreateDraftAsync(
423 | STORY_DATA_IDENTIFIER,
424 | DEFAULT_MESSAGE_BODY,
425 | AuthenticationHelper.LoggedInUserEmail
426 | );
427 |
428 | if (newMessageId == null)
429 | return false;
430 |
431 | // Pass a MemoryStream object for the sake of simplicity.
432 |
433 | using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes("TryAddMailAttachmentAsync")))
434 | {
435 | await EmailSnippets.AddFileAttachmentAsync(newMessageId, ms);
436 | }
437 |
438 | return true;
439 |
440 | }
441 |
442 | public static async Task TryDeleteMailFolderAsync()
443 | {
444 |
445 | var folderId = await EmailSnippets.CreateMailFolderAsync("Inbox", "FolderToDelete");
446 |
447 | var isFolderDeleted = await EmailSnippets.DeleteMailFolderAsync(folderId);
448 | return isFolderDeleted;
449 | }
450 |
451 | private static async Task GetSentMessageIdAsync()
452 | {
453 | // Search for a maximum of 10 times
454 | for (int i = 0; i < 10; i++)
455 | {
456 | var message = await EmailSnippets.GetMessagesAsync(STORY_DATA_IDENTIFIER
457 | , DateTimeOffset.Now.Subtract(new TimeSpan(0, 1, 0)));
458 | if (message != null)
459 | return message.Id;
460 |
461 | // Delay before trying again. Increase this value if you connection to the server
462 | // is slow and causes false results.
463 | await Task.Delay(200);
464 |
465 | }
466 |
467 | // Couldn't find the sent message
468 | return string.Empty;
469 | }
470 |
471 | }
472 | }
473 |
474 | //*********************************************************
475 | //
476 | //O365-Win-Snippets, https://github.com/OfficeDev/O365-Win-Snippets
477 | //
478 | //Copyright (c) Microsoft Corporation
479 | //All rights reserved.
480 | //
481 | // MIT License:
482 | // Permission is hereby granted, free of charge, to any person obtaining
483 | // a copy of this software and associated documentation files (the
484 | // ""Software""), to deal in the Software without restriction, including
485 | // without limitation the rights to use, copy, modify, merge, publish,
486 | // distribute, sublicense, and/or sell copies of the Software, and to
487 | // permit persons to whom the Software is furnished to do so, subject to
488 | // the following conditions:
489 |
490 | // The above copyright notice and this permission notice shall be
491 | // included in all copies or substantial portions of the Software.
492 |
493 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
494 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
495 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
496 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
497 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
498 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
499 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
500 | //
501 | //*********************************************************
--------------------------------------------------------------------------------
/src/Files/FilesSnippets.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file.
2 |
3 | using Microsoft.IdentityModel.Clients.ActiveDirectory;
4 | using Microsoft.OData.Core;
5 | using Microsoft.Office365.Discovery;
6 | using Microsoft.Office365.SharePoint.CoreServices;
7 | using Microsoft.Office365.SharePoint.FileServices;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Diagnostics;
11 | using System.IO;
12 | using System.Linq;
13 | using System.Text;
14 | using System.Threading.Tasks;
15 |
16 |
17 | namespace O365_Win_Snippets
18 | {
19 | class FilesSnippets
20 | {
21 | private static SharePointClient _sharePointClient = null;
22 |
23 | ///
24 | /// Checks that an OutlookServicesClient object is available.
25 | ///
26 | /// The OutlookServicesClient object.
27 | public static async Task GetSharePointClientAsync()
28 | {
29 | if (_sharePointClient != null && !String.IsNullOrEmpty(AuthenticationHelper.LastAuthority))
30 | {
31 | Debug.WriteLine("Got a SharePoint client for Files.");
32 | return _sharePointClient;
33 | }
34 | else
35 | {
36 | try
37 | {
38 | //First, look for the authority used during the last authentication.
39 | //If that value is not populated, use CommonAuthority.
40 | string authority = null;
41 |
42 | if (String.IsNullOrEmpty(AuthenticationHelper.LastAuthority))
43 | {
44 | authority = AuthenticationHelper.CommonAuthority;
45 | }
46 | else
47 | {
48 | authority = AuthenticationHelper.LastAuthority;
49 | }
50 |
51 | // Create an AuthenticationContext using this authority.
52 | AuthenticationHelper._authenticationContext = new AuthenticationContext(authority);
53 |
54 | // Set the value of _authenticationContext.UseCorporateNetwork to true so that you
55 | // can use this app inside a corporate intranet. If the value of UseCorporateNetwork
56 | // is true, you also need to add the Enterprise Authentication, Private Networks, and
57 | // Shared User Certificates capabilities in the Package.appxmanifest file.
58 | AuthenticationHelper._authenticationContext.UseCorporateNetwork = true;
59 |
60 | //See the Discovery Service Sample (https://github.com/OfficeDev/Office365-Discovery-Service-Sample)
61 | //for an approach that improves performance by storing the discovery service information in a cache.
62 | DiscoveryClient discoveryClient = new DiscoveryClient(
63 | async () => await AuthenticationHelper.GetTokenHelperAsync(AuthenticationHelper._authenticationContext, AuthenticationHelper.DiscoveryResourceId));
64 |
65 | // Get the specified capability ("Calendar").
66 | CapabilityDiscoveryResult result =
67 | await discoveryClient.DiscoverCapabilityAsync("MyFiles");
68 |
69 | var token = await AuthenticationHelper.GetTokenHelperAsync(AuthenticationHelper._authenticationContext, result.ServiceResourceId);
70 | // Check the token
71 | if (String.IsNullOrEmpty(token))
72 | {
73 | // User cancelled sign-in
74 | return null;
75 | }
76 | else
77 | {
78 |
79 | _sharePointClient = new SharePointClient(
80 | result.ServiceEndpointUri,
81 | async () => await AuthenticationHelper.GetTokenHelperAsync(AuthenticationHelper._authenticationContext, result.ServiceResourceId));
82 | Debug.WriteLine("Got a SharePoint client for Files.");
83 | return _sharePointClient;
84 | }
85 | }
86 | // The following is a list of exceptions you should consider handling in your app.
87 | // In the case of this sample, the exceptions are handled by returning null upstream.
88 | catch (DiscoveryFailedException dfe)
89 | {
90 | Debug.WriteLine(dfe.Message);
91 | }
92 | catch (ArgumentException ae)
93 | {
94 | Debug.WriteLine(ae.Message);
95 | }
96 |
97 | AuthenticationHelper._authenticationContext.TokenCache.Clear();
98 |
99 | return null;
100 | }
101 | }
102 |
103 | //Files operations
104 |
105 | public static async Task CreateFileAsync(string fileName, Stream fileContent)
106 | {
107 |
108 | var sharePointClient = await GetSharePointClientAsync();
109 |
110 | File newFile = new File
111 | {
112 | Name = fileName
113 | };
114 |
115 | await sharePointClient.Files.AddItemAsync(newFile);
116 | await sharePointClient.Files.GetById(newFile.Id).ToFile().UploadAsync(fileContent);
117 |
118 | Debug.WriteLine("Created a file: " + newFile.Id);
119 |
120 | return newFile.Id;
121 |
122 | }
123 |
124 | public static async Task UpdateFileContentAsync(string Id, Stream fileContent)
125 | {
126 | try
127 | {
128 | var sharePointClient = await GetSharePointClientAsync();
129 |
130 | //update the file with the content
131 | await sharePointClient.Files.GetById(Id).ToFile().UploadAsync(fileContent);
132 |
133 | Debug.WriteLine("Updated file content: " + Id);
134 |
135 | return true;
136 |
137 | }
138 | catch (ODataErrorException ex)
139 | {
140 | // GetById will throw an ODataErrorException when the
141 | // item with the specified Id can't be found in the contact store on the server.
142 | Debug.WriteLine(ex.Message);
143 | return false;
144 | }
145 | }
146 |
147 | public static async Task DownloadFileAsync(string Id)
148 | {
149 |
150 | try
151 | {
152 | var sharePointClient = await GetSharePointClientAsync();
153 |
154 | var stream = await sharePointClient.Files.GetById(Id).ToFile().DownloadAsync();
155 |
156 | Debug.WriteLine("Downloaded a file: " + Id);
157 |
158 | return stream;
159 | }
160 | catch (ODataErrorException ex)
161 | {
162 | // GetById will throw an ODataErrorException when the
163 | // item with the specified Id can't be found in the contact store on the server.
164 | Debug.WriteLine(ex.Message);
165 | return null;
166 | }
167 | }
168 |
169 | public static async Task DeleteFileAsync(string Id)
170 | {
171 | try
172 | {
173 | var sharePointClient = await GetSharePointClientAsync();
174 | var file = await sharePointClient.Files.GetById(Id).ToFile().ExecuteAsync();
175 | await file.DeleteAsync();
176 |
177 | Debug.WriteLine("Deleted a file: " + Id);
178 |
179 | return true;
180 | }
181 | catch (ODataErrorException ex)
182 | {
183 | // GetById will throw an ODataErrorException when the
184 | // item with the specified Id can't be found in the contact store on the server.
185 | Debug.WriteLine(ex.Message);
186 | return false;
187 | }
188 | }
189 |
190 | public static async Task CopyFileAsync(string fileId, string destinationFolderId)
191 | {
192 | try
193 | {
194 | var sharePointClient = await GetSharePointClientAsync();
195 |
196 | var copiedFile = await sharePointClient.Files.GetById(fileId).ToFile().CopyAsync(destinationFolderId, null, null);
197 |
198 | Debug.WriteLine("Copied file to folder.");
199 |
200 | return copiedFile.Id;
201 | }
202 | catch (ODataErrorException ex)
203 | {
204 | // GetById will throw an ODataErrorException when the
205 | // item with the specified Id can't be found in the contact store on the server.
206 | Debug.WriteLine(ex.Message);
207 | return null;
208 | }
209 | }
210 |
211 | public static async Task RenameFileAsync(string fileId, string newName)
212 | {
213 |
214 | try
215 | {
216 | var sharePointClient = await GetSharePointClientAsync();
217 |
218 | var file = await sharePointClient.Files.GetById(fileId).ToFile().ExecuteAsync();
219 |
220 | file.Name = newName;
221 | await file.UpdateAsync();
222 |
223 | Debug.WriteLine("Renamed a file: " + fileId);
224 |
225 | return file.Name;
226 | }
227 | catch (ODataErrorException ex)
228 | {
229 | // GetById will throw an ODataErrorException when the
230 | // item with the specified Id can't be found in the contact store on the server.
231 | Debug.WriteLine(ex.Message);
232 | return null;
233 | }
234 | }
235 |
236 | //Folders operations
237 | public static async Task> GetFolderChildrenAsync(string folderId)
238 | {
239 | var sharePointClient = await GetSharePointClientAsync();
240 | try
241 | {
242 | var items = await sharePointClient.Files.GetById(folderId).ToFolder().Children.ExecuteAsync();
243 |
244 | Debug.WriteLine("First child of " + folderId + ": " + items.CurrentPage[0].Id);
245 |
246 | return items.CurrentPage.ToList();
247 | }
248 | catch (ODataErrorException ex)
249 | {
250 | // GetById will throw an ODataErrorException when the
251 | // item with the specified Id can't be found in the contact store on the server.
252 | Debug.WriteLine(ex.Message);
253 | return null;
254 | }
255 | }
256 |
257 | public static async Task CreateFolderAsync(string folderName, string parentFolderId)
258 | {
259 | try
260 | {
261 | var sharePointClient = await GetSharePointClientAsync();
262 | Folder newFolder = new Folder
263 | {
264 | Name = folderName
265 | };
266 |
267 | await sharePointClient.Files.GetById(parentFolderId).ToFolder().Children.AddItemAsync(newFolder);
268 | var newItem = await sharePointClient.Files.GetById(newFolder.Id).ToFolder().ExecuteAsync();
269 |
270 | Debug.WriteLine("Created a folder: " + newItem.Id);
271 |
272 | return (Folder)newItem;
273 | }
274 | catch (ODataErrorException ex)
275 | {
276 | // GetById will throw an ODataErrorException when the
277 | // item with the specified Id can't be found in the contact store on the server.
278 | Debug.WriteLine(ex.Message);
279 | return null;
280 | }
281 | }
282 |
283 |
284 | public static async Task DeleteFolderAsync(string folderId)
285 | {
286 | try
287 | {
288 | var sharePointClient = await GetSharePointClientAsync();
289 | var item = await sharePointClient.Files.GetById(folderId).ToFolder().ExecuteAsync();
290 |
291 | await item.DeleteAsync();
292 |
293 | return true;
294 |
295 | }
296 | catch (ODataErrorException ex)
297 | {
298 | // GetById will throw an ODataErrorException when the
299 | // item with the specified Id can't be found in the contact store on the server.
300 | Debug.WriteLine(ex.Message);
301 | return false;
302 | }
303 | }
304 |
305 | }
306 | }
307 |
308 | //*********************************************************
309 | //
310 | //O365-Win-Snippets, https://github.com/OfficeDev/O365-Win-Snippets
311 | //
312 | //Copyright (c) Microsoft Corporation
313 | //All rights reserved.
314 | //
315 | // MIT License:
316 | // Permission is hereby granted, free of charge, to any person obtaining
317 | // a copy of this software and associated documentation files (the
318 | // ""Software""), to deal in the Software without restriction, including
319 | // without limitation the rights to use, copy, modify, merge, publish,
320 | // distribute, sublicense, and/or sell copies of the Software, and to
321 | // permit persons to whom the Software is furnished to do so, subject to
322 | // the following conditions:
323 |
324 | // The above copyright notice and this permission notice shall be
325 | // included in all copies or substantial portions of the Software.
326 |
327 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
328 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
329 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
330 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
331 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
332 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
333 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
334 | //
335 | //*********************************************************
--------------------------------------------------------------------------------
/src/Files/FilesStories.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file.
2 |
3 | using Microsoft.Office365.SharePoint.FileServices;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace O365_Win_Snippets
12 | {
13 | class FilesStories
14 | {
15 | private static readonly string STORY_DATA_IDENTIFIER = Guid.NewGuid().ToString();
16 |
17 | public static async Task TryGetSharePointClientAsync()
18 | {
19 | var sharepointClient = await FilesSnippets.GetSharePointClientAsync();
20 | return sharepointClient != null;
21 | }
22 |
23 | //Files stories
24 |
25 | public static async Task TryCreateFileAsync()
26 | {
27 | // Grab a list of folder items
28 | var items = await FilesSnippets.GetFolderChildrenAsync("root");
29 | if (items == null)
30 | return false;
31 |
32 | var origCount = items.Count;
33 |
34 | var createdFileId = await FilesSnippets.CreateFileAsync(STORY_DATA_IDENTIFIER + "_" + Guid.NewGuid().ToString(), new MemoryStream(Encoding.UTF8.GetBytes("TryAddFileAsync")));
35 | if (createdFileId == null)
36 | return false;
37 |
38 |
39 | // Grab the files again
40 | items = await FilesSnippets.GetFolderChildrenAsync("root");
41 | if (items == null)
42 | return false;
43 |
44 | // Number of files should have increased by 1
45 | if (items.Count != origCount + 1)
46 | return false;
47 |
48 | //Cleanup
49 | await FilesSnippets.DeleteFileAsync(createdFileId);
50 |
51 |
52 | return true;
53 |
54 | }
55 |
56 | public static async Task TryUpdateFileContentAsync()
57 | {
58 | // Add a file & verify
59 | // Grab a list of files
60 | var items = await FilesSnippets.GetFolderChildrenAsync("root");
61 | if (items == null)
62 | return false;
63 |
64 | var origCount = items.Count;
65 |
66 | // Create a file
67 | var createdFileId = await FilesSnippets.CreateFileAsync(STORY_DATA_IDENTIFIER + "_" + Guid.NewGuid().ToString(), new MemoryStream(Encoding.UTF8.GetBytes("TryUpdateFileAsync")));
68 | if (createdFileId == null)
69 | return false;
70 |
71 | // Grab the files again
72 | items = await FilesSnippets.GetFolderChildrenAsync("root");
73 | if (items == null)
74 | return false;
75 |
76 | // Number of files should have increased by 1
77 | if (items.Count != origCount + 1)
78 | return false;
79 |
80 | // Update the content
81 |
82 | string updatedContent = "Updated content";
83 | var updated = await FilesSnippets.UpdateFileContentAsync(createdFileId, new MemoryStream(Encoding.UTF8.GetBytes(updatedContent)));
84 |
85 | // Download the file and compare with the updated content.
86 |
87 | using (var stream = await FilesSnippets.DownloadFileAsync(createdFileId))
88 | {
89 | if (stream == null)
90 | return false;
91 |
92 | StreamReader reader = new StreamReader(stream);
93 | var downloadedString = await reader.ReadToEndAsync();
94 | if (downloadedString != updatedContent)
95 | return false;
96 | }
97 |
98 | //Cleanup
99 | await FilesSnippets.DeleteFileAsync(createdFileId);
100 |
101 | return updated;
102 |
103 |
104 | }
105 |
106 | public static async Task TryDownloadFileAsync()
107 | {
108 |
109 | string fileContents = "TryDownloadFileAsync";
110 |
111 | // Create a file
112 | var createdFile = await FilesSnippets.CreateFileAsync(STORY_DATA_IDENTIFIER + "_" + Guid.NewGuid().ToString(), new MemoryStream(Encoding.UTF8.GetBytes(fileContents)));
113 | if (createdFile == null)
114 | return false;
115 |
116 | // Download the file
117 | using (var stream = await FilesSnippets.DownloadFileAsync(createdFile))
118 | {
119 | if (stream == null)
120 | return false;
121 |
122 | StreamReader reader = new StreamReader(stream);
123 | var downloadedString = await reader.ReadToEndAsync();
124 | if (downloadedString != fileContents)
125 | return false;
126 | }
127 |
128 | return true;
129 | }
130 |
131 | public static async Task TryDeleteFileAsync()
132 | {
133 | // Grab a list of files
134 | var items = await FilesSnippets.GetFolderChildrenAsync("root");
135 | if (items == null)
136 | return false;
137 |
138 | var origCount = items.Count;
139 |
140 | // Create a file
141 | var createdFile = await FilesSnippets.CreateFileAsync(STORY_DATA_IDENTIFIER + "_" + Guid.NewGuid().ToString(), new MemoryStream(Encoding.UTF8.GetBytes("CanAddFileAsync")));
142 | if (createdFile == null)
143 | return false;
144 |
145 | // Grab the files again
146 | items = await FilesSnippets.GetFolderChildrenAsync("root");
147 | if (items == null)
148 | return false;
149 |
150 | // Number of files should have increased by 1
151 | if (items.Count != origCount + 1)
152 | return false;
153 |
154 | // Delete our test file
155 | await FilesSnippets.DeleteFileAsync(createdFile);
156 |
157 | //Grab the files again
158 | items = await FilesSnippets.GetFolderChildrenAsync("root");
159 | if (items == null)
160 | return false;
161 |
162 | // Number of files should be back at the original count
163 | if (items.Count != origCount)
164 | return false;
165 |
166 | return true;
167 | }
168 |
169 | public static async Task TryCopyFileAsync()
170 | {
171 |
172 | // Grab the root folder.
173 | var items = await FilesSnippets.GetFolderChildrenAsync("root");
174 | if (items == null)
175 | return false;
176 |
177 | // Create a new file.
178 | var createdFileId = await FilesSnippets.CreateFileAsync(STORY_DATA_IDENTIFIER + "_" + Guid.NewGuid().ToString(), new MemoryStream(Encoding.UTF8.GetBytes("TryAddFileAsync")));
179 | if (createdFileId == null)
180 | return false;
181 |
182 | // Create a new folder in the root folder.
183 | var folder = await FilesSnippets.CreateFolderAsync(STORY_DATA_IDENTIFIER, "root");
184 |
185 | // Copy the new file into the new folder.
186 | var copiedFileId = await FilesSnippets.CopyFileAsync(createdFileId, folder.Id);
187 |
188 | // Clean up.
189 | // Comment out if you want to see the file, the folder, and the copied file.
190 | await FilesSnippets.DeleteFileAsync(createdFileId);
191 |
192 | // Deleting the folder also deletes the file copied into it.
193 | await FilesSnippets.DeleteFolderAsync(folder.Id);
194 |
195 |
196 | return true;
197 |
198 | }
199 |
200 | public static async Task TryRenameFileAsync()
201 | {
202 |
203 | string newFileName = "updated name";
204 |
205 | // Create a file
206 | var createdFileId = await FilesSnippets.CreateFileAsync(STORY_DATA_IDENTIFIER + "_" + Guid.NewGuid().ToString(), new MemoryStream(Encoding.UTF8.GetBytes("TryUpdateFileAsync")));
207 | if (createdFileId == null)
208 | return false;
209 |
210 | var fileName = await FilesSnippets.RenameFileAsync(createdFileId, "updated name");
211 |
212 | if (fileName != newFileName)
213 | return false;
214 |
215 | //Cleanup
216 |
217 | await FilesSnippets.DeleteFileAsync(createdFileId);
218 |
219 | return true;
220 |
221 |
222 | }
223 |
224 | //Folders stories
225 |
226 | public static async Task TryGetFolderChildrenAsync()
227 | {
228 | var items = await FilesSnippets.GetFolderChildrenAsync("root");
229 | return items != null;
230 | }
231 |
232 | public static async Task TryCreateFolderAsync()
233 | {
234 |
235 | var folder = await FilesSnippets.CreateFolderAsync(STORY_DATA_IDENTIFIER, "root");
236 |
237 | //Cleanup. Comment if you want to see the new folder under your root folder.
238 | await FilesSnippets.DeleteFolderAsync(folder.Id);
239 |
240 | return folder != null;
241 | }
242 |
243 | public static async Task TryDeleteFolderAsync()
244 | {
245 |
246 | var folder = await FilesSnippets.CreateFolderAsync(STORY_DATA_IDENTIFIER, "root");
247 |
248 |
249 | var result = await FilesSnippets.DeleteFolderAsync(folder.Id);
250 |
251 | return result;
252 |
253 | }
254 |
255 | }
256 | }
257 |
258 | //*********************************************************
259 | //
260 | //O365-Win-Snippets, https://github.com/OfficeDev/O365-Win-Snippets
261 | //
262 | //Copyright (c) Microsoft Corporation
263 | //All rights reserved.
264 | //
265 | // MIT License:
266 | // Permission is hereby granted, free of charge, to any person obtaining
267 | // a copy of this software and associated documentation files (the
268 | // ""Software""), to deal in the Software without restriction, including
269 | // without limitation the rights to use, copy, modify, merge, publish,
270 | // distribute, sublicense, and/or sell copies of the Software, and to
271 | // permit persons to whom the Software is furnished to do so, subject to
272 | // the following conditions:
273 |
274 | // The above copyright notice and this permission notice shall be
275 | // included in all copies or substantial portions of the Software.
276 |
277 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
278 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
279 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
280 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
281 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
282 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
283 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
284 | //
285 | //*********************************************************
--------------------------------------------------------------------------------
/src/MainPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/MainPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.Diagnostics;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Runtime.InteropServices.WindowsRuntime;
8 | using System.Threading.Tasks;
9 | using Windows.Foundation;
10 | using Windows.Foundation.Collections;
11 | using Windows.UI.Xaml;
12 | using Windows.UI.Xaml.Controls;
13 | using Windows.UI.Xaml.Controls.Primitives;
14 | using Windows.UI.Xaml.Data;
15 | using Windows.UI.Xaml.Input;
16 | using Windows.UI.Xaml.Media;
17 | using Windows.UI.Xaml.Navigation;
18 |
19 | // The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
20 |
21 | namespace O365_Win_Snippets
22 | {
23 | ///
24 | /// An empty page that can be used on its own or navigated to within a Frame.
25 | ///
26 | public sealed partial class MainPage : Page
27 | {
28 | public List StoryCollection { get; private set; }
29 | public MainPage()
30 | {
31 | this.InitializeComponent();
32 | CreateTestList();
33 | }
34 |
35 | protected override void OnNavigatedTo(NavigationEventArgs e)
36 | {
37 | // Developer code - if you haven't registered the app yet, we warn you.
38 | if (!App.Current.Resources.ContainsKey("ida:ClientID"))
39 | {
40 | Debug.WriteLine("Oops - App not registered with Office 365. To run this sample, you must register it with Office 365. You can do that through the 'Add | Connected services' dialog in Visual Studio. See Readme for more info");
41 |
42 | }
43 | }
44 | private void CreateTestList()
45 | {
46 | StoryCollection = new List();
47 |
48 | // These stories require your app to have permission to access your organization's directory.
49 | // Comment them if you're not going to run the app with that permission level.
50 |
51 | StoryCollection.Add(new StoryDefinition() { GroupName = "Users & Groups", Title = "Client", RunStoryAsync = UsersAndGroupsStories.TryGetAadGraphClientAsync });
52 | StoryCollection.Add(new StoryDefinition() { GroupName = "Users & Groups", Title = "Read Users", RunStoryAsync = UsersAndGroupsStories.TryGetUsersAsync });
53 | StoryCollection.Add(new StoryDefinition() { GroupName = "Users & Groups", Title = "Tenant Details", RunStoryAsync = UsersAndGroupsStories.TryGetTenantAsync });
54 | StoryCollection.Add(new StoryDefinition() { GroupName = "Users & Groups", Title = "Read Groups", RunStoryAsync = UsersAndGroupsStories.TryGetGroupsAsync });
55 |
56 | StoryCollection.Add(new StoryDefinition() { GroupName = "Contacts", Title = "Client", RunStoryAsync = ContactsStories.TryGetOutlookClientAsync });
57 | StoryCollection.Add(new StoryDefinition() { GroupName = "Contacts", Title = "Read", RunStoryAsync = ContactsStories.TryGetContactsAsync });
58 | StoryCollection.Add(new StoryDefinition() { GroupName = "Contacts", Title = "Get contact", RunStoryAsync = ContactsStories.TryGetContactAsync });
59 | StoryCollection.Add(new StoryDefinition() { GroupName = "Contacts", Title = "Create", RunStoryAsync = ContactsStories.TryAddNewContactAsync });
60 | StoryCollection.Add(new StoryDefinition() { GroupName = "Contacts", Title = "Delete", RunStoryAsync = ContactsStories.TryDeleteContactAsync });
61 | StoryCollection.Add(new StoryDefinition() { GroupName = "Contacts", Title = "Update", RunStoryAsync = ContactsStories.TryUpdateContactAsync });
62 |
63 |
64 | StoryCollection.Add(new StoryDefinition() { GroupName = "Calendar", Title = "Client", RunStoryAsync = CalendarStories.TryGetOutlookClientAsync });
65 | StoryCollection.Add(new StoryDefinition() { GroupName = "Calendar", Title = "Read", RunStoryAsync = CalendarStories.TryGetCalendarEventsAsync });
66 | StoryCollection.Add(new StoryDefinition() { GroupName = "Calendar", Title = "Create", RunStoryAsync = CalendarStories.TryCreateCalendarEventAsync });
67 | StoryCollection.Add(new StoryDefinition() { GroupName = "Calendar", Title = "Create with args", RunStoryAsync = CalendarStories.TryCreateCalendarEventWithArgsAsync });
68 | StoryCollection.Add(new StoryDefinition() { GroupName = "Calendar", Title = "Update", RunStoryAsync = CalendarStories.TryUpdateCalendarEventAsync });
69 | StoryCollection.Add(new StoryDefinition() { GroupName = "Calendar", Title = "Delete", RunStoryAsync = CalendarStories.TryDeleteCalendarEventAsync });
70 |
71 |
72 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email", Title = "Client", RunStoryAsync = EmailStories.TryGetOutlookClientAsync });
73 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email", Title = "Read Inbox", RunStoryAsync = EmailStories.TryGetInboxMessagesAsync });
74 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email", Title = "Read messages", RunStoryAsync = EmailStories.TryGetMessagesAsync });
75 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email", Title = "SendMail", RunStoryAsync = EmailStories.TrySendMessageAsync });
76 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email", Title = "Reply", RunStoryAsync = EmailStories.TryReplyMessageAsync });
77 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email", Title = "Reply All", RunStoryAsync = EmailStories.TryReplyAllAsync });
78 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email", Title = "Forward", RunStoryAsync = EmailStories.TryForwardMessageAsync });
79 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email", Title = "Create draft", RunStoryAsync = EmailStories.TryCreateDraftAsync });
80 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email", Title = "Update", RunStoryAsync = EmailStories.TryUpdateMessageAsync });
81 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email", Title = "Delete", RunStoryAsync = EmailStories.TryDeleteMessageAsync });
82 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email", Title = "Move", RunStoryAsync = EmailStories.TryMoveMessageAsync });
83 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email", Title = "Copy", RunStoryAsync = EmailStories.TryCopyMessageAsync });
84 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email", Title = "Add Attachment", RunStoryAsync = EmailStories.TryAddFileAttachmentAsync });
85 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email", Title = "Get Attachments", RunStoryAsync = EmailStories.TryGetFileAttachmentsAsync });
86 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email", Title = "Get Web Link", RunStoryAsync = EmailStories.TryGetMessageWebLinkAsync });
87 |
88 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email folder", Title = "Read Folders", RunStoryAsync = EmailStories.TryGetMailFoldersAsync });
89 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email folder", Title = "Create", RunStoryAsync = EmailStories.TryCreateMailFolderAsync });
90 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email folder", Title = "Rename", RunStoryAsync = EmailStories.TryUpdateMailFolderAsync });
91 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email folder", Title = "Move", RunStoryAsync = EmailStories.TryMoveMailFolderAsync });
92 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email folder", Title = "Copy", RunStoryAsync = EmailStories.TryCopyMailFolderAsync });
93 | StoryCollection.Add(new StoryDefinition() { GroupName = "Email folder", Title = "Delete", RunStoryAsync = EmailStories.TryDeleteMailFolderAsync });
94 |
95 |
96 |
97 | StoryCollection.Add(new StoryDefinition() { GroupName = "Files", Title = "Client", RunStoryAsync = FilesStories.TryGetSharePointClientAsync });
98 | StoryCollection.Add(new StoryDefinition() { GroupName = "Files", Title = "Read folders", RunStoryAsync = FilesStories.TryGetFolderChildrenAsync });
99 | StoryCollection.Add(new StoryDefinition() { GroupName = "Files", Title = "Create folder", RunStoryAsync = FilesStories.TryCreateFolderAsync });
100 | StoryCollection.Add(new StoryDefinition() { GroupName = "Files", Title = "Delete folder", RunStoryAsync = FilesStories.TryDeleteFolderAsync });
101 | StoryCollection.Add(new StoryDefinition() { GroupName = "Files", Title = "Create file", RunStoryAsync = FilesStories.TryCreateFileAsync });
102 | StoryCollection.Add(new StoryDefinition() { GroupName = "Files", Title = "Update content", RunStoryAsync = FilesStories.TryUpdateFileContentAsync });
103 | StoryCollection.Add(new StoryDefinition() { GroupName = "Files", Title = "Delete file", RunStoryAsync = FilesStories.TryDeleteFileAsync });
104 | StoryCollection.Add(new StoryDefinition() { GroupName = "Files", Title = "Download", RunStoryAsync = FilesStories.TryDownloadFileAsync });
105 | StoryCollection.Add(new StoryDefinition() { GroupName = "Files", Title = "Copy file", RunStoryAsync = FilesStories.TryCopyFileAsync });
106 | StoryCollection.Add(new StoryDefinition() { GroupName = "Files", Title = "Rename file", RunStoryAsync = FilesStories.TryRenameFileAsync });
107 |
108 | var result = from story in StoryCollection group story by story.GroupName into api orderby api.Key select api;
109 | StoriesByApi.Source = result;
110 | }
111 |
112 |
113 | private async void RunSelectedStories_Click(object sender, RoutedEventArgs e)
114 | {
115 |
116 | await runSelectedAsync();
117 | }
118 |
119 | private async Task runSelectedAsync()
120 | {
121 | ResetStories();
122 | Stopwatch sw = new Stopwatch();
123 |
124 | foreach (var story in StoryGrid.SelectedItems)
125 | {
126 | StoryDefinition currentStory = story as StoryDefinition;
127 | currentStory.IsRunning = true;
128 | sw.Restart();
129 | bool result = false;
130 | try
131 | {
132 | result = await currentStory.RunStoryAsync();
133 | Debug.WriteLine(String.Format("{0}.{1} {2}", currentStory.GroupName, currentStory.Title, (result) ? "passed" : "failed"));
134 | }
135 | catch (Exception ex)
136 | {
137 | Debug.WriteLine("{0}.{1} failed. Exception: {2}", currentStory.GroupName, currentStory.Title, ex.Message);
138 | result = false;
139 |
140 | }
141 | currentStory.Result = result;
142 | sw.Stop();
143 | currentStory.DurationMS = sw.ElapsedMilliseconds;
144 | currentStory.IsRunning = false;
145 |
146 |
147 | }
148 |
149 | // To shut down this app when the Stories complete, uncomment the following line.
150 | //Application.Current.Exit();
151 | }
152 |
153 | private async void RunAll_Click(object sender, RoutedEventArgs e)
154 | {
155 | StoryGrid.SelectedItems.Clear();
156 | foreach (var item in StoryGrid.Items)
157 | {
158 | StoryGrid.SelectedItems.Add(item);
159 | }
160 | await runSelectedAsync();
161 | }
162 |
163 | private void ResetStories()
164 | {
165 | foreach (var story in StoryCollection)
166 | {
167 | story.Result = null;
168 | story.DurationMS = null;
169 | }
170 | }
171 |
172 | private void ClearSelection_Click(object sender, RoutedEventArgs e)
173 | {
174 | StoryGrid.SelectedItems.Clear();
175 | }
176 |
177 | private void Disconnect_Click(object sender, RoutedEventArgs e)
178 | {
179 | AuthenticationHelper.SignOut();
180 | StoryGrid.SelectedItems.Clear();
181 | }
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/src/O365-Win-Snippets.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {186CF7AD-D3B3-478E-B08B-650E71DCA726}
8 | AppContainerExe
9 | Properties
10 | O365_Win_Snippets
11 | O365-Win-Snippets
12 | en-US
13 | 8.1
14 | 12
15 | 512
16 | {BC8A1FFA-BEE3-4634-8014-F334798102B3};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
17 | O365-Win-Snippets_TemporaryKey.pfx
18 |
19 |
20 | AnyCPU
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE;NETFX_CORE;WINDOWS_APP
26 | prompt
27 | 4
28 |
29 |
30 | AnyCPU
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE;NETFX_CORE;WINDOWS_APP
35 | prompt
36 | 4
37 |
38 |
39 | true
40 | bin\ARM\Debug\
41 | DEBUG;TRACE;NETFX_CORE;WINDOWS_APP
42 | ;2008
43 | full
44 | ARM
45 | false
46 | prompt
47 | true
48 |
49 |
50 | bin\ARM\Release\
51 | TRACE;NETFX_CORE;WINDOWS_APP
52 | true
53 | ;2008
54 | pdbonly
55 | ARM
56 | false
57 | prompt
58 | true
59 |
60 |
61 | true
62 | bin\x64\Debug\
63 | DEBUG;TRACE;NETFX_CORE;WINDOWS_APP
64 | ;2008
65 | full
66 | x64
67 | false
68 | prompt
69 | true
70 |
71 |
72 | bin\x64\Release\
73 | TRACE;NETFX_CORE;WINDOWS_APP
74 | true
75 | ;2008
76 | pdbonly
77 | x64
78 | false
79 | prompt
80 | true
81 |
82 |
83 | true
84 | bin\x86\Debug\
85 | DEBUG;TRACE;NETFX_CORE;WINDOWS_APP
86 | ;2008
87 | full
88 | x86
89 | false
90 | prompt
91 | true
92 |
93 |
94 | bin\x86\Release\
95 | TRACE;NETFX_CORE;WINDOWS_APP
96 | true
97 | ;2008
98 | pdbonly
99 | x86
100 | false
101 | prompt
102 | true
103 |
104 |
105 |
106 | App.xaml
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 | MainPage.xaml
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | Designer
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 | MSBuild:Compile
144 | Designer
145 |
146 |
147 | MSBuild:Compile
148 | Designer
149 |
150 |
151 |
152 |
153 | ..\packages\Microsoft.Azure.ActiveDirectory.GraphClient.2.0.8\lib\portable-net40+wp8+win8+MonoAndroid10+MonoTouch10+WindowsPhoneApp81\Microsoft.Azure.ActiveDirectory.GraphClient.dll
154 | True
155 |
156 |
157 | False
158 | ..\packages\Microsoft.Data.Edm.5.6.4\lib\portable-net45+wp8+win8+wpa\Microsoft.Data.Edm.dll
159 |
160 |
161 | False
162 | ..\packages\Microsoft.Data.OData.5.6.4\lib\portable-net45+wp8+win8+wpa\Microsoft.Data.OData.dll
163 |
164 |
165 | False
166 | ..\packages\Microsoft.Data.Services.Client.5.6.4\lib\portable-net45+wp8+win8+wpa\Microsoft.Data.Services.Client.dll
167 |
168 |
169 | ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.14.201151115\lib\netcore45\Microsoft.IdentityModel.Clients.ActiveDirectory.winmd
170 |
171 |
172 | False
173 | ..\packages\Microsoft.OData.Client.6.11.0\lib\portable-net45+wp8+win8+wpa\Microsoft.OData.Client.dll
174 |
175 |
176 | False
177 | ..\packages\Microsoft.OData.Core.6.11.0\lib\portable-net40+sl5+wp8+win8+wpa\Microsoft.OData.Core.dll
178 |
179 |
180 | False
181 | ..\packages\Microsoft.OData.Edm.6.11.0\lib\portable-net40+sl5+wp8+win8+wpa\Microsoft.OData.Edm.dll
182 |
183 |
184 | ..\packages\Microsoft.OData.ProxyExtensions.1.0.30\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Microsoft.OData.ProxyExtensions.dll
185 |
186 |
187 | ..\packages\Microsoft.Office365.Discovery.1.0.22\lib\portable-net40+sl5+wp8+win8+MonoAndroid10+MonoTouch10+WindowsPhoneApp81\Microsoft.Office365.Discovery.dll
188 |
189 |
190 | False
191 | ..\packages\Microsoft.Office365.OutlookServices.1.0.34\lib\portable-net45+win+wpa81+wp80+MonoAndroid10+xamarinios10+MonoTouch10\Microsoft.Office365.OutlookServices.Portable.dll
192 |
193 |
194 | ..\packages\Microsoft.Office365.SharePoint.1.0.22\lib\portable-net40+sl5+wp8+win8+MonoAndroid10+MonoTouch10+WindowsPhoneApp81\Microsoft.Office365.SharePoint.Portable.dll
195 |
196 |
197 | False
198 | ..\packages\Microsoft.Spatial.6.11.0\lib\portable-net40+sl5+wp8+win8+wpa\Microsoft.Spatial.dll
199 |
200 |
201 | ..\packages\Newtonsoft.Json.6.0.5\lib\netcore45\Newtonsoft.Json.dll
202 |
203 |
204 | False
205 | ..\packages\System.Spatial.5.6.4\lib\portable-net45+wp8+win8+wpa\System.Spatial.dll
206 |
207 |
208 |
209 | 12.0
210 |
211 |
212 |
219 |
--------------------------------------------------------------------------------
/src/OdataProxy exceptions.txt:
--------------------------------------------------------------------------------
1 | User:
2 |
3 | Error 1 The type 'Microsoft.OData.ProxyExtensions.IEntityBase' is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.OData.ProxyExtensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. C:\Users\jamescro\Documents\Visual Studio 2013\Projects\GraphAPIDemo\GraphAPIDemo\MainPage.xaml.cs 117 21 GraphAPIDemo
4 | Error 2 The type 'Microsoft.OData.ProxyExtensions.EntityBase' is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.OData.ProxyExtensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. C:\Users\jamescro\Documents\Visual Studio 2013\Projects\GraphAPIDemo\GraphAPIDemo\MainPage.xaml.cs 119 21 GraphAPIDemo
5 |
6 |
7 |
8 | Files
9 |
10 |
11 | Error 3 The type 'Microsoft.OData.ProxyExtensions.IReadOnlyQueryableSetBase`1' is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.OData.ProxyExtensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. C:\Users\jamescro\Documents\Visual Studio 2013\Projects\GraphAPIDemo\GraphAPIDemo\MainPage.xaml.cs 142 21 GraphAPIDemo
12 | Error 2 The type 'Microsoft.OData.ProxyExtensions.IReadOnlyQueryableSetBase' is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.OData.ProxyExtensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. C:\Users\jamescro\Documents\Visual Studio 2013\Projects\GraphAPIDemo\GraphAPIDemo\MainPage.xaml.cs 142 21 GraphAPIDemo
13 | Error 1 The type 'Microsoft.OData.ProxyExtensions.IEntityBase' is defined in an assembly that is not referenced. You must add a reference to assembly 'Microsoft.OData.ProxyExtensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. C:\Users\jamescro\Documents\Visual Studio 2013\Projects\GraphAPIDemo\GraphAPIDemo\MainPage.xaml.cs 141 21 GraphAPIDemo
14 | Error 4 'Microsoft.Graph.IItemCollection' does not contain a definition for 'Take' and no extension method 'Take' accepting a first argument of type 'Microsoft.Graph.IItemCollection' could be found (are you missing a using directive or an assembly reference?) C:\Users\jamescro\Documents\Visual Studio 2013\Projects\GraphAPIDemo\GraphAPIDemo\MainPage.xaml.cs 142 45 GraphAPIDemo
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/Package.appxmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | O365-Win-Snippets
6 | Microsoft
7 | Assets\StoreLogo.png
8 |
9 |
10 | 6.3.0
11 | 6.3.0
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/src/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("O365-Win-Snippets")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("O365-Win-Snippets")]
13 | [assembly: AssemblyCopyright("Copyright © 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Build and Revision Numbers
25 | // by using the '*' as shown below:
26 | // [assembly: AssemblyVersion("1.0.*")]
27 | [assembly: AssemblyVersion("1.0.0.0")]
28 | [assembly: AssemblyFileVersion("1.0.0.0")]
29 | [assembly: ComVisible(false)]
--------------------------------------------------------------------------------
/src/ResultToBrushConverter.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file.
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using Windows.UI;
9 | using Windows.UI.Xaml.Data;
10 | using Windows.UI.Xaml.Media;
11 |
12 | namespace O365_Win_Snippets
13 | {
14 | ///
15 | /// Value converter that translates true to and false to
16 | /// .
17 | ///
18 | public sealed class ResultToBrushConverter : IValueConverter
19 | {
20 | private static readonly SolidColorBrush NOT_STARTED_BRUSH = new SolidColorBrush(Colors.LightSlateGray);
21 | private static readonly SolidColorBrush SUCCESS_BRUSH = new SolidColorBrush(Colors.Green);
22 | private static readonly SolidColorBrush FAILED_BRUSH = new SolidColorBrush(Colors.Red);
23 | public object Convert(object value, Type targetType, object parameter, string language)
24 | {
25 | bool? result = (bool?)value;
26 | if (result.HasValue)
27 | {
28 | return (result.Value) ? SUCCESS_BRUSH : FAILED_BRUSH;
29 | }
30 | else
31 | {
32 | return NOT_STARTED_BRUSH;
33 | }
34 | }
35 |
36 | public object ConvertBack(object value, Type targetType, object parameter, string language)
37 | {
38 | throw new NotImplementedException();
39 | }
40 | }
41 | }
42 |
43 | //*********************************************************
44 | //
45 | //O365-Win-Snippets, https://github.com/OfficeDev/O365-Win-Snippets
46 | //
47 | //Copyright (c) Microsoft Corporation
48 | //All rights reserved.
49 | //
50 | // MIT License:
51 | // Permission is hereby granted, free of charge, to any person obtaining
52 | // a copy of this software and associated documentation files (the
53 | // ""Software""), to deal in the Software without restriction, including
54 | // without limitation the rights to use, copy, modify, merge, publish,
55 | // distribute, sublicense, and/or sell copies of the Software, and to
56 | // permit persons to whom the Software is furnished to do so, subject to
57 | // the following conditions:
58 |
59 | // The above copyright notice and this permission notice shall be
60 | // included in all copies or substantial portions of the Software.
61 |
62 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
63 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
64 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
65 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
66 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
67 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
68 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
69 | //
70 | //*********************************************************
--------------------------------------------------------------------------------
/src/StoryDefinition.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file.
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace O365_Win_Snippets
10 | {
11 |
12 | public class StoryDefinition : ViewModelBase
13 | {
14 | public string GroupName { get; set; }
15 | public string Title { get; set; }
16 |
17 | // Delegate method to call
18 | public Func> RunStoryAsync { get; set; }
19 |
20 | bool _isRunning = false;
21 | public bool IsRunning
22 | {
23 | get
24 | {
25 | return _isRunning;
26 | }
27 | set
28 | {
29 | SetProperty(ref _isRunning, value);
30 | }
31 | }
32 |
33 | bool? _result = null;
34 | public bool? Result
35 | {
36 | get
37 | {
38 | return _result;
39 | }
40 | set
41 | {
42 | SetProperty(ref _result, value);
43 | }
44 | }
45 |
46 | long? _durationMS = 0;
47 | public long? DurationMS
48 | {
49 | get
50 | {
51 | return _durationMS;
52 | }
53 | set
54 | {
55 | SetProperty(ref _durationMS, value);
56 | }
57 | }
58 |
59 | }
60 |
61 | public class TestGroup
62 | {
63 | public string GroupTitle { get; set; }
64 | public List Tests { get; set; }
65 | }
66 |
67 |
68 | }
69 |
70 | //*********************************************************
71 | //
72 | //O365-Win-Snippets, https://github.com/OfficeDev/O365-Win-Snippets
73 | //
74 | //Copyright (c) Microsoft Corporation
75 | //All rights reserved.
76 | //
77 | // MIT License:
78 | // Permission is hereby granted, free of charge, to any person obtaining
79 | // a copy of this software and associated documentation files (the
80 | // ""Software""), to deal in the Software without restriction, including
81 | // without limitation the rights to use, copy, modify, merge, publish,
82 | // distribute, sublicense, and/or sell copies of the Software, and to
83 | // permit persons to whom the Software is furnished to do so, subject to
84 | // the following conditions:
85 |
86 | // The above copyright notice and this permission notice shall be
87 | // included in all copies or substantial portions of the Software.
88 |
89 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
90 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
91 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
92 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
93 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
94 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
95 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
96 | //
97 | //*********************************************************
--------------------------------------------------------------------------------
/src/UsersAndGroups/UsersAndGroupsSnippets.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file.
2 |
3 | using Microsoft.Azure.ActiveDirectory.GraphClient;
4 | using Microsoft.IdentityModel.Clients.ActiveDirectory;
5 | using Microsoft.Office365.Discovery;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Diagnostics;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 |
13 |
14 | namespace O365_Win_Snippets
15 | {
16 | class UsersAndGroupsSnippets
17 | {
18 | ///
19 | /// Checks that a Graph client is available to the client.
20 | ///
21 | /// The Graph client.
22 | private static ActiveDirectoryClient _graphClient = null;
23 |
24 | public static async Task GetGraphClientAsync()
25 | {
26 | //Check to see if this client has already been created. If so, return it. Otherwise, create a new one.
27 | if (_graphClient != null)
28 | {
29 | Debug.WriteLine("Got a Graph client for Users and Groups.");
30 | return _graphClient;
31 | }
32 | else
33 | {
34 | // Active Directory service endpoints
35 | const string AadServiceResourceId = "https://graph.windows.net/";
36 | Uri AadServiceEndpointUri = new Uri("https://graph.windows.net/");
37 |
38 | try
39 | {
40 | //First, look for the authority used during the last authentication.
41 | //If that value is not populated, use _commonAuthority.
42 | string authority = null;
43 | if (String.IsNullOrEmpty(AuthenticationHelper.LastAuthority))
44 | {
45 | authority = AuthenticationHelper.CommonAuthority;
46 | }
47 | else
48 | {
49 | authority = AuthenticationHelper.LastAuthority;
50 | }
51 |
52 | // Create an AuthenticationContext using this authority.
53 | AuthenticationHelper._authenticationContext = new AuthenticationContext(authority);
54 |
55 | var token = await AuthenticationHelper.GetTokenHelperAsync(AuthenticationHelper._authenticationContext, AadServiceResourceId);
56 |
57 | // Check the token
58 | if (String.IsNullOrEmpty(token))
59 | {
60 | // User cancelled sign-in
61 | return null;
62 | }
63 | else
64 | {
65 | // Create our ActiveDirectory client.
66 | _graphClient = new ActiveDirectoryClient(
67 | new Uri(AadServiceEndpointUri, AuthenticationHelper.TenantId),
68 | async () => await AuthenticationHelper.GetTokenHelperAsync(AuthenticationHelper._authenticationContext, AadServiceResourceId));
69 |
70 | Debug.WriteLine("Got a Graph client for Users and Groups.");
71 |
72 | return _graphClient;
73 | }
74 |
75 |
76 | }
77 |
78 | catch (Exception)
79 | {
80 | // Argument exception
81 | }
82 | AuthenticationHelper._authenticationContext.TokenCache.Clear();
83 | return null;
84 | }
85 | }
86 |
87 | public static async Task> GetUsersAsync()
88 | {
89 |
90 | var client = await GetGraphClientAsync();
91 |
92 | var users = await client.Users.ExecuteAsync();
93 |
94 | Debug.WriteLine("First user in collection: " + users.CurrentPage[0].DisplayName);
95 |
96 | return users.CurrentPage.ToList();
97 |
98 |
99 | }
100 |
101 | public static async Task GetTenantDetailsAsync()
102 | {
103 |
104 | var client = await GetGraphClientAsync();
105 |
106 | var tenantDetails = await client.TenantDetails.ExecuteAsync();
107 |
108 | Debug.WriteLine("Got tenant details.");
109 |
110 | return tenantDetails.CurrentPage.First();
111 |
112 |
113 | }
114 |
115 | public static async Task> GetGroupsAsync()
116 | {
117 |
118 | var client = await GetGraphClientAsync();
119 |
120 | var groups = await client.Groups.ExecuteAsync();
121 |
122 | if (groups.CurrentPage.Count == 0)
123 | {
124 | Debug.WriteLine("No groups.");
125 | return new List();
126 | }
127 |
128 | Debug.WriteLine("First group in collection: " + groups.CurrentPage[0].DisplayName);
129 |
130 | return groups.CurrentPage.ToList();
131 |
132 | }
133 |
134 | }
135 | }
136 |
137 | //*********************************************************
138 | //
139 | //O365-Win-Snippets, https://github.com/OfficeDev/O365-Win-Snippets
140 | //
141 | //Copyright (c) Microsoft Corporation
142 | //All rights reserved.
143 | //
144 | // MIT License:
145 | // Permission is hereby granted, free of charge, to any person obtaining
146 | // a copy of this software and associated documentation files (the
147 | // ""Software""), to deal in the Software without restriction, including
148 | // without limitation the rights to use, copy, modify, merge, publish,
149 | // distribute, sublicense, and/or sell copies of the Software, and to
150 | // permit persons to whom the Software is furnished to do so, subject to
151 | // the following conditions:
152 |
153 | // The above copyright notice and this permission notice shall be
154 | // included in all copies or substantial portions of the Software.
155 |
156 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
157 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
158 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
159 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
160 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
161 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
162 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
163 | //
164 | //*********************************************************
--------------------------------------------------------------------------------
/src/UsersAndGroups/UsersAndGroupsStories.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file.
2 |
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace O365_Win_Snippets
10 | {
11 | class UsersAndGroupsStories
12 | {
13 | public static async Task TryGetAadGraphClientAsync()
14 | {
15 | var client = await UsersAndGroupsSnippets.GetGraphClientAsync();
16 | return client != null;
17 | }
18 |
19 | public static async Task TryGetUsersAsync()
20 | {
21 | var users = await UsersAndGroupsSnippets.GetUsersAsync();
22 |
23 | return users != null;
24 | }
25 |
26 | public static async Task TryGetTenantAsync()
27 | {
28 | var details = await UsersAndGroupsSnippets.GetTenantDetailsAsync();
29 |
30 | return details != null;
31 | }
32 |
33 | public static async Task TryGetGroupsAsync()
34 | {
35 | var groups = await UsersAndGroupsSnippets.GetGroupsAsync();
36 |
37 | return groups != null;
38 | }
39 |
40 | }
41 | }
42 |
43 | //*********************************************************
44 | //
45 | //O365-Win-Snippets, https://github.com/OfficeDev/O365-Win-Snippets
46 | //
47 | //Copyright (c) Microsoft Corporation
48 | //All rights reserved.
49 | //
50 | // MIT License:
51 | // Permission is hereby granted, free of charge, to any person obtaining
52 | // a copy of this software and associated documentation files (the
53 | // ""Software""), to deal in the Software without restriction, including
54 | // without limitation the rights to use, copy, modify, merge, publish,
55 | // distribute, sublicense, and/or sell copies of the Software, and to
56 | // permit persons to whom the Software is furnished to do so, subject to
57 | // the following conditions:
58 |
59 | // The above copyright notice and this permission notice shall be
60 | // included in all copies or substantial portions of the Software.
61 |
62 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
63 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
64 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
65 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
66 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
67 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
68 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
69 | //
70 | //*********************************************************
--------------------------------------------------------------------------------
/src/ViewModelBase.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file.
2 |
3 | using System;
4 | using System.ComponentModel;
5 | using System.Runtime.CompilerServices;
6 |
7 | namespace O365_Win_Snippets
8 | {
9 | ///
10 | /// Base view model for working with Office 365 services.
11 | ///
12 | public class ViewModelBase : INotifyPropertyChanged
13 | {
14 |
15 | protected bool SetProperty(ref T field, T value, [CallerMemberName] string propertyName = "")
16 | {
17 | // If the value is the same as the current value, return false to indicate this was a no-op.
18 | if (Object.Equals(field, value))
19 | return false;
20 |
21 | // Raise any registered property changed events and indicate to the user that the value was indeed changed.
22 | field = value;
23 | NotifyPropertyChanged(propertyName);
24 | return true;
25 | }
26 |
27 | public event PropertyChangedEventHandler PropertyChanged;
28 |
29 |
30 | protected void NotifyPropertyChanged([CallerMemberName]string propertyName = "")
31 | {
32 | if (PropertyChanged != null)
33 | PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
34 | }
35 | }
36 | }
37 |
38 | //*********************************************************
39 | //
40 | // MIT License:
41 | // Permission is hereby granted, free of charge, to any person obtaining
42 | // a copy of this software and associated documentation files (the
43 | // ""Software""), to deal in the Software without restriction, including
44 | // without limitation the rights to use, copy, modify, merge, publish,
45 | // distribute, sublicense, and/or sell copies of the Software, and to
46 | // permit persons to whom the Software is furnished to do so, subject to
47 | // the following conditions:
48 |
49 | // The above copyright notice and this permission notice shall be
50 | // included in all copies or substantial portions of the Software.
51 |
52 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
53 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
54 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
55 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
56 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
57 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
58 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
59 | //
60 | //*********************************************************
61 |
--------------------------------------------------------------------------------
/src/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------