Metadata-Version: 2.4
Name: cctodo
Version: 0.1.0
Summary: Command line tool and Python client for ccToDo (www.cctodo.com)
Author-email: CloudCircus <support@cctodo.com>
License-Expression: MIT
Project-URL: Homepage, https://www.cctodo.com/
Project-URL: Source, https://github.com/RubenNorgaard/cctodo_py
Keywords: todo,tasks,cli,cctodo
Classifier: Environment :: Console
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Office/Business :: Scheduling
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Dynamic: license-file

# cctodo

The command line tool and Python client for [ccToDo](https://www.cctodo.com/), made by CloudCircus.

```sh
pip install cctodo
cctodo login          # paste a token from Settings → API tokens
cctodo mytasks
cctodo new -group "work group" "my task"
cctodo done 123
```

It uses only the Python standard library and needs Python 3.9 or newer.

## Commands

Tasks are shown with their id (`#123`), and the commands take that id. Where a command takes a group,
you can give its id, its title, or the start of the title (case-insensitive). Without `-g`, commands
use your **My Tasks**.

| Command | What it does |
|---|---|
| `cctodo mytasks` (`my`) | Your pending My Tasks. `-c` shows completed tasks instead. |
| `cctodo list [GROUP]` (`ls`) | A group's pending tasks. `--all` lists every group, `-c` shows completed tasks. |
| `cctodo assigned` | Pending tasks assigned to you, in all groups. |
| `cctodo groups` | Your groups, with their pending counts. |
| `cctodo new TITLE… [-g GROUP] [-a WHO] [-b BODY] [-e]` (`add`) | Adds a task at the bottom of the list. `-b -` reads the details from stdin; `-e` writes the title and details in `$EDITOR`. |
| `cctodo show ID` | A task with its details (markdown) and comments. |
| `cctodo done ID…` / `start ID…` / `reopen ID…` | Sets the state to done, in progress, or to do. |
| `cctodo edit ID [-t TITLE] [-b BODY]` | Edits a task. With no options it opens `$EDITOR`: the first line is the title and the rest is the details. It refuses to overwrite someone else's newer edit. |
| `cctodo assign ID WHO` | Assigns to `me`, a member's email, or `none`. |
| `cctodo mv ID -g GROUP` / `mv ID --before ID2` / `--after ID2` | Moves a task to another group, or reorders it. |
| `cctodo rm ID… [-y]` | Deletes tasks after asking you to confirm. |
| `cctodo comment ID TEXT… [-r COMMENT_ID]` | Adds a comment, or a reply with `-r`. |
| `cctodo group new/rename/members/leave/rm` | Manages groups. |
| `cctodo invite GROUP EMAIL [-m MESSAGE]` | Invites someone. If you're a member rather than an owner, an owner approves the invite first. |
| `cctodo invites` / `accept ID` / `decline ID` | Lists and answers invites addressed to you. |
| `cctodo whoami` / `logout` | Shows the account you're logged in as, or forgets the saved token. |

Add `--json` to any command for the raw API output. `NO_COLOR` turns colours off.

**Exit codes:**
- `0`: the command succeeded.
- `1`: an error occurred.
- `3`: you're not logged in, or your token was revoked.

## Configuration

`cctodo login` saves the token in `~/.config/cctodo/config.json`, readable only by you
(`%APPDATA%\cctodo\config.json` on Windows). You can set these environment variables instead:

- `CCTODO_TOKEN`: the API token.
- `CCTODO_API_URL`: the API address. It defaults to `https://api.cctodo.com`.
- `CCTODO_CONFIG`: a different config file.

To revoke a token, go to Settings → API tokens on www.cctodo.com.

## Python

```python
from cctodo import Client, Conflict

todo = Client()                                  # the same token as the CLI (or Client(token="cct_..."))
work = todo.find_group("work group")
task = todo.create_task(work.id, "Write the report", body="Due **Friday**")
todo.assign(task.id, todo.me().id)
todo.start(task.id)

for t in todo.tasks(work.id):                    # pending tasks, in order
    print(t.id, t.state, t.title)                # attribute or t["title"] access

try:
    todo.update_task(task.id, body="…", expected_updated_at=task.updated_at)
except Conflict:
    print("Someone else changed it first")
```

**Return values:** results are the API's JSON as `Record` objects (dicts with attribute access).

**Errors:** errors raise `cctodo.NotFound` (404; this also covers groups you're not in), `NotAllowed` (403),
`Invalid` (400), `Conflict` (409), `RateLimited` (429) or `Unauthorized` (401). All of them subclass `cctodo.CctodoError`.

## Development

```sh
pip install -e .
python -m unittest discover -s . -t .
CCTODO_API_URL=http://api.localhost:8000 cctodo whoami      # against a local cctodo_web
```

## Licence

MIT. See [LICENSE](LICENSE).
