Skip to content

Commit ad65015

Browse files
authored
feature/event privacy + fix eventview error (#271)
1 parent 4c117a3 commit ad65015

File tree

10 files changed

+230
-76
lines changed

10 files changed

+230
-76
lines changed

app/database/models.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
from app.config import PSQL_ENVIRONMENT
2828
from app.dependencies import logger
29+
from app.internal.privacy import PrivacyKinds
2930
import app.routers.salary.config as SalaryConfig
3031

3132
Base: DeclarativeMeta = declarative_base()
@@ -95,6 +96,7 @@ class Event(Base):
9596
color = Column(String, nullable=True)
9697
all_day = Column(Boolean, default=False)
9798
invitees = Column(String)
99+
privacy = Column(String, default=PrivacyKinds.Public.name, nullable=False)
98100
emotion = Column(String, nullable=True)
99101
availability = Column(Boolean, default=True, nullable=False)
100102

app/internal/calendar_privacy.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from app.dependencies import get_db
22
from app.database.models import User
3+
from app.internal.privacy import PrivacyKinds
34
# TODO switch to using this when the user system is merged
45
# from app.internal.security.dependancies import (
56
# current_user, CurrentUser)
@@ -23,10 +24,10 @@ def can_show_calendar(
2324
).first()
2425
privacy = current_user.privacy
2526
is_current_user = current_user.username == requested_user.username
26-
if privacy == 'Private' and is_current_user:
27+
if privacy == PrivacyKinds.Private.name and is_current_user:
2728
return True
2829

29-
elif privacy == 'Public':
30+
elif privacy == PrivacyKinds.Public.name:
3031
return True
3132

3233
return False

app/internal/privacy.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import enum
2+
3+
4+
class PrivacyKinds(enum.Enum):
5+
Public = 1
6+
Private = 2
7+
Hidden = 3

app/routers/event.py

Lines changed: 78 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from sqlalchemy.exc import SQLAlchemyError
99
from sqlalchemy.orm import Session
1010
from sqlalchemy.orm.exc import MultipleResultsFound, NoResultFound
11+
from sqlalchemy.sql.elements import Null
1112
from starlette import status
1213
from starlette.responses import RedirectResponse, Response
1314
from starlette.templating import _TemplateResponse
@@ -22,10 +23,10 @@
2223
)
2324
from app.internal import comment as cmt
2425
from app.internal.emotion import get_emotion
26+
from app.internal.privacy import PrivacyKinds
2527
from app.internal.utils import create_model, get_current_user
2628
from app.routers.categories import get_user_categories
2729

28-
2930
EVENT_DATA = Tuple[Event, List[Dict[str, str]], str]
3031
TIME_FORMAT = "%Y-%m-%d %H:%M"
3132
START_FORMAT = "%A, %d/%m/%Y %H:%M"
@@ -82,13 +83,20 @@ async def create_event_api(event: EventModel, session=Depends(get_db)):
8283

8384
@router.get("/edit", include_in_schema=False)
8485
@router.get("/edit")
85-
async def eventedit(request: Request,
86-
db_session: Session = Depends(get_db)) -> Response:
87-
user_id = 1 # until issue#29 will get current user_id from session
86+
async def eventedit(
87+
request: Request,
88+
db_session: Session = Depends(get_db),
89+
) -> Response:
90+
user_id = 1 # until issue#29 will get current user_id from session
8891
categories_list = get_user_categories(db_session, user_id)
89-
return templates.TemplateResponse("eventedit.html",
90-
{"request": request,
91-
"categories_list": categories_list})
92+
return templates.TemplateResponse(
93+
"eventedit.html",
94+
{
95+
"request": request,
96+
"categories_list": categories_list,
97+
"privacy": PrivacyKinds,
98+
},
99+
)
92100

93101

