Skip to content

Commit

Permalink
Merge pull request #1 from icdocsoc/chore-flatten-dirs
Browse files Browse the repository at this point in the history
Chore: More directories to be clearer; fix CI
  • Loading branch information
Gum-Joe authored Aug 1, 2024
2 parents e402714 + 204667c commit 222a166
Show file tree
Hide file tree
Showing 77 changed files with 463 additions and 355 deletions.
36 changes: 18 additions & 18 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@

[workspace]
resolver = '2'
members = [
'packages/docsoc_clickup_calendar_sync',
]
members = ['clickup/calendar-sync']

[profile.release]
lto = true
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
[package]
name = "docsoc_clickup_calendar_sync"
name = "calendar-sync"
version = "0.1.0"
edition = "2021"



[dependencies]
env_logger = "0.11.3"
log = "0.4.22"
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,48 @@ It uses the ClickUp v2.0 API. [https://clickup.com/api/](https://clickup.com/api

> [!important]
> The sync is one way: events deleted & modifed in the google calendar will be synced into ClickUp, but modifications in ClickUp will NOT be synced back to the google calendar.
>
>
> This is becaue the author couldn't be bothered with two way sync as he'd have to solve how to resolve conflicts, which is hard when the tool is ran as a cron job or headlessly on a server!
The system uses a postgres database interacted with via the Diesel ORM to store mapping from calendar event IDs (known as UIDs in ical format) to ClickUp task IDs. This allows the system to update or delete events in ClickUp when they are updated or deleted in the Google Calendar.

The application is setup to autorun migrations on boot, so that you don't need to do this yourself.

## Quick start

### Docker Compose

1. Create a list in ClickUp for calendar events to be imported into
2. Make a copy of the `.env.example` file and rename it to `.env`, filling it in (it explains what each field is for)
3. Run `docker compose up` in this directory

### Bare metal/VM

1. Create a list in ClickUp for calendar events to be imported into
2. Setup a postgres database
3. Make a copy of the `.env.example` file and rename it to `.env`, filling it in (it explains what each field is for)
4. Run the tool with `cargo run --release` at regular intervals (e.g. every hour) to keep the calendars in sync

### Building the docker image manually

> [!important]
> Due the monorepo structure of the code, the docker build for this must be ran from the root of the repo
To build the docker image:
> To build the docker image:
1. Go to the root of the monorepo
2. Run `docker build -f ./packages/docsoc_clickup_calendar_sync/Dockerfile -t docsoc/docsoc_clickup_calendar_sync .`
2. Run `docker build -f ./packages/calendar-sync/Dockerfile -t docsoc/calendar-sync .`

## How it works

1. The tools downloads the ical file for the DoCSoc Private calendar
2. It parses the ical file and extracts the events in a iterator of `ParsedEvent`s
3. For each `ParsedEvent`, it checks if the event is in the database
- If it is, it updates the event in ClickUp to ensure it is consistent with all the info in the Google Calendar
- If it is not, it creates the event in ClickUp and adds a mapping to its database
- If it is, it updates the event in ClickUp to ensure it is consistent with all the info in the Google Calendar
- If it is not, it creates the event in ClickUp and adds a mapping to its database
4. It then creates a set of all the UIDs from the iCal is downloads and:
- For each mapping in the database...
- ...if the UID is not in the set, it deletes the event in ClickUp and removes the mapping from the database
- For each mapping in the database...
- ...if the UID is not in the set, it deletes the event in ClickUp and removes the mapping from the database

## Other quirks of the tools
- The tool uses the `govenor` crate to stick to the rate limit of the ClickUp API, however it does this in a hacky way (see code)


- The tool uses the `govenor` crate to stick to the rate limit of the ClickUp API, however it does this in a hacky way (see code)
File renamed without changes.
32 changes: 32 additions & 0 deletions clickup/calendar-sync/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
services:
sync_job:
image: docsoc/docsoc_clickup_calendar_sync
build:
context: ../.. # We need the monorepo root as deps are managed and built to the root
dockerfile: ./packages/docsoc_clickup_calendar_sync/Dockerfile
init: true # don't run as PID 1 so we can kill the sleep process
# Run every 30 mins
command: ["./scripts/run_interval.sh", "/usr/local/bin/docsoc_clickup_calendar_sync", "30m"]
depends_on:
- postgres
environment:
# The following environment variables should be set in the .env file
# and docker compose will auto load them
DATABASE_URL: postgresql://docsoc:docsoc@postgres/docsoc
DOCSOC_PRIVATE_ICAL: ${DOCSOC_PRIVATE_ICAL}
DOCSOC_START_DATE: ${DOCSOC_START_DATE}
DOCSOC_END_DATE: ${DOCSOC_END_DATE}
CLICKUP_ACCESS_TOKEN: ${CLICKUP_ACCESS_TOKEN}
CLICKUP_TARGET_LIST_ID: ${CLICKUP_TARGET_LIST_ID}
CLICKUP_RATE_LIMIT_PER_MIN: ${CLICKUP_RATE_LIMIT_PER_MIN}
postgres:
image: postgres:16
environment:
POSTGRES_USER: docsoc
POSTGRES_PASSWORD: docsoc
POSTGRES_DB: docsoc
volumes:
- docsoc_clickup_postgres_data:/var/lib/postgresql/data

volumes:
docsoc_clickup_postgres_data:
File renamed without changes.
69 changes: 69 additions & 0 deletions clickup/calendar-sync/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
{
"name": "calendar-sync",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"sourceRoot": "clickup/calendar-sync/src",
"tags": [],
"targets": {
"build": {
"executor": "@monodon/rust:build",
"outputs": ["{options.target-dir}"],
"options": {
"target-dir": "dist/target/docsoc_clickup_calendar_sync"
},
"configurations": {
"production": {
"release": true
}
}
},
"test": {
"executor": "@monodon/rust:test",
"outputs": ["{options.target-dir}"],
"options": {
"target-dir": "dist/target/docsoc_clickup_calendar_sync"
},
"configurations": {
"production": {
"release": true
}
}
},
"lint": {
"executor": "@monodon/rust:lint",
"outputs": ["{options.target-dir}"],
"options": {
"target-dir": "dist/target/docsoc_clickup_calendar_sync"
}
},
"run": {
"executor": "@monodon/rust:run",
"outputs": ["{options.target-dir}"],
"options": {
"target-dir": "dist/target/docsoc_clickup_calendar_sync"
},
"configurations": {
"production": {
"release": true
}
}
},
"container": {
"executor": "@nx-tools/nx-container:build",
"options": {
"engine": "docker",
"metadata": {
"images": ["docsoc/docsoc_clickup_calendar_sync"],
"load": true,
"tags": [
"type=schedule",
"type=ref,event=branch",
"type=ref,event=tag",
"type=ref,event=pr",
"type=sha,prefix=sha-"
]
}
}
}
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 2 additions & 0 deletions email/libmailmerge/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
dist
25 changes: 25 additions & 0 deletions email/libmailmerge/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.json"],
"parser": "jsonc-eslint-parser",
"rules": {
"@nx/dependency-checks": "error"
}
}
]
}
File renamed without changes.
3 changes: 3 additions & 0 deletions email/libmailmerge/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"editor.formatOnSave": true
}
9 changes: 9 additions & 0 deletions email/libmailmerge/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# libmailmerge

