Last active
March 11, 2025 20:13
-
-
Save hu553in/1ac9f48c8368398bcc1018748537e54e to your computer and use it in GitHub Desktop.
Yandex Cloud function to get RSS feed built from Todoist tasks with "rss" label
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"encoding/json" | |
"encoding/xml" | |
"fmt" | |
"io/ioutil" | |
"net/http" | |
"os" | |
"slices" | |
"time" | |
) | |
type Response struct { | |
StatusCode int `json:"statusCode"` | |
Body interface{} `json:"body"` | |
} | |
type TodoistTask struct { | |
ID string `json:"id"` | |
Content string `json:"content"` | |
Description string `json:"description"` | |
CreatedAt string `json:"created_at"` | |
URL string `json:"url"` | |
Labels []string `json:"labels"` | |
} | |
type RSS struct { | |
XMLName xml.Name `xml:"rss"` | |
Version string `xml:"version,attr"` | |
Channel Channel `xml:"channel"` | |
} | |
type Channel struct { | |
Title string `xml:"title"` | |
Link string `xml:"link"` | |
Description string `xml:"description"` | |
Items []Item `xml:"item"` | |
} | |
type Item struct { | |
Title string `xml:"title"` | |
Link string `xml:"link"` | |
Description string `xml:"description"` | |
PubDate string `xml:"pubDate"` | |
GUID string `xml:"guid"` | |
} | |
func Handler(ctx context.Context) (*Response, error) { | |
token := os.Getenv("TODOIST_TOKEN") | |
if token == "" { | |
return nil, fmt.Errorf("TODOIST_TOKEN environment variable is not set") | |
} | |
client := &http.Client{Timeout: 10 * time.Second} | |
req, err := http.NewRequestWithContext(ctx, "GET", "https://api.todoist.com/rest/v2/tasks", nil) | |
if err != nil { | |
return nil, err | |
} | |
req.Header.Set("Authorization", "Bearer "+token) | |
resp, err := client.Do(req) | |
if err != nil { | |
return nil, err | |
} | |
defer resp.Body.Close() | |
if resp.StatusCode != http.StatusOK { | |
bodyBytes, _ := ioutil.ReadAll(resp.Body) | |
return nil, fmt.Errorf("failed to fetch tasks: %s", string(bodyBytes)) | |
} | |
bodyBytes, err := ioutil.ReadAll(resp.Body) | |
if err != nil { | |
return nil, err | |
} | |
var tasks []TodoistTask | |
if err := json.Unmarshal(bodyBytes, &tasks); err != nil { | |
return nil, err | |
} | |
var filtered []TodoistTask | |
for _, task := range tasks { | |
if slices.Contains(task.Labels, "rss") { | |
filtered = append(filtered, task) | |
} | |
} | |
rss := RSS{ | |
Version: "2.0", | |
Channel: Channel{ | |
Title: "Todoist Tasks", | |
Link: "https://todoist.com", | |
Description: "RSS feed of Todoist tasks", | |
}, | |
} | |
for _, task := range filtered { | |
t, err := time.Parse(time.RFC3339Nano, task.CreatedAt) | |
if err != nil { | |
t = time.Now() | |
} | |
item := Item{ | |
Title: task.Content, | |
Link: task.URL, | |
Description: task.Description, | |
PubDate: t.Format(time.RFC1123Z), | |
GUID: task.ID, | |
} | |
rss.Channel.Items = append(rss.Channel.Items, item) | |
} | |
output, err := xml.MarshalIndent(rss, "", " ") | |
if err != nil { | |
return nil, err | |
} | |
rssFeed := xml.Header + string(output) | |
return &Response{ | |
StatusCode: 200, | |
Body: rssFeed, | |
}, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment