Skip to content

Commit 9522545

Browse files
committed
Use the idiomatic None for no required grant instead of empty string
1 parent d08c67e commit 9522545

File tree

7 files changed

+80
-30
lines changed

7 files changed

+80
-30
lines changed

soauth/api/app_manager.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from typing import Annotated
66

77
from fastapi import APIRouter, Depends, HTTPException, Request, status
8+
from pydantic import BaseModel
89

910
from soauth.core.app import AppData
1011
from soauth.core.models import AppDetailResponse, AppRefreshResponse
@@ -36,6 +37,14 @@ async def handle_app_manager_user(request: Request) -> SOUserWithGrants:
3637
app_management_routes = APIRouter(tags=["App Management"])
3738

3839

40+
class AppCreationRequest(BaseModel):
41+
name: str
42+
domain: str
43+
redirect_url: str
44+
visibility_grant: str | None = None
45+
api_access: bool = False
46+
47+
3948
@app_management_routes.put(
4049
"/app",
4150
summary="Create a new application",
@@ -49,26 +58,22 @@ async def handle_app_manager_user(request: Request) -> SOUserWithGrants:
4958
},
5059
)
5160
async def create_app(
52-
name: str,
53-
domain: str,
54-
redirect_url: str,
55-
visibility_grant: str,
56-
api_access: bool,
61+
model: AppCreationRequest,
5762
user: AppManagerUser,
5863
conn: DatabaseDependency,
5964
settings: SettingsDependency,
6065
log: LoggerDependency,
6166
) -> AppRefreshResponse:
62-
log = log.bind(user=user, domain=domain)
67+
log = log.bind(user=user, creation_request=model)
6368
# Note: the 'user' as given by the auth system is not the same as our database
6469
# user, it's re-created from the webtoken.
6570
database_user = await user_service.read_by_id(user_id=user.user_id, conn=conn)
6671
app = await app_service.create(
67-
name=name,
68-
domain=domain,
69-
redirect_url=redirect_url,
70-
visibility_grant=visibility_grant,
71-
api_access=api_access,
72+
name=model.name,
73+
domain=model.domain,
74+
redirect_url=model.redirect_url,
75+
visibility_grant=model.visibility_grant,
76+
api_access=model.api_access,
7277
user=database_user,
7378
settings=settings,
7479
conn=conn,
@@ -102,7 +107,10 @@ async def apps(
102107
) -> list[AppData]:
103108
log = log.bind(user=user)
104109
created_by = None if "admin" in user.grants else user.user_id
105-
result = await app_service.get_app_list(created_by_user_id = created_by, user_name = user.display_name, conn=conn)
110+
database_user = await user_service.read_by_id(user_id=user.user_id, conn=conn)
111+
result = await app_service.get_app_list(
112+
created_by_user_id=created_by, user=database_user, conn=conn
113+
)
106114
log.bind(number_of_apps=len(result))
107115
await log.ainfo("api.appmanager.apps")
108116
return result

soauth/api/keys.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,30 @@ async def list(
8484
user: AuthenticatedUserDependency,
8585
) -> list[AppDetailResponse]:
8686
# In theory we can chain these futures, but not worth it.
87+
database_user = await user_service.read_by_id(user_id=user.user_id, conn=conn)
88+
89+
log = log.bind(user_id=database_user.user_id, user_name=database_user.user_name)
90+
8791
app_list = await app_service.get_app_list(
88-
created_by_user_id=None, user_name=user.display_name , conn=conn, require_api_access=False
92+
created_by_user_id=None, user=database_user, conn=conn, require_api_access=False
93+
)
94+
95+
log = log.bind(
96+
number_of_apps=len(app_list),
97+
app_list=[x.app_name for x in app_list],
8998
)
9099

91100
login_list = await refresh_service.get_all_logins_for_user(
92101
user_id=user.user_id, conn=conn, log=log
93102
)
94103

104+
log = log.bind(
105+
number_of_logins=len(login_list),
106+
login_list=[f"{y.app_id} ({y.app_name})" for y in login_list],
107+
)
108+
109+
await log.ainfo("api.key_management.list")
110+
95111
return [
96112
AppDetailResponse(app=x, users=[y for y in login_list if y.app_id == x.app_id])
97113
for x in app_list

soauth/app/apps.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,26 +57,31 @@ def app_create_post(
5757
log: LoggerDependency,
5858
name: Annotated[str, Form()],
5959
domain: Annotated[str, Form()],
60-
visibility_grant: Annotated[str, Form()],
6160
redirect: Annotated[str, Form()],
61+
visibility_grant: Annotated[str | None, Form()] = None,
6262
api: Annotated[bool | None, Form()] = None,
6363
):
64-
log = log.bind(domain=domain)
65-
6664
if api is None:
6765
api = False
6866

67+
if not visibility_grant:
68+
visibility_grant = None
69+
70+
content = {
71+
"name": name,
72+
"domain": domain,
73+
"redirect_url": redirect,
74+
"visibility_grant": visibility_grant,
75+
"api_access": api,
76+
}
77+
78+
log = log.bind(**content)
79+
6980
response = handle_request(
7081
url=f"{request.app.app_detail_url}",
7182
request=request,
7283
method="put",
73-
params={
74-
"name": name,
75-
"domain": domain,
76-
"redirect_url": redirect,
77-
"visibility_grant": visibility_grant,
78-
"api_access": api,
79-
},
84+
json=content,
8085
)
8186

8287
log.bind(response=response.json())

soauth/app/templates/app_detail.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ <h2>{{app.app_name}}</h2>
3636
<li><span class="nes-text is-primary">Created at</span> {{app.created_at}}</li>
3737
<li><span class="nes-text is-primary">Domain</span> {{app.domain}}</li>
3838
<li><span class="nes-text is-primary">API Access?</span> {{app.api_access}}</li>
39+
<li><span class="nes-text is-primary">Required grant</span> {{app.visibility_grant}}</li>
3940
</ul>
4041
</div>
4142
</section>

soauth/core/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class AppData(BaseModel):
1717
created_by_user_name: str | None
1818
created_at: datetime
1919
domain: str
20-
visibility_grant: str
20+
visibility_grant: str | None = None
2121

2222

2323
class LoggedInUserData(BaseModel):

soauth/database/app.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class App(SQLModel, table=True):
3030
created_at: datetime = Field(sa_column=Column(DateTime(timezone=True)))
3131

3232
domain: str
33-
visibility_grant: str = Field(default="")
33+
visibility_grant: str | None = None
3434

3535
key_pair_type: str
3636
# Note that the 'public key' is not really public - it should
@@ -53,7 +53,6 @@ def has_visibility_grant(self, user_grant: set[str]) -> bool:
5353
return True
5454
return self.visibility_grant in user_grant
5555

56-
5756
def to_core(self) -> AppData:
5857
return AppData(
5958
app_name=self.app_name,

soauth/service/app.py

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
from soauth.core.uuid import UUID
1616
from soauth.database.app import App
1717
from soauth.database.user import User
18-
from soauth.service import user as user_service
1918

2019

2120
class AppNotFound(Exception):
@@ -70,7 +69,7 @@ async def create(
7069

7170
async def get_app_list(
7271
created_by_user_id: UUID | None,
73-
user_name: str,
72+
user: User,
7473
conn: AsyncSession,
7574
require_api_access: bool = False,
7675
) -> list[AppData]:
@@ -87,9 +86,31 @@ async def get_app_list(
8786
if require_api_access:
8887
query = query.filter_by(api_access=True)
8988

89+
grants = user.get_effective_grants()
90+
91+
if "admin" not in grants:
92+
query = query.filter(
93+
App.visibility_grant.in_(grants) | App.visibility_grant.is_(None)
94+
)
95+
9096
res = await conn.execute(query)
91-
user_details = await user_service.read_by_name(user_name=user_name, conn=conn)
92-
return [x.to_core() for x in res.scalars().unique().all() if x.has_visibility_grant(user_details.get_effective_grants())]
97+
98+
# Check again, make sure our results do really have the right visibility
99+
# grant.
100+
101+
apps = res.unique().scalars().all()
102+
103+
for app in apps:
104+
if "admin" not in grants and app.visibility_grant not in grants:
105+
if app.visibility_grant is None:
106+
continue
107+
108+
raise AppNotFound(
109+
f"User {user.user_name} does not have visibility grant "
110+
f"{app.visibility_grant} for app {app.app_name}."
111+
)
112+
113+
return [app.to_core() for app in apps]
93114

94115

95116
async def read_by_id(app_id: UUID, conn: AsyncSession) -> App:

0 commit comments

Comments
 (0)