23
23
from synapse .api .constants import UserTypes
24
24
from synapse .api .errors import Codes , StoreError , SynapseError , ThreepidValidationError
25
25
from synapse .metrics .background_process_metrics import wrap_as_background_process
26
- from synapse .storage .database import DatabasePool , LoggingDatabaseConnection
26
+ from synapse .storage .database import (
27
+ DatabasePool ,
28
+ LoggingDatabaseConnection ,
29
+ LoggingTransaction ,
30
+ )
27
31
from synapse .storage .databases .main .cache import CacheInvalidationWorkerStore
28
32
from synapse .storage .databases .main .stats import StatsStore
29
33
from synapse .storage .types import Cursor
40
44
logger = logging .getLogger (__name__ )
41
45
42
46
47
+ class ExternalIDReuseException (Exception ):
48
+ """Exception if writing an external id for a user fails,
49
+ because this external id is given to an other user."""
50
+
51
+ pass
52
+
53
+
43
54
@attr .s (frozen = True , slots = True )
44
55
class TokenLookupResult :
45
56
"""Result of looking up an access token.
@@ -588,24 +599,44 @@ async def record_user_external_id(
588
599
auth_provider: identifier for the remote auth provider
589
600
external_id: id on that system
590
601
user_id: complete mxid that it is mapped to
602
+ Raises:
603
+ ExternalIDReuseException if the new external_id could not be mapped.
591
604
"""
592
- await self .db_pool .simple_insert (
605
+
606
+ try :
607
+ await self .db_pool .runInteraction (
608
+ "record_user_external_id" ,
609
+ self ._record_user_external_id_txn ,
610
+ auth_provider ,
611
+ external_id ,
612
+ user_id ,
613
+ )
614
+ except self .database_engine .module .IntegrityError :
615
+ raise ExternalIDReuseException ()
616
+
617
+ def _record_user_external_id_txn (
618
+ self ,
619
+ txn : LoggingTransaction ,
620
+ auth_provider : str ,
621
+ external_id : str ,
622
+ user_id : str ,
623
+ ) -> None :
624
+
625
+ self .db_pool .simple_insert_txn (
626
+ txn ,
593
627
table = "user_external_ids" ,
594
628
values = {
595
629
"auth_provider" : auth_provider ,
596
630
"external_id" : external_id ,
597
631
"user_id" : user_id ,
598
632
},
599
- desc = "record_user_external_id" ,
600
633
)
601
634
602
635
async def remove_user_external_id (
603
636
self , auth_provider : str , external_id : str , user_id : str
604
637
) -> None :
605
638
"""Remove a mapping from an external user id to a mxid
606
-
607
639
If the mapping is not found, this method does nothing.
608
-
609
640
Args:
610
641
auth_provider: identifier for the remote auth provider
611
642
external_id: id on that system
@@ -621,6 +652,60 @@ async def remove_user_external_id(
621
652
desc = "remove_user_external_id" ,
622
653
)
623
654
655
+ async def replace_user_external_id (
656
+ self ,
657
+ record_external_ids : List [Tuple [str , str ]],
658
+ user_id : str ,
659
+ ) -> None :
660
+ """Replace mappings from external user ids to a mxid in a single transaction.
661
+ All mappings are deleted and the new ones are created.
662
+
663
+ Args:
664
+ record_external_ids:
665
+ List with tuple of auth_provider and external_id to record
666
+ user_id: complete mxid that it is mapped to
667
+ Raises:
668
+ ExternalIDReuseException if the new external_id could not be mapped.
669
+ """
670
+
671
+ def _remove_user_external_ids_txn (
672
+ txn : LoggingTransaction ,
673
+ user_id : str ,
674
+ ) -> None :
675
+ """Remove all mappings from external user ids to a mxid
676
+ If these mappings are not found, this method does nothing.
677
+
678
+ Args:
679
+ user_id: complete mxid that it is mapped to
680
+ """
681
+
682
+ self .db_pool .simple_delete_txn (
683
+ txn ,
684
+ table = "user_external_ids" ,
685
+ keyvalues = {"user_id" : user_id },
686
+ )
687
+
688
+ def _replace_user_external_id_txn (
689
+ txn : LoggingTransaction ,
690
+ ):
691
+ _remove_user_external_ids_txn (txn , user_id )
692
+
693
+ for auth_provider , external_id in record_external_ids :
694
+ self ._record_user_external_id_txn (
695
+ txn ,
696
+ auth_provider ,
697
+ external_id ,
698
+ user_id ,
699
+ )
700
+
701
+ try :
702
+ await self .db_pool .runInteraction (
703
+ "replace_user_external_id" ,
704
+ _replace_user_external_id_txn ,
705
+ )
706
+ except self .database_engine .module .IntegrityError :
707
+ raise ExternalIDReuseException ()
708
+
624
709
async def get_user_by_external_id (
625
710
self , auth_provider : str , external_id : str
626
711
) -> Optional [str ]:
0 commit comments