From c4c57e9225c2b08b001ad133c5e27bc8371de4fd Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Wed, 22 Mar 2023 11:29:46 +0100 Subject: [PATCH 01/46] modify api intro section --- docs/dev.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/dev.md b/docs/dev.md index 66e8b0e6b..5967f7340 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -19,9 +19,11 @@ npm run serve # Public API +The root URL is `https://mynextcloud.org/index.php/apps/cospend`. Replace `mynextcloud.org` by your actual domain. + Plan was to make Cospend public API strictly identical to [IHateMoney API](https://ihatemoney.readthedocs.io/en/latest/api.html) but there is a restriction i couldn't bypass : the authentication system. IHateMoney uses the basic HTTP authentication, just like Nextcloud user authentication. So, to get a guest access to a Cospend project, this type of authentication was first rejected by Nextcloud user auth system and then accepted by Cospend with a huge latency. -So the only differences between IHateMoney API and Cospend API are : +So the most noticeable differences between IHateMoney API and Cospend API are : * The password has to be included in the URL path, just after the project ID, like that : `https://mynextcloud.org/index.php/apps/cospend/api/myproject/projectPassword/bills` * The parameter `payed_for` cannot be given multiple times like in IHateMoney. It has to be given once with coma separated values. From 4015c783926068ba48616a10c796a8b2c5a44845 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Wed, 22 Mar 2023 11:30:06 +0100 Subject: [PATCH 02/46] how to connect with share link --- docs/dev.md | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 1 deletion(-) diff --git a/docs/dev.md b/docs/dev.md index 5967f7340..2b60925a5 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -28,6 +28,163 @@ So the most noticeable differences between IHateMoney API and Cospend API are : * The password has to be included in the URL path, just after the project ID, like that : `https://mynextcloud.org/index.php/apps/cospend/api/myproject/projectPassword/bills` * The parameter `payed_for` cannot be given multiple times like in IHateMoney. It has to be given once with coma separated values. -That's it. + +## How to connect +First and foremost, understand how to connect and get your first command working. There are two to three components you want to get: +* The project's ID `` OR token `` +* The project's password: `` +* The account's credentials (if you're not using the share link method): ``, ``, ``,... depending on the method used. + +To correctly test your API for the first time, make sure you have one or two transactions entered through the web UI, otherwise you will get an empty response body despite the configuration being correct. + +### First method: Share Link + +This assumes you already have a project created, and want to use your API on specifically this project. This is basically a guest access to a project created beforehand. It doesn't depend on a specific account. + +If you use this method, your API path will have the following shape: `/api/projects///` +#### Get the `` + + + +Go to the project settings in the UI, open the Sharing tab, and create a share link. Your link should look something like this: +`https://mynextcloud.org/apps/cospend/s/ba3355eaecc6254ad1755fa8e7cdf54a)` + +Take note of the project's token (`ba3355eaecc6254ad1755fa8e7cdf54a`), that will act as your ``. +#### Get the `` +If you chose to set a password on your link, use it as your ``. + +**If you don't set a password on your share link, there will be a default password**: The default password is `no-pass`. It's not required when using the web view, but it is with the API, as explained earlier. +#### Trying +You can now try your first ``: `/statistics`. If you've followed correctly, your request should look like this: + +```bash +curl -s https://mynextcloud.org/index.php/apps/cospend/api/projects/ba3355eaecc6254ad1755fa8e7cdf54a/no-pass/statistics +``` +and have a correct result: +
+ +```json +{ + "stats": [ + { + "balance": -119, + "filtered_balance": -119, + "paid": 0, + "spent": 119, + "member": { + "activated": true, + "userid": "firstuserid", + "name": "John Do", + "id": 4, + "weight": 1, + "color": { + "r": 110, + "g": 166, + "b": 143 + }, + "lastchanged": 1679234081 + } + }, + { + "balance": 119, + "filtered_balance": 119, + "paid": 520, + "spent": 401, + "member": { + "activated": true, + "userid": "seconduserid", + "name": "Alice Foo", + "id": 3, + "weight": 1, + "color": { + "r": 0, + "g": 130, + "b": 201 + }, + "lastchanged": 1679234078 + } + } + ], + "memberMonthlyPaidStats": { + "2023-03": { + "4": 0, + "3": 520, + "0": 520 + }, + "Average per month": { + "4": 0, + "3": 520, + "0": 520 + } + }, + "memberMonthlySpentStats": { + "2023-03": { + "4": 119, + "3": 401, + "0": 520 + }, + "Average per month": { + "4": 119, + "3": 401, + "0": 520 + } + }, + "categoryStats": [ + 520 + ], + "categoryMonthlyStats": [ + { + "2023-03": 520, + "Average per month": 520 + } + ], + "paymentModeStats": [ + 520 + ], + "paymentModeMonthlyStats": [ + { + "2023-03": 520, + "Average per month": 520 + } + ], + "categoryMemberStats": [ + { + "4": 0, + "3": 520 + } + ], + "memberIds": [ + 4, + 3 + ], + "allMemberIds": [ + 4, + 3 + ], + "membersPaidFor": { + "4": { + "4": 0, + "3": 0, + "total": 0 + }, + "total": { + "4": 119, + "3": 401 + }, + "3": { + "4": 119, + "3": 401, + "total": 520 + } + }, + "realMonths": [ + "2023-03" + ] +} +``` + +
+ + Detailed API description will come later. From 86f1272d103f198e758db3170533076a2ab779f2 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Wed, 22 Mar 2023 11:30:22 +0100 Subject: [PATCH 03/46] how to connect with app password --- docs/dev.md | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/docs/dev.md b/docs/dev.md index 2b60925a5..0c7a158f3 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -186,5 +186,46 @@ and have a correct result: +### Second method: App Password (UI) +This second method gives a larger access to your account, not just to cospend or to a single cospend's project. + +#### Obtaining the credentials +First of all, you need a **password**. Open your Nextcloud UI, visit your personal settings, under Security (https://mynextcloud.org/settings/user/security). Under _Devices & Sessions_, create a new app password. Make good note of the given password (a series of alphanumericals separated by dashes). This is your ``. + +The next bit of information is your Nextcloud's **username** (used to login, not your profile name neither your email address). This is your `` + +To work on a project, you will also need its **ID**. Note that this is different than the `` used earlier. Here, we don't need to create a guest access to a project. The project ID is the name of the project, in lower case, with spaces replaced by dashes. When you click on the project in the web UI, you will see the ID in the address bar: `https://mynextcloud.org/apps/cospend/p/` + +If you use this method, your API path will have the following shape: `/api-priv/projects//` + +**Do note:** +* This URL starts with `api-priv` instead of `api`. This is for logged in clients, that don't require a project's password. +* There's no more password on the project +#### Using the credentials +This method uses [HTTP Basic Authentication](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#basic_authentication_scheme). Most libraries and languages offer an easy method for that (e.g. `curl -u ":" `). If you need to do it manually: +* Prepare the string +* Base64 encode it +* Pass the result to a header `Authorization: Basic ` + +For instance: +```bash +curl -u "johndoe:mypassword" https://example.com +# equivalent to: +encoded=$(echo -n "johndoe:mypassword" | base64) # -n mandatory, otherwise \n is also encoded +curl -H "Authorization: Basic $encoded" https://example.com +``` + +In order for the header to be correctly interpreted, you also need an additional header: `OCS-APIRequest: true`. For instance: +``` +curl -H "OCS-APIRequest: true" -u ":" +``` +#### Trying +You can now try your first ``: `/statistics`. If you've followed correctly, your request should look like this: + +```bash +curl -s -u ":/statistics +``` +And obtain the same result as before. + -Detailed API description will come later. From 1b0dc849dea685ad7530d2112ad4f67842605963 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Wed, 22 Mar 2023 11:30:37 +0100 Subject: [PATCH 04/46] api spec toc --- docs/dev.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 0c7a158f3..8e1a41810 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -229,3 +229,48 @@ https://mynextcloud.org/index.php/apps/cospend/api/projects//statist And obtain the same result as before. + +## Specifications +Now that you've managed to land your first succesful request, let's dive into the concrete API specification. + +As explained above, depending on your authentication method, the endpoint will look slightly different. +The core part of the endpoint (`/api/projects//` for anonymous, and `/api-priv/projects/` for logged in) will be substituted by ``. If `` is not mentioned, the endpoint is relative to the root url. + +**Examples**: +| Endpoint | Full URL(s) | +| :---------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `/api/ping` | `https://mynextcloud.org/index.php/apps/cospend/api/ping` | +| `/bills` | *`https://mynextcloud.org/index.php/apps/cospend/api/projects///bills`
*`https://mynextcloud.org/index.php/apps/cospend/api-priv/projects//bills` | + + +| Name | Endpoint | Method | Anonymous/Logged | +| -------------------------------------------------- | :------------------------------------------------------------ | :----- | ---------------- | +| [Ping ](#ping ) | `/api/ping` | GET | **Logged** | +| [Create Project ](#create-project ) | `/api/projects` (anonymous),
`/api-priv/projects` (logged) | POST | Anonymous/Logged | +| [Get Project Info ](#get-project-info ) | `/` | GET | Anonymous/Logged | +| [Set Project Info ](#set-project-info ) | `/` | PUT | Anonymous/Logged | +| [Delete project ](#delete-project ) | `/` | DELETE | Anonymous/Logged | +| [Get Members ](#get-members ) | `/members` | GET | Anonymous/Logged | +| [Add Member ](#add-member ) | `/members` | POST | Anonymous/Logged | +| [Add Member V2 ](#add-member-v2 ) | `/apiv2/projects///members` | POST | **Anonymous** | +| [Edit Member ](#edit-member ) | `/members/` | PUT | Anonymous/Logged | +| [Delete Member ](#delete-member ) | `/members/` | DELETE | Anonymous/Logged | +| [Get Bills ](#get-bills ) | `/bills` | GET | Anonymous/Logged | +| [Get Bills V2 ](#get-bills-v2 ) | `/apiv2/projects///bills` | GET | **Anonymous** | +| [Get Bills V3 ](#get-bills-v3 ) | `/apiv3/projects///bills` | GET | **Anonymous** | +| [Add Bill ](#add-bill ) | `/bills` | POST | Anonymous/Logged | +| [Edit Bill ](#edit-bill ) | `/bills/` | PUT | Anonymous/Logged | +| [Delete Bill ](#delete-bill ) | `/bills/` | DELETE | Anonymous/Logged | +| [Get Project Statistics](#get-project-statistics ) | `/statistics` | GET | Anonymous/Logged | +| [Get Project Settlement](#get-project-settlement ) | `/settle` | GET | Anonymous/Logged | +| [Auto Settlement ](#auto-settlement ) | `/autosettlement` | GET | Anonymous/Logged | +| [Add Currency ](#add-currency ) | `/currency` | POST | Anonymous/Logged | +| [Edit Currency ](#edit-currency ) | `/currency/` | PUT | Anonymous/Logged | +| [Delete Currency ](#delete-currency ) | `/currency/` | DELETE | Anonymous/Logged | +| [Add Payment Mode ](#add-payment-mode ) | `/paymentmode` | POST | Anonymous/Logged | +| [Edit Payment Mode ](#edit-payment-mode ) | `/paymentmode/` | PUT | Anonymous/Logged | +| [Delete Payment Mode ](#delete-payment-mode ) | `/paymentmode/` | DELETE | Anonymous/Logged | +| [Add Category ](#add-category ) | `/category/` | POST | Anonymous/Logged | +| [Edit Category ](#edit-category ) | `/category/` | PUT | Anonymous/Logged | +| [Delete Category ](#delete-category ) | `/category/` | DELETE | Anonymous/Logged | + From cd3fcdbc8381a96a32e70c8e7ed2475a32d5ec00 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Wed, 22 Mar 2023 11:30:54 +0100 Subject: [PATCH 05/46] complete api headers --- docs/dev.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 8e1a41810..07705e6d8 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -274,3 +274,31 @@ The core part of the endpoint (`/api/projects// | [Edit Category ](#edit-category ) | `/category/` | PUT | Anonymous/Logged | | [Delete Category ](#delete-category ) | `/category/` | DELETE | Anonymous/Logged | +### Ping +### Create Project +### Get Project Info +### Set Project Info +### Delete project +### Get Members +### Add Member +### Add Member V2 +### Edit Member +### Delete Member +### Get Bills +### Get Bills V2 +### Get Bills V3 +### Add Bill +### Edit Bill +### Delete Bill +### Get Project Statistics +### Get Project Settlement +### Auto Settlement +### Add Currency +### Edit Currency +### Delete Currency +### Add Payment Mode +### Edit Payment Mode +### Delete Payment Mode +### Add Category +### Edit Category +### Delete Category \ No newline at end of file From 60b548544064ca4384d59bd710506ab333d9c883 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Wed, 22 Mar 2023 11:31:24 +0100 Subject: [PATCH 06/46] complete doc TOC --- docs/dev.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 07705e6d8..28b72daa7 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1,3 +1,44 @@ +- [Development environment](#development-environment) +- [Public API](#public-api) + - [How to connect](#how-to-connect) + - [First method: Share Link](#first-method-share-link) + - [Get the ``](#get-the-project_token) + - [Get the ``](#get-the-project_password) + - [Trying](#trying) + - [Second method: App Password (UI)](#second-method-app-password-ui) + - [Obtaining the credentials](#obtaining-the-credentials) + - [Using the credentials](#using-the-credentials) + - [Trying](#trying-1) + - [Specifications](#specifications) + - [Ping](#ping) + - [Create Project](#create-project) + - [Get Project Info](#get-project-info) + - [Set Project Info](#set-project-info) + - [Delete project](#delete-project) + - [Get Members](#get-members) + - [Add Member](#add-member) + - [Add Member V2](#add-member-v2) + - [Edit Member](#edit-member) + - [Delete Member](#delete-member) + - [Get Bills](#get-bills) + - [Get Bills V2](#get-bills-v2) + - [Get Bills V3](#get-bills-v3) + - [Add Bill](#add-bill) + - [Edit Bill](#edit-bill) + - [Delete Bill](#delete-bill) + - [Get Project Statistics](#get-project-statistics) + - [Get Project Settlement](#get-project-settlement) + - [Auto Settlement](#auto-settlement) + - [Add Currency](#add-currency) + - [Edit Currency](#edit-currency) + - [Delete Currency](#delete-currency) + - [Add Payment Mode](#add-payment-mode) + - [Edit Payment Mode](#edit-payment-mode) + - [Delete Payment Mode](#delete-payment-mode) + - [Add Category](#add-category) + - [Edit Category](#edit-category) + - [Delete Category](#delete-category) + # Development environment Clone this repository and build: From d975c8881b9fb2fec15f5f7401ee78fa9d176068 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 17:30:21 +0200 Subject: [PATCH 07/46] remove trailing space --- docs/user.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user.md b/docs/user.md index e4faf1420..8e620660d 100644 --- a/docs/user.md +++ b/docs/user.md @@ -73,7 +73,7 @@ This link is accessible in projects context menu => "guest link". ## Guest access permissions -There are 4 levels of guest link permissions : +There are 4 levels of guest link permissions : * Viewer : read-only access * Participant : can create, modify or delete bills From 42c1c286070b22b0759ab1b69aac3bee219c34ed Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 17:30:55 +0200 Subject: [PATCH 08/46] Add user information about repeating bills --- docs/user.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/user.md b/docs/user.md index 8e620660d..465a76f4a 100644 --- a/docs/user.md +++ b/docs/user.md @@ -90,6 +90,13 @@ Just provide a user name and that's it. Member is added with a weight of 1 and i Pretty simple too. Press the "new bill" button. Fill all fields and the bill will be saved automatically. +## Repeating bills +This may need a bit more explanation. +* Repeat: This indicates how often the bill should be repeated. Daily means the bill will be repeated in 24 hours, weekly in 7 days, bi-weekly in 14 days. Monthly says the bill will be repeated at the same day (e.g. 10th of the month) next month, and a yearly bill will be repeated the same date, same time, next year. Semi-monthly is a bit particular: bills will be repeated on the 1st and 15th of each month. +* Frequency: This is a modifier for Repeat. By default, Daily means the next repetition will be in 1 day, weekly in 1 week, and so on. The frequency is 1. If you want to do a bill that repeats every 3 days, you would chose a Daily repeat, but with a frequency of 3. Note that with this behavior, a bill repeating Weekly with a frequency of 1 is the same as a bill repeating Daily with a frequency of 7, and a bi-weekly with frequency 1 is the same as a weekly with frequency 2 or a daily with frequency 14. +* Include all active members on repeat: by default, repeating a bill will replicate also the owers. The same people will owe the same bill, paid by the same person. However, you may want to split a bill across "everyone", regardless of who is in the project at the moment. For instance, you may want to split the Netflix subscription across a group of roommates. But people may come and go, throughout the year. So the actual owers of the bill will always be "all the people currenetly in the appartment". When someone leave, deactivate them as a member, and they won't be counted for the next bill. Someone joins the project, and they will owe their share of the next repeating bill. Note, this is not retro-active: someone joining a project won't suddenly owe all of the previous repeating bills. +* Repeat until: A repeating bill may not do so indefinitely. Maybe you took a 6. months subscription, or have a lease for 24 months. Indicate the moment after which this bill should not repeat. If the end date is between repetitions, the end date won't create a "final" bill; e.g. a bill repeats every Sunday, and you set an end date on a Tuesday, then the last Sunday preceding the Tuesday will be the last repetition, and nothing after. + # Project statistics Well does it need explanations ? From 559e9b1312eb15f75c6d1ccb57a85c554d82ff72 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 17:31:11 +0200 Subject: [PATCH 09/46] add ToC in user.md --- docs/user.md | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/docs/user.md b/docs/user.md index 465a76f4a..2ba4905c0 100644 --- a/docs/user.md +++ b/docs/user.md @@ -1,16 +1,17 @@ -* [Introduction](#s1) - * [What is a project :paperclip: ?](#s1-1) - * [What are balances :balance_scale: ?](#s1-2) - * [What is a member :ok_woman: ?](#s1-3) - * [What is a bill :dollar: ?](#s1-4) -* [Add a project](#s2) - * [Guest access](#s2-1) - * [Guest access permissions](#s2-1-1) -* [Add a member](#s3) -* [Add a bill](#s4) -* [Project statistics](#s5) -* [Settle the project](#s6) -* [Anonymous project creation](#s7) +- [Introduction](#introduction) + - [What is a project :paperclip: ?](#what-is-a-project-paperclip-) + - [What are balances :balance\_scale: ?](#what-are-balances-balance_scale-) + - [What is a member :ok\_woman: ?](#what-is-a-member-ok_woman-) + - [What is a bill :dollar: ?](#what-is-a-bill-dollar-) +- [Add a project](#add-a-project) + - [Guest access](#guest-access) + - [Guest access permissions](#guest-access-permissions) +- [Add a member](#add-a-member) +- [Add a bill](#add-a-bill) + - [ Repeating bills](#-repeating-bills) +- [Project statistics](#project-statistics) +- [Settle the project](#settle-the-project) +- [Anonymous project creation](#anonymous-project-creation) # Introduction From 7980617dfc8c6380f6d0de2781e0566ebee62ef7 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 17:52:18 +0200 Subject: [PATCH 10/46] adding generic additional information --- docs/dev.md | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 28b72daa7..03a1a08e1 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -10,6 +10,13 @@ - [Using the credentials](#using-the-credentials) - [Trying](#trying-1) - [Specifications](#specifications) + - [Additional details](#additional-details) + - [A note about errors](#a-note-about-errors) + - [A note about access levels](#a-note-about-access-levels) + - [Autoexport](#autoexport) + - [Sort](#sort) + - [Repeat](#repeat) + - [Payment Modes' ID](#payment-modes-id) - [Ping](#ping) - [Create Project](#create-project) - [Get Project Info](#get-project-info) @@ -315,6 +322,106 @@ The core part of the endpoint (`/api/projects// | [Edit Category ](#edit-category ) | `/category/` | PUT | Anonymous/Logged | | [Delete Category ](#delete-category ) | `/category/` | DELETE | Anonymous/Logged | +### Additional details +#### A note about errors +While some errors are explicit and specific to a situation, many situations have the same error for the same behavior. In order to make the following specification more readable, non-specific errors are explained here + + +* Missing login for private API + * Situation: the credentials are missing altogether, although using a logged in endpoint (`.../api-priv/...`) + * Error message: `{"message":"CORS requires basic auth"}` +* The credentials are invalid + * Situation: you're using a logged in endpoint, but your credentials are incorrect (althrough present) + * Error message: `{"message":""}` +* The URL is incorrect + * Situation: You're using anonymous or logged in requests, and the endpoint you're accessing doesn't exist, and can't exist (nb: this doesn't apply if e.g. the project name is incorrect). This happens a lot when debugging. + * Example: `curl -u 'johndoe:password' https://mynextcloud.org/index.php/apps/cospend/api/pingdawd` <-- + * _No error message_. Only a line-feed (`\n`) character is returned. + +#### A note about access levels +Users or tokens can have an access level, described by an integer from 1 to 4. They are defined as the following: + +* 1: Viewer, can view everything (read-only access) +* 2: Participant, can read and write bills, as a normal participant +* 3: Maintainer, +* 4: Admin, + +#### Autoexport +Autoexport is defined by a single character, with the following matches: +* `n`: No +* `d`: Daily +* `w`: Weekly +* `m`: Monthly + +#### Sort +Categories and Payment Modes can be sorted. A single character characterizes the method, with the following matches: +* `a`: Alphabetical, +* `m`: Manual, +* `u`: Most Used, +* `r`: Most Recently used, + +#### Repeat +Bills can be set to be repeating/recurring. Check the [user guide](./user.md#repeating-bills) for additional information of what each field actually does. The `repeat` field is again defined by a single character, with the following matches: +* `n`: never +* `d`: daily (every X day) +* `w`: weekly (every X weeks, every 7*X days) +* `b`: bi-weekly (every 2 weeks, every 14 days) +* `s`: semi-monthly (twice a month, on the 1st and 15th of each month) +* `m`: monthly (every X months) +* `y`: yearly (every X years) + +The field `repeatfreq` is the modifier for the repeat. It's an integer, that in practice replaces the X in the above matches. It is ignored for bi-weekly and semi-monthly repetitions. + +`repeatuntil` is simply a date, defined as a Unix timestamp. For a bill that is set to repeat, at each cron run, the current "computed next run" for the bill is compared to the `repeatuntil` field. + +`repeatallactive` determines if the bill should just copy the set list of owers (False) or all current active members as the new owers (True). Note that this is not a boolean, but an integer. A value of 1 indicates True/ticked (repeat using all active members), while _any other value_ indicates False/unticked (only use the same list of owers). Default False value set by the web interface is 0. If you set a different value through the API (e.g. 5), the same value will be given back upon query. For obvious reasons it is **not recommmended** to use other values than 0 and 1. + + + +#### Payment Modes' ID +Payment modes are defined by two ID: `id`, which is an integer, unique across all projects of this NC instance, and `old_id`, which is a single character. + +While `id` is faily standard, `old_id` requires a bit more attention. It is only defined for the 5 default payment modes: +* `c` is `Credit card` +* `b` is `Cash` +* `f` is `Check` +* `t` is `Transfer` +* `o` is `Online Service`. + +Manually created payment modes still have a standard `id`, but their `old_id` is `null`. + +There is however another small specificity. When references are made to payment modes, another letter, `n` can appear. See for example an exract from an output from [Get Bills](#get-bills-logged-in) (many fields are omitted, this is for illustration purpose): +```json +{ + "bills": [ + { + "id": 1, + "amount": 66, + "what": "Yet another bill", + "paymentmode": "n", + "paymentmodeid": 0, + <....> + } + { + "id": 2, + "amount": 100, + "what": "New Bill", + "paymentmode": "n", + "paymentmodeid": 26, + <....> + } + ] +} +``` + +Notice how the first bill, with ID 1, has `paymentmode="n"` and `paymentmodeid=0`. Having both of those means there are no payment mode set (`None`). +The `n` indicates there are no `old_id` for this paymment mode. + +The second bill, however, has `paymentmode="n"`, as before, but `paymentmodeid=26`. In this, this shows the payment mode is a manually created payment mode (with `id` 26). + +As a general rule, everything related to the `old_id` (so the `paymentmode` in the latter case) can safely be ignored. + + ### Ping ### Create Project ### Get Project Info From 2ea41e613d83f3d338c4a03f4291aa054b8ab0fc Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 17:53:06 +0200 Subject: [PATCH 11/46] removing incorrect information about OCS header --- docs/dev.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/dev.md b/docs/dev.md index 03a1a08e1..2d886f20d 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -263,15 +263,11 @@ encoded=$(echo -n "johndoe:mypassword" | base64) # -n mandatory, otherwise \n is curl -H "Authorization: Basic $encoded" https://example.com ``` -In order for the header to be correctly interpreted, you also need an additional header: `OCS-APIRequest: true`. For instance: -``` -curl -H "OCS-APIRequest: true" -u ":" -``` #### Trying You can now try your first ``: `/statistics`. If you've followed correctly, your request should look like this: ```bash -curl -s -u "::/statistics ``` And obtain the same result as before. From f1193b215fdcc4da5a5708073b28b89d2d133887 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 17:53:53 +0200 Subject: [PATCH 12/46] differentiate getting bills anonymously and logged --- docs/dev.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/dev.md b/docs/dev.md index 2d886f20d..3a2f2b925 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -27,7 +27,8 @@ - [Add Member V2](#add-member-v2) - [Edit Member](#edit-member) - [Delete Member](#delete-member) - - [Get Bills](#get-bills) + - [Get Bills (logged in)](#get-bills-logged-in) + - [Get Bills (anonymous)](#get-bills-anonymous) - [Get Bills V2](#get-bills-v2) - [Get Bills V3](#get-bills-v3) - [Add Bill](#add-bill) @@ -428,7 +429,8 @@ As a general rule, everything related to the `old_id` (so the `paymentmode` in t ### Add Member V2 ### Edit Member ### Delete Member -### Get Bills +### Get Bills (logged in) +### Get Bills (anonymous) ### Get Bills V2 ### Get Bills V3 ### Add Bill From d596b009340c50517ee5d359eb14abb2cc5a45b8 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 17:54:45 +0200 Subject: [PATCH 13/46] details ping --- docs/dev.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 3a2f2b925..1753e1b29 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -420,6 +420,23 @@ As a general rule, everything related to the `old_id` (so the `paymentmode` in t ### Ping +* Availability: logged requests +* Method: `GET` +* Path: `/api/ping` +* Return: Name of the user making the request, in a 1-element list. +* Errors: + * If the request is made without proper authentication, an error is returned + * If the authentication is incorrect, an empty message is returned +* Example usage: + ```console + ## no proper login + ~$ curl https://mynextcloud.org/index.php/apps/cospend/api/ping + {"message":"Current user is not logged in"} + + ## correct usage + ~$ curl-u "johndoe:mypassword" https://mynextcloud.org/index.php/apps/cospend/api/ping + ["Johndoe"] + ``` ### Create Project ### Get Project Info ### Set Project Info From eaf543010bad8e10d8765bf36fee00b37482a7bd Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:19:04 +0200 Subject: [PATCH 14/46] uniformize name in ping --- docs/dev.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dev.md b/docs/dev.md index 1753e1b29..d5d82cdf1 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -422,7 +422,7 @@ As a general rule, everything related to the `old_id` (so the `paymentmode` in t ### Ping * Availability: logged requests * Method: `GET` -* Path: `/api/ping` +* Endpoint: `/api/ping` * Return: Name of the user making the request, in a 1-element list. * Errors: * If the request is made without proper authentication, an error is returned From 33542e2cd942bdb71d95f629360215ebb9eaa3fc Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:22:05 +0200 Subject: [PATCH 15/46] describe create project --- docs/dev.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index d5d82cdf1..7d3b6dde9 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -438,6 +438,29 @@ As a general rule, everything related to the `old_id` (so the `paymentmode` in t ["Johndoe"] ``` ### Create Project +Create a project. To create it anonymously, the permission `allowAnonymousCreation` must be enabled (in Nextcloud's Administration settings > Misc > Cospend > Allow guests to create projects) +* Availability: Logged and Anonymous requests +* Method: `POST` +* Endpoint: `/api/projects` (anonymous), or `/api-priv/projects` (logged in) +* Parameters: + * `name`: Displayed name of the project (mandatory) + * `id`: A string, unique name across the instance. Must **not** contain a forward slash (`/`) As a comparison, the web lowercases the name and replaces spaces with dashes (`My First Project` -> `my-first-project`). (mandatory) + * `password`: A password for the project (this is the deprecated password protected access, share link password) + * `contact_email`: A contact email for the the project (optional) +* Return: The ID of the newly created project (the same provided in `id`). +* Errors: + * If the `id` contains a forward slash, `{"message": "Invalid project id"}` with code 400 + * If the `id` is already used, `{"message": "A project with id already exists"}` with code 400 +* Example usage: + ```console + ~$ curl -s -X POST \ + --data-urlencode 'name=My First Project'\ + --data-urlencode 'id=my-first-project'\ + -u 'johndoe:mypassword'\ + 'https://mynextcloud.org/index.php/apps/cospend/api-priv/projects' + + "my-first-project" + ``` ### Get Project Info ### Set Project Info ### Delete project From fdc3b470dfaf895cafaf2f34b62b47fc319353a3 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:24:23 +0200 Subject: [PATCH 16/46] describe get project info --- docs/dev.md | 290 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 7d3b6dde9..c0f386431 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -462,6 +462,296 @@ Create a project. To create it anonymously, the permission `allowAnonymousCreati "my-first-project" ``` ### Get Project Info +* Availability: Logged and Anonymous requests +* Method: GET +* Endpoint: `` +* Return: + * `name` [string]: Name of the project. + * `contact_email` [string]: Email of the project owner. + * `id` [string]: ID of the project (as used in the logged in endpoint). + * `guestaccesslevel` [integer]: [Access level](#a-note-about-access-levels) for guests . + * `autoexport` [string]: Is the project set to auto-export (values: `"y"` or `"n"`). + * `currencyname` [string]: Name of the currency of the project. `null` if the currency hasn't been set. + * `lastchanged` [integer]: Unix timestamp of the last modification of the project . + * `active_members` [list]: List of active members. This is a list, each entry containing the following: + * `activated` [boolean]: Whether this user is activated or not. + * `userId` [string]: The user's nextcloud ID (username) + * `name` [string]: The user's nextcloud full name. + * `id` [integer]: The user's cospend ID in this project + * `weight` [integer]: The user's [weight](user.md#what-is-a-member-ok_woman-) in this project + * `color` [object]: An object containing the RGB components (0ver 255) of the color of the user. Specifically: + * `r` [integer]: the Red component (0-255) + * `g` [integer]: the Green component (0-255) + * `b` [integer]: the Blue component (0-255) + * `lastchanged` [integer]: Unix timestamp of the last modification of the user + * `members` [list]: this has the same content as the `active_members` entry. The difference is + * `balance` [object]: An object, in which keys are the members' project integer ID, and the values are the current balance of each member (as a number, positive or negative). By definition, the sum of the balance equal 0. + * `nb_bills` [integer]: Total number of bills in this project. + * `total_spent` [number]: Sum of all the bills' sums. + * `shares` [list]: List of accesses to the project. They can be of 2 types: Users or links (this is what is available in the web interface, under the project's Sharing tab.): + * Users: an object with the following entries: + * `userId` [string]: The user's nextcloud ID (username) + * `name` [string]: The user's nextcloud full name + * `id` [integer]: The user's cospend ID in this project . + * `accesslevel` []: The user's [access level](#a-note-about-access-levels). + * `type` [string]: A single character `"u"`, to indicate the type of access (means "User"). + * `manually_added` [boolean]: Was this share created manually or automatically. + * Links: an object with the following entries: + * `token` [string]: The token used for guest access. This is the `` explained [earlier](#get-the-project_token). + * `id` [integer]: The link's cospend ID in this project 4. + * `accesslevel` []: The [access level](#a-note-about-access-levels) of the link. + * `label` [string, optional]: Label given to the link. If none is specified, `null`. + * `password` [string, optional]: Password give to the link. If none is specified, `null`. **Remember**: if you're using the API with a link that doesn't have a password, you need to use the [default password](#get-the-project_password) + * `type` [string]: A single character `"l"`, to indicate the type of access (means "Link"). + * `currencies` [list]: A list of all secondary currencies. If none, the list is just empty. Each entry is an object with the following entries: + * `name` [string]: Name of the currency + * `exhange_rate` [number]: The factor between for this currency (_1 of this currency = X of main currency_) + * `id` [integer]: ID of the currency for this project + * `categories` [object]: An object containing all the categories. The keys are the categories' ID. For each category, the object is the following: + * `name` [string]: Name of the category. + * `icon` [string]: Single unicode character containing the emoji used as the icon of the category. + * `color` [string]: RGB string, prefixed with a pound sign, that represents the color of the category. + * `id` [integer]: ID of the currency (this is the *same* as the key that leads to this object). **The ID is global across all your projects**. Category `"1"` is only availably in a single project for instance. + * `order` [integer]: Order of the category, when sorting is manual + * `paymentmodes` [object]: Payment modes, with the same format as `categories`: this is an object, the keys are the payment modes' ID, and the values are objects. The objects have the following shape: + * `name` [string]: Name of the payment method. + * `icon` [string]: Single unicode character containing the emoji used as the icon of the payment method. + * `color` [string]: RGB string, prefixed with a pound sign, that represents the color of the payment method. + * `id` [integer]: ID of the currency (this is the *same* as the key that leads to this object). **The ID is global across all your projects**. Payment method `"1"` is only availably in a single project for instance. + * `order` [integer]: Order of the payment method, when sorting is manual. + * `old_id` [string]: Legacy name for the ID of the payment method. + * `deletion_disabled` [boolean]: false, + * `categorysort` [string]: How the categories are sorted. See the [corresponding note](#sort) + * `paymentmodesort` [string]: Similar to `categorysort`, but for payment modes. See the [corresponding note](#sort) + * `myaccesslevel` [integer]: [Access level](#a-note-about-access-levels) of the user making the request. + +* Errors: + * +* Example usage: + ```console + ~$ curl -s -u 'johndoe:mypassword' https://mynextcloud.org/index.php/apps/cospend/api-priv/projects/my-first-project + ``` +
+ Sample answer + + ```json + { + "name": "My First Project", + "contact_email": "johndoe@mynextcloud.org", + "id": "my-first-project", + "guestaccesslevel": 2, + "autoexport": "n", + "currencyname": "EUR", + "lastchanged": 1678648595, + "active_members": [ + { + "activated": true, + "userid": "alicedoe", + "name": "Alice Doe", + "id": 2, + "weight": 1, + "color": { + "r": 110, + "g": 166, + "b": 143 + }, + "lastchanged": 1678636572 + }, + { + "activated": true, + "userid": "johndoe", + "name": "John Doe", + "id": 1, + "weight": 1, + "color": { + "r": 0, + "g": 130, + "b": 201 + }, + "lastchanged": 1678636568 + } + ], + "members": [ + { + "activated": true, + "userid": "alicedoe", + "name": "Alice Doe", + "id": 2, + "weight": 1, + "color": { + "r": 110, + "g": 166, + "b": 143 + }, + "lastchanged": 1678636572 + }, + { + "activated": true, + "userid": "johndoe", + "name": "John Doe", + "id": 1, + "weight": 1, + "color": { + "r": 0, + "g": 130, + "b": 201 + }, + "lastchanged": 1678636568 + } + ], + "balance": { + "2": -83, + "1": 83 + }, + "nb_bills": 2, + "total_spent": 166, + "shares": [ + { + "userid": "alicedoe", + "name": "Alice Doe", + "id": 3, + "accesslevel": 2, + "type": "u", + "manually_added": false + }, + { + "token": "bb9d1bced1d3896e6672db461753e93d", + "id": 4, + "accesslevel": 2, + "label": null, + "password": null, + "type": "l" + } + ], + "currencies": [], + "categories": { + "1": { + "name": "Grocery", + "icon": "🛒", + "color": "#ffaa00", + "id": 1, + "order": 0 + }, + "2": { + "name": "Bar/Party", + "icon": "🎉", + "color": "#aa55ff", + "id": 2, + "order": 0 + }, + "3": { + "name": "Rent", + "icon": "🏠", + "color": "#da8733", + "id": 3, + "order": 0 + }, + "4": { + "name": "Bill", + "icon": "🌩", + "color": "#4aa6b0", + "id": 4, + "order": 0 + }, + "5": { + "name": "Excursion/Culture", + "icon": "🚸", + "color": "#0055ff", + "id": 5, + "order": 0 + }, + "6": { + "name": "Health", + "icon": "💚", + "color": "#bf090c", + "id": 6, + "order": 0 + }, + "7": { + "name": "Shopping", + "icon": "🛍", + "color": "#e167d1", + "id": 7, + "order": 0 + }, + "8": { + "name": "Restaurant", + "icon": "🍴", + "color": "#d0d5e1", + "id": 8, + "order": 0 + }, + "9": { + "name": "Accommodation", + "icon": "🛌", + "color": "#5de1a3", + "id": 9, + "order": 0 + }, + "10": { + "name": "Transport", + "icon": "🚌", + "color": "#6f2ee1", + "id": 10, + "order": 0 + }, + "11": { + "name": "Sport", + "icon": "🎾", + "color": "#69e177", + "id": 11, + "order": 0 + } + }, + "paymentmodes": { + "1": { + "name": "Credit card", + "icon": "💳", + "color": "#FF7F50", + "id": 1, + "order": 0, + "old_id": "c" + }, + "2": { + "name": "Cash", + "icon": "💵", + "color": "#556B2F", + "id": 2, + "order": 0, + "old_id": "b" + }, + "3": { + "name": "Check", + "icon": "🎫", + "color": "#A9A9A9", + "id": 3, + "order": 0, + "old_id": "f" + }, + "4": { + "name": "Transfer", + "icon": "⇄", + "color": "#00CED1", + "id": 4, + "order": 0, + "old_id": "t" + }, + "5": { + "name": "Online service", + "icon": "🌎", + "color": "#9932CC", + "id": 5, + "order": 0, + "old_id": "o" + } + }, + "deletion_disabled": false, + "categorysort": "a", + "paymentmodesort": "a", + "myaccesslevel": 4 + } + ``` +
### Set Project Info ### Delete project ### Get Members From 9626a26c93d32cd5c8c0b273c4f33969936c6b93 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:28:46 +0200 Subject: [PATCH 17/46] describe set project info --- docs/dev.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index c0f386431..4ac6bd589 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -752,7 +752,39 @@ Create a project. To create it anonymously, the permission `allowAnonymousCreati } ``` + ### Set Project Info +* Availability: +* Method: PUT +* Endpoint: `` +* Parameters: + * `name`: New name of the project (**NB**: this doesn't change the project ID used in the API) + * `contact_email`: New contact email for the project. Must be a valid (non-overloaded) address. + * `autoexport`: Set the [auto-export policy](#autoexport). + * `currencyname`: Set the main currency of the project. + * `deletion_disabled`: Whether the deletion of bills is allowed (ticks or not the box "Disable bills deletion" from the web UI). Values `0`, `false` and an empty value untick the box, everything else ticks the box. + * `categorysort`: A [valid character](#sort) to set the sort mode for the categories. + * `paymentmodesort`: A [valid character](#sort) to set the sort mode for the payment modes. +* Return: `"UPDATED"` +* Errors: + * If the email address is not deemed valid, return is `{"contact_email": ["Invalid email address"]}` + * If `autoexport` is not valid, return is `{"autoexport": ["Invalid frequency"]}` + * If the `categorysortorder` is not one of the [valid character](#sort), return is `{"categorysort": ["Invalid sort order"]}` + * If the `paymentmodesortorder` is not one of the [valid character](#sort), return is `{"paymentmodesort": ["Invalid sort order"]}` +* Example usage: + ```console + ~$ curl -s -X PUT \ + -d 'name=My Project New Name&\ + contact_email=contactme@example.org&\ + autoexport=d&\ + currencyname=USD&\ + deletion_disabled=1&\ + categorysort=m&\ + paymentmodesort=u' \ + -u 'johndoe:mypassword' \ + https://mynextcloud.org/index.php/apps/cospend/api-priv/projects/my-first-project + "UPDATED" + ``` ### Delete project ### Get Members ### Add Member From c263c1186634ce62e7769ba1961e800b167d3a5b Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:32:09 +0200 Subject: [PATCH 18/46] describe delete project --- docs/dev.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 4ac6bd589..f6b5bea42 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -786,6 +786,17 @@ Create a project. To create it anonymously, the permission `allowAnonymousCreati "UPDATED" ``` ### Delete project +* Availability: Logged and Anonymous requests (must have the `Admin` [access level](#a-note-about-access-levels)) +* Method: DELETE +* Endpoint: `` +* Return: `{"message": "DELETED"}` +* Errors: + * If the ID of the project doesn't exist, returns `{"message": "Not found"}` with code 404 +* Example usage: + ```console + ~$ curl -s -X DELETE -u 'johndoe:mypassword' https://mynextcloud.org/index.php/apps/cospend/api-priv/projects/my-first-project + {"message": "DELETED"} + ``` ### Get Members ### Add Member ### Add Member V2 From 77191e1be98bd295d80697ec107379f464f0912d Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:34:51 +0200 Subject: [PATCH 19/46] describe get members --- docs/dev.md | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index f6b5bea42..7e2d8dca8 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -798,6 +798,65 @@ Create a project. To create it anonymously, the permission `allowAnonymousCreati {"message": "DELETED"} ``` ### Get Members +* Availability: Logged and Anonymous requests +* Method: GET +* Endpoint: `/members` +* Parameters: + * `lastchanged`: An integer, representing a Unix timestamp. Only return users that have deen changed _after_ this moment. +* Return: A list of objects, each containing information about a member (not links). This is the same information as you would get in the `members` section of the [project information](#get-project-info). Specifically, each objects of the list looks like the following: + * `activated` [boolean]: Whether this user is activated or not. + * `userId` [string]: The user's nextcloud ID (username). + * `name` [string]: The user's nextcloud full name. + * `id` [integer]: The user's cospend ID in this project. + * `weight` [integer]: The user's [weight](user.md#what-is-a-member-ok_woman-) in this project. + * `color` [object]: An object containing the RGB components (0ver 255) of the color of the user. Specifically: + * `r` [integer]: the Red component (0-255), + * `g` [integer]: the Green component (0-255), + * `b` [integer]: the Blue component (0-255). + * `lastchanged` [integer]: Unix timestamp of the last modification of the user. + +* Example usage: + ```console + ~$ curl -u 'johndoe:mypassword' https://mynextcloud.org/index.php/apps/cospend/api-priv/projects/my-first-project/members + ``` + +
+ Sample answer + + ```json + { + [ + { + "activated": true, + "userid": "alicedoe", + "name": "Alice Doe", + "id": 2, + "weight": 1, + "color": { + "r": 110, + "g": 166, + "b": 143 + }, + "lastchanged": 1678636572 + }, + { + "activated": true, + "userid": "johndoe", + "name": "John Doe", + "id": 1, + "weight": 1, + "color": { + "r": 0, + "g": 130, + "b": 201 + }, + "lastchanged": 1678636568 + } + ] + } + ``` +
+ ### Add Member ### Add Member V2 ### Edit Member From 94c782728677a6bd07a46d772955ebeec85a88a6 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:36:47 +0200 Subject: [PATCH 20/46] describe add member --- docs/dev.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 7e2d8dca8..a938a2649 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -858,6 +858,27 @@ Create a project. To create it anonymously, the permission `allowAnonymousCreati ### Add Member +This will add a member to the project, to associate to bills. The method differs slightly for logged in and anonymous users. To preserve compatibiltiy with IHateMoney, the anonymous version of this endpoint doesn't allow to link the member to a Nextcloud user, while the logged in endpoint allows it. + +Users with anonymous access wishing to add a member and link it to a Nextcloud user should use the [v2 endpoint](#add-member-v2) just below. + +* Availability: Logged and Anonymous requests +* Endpoint: `/members` +* Method: POST +* Parameters: + * `name`: Name of the user to add. Mandatory. + * `weight`: Weight the user should have; a positive number, decimal or integer. Defaults to 1. + * `active`: Boolean, whether the user is active or not. Defaults to True. + * `color`: The color of the user. Must start by a pound sign, followed by 3 or 6 hexadecimal characters. Defaults to Null + * `userid`: **Only for logged in endpoint**, not for anonymous. Nextcloud ID (username) of the user to link to that member. + +* Return: ID of the newly created member, as a simple integer. +* Errors: + * If the weight is not a valid positive number, returns `{"message": "Weight is not a valid decimal value"}` + * If the color isn't a valid 3 or 6 hexadecimal characters prefixed with a pound sign, returns `{"message": "Invalid color value"}` + * If the name is already present in the list of members, returns `{"message": "This project already has this member"}` + * If the `name` field is not specified, returns `{"message": "Name field is required"}` + ### Add Member V2 ### Edit Member ### Delete Member From 3e47df752101a2349cdf5270aeda0785ee1bf1fd Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:42:13 +0200 Subject: [PATCH 21/46] describe add member v2 --- docs/dev.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index a938a2649..9eb495ec4 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -880,6 +880,18 @@ Users with anonymous access wishing to add a member and link it to a Nextcloud u * If the `name` field is not specified, returns `{"message": "Name field is required"}` ### Add Member V2 +This is a complement to the [previous endpoint](#add-member). This brings to anonymous users the possibility to add a member and link them to a Nextcloud user. +* Availability: Anonymous requests +* Endpoint: `/apiv2/projects///members` +* Method: POST +* Note: This endpoint allows you to link a Nextcloud user as a Cospend member. Not specifying `userid` is strictly the same as the [basic `addmember`](#add-member) +* Parameters: + * `name`: Name of the user to add. Mandatory. + * `weight`: Weight the user should have; a positive number, decimal or integer. Defaults to 1. + * `active`: Boolean, whether the user is active or not. Defaults to True. + * `color`: The color of the user. Must start by a pound sign, followed by 3 or 6 hexadecimal characters. Defaults to Null + * `userid`: Nextcloud ID (username) of the user to link to that member. +* Return: An object describing the user, with the same fields as the parameters, and the additional field `id` containing the id of the newly created member. ### Edit Member ### Delete Member ### Get Bills (logged in) From d6dc0faeada16322886f8c466ef4f9e63a4b980e Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:42:29 +0200 Subject: [PATCH 22/46] describe edit member --- docs/dev.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 9eb495ec4..2df254032 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -893,6 +893,24 @@ This is a complement to the [previous endpoint](#add-member). This brings to ano * `userid`: Nextcloud ID (username) of the user to link to that member. * Return: An object describing the user, with the same fields as the parameters, and the additional field `id` containing the id of the newly created member. ### Edit Member +* Availability: Logged and Anonymous users +* Endpoint: `/members/` +* Method: PUT +* Parameters: + * `memberid`: ID of the cospend member to edit. Mandatory. + * `name`: New name of the member. + * `weight`: New weight of the member. + * `activated`: Is the member active or not. + * `color`: New color of the member. + * `userid`: Nextcloud ID (username) of a user to link to the member. +* Return: +* Errors: + * If the member name already exists, returns `{"name": "Name already exists"}` with code 403. + * If the color isn't a valid 3 or 6 hexadecimal characters prefixed with a pound sign, returns `{"color": "Invalid value"}` with code 403. + * If the name is invalid (contains a forward slash `/`), returns `{"name": "Invalid member name"}` with code 403. + * If the weight is not a valid positive number, returns `{"weight": "Not a valid decimal value"}` with code 403 + * If the member ID (in the URL) is not a valid existing member, returns `{"name": "This project have no such member"}` with code 403. + ### Delete Member ### Get Bills (logged in) ### Get Bills (anonymous) From 4c06a9baa1d552c39c0fa7720b3281218cf3373a Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:42:49 +0200 Subject: [PATCH 23/46] describe delete member --- docs/dev.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 2df254032..a6f23c436 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -912,6 +912,12 @@ This is a complement to the [previous endpoint](#add-member). This brings to ano * If the member ID (in the URL) is not a valid existing member, returns `{"name": "This project have no such member"}` with code 403. ### Delete Member +* Availability: Logged and Anonymous requests. +* Endpoint: `/members/` +* Method: DELETE +* Return: `"OK"` +* Errors: + * If the `` is not found, returns `"Not found"` with code 404. ### Get Bills (logged in) ### Get Bills (anonymous) ### Get Bills V2 From 993c18c43b7c08ec8be5a1f2d407d1a9c66f408b Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:43:03 +0200 Subject: [PATCH 24/46] describe get bills logged in --- docs/dev.md | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index a6f23c436..6b481d0bc 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -918,7 +918,132 @@ This is a complement to the [previous endpoint](#add-member). This brings to ano * Return: `"OK"` * Errors: * If the `` is not found, returns `"Not found"` with code 404. + ### Get Bills (logged in) +This endpoint is slightly different whether you're anonymous or logged in, although the endpoint is the same. +* Availability: Logged in requests. +* Endpoint: `/bills` (**Only logged in base endpoint**) +* Method: GET +* Parameters: + * `lastchanged`: An integer, representing a Unix timestamp. The lower limit for bills' `lastchanged` field. Aka, returns all bills that have been last modified after this date. **Note: any data will be accepted**, make sure you pass correct values. Even letters and special characters won't yield an error. +* Return: An **object** (contrary to the anonymous endpoint), with the following entries: + * `bills` [list]: A list of objects, each representing one bill (one elemenent from the web UI). They are sorted ascendingly by their field `timestamp`. Each bill is composed of the following entries: + * `id` [integer]: ID of the bill. + * `amount` [number]: Amount of the bill. + * `what` [string]: Name/title of the bill. + * `comment` [string]: Comment of the bill + * `timestamp` [int]: Unix timestamp of the _creation_ of the bill. + * `date` [string]: Human-readable date of the _creation_ of the bill, in the format `YYYY-MM-DD`. Time is not present in this field. + * `payer_id` [int]: ID of the Cospend member that paid the bill. + * `owers` [list]: List of objects, containing details about people owing money on this bill. Each object contains the following: + * `id` [int]: Cospend ID of this ower + * `weight` [number]: Weight of the ower in this particular bill + * `name` [string]: The ower's Nextcloud's full name. + * `activated` [boolean]: Whether the ower is active or not. + * `owerIds` [list]: List of which member is listed as owers in this bill. This is the same information as present in `owers`, but this only contains the list of member ID of the owers, and nothing else. + * `repeat` [string]: The [repeat cycle](#repeat) of the bill. + * `paymentmode` [string]: Legacy Payment mode ID, defined by a single character (or `n` if no payment or a non-default payment mode is selected, see [this note](#payment-modes-id)). + * `paymentmodeid` [integer]: The modern ID of the payment mode used for this bill; 0 means no payment mode has been selected. If the payment mode is one of the default ones, this is redundant to `paymentmode`. + * `categoryid` [integer]: Similarly represents the ID of the category of the bill. 0 means no category has been selected. + * `lastchanged` [integer]: Unix timestamp of the moment this bill was last edited/changed. + * `repeatallactive` [integer]: Whether the bill should repeat for all members currently active or specifically the current owers of the bill. See [this note](#repeat) for how it's used. + * `repeatuntil` [integer]: Unix timestamp of the datetime after which the bill will stop repeating. `null` if no date has been set. + * `repeatfreq` [integer]: Modifier of the frequency for repeating. See [this note](#repeat) for what it means. + * `allbillsid` [list]: A list of all the IDs of existing bills. Even if the bills have been filtered out by the `lastchanged` parameter, their ID will still appear here. + * `timestamp` [integer]: Unix timestamp of the time of the request + +* Example usage: + ```console + ~$ curl -s -u 'johndoe:mypassword' https://mynextcloud.org/index.php/apps/cospend/api-priv/projects/my-first-project/bills + ``` + +
+ Sample answer + + ```json + { + "bills": [ + { + "id": 1, + "amount": 200, + "what": "First bill", + "comment": "", + "timestamp": 1678636575, + "date": "2023-03-12", + "payer_id": 1, + "owers": [ + { + "id": 1, + "weight": 1, + "name": "John Doe", + "activated": true + }, + { + "id": 2, + "weight": 1, + "name": "Alice Doe", + "activated": true + } + ], + "owerIds": [ + 1, + 2 + ], + "repeat": "n", + "paymentmode": "n", + "paymentmodeid": 0, + "categoryid": 0, + "lastchanged": 1680875221, + "repeatallactive": 0, + "repeatuntil": null, + "repeatfreq": 1 + }, + { + "id": 2, + "amount": 66, + "what": "Yet another bill", + "comment": "", + "timestamp": 1678645901, + "date": "2023-03-12", + "payer_id": 1, + "owers": [ + { + "id": 1, + "weight": 1, + "name": "Olivier", + "activated": true + }, + { + "id": 2, + "weight": 1, + "name": "Coralie", + "activated": true + } + ], + "owerIds": [ + 1, + 2 + ], + "repeat": "n", + "paymentmode": "n", + "paymentmodeid": 0, + "categoryid": 0, + "lastchanged": 1678645916, + "repeatallactive": 0, + "repeatuntil": null, + "repeatfreq": 1 + } + ], + "allBillIds": [ + 2, + 1 + ], + "timestamp": 1680875473 + } + ``` +
+ + ### Get Bills (anonymous) ### Get Bills V2 ### Get Bills V3 From 4be0905a8e4ddbbdd5b51efe7b8f1b59637a534a Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:43:13 +0200 Subject: [PATCH 25/46] describe get bills anonymous --- docs/dev.md | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 6b481d0bc..6290174aa 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1045,6 +1045,130 @@ This endpoint is slightly different whether you're anonymous or logged in, altho ### Get Bills (anonymous) +This endpoint is slightly different whether you're anonymous or logged in, although the endpoint is the same. It allows you to _limit_ the results, but not _filter_ them. +* Availability: Anonymous requests +* Endpoint: `/bills` (**Only anonymous base endpoint**) +* Method: GET +* Parameters: + * `lastchanged`: An integer, representing a Unix timestamp. The lower limit for bills' `lastchanged` field. Aka, returns all bills that have been last modified after this date. **Note: any data will be accepted**, make sure you pass correct values. Even letters and special characters won't yield an error. + * `limit`: An integer, how may items should be returned at maximum. + * `offset`: An integer (starting at 0), defining from which position of the list should the limit apply. Ignored if `limit` is not specified. Default to 0 (no element discarded). + * `reverse`: A boolean, to determine if the list of bills should be sorted ascending (default, false) or descending (true). `0` and `false` mean False, everything else means True. +* Return: A **list** (contrary to the logged in endpoint) of all the bills. This is the same as the list of `bills` returned by the [logged in endpoint](#get-bills-logged-in). This method doesn't return `allBillIds` or `timestamp`, it just returns the list of bills. As such, the parameters passed influence how this list is returned. The parameters are applied in the following order (assuming all of them have been provided): + 1. Get all of the bills with that have been modified after `lastchanged` + 2. Sort the list ascending or descending according to `reverse` + 3. Discard elements before `offset` + 4. Discard elements after `limit`. + + Assuming, without parameters, the bills returned would be `[1,2,3,4,5]`, and the parameters are `reverse=true&offset=2&limit=2`, the end result will be `[3,2]. +* Errors: + * Negative `offset` or `limit` throws an error 500, with message `parse error: Invalid numeric literal at line 1, column 10`. + +* Example usage: + ```console + $~ curl -s 'https://mynextcloud.org/index.php/apps/cospend/api/projects/bb9d1bced1d3896e6672db461753e93d/no-pass/bills?reverse=truelimit=2&offset=1' + ``` + +
+ Sample answer + + ```json + [ + { + "id": 5, + "amount": 351, + "what": "A nice bill", + "comment": "", + "timestamp": 1679234191, + "date": "2023-03-19", + "payer_id": 3, + "owers": [ + { + "id": 3, + "weight": 1, + "name": "John Doe", + "activated": true + } + ], + "owerIds": [ + 3 + ], + "repeat": "n", + "paymentmode": "n", + "paymentmodeid": 0, + "categoryid": 0, + "lastchanged": 1679234239, + "repeatallactive": 0, + "repeatuntil": null, + "repeatfreq": 1 + }, + { + "id": 6, + "amount": 69, + "what": "A nice bill", + "comment": "", + "timestamp": 1679234191, + "date": "2023-03-19", + "payer_id": 3, + "owers": [ + { + "id": 4, + "weight": 1, + "name": "Alice Doe", + "activated": true + } + ], + "owerIds": [ + 4 + ], + "repeat": "n", + "paymentmode": "n", + "paymentmodeid": 0, + "categoryid": 0, + "lastchanged": 1679234239, + "repeatallactive": 0, + "repeatuntil": null, + "repeatfreq": 1 + }, + { + "id": 3, + "amount": 100, + "what": "My first bill", + "comment": "", + "timestamp": 1679234084, + "date": "2023-03-19", + "payer_id": 3, + "owers": [ + { + "id": 3, + "weight": 1, + "name": "John Doe", + "activated": true + }, + { + "id": 4, + "weight": 1, + "name": "Alice Doe", + "activated": true + } + ], + "owerIds": [ + 3, + 4 + ], + "repeat": "n", + "paymentmode": "n", + "paymentmodeid": 0, + "categoryid": 0, + "lastchanged": 1679234133, + "repeatallactive": 0, + "repeatuntil": null, + "repeatfreq": 1 + } + ] + ``` +
+ ### Get Bills V2 ### Get Bills V3 ### Add Bill From b520e3ce59da4171af16fe1dc2f312ed41176586 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:43:36 +0200 Subject: [PATCH 26/46] describe get bills v2 --- docs/dev.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 6290174aa..2d896e343 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1170,6 +1170,11 @@ This endpoint is slightly different whether you're anonymous or logged in, altho ### Get Bills V2 +This is equivalent to [the logged in equivalent](#get-bills-logged-in). Check the other section for detailed specifications. +* Availability: Anonymous requests +* Endpoint: `/apiv2/projects///bills` +* Method: GET + ### Get Bills V3 ### Add Bill ### Edit Bill From 00be5c9fe9480e71c54774c9b7af65b936b976a5 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:43:49 +0200 Subject: [PATCH 27/46] describe get bills v3 --- docs/dev.md | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 2d896e343..e9e07af4c 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1176,6 +1176,149 @@ This is equivalent to [the logged in equivalent](#get-bills-logged-in). Check th * Method: GET ### Get Bills V3 +* Availability: Anonymous requests +* Endpoint: `/apiv3/projects///bills` +* Method: GET +* Parameters: + * `lastchanged`, `offset`, `limit`, `reverse`: the same as [the v2 counterpart](#get-bills-v2) + * `payerId`: An integer, representing one cospend member's ID. Filter bills to only keep the ones that were paid by this member. It only applies to `payer_id`, not to owerIds. + * `categoryId`: An integer, representing a category's ID. Filter bills to only keep the ones that have this category indicated. + * `paymentModeId`: Similarly, an integer representing a payment mode's ID. Filter bills to only keep the ones that have this payment mode indicated. Note, this is the payment mode ID (an integer), not the [legacy ID](#payment-modes-id) (a letter) + * `includeBillId`: An integer, representing the ID of one (1) bill, to forcefully include despite the limit filtering. This is only available when `limit` is used, otherwise the parameter is ignored. This + * `searchTerm`: +* Return: An object, containing the following: + * `nb_bills` [integer]: The number of bills _filtered_, before _limits_. The number here may be different from the actual number of bills in `bills`, if you've used `limit`. + * `bills` [list]: List of bills, with the same structure of other method ([logged in](#get-bills-logged-in), [anonymous](#get-bills-anonymous), [anonymous v2](#get-bills-v2)) + +* Example usage: + ```console + $~ curl -s 'https://mynextcloud.org/index.php/apps/cospend/apiv3/projects/bb9d1bced1d3896e6672db461753e93d/no-pass/bills?limit=2' + ``` + +
+ Sample answer + + ```json + { + "nb_bills": 3, + "bills": [ + { + "id": 3, + "amount": 100, + "what": "My first bill", + "comment": "", + "timestamp": 1679234084, + "date": "2023-03-19", + "payer_id": 3, + "owers": [ + { + "id": 3, + "weight": 1, + "name": "John Doe", + "activated": true + }, + { + "id": 4, + "weight": 1, + "name": "Alice Doe", + "activated": true + } + ], + "owerIds": [ + 3, + 4 + ], + "repeat": "n", + "paymentmode": "n", + "paymentmodeid": 0, + "categoryid": 0, + "lastchanged": 1679234133, + "repeatallactive": 0, + "repeatuntil": null, + "repeatfreq": 1 + }, + { + "id": 5, + "amount": 351, + "what": "A nice bill", + "comment": "", + "timestamp": 1679234191, + "date": "2023-03-19", + "payer_id": 3, + "owers": [ + { + "id": 3, + "weight": 1, + "name": "John Doe", + "activated": true + } + ], + "owerIds": [ + 3 + ], + "repeat": "n", + "paymentmode": "n", + "paymentmodeid": 0, + "categoryid": 0, + "lastchanged": 1679234239, + "repeatallactive": 0, + "repeatuntil": null, + "repeatfreq": 1 + } + ] + } + ``` +
+ + Some more examples, to understand the difference between _limiting_ and _filtering_ + + ```console + $~ curl -s 'https://mynextcloud.org/index.php/apps/cospend/apiv3/projects/bb9d1bced1d3896e6672db461753e93d/no-pass/bills' \ + | jq -r '.bills[].id' # get the ID of each returned bills, no **filter** or **limit** + + 1,2,7,8,10,9,11,12 + + + $~ curl -s 'https://mynextcloud.org/index.php/apps/cospend/apiv3/projects/bb9d1bced1d3896e6672db461753e93d/no-pass/bills?limit=3' \ + | jq -r '.bills[].id' # **limit** to 3 items + + 1,2,7 + + $~ curl -s 'https://mynextcloud.org/index.php/apps/cospend/apiv3/projects/bb9d1bced1d3896e6672db461753e93d/no-pass/bills?limit=3&offset=4' \ + | jq -r '.bills[].id' # same **limit** but offset by 4 + + 10,9,11 + + $~ curl -s 'https://mynextcloud.org/index.php/apps/cospend/apiv3/projects/bb9d1bced1d3896e6672db461753e93d/no-pass/bills?payerId=1' \ + | jq -r '.bills[].id' # **filter** only the bills made by a specific member. + + ## all bills but 11 and 12 are paid by member 1. + 1,2,7,8,10,9 + + $~ curl -s 'https://mynextcloud.org/index.php/apps/cospend/apiv3/projects/bb9d1bced1d3896e6672db461753e93d/no-pass/bills?limit=3&offset=4&payerId=1' \ + | jq -r '.bills[].id' # merge the two previous: first **filter** to user 1, then **limit** to 3 results, offset by 4 + + ## from the offset of 4, the limit is not "reached" + 10,9 + + $~ curl -s 'https://mynextcloud.org/index.php/apps/cospend/apiv3/projects/bb9d1bced1d3896e6672db461753e93d/no-pass/bills?limit=3&offset=4&payerId=1' \ + | jq -r '.nb_bills' # same request, but get the field nb_bills instead of listing the bills' ID + + ## despite returning only bills 10 and 9 (after **limit**), nb_bills returns the number of bills after **filter** but excluding **limits** + 6 + + $~ curl -s 'https://mynextcloud.org/index.php/apps/cospend/apiv3/projects/bb9d1bced1d3896e6672db461753e93d/no-pass/bills?limit=3&offset=4&payerId=1&includeBillId=10' \ + | jq -r '.bills[].id' # Same, but forcefully include bill 10 (already included) + + 10,9 + + $~ curl -s 'https://mynextcloud.org/index.php/apps/cospend/apiv3/projects/bb9d1bced1d3896e6672db461753e93d/no-pass/bills?limit=3&offset=4&payerId=1&includeBillId=12' \ + | jq -r '.bills[].id' # Same, but forcefully include bill 12 (not yet included) + + ## includeBillId is a **limiting** option, doesn't take precedence over **filtering**. Bill 12 wouldn't have been returned after filtering, so it's not included after limiting. + 10,9 + ``` ### Add Bill ### Edit Bill ### Delete Bill From 465b54681534198cc091f58e04326fd11e877a1d Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:44:04 +0200 Subject: [PATCH 28/46] describe add bill --- docs/dev.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index e9e07af4c..50c9f0a72 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1320,6 +1320,34 @@ This is equivalent to [the logged in equivalent](#get-bills-logged-in). Check th 10,9 ``` ### Add Bill +* Availability: Logged in and Anonymous requests +* Method: POST +* Endpoint: `/bills` +* Parameters: + * `date`: A string indicating the date of the payment (optional, but one of `timestamp` and `date` is mandatory) + * `what`: A string indicating the subject of the bill (optionnal) + * `payer`: An integer (mandatory) + * `payed_for`: A string, being a list of coma-separated of integers, each representing a member ID, to indicate the owers of the bill; can be a single integer if there is only one ower. + * `amount`: A number (integer or floating point) to indicate the value of the bill (mandatory) + * `repeat`: A string (one character) to indicating the [reapeating mode](#repeat) (optional, `n` by default) + * `paymentmode`: A string (one character) referring to the `old_id` of a [payment mode](#payment-modes-id) (optional) + * `paymentmodeid`: An integer representing the `id` of a [payment mode](#payment-modes-id) (optional) + * `categoryid`: An integer representing the `id` of a category (optional). + * `repeatallactive`: An integer to indicate if a bill should [repeat](#repeat) for all active members or only the ones indicated (optional, defaults to 0). + * `repeatuntil`: An integer, representing a Unix timestamp of the moment after which a bill should stop repeating (optional; if a bill is repeating and this is not specified, the bill will repeat infinitely) + * `repeatfreq`: An integer, represeting the frequency of the [bill repetition](#repeat). + * `timestamp`: An integer, representing a Unix timestamp of the date and time of the bill; takes precedence over `date` (Optional, but one of `timestamp` and `date` is mandatory), + * `comment`: A string to indicate a comment to the bill (optionnal) +* Return: A single integer, representing the ID of the bill that has just been added. +* Errors: + * If neither `timestamp` nor `date` are specified, returns `{"message": "Timestamp (or date) field is required"}` with code 400. + * If `timestamp` is not specified, `date` is specified and `date` can't be interpreted as a valid date, returns `{"date": "Invalid date"}` with code 400. + * If the field `amount` is not specified, returns `{"amount": "This field is required"}` with code 400. + * If the field `payer` is not specified, returns `{"payer": "This field is required"}` with code 400. + * If the field `payer` is specified but is not a vaid member ID: `{"payer": "Not a valid choice"}` with code 400. + * If `payed_for` if not specified, or can't be interpreted as a list of numbers, returns `{"payer": "Invalid value"}` with code 400. + * If *any* of the integers of `payed_for` is not a valid member ID, returns `{"payed_for": "Not a valid choice"}` with code 400. + ### Edit Bill ### Delete Bill ### Get Project Statistics From 168b707059750c7811fd765ac4b695eb4770f983 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:44:24 +0200 Subject: [PATCH 29/46] describe edit bill --- docs/dev.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 50c9f0a72..0fdcfcf0f 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1349,6 +1349,19 @@ This is equivalent to [the logged in equivalent](#get-bills-logged-in). Check th * If *any* of the integers of `payed_for` is not a valid member ID, returns `{"payed_for": "Not a valid choice"}` with code 400. ### Edit Bill +* Availability: Logged in and Anonymous requests +* Method: PUT +* Endpoint: `/bills/` +* Parameters: They are the same as [Add Bill](#add-bill); note that the endpoint contains the `bill_id`. +* Return: + * The ID of the bill edited +* Errors (all return code 400): + * If the `` from the endpoint doesn't match an existing bill, returns `{"message": "There is no such bill"}`. + * If the `repeat` character is not [valid](#repeat), returns `{"repeat": "Invalid value"}` + * If `date` is invalid (and `timestamp` is not specified), returns `{"date": "Invalid value"}`. + * If the field `payer` is specified but is not a vaid member ID: `{"payer": "Not a valid choice"}`. + * If *any* of the integers of `payed_for` is not a number, returns `{"payed_for": "Invalid value"}`; if either of them isn't a valid member ID, returns `{"payed_fo": "Not a valid choice"}`. + ### Delete Bill ### Get Project Statistics ### Get Project Settlement From 4c17812f97229c109e560fffea7764ae271db575 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:44:54 +0200 Subject: [PATCH 30/46] describe edit bills --- docs/dev.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 0fdcfcf0f..c584ac147 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1362,6 +1362,23 @@ This is equivalent to [the logged in equivalent](#get-bills-logged-in). Check th * If the field `payer` is specified but is not a vaid member ID: `{"payer": "Not a valid choice"}`. * If *any* of the integers of `payed_for` is not a number, returns `{"payed_for": "Invalid value"}`; if either of them isn't a valid member ID, returns `{"payed_fo": "Not a valid choice"}`. +### Edit Bills +Using anonymous access, it's possible to edit bills in batches. +Instead of specifying the bills as a part of the URL, the bills are passed as a parameter (coma-separated integers). +The other parameters are the same as [Edit Bill](#edit-bill). +The values are applied identically to all of the bills passed. + +Note that in case of an error (notably if one of the ID is invalid), all bills before the error are processed, but the ones after are not. +* Availability: Anonymous requests only +* Method: PUT +* Endpoint: `/bills` +* Parameters: + * `bills`: Coma-separated integers, each being a valid existing bill to edit. + * Same as [Edit Bill](#edit-bill). +* Return: The same coma-separated list of IDs passed as parameter. +* Errors: + * Same errors than [Edit Bill](#edit-bill). + ### Delete Bill ### Get Project Statistics ### Get Project Settlement From 7a11ce83261f85ad37d418b9787c0107217eb960 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:45:10 +0200 Subject: [PATCH 31/46] describe delete bill --- docs/dev.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index c584ac147..e0ef45b0f 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1380,6 +1380,13 @@ Note that in case of an error (notably if one of the ID is invalid), all bills b * Same errors than [Edit Bill](#edit-bill). ### Delete Bill +* Availability: Logged in and Anonymous requests. +* Method: DELETE +* Endpoint: `/bills/ Date: Mon, 24 Apr 2023 18:45:24 +0200 Subject: [PATCH 32/46] describe delete bills --- docs/dev.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index e0ef45b0f..498ce76dd 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1387,6 +1387,20 @@ Note that in case of an error (notably if one of the ID is invalid), all bills b * Errors: * If the ID provided doesn't match a valid bill, returns `{"message": "Not Found"}`, with code 400. +### Delete Bills +Similarly to [Edit Bills](#edit-bills), this is an anonymous-only helper endpoint, to allow to delete bills in batches. +Specify the bills as coma-separated integers, each representing one of the bills to delete. + +Note that in case of an error (notably if one of the ID is invalid), all bills before the error are processed, but the ones after are not. + +* Availability: Anonymous requests +* Endpoint: `/bills` +* Method: DELETE +* Parameters: + * `bills`: Coma-separated integers, each being a valid existing bill to edit. +* Return: `OK` +* Errors: + * If *any* of the ID provided doesn't match a valid bill, returns `{"message": "Not Found"}`, with code 400. ### Get Project Statistics ### Get Project Settlement ### Auto Settlement From 362448bfb206e2be4f5fcba9dd4152659539726a Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:45:44 +0200 Subject: [PATCH 33/46] describe get stats --- docs/dev.md | 355 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 355 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 498ce76dd..ac64e500a 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1402,6 +1402,361 @@ Note that in case of an error (notably if one of the ID is invalid), all bills b * Errors: * If *any* of the ID provided doesn't match a valid bill, returns `{"message": "Not Found"}`, with code 400. ### Get Project Statistics +This endpoint will retrieve all the bills that *match all* the filters passed as parameters, and compute statistics on them. + +Note: statistics include operations on the numbers; due to their nature, operations on floating points may be slightly erroneous; make you take that into account when displaying your results. Remember that [`0.1 + 0.2 != 0.3`](https://blog.reverberate.org/2016/02/06/floating-point-demystified-part2.html) +* Availability: Logged in and Anonymous requests +* Method: GET +* Endpoint: `//statistics` +* Parameters: + * `tsMin`: An integer, representing a Unix timestamp; compute stats only on bills paid *after* that moment + * `tsMax`: An integer, representing a Unix timestamp; compute stats only on bills paid *before* that moment + * `paymentModeId`: An integer, representing a [payment mode's ID](#payment-modes-id); compute stats only on bills with that payment mode ID + * `categoryId`: An integer, representing a category's ID; compute stats only on bills with that category ID. + * `amountMin`: A number representing a minimum amount for bills; compute stats only on bills with a *greater* amount than this. + * `amountMax`: A number representing a minimum amount for bills; compute stats only on bills with a *lower* amount than this. + * `showDisabled`: A string, to indicate if stats should be computer on all the active members only (default) or all members including the disabled ones. `0` to show all members, anything else to only show active members. + * `currencyId`: An integer, representing a currency's ID; compute stats only on bills paid with that currency. + * `payerId`: An integer, representing a member's ID in the project; compute stats only on bills paid by that member. +* Return: an object, with the following fields: + * `stats`: a list of objects; each entry represents some stats on the members. Sorted aphabetically by their lowercase `name`. Each entry contains the following fields: + * `balance` [number]: How much that member ows others or is owed by other members, overall, regardless of the filters passed. + * `filtered_balance` [number]: The balance of the user after applying the filters passed as parameters. + * `paid` [number]: How much that member paid across the bills (sum of the total of the bills paid by that member). + * `spent` [number]: How much that member spent across bills (sum of how much that user owes in each bills, including the ones not paid by that user). + * `member`: An object giving information on the user. The same information as returned in [Get Members](#get-members). + * `memberMonthlyPaidStats` [object]: An object, grouping how many each member _paid_ on each month. Each entry is a month (`YYYY-MM`), except one special entry that is `Average per month`. + * For each month (and the special `Average per month`), there is the ID of each member that contributed that month (as a string), and how much they paid over that month. + * The special "ID" `"0"` is the total for that month (e.g. member `"1"` paid 500, member `"2"` paid 100, then "member" `"0"` paid 1500) + * `memberMonthlySpentStats` [object]: An object, with the same construction as `memberMonthlyPaidStats` but declines how many each member _spent_ on each month. + * `categoryStats`: An object OR a list, saying how much has been spent in each category. + * If no bill has a category, the result is a list containing a single number, representing the total spent (in the "None" category) + * If at least one bill has a category, the result is an object; keys are the categories' ID, and the values are how much has been spent in that category. Additionally, "category `"0"`" represents the bills without category. + * `categoryMonthlyStats`: Similarly, an object OR a list, giving how much has been spent monthly for each category. + * If no bill has a category, the result is a list containing a single object (same format as `memberMonthlyPaidStats`: one key `YYYY-MM` per month plus an additional `"Average per month"`) + * If at least one bill has a category, the result is an object, which keys are the categories' ID and the values are the monthly stats (as above); the special "category `"0"` represents all the bills without category. + * `paymentModeStats`: Similarly, an object OR a list, for how much as been spent with each payment mode overall. + * `paymentModeMonthlyStats`: Similarly, an object OR a list, for how much as been spent during each month with each payment mode. + * `categoryMemberStats`: Similarly, an object OR a list, for how much each member spent per category. Keys are the categories' ID, values are an object; in this object, keys are the members' ID and values are how much this member spent on this category. + * `memberIds` [list]: List of integers, representing the IDs of all the _active_ members of the project. + * `allMemberIds` [list]: List of integers, representing the IDs of all the members of the project (even the disabled ones). + * `membersPaidFor` [object]: An object representing how much each member paid for other members. + * Each key is a member ID. Values are object to indicate how much a member (parent) paid for each other member (children), in which the keys are members' ID. There is also a special `"total"` key, representing how much the (parent) member paid in total. + * There is an additional special key `total`, leading to another object with members ID as keys. Each line represents how much was paid for this user (how much this member spent, this is the same as `stats.spent` above) + * `realMonths` [list]: List of all the months (still in the format `YYYY-MM`) that the stats cover. +* Example usage: + ```console + ## In this, no bill has a category + ~$ curl -s 'https://mynextcloud.org/index.php/apps/cospend/api/projects/bb9d1bced1d3896e6672db461753e93d/no-pass/statistics' + ``` +
+ Sample answer + + ```json + { + "stats": [ + { + "balance": -1105.6666666667002, + "filtered_balance": -1105.6666666667002, + "paid": 1000, + "spent": 2105.6666666667, + "member": { + "activated": true, + "userid": "alicedoe", + "name": "Alice Doe", + "id": 2, + "weight": 1, + "color": { + "r": 110, + "g": 166, + "b": 143 + }, + "lastchanged": 1678636572 + } + }, + { + "balance": 1105.6666666667002, + "filtered_balance": 1105.6666666667002, + "paid": 2600.00000000003, + "spent": 1494.33333333333, + "member": { + "activated": true, + "userid": "johndoe", + "name": "John Doe", + "id": 1, + "weight": 1, + "color": { + "r": 0, + "g": 130, + "b": 201 + }, + "lastchanged": 1678636568 + } + } + ], + "memberMonthlyPaidStats": { + "2023-03": { + "2": 0, + "1": 266, + "0": 266 + }, + "2023-04": { + "2": 1000, + "1": 2334.00000000003, + "0": 3334.00000000003 + }, + "Average per month": { + "2": 500, + "1": 1300.000000000015, + "0": 1800.000000000015 + } + }, + "memberMonthlySpentStats": { + "2023-03": { + "2": 133, + "1": 133, + "0": 266 + }, + "2023-04": { + "2": 1972.6666666667002, + "1": 1361.33333333333, + "0": 3334.00000000003 + }, + "Average per month": { + "2": 1052.83333333335, + "1": 747.166666666665, + "0": 1800.000000000015 + } + }, + "categoryStats": [ + 3600.00000000003 + ], + "categoryMonthlyStats": [ + { + "2023-03": 266, + "2023-04": 3334.00000000003, + "Average per month": 1800.000000000015 + } + ], + "paymentModeStats": { + "0": 2800.00000000003, + "3": 600, + "26": 200 + }, + "paymentModeMonthlyStats": { + "0": { + "2023-03": 266, + "2023-04": 2534.00000000003, + "Average per month": 1400.000000000015 + }, + "3": { + "2023-04": 600, + "Average per month": 300 + }, + "26": { + "2023-04": 200, + "Average per month": 100 + } + }, + "categoryMemberStats": [ + { + "2": 1000, + "1": 2600.00000000003 + } + ], + "memberIds": [ + 2, + 1 + ], + "allMemberIds": [ + 2, + 1 + ], + "membersPaidFor": { + "2": { + "2": 550, + "1": 450, + "total": 1000 + }, + "total": { + "2": 2105.6666666667, + "1": 1494.33333333333 + }, + "1": { + "2": 1555.6666666667002, + "1": 1044.33333333333, + "total": 2600.00000000003 + } + }, + "realMonths": [ + "2023-03", + "2023-04" + ] + } + ``` +
+ + ```console + ## The same, but >one< bill has a category + ~$ curl -s 'https://mynextcloud.org/index.php/apps/cospend/api/projects/bb9d1bced1d3896e6672db461753e93d/no-pass/statistics' + ``` + +
+ Sample answer + + ```json + { + "stats": [ + { + "balance": -1105.6666666667002, + "filtered_balance": -1105.6666666667002, + "paid": 1000, + "spent": 2105.6666666667, + "member": { + "activated": true, + "userid": "alicedoe", + "name": "Alice Doe", + "id": 2, + "weight": 1, + "color": { + "r": 110, + "g": 166, + "b": 143 + }, + "lastchanged": 1678636572 + } + }, + { + "balance": 1105.6666666667002, + "filtered_balance": 1105.6666666667002, + "paid": 2600.00000000003, + "spent": 1494.33333333333, + "member": { + "activated": true, + "userid": "johndoe", + "name": "John Doe", + "id": 1, + "weight": 1, + "color": { + "r": 0, + "g": 130, + "b": 201 + }, + "lastchanged": 1678636568 + } + } + ], + "memberMonthlyPaidStats": { + "2023-03": { + "2": 0, + "1": 266, + "0": 266 + }, + "2023-04": { + "2": 1000, + "1": 2334.00000000003, + "0": 3334.00000000003 + }, + "Average per month": { + "2": 500, + "1": 1300.000000000015, + "0": 1800.000000000015 + } + }, + "memberMonthlySpentStats": { + "2023-03": { + "2": 133, + "1": 133, + "0": 266 + }, + "2023-04": { + "2": 1972.6666666667002, + "1": 1361.33333333333, + "0": 3334.00000000003 + }, + "Average per month": { + "2": 1052.83333333335, + "1": 747.166666666665, + "0": 1800.000000000015 + } + }, + "categoryStats": { + "0": 2700.00000000003, + "9": 900 + }, + "categoryMonthlyStats": { + "0": { + "2023-03": 266, + "2023-04": 2434.00000000003, + "Average per month": 1350.000000000015 + }, + "9": { + "2023-04": 900, + "Average per month": 450 + } + }, + "paymentModeStats": { + "0": 2800.00000000003, + "3": 600, + "26": 200 + }, + "paymentModeMonthlyStats": { + "0": { + "2023-03": 266, + "2023-04": 2534.00000000003, + "Average per month": 1400.000000000015 + }, + "3": { + "2023-04": 600, + "Average per month": 300 + }, + "26": { + "2023-04": 200, + "Average per month": 100 + } + }, + "categoryMemberStats": { + "0": { + "2": 100, + "1": 2600.00000000003 + }, + "9": { + "2": 900, + "1": 0 + } + }, + "memberIds": [ + 2, + 1 + ], + "allMemberIds": [ + 2, + 1 + ], + "membersPaidFor": { + "2": { + "2": 550, + "1": 450, + "total": 1000 + }, + "total": { + "2": 2105.6666666667, + "1": 1494.33333333333 + }, + "1": { + "2": 1555.6666666667002, + "1": 1044.33333333333, + "total": 2600.00000000003 + } + }, + "realMonths": [ + "2023-03", + "2023-04" + ] + } + ``` +
+ ### Get Project Settlement ### Auto Settlement ### Add Currency From ccecabdf523f8317f536382527526717eb3e2d54 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:45:56 +0200 Subject: [PATCH 34/46] describe get settlement --- docs/dev.md | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index ac64e500a..8331b0771 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1758,6 +1758,69 @@ Note: statistics include operations on the numbers; due to their nature, operati ### Get Project Settlement +* Availability: Logged in and Anonymous requests +* Method: GET +* Endpoint: `/settle` +* Parameters: + * `centeredOn` [integer]: A member ID. Make the settlement centered on a member, meaning how much that user must receive and give to everyone else to have a balance of 0. Any number is accepted, which will appear like a "virtual" or "transient" member that must simple receive money from people and giving it away to other members. + * `maxTimestamp` [integer]: Represents a Unix timestamp. Only retrieve bills paid before that moment to compute the balances. +* Return: An object with the keys `transactions` (what transactions must be done to settle), and `balances` (list of total balances for each member). + * `transactions` [list]: A list of objects. Each item represents one transaction that must be carried, with the keys `from` and `to` (integers, members ID) and the keys `amount` (number, how much must be paid). + * `balances` [object]: Each key is a member's ID, and the value is the current balance of that member. + +* Example usage: + ```console + ~$ curl -s 'https://mynextcloud.org/index.php/apps/cospend/api/projects/bb9d1bced1d3896e6672db461753e93d/no-pass/settle' + ``` +
+ Sample answer + + ```json + { + "transactions": [ + { + "to": 1, + "amount": 1105.6666666667002, + "from": 2 + } + ], + "balances": { + "2": -1105.6666666667002, + "1": 1105.6666666667002 + } + } + ``` +
+ + ```console + ~$ curl -s 'https://mynextcloud.org/index.php/apps/cospend/api/projects/bb9d1bced1d3896e6672db461753e93d/no-pass/settle?centeredOn=52432335' + ``` +
+ Sample answer + + ```json + { + "transactions": [ + { + "from": 2, + "to": 52432335, + "amount": 1105.6666666667002 + }, + { + "from": 52432335, + "to": 1, + "amount": 1105.6666666667002 + } + ], + "balances": { + "2": -1105.6666666667002, + "1": 1105.6666666667002 + } + } + + ``` +
+ ### Auto Settlement ### Add Currency ### Edit Currency From d46caf9d25fd0175c4703e81e58627cee6d7134f Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:46:14 +0200 Subject: [PATCH 35/46] describe auto settlement --- docs/dev.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 8331b0771..813607a3a 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1822,6 +1822,16 @@ Note: statistics include operations on the numbers; due to their nature, operati ### Auto Settlement +This function calls the same method as [Get Project Settlement](#get-project-settlement), then actually creates the bills that would have been returned. +If the member of the project decide it's time to settle, they could first call the former endpoint, perform the recommended transcations, then automatically create the bills with this endpoint. + +Each bill created with this method will have the tile `` (using the full names). +* Availability: Logged in and Anonymous requests +* Method: GET +* Endpoint: `/autosettlement` +* Return: `{"success": true}` +* Errors: + * If any of the bill has an issue while being created, `{"message": "Error when adding a bill"}` is returned, with code 403. All bills before the creation will be created, the error'ed bill and the following won't. ### Add Currency ### Edit Currency ### Delete Currency From 33330acf2414060ff25aed3667565864b24c62f4 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:47:04 +0200 Subject: [PATCH 36/46] describe add currency --- docs/dev.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 813607a3a..bcd890711 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1832,7 +1832,18 @@ Each bill created with this method will have the tile `/currency` +* Parameters: + * `name`: The name of the currency (mandatory). + * `currency`: A number representing the exchange rate. 1 of this currency = X of main currency (mandatory). +* Return: A simple integer, the ID of the newly created currency. +* Errors: + * If you don't have the permissions to manage currencies, `{"message": "You are not allowed to manage currencies"}`, with code 401. + ### Edit Currency ### Delete Currency ### Add Payment Mode From 17463835f9c1a0d1caa4f44bcd93a8c2318dc110 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:47:20 +0200 Subject: [PATCH 37/46] describe edit currency --- docs/dev.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index bcd890711..56aa67290 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1845,6 +1845,18 @@ Each bill created with this method will have the tile `/currency/` +* Parameters: + * `name`: New name of the currency. + * `rate`: New exchange rate of the currency. +* Return: +* Errors: + * If you don't have the permissions to manage currencies, `{"message": "You are not allowed to manage currencies"}`, with code 401. + * If the `` doesn't match an existing currency, `{"message": "This project have no such currency"}`, with code 400. + * If `name` is empty or if the exchange rate is 0, `{"message": "Incorrect field values"}`, with code 400. + ### Delete Currency ### Add Payment Mode ### Edit Payment Mode From 46dae143d475db2409eae07cf6d468ca1429fd71 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:47:34 +0200 Subject: [PATCH 38/46] describe delete currency --- docs/dev.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 56aa67290..fc347e55c 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1858,6 +1858,14 @@ Each bill created with this method will have the tile `/currency/` +* Return: The ID of the deleted currency (same as passed in the URL) +* Errors: + * If you don't have the permissions to manage currencies, `{"message": "You are not allowed to manage currencies"}`, with code 401. + * If the `` doesn't match an existing currency, `{"message": "Not found"}`, with code 400. + ### Add Payment Mode ### Edit Payment Mode ### Delete Payment Mode From 4ae785b2659323c3f9450fd486ca4caae2f135ad Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:47:52 +0200 Subject: [PATCH 39/46] describe add payment mode --- docs/dev.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index fc347e55c..516f40968 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1867,6 +1867,25 @@ Each bill created with this method will have the tile `` doesn't match an existing currency, `{"message": "Not found"}`, with code 400. ### Add Payment Mode +* Availability: Logged in and Anonymous requests +* Method: POST +* Endpoint: `/paymentmode` +* Parameters: + * `name`: Name of the new payment mode (mandatory) + * `icon`: The icon of the payment mode, as a string (optional). + * `color`: Color of the payment mode (format `#RRGGBB`). Any text will be accepted and stored as-is, but it will just not be possible to display it, it will default to black on the official Cospend web app (optional). + * `order`: Which position should the payment mode have when sorting is manual (default 0); **Only available on anonymous endpoint** (optionlal) +* Return: The ID of the newly created payment mode, an integer. +* Example usage: + ```console + ~$ curl -s -X POST \ + --data-urlencode 'color=#FF0000' \ + --data-urlencode 'name=MyAPIPaymentMode' \ + --data-urlencode 'icon=💯' \ + -u 'johndoe:mypassword' \ + 'https://mynextcloud.org/index.php/apps/cospend/api-priv/projects/my-first-project/paymentmode' + 31 + ``` ### Edit Payment Mode ### Delete Payment Mode ### Add Category From edffaed7422cb6e762520e2aaf183a59e7a0ca19 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:48:11 +0200 Subject: [PATCH 40/46] describe edit payment mode --- docs/dev.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 516f40968..b75e7003c 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1887,6 +1887,42 @@ Each bill created with this method will have the tile `/paymentmode/` +* Parameters: + * `name`: Name of the new payment mode (mandatory) + * `icon`: The icon of the payment mode, as a string (optional). + * `color`: Color of the icon (format `#RRGGBB`). + +* Return: The whole new object. Roughly the same as in [Get project info](#get-project-info), except that `order` is not present, but instead `project_id` is returned. + * `name` [string] + * `icon` [string] + * `color` [string] + * `id` [integer] + * `projectid` [string] + * `old_id` [string] +* Errors: + * If the `` is not a valid payment mode ID, `{"message": "This project has no such payment mode"}`, with code 400 + * If `name` is not specified, `{"message": "Incorrect field value"}` with code 400. +* Example usage: + ```console + ~$ curl -X PUT \ + --data-urlencode 'name=My first edited payment mode'\ + -u 'johndow:mypassword' \ + 'https://mynextcloud.org/index.php/apps/cospend/api-priv/projects/my-first-project/paymentmode/32 + + { + "name": "My first edited payment mode", + "icon": "", + "color": null, + "id": 32, + "projectid": "my-first-project", + "old_id": null + } + ``` + ### Delete Payment Mode ### Add Category ### Edit Category From 5b1e8d7408b0173d3911bc2a79040d95451ec682 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:48:31 +0200 Subject: [PATCH 41/46] describe delete payment mode --- docs/dev.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index b75e7003c..c8849949d 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1924,6 +1924,13 @@ Edit a payment mode. The name is mandatory, while other fields are optional; how ``` ### Delete Payment Mode +* Availability: Logged in and Anonymous requests +* Method: DELETE +* Endpoint: `/paymentmode/` +* Return: ``, the ID of the deleted payment mode (same as provided), as an integer. +* Errors: + * If `` doesn't match any existing payment mode, `{"message": "Not found"}` with code 400 + ### Add Category ### Edit Category ### Delete Category \ No newline at end of file From a533473a8fb0d25116a511575779622443c60505 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:48:51 +0200 Subject: [PATCH 42/46] describe add category --- docs/dev.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index c8849949d..643d9fe81 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1932,5 +1932,26 @@ Edit a payment mode. The name is mandatory, while other fields are optional; how * If `` doesn't match any existing payment mode, `{"message": "Not found"}` with code 400 ### Add Category +* Availability: Logged in and Anonymous requests +* Method: POST +* Endpoint: `/category` +* Parameters: + * `name`: Name of the new category (mandatory) + * `icon`: The icon of the category, as a string (optional). + * `color`: Color of the category (format `#RRGGBB`). Any text will be accepted and stored as-is, but it will just not be possible to display it, it will default to black on the official Cospend web app (optional). + * `order`: Which position should the category have when sorting is manual (default 0); **Only available on anonymous endpoint** (optionlal) + +* Return: The ID of the newly created category, an integer. +* Example usage: + ```console + ~$ curl -s -X POST \ + --data-urlencode 'color=#DEAA12' \ + --data-urlencode 'name=A Nice Category' \ + --data-urlencode 'icon=💯' \ + -u 'johndoe:mypassword' \ + 'https://mynextcloud.org/index.php/apps/cospend/api-priv/projects/my-first-project/category' + 57 + ``` + ### Edit Category ### Delete Category \ No newline at end of file From 059af2bb7f44fb071e90dd552ef50018cd945ac6 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:49:29 +0200 Subject: [PATCH 43/46] describe edit category --- docs/dev.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/docs/dev.md b/docs/dev.md index 643d9fe81..40675fddc 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1954,4 +1954,40 @@ Edit a payment mode. The name is mandatory, while other fields are optional; how ``` ### Edit Category +Edit a payment mode. The name is mandatory, while other fields are optional; however non-used fields will delete the information. So you should specify all fields you don't intend to delete, even if it means re-specifying the same fields as when creating. +* Availability: Logged in and Anonymous requests +* Method: PUT +* Endpoint: `/category/` +* Parameters: + * `name`: Name of the new payment mode (mandatory) + * `icon`: The icon of the payment mode, as a string (optional). + * `color`: Color of the icon (format `#RRGGBB`). + +* Return: The whole new object. Roughly the same as in [Get project info](#get-project-info), except that `order` is not present, but instead `project_id` is returned. + * `name` [string] + * `icon` [string] + * `color` [string] + * `id` [integer] + * `projectid` [string] + * `old_id` [string] +* Errors: + * If the `` is not a valid category ID, `{"message": "This project has no such payment mode"}`, with code 400 + * If `name` is not specified, `{"message": "Incorrect field value"}` with code 400. +* Example usage: + ```console + ~$ curl -X PUT \ + --data-urlencode 'name=Edited category'\ + --data-urlencode 'color=#aabbcc'\ + -u 'johndoe:mypassword' \ + 'https://mynextcloud.org/index.php/apps/cospend/api-priv/projects/my-first-project/category/57' + + { + "name": "Edited category", + "icon": "", + "color": "#aabbcc", + "id": 57, + "projectid": "my-first-project" + } + ``` + ### Delete Category \ No newline at end of file From 0eb89bf5c8c1bc0208c2a55189eea35dc005add2 Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:49:41 +0200 Subject: [PATCH 44/46] describe delete category --- docs/dev.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/dev.md b/docs/dev.md index 40675fddc..cfcb3c9e0 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -1990,4 +1990,10 @@ Edit a payment mode. The name is mandatory, while other fields are optional; how } ``` -### Delete Category \ No newline at end of file +### Delete Category +* Availability: Logged in and Anonymous requests +* Method: DELETE +* Endpoint: `/category/` +* Return: ``, the ID of the deleted category (same as provided), as an integer. +* Errors: + * If `` doesn't match any existing category, `{"message": "Not found"}` with code 400 From 275530ae1524db93c1d37d50ae307a97dd3e325e Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:50:00 +0200 Subject: [PATCH 45/46] update cheatsheet --- docs/dev.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/dev.md b/docs/dev.md index cfcb3c9e0..2bbf2f7b6 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -292,20 +292,23 @@ The core part of the endpoint (`/api/projects// | -------------------------------------------------- | :------------------------------------------------------------ | :----- | ---------------- | | [Ping ](#ping ) | `/api/ping` | GET | **Logged** | | [Create Project ](#create-project ) | `/api/projects` (anonymous),
`/api-priv/projects` (logged) | POST | Anonymous/Logged | -| [Get Project Info ](#get-project-info ) | `/` | GET | Anonymous/Logged | -| [Set Project Info ](#set-project-info ) | `/` | PUT | Anonymous/Logged | -| [Delete project ](#delete-project ) | `/` | DELETE | Anonymous/Logged | +| [Get Project Info ](#get-project-info ) | `` | GET | Anonymous/Logged | +| [Set Project Info ](#set-project-info ) | `` | PUT | Anonymous/Logged | +| [Delete project ](#delete-project ) | `` | DELETE | Anonymous/Logged | | [Get Members ](#get-members ) | `/members` | GET | Anonymous/Logged | | [Add Member ](#add-member ) | `/members` | POST | Anonymous/Logged | | [Add Member V2 ](#add-member-v2 ) | `/apiv2/projects///members` | POST | **Anonymous** | | [Edit Member ](#edit-member ) | `/members/` | PUT | Anonymous/Logged | | [Delete Member ](#delete-member ) | `/members/` | DELETE | Anonymous/Logged | -| [Get Bills ](#get-bills ) | `/bills` | GET | Anonymous/Logged | +| [Get Bills (logged in) ](#get-bills-logged-in ) | `/bills` | GET | **Logged** | +| [Get Bills (anonymous) ](#get-bills-anonymous ) | `/bills` | GET | **Anonymous** | | [Get Bills V2 ](#get-bills-v2 ) | `/apiv2/projects///bills` | GET | **Anonymous** | | [Get Bills V3 ](#get-bills-v3 ) | `/apiv3/projects///bills` | GET | **Anonymous** | | [Add Bill ](#add-bill ) | `/bills` | POST | Anonymous/Logged | | [Edit Bill ](#edit-bill ) | `/bills/` | PUT | Anonymous/Logged | +| [Edit Bills ](#edit-bills ) | `/bills` | PUT | **Anonymous** | | [Delete Bill ](#delete-bill ) | `/bills/` | DELETE | Anonymous/Logged | +| [Delete Bills ](#delete-bills ) | `/bills` | DELETE | **Anonymous** | | [Get Project Statistics](#get-project-statistics ) | `/statistics` | GET | Anonymous/Logged | | [Get Project Settlement](#get-project-settlement ) | `/settle` | GET | Anonymous/Logged | | [Auto Settlement ](#auto-settlement ) | `/autosettlement` | GET | Anonymous/Logged | @@ -315,7 +318,7 @@ The core part of the endpoint (`/api/projects// | [Add Payment Mode ](#add-payment-mode ) | `/paymentmode` | POST | Anonymous/Logged | | [Edit Payment Mode ](#edit-payment-mode ) | `/paymentmode/` | PUT | Anonymous/Logged | | [Delete Payment Mode ](#delete-payment-mode ) | `/paymentmode/` | DELETE | Anonymous/Logged | -| [Add Category ](#add-category ) | `/category/` | POST | Anonymous/Logged | +| [Add Category ](#add-category ) | `/category` | POST | Anonymous/Logged | | [Edit Category ](#edit-category ) | `/category/` | PUT | Anonymous/Logged | | [Delete Category ](#delete-category ) | `/category/` | DELETE | Anonymous/Logged | From 0a62eeb1682135a4fecfd83bd6d045a7c2e2cf3c Mon Sep 17 00:00:00 2001 From: Olivier Cloux Date: Mon, 24 Apr 2023 18:51:04 +0200 Subject: [PATCH 46/46] update ToC --- docs/dev.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/dev.md b/docs/dev.md index 2bbf2f7b6..829e279f1 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -10,6 +10,7 @@ - [Using the credentials](#using-the-credentials) - [Trying](#trying-1) - [Specifications](#specifications) + - [Cheatsheet/quick access](#cheatsheetquick-access) - [Additional details](#additional-details) - [A note about errors](#a-note-about-errors) - [A note about access levels](#a-note-about-access-levels) @@ -33,9 +34,10 @@ - [Get Bills V3](#get-bills-v3) - [Add Bill](#add-bill) - [Edit Bill](#edit-bill) + - [Edit Bills](#edit-bills) - [Delete Bill](#delete-bill) + - [Delete Bills](#delete-bills) - [Get Project Statistics](#get-project-statistics) - - [Get Project Settlement](#get-project-settlement) - [Auto Settlement](#auto-settlement) - [Add Currency](#add-currency) - [Edit Currency](#edit-currency) @@ -93,8 +95,6 @@ This assumes you already have a project created, and want to use your API on spe If you use this method, your API path will have the following shape: `/api/projects///` #### Get the `` - - Go to the project settings in the UI, open the Sharing tab, and create a share link. Your link should look something like this: `https://mynextcloud.org/apps/cospend/s/ba3355eaecc6254ad1755fa8e7cdf54a)` @@ -287,6 +287,7 @@ The core part of the endpoint (`/api/projects// | `/api/ping` | `https://mynextcloud.org/index.php/apps/cospend/api/ping` | | `/bills` | *`https://mynextcloud.org/index.php/apps/cospend/api/projects///bills`
*`https://mynextcloud.org/index.php/apps/cospend/api-priv/projects//bills` | +### Cheatsheet/quick access | Name | Endpoint | Method | Anonymous/Logged | | -------------------------------------------------- | :------------------------------------------------------------ | :----- | ---------------- |