Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

code doctor test #55

Open
wants to merge 378 commits into
base: initial_commit
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 250 commits
Commits
Show all changes
378 commits
Select commit Hold shift + click to select a range
fa5ec22
Make sure pip dependencies are up to date.
cb109 Jun 21, 2018
87a5967
Extend script.
cb109 Jun 21, 2018
21fd6b2
Resurrect main entry view.
cb109 Jun 21, 2018
7f2536e
Update script.
cb109 Jun 21, 2018
c5aec01
Extend collective stats.
cb109 Jun 22, 2018
66bbd64
Allow editing avatar url on gravataaars.com directly.
cb109 Jun 22, 2018
39dd4d9
Fix wrong length used.
cb109 Jun 22, 2018
31b05cb
Fix name.
cb109 Jun 22, 2018
25b942b
Make sure staticfiles work in prod and dev, both served from /static/.
cb109 Jun 22, 2018
fc0a523
Add note about broken service worker.
cb109 Jun 22, 2018
d40f11f
Hide some stats, too confusing.
cb109 Jun 22, 2018
bfdd6d9
Use ip instead of localhost name.
cb109 Jun 22, 2018
c68df19
Fix icon not prefixed with /static/.
cb109 Jun 23, 2018
a6a7d33
Improve login spacing for mobile.
cb109 Jun 23, 2018
88d1ec3
Use a clipped drawer on mobile, to make it easier to close it.
cb109 Jun 23, 2018
0047882
Add shortcut btn to add entry. Tweak drawer layout.
cb109 Jun 23, 2018
6c634e4
Tweak admin field order.
cb109 Jun 23, 2018
a8cd981
Fix collective data not updated on page reload.
cb109 Jun 23, 2018
8689d85
Make sure current member is on top of list in dropdown.
cb109 Jun 23, 2018
c046bdf
Use a more pleasant blue as primary.
cb109 Jun 23, 2018
e15e529
Show creation date and no. of members in drawer.
cb109 Jun 23, 2018
9af525b
Write down some things in the readme.
cb109 Jun 23, 2018
3dec664
Update example configs for systemd and nginx.
cb109 Jun 23, 2018
9065d39
Merge branch 'develop'
cb109 Jun 23, 2018
a761a14
Add endpoint to query backend version.
cb109 Jun 23, 2018
5b46744
Add gunicorn to dependencies.
cb109 Jun 23, 2018
4368b65
Stub a widget to add a reaction to a transfer.
cb109 Jun 23, 2018
ad96073
Update manifest theme color.
cb109 Jun 23, 2018
85b943a
Add a generic Reaction model and link it to Purchase and Liquidation.
cb109 Jun 23, 2018
61c30e6
Serialize Reactions for transfers.
cb109 Jun 24, 2018
ae04708
Extract reactions and actionbar into reusable components.
cb109 Jun 24, 2018
4625d10
Implement adding Reactions.
cb109 Jun 24, 2018
d20abc1
Make sure we can only have one reaction per member, but we can change…
cb109 Jun 24, 2018
4aa885d
Merge branch 'reactions' into develop
cb109 Jun 24, 2018
24163a4
Add explanation and move buttons to top for better UX on mobile.
cb109 Jun 24, 2018
899837c
Make it hopefully less confusing which mode is chosen.
cb109 Jun 24, 2018
3b6764f
Merge branch 'develop'
cb109 Jun 24, 2018
d5e8ee0
Expand more.
cb109 Jun 24, 2018
8f586a6
Require confirmation to logout to avoid doing so by accident.
cb109 Jun 24, 2018
e1351cb
Move ranking to main page in a separate tab.
cb109 Jun 24, 2018
490da61
Fix select widget on firefox overflowing.
cb109 Jun 24, 2018
f774f0d
Add median to stats.
cb109 Jun 24, 2018
bb590e5
Improve highlighting.
cb109 Jun 24, 2018
47d34e5
Add divider.
cb109 Jun 24, 2018
b95de87
Add a tab for the cashing up page.
cb109 Jun 24, 2018
ecb9572
Only wrap ome things in a container, e.g. not the tab buttons.
cb109 Jun 24, 2018
5093083
Fix button offset.
cb109 Jun 25, 2018
3e94cd6
Implement calculation of necessary pacyback steps for cashing-up.
cb109 Jun 25, 2018
a04057c
Avoid collecting empty paybacks.
cb109 Jun 25, 2018
3a484da
Add a simple endpoint for the cashup.
cb109 Jun 25, 2018
4ae345a
Merge paybacks for Liquidations into existing list, extend as needed.
cb109 Jun 26, 2018
c7de83b
Tweak container.
cb109 Jun 26, 2018
e8dc3a3
Add the cashup data to the serialized collective.
cb109 Jun 27, 2018
b069bc9
Allow longer usernames to wrap around.
cb109 Jun 27, 2018
7ee1055
Revert back to a vertical layout, which is nicer to use.
cb109 Jun 27, 2018
6da7ac9
Implement a list of sorted payback actions..
cb109 Jun 27, 2018
ca866ea
Ignore values below 0.01 as they and give feedback when all done.
cb109 Jun 27, 2018
aa06152
Merge branch 'cashing-up' into develop
cb109 Jun 27, 2018
13f8d83
Bump version to 2.2.0.
cb109 Jun 27, 2018
b29eaf4
Merge branch 'develop'
cb109 Jun 27, 2018
4924faf
Fix wrong expression.
cb109 Jun 27, 2018
3f11850
Merge branch 'develop'
cb109 Jun 27, 2018
14a48d0
Fix debtor/creditor roles must be swapped eventually.
cb109 Jul 3, 2018
d354263
Remove first name.
cb109 Jul 3, 2018
9c4f250
Remember visited collective urls and list them on /unknown as links.
cb109 Jul 3, 2018
ac9b7e8
Bump version to 2.3.0.
cb109 Jul 3, 2018
2887f11
Implement removal of reactions.
cb109 Jul 7, 2018
cebb002
Merge branch 'develop'
cb109 Jul 7, 2018
dc91dbb
Implement updating existing transfers.
cb109 Jul 7, 2018
66f7b3a
Bump version to 2.4.0.
cb109 Jul 7, 2018
a2db3e3
Merge branch 'edit-transfers' into develop
cb109 Jul 7, 2018
78f92a0
Update button text.
cb109 Jul 7, 2018
2398bb8
Merge branch 'develop'
cb109 Jul 7, 2018
875817e
Add screenshots to readme.
cb109 Jul 17, 2018
f7b187c
Extend readme, add license.
cb109 Jul 17, 2018
16ac724
Add demo link etc.
cb109 Jul 17, 2018
9a3fea9
Remove empty line.
cb109 Jul 17, 2018
22b6ced
Add tool links.
cb109 Jul 17, 2018
a66a490
Add DRF credit.
cb109 Jul 17, 2018
4afcbb4
Fix wording.
cb109 Jul 17, 2018
c6ef8c7
Fix typo.
cb109 Jul 18, 2018
14e4737
Add travis file.
cb109 Jul 18, 2018
3b631a5
Run pytest with higher verbosity.
cb109 Jul 18, 2018
fff4d0a
Add travis badge to readme.
cb109 Jul 18, 2018
b1080a2
Implement a simple search field for transfers.
cb109 Jul 21, 2018
675cc25
Bump version to 2.5.0.
cb109 Jul 21, 2018
1ae7b1b
Tweak hint and placeholder.
cb109 Jul 21, 2018
b0ee89a
Tweak translation.
cb109 Jul 21, 2018
0f535eb
Preselect debtor in dialog if there are only two members.
cb109 Jul 21, 2018
6a775c4
Tweak translation.
cb109 Jul 21, 2018
4bf50c5
Merge branch 'develop'
cb109 Jul 21, 2018
671cbc1
Fix wrongly comparing id vs object.
cb109 Jul 21, 2018
92cbb5e
Bump version to 2.5.1.
cb109 Jul 21, 2018
a77f16c
Merge branch 'develop'
cb109 Jul 21, 2018
02e136f
Show average value as default, allowing to toggle to median as an opt…
cb109 Mar 14, 2019
7d0abf7
Swap toolbar button with a bottom-right FAB.
cb109 Mar 14, 2019
f08a396
Bump version to 2.6.0.
cb109 Mar 14, 2019
6cc0d33
Merge branch 'develop'
cb109 Mar 14, 2019
304dc4b
Hide button on login page.
cb109 Mar 15, 2019
f4855b6
Merge branch 'develop'
cb109 Mar 15, 2019
b57e358
Fixed Exists-Check, Removed redundant regex
Zarathustra2 Jul 19, 2019
7a72780
Fixed exists() call
Zarathustra2 Jul 19, 2019
edc78d3
Change spelling from payed to paid
hackebrot Aug 20, 2019
01499ae
Merge pull request #18 from hackebrot/update-payed-for-spelling
cb109 Aug 23, 2019
19a2854
Merge pull request #14 from Zarathustra2/develop
cb109 Aug 30, 2019
bb6af07
Add readonly field
cb109 Sep 1, 2019
8292f5f
Add middleware to reject create/modify/delete on readonly Collectives
cb109 Sep 1, 2019
0e6be0c
Add readonly field to admin list
cb109 Sep 1, 2019
d031337
Handle endpoints (e.g. admin) that don't include a key in their url
cb109 Sep 1, 2019
3c056d8
Hide related UI for readonly Collective and show a toolbar warning
cb109 Sep 1, 2019
7af6a55
Add a basic test for the readonly_middleware
cb109 Sep 1, 2019
126ea2f
Update docstring
cb109 Sep 1, 2019
716dabd
Merge pull request #20 from cb109/feature/#19-colelctive-readonly-mode
cb109 Sep 1, 2019
2215af9
Bump version to 2.7.0
cb109 Sep 1, 2019
99925a8
Merge branch 'develop'
cb109 Sep 1, 2019
2148acd
Update all python pip packages to latest versions
cb109 Sep 4, 2019
24a4a40
Merge branch 'feature/#16-update-django-to-fix-sqlite-testruns' into …
cb109 Sep 4, 2019
c6bff13
Patch price/amount values to fix test
cb109 Sep 4, 2019
849c202
Add django-filer and django-whitenoise so we can upload and host images
cb109 Sep 4, 2019
1093560
Fix filer images not shown as static urlpatterns for media is missing
cb109 Sep 4, 2019
3a720be
Update readme
cb109 Sep 4, 2019
7f3cc19
Ignore public/media/
cb109 Sep 4, 2019
4a7bb7d
Merge branch 'feature/#22-host-generated-avatar-images' into develop
cb109 Sep 4, 2019
2abd6ff
Show 'Edit on getavataaars' link only for relevant urls
cb109 Sep 4, 2019
b77b12d
Commit unfinished work to have unique urls per collective
cb109 Sep 1, 2019
7a67951
Go to unknown page after logout to pick a new collective
cb109 Sep 4, 2019
34b7c06
Add some padding, looks less cluttered
cb109 Sep 4, 2019
0764073
Fix initial vue warnings when selectedMember not yet available
cb109 Sep 4, 2019
2ca5d34
Remember visited collective names to display in unknown page
cb109 Sep 4, 2019
998452c
Merge pull request #24 from cb109/feature/#6-collective-uuid-in-url
cb109 Sep 4, 2019
731552b
Add migration related to django-money update
cb109 Sep 4, 2019
b8fffa1
Add optional paypal_me_username field to profile model
cb109 Sep 4, 2019
3b23bc8
Add button to open paypal.me tab in browser with correct amount
cb109 Sep 4, 2019
cfe0c99
Fix attr order
cb109 Sep 4, 2019
9d097ff
Merge pull request #25 from cb109/feature/#4-paypal.me-button-on-cashup
cb109 Sep 4, 2019
ccf6452
Update readme
cb109 Sep 4, 2019
9908797
Fix NaN shown for average price/amount when there are none yet
cb109 Sep 4, 2019
dfe9db0
Bump version to 2.8.0
cb109 Sep 4, 2019
8319ad3
Merge branch 'develop'
cb109 Sep 4, 2019
0c7b5e0
Hotfix admin media prefix so filer will load its css
cb109 Sep 4, 2019
3c1e499
Temporarily configure dev-server for remote proxying
cb109 Sep 9, 2019
67282a1
Revert "Temporarily configure dev-server for remote proxying"
cb109 Sep 9, 2019
21c8436
Prevent visiting /transfers without being logged in
cb109 Sep 9, 2019
3bae55f
Close dialog when pressing browser back-button instead of navigating
cb109 Sep 9, 2019
57ae716
Order members consistently by doing it serverside
cb109 Sep 11, 2019
0e1a876
Display last name in ranking if user has one
cb109 Sep 11, 2019
d6b76c3
Fix no margin between two words
cb109 Sep 11, 2019
8f891e5
Remove unused name attributes on page components
cb109 Sep 11, 2019
26aface
Fix typo
cb109 Sep 11, 2019
ef06865
Redirect to login when possible on failed route guard auth check
cb109 Sep 11, 2019
30f175c
Add back-button to login screen to allow easy switch between Collectives
cb109 Sep 11, 2019
cbc6982
Update translations
cb109 Sep 11, 2019
615f043
Make icon and text less oversized
cb109 Sep 11, 2019
f07c6e6
Fix links to previous Collectives not using vue-router
cb109 Sep 11, 2019
4514ae0
Avoid flickering display of dialog overlay after login
cb109 Sep 11, 2019
1597c12
Try to avoid pagination button overflow
cb109 Sep 11, 2019
3a08610
Add version indicator on unknown-page
cb109 Sep 11, 2019
050c401
Bump version to 2.9.0
cb109 Sep 11, 2019
b655098
Merge branch 'develop'
cb109 Sep 11, 2019
946319a
Add example script on how to modify all avatar_image_urls
cb109 Sep 12, 2019
d42d9c6
Improve layout of create/edit-transfer dialog
cb109 Sep 12, 2019
64442b0
Use a slightl darker primary color
cb109 Sep 12, 2019
9c3b976
Fix swap-button offsets. Tweak translation to fit into mobile button
cb109 Sep 12, 2019
c4a4903
Add optional logo_image field to Collective
cb109 Sep 12, 2019
267f63c
Display Collective.logo_image as toolbar side icon when available
cb109 Sep 12, 2019
bf9e6ab
Change primary color again
cb109 Sep 12, 2019
015dd61
Bump version to 2.10.0
cb109 Sep 12, 2019
335a419
Merge branch 'develop'
cb109 Sep 12, 2019
43876d8
Fix pagination controls wider than screen width on mobile
cb109 Sep 12, 2019
1ae0d6c
Bump version to 2.10.1
cb109 Sep 12, 2019
ec3b2d0
Merge branch 'develop'
cb109 Sep 12, 2019
8387be8
Fix color not updated in manifest file
cb109 Sep 13, 2019
01601d7
Fix PWA always logging out when launched anew
cb109 Sep 13, 2019
c1962fb
Fix attribute order
cb109 Sep 13, 2019
ebab054
Bump version to 2.10.2
cb109 Sep 13, 2019
59d4a12
Merge branch 'develop'
cb109 Sep 13, 2019
d294cbf
Remove uuid check from url and rely on localStorage instead
cb109 Sep 14, 2019
dfaa511
Bump version to 2.10.3
cb109 Sep 14, 2019
d383f72
Merge branch 'develop'
cb109 Sep 14, 2019
fe1dcb6
Fix some navigation issues by moving logic from component to router
cb109 Sep 19, 2019
bdb643b
Handle invalid routes
cb109 Sep 19, 2019
bfa5343
Bump version to 2.10.4
cb109 Sep 19, 2019
2fffffa
Merge branch 'develop'
cb109 Sep 19, 2019
4e65997
Make FAB icon size based on screen size
cb109 Sep 19, 2019
67b3ea9
Fix arrow overlapping avatar image in payback-list-tile
cb109 Sep 19, 2019
98ec5d5
Bump version to 2.10.5
cb109 Sep 19, 2019
925f3f3
Merge branch 'develop'
cb109 Sep 19, 2019
306538e
Configure tox
cb109 Sep 23, 2019
a7b2b1e
Ensure that negative transfer amounts are supported in the backend
cb109 Sep 23, 2019
0ee77cb
Add support for negative (non-zero) amount/price in API and frontend
cb109 Sep 23, 2019
f6dbf69
Merge pull request #32 from cb109/feature/#31-support-negative-purchases
cb109 Sep 23, 2019
09ed290
Fix ranking/cashup lists have no extra scroll space, thus FAB overlaps
cb109 Sep 23, 2019
f28e3bd
Bump version to 2.11.0
cb109 Sep 23, 2019
690bdd5
Merge branch 'develop'
cb109 Sep 23, 2019
d448296
Add codacy badge and fix some of its reported issues
cb109 Sep 25, 2019
9cd9d6c
Try to fix codacy issue list-item-bullet-indent
cb109 Sep 25, 2019
3a00f0a
Try and fix PWA startup memory one more time
cb109 Sep 30, 2019
387ecc2
Bump version to 2.11.1
cb109 Sep 30, 2019
7568fb8
Merge branch 'develop'
cb109 Sep 30, 2019
275a623
Another try to fix PWA startup
cb109 Sep 30, 2019
6001c5d
Bump version to 2.11.2
cb109 Sep 30, 2019
d8bf0f5
Merge branch 'develop'
cb109 Sep 30, 2019
d60cec7
Bump pillow from 6.1.0 to 6.2.0
dependabot[bot] Nov 1, 2019
b7f3151
Merge pull request #33 from cb109/dependabot/pip/pillow-6.2.0
cb109 Nov 13, 2019
ceeeced
Bump django from 2.2.5 to 2.2.8
dependabot[bot] Dec 4, 2019
a328eb0
Merge pull request #34 from cb109/dependabot/pip/django-2.2.8
cb109 Dec 8, 2019
c4da250
Bump django from 2.2.8 to 2.2.10
dependabot[bot] Feb 11, 2020
8c93b2c
Merge pull request #35 from cb109/dependabot/pip/django-2.2.10
cb109 Feb 14, 2020
2fa99f8
Ignore some more dev files
cb109 Aug 20, 2020
58eedf7
Fix some labels cutoff on firefox
cb109 Aug 20, 2020
291bbfb
Update installed npm libraries
cb109 Aug 20, 2020
827f669
Improve "tab" ui to switch between purchase and liquidation
cb109 Aug 20, 2020
b836f2c
Fix language select cutoff on FF
cb109 Aug 20, 2020
9a9741e
Rephrase 'Liquidation' as 'Transfer' in UI for better understanding
cb109 Aug 20, 2020
820e171
Bump version 2.11.2 -> 2.11.3
cb109 Aug 20, 2020
2aa0125
Merge branch 'develop'
cb109 Aug 20, 2020
cabb8e3
Fix a few css styles (missing v- prefix)
cb109 Aug 27, 2020
94b5de8
Simplify UI and fix selects not full width and weird button offset
cb109 Aug 27, 2020
e8c2814
Bump version 2.11.3 -> 2.11.4
cb109 Aug 27, 2020
43a63bb
Merge branch 'develop'
cb109 Aug 27, 2020
6ee1874
Use first_name + last_name when possible, not username
cb109 Sep 5, 2021
220ed02
Use full name in missing places in UI
cb109 Sep 5, 2021
eca25da
Merge branch 'feature/#52-username-vs-firstname' into develop
cb109 Sep 5, 2021
1415697
Use shorter names in lists so it's not as crowded with text
cb109 Sep 5, 2021
336a191
Link to app from admin list
cb109 Jul 21, 2022
0f2a72d
Improve admin convenience, run black against models.py
cb109 Jul 21, 2022
8ae6886
Wording
cb109 Sep 9, 2022
bd57d31
Add PurchaseWeight model
cb109 Sep 17, 2022
559d863
Fix typo, autoformat
cb109 Sep 17, 2022
8ac5cbc
Avoid rounding to early, keep Decimal until display
cb109 Sep 17, 2022
c6d437c
Add Purchase.weights and update Collective.stats accordingly
cb109 Sep 17, 2022
6371550
Update calc_paybacks() to consider Purchase weights
cb109 Sep 17, 2022
bad7bfd
Fix not getting member weight correctly
cb109 Sep 17, 2022
0be2f3e
Register PurchaseWeight on admin
cb109 Sep 17, 2022
d7e32e2
Mark Purchase if using weights
cb109 Sep 17, 2022
9dad01d
Implement submitting weights on Purchase UPDATE
cb109 Sep 17, 2022
7ba61bc
Add avatars to weights table
cb109 Sep 17, 2022
4cfd122
Fix can click submit button when no price specified
cb109 Sep 17, 2022
ad369b2
Fix missing margin
cb109 Sep 19, 2022
d8663e9
Fix preview based on saved price, not currently edited price
cb109 Sep 19, 2022
93d413c
Fix weights warning shown after editing without submitting
cb109 Sep 19, 2022
1cf5260
Add repayment button to quickly track those
cb109 Sep 19, 2022
da7fa77
Allow specifying weights on Purchase CREATE
cb109 Sep 19, 2022
ebbc65b
Tweak translation
cb109 Sep 19, 2022
4f9a09f
No need for base class in super() anymore
cb109 Sep 19, 2022
c8270fc
Use f-strings over .format()
cb109 Sep 19, 2022
8fd4a7b
Merge pull request #65 from cb109/feature/#64-split-purchase-by-weights
cb109 Sep 19, 2022
3daea2f
Bump version 2.11.04 -> 2.2.0
cb109 Sep 19, 2022
9cd7883
Fix version bump ->2.12.0
cb109 Sep 20, 2022
2d5653e
Add button to set all weights to specified number
cb109 Sep 22, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
.idea/
.pytest_cache/
.tox/
*.py[cod]
Activate.ps1
db.sqlite3
public/media/
public/static/
venv/
8 changes: 8 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
language: python
python:
- "3.6"
install:
- pip install pip-tools
- pip-sync
script:
- pytest -vv -s payshare/purchases/tests.py
21 changes: 21 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2018 Christoph Buelter

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
120 changes: 120 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Payshare

