Skip to content

Commit 9ce291f

Browse files
authored
Merge pull request #770 from Arnthorny/feat/delete-invite-link
feat: endpoint to delete invites (superadmin)
2 parents a55ecef + 8e361de commit 9ce291f

File tree

3 files changed

+121
-3
lines changed

3 files changed

+121
-3
lines changed

Diff for: api/v1/routes/invitations.py

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
from fastapi import APIRouter, Depends, HTTPException, Request
1+
from fastapi import APIRouter, Depends, HTTPException, Request, status
22
from sqlalchemy.orm import Session
33
from urllib.parse import urlparse, parse_qs
44
from api.v1.schemas import invitations
55
from api.db.database import get_db as get_session
66
from api.v1.services import invite
77
from api.v1.models.user import User
8+
from api.utils.success_response import success_response
89
from api.v1.services.user import user_service
910
import logging
1011

@@ -42,4 +43,18 @@ async def add_user_to_organization(
4243

4344
logging.info(f"Processing invitation ID: {invite_id}")
4445

45-
return invite.InviteService.add_user_to_organization(invite_id, session)
46+
return invite.InviteService.add_user_to_organization(invite_id, session)
47+
48+
@invites.delete("/{invite_id}", status_code=status.HTTP_204_NO_CONTENT)
49+
def delete_invite(
50+
invite_id: str,
51+
db: Session = Depends(get_session),
52+
admin: User = Depends(user_service.get_current_super_admin)
53+
):
54+
""" Delete invite from database """
55+
invite_is_deleted = invite.InviteService.delete(db, invite_id)
56+
57+
if not invite_is_deleted:
58+
raise HTTPException(status_code=404, detail="Invalid invitation id")
59+
60+
logging.info(f"Deleted invite. ID: {invite_id}")

Diff for: api/v1/services/invite.py

+32-1
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111
from api.v1.models.user import User
1212
from api.v1.models.associations import user_organization_association
1313
from api.v1.schemas import invitations
14+
from api.core.base.services import Service
1415
from urllib.parse import urlencode
1516

1617

17-
class InviteService:
18+
class InviteService(Service):
1819
@staticmethod
1920
def create(
2021
invite: invitations.InvitationCreate, request: Request, session: Session
@@ -139,5 +140,35 @@ def add_user_to_organization(invite_id: str, session: Session):
139140
status_code=500,
140141
detail="An error occurred while adding the user to the organization",
141142
)
143+
@staticmethod
144+
def delete(session: Session, id: str):
145+
"""Function to delete invite link
146+
147+
Args:
148+
session(Session): The current ORM session object.
149+
id(str): Invite id string
150+
151+
Returns:
152+
True if delete is successful else False
153+
154+
"""
155+
invite = (
156+
session.query(Invitation).filter_by(id=id).first()
157+
)
158+
159+
if invite is None:
160+
return False
161+
session.delete(invite)
162+
session.commit()
163+
return True
164+
165+
def fetch(self):
166+
pass
167+
168+
def fetch_all(self):
169+
pass
142170

171+
def update(self):
172+
pass
173+
143174
invite_service = InviteService()

Diff for: tests/v1/invitation/test_delete_invitation.py

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Dependencies:
2+
# pip install pytest-mock
3+
import pytest
4+
from unittest.mock import patch, MagicMock
5+
from fastapi.testclient import TestClient
6+
from main import app
7+
from api.v1.services.user import user_service
8+
from api.db.database import get_db
9+
from sqlalchemy.orm import Session
10+
from datetime import datetime
11+
from api.v1.services.user import oauth2_scheme
12+
13+
14+
def mock_deps():
15+
return MagicMock(id="user_id")
16+
17+
def mock_oauth():
18+
return 'access_token'
19+
20+
def mock_db():
21+
return MagicMock(spec=Session)
22+
23+
@pytest.fixture
24+
def client():
25+
client = TestClient(app)
26+
yield client
27+
28+
DELETE_ENDPOINT = "/api/v1/invite/invite_id"
29+
class TestCodeUnderTest:
30+
@classmethod
31+
def setup_class(cls):
32+
app.dependency_overrides[user_service.get_current_super_admin] = mock_deps
33+
app.dependency_overrides[get_db] = mock_db
34+
35+
@classmethod
36+
def teardown_class(cls):
37+
app.dependency_overrides = {}
38+
39+
# Successfully delete invite from to the database
40+
def test_delete_invite_success(self, client):
41+
42+
response = client.delete(DELETE_ENDPOINT)
43+
44+
assert response.status_code == 204
45+
46+
# Invalid invite id
47+
def test_delete_invite_invalid_id(self, client):
48+
49+
50+
with patch('api.v1.services.invite.InviteService.delete', return_value=False) as tmp:
51+
response = client.delete(DELETE_ENDPOINT)
52+
assert response.status_code == 404
53+
assert response.json()['message'] == "Invalid invitation id"
54+
55+
# Handling unauthorized request
56+
def test_delete_invite_unauth(self, client):
57+
app.dependency_overrides = {}
58+
59+
response = client.delete(DELETE_ENDPOINT)
60+
assert response.status_code == 401
61+
assert response.json()['message'] == 'Not authenticated'
62+
63+
# Handling forbidden request
64+
def test_delete_invite_forbidden(self, client):
65+
app.dependency_overrides = {}
66+
app.dependency_overrides[get_db] = mock_db
67+
app.dependency_overrides[oauth2_scheme] = mock_oauth
68+
69+
with patch('api.v1.services.user.user_service.get_current_user', return_value=MagicMock(is_super_admin=False)) as cu:
70+
response = client.delete(DELETE_ENDPOINT)
71+
assert response.status_code == 403
72+
assert response.json()['message'] == 'You do not have permission to access this resource'

0 commit comments

Comments
 (0)