Skip to content

Commit e022465

Browse files
committed
merging in remote main
2 parents b50cdf5 + 405c33c commit e022465

32 files changed

+942
-153
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: Auto Milestone Management
2+
on:
3+
pull_request:
4+
branches:
5+
- main
6+
types:
7+
- closed
8+
9+
permissions:
10+
issues: write
11+
pull-requests: write
12+
13+
jobs:
14+
add-milestone:
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Add milestone on PR merge
18+
if: github.event.pull_request.merged == true
19+
uses: actions/github-script@v8
20+
with:
21+
script: |
22+
const date = new Date();
23+
const month = date.getMonth() + 1;
24+
const year = date.getFullYear();
25+
const yy = String(year % 100);
26+
27+
let term;
28+
if (month <= 4) term = "W";
29+
else if (month >= 9) term = "F";
30+
else term = "S";
31+
32+
const format = yy + term;
33+
34+
const { data: milestones } = await github.rest.issues.listMilestones({
35+
owner: context.repo.owner,
36+
repo: context.repo.repo,
37+
state: "open"
38+
});
39+
40+
let milestone = null;
41+
for (let i = 0; i < milestones.length; i++) {
42+
if (milestones[i].title == format) {
43+
milestone = milestones[i];
44+
break;
45+
}
46+
}
47+
48+
if (!milestone) {
49+
const { data: new_milestone } = await github.rest.issues.createMilestone({
50+
owner: context.repo.owner,
51+
repo: context.repo.repo,
52+
title: format
53+
});
54+
milestone = new_milestone;
55+
}
56+
57+
await github.rest.issues.update({
58+
owner: context.repo.owner,
59+
repo: context.repo.repo,
60+
issue_number: context.payload.pull_request.number,
61+
milestone: milestone.number
62+
});

.github/workflows/pytest.yml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,26 @@ jobs:
3030
pip install -r requirements.txt
3131
pip install -e .
3232
33+
- name: Set up PostgreSQL database
34+
run: |
35+
sudo service postgresql start
36+
sudo -u postgres psql -c "CREATE USER ci_user WITH PASSWORD 'ci_password' SUPERUSER;"
37+
sudo -u postgres psql -c "CREATE DATABASE gs;"
38+
39+
- name: Create CI .env file
40+
run: |
41+
cat > .env << EOF
42+
GS_DATABASE_USER=ci_user
43+
GS_DATABASE_PASSWORD=ci_password
44+
GS_DATABASE_LOCATION=localhost
45+
GS_DATABASE_PORT=5432
46+
GS_DATABASE_NAME=gs
47+
EOF
48+
49+
- name: Run Alembic migrations
50+
run: |
51+
alembic upgrade head
52+
3353
- name: Create binary directory
3454
run: |
3555
mkdir build_gs
@@ -42,5 +62,11 @@ jobs:
4262
cmake --build .
4363
4464
- name: Run pytest
65+
env:
66+
GS_DATABASE_USER: ci_user
67+
GS_DATABASE_PASSWORD: ci_password
68+
GS_DATABASE_LOCATION: localhost
69+
GS_DATABASE_PORT: 5432
70+
GS_DATABASE_NAME: gs
4571
run: |
4672
python -m pytest

Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ FROM python:3.11-slim
33
WORKDIR /app
44
COPY requirements.txt /app/
55
COPY /gs/backend /app/
6+
RUN apt-get update && apt-get install -y gcc build-essential
67
RUN pip install -r requirements.txt
78
EXPOSE 8000
89

9-
CMD ["fastapi", "run", "gs/backend/main.py"]
10+
#CMD ["fastapi", "run", "gs/backend/main.py"]
11+
CMD ["uvicorn", "gs.backend.main:app", "--host", "0.0.0.0", "--port", "8000"]

