Microsoft Graph for Office 365 - 用例:在Planner中创建plans, buckets和tasks

Microsoft 365 同时被 3 个专栏收录
163 篇文章 2 订阅
76 篇文章 0 订阅

本篇我们要将应用程序跟Planner集成。
在这里插入图片描述

Microsoft Planner介绍

首先自然是先介绍一下Planner。Planner是Office 365的组件之一,用于团队任务管理。
Planner通过在内部搜集管理任务来帮助团队进行自我管理和快速开始新项目。Planner提供跟踪进度的能力、提供会话的功能,并能将报告状态以不同的图表呈现。Microsoft Planner是Office 365生态系统的一部分,自然Microsoft Graph中具有Planner相关的API。如果读者想要了解更多关于服务自身的内容,微软建议大家查看详细的介绍。总之今天我们介绍的内容是如何利用Microsoft Graph的API去自动化和集成Planner的一些内容。

Plans

Plans是Planner的起点,也就是基础单元。它是一个任务、设置和其他内容的逻辑容器。现阶段,plans必须创建在Office 365组的下面,一个组可以包含多个plans。用户可以通过Planner(tasks.office.com)和Microsoft Teams(添加标签页时)创建plans。作为开发者,我们可以通过planner/plans终结点去创建新的plans。有两点要注意:plans也遵从安全设置;plan的owner属性必须设置为其关联的组的Id。

我们今天要演示的就是用代码创建plans。

Buckets

Buckets,直译是桶的意思,它实际上是plan中的一个逻辑容器,也可以理解为Planner的第二级容器。Buckets帮助用户组织他们的任务,如基于步骤、状态、分类和所有权等,这取决于团队要如何使用。每个Bucket在Planner中展示为垂直的一列。
在这里插入图片描述
作为开发者,我们可以利用Microsoft Graph去创建/更新/删除buckets。这在我们想要模板化plans时很有用。试想假设我们为一家提供市场服务的咨询公司工作,其中大多数的广告活动项目都遵从相同的模式:一些属于设计者的任务,一些属于网站长的任务,一些属于社区管理者的任务和一些印刷层的任务等。我们完全可以想象得到,创建新项目和plans的自动化,包含了一些默认的buckets用来分工。buckets终结点可以帮助我们实现它。

Tasks

任务就不需要过多解释了,因为它就是任务……是指一个项目中想要完成的单元工作以推进项目的顺利进行。通过tasks终结点我们可以创建/读取/更新/删除任务及其相关的细节信息,包括分类、进度、受理人、讨论区等。

继续上面提到的那个例子,向模板里继续添加默认的tasks并指派给相关的人员,这使得模板更加丰富了。

Permissions

现阶段,跟Planner交互需要Groups.Read.All或Groups.ReadWrite.All权限。我们这次代码演示的内容会向Planner写数据,因此需要Groups.ReadWrite.All权限,同时需要查询租户内的用户,也需要User.ReadBasic.All权限。

练习

介绍完了该说代码了。
Step 1. 更新应用程序注册权限

前面介绍了,不多说了,如果还没有所需的权限就更新一下,记得选择托管权限。

Step 2. 确保要使用的用户属于某个Office 365组
为了用于演示,其实最简单的方式就是用我们的用户创建一个新组。

Step 3. 为你的应用启用设备码流支持
可以参考上一篇
本文的示例需要设备码流进行认证。

Step 4. 代码实现
在Helpers文件夹中创建一个新类PlannerHelper.cs,并替换为以下代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Graph;

namespace GraphDemo
{
    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;
        }
    }
}

扩展Program类去列出存在的Plans

Program类中更新Main方法,添加以下两行代码用于获取plans:

var plannerHelper = new PlannerHelper(graphClient);
plannerHelper.PlannerHelperCall().GetAwaiter().GetResult();

下面我们继续添加Bucket和Task的操作支持。

添加Bucket
在PlannerHelper类中添加CreatePlannerBucket方法,代码如下:

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;
        }

在PlannerHelperCall方法的末尾添加代码:

var bucketId = await CreatePlannerBucket(groupId, planId);

添加Task
在PlannerHelper类中添加CreatePlannerTask方法,代码如下:

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");
        }

注意:在添加Task时我们的代码是查询当前租户中的前三个用户作为受理人添加的,如果我们的Plan是新建的,需要把这三个用户添加进来作为成员,否则在添加完Task之后我们在界面上看到Task的受理人处会显示前成员。

在PlannerHelperCall方法的末尾继续添加一行代码:

await CreatePlannerTask(users, groupId, planId, bucketId);

到这里要演示的代码就全部完成了。
运行结果如下所示:
在这里插入图片描述
在这里插入图片描述
示例代码已更新,戳这里

  • 2
    点赞
  • 0
    评论
  • 2
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:猿与汪的秘密 设计师:我叫白小胖 返回首页

打赏作者

Justin-Liu

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值