Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 24 additions & 0 deletions .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FROM mcr.microsoft.com/devcontainers/python:3.12

# Install GitHub CLI
RUN rm -f /etc/apt/sources.list.d/yarn*.list || true && \
rm -f /etc/apt/trusted.gpg.d/yarn*.gpg || true && \
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg && \
echo "deb [signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | tee /etc/apt/sources.list.d/github-cli.list && \
apt-get update && \
apt-get install -y gh && \
apt-get clean && rm -rf /var/lib/apt/lists/*

# Install Railway CLI
RUN curl -fsSL https://railway.app/install.sh | bash

# Configure Git
RUN git config --global pull.ff true

# Install Poetry
RUN pip install poetry && \
poetry config virtualenvs.in-project true && \
poetry config virtualenvs.create true

# Install poetry-shell plugin
RUN poetry self add poetry-plugin-shell
8 changes: 5 additions & 3 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"name": "Python Flask DevContainer",
"image": "mcr.microsoft.com/devcontainers/python:3.12",
"build": {
"dockerfile": "Dockerfile"
},
"customizations": {
"vscode": {
"settings": {
Expand All @@ -12,6 +14,6 @@
]
}
},
"postCreateCommand": "bash .devcontainer/post-create.sh",
"postCreateCommand": "poetry install --no-root",
"remoteUser": "vscode"
}
}
27 changes: 0 additions & 27 deletions .devcontainer/post-create.sh

This file was deleted.

2 changes: 1 addition & 1 deletion campus_python/api/v1/submissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def update(

def submit(self) -> None:
"""Finalize/submit this submission (marks submitted_at timestamp)."""
path = f"{self.make_path()}/submit"
path = self.make_path("submit", end_slash=False)
resp = self.client.post(path)
resp.raise_for_status()
return None
Expand Down
8 changes: 4 additions & 4 deletions campus_python/api/v1/timetable.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ def __getitem__(self, timetable_id: str) -> "Timetables.Timetable":

def get_current(self) -> str:
"""Get the timetable ID of current timetable."""
resp = self.client.get(self.make_path("current"))
resp = self.client.get(self.make_path("current", end_slash=False))
resp.raise_for_status()
return resp.json()["value"]

def get_next(self) -> str:
"""Get the timetable ID of next timetable."""
resp = self.client.get(self.make_path("next"))
resp = self.client.get(self.make_path("next", end_slash=False))
resp.raise_for_status()
return resp.json()["value"]

Expand All @@ -79,7 +79,7 @@ def set_current(self, timetable_id: str) -> None:
timetable_id: ID of the timetable to set as current
"""
resp = self.client.put(
self.make_path("current"),
self.make_path("current", end_slash=False),
json={"value": timetable_id}
)
resp.raise_for_status()
Expand All @@ -91,7 +91,7 @@ def set_next(self, timetable_id: str) -> None:
timetable_id: ID of the timetable to set as next
"""
resp = self.client.put(
self.make_path("next"),
self.make_path("next", end_slash=False),
json={"value": timetable_id}
)
resp.raise_for_status()
Expand Down
6 changes: 3 additions & 3 deletions campus_python/auth/v1/clients.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def revoke(self) -> str:
Returns:
The newly generated client secret.
"""
resp = self.client.post(self.make_path("revoke"))
resp = self.client.post(self.make_path("revoke", end_slash=False))
# Raise error if status code is not 2XX or 3XX
resp.raise_for_status()
return resp.json()["secret"]
Expand Down Expand Up @@ -105,7 +105,7 @@ def grant(
vault: str,
permission: int,
) -> JsonDict:
resp = self.client.post(self.make_path("grant"), json={
resp = self.client.post(self.make_path("grant", end_slash=False), json={
"vault": vault,
"permission": permission,
})
Expand All @@ -118,7 +118,7 @@ def revoke(
vault: str,
permission: int,
) -> JsonDict:
resp = self.client.post(self.make_path("revoke"), json={
resp = self.client.post(self.make_path("revoke", end_slash=False), json={
"vault": vault,
"permission": permission,
})
Expand Down
4 changes: 2 additions & 2 deletions campus_python/auth/v1/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def __getitem__(self, session_id: str) -> "CampusSessions.Session":
def from_code(self, code: str) -> campus.model.AuthSession:
"""Get a session using authorization code."""
resp = self.client.post(
self.make_path("authorization_code"),
self.make_path("authorization_code", end_slash=False),
json={"code": code}
)
resp.raise_for_status()
Expand Down Expand Up @@ -85,7 +85,7 @@ def sweep(self, at_time: datetime | str | None = None) -> int:
json_data["at_time"] = schema.DateTime(at_time)
case None:
json_data["at_time"] = schema.DateTime.utcnow()
resp = self.client.post(self.make_path("sweep"), json=json_data)
resp = self.client.post(self.make_path("sweep", end_slash=False), json=json_data)
resp.raise_for_status()
return int(resp.json()["swept_count"])

Expand Down
2 changes: 1 addition & 1 deletion campus_python/auth/v1/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class User(Resource):
"""Single vault user resource."""

def activate(self) -> campus.model.User:
resp = self.client.post(self.make_path("activate"))
resp = self.client.post(self.make_path("activate", end_slash=False))
resp.raise_for_status()
return campus.model.User.from_resource(resp.json())

Expand Down
15 changes: 9 additions & 6 deletions campus_python/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,19 @@ def client(self) -> JsonClient:
return self.root.client
raise AttributeError(f"No client defined for {self}")

def make_path(self, part: str | None = None) -> str:
def make_path(self, part: str | None = None, end_slash: bool = True) -> str:
"""Create a full path for a resource collection.

Resource collection paths always end in a /.
Args:
part: Optional sub-resource or action path.
end_slash: Whether to add a trailing slash (default: True for collections).

Returns:
Full path for the resource collection or sub-resource.
"""
if part:
return (
f"/{self.root.make_path(self.path).strip(SLASH)}"
f"/{part.strip(SLASH)}/"
)
base = f"/{self.root.make_path(self.path).strip(SLASH)}/{part.strip(SLASH)}"
return f"{base}/" if end_slash else base
else:
return f"/{self.root.make_path(self.path).strip(SLASH)}/"

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "campus-api-python"
version = "0.1.60"
version = "0.1.61"
description = "Campus API for Python projects"
authors = ["NYJC Computing <nyjc.computing@nyjc.edu.sg>"]

Expand Down
Loading