Skip to content

Commit 959b9c7

Browse files
committed
retry hackatime account link endpoint
1 parent d7507a3 commit 959b9c7

File tree

3 files changed

+61
-11
lines changed

3 files changed

+61
-11
lines changed

api/v1/auth/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ async def send_otp_code(to_email: str, old_email: Optional[str] = None) -> bool:
255255
use_tls=True,
256256
)
257257
except Exception as e:
258-
error("Error sending OTP email:", e)
258+
error("Error sending OTP email:", exc_info=e)
259259
raise HTTPException(status_code=500, detail="Error sending OTP email") from e
260260

261261
return True

api/v1/projects/main.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ async def link_hackatime_project(
252252
user.hackatime_id, project.hackatime_projects + [hackatime_project.name]
253253
)
254254
except Exception as e: # type: ignore # pylint: disable=broad-exception-caught
255-
error("Error fetching Hackatime projects:", e)
255+
error("Error fetching Hackatime projects:", exc_info=e)
256256
raise HTTPException(
257257
status_code=500, detail="Error fetching Hackatime projects"
258258
) from e
@@ -277,7 +277,7 @@ async def link_hackatime_project(
277277
return ProjectResponse.from_model(project)
278278
except Exception as e: # type: ignore # pylint: disable=broad-exception-caught
279279
await session.rollback()
280-
error("Error linking Hackatime project:", e)
280+
error("Error linking Hackatime project:", exc_info=e)
281281
raise HTTPException(
282282
status_code=500, detail="Error linking Hackatime project"
283283
) from e
@@ -327,7 +327,7 @@ async def unlink_hackatime_project(
327327
try:
328328
user_projects = get_projects(user.hackatime_id, new_projects)
329329
except Exception as e: # type: ignore # pylint: disable=broad-exception-caught
330-
error("Error fetching Hackatime projects:", e)
330+
error("Error fetching Hackatime projects:", exc_info=e)
331331
raise HTTPException(
332332
status_code=500, detail="Error fetching Hackatime projects"
333333
) from e
@@ -344,7 +344,7 @@ async def unlink_hackatime_project(
344344
return ProjectResponse.from_model(project)
345345
except Exception as e: # type: ignore # pylint: disable=broad-exception-caught
346346
await session.rollback()
347-
error("Error unlinking Hackatime project:", e)
347+
error("Error unlinking Hackatime project:", exc_info=e)
348348
raise HTTPException(
349349
status_code=500, detail="Error unlinking Hackatime project"
350350
) from e
@@ -411,5 +411,5 @@ async def create_project(
411411
return ProjectResponse.from_model(new_project)
412412
except Exception as e: # type: ignore # pylint: disable=broad-exception-caught
413413
await session.rollback()
414-
error("Error creating new project:", e)
415-
return HTTPException(status_code=500, detail="Error creating new project")
414+
error("Error creating new project:", exc_info=e)
415+
raise HTTPException(status_code=500, detail="Error creating new project")

api/v1/users/main.py

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
from api.v1.auth.main import require_auth, send_otp_code # type: ignore
2121
from db import get_db
22-
from lib.hackatime import get_projects
22+
from lib.hackatime import get_account, get_projects
2323
from models.user import User
2424

2525
router = APIRouter()
@@ -217,7 +217,7 @@ async def recalculate_hackatime_time(
217217
try:
218218
user_projects = get_projects(user.hackatime_id, list(all_hackatime_projects))
219219
except Exception as e: # type: ignore # pylint: disable=broad-exception-caught
220-
error("Error fetching Hackatime projects:", e)
220+
error("Error fetching Hackatime projects:", exc_info=e)
221221
raise HTTPException(
222222
status_code=500, detail="Error fetching Hackatime projects"
223223
) from e
@@ -242,15 +242,65 @@ async def recalculate_hackatime_time(
242242
return Response(status_code=204)
243243
except Exception as e: # type: ignore # pylint: disable=broad-exception-caught
244244
await session.rollback()
245-
error("Error updating Hackatime data:", e)
245+
error("Error updating Hackatime data:", exc_info=e)
246246
raise HTTPException(
247247
status_code=500, detail="Error updating Hackatime data"
248248
) from e
249249

250+
@router.get("/retry_hackatime_link")
251+
@require_auth
252+
async def retry_hackatime_link(
253+
request: Request,
254+
session: AsyncSession = Depends(get_db),
255+
):
256+
"""Retry linking Hackatime account for a user"""
257+
user_email = request.state.user["sub"]
250258

251-
# disabled for 30 days, no login -> delete
259+
user_raw = await session.execute(
260+
sqlalchemy.select(User).where(User.email == user_email)
261+
)
252262

263+
user = user_raw.scalar_one_or_none()
253264

265+
if user is None:
266+
raise HTTPException(
267+
status_code=404, detail="User not found"
268+
) # user doesn't exist
269+
270+
if user.hackatime_id:
271+
raise HTTPException(
272+
status_code=400, detail="User already has a linked Hackatime ID"
273+
)
274+
275+
hackatime_data = None
276+
try:
277+
hackatime_data = get_account(user_email)
278+
except Exception as e: # type: ignore # pylint: disable=broad-exception-caught
279+
error("Error fetching Hackatime account data:", exc_info=e)
280+
raise HTTPException(
281+
status_code=500, detail="Error fetching Hackatime account data"
282+
) from e
283+
284+
if not hackatime_data:
285+
raise HTTPException(
286+
status_code=404, detail="Hackatime account not found"
287+
)
288+
289+
user.hackatime_id = hackatime_data.id
290+
user.username = hackatime_data.username
291+
292+
try:
293+
await session.commit()
294+
await session.refresh(user)
295+
return Response(status_code=204)
296+
except Exception as e: # type: ignore # pylint: disable=broad-exception-caught
297+
await session.rollback()
298+
error("Error linking Hackatime account:", exc_info=e)
299+
raise HTTPException(
300+
status_code=500, detail="Error linking Hackatime account"
301+
) from e
302+
303+
# disabled for 30 days, no login -> delete
254304
# @protect
255305
async def is_pending_deletion():
256306
"""Check if a user account is pending deletion"""

0 commit comments

Comments
 (0)