alembic.ini

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# A generic, single database configuration.
2+
3+
[alembic]
4+
# path to migration scripts
5+
script_location = migrations
6+
7+
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
8+
# Uncomment the line below if you want the files to be prepended with date and time
9+
# see https://alembic.sqlalchemy.org/en/latest/tutorial.html#editing-the-ini-file
10+
# for all available tokens
11+
# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
12+
13+
# sys.path path, will be prepended to sys.path if present.
14+
# defaults to the current working directory.
15+
prepend_sys_path = .
16+
17+
# timezone to use when rendering the date within the migration file
18+
# as well as the filename.
19+
# If specified, requires the python-dateutil library that can be
20+
# installed by adding `alembic[tz]` to the pip requirements
21+
# string value is passed to dateutil.tz.gettz()
22+
# leave blank for localtime
23+
# timezone =
24+
25+
# max length of characters to apply to the
26+
# "slug" field
27+
# truncate_slug_length = 40
28+
29+
# set to 'true' to run the environment during
30+
# the 'revision' command, regardless of autogenerate
31+
# revision_environment = false
32+
33+
# set to 'true' to allow .pyc and .pyo files without
34+
# a source .py file to be detected as revisions in the
35+
# versions/ directory
36+
# sourceless = false
37+
38+
# version location specification; This defaults
39+
# to migrations/versions. When using multiple version
40+
# directories, initial revisions must be specified with --version-path.
41+
# The path separator used here should be the separator specified by "version_path_separator" below.
42+
# version_locations = %(here)s/bar:%(here)s/bat:migrations/versions
43+
44+
# version path separator; As mentioned above, this is the character used to split
45+
# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep.
46+
# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas.
47+
# Valid values for version_path_separator are:
48+
#
49+
# version_path_separator = :
50+
# version_path_separator = ;
51+
# version_path_separator = space
52+
version_path_separator = os # Use os.pathsep. Default configuration used for new projects.
53+
54+
# set to 'true' to search source files recursively
55+
# in each "version_locations" directory
56+
# new in Alembic version 1.10
57+
# recursive_version_locations = false
58+
59+
# the output encoding used when revision files
60+
# are written from script.py.mako
61+
# output_encoding = utf-8
62+
63+
sqlalchemy.url = driver://user:pass@localhost/dbname
64+
65+
66+
[post_write_hooks]
67+
# post_write_hooks defines scripts or Python functions that are run
68+
# on newly generated revision scripts. See the documentation for further
69+
# detail and examples
70+
71+
# format using "black" - use the console_scripts runner, against the "black" entrypoint
72+
# hooks = black
73+
# black.type = console_scripts
74+
# black.entrypoint = black
75+
# black.options = -l 79 REVISION_SCRIPT_FILENAME
76+
77+
# Logging configuration
78+
[loggers]
79+
keys = root,sqlalchemy,alembic
80+
81+
[handlers]
82+
keys = console
83+
84+
[formatters]
85+
keys = generic
86+
87+
[logger_root]
88+
level = WARN
89+
handlers = console
90+
qualname =
91+
92+
[logger_sqlalchemy]
93+
level = WARN
94+
handlers =
95+
qualname = sqlalchemy.engine
96+
97+
[logger_alembic]
98+
level = INFO
99+
handlers =
100+
qualname = alembic
101+
102+
[handler_console]
103+
class = StreamHandler
104+
args = (sys.stderr,)
105+
level = NOTSET
106+
formatter = generic
107+
108+
[formatter_generic]
109+
format = %(levelname)-5.5s [%(name)s] %(message)s
110+
datefmt = %H:%M:%S

gs/backend/api/backend_setup.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import logging
2+
13
from fastapi import FastAPI
4+
from loguru import logger
25

36
from gs.backend.api.middleware.auth_middleware import AuthMiddleware
47
from gs.backend.api.middleware.cors_middleware import add_cors_middleware
@@ -37,3 +40,18 @@ def setup_middlewares(app: FastAPI) -> None:
3740
LoggerMiddleware,
3841
excluded_endpoints=backend_config.logger_config.excluded_endpoints,
3942
)
43+
44+
45+
def setup_logging() -> None:
46+
"""Sets all logs from SQLAlchemy to the custom logger level VERBOSE"""
47+
verbose_level = 15 # DEBUG=10, INFO=20
48+
logger.level("VERBOSE", no=verbose_level, color="<blue>")
49+
50+
class SQLAlchemyHandler(logging.Handler):
51+
def emit(self, record: logging.LogRecord) -> None:
52+
logger.log("VERBOSE", record.getMessage())
53+
54+
sqlalchemy_logger = logging.getLogger("sqlalchemy.engine")
55+
sqlalchemy_logger.setLevel(logging.INFO)
56+
sqlalchemy_logger.addHandler(SQLAlchemyHandler())
57+
sqlalchemy_logger.propagate = False
Lines changed: 28 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
from uuid import UUID
22

