|
1 | 1 | """GraphQL mutations for calendar integration webhook management.""" |
2 | 2 |
|
3 | | -import datetime |
4 | 3 | from dataclasses import dataclass |
5 | 4 | from typing import TYPE_CHECKING, Annotated, cast |
6 | 5 |
|
7 | 6 | import strawberry |
8 | 7 | from dependency_injector.wiring import Provide, inject |
9 | 8 | from graphql import GraphQLError |
10 | 9 |
|
11 | | -from calendar_integration.exceptions import CalendarGroupError |
12 | | -from calendar_integration.graphql import ( |
13 | | - CalendarEventGraphQLType, |
14 | | - CalendarGroupGraphQLType, |
15 | | - CalendarWebhookSubscriptionGraphQLType, |
16 | | -) |
17 | | -from calendar_integration.models import CalendarGroup |
18 | | -from calendar_integration.services.dataclasses import ( |
19 | | - CalendarGroupEventInputData, |
20 | | - CalendarGroupInputData, |
21 | | - CalendarGroupSlotInputData, |
22 | | - CalendarGroupSlotSelectionInputData, |
23 | | - EventAttendanceInputData, |
24 | | - EventExternalAttendanceInputData, |
25 | | - ExternalAttendeeInputData, |
26 | | -) |
| 10 | +from calendar_integration.graphql import CalendarWebhookSubscriptionGraphQLType |
27 | 11 | from calendar_integration.services.webhook_analytics_service import WebhookAnalyticsService |
28 | 12 | from organizations.models import Organization |
29 | 13 |
|
30 | 14 |
|
31 | 15 | if TYPE_CHECKING: |
32 | | - from calendar_integration.services.calendar_group_service import CalendarGroupService |
33 | 16 | from calendar_integration.services.calendar_service import CalendarService |
34 | 17 |
|
35 | 18 |
|
@@ -237,259 +220,3 @@ def cleanup_webhook_events( |
237 | 220 | deleted_count=0, |
238 | 221 | error_message=f"Failed to cleanup events: {e!s}", |
239 | 222 | ) |
240 | | - |
241 | | - |
242 | | -# --------------------------------------------------------------------------- |
243 | | -# CalendarGroup mutations |
244 | | -# --------------------------------------------------------------------------- |
245 | | - |
246 | | - |
247 | | -@dataclass |
248 | | -class CalendarGroupMutationDependencies: |
249 | | - """Dependencies for CalendarGroup mutations.""" |
250 | | - |
251 | | - calendar_group_service: "CalendarGroupService" |
252 | | - calendar_service: "CalendarService" |
253 | | - |
254 | | - |
255 | | -@inject |
256 | | -def get_calendar_group_mutation_dependencies( |
257 | | - calendar_group_service: Annotated[ |
258 | | - "CalendarGroupService | None", Provide["calendar_group_service"] |
259 | | - ] = None, |
260 | | - calendar_service: Annotated["CalendarService | None", Provide["calendar_service"]] = None, |
261 | | -) -> CalendarGroupMutationDependencies: |
262 | | - required = [calendar_group_service, calendar_service] |
263 | | - if any(dep is None for dep in required): |
264 | | - raise GraphQLError( |
265 | | - f"Missing required dependency {', '.join([str(d) for d in required if d is None])}" |
266 | | - ) |
267 | | - return CalendarGroupMutationDependencies( |
268 | | - calendar_group_service=cast("CalendarGroupService", calendar_group_service), |
269 | | - calendar_service=cast("CalendarService", calendar_service), |
270 | | - ) |
271 | | - |
272 | | - |
273 | | -@strawberry.input |
274 | | -class CalendarGroupSlotInput: |
275 | | - name: str |
276 | | - calendar_ids: list[int] |
277 | | - required_count: int = 1 |
278 | | - description: str = "" |
279 | | - order: int = 0 |
280 | | - |
281 | | - |
282 | | -@strawberry.input |
283 | | -class CalendarGroupInput: |
284 | | - organization_id: int |
285 | | - name: str |
286 | | - description: str = "" |
287 | | - slots: list[CalendarGroupSlotInput] = strawberry.field(default_factory=list) |
288 | | - |
289 | | - |
290 | | -@strawberry.input |
291 | | -class UpdateCalendarGroupInput: |
292 | | - organization_id: int |
293 | | - group_id: int |
294 | | - name: str |
295 | | - description: str = "" |
296 | | - slots: list[CalendarGroupSlotInput] = strawberry.field(default_factory=list) |
297 | | - |
298 | | - |
299 | | -@strawberry.input |
300 | | -class DeleteCalendarGroupInput: |
301 | | - organization_id: int |
302 | | - group_id: int |
303 | | - |
304 | | - |
305 | | -@strawberry.input |
306 | | -class CalendarGroupSlotSelectionInput: |
307 | | - slot_id: int |
308 | | - calendar_ids: list[int] |
309 | | - |
310 | | - |
311 | | -@strawberry.input |
312 | | -class ExternalAttendeeInput: |
313 | | - email: str |
314 | | - name: str = "" |
315 | | - id: int | None = None # noqa: A003 |
316 | | - |
317 | | - |
318 | | -@strawberry.input |
319 | | -class EventExternalAttendanceInput: |
320 | | - external_attendee: ExternalAttendeeInput |
321 | | - |
322 | | - |
323 | | -@strawberry.input |
324 | | -class EventAttendanceInput: |
325 | | - user_id: int |
326 | | - |
327 | | - |
328 | | -@strawberry.input |
329 | | -class CalendarGroupEventInput: |
330 | | - organization_id: int |
331 | | - group_id: int |
332 | | - title: str |
333 | | - description: str |
334 | | - start_time: datetime.datetime |
335 | | - end_time: datetime.datetime |
336 | | - timezone: str |
337 | | - slot_selections: list[CalendarGroupSlotSelectionInput] |
338 | | - attendances: list[EventAttendanceInput] = strawberry.field(default_factory=list) |
339 | | - external_attendances: list[EventExternalAttendanceInput] = strawberry.field( |
340 | | - default_factory=list |
341 | | - ) |
342 | | - |
343 | | - |
344 | | -@strawberry.type |
345 | | -class CalendarGroupResult: |
346 | | - success: bool |
347 | | - group: CalendarGroupGraphQLType | None = None |
348 | | - error_message: str | None = None |
349 | | - |
350 | | - |
351 | | -@strawberry.type |
352 | | -class DeleteCalendarGroupResult: |
353 | | - success: bool |
354 | | - error_message: str | None = None |
355 | | - |
356 | | - |
357 | | -@strawberry.type |
358 | | -class CalendarGroupEventResult: |
359 | | - success: bool |
360 | | - event: CalendarEventGraphQLType | None = None |
361 | | - error_message: str | None = None |
362 | | - |
363 | | - |
364 | | -def _to_slot_input_data(slots: list[CalendarGroupSlotInput]) -> list[CalendarGroupSlotInputData]: |
365 | | - return [ |
366 | | - CalendarGroupSlotInputData( |
367 | | - name=s.name, |
368 | | - calendar_ids=list(s.calendar_ids), |
369 | | - required_count=s.required_count, |
370 | | - description=s.description, |
371 | | - order=s.order, |
372 | | - ) |
373 | | - for s in slots |
374 | | - ] |
375 | | - |
376 | | - |
377 | | -def _load_organization(organization_id: int) -> Organization | None: |
378 | | - try: |
379 | | - return Organization.objects.get(id=organization_id) |
380 | | - except Organization.DoesNotExist: |
381 | | - return None |
382 | | - |
383 | | - |
384 | | -@strawberry.type |
385 | | -class CalendarGroupMutations: |
386 | | - """GraphQL mutations for CalendarGroup CRUD and grouped event booking.""" |
387 | | - |
388 | | - @strawberry.mutation |
389 | | - def create_calendar_group( |
390 | | - self, |
391 | | - input: CalendarGroupInput, # noqa: A002 |
392 | | - ) -> CalendarGroupResult: |
393 | | - organization = _load_organization(input.organization_id) |
394 | | - if organization is None: |
395 | | - return CalendarGroupResult(success=False, error_message="Organization not found") |
396 | | - deps = get_calendar_group_mutation_dependencies() |
397 | | - deps.calendar_group_service.initialize(organization=organization) |
398 | | - try: |
399 | | - group = deps.calendar_group_service.create_group( |
400 | | - CalendarGroupInputData( |
401 | | - name=input.name, |
402 | | - description=input.description, |
403 | | - slots=_to_slot_input_data(input.slots), |
404 | | - ) |
405 | | - ) |
406 | | - except CalendarGroupError as e: |
407 | | - return CalendarGroupResult(success=False, error_message=str(e)) |
408 | | - return CalendarGroupResult(success=True, group=group) # type: ignore[arg-type] |
409 | | - |
410 | | - @strawberry.mutation |
411 | | - def update_calendar_group( |
412 | | - self, |
413 | | - input: UpdateCalendarGroupInput, # noqa: A002 |
414 | | - ) -> CalendarGroupResult: |
415 | | - organization = _load_organization(input.organization_id) |
416 | | - if organization is None: |
417 | | - return CalendarGroupResult(success=False, error_message="Organization not found") |
418 | | - deps = get_calendar_group_mutation_dependencies() |
419 | | - deps.calendar_group_service.initialize(organization=organization) |
420 | | - try: |
421 | | - group = deps.calendar_group_service.update_group( |
422 | | - group_id=input.group_id, |
423 | | - data=CalendarGroupInputData( |
424 | | - name=input.name, |
425 | | - description=input.description, |
426 | | - slots=_to_slot_input_data(input.slots), |
427 | | - ), |
428 | | - ) |
429 | | - except CalendarGroup.DoesNotExist: |
430 | | - return CalendarGroupResult(success=False, error_message="Group not found") |
431 | | - except CalendarGroupError as e: |
432 | | - return CalendarGroupResult(success=False, error_message=str(e)) |
433 | | - return CalendarGroupResult(success=True, group=group) # type: ignore[arg-type] |
434 | | - |
435 | | - @strawberry.mutation |
436 | | - def delete_calendar_group( |
437 | | - self, |
438 | | - input: DeleteCalendarGroupInput, # noqa: A002 |
439 | | - ) -> DeleteCalendarGroupResult: |
440 | | - organization = _load_organization(input.organization_id) |
441 | | - if organization is None: |
442 | | - return DeleteCalendarGroupResult(success=False, error_message="Organization not found") |
443 | | - deps = get_calendar_group_mutation_dependencies() |
444 | | - deps.calendar_group_service.initialize(organization=organization) |
445 | | - try: |
446 | | - deps.calendar_group_service.delete_group(group_id=input.group_id) |
447 | | - except CalendarGroup.DoesNotExist: |
448 | | - return DeleteCalendarGroupResult(success=False, error_message="Group not found") |
449 | | - except CalendarGroupError as e: |
450 | | - return DeleteCalendarGroupResult(success=False, error_message=str(e)) |
451 | | - return DeleteCalendarGroupResult(success=True) |
452 | | - |
453 | | - @strawberry.mutation |
454 | | - def create_calendar_group_event( |
455 | | - self, |
456 | | - input: CalendarGroupEventInput, # noqa: A002 |
457 | | - ) -> CalendarGroupEventResult: |
458 | | - organization = _load_organization(input.organization_id) |
459 | | - if organization is None: |
460 | | - return CalendarGroupEventResult(success=False, error_message="Organization not found") |
461 | | - deps = get_calendar_group_mutation_dependencies() |
462 | | - deps.calendar_service.initialize_without_provider(organization=organization) |
463 | | - deps.calendar_group_service.initialize(organization=organization) |
464 | | - data = CalendarGroupEventInputData( |
465 | | - title=input.title, |
466 | | - description=input.description, |
467 | | - start_time=input.start_time, |
468 | | - end_time=input.end_time, |
469 | | - timezone=input.timezone, |
470 | | - group_id=input.group_id, |
471 | | - slot_selections=[ |
472 | | - CalendarGroupSlotSelectionInputData( |
473 | | - slot_id=s.slot_id, calendar_ids=list(s.calendar_ids) |
474 | | - ) |
475 | | - for s in input.slot_selections |
476 | | - ], |
477 | | - attendances=[EventAttendanceInputData(user_id=a.user_id) for a in input.attendances], |
478 | | - external_attendances=[ |
479 | | - EventExternalAttendanceInputData( |
480 | | - external_attendee=ExternalAttendeeInputData( |
481 | | - email=e.external_attendee.email, |
482 | | - name=e.external_attendee.name, |
483 | | - id=e.external_attendee.id, |
484 | | - ) |
485 | | - ) |
486 | | - for e in input.external_attendances |
487 | | - ], |
488 | | - ) |
489 | | - try: |
490 | | - event = deps.calendar_group_service.create_grouped_event(data) |
491 | | - except CalendarGroup.DoesNotExist: |
492 | | - return CalendarGroupEventResult(success=False, error_message="Group not found") |
493 | | - except CalendarGroupError as e: |
494 | | - return CalendarGroupEventResult(success=False, error_message=str(e)) |
495 | | - return CalendarGroupEventResult(success=True, event=event) # type: ignore[arg-type] |
0 commit comments