Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
4a2e181
Add JWT to request headers after login
jlegrand62 Jan 27, 2026
de0a7af
Implemented enhanced REST API options:
jlegrand62 Jan 27, 2026
efa9877
Add pybase64 to server dependencies
jlegrand62 Jan 27, 2026
9299acd
Add missing 'token' kwargs to creation REST API methods
jlegrand62 Jan 27, 2026
32ae184
Add `has_role`, guest user docstring, and `can_create_user`
jlegrand62 Jan 27, 2026
7fa611a
Fix misleading comment in auth manager
jlegrand62 Jan 27, 2026
640cd19
Improve metadata handling and logging for scans, filesets, and files
jlegrand62 Jan 27, 2026
cca5db0
Refactor RBAC Manager and clean up docstrings
jlegrand62 Jan 27, 2026
f66ba97
Update terminology from `JWT` to `JSON Web Token` in session management
jlegrand62 Jan 27, 2026
0525518
Add `requires_jwt` decorator and improve `**kwargs` propagation for R…
jlegrand62 Jan 27, 2026
08d6bbb
Refactor RBAC permission logic and documentation
jlegrand62 Jan 27, 2026
e5f0d4e
Warn on `None` metadata values instead of raising
jlegrand62 Jan 28, 2026
6b07859
Add type hints to metadata helper functions and tighten docstrings
jlegrand62 Jan 28, 2026
0ad81e6
Refactor core file system database logic
jlegrand62 Jan 28, 2026
4a08136
Improve comment wording in `plantdb_client.py`
jlegrand62 Jan 28, 2026
dee0f81
Update example URLs to use explicit host/port and include auth token
jlegrand62 Jan 28, 2026
5c6b439
Add role hierarchy and assignment checks
jlegrand62 Jan 29, 2026
e9aa3ab
Add unit tests for auth models
jlegrand62 Jan 29, 2026
6d42eb9
Remove refactored auth tests from `test_auth.py`
jlegrand62 Jan 29, 2026
d5c5fb8
Add session_token helper and refine session_username
jlegrand62 Jan 29, 2026
11aa7a9
Update User model docs and add tracking fields
jlegrand62 Jan 29, 2026
08ff72b
Clean up auth manager docstrings and minor text tweaks
jlegrand62 Jan 29, 2026
3bce9d7
Clean up documentation and docstring formatting
jlegrand62 Jan 29, 2026
d3ff778
Clean up temporary directories for dummy databases on disconnect
jlegrand62 Jan 29, 2026
9e76489
Rename group creation parameter and enhance RBAC logging
jlegrand62 Jan 29, 2026
15e42e8
Introduce `get_logged_username` helper and refine authentication flow
jlegrand62 Jan 29, 2026
24a3aea
Add example usage to authentication and group methods
jlegrand62 Jan 29, 2026
3a384c8
Improve documentation and formatting in FSDB core
jlegrand62 Jan 29, 2026
76effc7
Cleanup stray whitespace and error formatting in FSDB core
jlegrand62 Jan 29, 2026
d0a4d2e
Improve documentation and formatting in auth session
jlegrand62 Jan 29, 2026
46c3115
Add optional `session_manager` to `test_database`
jlegrand62 Jan 29, 2026
dbd196c
Add JWT session manager to test database setup
jlegrand62 Jan 29, 2026
a33b4d2
Standardize JWT terminology and improve wording in docs
jlegrand62 Jan 29, 2026
25b5660
Update doctest examples to use admin/guest
jlegrand62 Jan 29, 2026
cc44eb3
Fix Register resource
jlegrand62 Jan 29, 2026
22984e6
Add example usage for user registration, login, logout, and token val…
jlegrand62 Jan 29, 2026
014a85e
Improve TokenRefresh initialization and documentation
jlegrand62 Jan 29, 2026
96f9fd4
Remove redundant active session checks from session creation and JWT …
jlegrand62 Jan 29, 2026
9e980aa
Improve documentation and formatting in client rest_api
jlegrand62 Jan 29, 2026
97d775b
Improve documentation and formatting in client rest_api
jlegrand62 Jan 29, 2026
1e3a61a
Add user registration endpoint to client API
jlegrand62 Jan 29, 2026
8471dea
Add user registration support and unify response checks
jlegrand62 Jan 29, 2026
db848ec
Use username in account lockout log message
jlegrand62 Jan 30, 2026
a08915a
Add JWT protection to scan‑related REST endpoints
jlegrand62 Jan 30, 2026
ac23fa0
Adjust client REST API to return raw Response objects and update exam…
jlegrand62 Jan 30, 2026
ff96930
Add session_token parameter to scan-related REST API functions
jlegrand62 Jan 30, 2026
ded451f
Add default_user support to wrapped database methods
jlegrand62 Jan 30, 2026
2310571
Rename `requires_jwt` decorator and update its usage
jlegrand62 Jan 30, 2026
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
19 changes: 19 additions & 0 deletions src/client/plantdb/client/api_endpoints.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,3 +451,22 @@ def scan_file(scan_id: str, file_path: str, **kwargs) -> str:
"""
scan_id = sanitize_name(scan_id)
return f"/files/{scan_id}/{file_path.lstrip('/')}"



@url_prefix
def create_user(**kwargs):
"""Create the user registration URL.

