Skip to content

Commit

Permalink
Adjust CALDAV.test_connection to return a boolean or raise an excepti…
Browse files Browse the repository at this point in the history
…on with a message. (Fixes #802) (#805)

* Adjust CALDAV.test_connection to return a boolean or raise an exception with a message. (Fixes #802)

* 🌐 Add German translation

---------

Co-authored-by: Andreas Müller <[email protected]>
  • Loading branch information
MelissaAutumn and devmount authored Dec 20, 2024
1 parent 06f0c52 commit db8186e
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 10 deletions.
23 changes: 18 additions & 5 deletions backend/src/appointment/controller/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from ..database.models import CalendarProvider, BookingStatus
from ..database import schemas, models, repo
from ..controller.mailer import Attachment
from ..exceptions.calendar import TestConnectionFailed
from ..exceptions.validation import RemoteCalendarConnectionError
from ..l10n import l10n
from ..tasks.emails import send_invite_email, send_pending_email, send_rejection_email
Expand Down Expand Up @@ -329,24 +330,36 @@ def test_connection(self) -> bool:
except IndexError as ex:
# Library has an issue with top level urls, probably due to caldav spec?
logging.error(f'IE: Error testing connection {ex}')
return False
raise TestConnectionFailed(reason=None)
except KeyError as ex:
logging.error(f'KE: Error testing connection {ex}')
return False
raise TestConnectionFailed(reason=None)
except requests.exceptions.RequestException:
raise TestConnectionFailed(reason=None)
except NotImplementedError:
# Doesn't support authorization by digest, bearer, or basic header values
raise TestConnectionFailed(reason=l10n('remote-calendar-reason-doesnt-support-auth'))
except (
requests.exceptions.RequestException,
caldav.lib.error.NotFoundError,
caldav.lib.error.PropfindError,
caldav.lib.error.AuthorizationError
) as ex:
"""
RequestException: Max retries exceeded, bad connection, missing schema, etc...
NotFoundError: Good server, bad url.
PropfindError: Some properties could not be retrieved.
AuthorizationError: Credentials are not accepted.
"""
logging.error(f'Test Connection Error: {ex}')
return False

# Don't use the default "no reason" error message if we encounter it.
if ex.reason == caldav.lib.error.DAVError.reason:
ex.reason = None
if ex.reason == 'Unauthorized':
# ex.reason seems to be pulling from status codes for some errors?
# Let's replace this with our own.
ex.reason = l10n('remote-calendar-reason-unauthorized')

raise TestConnectionFailed(reason=ex.reason)

# They need at least VEVENT support for appointment to work.
return supports_vevent
Expand Down
9 changes: 9 additions & 0 deletions backend/src/appointment/exceptions/calendar.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
class EventNotCreatedException(Exception):
"""Raise if an event cannot be created on a remote calendar"""

pass


class EventNotDeletedException(Exception):
"""Raise if an event cannot be deleted on a remote calendar"""

pass


class TestConnectionFailed(Exception):
"""Raise if test connection fails, include remote error message."""

def __init__(self, reason: str | None = None):
self.reason = reason
12 changes: 11 additions & 1 deletion backend/src/appointment/exceptions/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,9 +205,19 @@ def get_msg(self):
class RemoteCalendarConnectionError(APIException):
id_code = 'REMOTE_CALENDAR_CONNECTION_ERROR'
status_code = 400
reason = None

def __init__(self, reason: str|None, **kwargs):
if reason:
self.reason = reason
super().__init__(**kwargs)

def get_msg(self):
return l10n('remote-calendar-connection-error')
reason = self.reason
if not self.reason:
reason = l10n('unknown-error-short')

return l10n('remote-calendar-connection-error', {'reason': reason})


class EventCouldNotBeAccepted(APIException):
Expand Down
11 changes: 10 additions & 1 deletion backend/src/appointment/l10n/de/main.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ health-bad = Zustand schlecht
## General Exceptions

unknown-error = Ein unbekannter Fehler ist aufgetreten. Bitte später noch einmal versuchen.
unknown-error-short = Unbekannter Fehler
appointment-not-found = Der Termin konnte nicht gefunden werden.
calendar-not-found = Der Kalender konnte nicht gefunden werden.
Expand All @@ -45,7 +46,15 @@ not-in-allow-list = Deine E-Mail-Adresse ist nicht in der Liste erlaubter Adress
schedule-not-active = Der Zeitplan wurde abgeschaltet. Bitte für weitere Informationen den Eigentümer des Zeitplans kontaktieren.
remote-calendar-connection-error = Der angebundene Kalender konnte nicht erreicht werden. Bitte die Verbindungsinformationen überprüfen und noch einmal versuchen.
remote-calendar-connection-error = Der angebundene Kalender konnte nicht erreicht werden: {$reason}.
remote-calendar-connection-error = The remote calendar could not be reached due to {$reason}.
Bitte die Verbindungsinformationen überprüfen und noch einmal versuchen.
# Possible entries for $reason,
remote-calendar-reason-doesnt-support-caldav = Der Kalender bietet keine CalDAV-Unterstützung
remote-calendar-reason-doesnt-support-auth = Der Kalender unterstützt keine Authentifizierung
remote-calendar-reason-unauthorized = Es gibt ein Problem mit Benutzername oder Passwort
event-could-not-be-accepted = Es ist ein Fehler bei der Annahme der Buchungsdaten aufgetreten. Bitte später noch einmal versuchen.
event-could-not-be-deleted = Es ist ein Fehler beim Entfernen des vorläufigen Termins aufgetreten. Bitte später noch einmal versuchen.
Expand Down
10 changes: 9 additions & 1 deletion backend/src/appointment/l10n/en/main.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ health-bad = Health BAD
## General Exceptions

unknown-error = An unknown error occurred. Please try again later.
unknown-error-short = an unknown error
appointment-not-found = The appointment could not be found.
calendar-not-found = The calendar could not be found.
Expand All @@ -45,7 +46,14 @@ not-in-allow-list = Your email is not in the allow list.
schedule-not-active = The schedule has been turned off. Please contact the schedule owner for more information.
remote-calendar-connection-error = The remote calendar could not be reached. Please verify your connection information and try again.
remote-calendar-connection-error = The remote calendar could not be reached due to {$reason}.
Please verify your connection information and try again.
# Possible entries for $reason,
remote-calendar-reason-doesnt-support-caldav = the remote calendar does not support CalDAV
remote-calendar-reason-doesnt-support-auth = the remote calendar does not support authentication
remote-calendar-reason-unauthorized = an issue with your username or password
event-could-not-be-accepted = There was an error accepting the booking details. Please try again later.
event-could-not-be-deleted = There was an error removing the hold event. Please try again later.
Expand Down
11 changes: 9 additions & 2 deletions backend/src/appointment/routes/caldav.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
from appointment.database import models, schemas, repo
from appointment.dependencies.auth import get_subscriber
from appointment.dependencies.database import get_db, get_redis
from appointment.exceptions.calendar import TestConnectionFailed
from appointment.exceptions.misc import UnexpectedBehaviourWarning
from appointment.exceptions.validation import RemoteCalendarConnectionError
from appointment.l10n import l10n

router = APIRouter()

Expand Down Expand Up @@ -99,8 +101,13 @@ def caldav_autodiscover_auth(
calendar_id=None,
)

if not con.test_connection():
raise RemoteCalendarConnectionError()
# If it returns False it doesn't support VEVENT (aka caldav)
# If it raises an exception there's a connection problem
try:
if not con.test_connection():
raise RemoteCalendarConnectionError(reason=l10n('remote-calendar-reason-doesnt-support-caldav'))
except TestConnectionFailed as ex:
raise RemoteCalendarConnectionError(reason=ex.reason)

caldav_id = json.dumps([connection.url, connection.user])
external_connection = repo.external_connection.get_by_type(
Expand Down
1 change: 1 addition & 0 deletions frontend/src/tbpro/elements/NoticeBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ const isError = props.type === 'error';
font-size: 0.8125rem;
font-weight: 700;
line-height: 1;
white-space: pre;
}
.notice {
position: relative;
Expand Down

0 comments on commit db8186e

Please sign in to comment.