1
+from typing import List
2
+from typing import Optional
3
+
4
+from fastapi import APIRouter
5
+from fastapi import Depends
6
+from fastapi import HTTPException
7
+from fastapi import Security
8
+from loguru import logger
9
+from sqlalchemy import delete
10
+from sqlalchemy import update
11
+from sqlalchemy.exc import NoResultFound
12
+from sqlalchemy.ext.asyncio import AsyncSession
13
+from sqlalchemy.future import select
14
+from sqlalchemy.orm import joinedload
15
+
16
+from app.auth.utils import AuthHandler
17
+from app.db.db_session import get_db
18
+from app.db.universal_models import Customers
19
+from app.db.universal_models import CustomersMeta
20
+from app.integrations.alert_creation_settings.models.alert_creation_settings import (
21
+ AlertCreationSettings,
22
+)
23
+from app.network_connectors.models.network_connectors import AvailableNetworkConnectors
24
+from app.network_connectors.models.network_connectors import CustomerNetworkConnectors
25
+from app.network_connectors.models.network_connectors import (
26
+ CustomerNetworkConnectorsMeta,
27
+)
28
+from app.network_connectors.models.network_connectors import NetworkConnectorsConfig
29
+from app.network_connectors.models.network_connectors import NetworkConnectorsKeys
30
+from app.network_connectors.models.network_connectors import NetworkConnectorsService
31
+from app.network_connectors.models.network_connectors import (
32
+ NetworkConnectorsSubscription,
33
+)
34
+from app.network_connectors.schema import AuthKey
35
+from app.network_connectors.schema import AvailableNetworkConnectorsResponse
36
+from app.network_connectors.schema import CreateNetworkConnectorsAuthKeys
37
+from app.network_connectors.schema import CreateNetworkConnectorsService
38
+from app.network_connectors.schema import CustomerNetworkConnectorsCreate
39
+from app.network_connectors.schema import CustomerNetworkConnectorsCreateResponse
40
+from app.network_connectors.schema import CustomerNetworkConnectorsDeleteResponse
41
+from app.network_connectors.schema import CustomerNetworkConnectorsMetaResponse
42
+from app.network_connectors.schema import CustomerNetworkConnectorsMetaSchema
43
+from app.network_connectors.schema import CustomerNetworkConnectorsResponse
44
+from app.network_connectors.schema import DeleteCustomerNetworkConnectors
45
+from app.network_connectors.schema import NetworkConnectorsWithAuthKeys
46
+from app.network_connectors.schema import UpdateCustomerNetworkConnectors
47
+
48
+network_connector_settings_router = APIRouter()
49
+
50
+
51
+async def fetch_available_network_connectors(session: AsyncSession):
52
+ """
53
+ Fetches available network_connectors and their auth keys from the database.
54
+
55
+ Args:
56
+ session (AsyncSession): The database session.
57
+
58
+ Returns:
59
+ List[NetworkConnectorsWithAuthKeys]: A list of available network_connectors with their auth keys.
60
+ """
61
+ stmt = select(AvailableNetworkConnectors).options(
62
+ joinedload(AvailableNetworkConnectors.network_connector_keys),
63
+ )
64
+ result = await session.execute(stmt)
65
+
66
+ # Use unique() to avoid duplicates caused by joined eager loading
67
+ unique_network_connectors = result.unique().scalars().all()
68
+
69
+ network_connectors_with_auth_keys = []
70
+ for network_connector in unique_network_connectors:
71
+ auth_keys = [AuthKey(auth_key_name=key.auth_key_name) for key in network_connector.network_connector_keys]
72
+ network_connector_data = NetworkConnectorsWithAuthKeys(
73
+ id=network_connector.id,
74
+ network_connector_name=network_connector.network_connector_name,
75
+ description=network_connector.description,
76
+ network_connector_details=network_connector.network_connector_details,
77
+ network_connector_keys=auth_keys,
78
+ )
79
+ network_connectors_with_auth_keys.append(network_connector_data)
80
+
81
+ return network_connectors_with_auth_keys
82
+
83
+
84
+async def validate_network_connector_name(network_connector_name: str, session: AsyncSession):
85
+ """
86
+ Validate if the network_connector name exists in available network_connectors.
87
+ """
88
+ available_network_connectors = await fetch_available_network_connectors(session)
89
+ if network_connector_name not in [ai.network_connector_name for ai in available_network_connectors]:
90
+ raise HTTPException(
91
+ status_code=400,
92
+ detail=f"NetworkConnectors {network_connector_name} is not a valid network_connector.",
93
+ )
94
+
95
+
96
+async def validate_network_connector_auth_keys(
97
+ network_connector_name: str,
98
+ network_connector_auth_keys: List[AuthKey],
99
+ session: AsyncSession,
100
+):
101
+ """
102
+ Validate if the network_connector auth keys are valid.
103
+ """
104
+ available_network_connectors = await fetch_available_network_connectors(session)
105
+ network_connector = [ai for ai in available_network_connectors if ai.network_connector_name == network_connector_name][0]
106
+ available_auth_keys = [ak.auth_key_name for ak in network_connector.network_connector_keys]
107
+ # loop through the `available_auth_keys` and check if the `network_connector_auth_keys` contains the `auth_key_name`
108
+ for auth_key in available_auth_keys:
109
+ if auth_key not in [iak.auth_key_name for iak in network_connector_auth_keys]:
110
+ raise HTTPException(
111
+ status_code=400,
112
+ detail=f"NetworkConnectors auth key {auth_key} does not exist.",
113
+ )
114
+
115
+
116
+async def validate_network_connector_auth_key_update(
117
+ network_connector_name: str,
118
+ network_connector_auth_key: List[AuthKey],
119
+ session: AsyncSession,
120
+):
121
+ """
122
+ Validate if the network_connector auth key is valid.
123
+ """
124
+ logger.info(f"network_connector_auth_key: {network_connector_auth_key}")
125
+ available_network_connectors = await fetch_available_network_connectors(session)
126
+ network_connector = [ai for ai in available_network_connectors if ai.network_connector_name == network_connector_name][0]
127
+ available_auth_keys = [ak.auth_key_name for ak in network_connector.auth_keys]
128
+ for auth_key in network_connector_auth_key:
129
+ if auth_key.auth_key_name not in available_auth_keys:
130
+ raise HTTPException(
131
+ status_code=400,
132
+ detail=f"NetworkConnectors auth key {auth_key.auth_key_name} does not exist.",
133
+ )
134
+
135
+
136
+async def validate_customer_code(customer_code: str, session: AsyncSession):
137
+ """
138
+ Validate if the customer code exists in the customers table.
139
+ """
140
+ stmt = select(Customers).where(Customers.customer_code == customer_code)
141
+ result = await session.execute(stmt)
142
+ if result.scalars().first() is None:
143
+ raise HTTPException(
144
+ status_code=400,
145
+ detail=f"Customer {customer_code} does not exist.",
146
+ )
147
+
148
+
149
+async def validate_customer_meta(customer_code: str, session: AsyncSession):
150
+ """
151
+ Validate if the customer code exists in the customers_meta table.
152
+ """
153
+ stmt = select(CustomersMeta).where(CustomersMeta.customer_code == customer_code)
154
+ result = await session.execute(stmt)
155
+ if result.scalars().first() is None:
156
+ raise HTTPException(
157
+ status_code=400,
158
+ detail=f"Customer {customer_code} meta does not exist. Please provision the customer before creating an network_connector.",
159
+ )
160
+
161
+
162
+async def check_existing_customer_network_connector(
163
+ customer_code: str,
164
+ network_connector_name: str,
165
+ session: AsyncSession,
166
+):
167
+ """
168
+ Check if the customer network_connector already exists.
169
+ """
170
+ # Assuming NetworkConnectorsService has an 'network_connector_name' field or similar
171
+ stmt = (
172
+ select(CustomerNetworkConnectors)
173
+ .join(CustomerNetworkConnectors.network_connectors_subscriptions)
174
+ .join(NetworkConnectorsSubscription.network_connectors_service)
175
+ .where(
176
+ CustomerNetworkConnectors.customer_code == customer_code,
177
+ NetworkConnectorsService.service_name == network_connector_name,
178
+ )
179
+ )
180
+ result = await session.execute(stmt)
181
+ if result.scalars().first() is not None:
182
+ raise HTTPException(
183
+ status_code=400,
184
+ detail=f"Customer network_connector {customer_code} {network_connector_name} already exists.",
185
+ )
186
+
187
+
188
+async def check_existing_customer_network_connector_meta(
189
+ customer_code: str,
190
+ network_connector_name: str,
191
+ session: AsyncSession,
192
+):
193
+ """
194
+ Check if the customer network_connector meta already exists for the customer code and network_connector name.
195
+ """
196
+ stmt = select(CustomerNetworkConnectorsMeta).where(
197
+ CustomerNetworkConnectorsMeta.customer_code == customer_code,
198
+ CustomerNetworkConnectorsMeta.network_connector_name == network_connector_name,
199
+ )
200
+ result = await session.execute(stmt)
201
+ if result.scalars().first() is not None:
202
+ raise HTTPException(
203
+ status_code=400,
204
+ detail=f"Customer network_connector meta {customer_code} {network_connector_name} already exists.",
205
+ )
206
+
207
+
208
+async def create_network_connector_service(
209
+ network_connector_name: str,
210
+ settings: CreateNetworkConnectorsService,
211
+ session: AsyncSession,
212
+) -> NetworkConnectorsService:
213
+ """
214
+ Create or fetch NetworkConnectorsService instance with custom configuration.
215
+ """
216
+ network_connector_service = NetworkConnectorsService(
217
+ service_name=network_connector_name,
218
+ auth_type=settings.auth_type,
219
+ configs=[
220
+ NetworkConnectorsConfig(
221
+ config_key=settings.config_key,
222
+ config_value=settings.config_value,
223
+ ),
224
+ ],
225
+ )
226
+ session.add(network_connector_service)
227
+ await session.flush()
228
+ return network_connector_service
229
+
230
+
231
+async def create_customer_network_connectors(
232
+ customer_code: str,
233
+ customer_name: str,
234
+ network_connector_service_id: int,
235
+ network_connector_service_name: str,
236
+ session: AsyncSession,
237
+) -> CustomerNetworkConnectors:
238
+ """
239
+ Create CustomerNetworkConnectors instance.
240
+ """
241
+ customer_network_connectors = CustomerNetworkConnectors(
242
+ customer_code=customer_code,
243
+ customer_name=customer_name,
244
+ network_connector_service_id=network_connector_service_id,
245
+ network_connector_service_name=network_connector_service_name,
246
+ deployed=False,
247
+ )
248
+ session.add(customer_network_connectors)
249
+ await session.flush()
250
+ return customer_network_connectors
251
+
252
+
253
+async def create_network_connector_subscription(
254
+ customer_network_connectors: CustomerNetworkConnectors,
255
+ network_connector_service: NetworkConnectorsService,
256
+ network_connector_auth_keys: List[CreateNetworkConnectorsAuthKeys],
257
+ session: AsyncSession,
258
+):
259
+ """
260
+ Create NetworkConnectorsSubscription instance.
261
+ """
262
+ for auth_key in network_connector_auth_keys:
263
+ new_network_connector_subscription = NetworkConnectorsSubscription(
264
+ customer_network_connectors=customer_network_connectors,
265
+ network_connectors_service=network_connector_service,
266
+ network_connectors_keys=[
267
+ NetworkConnectorsKeys(
268
+ auth_key_name=auth_key.auth_key_name,
269
+ auth_value=auth_key.auth_value,
270
+ ),
271
+ ],
272
+ )
273
+ session.add(new_network_connector_subscription)
274
+ await session.commit()
275
+
276
+
277
+async def get_customer_and_service_ids(session, customer_code, network_connector_name):
278
+ try:
279
+ result = await session.execute(
280
+ select(CustomerNetworkConnectors.id, NetworkConnectorsService.id)
281
+ .join(
282
+ NetworkConnectorsSubscription,
283
+ CustomerNetworkConnectors.id == NetworkConnectorsSubscription.customer_id,
284
+ )
285
+ .join(
286
+ NetworkConnectorsService,
287
+ NetworkConnectorsSubscription.network_connectors_service_id == NetworkConnectorsService.id,
288
+ )
289
+ .where(
290
+ CustomerNetworkConnectors.customer_code == customer_code,
291
+ NetworkConnectorsService.service_name == network_connector_name,
292
+ ),
293
+ )
294
+ return result.all()
295
+ except NoResultFound:
296
+ raise HTTPException(status_code=404, detail="Customer network_connector not found")
297
+
298
+
299
+async def get_subscription_ids(session, customer_id, network_connector_service_id):
300
+ result = await session.execute(
301
+ select(NetworkConnectorsSubscription.id).where(
302
+ NetworkConnectorsSubscription.customer_id == customer_id,
303
+ NetworkConnectorsSubscription.network_connectors_service_id == network_connector_service_id,
304
+ ),
305
+ )
306
+ # Fetch all results
307
+ subscription_ids_raw = result.scalars().all()
308
+
309
+ # Process the results
310
+ # If the result is a list of tuples (even with one element), extract the first element
311
+ if subscription_ids_raw and isinstance(subscription_ids_raw[0], tuple):
312
+ return [id_tuple[0] for id_tuple in subscription_ids_raw]
313
+ # If the result is a list of integers
314
+ elif subscription_ids_raw and isinstance(subscription_ids_raw[0], int):
315
+ return subscription_ids_raw
316
+ # If there are no results
317
+ else:
318
+ return []
319
+
320
+
321
+async def delete_metadata(session, subscription_ids):
322
+ await session.execute(
323
+ delete(NetworkConnectorsKeys).where(
324
+ NetworkConnectorsKeys.subscription_id.in_(subscription_ids),
325
+ ),
326
+ )
327
+
328
+
329
+async def delete_subscriptions(session, subscription_ids):
330
+ await session.execute(
331
+ delete(NetworkConnectorsSubscription).where(
332
+ NetworkConnectorsSubscription.id.in_(subscription_ids),
333
+ ),
334
+ )
335
+
336
+
337
+async def delete_configs(session, network_connector_service_id):
338
+ await session.execute(
339
+ delete(NetworkConnectorsConfig).where(
340
+ NetworkConnectorsConfig.network_connector_service_id == network_connector_service_id,
341
+ ),
342
+ )
343
+
344
+
345
+async def delete_network_connector_service(session, network_connector_service_id):
346
+ await session.execute(
347
+ delete(NetworkConnectorsService).where(
348
+ NetworkConnectorsService.id == network_connector_service_id,
349
+ ),
350
+ )
351
+
352
+
353
+async def delete_customer_network_connector_record(session, customer_id):
354
+ await session.execute(
355
+ delete(CustomerNetworkConnectors).where(CustomerNetworkConnectors.id == customer_id),
356
+ )
357
+
358
+
359
+async def find_customer_network_connector(
360
+ customer_code: str,
361
+ network_connector_name: str,
362
+ customer_network_connector_response,
363
+) -> Optional[CustomerNetworkConnectors]:
364
+ for ci in customer_network_connector_response.available_network_connectors:
365
+ for subscription in ci.network_connectors_subscriptions:
366
+ if subscription.network_connectors_service.service_name == network_connector_name:
367
+ return ci
368
+ return None
369
+
370
+
371
+def get_subscription_id(
372
+ customer_network_connector,
373
+ network_connector_name: str,
374
+ auth_key_name: str,
375
+) -> Optional[int]:
376
+ logger.info(f"Getting subscription id for {network_connector_name} {auth_key_name}")
377
+ for subscription in customer_network_connector.network_connectors_subscriptions:
378
+ if subscription.network_connectors_service.service_name == network_connector_name:
379
+ for auth_key in subscription.network_connector_keys:
380
+ if auth_key.auth_key_name == auth_key_name:
381
+ return subscription.id
382
+ return None
383
+
384
+
385
+async def get_tenant_id(
386
+ customer_network_connector: CustomerNetworkConnectorsCreate,
387
+ session: AsyncSession,
388
+) -> str:
389
+ """
390
+ Retrieves the Tenant ID for a given customer network_connector. This is the Office365 organization ID and
391
+ is used to create alerts for the customer in DFIR-IRIS.
392
+ """
393
+ stmt = (
394
+ select(NetworkConnectorsKeys)
395
+ .join(
396
+ NetworkConnectorsSubscription,
397
+ NetworkConnectorsKeys.subscription_id == NetworkConnectorsSubscription.id,
398
+ )
399
+ .join(
400
+ CustomerNetworkConnectors,
401
+ NetworkConnectorsSubscription.customer_id == CustomerNetworkConnectors.id,
402
+ )
403
+ .join(
404
+ NetworkConnectorsService,
405
+ NetworkConnectorsSubscription.network_connector_service_id == NetworkConnectorsService.id,
406
+ )
407
+ .where(
408
+ CustomerNetworkConnectors.customer_code == customer_network_connector.customer_code,
409
+ NetworkConnectorsService.service_name == customer_network_connector.network_connector_name,
410
+ NetworkConnectorsKeys.auth_key_name == "TENANT_ID",
411
+ )
412
+ )
413
+
414
+ result = await session.execute(stmt)
415
+ tenant_id = result.scalars().first()
416
+ if tenant_id is None:
417
+ raise HTTPException(
418
+ status_code=404,
419
+ detail=f"Tenant ID for customer {customer_network_connector.customer_code} not found.",
420
+ )
421
+ logger.info(f"tenant_id: {tenant_id.auth_value}")
422
+ return tenant_id.auth_value
423
+
424
+
425
+async def update_office365_organization_id(
426
+ customer_code: str,
427
+ tenant_id: str,
428
+ session: AsyncSession,
429
+):
430
+ """
431
+ Updates the Office365 organization ID in the alert_creation_settings table.
432
+ """
433
+ stmt = (
434
+ update(AlertCreationSettings)
435
+ .where(AlertCreationSettings.customer_code == customer_code)
436
+ .values(office365_organization_id=tenant_id)
437
+ )
438
+ await session.execute(stmt)
439
+ await session.commit()
440
+
441
+
442
+async def get_network_connector_service_id(
443
+ network_connector_name: str,
444
+ session: AsyncSession,
445
+) -> int:
446
+ """
447
+ Retrieves the AvailableNetworkConnectorss ID for a given network_connector name.
448
+ """
449
+ stmt = select(AvailableNetworkConnectors).where(
450
+ AvailableNetworkConnectors.network_connector_name == network_connector_name,
451
+ )
452
+ result = await session.execute(stmt)
453
+ network_connector_service = result.scalars().first()
454
+ if network_connector_service is None:
455
+ raise HTTPException(
456
+ status_code=404,
457
+ detail=f"NetworkConnectors service {network_connector_name} not found.",
458
+ )
459
+ return network_connector_service.id
460
+
461
+
462
+async def get_network_connector_service_name(
463
+ network_connector_name: str,
464
+ session: AsyncSession,
465
+) -> str:
466
+ """
467
+ Retrieves the AvailableNetworkConnectors ID for a given network_connector name.
468
+ """
469
+ stmt = select(AvailableNetworkConnectors).where(
470
+ AvailableNetworkConnectors.network_connector_name == network_connector_name,
471
+ )
472
+ result = await session.execute(stmt)
473
+ network_connector_service = result.scalars().first()
474
+ if network_connector_service is None:
475
+ raise HTTPException(
476
+ status_code=404,
477
+ detail=f"NetworkConnectors service {network_connector_name} not found.",
478
+ )
479
+ return network_connector_service.network_connector_name
480
+
481
+
482
+async def fetch_customer_network_connectors_data(session: AsyncSession):
483
+ """
484
+ Fetches customer network_connectors data from the database.
485
+ """
486
+ stmt = select(CustomerNetworkConnectors).options(
487
+ joinedload(CustomerNetworkConnectors.network_connectors_subscriptions).joinedload(
488
+ NetworkConnectorsSubscription.network_connectors_service,
489
+ ),
490
+ joinedload(CustomerNetworkConnectors.network_connectors_subscriptions).subqueryload(
491
+ NetworkConnectorsSubscription.network_connectors_keys,
492
+ ),
493
+ )
494
+ result = await session.execute(stmt)
495
+ return result.scalars().unique().all()
496
+
497
+
498
+def process_customer_network_connectors(customer_network_connectors_data):
499
+ """
500
+ Processes customer network_connectors data and returns a list of CustomerNetworkConnectors objects.
501
+ """
502
+ processed_customer_network_connectors = []
503
+ for ci in customer_network_connectors_data:
504
+ first_service_id = (
505
+ ci.network_connectors_subscriptions[0].network_connectors_service_id if ci.network_connectors_subscriptions else None
506
+ )
507
+ customer_network_connector_obj = CustomerNetworkConnectors(
508
+ id=ci.id,
509
+ customer_code=ci.customer_code,
510
+ customer_name=ci.customer_name,
511
+ network_connectors_subscriptions=ci.network_connectors_subscriptions,
512
+ network_connector_service_id=first_service_id,
513
+ network_connector_service_name=ci.network_connectors_subscriptions[0].network_connectors_service.service_name
514
+ if ci.network_connectors_subscriptions
515
+ else None,
516
+ deployed=ci.deployed,
517
+ )
518
+ processed_customer_network_connectors.append(customer_network_connector_obj)
519
+ return processed_customer_network_connectors
520
+
521
+
522
+@network_connector_settings_router.get(
523
+ "/available_network_connectors",
524
+ response_model=AvailableNetworkConnectorsResponse,
525
+ description="Get a list of available network_connectors.",
526
+ dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
527
+)
528
+async def get_available_network_connectors(
529
+ session: AsyncSession = Depends(get_db),
530
+):
531
+ """
532
+ Endpoint to get a list of available network_connectors.
533
+ """
534
+ available_network_connectors = await fetch_available_network_connectors(session)
535
+ return AvailableNetworkConnectorsResponse(
536
+ network_connector_keys=available_network_connectors,
537
+ message="Available network_connectors successfully retrieved.",
538
+ success=True,
539
+ )
540
+
541
+
542
+@network_connector_settings_router.get(
543
+ "/customer_network_connectors",
544
+ response_model=CustomerNetworkConnectorsResponse,
545
+ description="Get a list of customer network_connectors.",
546
+ dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
547
+)
548
+async def get_customer_network_connectors(session: AsyncSession = Depends(get_db)):
549
+ """
550
+ Endpoint to get a list of customer network_connectors.
551
+ """
552
+ customer_network_connectors_data = await fetch_customer_network_connectors_data(session)
553
+ processed_customer_network_connectors = process_customer_network_connectors(
554
+ customer_network_connectors_data,
555
+ )
556
+
557
+ return CustomerNetworkConnectorsResponse(
558
+ available_network_connectors=processed_customer_network_connectors,
559
+ message="Customer network_connectors successfully retrieved.",
560
+ success=True,
561
+ )
562
+
563
+
564
+@network_connector_settings_router.get(
565
+ "/customer_network_connectors_meta",
566
+ response_model=CustomerNetworkConnectorsMetaResponse,
567
+ description="Get a list of customer network_connectors metadata.",
568
+ dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
569
+)
570
+async def get_customer_network_connectors_meta(session: AsyncSession = Depends(get_db)):
571
+ """
572
+ Endpoint to get a list of customer network_connectors metadata.
573
+ """
574
+ try:
575
+ stmt = select(CustomerNetworkConnectorsMeta)
576
+ result = await session.execute(stmt)
577
+ customer_network_connectors_meta = result.scalars().all()
578
+ except Exception as e:
579
+ logger.error(f"Error while fetching customer network_connectors metadata: {e}")
580
+ customer_network_connectors_meta = []
581
+
582
+ logger.info(f"customer_network_connectors_meta: {customer_network_connectors_meta}")
583
+ return CustomerNetworkConnectorsMetaResponse(
584
+ customer_network_connectors_meta=customer_network_connectors_meta,
585
+ message="Customer network_connectors metadata successfully retrieved.",
586
+ success=True,
587
+ )
588
+
589
+
590
+@network_connector_settings_router.get(
591
+ "/customer_network_connectors/{customer_code}",
592
+ response_model=CustomerNetworkConnectorsResponse,
593
+ description="Get a list of customer network_connectors for a specific customer.",
594
+ dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
595
+)
596
+async def get_customer_network_connectors_by_customer_code(
597
+ customer_code: str,
598
+ session: AsyncSession = Depends(get_db),
599
+):
600
+ """
601
+ Endpoint to get a list of customer network_connectors for a specific customer.
602
+ """
603
+ stmt = (
604
+ select(CustomerNetworkConnectors)
605
+ .options(
606
+ joinedload(CustomerNetworkConnectors.network_connectors_subscriptions).joinedload(
607
+ NetworkConnectorsSubscription.network_connectors_service,
608
+ ),
609
+ joinedload(CustomerNetworkConnectors.network_connectors_subscriptions).subqueryload(
610
+ NetworkConnectorsSubscription.network_connectors_keys,
611
+ ), # Load NetworkConnectorsAuthKeys
612
+ )
613
+ .where(CustomerNetworkConnectors.customer_code == customer_code)
614
+ )
615
+ result = await session.execute(stmt)
616
+ customer_network_connectors = result.scalars().unique().all()
617
+ return CustomerNetworkConnectorsResponse(
618
+ available_network_connectors=customer_network_connectors,
619
+ message="Customer network_connectors successfully retrieved.",
620
+ success=True,
621
+ )
622
+
623
+
624
+@network_connector_settings_router.get(
625
+ "/customer_network_connectors_meta/{customer_code}",
626
+ response_model=CustomerNetworkConnectorsMetaResponse,
627
+ description="Get a list of customer network_connectors metadata for a specific customer.",
628
+ dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
629
+)
630
+async def get_customer_network_connectors_meta_by_customer_code(
631
+ customer_code: str,
632
+ session: AsyncSession = Depends(get_db),
633
+):
634
+ """
635
+ Endpoint to get a list of customer network_connectors metadata for a specific customer.
636
+ """
637
+ stmt = select(CustomerNetworkConnectorsMeta).where(
638
+ CustomerNetworkConnectorsMeta.customer_code == customer_code,
639
+ )
640
+ result = await session.execute(stmt)
641
+ customer_network_connectors_meta = result.scalars().all()
642
+ logger.info(f"customer_network_connectors_meta: {customer_network_connectors_meta}")
643
+ return CustomerNetworkConnectorsMetaResponse(
644
+ customer_network_connectors_meta=customer_network_connectors_meta,
645
+ message="Customer network_connectors metadata successfully retrieved.",
646
+ success=True,
647
+ )
648
+
649
+
650
+@network_connector_settings_router.post(
651
+ "/create_network_connector",
652
+ response_model=CustomerNetworkConnectorsCreateResponse,
653
+ description="Create a new customer network_connector.",
654
+ # dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
655
+)
656
+async def create_network_connector(
657
+ customer_network_connector_create: CustomerNetworkConnectorsCreate,
658
+ session: AsyncSession = Depends(get_db),
659
+):
660
+ """
661
+ Endpoint to create a new customer network_connector.
662
+ """
663
+ await validate_network_connector_name(
664
+ customer_network_connector_create.network_connector_name,
665
+ session,
666
+ )
667
+ await validate_network_connector_auth_keys(
668
+ customer_network_connector_create.network_connector_name,
669
+ customer_network_connector_create.network_connector_auth_keys,
670
+ session,
671
+ )
672
+ await validate_customer_code(customer_network_connector_create.customer_code, session)
673
+ await validate_customer_meta(customer_network_connector_create.customer_code, session)
674
+ await check_existing_customer_network_connector(
675
+ customer_network_connector_create.customer_code,
676
+ customer_network_connector_create.network_connector_name,
677
+ session,
678
+ )
679
+ network_connector_service_id = await get_network_connector_service_id(
680
+ customer_network_connector_create.network_connector_name,
681
+ session,
682
+ )
683
+ network_connector_service_name = await get_network_connector_service_name(
684
+ customer_network_connector_create.network_connector_name,
685
+ session,
686
+ )
687
+
688
+ network_connector_service = await create_network_connector_service(
689
+ customer_network_connector_create.network_connector_name,
690
+ settings=customer_network_connector_create.network_connector_config,
691
+ session=session,
692
+ )
693
+ customer_network_connectors = await create_customer_network_connectors(
694
+ customer_network_connector_create.customer_code,
695
+ customer_network_connector_create.customer_name,
696
+ network_connector_service_id=network_connector_service_id,
697
+ network_connector_service_name=network_connector_service_name,
698
+ session=session,
699
+ )
700
+ logger.info("Getting customer network_connector auth keys for subscription creation.")
701
+ logger.info(f"Customer Network Connectors: {customer_network_connectors}")
702
+ await create_network_connector_subscription(
703
+ customer_network_connectors,
704
+ network_connector_service,
705
+ network_connector_auth_keys=customer_network_connector_create.network_connector_auth_keys,
706
+ session=session,
707
+ )
708
+
709
+ return CustomerNetworkConnectorsCreateResponse(
710
+ message=f"Customer network_connector {customer_network_connector_create.customer_code} {customer_network_connector_create.network_connector_name} successfully created.",
711
+ success=True,
712
+ )
713
+
714
+
715
+@network_connector_settings_router.post(
716
+ "/create_network_connector_meta",
717
+ response_model=CustomerNetworkConnectorsMetaResponse,
718
+ description="Create a new customer network_connector metadata.",
719
+ # dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
720
+)
721
+async def create_network_connector_meta(
722
+ customer_network_connector_meta: CustomerNetworkConnectorsMetaSchema,
723
+ session: AsyncSession = Depends(get_db),
724
+):
725
+ """
726
+ Endpoint to create a new customer network_connector metadata.
727
+ """
728
+ await validate_customer_code(customer_network_connector_meta.customer_code, session)
729
+ await validate_customer_meta(customer_network_connector_meta.customer_code, session)
730
+ await check_existing_customer_network_connector_meta(
731
+ customer_network_connector_meta.customer_code,
732
+ customer_network_connector_meta.network_connector_name,
733
+ session,
734
+ )
735
+ try:
736
+ new_customer_network_connector_meta = CustomerNetworkConnectorsMeta(
737
+ **customer_network_connector_meta.dict(),
738
+ )
739
+ session.add(new_customer_network_connector_meta)
740
+ await session.commit()
741
+ return CustomerNetworkConnectorsMetaResponse(
742
+ message="Customer network_connector metadata successfully created.",
743
+ success=True,
744
+ )
745
+ except Exception as e:
746
+ logger.error(f"Error while creating customer network_connector metadata: {e}")
747
+ return CustomerNetworkConnectorsMetaResponse(
748
+ customer_network_connectors_meta=None,
749
+ message="Error while creating customer network_connector metadata.",
750
+ success=False,
751
+ )
752
+
753
+
754
+@network_connector_settings_router.put(
755
+ "/update_network_connector/{customer_code}",
756
+ response_model=CustomerNetworkConnectorsCreateResponse,
757
+ description="Update a customer network_connector.",
758
+ dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
759
+)
760
+async def update_network_connector(
761
+ customer_code: str,
762
+ customer_network_connector_update: UpdateCustomerNetworkConnectors,
763
+ session: AsyncSession = Depends(get_db),
764
+):
765
+ await validate_network_connector_name(
766
+ customer_network_connector_update.network_connector_name,
767
+ session,
768
+ )
769
+ customer_network_connector_response = await get_customer_network_connectors_by_customer_code(
770
+ customer_code,
771
+ session,
772
+ )
773
+
774
+ if not customer_network_connector_response:
775
+ raise HTTPException(status_code=404, detail="Customer network_connectors not found")
776
+
777
+ customer_network_connector = await find_customer_network_connector(
778
+ customer_code,
779
+ customer_network_connector_update.network_connector_name,
780
+ customer_network_connector_response,
781
+ )
782
+
783
+ if not customer_network_connector:
784
+ raise HTTPException(
785
+ status_code=404,
786
+ detail="Customer network_connector with specified service name not found.",
787
+ )
788
+
789
+ await validate_network_connector_auth_key_update(
790
+ customer_network_connector_update.network_connector_name,
791
+ customer_network_connector_update.network_connector_auth_keys,
792
+ session,
793
+ )
794
+
795
+ subscription_id = get_subscription_id(
796
+ customer_network_connector,
797
+ customer_network_connector_update.network_connector_name,
798
+ customer_network_connector_update.network_connector_auth_keys[0].auth_key_name,
799
+ )
800
+
801
+ if not subscription_id:
802
+ raise HTTPException(
803
+ status_code=404,
804
+ detail=f"NetworkConnectors auth key {customer_network_connector_update.network_connector_auth_keys[0].auth_key_name} not found.",
805
+ )
806
+
807
+ await session.execute(
808
+ update(NetworkConnectorsKeys)
809
+ .where(NetworkConnectorsKeys.subscription_id == subscription_id)
810
+ .values(
811
+ auth_value=customer_network_connector_update.network_connector_auth_keys[0].auth_value,
812
+ ),
813
+ )
814
+
815
+ await session.commit()
816
+
817
+ return CustomerNetworkConnectorsCreateResponse(
818
+ message=f"Customer network_connector {customer_code} {customer_network_connector_update.network_connector_name} successfully updated.",
819
+ success=True,
820
+ )
821
+
822
+
823
+@network_connector_settings_router.put(
824
+ "/available_network_connectors",
825
+ response_model=AvailableNetworkConnectorsResponse,
826
+ description="Update an available network_connector.",
827
+ dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
828
+)
829
+async def update_available_network_connectors(
830
+ available_network_connectors: List[AvailableNetworkConnectors],
831
+ session: AsyncSession = Depends(get_db),
832
+):
833
+ """
834
+ Endpoint to update an available network_connector.
835
+ """
836
+ for network_connector in available_network_connectors:
837
+ stmt = select(AvailableNetworkConnectors).where(
838
+ AvailableNetworkConnectors.network_connector_name == network_connector.network_connector_name,
839
+ )
840
+ result = await session.execute(stmt)
841
+ existing_network_connector = result.scalars().first()
842
+
843
+ if existing_network_connector is None:
844
+ raise HTTPException(
845
+ status_code=404,
846
+ detail=f"NetworkConnectors {network_connector.network_connector_name} not found.",
847
+ )
848
+
849
+ existing_network_connector.description = network_connector.description
850
+ existing_network_connector.network_connector_details = network_connector.network_connector_details
851
+
852
+ await session.commit()
853
+
854
+ return AvailableNetworkConnectorsResponse(
855
+ available_network_connectors=available_network_connectors,
856
+ message="Available network_connectors successfully updated.",
857
+ success=True,
858
+ )
859
+
860
+
861
+@network_connector_settings_router.delete(
862
+ "/delete_network_connector",
863
+ response_model=CustomerNetworkConnectorsDeleteResponse,
864
+ description="Delete a customer network_connector.",
865
+ dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
866
+)
867
+async def delete_network_connector(
868
+ delete_customer_network_connector: DeleteCustomerNetworkConnectors,
869
+ session: AsyncSession = Depends(get_db),
870
+):
871
+ customer_code = delete_customer_network_connector.customer_code
872
+ network_connector_name = delete_customer_network_connector.network_connector_name
873
+
874
+ results = await get_customer_and_service_ids(
875
+ session,
876
+ customer_code,
877
+ network_connector_name,
878
+ )
879
+ # Check if results is not empty
880
+ if results:
881
+ # Unpack the first tuple in results
882
+ customer_id, network_connector_service_id = results[0]
883
+ else:
884
+ # Handle the case where results is empty
885
+ raise HTTPException(status_code=404, detail="Customer network_connector not found")
886
+
887
+ subscription_ids = await get_subscription_ids(
888
+ session,
889
+ customer_id,
890
+ network_connector_service_id,
891
+ )
892
+ if not subscription_ids:
893
+ raise HTTPException(
894
+ status_code=404,
895
+ detail="No subscriptions found for customer network_connector",
896
+ )
897
+
898
+ await delete_metadata(session, subscription_ids)
899
+ await delete_subscriptions(session, subscription_ids)
900
+ await delete_configs(session, network_connector_service_id)
901
+ await delete_network_connector_service(session, network_connector_service_id)
902
+ await delete_customer_network_connector_record(session, customer_id)
903
+
904
+ await session.commit()
905
+
906
+ return CustomerNetworkConnectorsDeleteResponse(
907
+ message=f"Customer network_connector {customer_code} {network_connector_name} successfully deleted.",
908
+ success=True,
909
+ )
910
+
911
+
912
+@network_connector_settings_router.delete(
913
+ "/delete_network_connector_meta",
914
+ response_model=CustomerNetworkConnectorsMetaResponse,
915
+ description="Delete a customer network_connector metadata.",
916
+ dependencies=[Security(AuthHandler().require_any_scope("admin", "analyst"))],
917
+)
918
+async def delete_network_connector_meta(
919
+ customer_network_connector_meta: CustomerNetworkConnectorsMetaSchema,
920
+ session: AsyncSession = Depends(get_db),
921
+):
922
+ """
923
+ Endpoint to delete a customer network_connector metadata.
924
+ """
925
+ try:
926
+ stmt = delete(CustomerNetworkConnectorsMeta).where(
927
+ CustomerNetworkConnectorsMeta.customer_code == customer_network_connector_meta.customer_code,
928
+ CustomerNetworkConnectorsMeta.network_connector_name == customer_network_connector_meta.network_connector_name,
929
+ )
930
+ await session.execute(stmt)
931
+ await session.commit()
932
+ return CustomerNetworkConnectorsMetaResponse(
933
+ message="Customer network_connector metadata successfully deleted.",
934
+ success=True,
935
+ )
936
+ except Exception as e:
937
+ logger.error(f"Error while deleting customer network_connector metadata: {e}")
938
+ return CustomerNetworkConnectorsMetaResponse(
939
+ customer_network_connectors_meta=None,
940
+ message="Error while deleting customer network_connector metadata.",
941
+ success=False,
942
+ )