diff --git a/appinfo/info.xml b/appinfo/info.xml index 70308697..075a1749 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -32,9 +32,6 @@ OCA\Cospend\Command\ExportProject OCA\Cospend\Command\DeleteBills - - OCA\Cospend\Settings\Admin - OCA\Cospend\Activity\Setting diff --git a/appinfo/routes.php b/appinfo/routes.php index d072782c..661e8fce 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -27,7 +27,6 @@ return [ ['name' => 'utils#getOptionsValues', 'url' => '/option-values', 'verb' => 'GET'], ['name' => 'utils#saveOptionValue', 'url' => '/option-value', 'verb' => 'PUT'], - ['name' => 'utils#setAllowAnonymousCreation', 'url' => '/allow-anonymous-creation', 'verb' => 'PUT'], // OLD API for client using guest access (projectId + password) or public link (token + optional password) ['name' => 'oldApi#preflighted_cors', 'url' => '/api/{path}', 'verb' => 'OPTIONS', 'requirements' => ['path' => '.+']], diff --git a/css/admin.css b/css/admin.css deleted file mode 100644 index b9081d00..00000000 --- a/css/admin.css +++ /dev/null @@ -1,4 +0,0 @@ -label[for=allowAnonymousCreation] { - line-height: 40px; - vertical-align: top; -} diff --git a/docs/user.md b/docs/user.md index e4faf142..b62af906 100644 --- a/docs/user.md +++ b/docs/user.md @@ -3,14 +3,13 @@ * [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) +* [Create a project](#s2) + * [Shared access](#s2-1) + * [Share link permissions](#s2-1-1) +* [Create a member](#s3) +* [Create a bill](#s4) * [Project statistics](#s5) * [Settle the project](#s6) -* [Anonymous project creation](#s7) # Introduction @@ -21,25 +20,34 @@ Things you should know: ## What is a project :paperclip: ? -A project contains members and bills. A project is a way to manage what is spent in a group of persons. It's a way to know who paid what for whom and when and who owes how much to whom. +A project contains members and bills. A project is a way to manage what is spent in a group of persons. +It's a way to know who paid what for whom and when and who owes how much to the group. +Debts are not personal, a member who has a debt in the group (negative balance) can pay anyone in the group +to bring his/her balance back to zero and leave the group. This will have an effect on other's balances. ## What are balances :balance_scale: ? -The balance value represents the situation of a member in a project. A positive balance indicates that the member payed more for the group than the grouped payed for them. By keeping an eye on the balance, one can stop taking care of exactly how much they owe to each project member. +The balance value represents the situation of a member in a project. +A positive balance indicates that the member payed more for the group than the grouped payed for them. +By keeping an eye on the balance, one can stop taking care of exactly how much they owe to each project member. -If member A has a negative balance, -10 for example, it just means A owes 10$ to the group. Any payment of 10$ to the group (or a sub part of the group) will bring the balance back to zero. It does not matter who it was payed for. +If member A has a negative balance, -10 for example, it just means A owes 10$ to the group. +Any payment of 10$ to the group (or a sub part of the group) will bring the balance back to zero. +It does not matter who it was payed for. -All those actions have the same effect on member A's balance => bring it up: +All those actions have the same effect on the member A's balance => Make it raise of 10: -1. Member A pays 10$ to member B -2. Member A pays 5$ to member B and 5$ to member C -3. Member A pays a 10$ cake for the whole group +0. Member A pays 20$ for a cake that is eaten by A and B (one bill payed by A with A and B as owers) +1. Member A pays 10$ to member B (one bill payed by A with B as ower) +2. Member A pays 5$ to member B and 5$ to member C (one bill payed by A with B as ower, another bill payed by A with C as ower) +3. Member A pays a 15$ cake eaten by A, B and C (on bill payed by A with A, B and C as owers) The only difference is the effect on other members balances: +0. -10 in B's balance 1. -10 in B's balance 2. -5 in B's balance and -5 in C's balance -3. -1 in each member's balance (if there are 10 members in the project) +3. -5 in each ower's balance ## What is a member :ok_woman: ? @@ -57,54 +65,43 @@ It seems simple enough to do it intuitively with a small example but it gets rea A bill is a spending from one member which concerns one or more members in the project. A bill is defined by a name, an amount, a payer, a date and a list of owers. -# Add a project +# Create a project -When you first visit the app, there is no project yet. Well let's create one! +When you first visit the app, there is no project yet. -A project is defined by an ID, a name, a contact email address and a password. When you "add" a project. When creating a project from the web interface, the user's email address will be used as contact email address. +A project is defined by an ID and a name. -## Guest access +Cospend and SplitWise CSV project files can be imported in Cospend. -The project ID and password are important to provide access to people who don't have an account on the Nextcloud instance. They can visit the "Guest access link", enter the project ID and the password and have access to the project just like a regular user. +## Shared access -This link looks like `https://YOUR.NEXTCLOUD.ORG/index.php/apps/cospend/login` or `https://YOUR.NEXTCLOUD.ORG/index.php/apps/cospend/loginproject/PROJECT_ID` . Just put the correct values for YOUR.NEXTCLOUD.ORG and PROJECT_ID and you're good to go. +Cospend lets you share your projects with users, groups and circles. +It is also possible to create public share links to share a project with people who don't have an account on your Nextcloud instance. +Public share links can be password protected. -This link is accessible in projects context menu => "guest link". +## Share link permissions -## Guest access permissions +There are 4 permission levels for shared links: -There are 4 levels of guest link permissions : +* Viewer: read-only access +* Participant: can create, modify or delete bills +* Maintainer: same as participant + can create, modify, disable or delete a project member + can create, modify and delete categories, payment modes and currencies +* Admin: same as maintainer + can rename and delete project + can toggle bill deletion and auto-export + can modify categories or payment modes order -* Viewer : read-only access -* Participant : can create, modify or delete bills -* Maintainer : same as participant, + can create, modify, deactivate or delete a project member, and can create, modify and delete categories and currencies -* Admin : same as maintainer, + can rename and delete project, can enable/disable bill deletion and auto-export, can modify categories order - -# Add a member +# Create a member This is pretty simple. Press "+" in the project drop-down menu and then press "add a member". Just provide a user name and that's it. Member is added with a weight of 1 and is activated by default. -# Add a bill +# Create a bill -Pretty simple too. Press the "new bill" button. Fill all fields and the bill will be saved automatically. +Pretty simple too. Press the "new bill" button. Fill all fields and press the "Save bill" button. # Project statistics -Well does it need explanations ? +The filters on top of the statistics page apply to all the statistics charts and tables. # Settle the project -This feature shows you a possible way to settle the bills and put everyone's balance back to 0. - -# Anonymous project creation - -There is a Cospend setting called "anonymous project creation" which is only accessible to Nextcloud admins in "additional settings". - -This feature aims to reproduce the behaviour of IHateMoney in which there are no users, so there is a setting to allow project creation without being authenticated while your create the project. - -If your Nextcloud admin enabled "anonymous project creation", then it is possible to create projects from a client (like [MoneyBuster](https://gitlab.com/eneiluj/moneybuster)) without being a Nextcloud user. An "anonymous" project will not be associated with any Nextcloud user and will therefore NOT appear in any user's Cospend project list. The only ways to access such projects are: - -* with the [Cospend public login web page (also called guest access link)](#guest-access). -* with a client (like [MoneyBuster](https://gitlab.com/eneiluj/moneybuster)) +This feature gives you an optimal project settlement/reimbursement plan to put everyone's balance back to 0. diff --git a/lib/Controller/OldApiController.php b/lib/Controller/OldApiController.php index 420277df..50bfc45b 100644 --- a/lib/Controller/OldApiController.php +++ b/lib/Controller/OldApiController.php @@ -51,8 +51,6 @@ class OldApiController extends ApiController { ); } - // TODO get rid of anonymous project creation stuff (toggle and routes/contr methods) - #[NoAdminRequired] #[CORS] #[NoCSRFRequired] diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php index deb2d845..95dcb7af 100644 --- a/lib/Controller/PageController.php +++ b/lib/Controller/PageController.php @@ -25,7 +25,6 @@ use OCP\AppFramework\Http\NotFoundResponse; use OCP\AppFramework\Http\Response; use OCP\AppFramework\Services\IInitialState; use OCP\Collaboration\Reference\RenderReferenceEvent; -use OCP\DB\Exception; use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; use OCP\IL10N; diff --git a/lib/Controller/UtilsController.php b/lib/Controller/UtilsController.php index 89385bd9..5fd06a69 100644 --- a/lib/Controller/UtilsController.php +++ b/lib/Controller/UtilsController.php @@ -11,8 +11,9 @@ namespace OCA\Cospend\Controller; +use OCA\Cospend\AppInfo\Application; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\IConfig; -use OCP\AppFramework\Http\ContentSecurityPolicy; use OCP\IRequest; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\Controller; @@ -28,75 +29,43 @@ class UtilsController extends Controller { parent::__construct($appName, $request); } - /** - * set global point quota - */ - public function setAllowAnonymousCreation($allow): DataResponse { - $this->config->setAppValue('cospend', 'allowAnonymousCreation', $allow); - $response = new DataResponse(['done' => '1']); - $csp = new ContentSecurityPolicy(); - $csp->addAllowedImageDomain('*') - ->addAllowedMediaDomain('*') - ->addAllowedConnectDomain('*'); - $response->setContentSecurityPolicy($csp); - return $response; - } - /** * Delete user options - * @NoAdminRequired */ + #[NoAdminRequired] public function deleteOptionsValues(): DataResponse { - $keys = $this->config->getUserKeys($this->userId, 'cospend'); + $keys = $this->config->getUserKeys($this->userId, Application::APP_ID); foreach ($keys as $key) { - $this->config->deleteUserValue($this->userId, 'cospend', $key); + $this->config->deleteUserValue($this->userId, Application::APP_ID, $key); } - $response = new DataResponse(['done' => 1]); - $csp = new ContentSecurityPolicy(); - $csp->addAllowedImageDomain('*') - ->addAllowedMediaDomain('*') - ->addAllowedConnectDomain('*'); - $response->setContentSecurityPolicy($csp); - return $response; + return new DataResponse(['done' => 1]); } /** * Save options values to the DB for current user - * @NoAdminRequired */ + #[NoAdminRequired] public function saveOptionValue($options): DataResponse { foreach ($options as $key => $value) { - $this->config->setUserValue($this->userId, 'cospend', $key, $value); + $this->config->setUserValue($this->userId, Application::APP_ID, $key, $value); } - $response = new DataResponse(['done' => true]); - $csp = new ContentSecurityPolicy(); - $csp->addAllowedImageDomain('*') - ->addAllowedMediaDomain('*') - ->addAllowedConnectDomain('*'); - $response->setContentSecurityPolicy($csp); - return $response; + return new DataResponse(['done' => true]); } /** * get options values from the config for current user - * @NoAdminRequired */ + #[NoAdminRequired] public function getOptionsValues(): DataResponse { $ov = array(); - $keys = $this->config->getUserKeys($this->userId, 'cospend'); + $keys = $this->config->getUserKeys($this->userId, Application::APP_ID); foreach ($keys as $key) { - $value = $this->config->getUserValue($this->userId, 'cospend', $key); + $value = $this->config->getUserValue($this->userId, Application::APP_ID, $key); $ov[$key] = $value; } - $response = new DataResponse(['values' => $ov]); - $csp = new ContentSecurityPolicy(); - $csp->addAllowedImageDomain('*') - ->addAllowedMediaDomain('*') - ->addAllowedConnectDomain('*'); - $response->setContentSecurityPolicy($csp); - return $response; + return new DataResponse(['values' => $ov]); } } diff --git a/lib/Settings/Admin.php b/lib/Settings/Admin.php deleted file mode 100644 index 823e66cf..00000000 --- a/lib/Settings/Admin.php +++ /dev/null @@ -1,39 +0,0 @@ -config->getAppValue('cospend', 'allowAnonymousCreation'); - - $parameters = [ - 'allowAnonymousCreation' => $allow - ]; - return new TemplateResponse('cospend', 'admin', $parameters, ''); - } - - /** - * @inheritDoc - */ - public function getSection(): string { - return 'additional'; - } - - /** - * @inheritDoc - */ - public function getPriority(): int { - return 5; - } -} diff --git a/src/adminSettings.js b/src/adminSettings.js deleted file mode 100644 index 64f300f4..00000000 --- a/src/adminSettings.js +++ /dev/null @@ -1,13 +0,0 @@ -import { linkTo } from '@nextcloud/router' -import { getRequestToken } from '@nextcloud/auth' - -__webpack_nonce__ = btoa(getRequestToken()) // eslint-disable-line -__webpack_public_path__ = linkTo('cospend', 'js/') // eslint-disable-line - -document.addEventListener('DOMContentLoaded', async (event) => { - const { setAllowAnonymousCreation } = await import(/* webpackChunkName: "admin-settings-lazy" */'./network.js') - const anonyCheck = document.getElementById('allowAnonymousCreation') - anonyCheck.addEventListener('change', (event) => { - setAllowAnonymousCreation(event.target.checked ? '1' : '0') - }) -}) diff --git a/src/network.js b/src/network.js index 5ffb88d9..5b423be0 100644 --- a/src/network.js +++ b/src/network.js @@ -31,25 +31,6 @@ export function saveOptionValue(optionValues) { } } -export function setAllowAnonymousCreation(val) { - const url = generateUrl('/apps/cospend/allow-anonymous-creation') - const req = { - allow: val, - } - axios.put(url, req) - .then((response) => { - showSuccess( - t('cospend', 'Cospend setting saved'), - ) - }) - .catch((error) => { - showError( - t('cospend', 'Failed to save Cospend setting'), - ) - console.debug(error) - }) -} - export function exportProject(filename, projectId, projectName) { const req = { params: { diff --git a/templates/admin.php b/templates/admin.php deleted file mode 100644 index 2b7bddc5..00000000 --- a/templates/admin.php +++ /dev/null @@ -1,20 +0,0 @@ - - -
-

t('Cospend')); ?>

-

t('Allow guests to create projects')); ?>

-
-
-
-
-
- - /> - -
-
diff --git a/webpack.js b/webpack.js index 859def84..5b62b08f 100644 --- a/webpack.js +++ b/webpack.js @@ -15,7 +15,6 @@ webpackConfig.stats = { const appId = 'cospend' webpackConfig.entry = { - adminSettings: { import: path.join(__dirname, 'src', 'adminSettings.js'), filename: appId + '-adminSettings.js' }, main: { import: path.join(__dirname, 'src', 'main.js'), filename: appId + '-main.js' }, sharePassword: { import: path.join(__dirname, 'src', 'sharePassword.js'), filename: appId + '-sharePassword.js' }, dashboard: { import: path.join(__dirname, 'src', 'dashboard.js'), filename: appId + '-dashboard.js' },