Skip to content

Latest commit

 

History

History

day21-planner

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

Day 21 - Creating plans, buckets, and tasks in Planner

Prerequisites

To complete this sample you need the following:

  • Complete the Base Console Application Setup
  • Complete the Day 20 - Device Code Auth Setup
  • Visual Studio Code installed on your development machine. If you do not have Visual Studio Code, visit the previous link for download options. (Note: This tutorial was written with Visual Studio Code version 1.52.1. The steps in this guide may work with other versions, but that has not been tested.)
  • .Net Core SDK. (Note This tutorial was written with .Net Core SDK 5.0.101. The steps in this guide may work with other versions, but that has not been tested.)
  • C# extension for Visual Studio Code
  • Either a personal Microsoft account with a mailbox on Outlook.com, or a Microsoft work or school account.

If you don't have a Microsoft account, there are a couple of options to get a free account:

Step 1: Update the App Registration permissions

As this exercise requires new permissions the App Registration needs to be updated to include the Group.ReadWrite.All and User.ReadBasic.All permissions using the new Azure AD Portal App Registrations UI.

  1. Open a browser and navigate to the Azure AD Portal app registrations page. Login using a personal account (aka: Microsoft Account) or Work or School Account with permissions to create app registrations.

    Note: If you do not have permissions to create app registrations contact your Azure AD domain administrators.

  2. Click on the .NET Core Graph Tutorial item in the list

    Note: If you used a different name while completing the Base Console Application Setup select that instead.

  3. Click API permissions from the current blade content.

    1. Click Add a permission from the current blade content.

    2. On the Request API permissions flyout select Microsoft Graph.

      Screenshot of selecting Microsoft Graph permission to add to app registration

    3. Select Delegated permissions.

    4. In the "Select permissions" search box type "<Start of permission string>".

    5. Select Group.ReadWrite.All from the filtered list.

      Screenshot of adding Delegated permission for Group.ReadWrite.All

    6. Selection User.ReadBasic.All from the filtered list. Screenshot of adding Delegated permission for User.ReadBasic.All

    7. Click Add permissions at the bottom of flyout.

  4. Back on the API permissions content blade, click Grant admin consent for <name of tenant>.

    Screenshot of granting admin consent for newly added permission

    1. Click Yes.

    Note: Make sure you do not have any application permission already selected, it will make the request fail. If you do have some, remove them before granting the new permissions.

Step 2: Ensure that you are part of an Office 365 group

Planner relies on the Office 365 group infrastructure to function properly. Please make sure you create a group.

Step 3: Enable your application for Device Code Flow

  1. On the application registration view from the last step, click on Manifest.
  2. Set the allowPublicClient property to true.
  3. Click on Save

Step 4: Extend the app to List existing Planner Plans

In this step you will create a Helper method that encapsulates the logic for listing existing plans and then add calls to the console application created in the Device Code Flow.

Important: Ensure that you follow the steps from Day 20 Device Code Flow exercise or today's application updates will not leverage the proper authentication flow necessary to be successful.

