[BETA] Notion Recurring Tasks
@tildelabs
code:
data:privatelast updated:3 years ago
today
Build integrations remarkably fast!
You're viewing a public workflow template.
Sign up to customize, add steps, modify code and more.
Join 1,000,000+ developers using the Pipedream platform
steps.
trigger
Cron Scheduler
Deploy to configure a custom schedule
This workflow runs on Pipedream's servers and is triggered on a custom schedule.
steps.
config
auth
to use OAuth tokens and API keys in code via theauths object
params
Notion API Token

Enter your notion API Token here. Do not share this with anyone!

 
string ·params.notionApiToken
Task Database ID

Enter the target Notion database ID here.

 
string ·params.taskDatabaseId
Completed Property Name

The name for a task's "Completed" property in Notion.
Type: Checkbox

 
Complete
string ·params.completedPropertyName
Due Date Property Name

The name for a task's "Due Date" property in Notion.
Type: Date

 
Due Date
string ·params.dueDatePropertyName
Interval Property Name

The name for a task's "Interval" property in Notion.
Type: Select

 
Interval
string ·params.intervalPropertyName
Optional
code
Write any Node.jscodeand use anynpm package. You can alsoexport datafor use in later steps via return or this.key = 'value', pass input data to your code viaparams, and maintain state across executions with$checkpoint.
async (event, steps, params) => {
1
2
3
4
5
6
7
8
9
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
/*******************************************************************************/
/*** DO NOT EDIT ANY CODE. ENTER YOUR CONFIGURATION VALUES IN THE FORM ABOVE ***/
/*******************************************************************************/

// Collect and assign user input
this.API_TOKEN = params.notionApiToken
this.DB_ID = params.taskDatabaseId
this.PROPS = {
  complete: params.completedPropertyName, // Type: Checkbox
  dueDate: params.dueDatePropertyName,    // Type: Date
  interval: params.intervalPropertyName   // Type: Select
}

this.INTERVALS = params.intervals && Object.keys(params.intervals).length > 0 ? params.intervals : {
  "Daily" : [1, 'days'],
  "Weekly" : [1, 'weeks'],
  "Biweekly" : [2, 'weeks'],
  "Monthly" : [1, 'months'],
  "Quarterly" : [1, 'quarters'],
  "Semi-Annually" : [6, 'months'],
  "Annually" : [1, 'years']
}

// Validation
console.log('Validating user input...')
if (!/^secret_[\d|a-z|A-Z]+$/.test(this.API_TOKEN)) { throw new Error('Invalid Notion API token format')}
if (!/^[\d|a-f]{8}-?([\d|a-f]{4}-?){3}[\d|a-f]{12}$/.test(this.DB_ID)) { throw new Error('Invalid database ID format')}
const validIntervalUnits = ['days', 'weeks', 'months', 'quarters', 'years']
for (const interval in this.INTERVALS) {
  if (!(Array.isArray(this.INTERVALS[interval]) && this.INTERVALS[interval].length === 2)) { throw new Error(`Invalid recurring interval configuration for option: ${interval}.`)}
  if (!Number.isInteger(this.INTERVALS[interval][0])) { throw new Error(`Recurring interval must be an integer for option: ${interval}.`)}
  if (!(typeof this.INTERVALS[interval][1] === 'string' || this.INTERVALS[interval][1] instanceof String)) { throw new Error(`Recurring unit must be a string for option: ${interval}.`)}
  if (!validIntervalUnits.includes(this.INTERVALS[interval][1])) { throw new Error(`Recurring unit for option ${interval} must be one of: ${validIntervalUnits.join(', ')}.`)}
}
console.log('Validation complete!')
steps.
fetchCompletedRecurringTasks
auth
to use OAuth tokens and API keys in code via theauths object
code
Write any Node.jscodeand use anynpm package. You can alsoexport datafor use in later steps via return or this.key = 'value', pass input data to your code viaparams, and maintain state across executions with$checkpoint.
async (event, steps) => {
1
2
3
4
5
6
7
8
9
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
42
}
43
const axios = require("axios")
// Fetch completed recurring tasks
console.log("Fetch completed recurring tasks...")
const resp = await axios({
  method: "POST",
  url: `https://api.notion.com/v1/databases/${steps.config.DB_ID}/query`,
  headers: {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${steps.config.API_TOKEN}`, // API KEY
    "Notion-Version": "2021-05-13"
  },
  data : {
    filter : {
      and : [
        {
          property : steps.config.PROPS.complete,
          checkbox : {
            equals : true
          }
        },
        {
          property : steps.config.PROPS.interval,
          select : {
            is_not_empty : true
          }
        },
        {
          property : steps.config.PROPS.dueDate,
          date : {
            is_not_empty : true
          }
        }
      ]
    }
  }
}).catch(err => {
  console.log(err.response.data)
  throw err
})
console.log("Fetch complete!")
this.tasks = resp.data.results
steps.
updateRecurringTasks
auth
to use OAuth tokens and API keys in code via theauths object
code
Write any Node.jscodeand use anynpm package. You can alsoexport datafor use in later steps via return or this.key = 'value', pass input data to your code viaparams, and maintain state across executions with$checkpoint.
async (event, steps) => {
1
2
3
4
5
6
7
8
9
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
42
43
44
45
46
47
}
48
const axios = require("axios")
const moment = require("moment")
const DATE_TIME_REGEX = /^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(.[0-9]{3})?(-[0-9]{2}:[0-9]{2})?$/
this.updatedTasks = []

// Update tasks
console.log("Update recurring tasks with new dates...")
for (const task of steps.fetchCompletedRecurringTasks.tasks) {
  let patch = { properties : {} }
  // Uncheck the Complete checkbox
  patch.properties[steps.config.PROPS.complete] = { checkbox: false }
  
  // Modify the due date
  patch.properties[steps.config.PROPS.dueDate] = { date : {} }
  // Modify the start date
  let startDate = task.properties[steps.config.PROPS.dueDate].date.start ? moment.parseZone(task.properties[steps.config.PROPS.dueDate].date.start) : null
  if (!(task.properties[steps.config.PROPS.interval].select.name in steps.config.INTERVALS)) continue
  startDate.add(...steps.config.INTERVALS[task.properties[steps.config.PROPS.interval].select.name])
  let startDateFormat = DATE_TIME_REGEX.test(task.properties[steps.config.PROPS.dueDate].date.start) ? "YYYY-MM-DDTHH:mm:ss.SSSZ" : "YYYY-MM-DD" // Date only or Date & Time
  patch.properties[steps.config.PROPS.dueDate].date.start = startDate.format(startDateFormat)
  
  // Modify the end date, if it exists
  if (task.properties[steps.config.PROPS.dueDate].date.end) {
    let endDate = moment.parseZone(task.properties[steps.config.PROPS.dueDate].date.end)
    endDate.add(...steps.config.INTERVALS[task.properties[steps.config.PROPS.interval].select.name])
    let endDateFormat = DATE_TIME_REGEX.test(task.properties[steps.config.PROPS.dueDate].date.end) ? "YYYY-MM-DDTHH:mm:ss.SSSZ" : "YYYY-MM-DD" // Date only or Date & Time
    patch.properties[steps.config.PROPS.dueDate].date.end = endDate.format(endDateFormat)
  }

  const updatedTaskResp = await axios({
    method: "PATCH",
    url: `https://api.notion.com/v1/pages/${task.id}`,
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${steps.config.API_TOKEN}`, // API KEY
      "Notion-Version": "2021-05-13"
    },
    data : JSON.stringify(patch)
  }).catch(err => {
    console.log(err.response.data)
    throw err
  })
  this.updatedTasks.push(updatedTaskResp.data)
}
console.log("Update complete!")
console.log('Workflow finished ✅')