132 Commits

Author SHA1 Message Date
23b8e28a35 Dropped support for Python 3.8 2025-08-22 16:43:36 +03:00
d1ab309c23 Update dependency ujson to ~=5.11.0 2025-08-20 15:21:18 +03:00
732fafb965 Update dependency scipy to ~=1.16.1,<1.17.0 2025-07-27 19:52:48 +03:00
d4b73f8f88 Merge pull request 'Update dependency fastapi to v0.116.1' (#103) from renovate/fastapi-0.x into dev
Reviewed-on: #103
2025-07-12 01:41:06 +03:00
2318c416d8 Update dependency fastapi to v0.116.1 2025-07-11 20:15:26 +03:00
13d552cb57 Merge pull request 'Update dependency opencv-python to ~=4.12.0.88' (#102) from renovate/opencv-python-4.x into dev
Reviewed-on: #102
2025-07-08 00:50:40 +03:00
0dc0c8fc30 Merge pull request 'Update dependency fastapi to v0.116.0' (#101) from renovate/fastapi-0.x into dev
Reviewed-on: #101
2025-07-08 00:50:15 +03:00
bacba25d9f Update dependency fastapi to v0.116.0 2025-07-07 18:28:38 +03:00
31397498d4 Update dependency opencv-python to ~=4.12.0.88 2025-07-07 12:18:34 +03:00
15793ce24d Merge pull request 'Update dependency fastapi to v0.115.13' (#99) from renovate/fastapi-0.x into dev
Reviewed-on: #99
2025-06-22 01:00:18 +03:00
4a92ac82b9 Update dependency fastapi to v0.115.13 2025-06-17 15:44:45 +03:00
2ff2890c5d Update dependency fastapi to v0.115.12 (#96) 2025-03-24 01:07:41 +02:00
d72ad95983 Update dependency fastapi to v0.115.12 2025-03-24 00:57:42 +02:00
53ae39f715 Update dependency fastapi to v0.115.11 (#95) 2025-03-02 02:56:34 +02:00
03e83563dd Update dependency fastapi to v0.115.11 2025-03-02 01:03:04 +02:00
419901c6b6 Merge pull request 'Update dependency fastapi to v0.115.10' (#94) from renovate/fastapi-0.x into dev
Reviewed-on: #94
2025-02-28 23:13:39 +02:00
40b8f18b71 Update dependency fastapi to v0.115.10 2025-02-28 19:18:26 +02:00
fbd63e0df5 Update dependency fastapi to v0.115.9 (#93) 2025-02-28 01:40:54 +02:00
3751b9cf76 Update dependency fastapi to v0.115.9 2025-02-27 19:42:58 +02:00
a36032b251 Merge pull request 'Update dependency python-jose to ~=3.4.0' (#92) from renovate/python-jose-3.x into dev
Reviewed-on: #92
2025-02-18 22:21:10 +02:00
e0da6332f0 Update dependency python-jose to ~=3.4.0 2025-02-18 20:29:37 +02:00
9a9bcf9779 Merge pull request 'Update dependency fastapi to v0.115.8' (#90) from renovate/fastapi-0.x into dev
Reviewed-on: #90
2025-01-31 09:55:43 +02:00
933185fff7 Update dependency fastapi to v0.115.8 2025-01-30 16:58:06 +02:00
7299980bce Merge pull request 'Update dependency fastapi to v0.115.7' (#89) from renovate/fastapi-0.x into dev
Reviewed-on: #89
2025-01-24 14:33:31 +02:00
da04319bd9 Update dependency fastapi to v0.115.7 2025-01-23 00:58:25 +02:00
d9d65821c3 Merge pull request 'Update dependency opencv-python to ~=4.11.0.86' (#88) from renovate/opencv-python-4.x into dev
Reviewed-on: #88
2025-01-16 23:37:03 +02:00
7907c95cb8 Update dependency opencv-python to ~=4.11.0.86 2025-01-16 16:51:27 +02:00
31da6b29ca Update dependency exif to v1.6.1 (#84) 2024-12-10 08:21:51 +02:00
2884d989a8 Update dependency exif to v1.6.1 2024-12-10 07:00:03 +02:00
ae984a20e5 Merge pull request 'Update dependency fastapi to v0.115.6' (#83) from renovate/fastapi-0.x into dev
Reviewed-on: #83
2024-12-10 00:02:44 +02:00
c62359c9c2 Update dependency fastapi to v0.115.6 2024-12-04 01:36:36 +02:00
560ef5c986 Merge pull request 'Update dependency apscheduler to ~=3.11.0' (#82) from renovate/apscheduler-3.x into dev
Reviewed-on: #82
2024-11-24 22:17:28 +02:00
f0587d0422 Update dependency apscheduler to ~=3.11.0 2024-11-24 21:56:20 +02:00
381c6fd0d3 Merge pull request 'Update dependency fastapi to v0.115.5' (#81) from renovate/fastapi-0.x into dev
Reviewed-on: #81
2024-11-12 19:44:41 +02:00
b8a0ff79ec Update dependency fastapi to v0.115.5 2024-11-12 18:29:09 +02:00
51253d82af Merge pull request 'Update dependency fastapi to v0.115.4' (#80) from renovate/fastapi-0.x into dev
Reviewed-on: #80
2024-10-29 17:39:36 +02:00
6cdc804d30 Update dependency fastapi to v0.115.4 2024-10-28 00:45:41 +02:00
fe4cd2dc48 Merge pull request 'Update dependency fastapi to v0.115.3' (#79) from renovate/fastapi-0.x into dev
Reviewed-on: #79
2024-10-22 20:45:06 +03:00
b7def0fe64 Update dependency fastapi to v0.115.3 2024-10-22 18:11:55 +03:00
921119ee75 Merge pull request 'Update dependency async_pymongo to v0.1.11' (#78) from renovate/async_pymongo-0.x into dev
Reviewed-on: #78
2024-10-17 09:56:10 +03:00
bebf1f8541 Update dependency async_pymongo to v0.1.11 2024-10-16 20:15:06 +03:00
16afeb5a95 Merge pull request 'Update dependency async_pymongo to v0.1.10' (#77) from renovate/async_pymongo-0.x into dev
Reviewed-on: #77
2024-10-15 15:53:23 +03:00
764dfe540c Update dependency async_pymongo to v0.1.10 2024-10-15 13:10:25 +03:00
df32ee393e Update dependency fastapi to v0.115.2 (#76) 2024-10-12 13:57:41 +03:00
936a86728a Update dependency fastapi to v0.115.2 2024-10-12 13:19:17 +03:00
0438bd0483 Merge pull request 'Update dependency async_pymongo to v0.1.9' (#75) from renovate/async_pymongo-0.x into dev
Reviewed-on: #75
2024-10-08 16:49:50 +03:00
ff3a18691b Update dependency async_pymongo to v0.1.9 2024-10-08 16:30:35 +03:00
5a3e2fffe9 Merge pull request 'Update dependency async_pymongo to v0.1.8' (#74) from renovate/async_pymongo-0.x into dev
Reviewed-on: #74
2024-09-25 22:25:32 +03:00
f248433e11 Update dependency async_pymongo to v0.1.8 2024-09-25 17:14:21 +03:00
8c26ffc7be Merge pull request 'Update dependency async_pymongo to v0.1.7' (#73) from renovate/async_pymongo-0.x into dev
Reviewed-on: #73
2024-09-21 01:52:43 +03:00
8a7f53d63b Update dependency async_pymongo to v0.1.7 2024-09-20 17:25:41 +03:00
2c2704cd91 Merge pull request 'Update dependency fastapi to v0.115.0' (#72) from renovate/fastapi-0.x into dev
Reviewed-on: #72
2024-09-18 09:24:57 +03:00
1a7fe795b4 Update dependency fastapi to v0.115.0 2024-09-17 22:32:03 +03:00
d01842913d Update dependency fastapi to v0.114.2 (#71) 2024-09-14 01:52:17 +03:00
50c629c157 Update dependency fastapi to v0.114.2 2024-09-14 00:46:39 +03:00
95bfb1fe2f Merge pull request 'Update dependency fastapi to v0.114.1' (#70) from renovate/fastapi-0.x into dev
Reviewed-on: #70
2024-09-11 13:43:22 +03:00
b53743fb19 Update dependency fastapi to v0.114.1 2024-09-11 11:20:37 +03:00
2103d6b003 Merge pull request 'Update dependency fastapi to v0.114.0' (#69) from renovate/fastapi-0.x into dev
Reviewed-on: #69
2024-09-07 11:30:46 +03:00
126070bfdc Update dependency fastapi to v0.114.0 2024-09-06 20:52:33 +03:00
b660a12e23 Update requirements.txt 2024-08-21 11:51:21 +03:00
e1bb3e9af9 Merge pull request 'Update dependency fastapi to v0.112.1' (#66) from renovate/fastapi-0.x into dev
Reviewed-on: #66
2024-08-17 22:12:31 +03:00
8a58902f8c Update dependency fastapi to v0.112.1 2024-08-16 00:30:46 +03:00
8ba45faf50 Merge pull request 'Update dependency fastapi to v0.112.0' (#65) from renovate/fastapi-0.x into dev
Reviewed-on: #65
2024-08-03 00:58:26 +03:00
78f24bc423 Update dependency fastapi to v0.112.0 2024-08-02 09:58:30 +03:00
a148b9ac30 Merge pull request 'Update dependency fastapi to v0.111.1' (#64) from renovate/fastapi-0.x into dev
Reviewed-on: #64
2024-07-15 00:51:45 +03:00
af936b522d Update dependency fastapi to v0.111.1 2024-07-14 21:28:24 +03:00
50da0f78c7 Merge pull request 'Update dependency aiofiles to v24' (#62) from renovate/aiofiles-24.x into dev
Reviewed-on: #62
2024-06-24 18:27:24 +03:00
bda26f5ebf Update dependency aiofiles to v24 2024-06-24 14:56:40 +03:00
3df80337b7 Merge pull request 'Update dependency async_pymongo to v0.1.6' (#61) from renovate/async_pymongo-0.x into dev
Reviewed-on: #61
2024-06-23 14:34:03 +03:00
6955f1860a Update dependency async_pymongo to v0.1.6 2024-06-23 13:31:43 +03:00
22818c4cae Update dependency opencv-python to ~=4.10.0.82 (#60) 2024-06-03 21:16:37 +03:00
7e5f6c3cb7 Update dependency opencv-python to ~=4.10.0.82 2024-06-03 20:21:02 +03:00
46b6ed0e22 Merge pull request 'Update dependency async_pymongo to v0.1.5' (#59) from renovate/async_pymongo-0.x into dev
Reviewed-on: #59
2024-06-02 12:57:04 +03:00
89cdd8ca3b Selected async_pymongo from PyPi 2024-06-02 12:55:34 +03:00
50dfccef1a Update dependency async_pymongo to v0.1.5 2024-06-01 15:33:42 +03:00
a84cd1c5ed Merge pull request 'Update dependency ujson to ~=5.10.0' (#57) from renovate/ujson-5.x into dev
Reviewed-on: #57
2024-05-14 23:58:21 +03:00
2830a8e21a Update dependency ujson to ~=5.10.0 2024-05-14 05:38:17 +03:00
eee7e3a73f Update dependency mongodb-migrations to v1.3.1 (#56) 2024-05-14 01:48:32 +03:00
0de1f7f08d Update dependency mongodb-migrations to v1.3.1 2024-05-14 01:27:22 +03:00
5227c7cd14 Fixed venv name 2024-05-14 00:16:17 +03:00
6fea31e3fb Update dependency fastapi to v0.111.0 (#55) 2024-05-03 11:42:42 +03:00
e8312a99d0 Update dependency fastapi to v0.111.0 2024-05-03 04:07:24 +03:00
ab8b9bacde Update dependency fastapi to v0.110.3 (#54) 2024-04-30 09:11:30 +03:00
296b0014d5 Update dependency fastapi to v0.110.3 2024-04-30 04:21:33 +03:00
adcf25ff15 Merge pull request 'Update dependency scipy to ~=1.13.0' (#52) from renovate/scipy-1.x into dev
Reviewed-on: #52
2024-04-21 17:17:17 +03:00
508984442b Update dependency scipy to ~=1.13.0 2024-04-19 22:09:00 +03:00
37a6b4634c Merge pull request 'Update dependency fastapi to v0.110.2' (#53) from renovate/fastapi-0.x into dev
Reviewed-on: #53
2024-04-19 21:33:30 +03:00
5796c6ea40 Update dependency fastapi to v0.110.2 2024-04-19 04:29:24 +03:00
b488bbee0a Merge pull request 'Update dependency fastapi to v0.110.1' (#51) from renovate/fastapi-0.x into dev
Reviewed-on: #51
2024-04-02 15:09:18 +03:00
43597db03c Update dependency fastapi to v0.110.1 2024-04-02 07:04:42 +03:00
e6f3b7c4b1 Merge pull request 'Update dependency fastapi to v0.110.0' (#50) from renovate/fastapi-0.x into dev
Reviewed-on: #50
2024-02-25 22:31:46 +02:00
e91a6ad10e Update dependency fastapi to v0.110.0 2024-02-25 02:14:24 +02:00
aa6c5b99b1 Merge pull request 'Update dependency fastapi to v0.109.2' (#47) from renovate/fastapi-0.x into dev
Reviewed-on: #47
2024-02-13 19:06:10 +02:00
0991734377 Update dependency fastapi to v0.109.2 2024-02-04 23:48:51 +02:00
d4aa6558d6 Merge pull request 'Update dependency fastapi to v0.109.1' (#46) from renovate/fastapi-0.x into dev
Reviewed-on: #46
2024-02-04 01:19:48 +02:00
186fddacef Update dependency fastapi to v0.109.1 2024-02-03 15:16:16 +02:00
bf006a0734 Merge pull request 'Update dependency fastapi to v0.109.0' (#44) from renovate/fastapi-0.x into dev
Reviewed-on: #44
2024-01-21 13:54:49 +02:00
9d70724d64 Merge pull request 'Update dependency scipy to ~=1.12.0' (#45) from renovate/scipy-1.x into dev
Reviewed-on: #45
2024-01-21 13:54:36 +02:00
8b30afdf6a Update dependency scipy to ~=1.12.0 2024-01-21 00:09:11 +02:00
0db4661658 Update dependency fastapi to v0.109.0 2024-01-11 18:03:38 +02:00
bf4fbe2302 Merge pull request 'Update dependency opencv-python to ~=4.9.0.80' (#43) from renovate/opencv-python-4.x into dev
Reviewed-on: #43
2024-01-02 13:11:58 +02:00
3bb24f786d Update dependency opencv-python to ~=4.9.0.80 2023-12-31 15:53:38 +02:00
7adf849150 Merge pull request 'Update dependency fastapi to v0.108.0' (#42) from renovate/fastapi-0.x into dev
Reviewed-on: #42
2023-12-28 19:39:28 +02:00
e6c0a53742 Update dependency fastapi to v0.108.0 2023-12-26 22:33:57 +02:00
fa09dbc9b2 Merge pull request 'Added missing import of SearchLimitInvalidError' (#41) from master into dev
Reviewed-on: #41
2023-12-14 01:22:29 +02:00
c3a9a2f40a Added missing import of SearchLimitInvalidError 2023-12-14 01:22:03 +02:00
58933a9279 Merge pull request 'Fix of a fix in exceptions' (#40) from master into dev
Reviewed-on: #40
2023-12-14 01:21:12 +02:00
bcf74089f9 Fix of a fix in exceptions 2023-12-14 01:20:42 +02:00
891dc81271 Merge pull request 'Merge of the exceptions import fix' (#39) from master into dev
Reviewed-on: #39
2023-12-14 01:10:15 +02:00
25c902c194 Fixed the wrong exceptions being imported 2023-12-14 01:09:04 +02:00
5a794f7dc6 Merge pull request 'Update dependency ujson to ~=5.9.0' (#37) from renovate/ujson-5.x into dev
Reviewed-on: #37
2023-12-12 03:28:49 +02:00
848b2f1a8e Merge pull request 'Update dependency fastapi to v0.105.0' (#38) from renovate/fastapi-0.x into dev
Reviewed-on: #38
2023-12-12 03:28:35 +02:00
539b3b42c9 Update dependency fastapi to v0.105.0 2023-12-12 03:22:45 +02:00
f01d2d177b Update dependency ujson to ~=5.9.0 2023-12-11 01:36:10 +02:00
5129cb449e Merge pull request 'Quotas, new secrets, upgrades' (#36) from dev into master
Reviewed-on: #36
2023-11-25 20:12:43 +02:00
4d6efac3c4 Merge branch 'dev' 2023-11-25 19:12:05 +01:00
88b820e90d Merge branch 'master' into dev 2023-11-25 20:00:52 +02:00
afefea6f68 Fixed "TypeError" for UserInDB 2023-11-25 18:17:17 +01:00
e5fad5ba92 Fixed "unrecognized arguments" error 2023-11-25 18:14:30 +01:00
5174602c31 Added upgrade section 2023-11-25 18:12:01 +01:00
0043abdbad Migration for quotas added 2023-11-25 18:05:12 +01:00
0f423166f1 New secrets system and quotas (#35) 2023-11-25 17:50:09 +01:00
b2146b965a Fixed license link
Signed-off-by: Profitroll <profitroll@noreply.localhost>
2023-11-24 12:19:32 +02:00
3aa171869b Update dependency fastapi to v0.104.1 (#34) 2023-10-31 11:07:53 +02:00
126c66637e Update dependency fastapi to v0.104.1 2023-10-30 12:18:40 +02:00
d0d127d9c0 Merge pull request 'Update dependency fastapi to v0.104.0' (#33) from renovate/fastapi-0.x into dev
Reviewed-on: #33
2023-10-18 21:55:59 +03:00
728917b4b9 Update dependency fastapi to v0.104.0 2023-10-18 16:08:54 +03:00
b1eb8f9aac Merge pull request 'Update dependency fastapi to v0.103.2' (#32) from renovate/fastapi-0.x into dev
Reviewed-on: #32
2023-09-29 17:43:13 +03:00
0a30512dbc Update dependency fastapi to v0.103.2 2023-09-28 23:38:38 +03:00
14b09d7062 Merge pull request 'Update dependency opencv-python to ~=4.8.1.78' (#31) from renovate/opencv-python-4.x into dev
Reviewed-on: #31
2023-09-28 23:28:25 +03:00
ac8f2b2ba6 Update dependency opencv-python to ~=4.8.1.78 2023-09-28 14:20:54 +03:00
1bcca0f812 Merge pull request 'Random media requests' (#18) from dev into master
Reviewed-on: #18
2023-06-27 14:54:28 +03:00
14 changed files with 188 additions and 30 deletions

3
.gitignore vendored
View File

@@ -153,5 +153,6 @@ cython_debug/
#.idea/
# Custom
.vscode
data/
.vscode/
config.json

View File

@@ -1,7 +1,7 @@
<h1 align="center">Photos API</h1>
<p align="center">
<a href="https://git.end-play.xyz/profitroll/PhotosAPILICENSE"><img alt="License: GPL" src="https://img.shields.io/badge/License-GPL-blue"></a>
<a href="https://git.end-play.xyz/profitroll/PhotosAPI/src/branch/master/README.md"><img alt="License: GPL" src="https://img.shields.io/badge/License-GPL-blue"></a>
<a href="https://git.end-play.xyz/profitroll/PhotosAPI"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
</p>
@@ -9,7 +9,7 @@ Small and simple API server for saving photos and videos.
## Dependencies
* [Python 3.8+](https://www.python.org) (3.9+ recommended)
* [Python 3.9+](https://www.python.org) (3.11+ recommended)
* [MongoDB](https://www.mongodb.com)
* [exiftool](https://exiftool.org)
* [jpegoptim](https://github.com/tjko/jpegoptim)
@@ -35,8 +35,8 @@ First you need to have a Python interpreter, MongoDB and optionally git. You can
3. Create virtual environment [Optional yet recommended]:
1. Install virtualenv module: `pip install virtualenv`
2. Create venv: `python -m venv env`
3. Activate it using `source venv/bin/activate` on Linux, `venv\Scripts\activate.bat` in CMD or `venv\Scripts\Activate.ps1` in PowerShell.
2. Create venv: `python -m venv .venv`
3. Activate it using `source .venv/bin/activate` on Linux, `.venv\Scripts\activate.bat` in CMD or `.venv\Scripts\Activate.ps1` in PowerShell.
4. Install project's dependencies:
@@ -47,7 +47,8 @@ First you need to have a Python interpreter, MongoDB and optionally git. You can
1. Copy file `config_example.json` to `config.json`
2. Open `config.json` using your favorite text editor. For example `nano config.json`
3. Change `"database"` keys to match your MongoDB setup
4. Change `"external_address"` to the ip/http address you may get in responses. By default it's `"localhost"`. This is extremely useful when running behind reverse-proxy.
4. Set the key `"secret"` to your JWT secret. You can type in anything, but long secrets are recommended. You can also set environment variable `PHOTOSAPI_SECRET` as an alternative
5. Change `"external_address"` to the ip/http address you may get in responses. By default it's `"localhost"`. This is extremely useful when running behind reverse-proxy.
After configuring everything listed above your API will be able to boot, however further configuration can be done. You can read about it in [repository's wiki](https://git.end-play.xyz/profitroll/PhotosAPI/wiki/Configuration). There's no need to focus on that now, it makes more sense to configure it afterwards.
@@ -58,6 +59,19 @@ First you need to have a Python interpreter, MongoDB and optionally git. You can
Learn more about available uvicorn arguments using `uvicorn --help`
## Upgrading
When a new version comes out, sometimes you want to upgrade your instance right away. Here's a checklist what to do:
1. Carefully read the patch notes of the version you want to update to and all the versions that came out between the release of your version and the one you want to upgrade to.
Breaking changes will be marked so and config updates will also be described in the patch notes
2. Make a backup of your currently working instance. This includes both the PhotosAPI and the database
3. Download the latest version using git (`git pull` if you cloned the repo in the past) or from the releases
4. Reconfigure the config if needed and apply the changes from the patch notes
5. Upgrade the dependencies in your virtual environment using `pip install -r requirements.txt`
6. Start the migration using `python photos_api.py --migrate` from your virtual environment
7. Test if everything works and troubleshoot/rollback if not
## Using as a service
It's a good practice to use your API as a systemd service on Linux. Here's a quick overview how that can be done.
@@ -83,7 +97,7 @@ It's a good practice to use your API as a systemd service on Linux. Here's a qui
[Service]
Restart=always
Type=simple
ExecStart=/bin/bash -c 'source venv/bin/activate && venv/bin/uvicorn photos_api:app --port 8054'
ExecStart=/bin/bash -c 'source .venv/bin/activate && .venv/bin/uvicorn photos_api:app --port 8054'
WorkingDirectory=/opt/PhotosAPI
User=photosapi
Group=photosapi

View File

@@ -286,3 +286,23 @@ class UserCredentialsInvalid(HTTPException):
status_code=401,
detail=self.openapi["content"]["application/json"]["example"]["detail"],
)
class UserMediaQuotaReached(HTTPException):
"""Raises HTTP 403 if user's quota has been reached."""
def __init__(self):
self.openapi = {
"description": "Media Quota Reached",
"content": {
"application/json": {
"example": {
"detail": "Media quota has been reached, media upload impossible."
}
}
},
}
super().__init__(
status_code=403,
detail=self.openapi["content"]["application/json"]["example"]["detail"],
)

View File

@@ -6,6 +6,7 @@
"user": null,
"password": null
},
"secret": "",
"messages": {
"email_confirmed": "Email confirmed. You can now log in."
},
@@ -14,6 +15,7 @@
"media_token_valid_hours": 12,
"registration_enabled": true,
"registration_requires_confirmation": false,
"default_user_quota": 10000,
"mailer": {
"smtp": {
"host": "",

View File

@@ -3,6 +3,7 @@ from fastapi.responses import UJSONResponse
from starlette.status import (
HTTP_400_BAD_REQUEST,
HTTP_401_UNAUTHORIZED,
HTTP_403_FORBIDDEN,
HTTP_404_NOT_FOUND,
HTTP_406_NOT_ACCEPTABLE,
HTTP_409_CONFLICT,
@@ -10,19 +11,21 @@ from starlette.status import (
)
from classes.exceptions import (
AlbumNotFoundError,
AccessTokenInvalidError,
AlbumAlreadyExistsError,
AlbumIncorrectError,
AlbumNotFoundError,
PhotoNotFoundError,
PhotoSearchQueryEmptyError,
VideoNotFoundError,
VideoSearchQueryEmptyError,
SearchLimitInvalidError,
SearchPageInvalidError,
SearchTokenInvalidError,
AccessTokenInvalidError,
UserEmailCodeInvalid,
UserAlreadyExists,
UserCredentialsInvalid,
UserEmailCodeInvalid,
UserMediaQuotaReached,
VideoNotFoundError,
VideoSearchQueryEmptyError,
)
from modules.app import app
@@ -93,12 +96,24 @@ async def video_search_query_empty_exception_handler(
)
@app.exception_handler(SearchLimitInvalidError)
async def search_limit_invalid_exception_handler(
request: Request, exc: SearchLimitInvalidError
):
return UJSONResponse(
status_code=HTTP_400_BAD_REQUEST,
content={
"detail": "Parameter 'limit' must be greater or equal to 1."
},
)
@app.exception_handler(SearchPageInvalidError)
async def search_page_invalid_exception_handler(
request: Request, exc: SearchPageInvalidError
):
return UJSONResponse(
status_code=HTTP_400_BAD_REQUEST,
status_code=HTTP_401_UNAUTHORIZED,
content={
"detail": "Parameters 'page' and 'page_size' must be greater or equal to 1."
},
@@ -112,7 +127,7 @@ async def search_token_invalid_exception_handler(
return UJSONResponse(
status_code=HTTP_401_UNAUTHORIZED,
content={
"detail": "Parameters 'page' and 'page_size' must be greater or equal to 1."
"detail": "Invalid search token."
},
)
@@ -155,3 +170,13 @@ async def user_credentials_invalid_exception_handler(
status_code=HTTP_401_UNAUTHORIZED,
content={"detail": "Invalid credentials."},
)
@app.exception_handler(UserMediaQuotaReached)
async def user_media_quota_reached_exception_handler(
request: Request, exc: UserMediaQuotaReached
):
return UJSONResponse(
status_code=HTTP_403_FORBIDDEN,
content={"detail": "Media quota has been reached, media upload impossible."},
)

View File

@@ -30,6 +30,7 @@ from classes.exceptions import (
SearchLimitInvalidError,
SearchPageInvalidError,
SearchTokenInvalidError,
UserMediaQuotaReached,
)
from classes.models import (
Photo,
@@ -38,7 +39,7 @@ from classes.models import (
SearchResultsPhoto,
)
from modules.app import app
from modules.database import col_albums, col_photos, col_tokens
from modules.database import col_albums, col_photos, col_tokens, col_videos
from modules.exif_reader import extract_location
from modules.hasher import get_duplicates, get_phash
from modules.scheduler import scheduler
@@ -91,6 +92,7 @@ async def compress_image(image_path: str):
photo_post_responses = {
403: UserMediaQuotaReached().openapi,
404: AlbumNameNotFoundError("name").openapi,
409: {
"description": "Image Duplicates Found",
@@ -125,6 +127,13 @@ async def photo_upload(
if (await col_albums.find_one({"user": current_user.user, "name": album})) is None:
raise AlbumNameNotFoundError(album)
user_media_count = (
await col_photos.count_documents({"user": current_user.user})
) + (await col_videos.count_documents({"user": current_user.user}))
if user_media_count >= current_user.quota and not current_user.quota == -1: # type: ignore
raise UserMediaQuotaReached()
makedirs(Path(f"data/users/{current_user.user}/albums/{album}"), exist_ok=True)
filename = file.filename

View File

@@ -109,6 +109,7 @@ if configGet("registration_enabled") is True:
{
"user": user,
"email": email,
"quota": None,
"hash": get_password_hash(password),
"disabled": configGet("registration_requires_confirmation"),
}

View File

@@ -21,6 +21,7 @@ from classes.exceptions import (
SearchLimitInvalidError,
SearchPageInvalidError,
SearchTokenInvalidError,
UserMediaQuotaReached,
VideoNotFoundError,
VideoSearchQueryEmptyError,
)
@@ -31,10 +32,13 @@ from classes.models import (
VideoPublic,
)
from modules.app import app
from modules.database import col_albums, col_tokens, col_videos
from modules.database import col_albums, col_photos, col_tokens, col_videos
from modules.security import User, get_current_active_user
video_post_responses = {404: AlbumNameNotFoundError("name").openapi}
video_post_responses = {
403: UserMediaQuotaReached().openapi,
404: AlbumNameNotFoundError("name").openapi,
}
@app.post(
@@ -53,6 +57,13 @@ async def video_upload(
if (await col_albums.find_one({"user": current_user.user, "name": album})) is None:
raise AlbumNameNotFoundError(album)
user_media_count = (
await col_videos.count_documents({"user": current_user.user})
) + (await col_photos.count_documents({"user": current_user.user}))
if user_media_count >= current_user.quota and not current_user.quota == -1: # type: ignore
raise UserMediaQuotaReached()
makedirs(Path(f"data/users/{current_user.user}/albums/{album}"), exist_ok=True)
filename = file.filename

View File

@@ -0,0 +1,9 @@
from mongodb_migrations.base import BaseMigration
class Migration(BaseMigration):
def upgrade(self):
self.db.users.update_many({}, {"$set": {"quota": None}})
def downgrade(self):
self.db.test_collection.update_many({}, {"$unset": "quota"})

View File

@@ -1,7 +1,7 @@
from fastapi import FastAPI
from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html
app = FastAPI(title="END PLAY Photos", docs_url=None, redoc_url=None, version="0.5")
app = FastAPI(title="END PLAY Photos", docs_url=None, redoc_url=None, version="0.6")
@app.get("/docs", include_in_schema=False)

23
modules/migrator.py Normal file
View File

@@ -0,0 +1,23 @@
from typing import Any, Mapping
from mongodb_migrations.cli import MigrationManager
from mongodb_migrations.config import Configuration
from modules.utils import configGet
def migrate_database() -> None:
"""Apply migrations from folder `migrations/` to the database"""
db_config: Mapping[str, Any] = configGet("database")
manager_config = Configuration(
{
"mongo_host": db_config["host"],
"mongo_port": db_config["port"],
"mongo_database": db_config["name"],
"mongo_username": db_config["user"],
"mongo_password": db_config["password"],
}
)
manager = MigrationManager(manager_config)
manager.run()

View File

@@ -1,4 +1,5 @@
from datetime import datetime, timedelta, timezone
from os import getenv
from typing import List, Union
from fastapi import Depends, HTTPException, Security, status
@@ -8,9 +9,26 @@ from passlib.context import CryptContext
from pydantic import BaseModel, ValidationError
from modules.database import col_users
from modules.utils import configGet
try:
configGet("secret")
except KeyError as exc:
raise KeyError(
"PhotosAPI secret is not set. Secret key handling has changed in PhotosAPI 0.6.0, so you need to add the config key 'secret' to your config file."
) from exc
if configGet("secret") == "" and getenv("PHOTOSAPI_SECRET") is None:
raise KeyError(
"PhotosAPI secret is not set. Set the config key 'secret' or provide the environment variable 'PHOTOSAPI_SECRET' containing a secret string."
)
SECRET_KEY = (
getenv("PHOTOSAPI_SECRET")
if getenv("PHOTOSAPI_SECRET") is not None
else configGet("secret")
)
with open("secret_key", "r", encoding="utf-8") as f:
SECRET_KEY = f.read()
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_DAYS = 180
@@ -28,6 +46,7 @@ class TokenData(BaseModel):
class User(BaseModel):
user: str
email: Union[str, None] = None
quota: Union[int, None] = None
disabled: Union[bool, None] = None
@@ -71,6 +90,9 @@ async def get_user(user: str) -> UserInDB:
return UserInDB(
user=found_user["user"],
email=found_user["email"],
quota=found_user["quota"]
if found_user["quota"] is not None
else configGet("default_user_quota"),
disabled=found_user["disabled"],
hash=found_user["hash"],
)
@@ -87,13 +109,16 @@ def create_access_token(
data: dict, expires_delta: Union[timedelta, None] = None
) -> str:
to_encode = data.copy()
if expires_delta:
expire = datetime.now(tz=timezone.utc) + expires_delta
else:
expire = datetime.now(tz=timezone.utc) + timedelta(
days=ACCESS_TOKEN_EXPIRE_DAYS
)
to_encode["exp"] = expire
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
@@ -114,8 +139,10 @@ async def get_current_user(
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
user: str = payload.get("sub")
if user is None:
raise credentials_exception
token_scopes = payload.get("scopes", [])
token_data = TokenData(scopes=token_scopes, user=user)
except (JWTError, ValidationError) as exc:
@@ -133,6 +160,7 @@ async def get_current_user(
detail="Not enough permissions",
headers={"WWW-Authenticate": authenticate_value},
)
return user_record
@@ -141,4 +169,5 @@ async def get_current_active_user(
):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
return current_user

View File

@@ -1,4 +1,5 @@
import logging
from argparse import ArgumentParser
from os import makedirs
from pathlib import Path
@@ -6,6 +7,7 @@ from fastapi.responses import FileResponse
from modules.app import app
from modules.extensions_loader import dynamic_import_from_src
from modules.migrator import migrate_database
from modules.scheduler import scheduler
makedirs(Path("data/users"), exist_ok=True)
@@ -27,3 +29,15 @@ dynamic_import_from_src("extensions", star_import=True)
# =================================================================================
scheduler.start()
parser = ArgumentParser(
prog="PhotosAPI",
description="Small and simple API server for saving photos and videos.",
)
parser.add_argument("--migrate", action="store_true")
args, unknown = parser.parse_known_args()
if args.migrate:
migrate_database()

View File

@@ -1,13 +1,13 @@
aiofiles==23.2.1
apscheduler~=3.10.1
exif==1.6.0
fastapi[all]==0.103.1
opencv-python~=4.8.0.74
aiofiles==24.1.0
apscheduler~=3.11.0
async_pymongo==0.1.11
exif==1.6.1
fastapi[all]==0.116.1
mongodb-migrations==1.3.1
opencv-python~=4.12.0.88
passlib~=1.7.4
pymongo>=4.3.3
python-jose[cryptography]~=3.3.0
python-jose[cryptography]~=3.4.0
python-magic~=0.4.27
scipy~=1.11.0
ujson~=5.8.0
--extra-index-url https://git.end-play.xyz/api/packages/profitroll/pypi/simple
async_pymongo==0.1.4
scipy~=1.16.1,<1.17.0
ujson~=5.11.0