A web app to track shared expenses in a group of people.

[![Build Status](https://travis-ci.com/cb109/payshare.svg?branch=develop)](https://travis-ci.com/cb109/payshare)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/6a111b89f4464f3bb5eb69f08fad568e)](https://www.codacy.com/manual/cb109/payshare?utm_source=github.com&utm_medium=referral&utm_content=cb109/payshare&utm_campaign=Badge_Grade)

Payshare is the equivalent of a whiteboard in the kitchen of your shared flat where everyone writes down how much he paid for groceries, who paid the cinema ticket or pizza for whom and so on, while it does the math for you to figure out who should buy the next round.

## Demo

You can login using the password `demo` [here](https://payshare.cbuelter.de/28d7c6ad-9548-45d6-b023-b8e3b0950a44).

## License

**MIT**, see [LICENSE.txt](LICENSE.txt)

## Screenshots

![](docs/transfers.png) ![](docs/ranking.png)

![](docs/cashup.png) ![](docs/newoutlay.png)

## Terminology

- `Collective`: This is basically your shared flat, sports team, whatever
- `User`: A person that can be a member of one or more Collectives
- `Membership`: The connection of a User to a Collective
- ` Purchase`: A User bought something and the cost is shared equally in the Collective
- ` Liquidation` (named "Outlay" in the frontend): Some User gave money to another one and that debt will have to be paid back later

## Development Setup

If you want to setup and run the project yourself, follow these steps (assuming you are on a Unix OS):

### Backend

- Make sure you have Python 3.x installed
- Clone the project and `cd` into its root directory
- `$ virtualenv venv`
- `$ source venv/bin/activate`
- `$ pip install pip-tools`
- `$ pip-sync`
- `$ python manage.py migrate`
- `$ python manage.py createsuperuser`
- `$ python manage.py runserver`

### Frontend

Make sure to have ` npm` or ` yarn` installed globally

- `$ cd payshare/purchases/static/client`
- `$ yarn`/ `$ npm install`
- `$ npm run serve`

### Creating initial Data

The project currently relies on the Django admin pages to create new Collectives and Users and add Memberships between them.

Assuming your Django dev-server is running at the default port, go to:

[https://localhost:8000/admin](https://localhost:8000/admin)

- Create a Collective and set a password for it
- Create some Users (`username` is the only field that is displayed. Django requires us to set a password here, but you can just give any, it isn't used)
- Create Memberships for those Users in your Collective

The URL for your collective will be e.g. `http://localhost:8000/<collective-key>`. You can get the key from the admin pages. Send the URL (and the Collective's password of course) to everyone you want to participate, they will be asked to choose a User when logging in for the first time.

You can also assign an avatar for each user by assigning some URL to a hosted image (there is no own upload feature, sorry). You can do that in the ` User profiles` area in the admin pages. There are many avatar generators, I like these:

- [https://getavataaars.com](https://getavataaars.com/)
- [http://avatars.adorable.io](http://avatars.adorable.io/)
- [https://robohash.org](https://robohash.org/)

## A Note about Security

The whiteboard metaphor is valid: Anyone with a "key" to your flat (aka password for the Collective) can create and delete content or impersonate other Users. It's based on trust between the people in the group.

## Tech Stack

Project is build with [Django](https://www.djangoproject.com/) 2.1, [Django-REST-Framework](http://www.django-rest-framework.org/) 3, Vue 2.5, [vue](https://vuejs.org/)-cli-3 and the wonderful [Vuetify](https://vuetifyjs.com/en/) 1.1.0. It is build mainly to be used on a mobile phone, but responsive and very usable on desktop as well. Technically it is a [PWA](https://developers.google.com/web/progressive-web-apps/), but right now that is only used to cache the app shell, not any API responses. Uses SQLite as its database, creating a single file for easy backup.

## Deployment

Oh the joy of deploying custom web apps to your own server. Our backend can be setup as a systemd service that runs a WSGI app via gunicorn, whereas the frontend is built into a bundle of static files that our nginx webserver can serve.

### Building the Frontend

- `$ cd payshare/purchases/static/client`
- Update the `src/store.js` `apiBaseUrl` as needed, depending where your API lives on.
- `$ npm run build`
- ` $ cd -`
- `$ python manage.py collectstatic --noinput`
- Copy the results from `public` to a folder that your webserver knows, e.g. ` /var/www/payshare`
- Configure your webserver and systemd, see below
- Don't forget to install gunicorn: `$ pip install gunicorn`

Please see the following files for examples on simple systemd and nginx configurations:

- [payshare.service](payshare.service)
- [payshare.conf](payshare.conf)

Notes: We should use https in any case, but it is also a requirement for the service-worker. One specialty about location blocks here is that for some we'll want to pass through the URL path and for others we don't.

### Image Hosting (e.g. avatars)

You can upload images within the admin page using [Filer](https://django-filer.readthedocs.io/en/latest/index.html)
which is particularly helpful to upload avatars to use within the UserProfile model.
Any URLs that may have been used to create the avatar can be stored in the 'description'
field of the image so it can be used later on.

Images are hosted efficiently by making use of [Whitenoise](http://whitenoise.evans.io/en/stable/),
so there is no need to configure your webserver for it in addition.

### Paypal.me Integration

Well, integration is a big word. You can set a paypal.me username in the profile
of each User and the app will show a button on the cashup page to open a tab
in the browser with the correct amount for that payback action.
15 changes: 15 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/sh

workon payshare &&

pip install pip-tools &&
pip-sync &&

cd payshare/purchases/static/client &&
yarn install --check-files &&
npm run build &&

cd - &&
python manage.py collectstatic --noinput

echo "build finished"
Binary file added docs/cashup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/newoutlay.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/ranking.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/transfers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions payshare.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
server {
listen 443;
server_name payshare.com;

location ~ ^/(api|admin) {
# Make sure proxy is properly resolved via headers.
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;

# If we dont set this, https will make us run into a timeout.
# See: https://stackoverflow.com/questions/24453388
proxy_http_version 1.1;
proxy_set_header Connection "";

proxy_pass https://localhost:1234;
}

location /static {
root /var/www/payshare;
}

location / {
root /var/www/payshare/static;
error_page 404 =200 /index.html;
}
}
18 changes: 18 additions & 0 deletions payshare.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[Unit]
Description=Payshare

[Service]
User=root
WorkingDirectory=/opt/payshare/
ExecStart=/~/.virtualenvs/payshare/bin/gunicorn payshare.wsgi:application \
--workers 2 \
--bind 127.0.0.1:1234 \
--log-level debug \
--certfile /etc/letsencrypt/live/payshare.com/fullchain.pem \
--keyfile /etc/letsencrypt/live/payshare.com/privkey.pem \
--access-logfile /var/log/payshare-access.log \
--error-logfile /var/log/payshare-error.log

[Install]
WantedBy=multi-user.target
Alias=payshare.service
1 change: 1 addition & 0 deletions payshare/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = "2.11.4"
153 changes: 147 additions & 6 deletions payshare/purchases/admin.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,147 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.contrib import admin

# Register your models here.
from django.contrib import admin
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.safestring import mark_safe

from payshare.purchases.models import Collective
from payshare.purchases.models import Liquidation
from payshare.purchases.models import Membership
from payshare.purchases.models import Purchase
from payshare.purchases.models import UserProfile


class UserAdmin(admin.ModelAdmin):
list_display = (
"id",
"username",
"email",
"first_name",
"last_name",
)
list_editable = (
"username",
"email",
"first_name",
"last_name",
)
search_fields = ("username", "first_name", "last_name", "email", "id")


class UserProfileAdmin(admin.ModelAdmin):
list_display = (
"user",
"avatar_image_url_link",
"avatar_image_url",
"paypal_me_username",
"id",
)
autocomplete_fields = ("user",)
list_editable = ("avatar_image_url",)

def avatar_image_url_link(self, profile):
image_url = profile.avatar_image_url
editor_url = ""
is_avataaars_url = image_url.startswith("https://avataaars.io")
if is_avataaars_url:
editor_url = image_url.replace(
"https://avataaars.io", "https://getavataaars.com"
)
template = """
<image src="{0}"
style="max-width: 200px; max-height: 200px"/>
"""
if is_avataaars_url:
template += """
<a href="{1}" target="blank_">
Edit on https://getavataaars.com
</a>
"""
html = template.format(image_url, editor_url)
else:
html = template.format(image_url)
return mark_safe(html)


class CollectiveAdmin(admin.ModelAdmin):
class MembershipInline(admin.TabularInline):
model = Membership
autocomplete_fields = ("member",)

def get_queryset(self, request):
return (
super()
.get_queryset(request)
.order_by(
"member__first_name",
"member__last_name",
)
)

inlines = (MembershipInline,)

readonly_fields = ("key",)
list_display = (
"name",
"url",
"created_at",
"readonly",
"currency_symbol",
"id",
)
search_fields = ("name", "id")

@mark_safe
def url(self, collective):
url = reverse("app", args=[collective.key])
return f"<a href='{url}'>Visit in App: {collective.name}</a>"


class PurchaseAdmin(admin.ModelAdmin):
list_display = ["name", "active", "price", "buyer", "id", "collective"]
list_filter = ("collective",)
autocomplete_fields = ("buyer", "collective")

def active(self, purchase):
return not purchase.deleted

active.boolean = True


class LiquidationAdmin(admin.ModelAdmin):
list_display = [
"name",
"active",
"amount",
"creditor",
"debtor",
"id",
"collective",
]
list_filter = ("collective",)
autocomplete_fields = ("creditor", "debtor", "collective")

def active(self, liquidation):
return not liquidation.deleted

active.boolean = True


class MembershipAdmin(admin.ModelAdmin):
list_display = [
"collective",
"member",
"created_at",
"id",
]
list_filter = ("collective",)
autocomplete_fields = ("member", "collective")


admin.site.unregister(User)
admin.site.register(User, UserAdmin)
admin.site.register(UserProfile, UserProfileAdmin)

admin.site.register(Collective, CollectiveAdmin)
admin.site.register(Membership, MembershipAdmin)
admin.site.register(Purchase, PurchaseAdmin)
admin.site.register(Liquidation, LiquidationAdmin)
Loading