Extend program to List existing Planner Plans

  1. Inside the Program class update the method Main with the following definition. This method will leverage a Helper we will create next

    static void Main(string[] args)
    {
        // Load appsettings.json
        var config = LoadAppSettings();
        if (null == config)
        {
            Console.WriteLine("Missing or invalid appsettings.json file. Please see README.md for configuration instructions.");
            return;
        }
    
        var GraphServiceClient = GetAuthenticatedGraphClient(config);
        var plannerHelper = new PlannerHelper(GraphServiceClient);
        plannerHelper.PlannerHelperCall().GetAwaiter().GetResult();
    }
  2. Inside the Helpers folder add a class PlannerHelper.cs with the following definition.

    We will build on this class during the exercise. As it is defined, the helper will list current plans for the first group it can find, and create one if none exist.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using Microsoft.Graph;
    
    namespace ConsoleGraphTest
    {
        public class PlannerHelper
        {
            private readonly GraphServiceClient _graphClient;
            public PlannerHelper(GraphServiceClient graphClient)
            {
                _graphClient = graphClient ?? throw new ArgumentNullException(nameof(graphClient));
            }
            public async Task PlannerHelperCall()
            {
                //Getting the first group we can find to create a plan
                var groupId = (await _graphClient.Me.GetMemberGroups(false).Request().PostAsync()).FirstOrDefault();
    
                if (groupId != null)
                {
                    var users = await _graphClient.Users.Request(new List<QueryOption> {
                            new QueryOption("$top", "3")
                        }).GetAsync();
    
                    var planId = await GetAndListCurrentPlans(groupId) ?? await CreatePlannerPlan(users, groupId);
                }
            }
            private async Task<string> GetAndListCurrentPlans(string groupId)
            {
                //Querying plans in current group
                var plans = await _graphClient.Groups[groupId].Planner.Plans.Request(new List<QueryOption>
                {
                    new QueryOption("$orderby", "Title asc")
                }).GetAsync();
                if (plans.Any())
                {
                    Console.WriteLine($"Number of plans in current tenant: {plans.Count}");
                    Console.WriteLine(plans.Select(x => $"-- {x.Title}").Aggregate((x, y) => $"{x}\n{y}"));
                    return plans.First().Id;
                }
                else
                {
                    Console.WriteLine("No existing plan");
                    return null;
                }
            }
            private async Task<string> CreatePlannerPlan(IEnumerable<User> users, string groupId)
            {
                // Getting users to share the plan with
                var sharedWith = new PlannerUserIds();
                users.ToList().ForEach(x => sharedWith.Add(x.Id));
    
                // Creating a new planner plan
                var createdPlan = await _graphClient.Planner.Plans.Request().AddAsync(
                    new PlannerPlan
                    {
                        Title = $"My new Plan {Guid.NewGuid().ToString()}",
                        Owner = groupId,
                        Details = new PlannerPlanDetails
                        {
                            SharedWith = sharedWith,
                            CategoryDescriptions = new PlannerCategoryDescriptions
                            {
                                Category1 = "my first category",
                                Category2 = "my second category"
                            },
                        }
                    }
                );
                Console.WriteLine($"Added a new plan {createdPlan.Id}");
                return createdPlan.Id;
            }
        }
    }
  3. Save all files.

The console application is now able to list the plans in the group and create one if none exist. In order to test the console application run the following commands from the command line:

dotnet build
dotnet run

Extend program to add a Bucket

  1. Inside the PlannerHelper class add a new method CreatePlannerBucket with the following definition. This method adds a new bucket to a plan.

    private async Task<string> CreatePlannerBucket(string groupId, string planId)
    {
        // Creating a new bucket within the plan
        var createdBucket = await _graphClient.Planner.Buckets.Request().AddAsync(
            new PlannerBucket
            {
                Name = "my first bucket",
                OrderHint = " !",
                PlanId = planId
            }
        );
        Console.WriteLine($"Added new bucket {createdBucket.Name} to plan");
        return createdBucket.Id;
    }
  2. Inside the PlannerHelper add the following line at the end of the PlannerHelperCall method.

    var bucketId = await CreatePlannerBucket(groupId, planId);
  3. Save all files.

The console application is now able add new buckets to a plan. In order to test the console application run the following commands from the command line:

dotnet build
dotnet run

Extend program to add a Task

  1. Inside the PlannerHelper class add a new method CreatePlannerTask with the following definition. This method adds a new task to a bucket.

    private async Task CreatePlannerTask(IEnumerable<User> users, string groupId, string planId, string bucketId)
    {
        // Preparing the assignment for the task
        var assignments = new PlannerAssignments();
        users.ToList().ForEach(x => assignments.AddAssignee(x.Id));
        // Creating a task within the bucket
        var createdTask = await _graphClient.Planner.Tasks.Request().AddAsync(
            new PlannerTask
            {
                DueDateTime = DateTimeOffset.UtcNow.AddDays(7),
                Title = "Do the dishes",
                Details = new PlannerTaskDetails
                {
                    Description = "Do the dishes that are remaining in the sink"
                },
                Assignments = assignments,
                PlanId = planId,
                BucketId = bucketId
            }
        );
        Console.WriteLine($"Added new task {createdTask.Title} to bucket");
    }
  2. Inside the PlannerHelper class update the PlannerHelperCall method to add the following line at the end.

    await CreatePlannerTask(users, groupId, planId, bucketId);
  3. Save all files.

The console application is now able add new tasks to a bucket. In order to test the console application run the following commands from the command line:

dotnet build
dotnet run