Returns
-------
str
The URL path for user registration.

Examples
--------
>>> from plantdb.client import api_endpoints
>>> api_endpoints.create_user()
'/register'
"""
return f"/register"
45 changes: 34 additions & 11 deletions src/client/plantdb/client/plantdb_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@

import requests
from ada_url import join_url
from plantdb.client import api_endpoints
from requests import RequestException

from plantdb.client import api_endpoints
from plantdb.commons.log import get_logger


Expand Down Expand Up @@ -148,7 +148,7 @@ def validate_session_token(self, token):
"""
url = join_url(self.base_url, api_endpoints.token_validation())
response = self.session.post(url, headers={"Authorization": f"Bearer {token}"})
if response.status_code == 200:
if response.ok:
self.jwt_token = token
self.username = response.json().get('username')
# Add the JWT to the header
Expand Down Expand Up @@ -182,10 +182,12 @@ def login(self, username: str, password: str) -> bool:

try:
response = self.session.post(url, json=data)
if response.status_code == 200:
if response.ok:
result = response.json()
self.jwt_token = result.get('access_token')
self.username = username
# Add the JWT to the header
self.session.headers.update({'Authorization': f'Bearer {self.jwt_token}'})
return True
else:
error_msg = response.json().get('message', 'Login failed')
Expand All @@ -208,7 +210,7 @@ def logout(self) -> bool:
url = join_url(self.base_url, api_endpoints.logout())
try:
response = self.session.post(url)
if response.status_code == 200:
if response.ok:
self.username = None
# Remove the Authorization with the JWT from the header
self.session.headers.pop('Authorization')
Expand All @@ -217,12 +219,34 @@ def logout(self) -> bool:
except Exception:
return False

def create_user(self, username: str, password: str, fullname: str) -> bool:
"""Create a new user in the PlantDB API."""
url = join_url(self.base_url, api_endpoints.create_user())
data = {
'username': username,
'password': password,
'fullname': fullname,
}

try:
response = self.session.post(url, json=data)
if response.ok:
return True
else:
error_msg = response.json().get('message', 'Unknown server error.')
self.logger.error(f"Failed to create user: {error_msg}")
return False

except RequestException as e:
self.logger.error(f"User registration request failed: {e}")
return False

def refresh(self) -> bool:
"""Refresh the database."""
url = join_url(self.base_url, api_endpoints.refresh())
try:
response = self.session.get(url)
if response.status_code == 200:
if response.ok:
return True
return False
except Exception:
Expand All @@ -233,7 +257,7 @@ def refresh_token(self) -> bool:
url = join_url(self.base_url, api_endpoints.token_refresh())
try:
response = self.session.post(url)
if response.status_code == 200:
if response.ok:
result = response.json()
self.jwt_token = result.get('access_token')
self.username = result.get('username')
Expand Down Expand Up @@ -739,7 +763,6 @@ def create_file(self, file_data, file_id, ext, scan_id, fileset_id, metadata=Non
>>> metadata = {'description': 'Random RGB test image', 'author': 'John Doe'}
>>> response = client.create_file(image_data, file_id='random_image', ext='png', scan_id='real_plant', fileset_id='images', metadata=metadata)
>>> print(response)

"""
import os
import json
Expand All @@ -748,8 +771,8 @@ def create_file(self, file_data, file_id, ext, scan_id, fileset_id, metadata=Non

url = f"{self.base_url}/api/file"

ext = ext.lstrip('.').lower() # Remove leading dot if present
# Prepare form data
ext = ext.lstrip('.').lower() # Remove the leading dot if present
# Prepare data
data = {
'file_id': file_id,
'ext': ext,
Expand All @@ -775,10 +798,10 @@ def create_file(self, file_data, file_id, ext, scan_id, fileset_id, metadata=Non
}
response = self.session.post(url, files=files, data=data)
else:
# Convert to Path object if it's a string
# Convert to a Path object if it's a string
file_path = Path(file_data) if isinstance(file_data, str) else file_data

# Handle file from path
# Handle file from a path
with open(file_path, 'rb') as file_handle:
filename = os.path.basename(str(file_path))
files = {
Expand Down
Loading
Loading