Skip to content

Commit 4bc25fe

Browse files
authored
feat: Various different commands (#35)
1 parent fbe47f3 commit 4bc25fe

29 files changed

+591
-286
lines changed

Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ dev/run: build/.certificate_sentinel
4545
docker compose -f docker-compose.development.yml up -d
4646
SOPH__CONFIG_YAML_FILE=configurations/dev.yaml poetry run python src/sophrosyne/main.py run
4747

48+
.PHONY: dev/db/up
49+
dev/db/up:
50+
docker compose -f docker-compose.development.yml up -d
51+
4852
.PHONY: dev/db/down
4953
dev/db/down:
5054
docker compose -f docker-compose.development.yml down

alembic.ini

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[alembic]
44
# path to migration scripts
5-
script_location = migrations
5+
script_location = src/sophrosyne/migrations
66

77
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
88
# Uncomment the line below if you want the files to be prepended with date and time
@@ -58,7 +58,7 @@ version_path_separator = os # Use os.pathsep. Default configuration used for ne
5858
# are written from script.py.mako
5959
# output_encoding = utf-8
6060

61-
sqlalchemy.url = postgresql+asyncpg://localhost:5432/postgres
61+
sqlalchemy.url = postgresql+asyncpg://postgres:postgres@localhost:5432/postgres
6262

6363

6464
[post_write_hooks]
@@ -111,4 +111,4 @@ formatter = generic
111111

112112
[formatter_generic]
113113
format = %(levelname)-5.5s [%(name)s] %(message)s
114-
datefmt = %H:%M:%S
114+
datefmt = %H:%MWARNu

configurations/dev.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
security:
22
site_key: '6fAkguc1RQkgdWwoLdslkQjA/N5ujPvGEmG2l97Gt+4='
33
salt: 'KULByt65QDNWy4BhtkOagb3td08q992ZfPWLthFw00s='
4+
outgoing_tls_verify: False
45
development:
56
static_root_token: "thisisastaticroottoken"
67
logging:

migrations/README

-1
This file was deleted.

pyproject.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,13 @@ packages = [ "sophrosyne" ]
8080
type = "markdown"
8181
filename = "docs/api.md"
8282

83+
[tool.ruff]
84+
extend-exclude = ["*_pb2.py", "*_pb2_grpc.py", "*_pb2.pyi", "*/migrations/versions/*.py"]
85+
8386
[tool.ruff.lint]
8487
# Enable all `pydocstyle` rules, limiting to those that adhere to the
8588
# Google convention via `convention = "google"`, below.
86-
select = ["D", "I"]
89+
select = ["D", "I", "F"]
8790

8891
[tool.ruff.lint.pydocstyle]
8992
convention = "google"

src/sophrosyne/api/__init__.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
api_router (APIRouter): The API router for the API.
55
"""
66

7-
from typing import Annotated
8-
9-
from fastapi import APIRouter, Depends
7+
from fastapi import APIRouter
108

119
from sophrosyne.api.routers.health import router as health_router
1210
from sophrosyne.api.v1.api import api_router as v1_api_router

src/sophrosyne/api/v1/api.py

-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
api_router (APIRouter): The API router for the v1 version of the API.
88
"""
99

10-
from typing import Annotated
1110

1211
from fastapi import APIRouter, Depends
1312

src/sophrosyne/api/v1/models.py

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
should be defined in the core.models module instead.
1717
"""
1818

19-
from datetime import datetime
2019
from typing import Annotated, Literal, Union
2120

2221
from pydantic import EmailStr, Field

src/sophrosyne/api/v1/routers/checks.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
from sophrosyne.api.v1.tags import Tags
2626
from sophrosyne.core.models import Check, Profile
2727

28+
CHECK_NOT_FOUND: str = "Check not found"
29+
2830
router = APIRouter(dependencies=[Depends(require_admin)])
2931

3032

@@ -113,7 +115,7 @@ async def read_check(
113115
result = await db_session.exec(select(Check).where(Check.name == req.name))
114116
check = result.first()
115117
if not check:
116-
raise HTTPException(status_code=404, detail="Check not found")
118+
raise HTTPException(status_code=404, detail=CHECK_NOT_FOUND)
117119
return ChecksListCheckResponse.model_validate(
118120
check, update={"profiles": [p.name for p in check.profiles]}
119121
)
@@ -142,7 +144,7 @@ async def update_check(
142144
result = await db_session.exec(select(Check).where(Check.name == req.name))
143145
db_check = result.first()
144146
if not db_check:
145-
raise HTTPException(status_code=404, detail="Check not found")
147+
raise HTTPException(status_code=404, detail=CHECK_NOT_FOUND)
146148

147149
if req.profiles is not None:
148150
db_profiles = await db_session.exec(
@@ -175,7 +177,7 @@ async def delete_check(
175177
result = await db_session.exec(select(Check).where(Check.name == req.name))
176178
db_check = result.first()
177179
if not db_check:
178-
raise HTTPException(status_code=404, detail="Check not found")
180+
raise HTTPException(status_code=404, detail=CHECK_NOT_FOUND)
179181
await db_session.delete(db_check)
180182
await db_session.commit()
181183
return ChecksDeleteCheckResponse(ok=True)

src/sophrosyne/api/v1/routers/profiles.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
router (APIRouter): The FastAPI router for the profiles API.
55
"""
66

7-
from typing import Sequence
8-
97
from fastapi import APIRouter, Depends, HTTPException, Query
108
from sqlmodel import col, select
119
from sqlmodel.ext.asyncio.session import AsyncSession
@@ -27,6 +25,8 @@
2725

2826
router = APIRouter(dependencies=[Depends(require_admin)])
2927

28+
PROFILE_NOT_FOUND: str = "Profile not found"
29+
3030

3131
@router.post(
3232
"/profiles/create-profile",
@@ -125,7 +125,7 @@ async def read_profile(
125125
result = await db_session.exec(select(Profile).where(Profile.name == req.name))
126126
profile = result.first()
127127
if not profile:
128-
raise HTTPException(status_code=404, detail="Profile not found")
128+
raise HTTPException(status_code=404, detail=PROFILE_NOT_FOUND)
129129
return ProfilesListProfileResponse.model_validate(
130130
profile, update={"checks": [c.name for c in profile.checks]}
131131
)
@@ -156,7 +156,7 @@ async def update_profile(
156156
result = await db_session.exec(select(Profile).where(Profile.name == req.name))
157157
db_profile = result.first()
158158
if not db_profile:
159-
raise HTTPException(status_code=404, detail="Profile not found")
159+
raise HTTPException(status_code=404, detail=PROFILE_NOT_FOUND)
160160

161161
if req.checks is not None:
162162
db_checks = await db_session.exec(
@@ -198,7 +198,7 @@ async def delete_profile(
198198
result = await db_session.exec(select(Profile).where(Profile.name == req.name))
199199
db_profile = result.first()
200200
if not db_profile:
201-
raise HTTPException(status_code=404, detail="Profile not found")
201+
raise HTTPException(status_code=404, detail=PROFILE_NOT_FOUND)
202202
await db_session.delete(db_profile)
203203
await db_session.commit()
204204
return ProfilesDeleteProfileResponse(ok=True)

src/sophrosyne/api/v1/routers/safety.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44
router (APIRouter): The FastAPI router for the safety endpoints.
55
"""
66

7-
from typing import Annotated, Literal, Union
7+
from typing import Annotated
88

99
from fastapi import APIRouter, Body, Depends
10-
from pydantic import Field
1110

1211
from sophrosyne.api.dependencies import auth_and_return_user, get_safety_service
1312
from sophrosyne.api.v1.models import (

src/sophrosyne/api/v1/routers/users.py

+28-16
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
from sqlmodel import select
99
from sqlmodel.ext.asyncio.session import AsyncSession
1010

11-
from sophrosyne.api.dependencies import auth_and_return_user, get_db_session, require_admin
11+
from sophrosyne.api.dependencies import (
12+
auth_and_return_user,
13+
get_db_session,
14+
require_admin,
15+
)
1216
from sophrosyne.api.v1.models import (
1317
UsersCreateUserRequest,
1418
UsersCreateUserResponse,
@@ -28,22 +32,25 @@
2832

2933
router = APIRouter()
3034

35+
USER_NOT_FOUND = "User not found"
36+
3137

3238
@router.post(
33-
"/users/create-user", response_model=UsersCreateUserResponse, tags=[Tags.users]
39+
"/users/create-user",
40+
response_model=UsersCreateUserResponse,
41+
tags=[Tags.users],
42+
dependencies=[Depends(require_admin)],
3443
)
3544
async def create_user(
3645
*,
3746
db_session: AsyncSession = Depends(get_db_session),
3847
user: UsersCreateUserRequest,
39-
require_admin=Depends(require_admin),
4048
):
4149
"""Create a new user.
4250
4351
Args:
4452
db_session (AsyncSession): The database session.
4553
user (UsersCreateUserRequest): The request payload containing user data.
46-
require_admin (bool): The admin requirement dependency.
4754
4855
Returns:
4956
UsersCreateUserResponse: The newly created user.
@@ -62,22 +69,23 @@ async def create_user(
6269

6370

6471
@router.get(
65-
"/users/list-users", response_model=UsersListUsersResponse, tags=[Tags.users]
72+
"/users/list-users",
73+
response_model=UsersListUsersResponse,
74+
tags=[Tags.users],
75+
dependencies=Depends(require_admin),
6676
)
6777
async def read_users(
6878
*,
6979
db_session: AsyncSession = Depends(get_db_session),
7080
offset: int = 0,
7181
limit: int = Query(100, le=100),
72-
require_admin=Depends(require_admin),
7382
):
7483
"""Retrieve a list of users from the database.
7584
7685
Args:
7786
db_session (AsyncSession): The database session.
7887
offset (int): The offset for pagination. Defaults to 0.
7988
limit (int): The maximum number of users to retrieve. Defaults to 100.
80-
require_admin (bool): The admin requirement dependency.
8189
8290
Returns:
8391
UsersListUsersResponse: A list of user objects.
@@ -117,20 +125,22 @@ async def read_user(
117125
result = await db_session.exec(select(User).where(User.name == req.name))
118126
user = result.first()
119127
if not user:
120-
raise HTTPException(status_code=400, detail="User not found")
128+
raise HTTPException(status_code=400, detail=USER_NOT_FOUND)
121129
if current_user.name != user.name:
122-
raise HTTPException(status_code=403, detail="User not found")
130+
raise HTTPException(status_code=403, detail=USER_NOT_FOUND)
123131
return user
124132

125133

126134
@router.patch(
127-
"/users/update-user", response_model=UsersUpdateUserResponse, tags=[Tags.users]
135+
"/users/update-user",
136+
response_model=UsersUpdateUserResponse,
137+
tags=[Tags.users],
138+
dependencies=[Depends(require_admin)],
128139
)
129140
async def update_user(
130141
*,
131142
db_session: AsyncSession = Depends(get_db_session),
132143
req: UsersUpdateUserRequest,
133-
require_admin=Depends(require_admin),
134144
):
135145
"""Update a user in the database.
136146
@@ -147,7 +157,7 @@ async def update_user(
147157
result = await db_session.exec(select(User).where(User.name == req.name))
148158
db_user = result.first()
149159
if not db_user:
150-
raise HTTPException(status_code=400, detail="User not found")
160+
raise HTTPException(status_code=400, detail=USER_NOT_FOUND)
151161
user_data = req.model_dump(exclude_unset=True)
152162
db_user.sqlmodel_update(user_data)
153163
db_session.add(db_user)
@@ -157,13 +167,15 @@ async def update_user(
157167

158168

159169
@router.delete(
160-
"/users/delete-user", response_model=UsersDeleteUserResponse, tags=[Tags.users]
170+
"/users/delete-user",
171+
response_model=UsersDeleteUserResponse,
172+
tags=[Tags.users],
173+
dependencies=[Depends(require_admin)],
161174
)
162175
async def delete_user(
163176
*,
164177
db_session: AsyncSession = Depends(get_db_session),
165178
req: UsersDeleteUserRequest,
166-
require_admin=Depends(require_admin),
167179
):
168180
"""Delete a user from the database.
169181
@@ -177,7 +189,7 @@ async def delete_user(
177189
result = await db_session.exec(select(User).where(User.name == req.name))
178190
db_user = result.first()
179191
if not db_user:
180-
raise HTTPException(status_code=400, detail="User not found")
192+
raise HTTPException(status_code=400, detail=USER_NOT_FOUND)
181193
await db_session.delete(db_user)
182194
await db_session.commit()
183195
return UsersDeleteUserResponse(ok=True)
@@ -208,7 +220,7 @@ async def rotate_user_token(
208220
result = await db_session.exec(select(User).where(User.name == req.name))
209221
db_user = result.first()
210222
if not db_user:
211-
raise HTTPException(status_code=400, detail="User not found")
223+
raise HTTPException(status_code=400, detail=USER_NOT_FOUND)
212224
if current_user.name != db_user.name and not current_user.is_admin:
213225
raise HTTPException(status_code=403, detail="Not authorized")
214226
token = new_token()

0 commit comments

Comments
 (0)