94102
@router.post("/edit", include_in_schema=False)
@@ -111,8 +119,11 @@ async def create_new_event(
111119

112120
vc_link = data["vc_link"]
113121
category_id = data.get("category_id")
122+
privacy = data["privacy"]
123+
privacy_kinds = [kind.name for kind in PrivacyKinds]
124+
if privacy not in privacy_kinds:
125+
privacy = PrivacyKinds.Public.name
114126
is_google_event = data.get("is_google_event", "True") == "True"
115-
116127
invited_emails = get_invited_emails(data["invited"])
117128
uninvited_contacts = get_uninvited_regular_emails(
118129
session,
@@ -129,25 +140,35 @@ async def create_new_event(
129140
title=title,
130141
start=start,
131142
end=end,
132-
owner_id=owner_id,
133143
all_day=all_day,
144+
owner_id=owner_id,
134145
content=content,
135146
location=location,
136147
vc_link=vc_link,
137148
invitees=invited_emails,
138149
category_id=category_id,
139150
availability=availability,
140151
is_google_event=is_google_event,
152+
privacy=privacy,
141153
)
142154

143155
messages = get_messages(session, event, uninvited_contacts)
144156
return RedirectResponse(
145157
router.url_path_for("eventview", event_id=event.id)
146-
+ f'messages={"---".join(messages)}',
158+
+ f'?messages={"---".join(messages)}',
147159
status_code=status.HTTP_302_FOUND,
148160
)
149161

150162

163+
def raise_for_nonexisting_event(event_id: int) -> None:
164+
error_message = f"Event ID does not exist. ID: {event_id}"
165+
logger.exception(error_message)
166+
raise HTTPException(
167+
status_code=status.HTTP_404_NOT_FOUND,
168+
detail=error_message,
169+
)
170+
171+
151172
@router.get("/{event_id}", include_in_schema=False)
152173
async def eventview(
153174
request: Request,
@@ -159,12 +180,15 @@ async def eventview(
159180
if event.all_day:
160181
start_format = "%A, %d/%m/%Y"
161182
end_format = ""
183+
event_considering_privacy = event_to_show(event, db)
184+
if not event_considering_privacy:
185+
raise_for_nonexisting_event(event.id)
162186
messages = request.query_params.get("messages", "").split("---")
163187
return templates.TemplateResponse(
164188
"eventview.html",
165189
{
166190
"request": request,
167-
"event": event,
191+
"event": event_considering_privacy,
168192
"comments": comments,
169193
"start_format": start_format,
170194
"end_format": end_format,
@@ -173,6 +197,46 @@ async def eventview(
173197
)
174198

175199

200+
def check_event_owner(
201+
event: Event,
202+
session: Depends(get_db),
203+
user: Optional[User] = None,
204+
) -> bool:
205+
# TODO use current_user after user system merge
206+
if not user:
207+
user = get_current_user(session)
208+
is_owner = event.owner_id == user.id
209+
return is_owner
210+
211+
212+
def event_to_show(
213+
event: Event,
214+
session: Depends(get_db),
215+
user: Optional[User] = None,
216+
) -> Optional[Event]:
217+
"""Check the given event's privacy and return
218+
event/fixed private event/ nothing (hidden) accordingly"""
219+
is_owner = check_event_owner(event, session, user)
220+
if event.privacy == PrivacyKinds.Private.name and not is_owner:
221+
event_dict = event.__dict__.copy()
222+
if event_dict.get("_sa_instance_state", None):
223+
event_dict.pop("_sa_instance_state")
224+
event_dict.pop("id")
225+
private_event = Event(**event_dict)
226+
private_event.title = PrivacyKinds.Private.name
227+
private_event.content = PrivacyKinds.Private.name
228+
private_event.location = PrivacyKinds.Private.name
229+
private_event.color = Null
230+
private_event.invitees = PrivacyKinds.Private.name
231+
private_event.category_id = Null
232+
private_event.emotion = Null
233+
return private_event
234+
elif event.privacy == PrivacyKinds.Hidden.name and not is_owner:
235+
return
236+
elif event.privacy == PrivacyKinds.Public.name or is_owner:
237+
return event
238+
239+
176240
@router.post("/{event_id}/owner")
177241
async def change_owner(
178242
request: Request,
@@ -220,12 +284,7 @@ def by_id(db: Session, event_id: int) -> Event:
220284
try:
221285
event = db.query(Event).filter_by(id=event_id).one()
222286
except NoResultFound:
223-
error_message = f"Event ID does not exist. ID: {event_id}"
224-
logger.exception(error_message)
225-
raise HTTPException(
226-
status_code=status.HTTP_404_NOT_FOUND,
227-
detail=error_message,
228-
)
287+
raise_for_nonexisting_event(event_id)
229288
except MultipleResultsFound:
230289
error_message = (
231290
f"Multiple results found when getting event. Expected only one. "
@@ -337,6 +396,7 @@ def create_event(
337396
category_id: Optional[int] = None,
338397
availability: bool = True,
339398
is_google_event: bool = False,
399+
privacy: str = PrivacyKinds.Public.name,
340400
):
341401
"""Creates an event and an association."""
342402

@@ -348,6 +408,7 @@ def create_event(
348408
title=title,
349409
start=start,
350410
end=end,
411+
privacy=privacy,
351412
content=content,
352413
owner_id=owner_id,
353414
location=location,

app/routers/profile.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from app.internal.on_this_day_events import get_on_this_day_events
1414
from app.internal.import_holidays import (get_holidays_from_file,
1515
save_holidays_to_db)
16+
from app.internal.privacy import PrivacyKinds
1617

1718
PICTURE_EXTENSION = config.PICTURE_EXTENSION
1819
PICTURE_SIZE = config.AVATAR_SIZE
@@ -58,8 +59,9 @@ async def profile(
5859
"user": user,
5960
"events": upcoming_events,
6061
"signs": signs,
61-
'google_error': GOOGLE_ERROR,
62+
"google_error": GOOGLE_ERROR,
6263
"on_this_day_data": on_this_day_data,
64+
"privacy": PrivacyKinds
6365
})
6466

6567

app/templates/partials/calendar/event/edit_event_details_tab.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,9 @@
8080

8181
<label for="privacy">Privacy:</label>
8282
<select id="privacy" name="privacy">
83-
<option value="private">Private</option>
84-
<option value="public" selected>Public</option>
83+
<option value="{{ privacy.Private.name }}">{{ privacy.Private.name }}</option>
84+
<option value="{{ privacy.Public.name }}" selected>{{ privacy.Public.name }}</option>
85+
<option value="{{ privacy.Hidden.name }}">{{ privacy.Hidden.name }}</option>
8586
</select>
8687

8788
<label for="user_categories">Category</label>
@@ -104,4 +105,3 @@
104105

105106
</div>
106107
</div>
107-

app/templates/partials/user_profile/sidebar_left/profile_card/modals/calendar_privacy_modal.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ <h2 class="modal-title">Set your calendar privacy</h2>
77
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
88
</div>
99
<div class="modal-body">
10-
<form action="update_calendar_privacy" method="post">
10+
<form action="privacy" method="post">
1111
<select class="form-control-sm" name="privacy">
12-
<option value="private">Private</option>
13-
<option value="public">Public</option>
12+
<option value="{{ privacy.Private.name }}">{{ privacy.Private.name }}</option>
13+
<option value="{{ privacy.Public.name }}">{{ privacy.Public.name }}</option>
1414
</select>
1515
<div class="d-flex flex-row-reverse mt-4">
1616
<button type="submit" class="btn btn-sm btn-success">Save changes</button>
@@ -19,4 +19,4 @@ <h2 class="modal-title">Set your calendar privacy</h2>
1919
</div>
2020
</div>
2121
</div>
22-
</div>
22+
</div>

app/templates/profile.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@
1616
</div>
1717
</div>
1818
{% include "partials/calendar/event/text_editor_partial_body.html" %}
19-
{% endblock content %}
19+
{% endblock content %}

0 commit comments

Comments
 (0)