3-
from fastapi import APIRouter, HTTPException
3+
from fastapi import APIRouter
44

55
from gs.backend.api.v1.aro.models.requests import UserRequest
66
from gs.backend.api.v1.aro.models.responses import AllUsersResponse, UserResponse
7-
from gs.backend.data.data_wrappers.aro_wrapper.aro_user_data_wrapper import (
8-
add_user,
9-
delete_user_by_id,
10-
update_user_by_id,
11-
)
12-
from gs.backend.data.data_wrappers.aro_wrapper.aro_user_data_wrapper import get_all_users as get_all_db_users
7+
from gs.backend.data.data_wrappers.wrappers import AROUsersWrapper
138

149
aro_user_router = APIRouter(tags=["ARO", "User Information"])
1510

@@ -21,10 +16,22 @@ async def get_all_users() -> AllUsersResponse:
2116
2217
:return: all users
2318
"""
24-
users = get_all_db_users()
19+
users = AROUsersWrapper().get_all()
2520
return AllUsersResponse(data=users)
2621

2722

23+
@aro_user_router.get("/get_user/{userid}", response_model=UserResponse)
24+
def get_user(userid: str) -> UserResponse:
25+
"""
26+
Gets a user by ID
27+
28+
:param userid: The unique identifier of the user
29+
:return: the user
30+
"""
31+
user = AROUsersWrapper().get_by_id(UUID(userid))
32+
return UserResponse(data=user)
33+
34+
2835
@aro_user_router.post("/create_user", response_model=UserResponse)
2936
def create_user(payload: UserRequest) -> UserResponse:
3037
"""
@@ -33,48 +40,25 @@ def create_user(payload: UserRequest) -> UserResponse:
3340
:return: returns the user created
3441
"""
3542

36-
user = add_user(
37-
call_sign=payload.call_sign,
38-
email=payload.email,
39-
f_name=payload.first_name,
40-
l_name=payload.last_name,
41-
phone_number=payload.phone_number,
43+
user = AROUsersWrapper().create(
44+
data={
45+
"call_sign": payload.call_sign,
46+
"email": payload.email,
47+
"first_name": payload.first_name,
48+
"last_name": payload.last_name,
49+
"phone_number": payload.phone_number,
50+
}
4251
)
4352

4453
return UserResponse(data=user)
4554

4655

47-
@aro_user_router.put("/update_user/{userid}", response_model=UserResponse)
48-
def update_user(userid: str, payload: UserRequest) -> UserResponse:
49-
"""
50-
Modifies the user’s info based on the payload
51-
:param userid: The unique identifier of the user to be updated
52-
:param payload: The data used to update a user
53-
:return: returns the user updated
54-
"""
55-
try:
56-
user = update_user_by_id(
57-
userid=UUID(userid),
58-
call_sign=payload.call_sign,
59-
email=payload.email,
60-
f_name=payload.first_name,
61-
l_name=payload.last_name,
62-
phone_number=payload.phone_number,
63-
)
64-
return UserResponse(data=user)
65-
except ValueError as e:
66-
raise HTTPException(status_code=404, detail=str(e)) from e
67-
68-
69-
@aro_user_router.delete("/delete_user/{userid}", response_model=AllUsersResponse)
70-
def delete_user(userid: str) -> AllUsersResponse:
56+
@aro_user_router.delete("/delete_user/{userid}", response_model=UserResponse)
57+
def delete_user(userid: str) -> UserResponse:
7158
"""
7259
Deletes a user based on the user ID
7360
:param userid: The unique identifier of the user to be deleted
74-
:return: returns the user deleted
61+
:return: returns the deleted user
7562
"""
76-
try:
77-
users = delete_user_by_id(UUID(userid))
78-
return AllUsersResponse(data=users)
79-
except ValueError as e:
80-
raise HTTPException(status_code=404, detail=str(e)) from e
63+
deleted_user = AROUsersWrapper().delete_by_id(UUID(userid))
64+
return UserResponse(data=deleted_user)

0 commit comments

Comments
 (0)