Msg.Planner.Tasks (msg v0.3.8)
Manage Microsoft Planner Tasks.
Planner Tasks belong to Plans and can be assigned to users. Tasks support custom metadata embedded in the description field via HTML comments for application-specific data.
Required Permissions
Tasks in Group Plans
- Application: ❌ Not supported
- Delegated:
Tasks.ReadWriteorGroup.ReadWrite.All- required for group plan tasks
User Tasks
- Application:
Tasks.ReadWrite.All- read/write all tasks - Delegated:
Tasks.ReadWrite- read/write user's tasks
Authentication
- Tasks in group plans: Requires delegated permissions (refresh token)
- User tasks: Works with application-only authentication
Etag-Based Concurrency
Like Plans, Tasks require etags for all update and delete operations. Etags are returned
in the @odata.etag field and must be included in the If-Match header.
Metadata Embedding
Since Planner tasks don't support open extensions, this module provides helper functions to embed custom metadata in task descriptions using HTML comments:
<!-- metadata:project_id=proj_123,resource_id=res_456 -->Examples
# List tasks in a plan
{:ok, tasks} = Msg.Planner.Tasks.list_by_plan(client, "plan-id")
# List tasks assigned to a user
{:ok, tasks} = Msg.Planner.Tasks.list_by_user(client, user_id: "user@contoso.com")
# Create task with embedded metadata
description = Msg.Planner.Tasks.embed_metadata(
"Complete project deliverable",
%{project_id: "proj_123", resource_id: "res_456"}
)
{:ok, task} = Msg.Planner.Tasks.create(client, %{
plan_id: "plan-id",
title: "Complete deliverable by Jan 15",
description: description
})
# Parse metadata from task
metadata = Msg.Planner.Tasks.parse_metadata(task["description"])
# => %{project_id: "proj_123", resource_id: "res_456"}References
Summary
Functions
Creates a new Planner Task.
Deletes a Planner Task.
Embeds metadata in a task description.
Gets a single Planner Task.
Lists tasks in a Planner Plan.
Lists tasks assigned to a user.
Parses metadata from a task description.
Updates a Planner Task.
Functions
@spec create(Req.Request.t(), map()) :: {:ok, map()} | {:error, term()}
Creates a new Planner Task.
Parameters
client- Authenticated Req.Request clienttask- Map with task properties::plan_id(required) - ID of plan to create task in:title(required) - Task title:due_date_time(optional) - Due date:start_date_time(optional) - Start date:percent_complete(optional) - 0-100:assignments(optional) - Map of user assignments:description(optional) - Task description
Returns
{:ok, task}- Created task with generatedidand@odata.etag{:error, term}- Error
Examples
{:ok, task} = Msg.Planner.Tasks.create(client, %{
plan_id: "plan-id",
title: "Complete deliverable by Jan 15",
due_date_time: "2025-01-15T17:00:00Z",
description: "Complete project deliverable and submit for review"
})
@spec delete(Req.Request.t(), String.t(), String.t()) :: :ok | {:error, term()}
Deletes a Planner Task.
Important: Requires the current etag for concurrency control.
Parameters
client- Authenticated Req.Request clienttask_id- ID of task to deleteetag- Current etag for concurrency control
Returns
:ok- Task deleted successfully (204 status){:error, {:etag_mismatch, current_etag}}- Etag conflict (412){:error, :not_found}- Task doesn't exist{:error, term}- Other errors
Examples
{:ok, task} = Msg.Planner.Tasks.get(client, task_id)
:ok = Msg.Planner.Tasks.delete(client, task_id, task["@odata.etag"])
Embeds metadata in a task description.
Adds or updates an HTML comment at the beginning of the description with custom metadata. If metadata already exists, it will be replaced.
Parameters
description- Existing description (may be nil or empty)metadata- Map of metadata key-value pairs
Returns
- Updated description string with metadata embedded
Examples
desc = Msg.Planner.Tasks.embed_metadata(
"Complete the deliverable",
%{project_id: "proj_123", resource_id: "res_456"}
)
# => "<!-- metadata:project_id=proj_123,resource_id=res_456 -->\nComplete the deliverable"
# Update existing metadata
existing = "<!-- metadata:old=value -->\nOld description"
updated = Msg.Planner.Tasks.embed_metadata(existing, %{new: "data"})
# => "<!-- metadata:new=data -->\nOld description"
@spec get(Req.Request.t(), String.t()) :: {:ok, map()} | {:error, term()}
Gets a single Planner Task.
Parameters
client- Authenticated Req.Request clienttask_id- ID of the task to retrieve
Returns
{:ok, task}- Task map with details including@odata.etag{:error, :not_found}- Task doesn't exist{:error, term}- Other errors
Examples
{:ok, task} = Msg.Planner.Tasks.get(client, "task-id")
etag = task["@odata.etag"]
@spec list_by_plan(Req.Request.t(), String.t(), keyword()) :: {:ok, [map()]} | {:ok, map()} | {:error, term()}
Lists tasks in a Planner Plan.
Parameters
client- Authenticated Req.Request clientplan_id- ID of the planopts- Keyword list of options::auto_paginate- Boolean, default true (fetch all pages)
Returns
{:ok, [task]}- List of tasks (all tasks in the plan){:error, term}- Error
Examples
{:ok, tasks} = Msg.Planner.Tasks.list_by_plan(client, "plan-id")
@spec list_by_user( Req.Request.t(), keyword() ) :: {:ok, [map()]} | {:ok, map()} | {:error, term()}
Lists tasks assigned to a user.
Parameters
client- Authenticated Req.Request clientopts- Keyword list of options::user_id(required) - User ID or UPN:auto_paginate- Boolean, default true (fetch all pages)
Returns
{:ok, [task]}- All tasks assigned to specified user (across all plans){:error, term}- Error
Examples
{:ok, tasks} = Msg.Planner.Tasks.list_by_user(client, user_id: "user@contoso.com")
Parses metadata from a task description.
Extracts custom metadata embedded in an HTML comment at the beginning of the description.
Parameters
description- Task description string (may be nil)
Returns
- Map of metadata key-value pairs, or
nilif no metadata found
Format
The metadata must be in the first line as an HTML comment:
<!-- metadata:key1=value1,key2=value2,key3=value3 -->Examples
description = """
<!-- metadata:project_id=proj_123,resource_id=res_456,organization_id=org_789 -->
Complete the deliverable
Due by end of day
"""
metadata = Msg.Planner.Tasks.parse_metadata(description)
# => %{project_id: "proj_123", resource_id: "res_456", organization_id: "org_789"}
# No metadata
Msg.Planner.Tasks.parse_metadata("Just a description")
# => nil
Updates a Planner Task.
Important: Requires the current etag for concurrency control.
Parameters
client- Authenticated Req.Request clienttask_id- ID of task to updateupdates- Map of fields to updateopts- Keyword list of options::etag(required) - Current etag from the task
Returns
{:ok, task}- Updated task with new@odata.etag{:error, {:etag_mismatch, current_etag}}- Etag conflict (412){:error, :not_found}- Task doesn't exist{:error, term}- Other errors
Examples
{:ok, task} = Msg.Planner.Tasks.get(client, task_id)
{:ok, updated} = Msg.Planner.Tasks.update(client, task_id,
%{percent_complete: 50},
etag: task["@odata.etag"]
)