This library was generated with [Nx](https://nx.dev).

## Building

Run `nx build libmailmerge` to build the library.

## Plan
7 changes: 7 additions & 0 deletions email/libmailmerge/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* eslint-disable */
export default {
displayName: "libmailmerge",
preset: "../../jest.preset.js",
coverageDirectory: "../../coverage/email/libmailmerge",
testMatch: ["<rootDir>/test/**/*.ts"],
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "docsoc-mail-merge",
"version": "0.0.1",
"name": "@docsoc/libmailmerge",
"version": "0.1.0",
"dependencies": {
"dotenv": "^16.4.5",
"email-validator": "^2.0.4",
Expand All @@ -12,11 +12,15 @@
"nunjucks": "^3.2.4",
"readline-sync": "^1.4.10",
"tslib": "^2.3.0",
"unique-names-generator": "^4.7.1"
"unique-names-generator": "^4.7.1",
"csv-parse": "5.5.6",
"chalk": "4.1.2",
"winston": "3.13.1"
},
"scripts": {
"start": "ts-node src/cli.ts",
"test": "jest"
"test": "jest",
"build": "tsc --build --verbose"
},
"bin": "./dist/cli.js",
"type": "commonjs",
Expand Down
29 changes: 29 additions & 0 deletions email/libmailmerge/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "libmailmerge",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "email/libmailmerge/src",
"projectType": "application",
"tags": [],
"targets": {
"build": {
"executor": "@nx/js:tsc",
"outputs": [
"{options.outputPath}"
],
"options": {
"outputPath": "dist/email/libmailmerge",
"main": "email/libmailmerge/src/cli.ts",
"tsConfig": "email/libmailmerge/tsconfig.lib.json",
"assets": [],
"rootDir": "email/libmailmerge/src"
}
},
"run": {
"executor": "@nrwl/workspace:run-commands",
"outputs": [],
"options": {
"command": "ts-node src/cli.ts"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { parse } from "csv-parse";
import "dotenv/config";
import { promises as fs } from "fs";
import markdownit from "markdown-it";
import nunjucks from "nunjucks";
// load .env
import { join } from "path";

import { defaultMailer, getDefaultMailer } from "./mailer/defaultMailer";
import Mailer from "./mailer/mailer";
import { renderMarkdownToHtml } from "./markdown/toHtml";
import createLogger from "./util/logger";

Expand All @@ -17,14 +15,14 @@ async function main() {
logger.info("Starting DoCSoc Mail Merge");
logger.info("Loading template...");

const template = await fs.readFile(join(__dirname, "../templates/TEMPLATE.md.njk"), "utf-8");
// const template = await fs.readFile(join(__dirname, "../templates/TEMPLATE.md.njk"), "utf-8");
const csv = await fs.readFile(join(__dirname, "../data/names.csv"), "utf-8");
const templateCompiled = nunjucks.compile(
template,
nunjucks.configure({
throwOnUndefined: true,
}),
);
// const templateCompiled = nunjucks.compile(
// template,
// nunjucks.configure({
// throwOnUndefined: true,
// }),
// );
const htmlWrapper = await fs.readFile(join(__dirname, "../templates/wrapper.html.njk"), "utf-8");
const htmlWrapperCompiled = nunjucks.compile(htmlWrapper, nunjucks.configure({ autoescape: false }));
const mailer = getDefaultMailer();
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import inquirer from "inquirer";

import { TemplateEngine } from "../engines/types";
import createLogger from "../util/logger";

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import nodemailer from "nodemailer";
import { EmailString, FromEmail } from "../util/types";
import { convert } from "html-to-text";
import { validate } from "email-validator";
import { convert } from "html-to-text";
import nodemailer from "nodemailer";

import createLogger from "../util/logger";
import { EmailString, FromEmail } from "../util/types";

const logger = createLogger("mailer");

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 222a166

Please sign in to comment.