# Buggy code
async def on_POST(
    self, request: SynapseRequest, room_identifier: str
) -> Tuple[int, JsonDict]:
    requester = await self.auth.get_user_by_req(request)
    await assert_user_is_admin(self.auth, requester.user)

    content = parse_json_object_from_request(request)

    assert_params_in_dict(content, ["user_id"])
    target_user = UserID.from_string(content["user_id"])

    if not self.hs.is_mine(target_user):
        raise SynapseError(400, "This endpoint can only be used with local users")

    if not await self.admin_handler.get_user(target_user):
        raise NotFoundError("User not found")

    if RoomID.is_valid(room_identifier):
        room_id = room_identifier
        try:
            remote_room_hosts = [
                x.decode("ascii") for x in request.args[b"server_name"]
            ]  # type: Optional[List[str]]
        except Exception:
            remote_room_hosts = None
    elif RoomAlias.is_valid(room_identifier):
        handler = self.room_member_handler
        room_alias = RoomAlias.from_string(room_identifier)
        room_id, remote_room_hosts = await handler.lookup_room_alias(room_alias)
    else:
        raise SynapseError(
            400, "%s was not legal room ID or room alias" % (room_identifier,)
        )

    fake_requester = create_requester(
        target_user, authenticated_entity=requester.authenticated_entity
    )

    # send invite if room has "JoinRules.INVITE"
    room_state = await self.state_handler.get_current_state(room_id)
    join_rules_event = room_state.get((EventTypes.JoinRules, ""))
    if join_rules_event:
        if not (join_rules_event.content.get("join_rule") == JoinRules.PUBLIC):
            # update_membership with an action of "invite" can raise a
            # ShadowBanError. This is not handled since it is assumed that
            # an admin isn't going to call this API with a shadow-banned user.
            await self.room_member_handler.update_membership(
                requester=requester,
                target=fake_requester.user,
                room_id=room_id,
                action="invite",
                remote_room_hosts=remote_room_hosts,
                ratelimit=False,
            )

    await self.room_member_handler.update_membership(
        requester=fake_requester,
        target=fake_requester.user,
        room_id=room_id,
        action="join",
        remote_room_hosts=remote_room_hosts,
        ratelimit=False,
    )

    return 200, {"room_id": room_id}


# Traceback (ValueError)
2021-02-26 14:01:23,554 - synapse.http.server - 94 - ERROR - POST-320 - Failed handle request via 'JoinRoomAliasServlet': <XForwardedForRequest at 0x7feef12ec358 method='POST' uri='/_synapse/admin/v1/join/%23test%3Aexemple.test.com' clientproto='HTTP/1.1' site='8008'>
Traceback (most recent call last):
File "/opt/synapse2/env/lib/python3.6/site-packages/twisted/internet/defer.py", line 1416, in _inlineCallbacks
result = result.throwExceptionIntoGenerator(g)
File "/opt/synapse2/env/lib/python3.6/site-packages/twisted/python/failure.py", line 512, in throwExceptionIntoGenerator
return g.throw(self.type, self.value, self.tb)
File "/opt/synapse2/env/lib/python3.6/site-packages/synapse/storage/databases/main/event_federation.py", line 634, in get_latest_event_ids_in_room
desc="get_latest_event_ids_in_room",
File "/opt/synapse2/env/lib/python3.6/site-packages/synapse/storage/database.py", line 1453, in simple_select_onecol
db_autocommit=True,
File "/opt/synapse2/env/lib/python3.6/site-packages/synapse/storage/database.py", line 676, in runInteraction
**kwargs,
File "/opt/synapse2/env/lib/python3.6/site-packages/synapse/storage/database.py", line 752, in runWithConnection
self._db_pool.runWithConnection(inner_func, *args, **kwargs)
File "/opt/synapse2/env/lib/python3.6/site-packages/twisted/python/threadpool.py", line 250, in inContext
result = inContext.theWork()
File "/opt/synapse2/env/lib/python3.6/site-packages/twisted/python/threadpool.py", line 266, in <lambda>
inContext.theWork = lambda: context.call(ctx, func, *args, **kw)
File "/opt/synapse2/env/lib/python3.6/site-packages/twisted/python/context.py", line 122, in callWithContext
return self.currentContext().callWithContext(ctx, func, *args, **kw)
File "/opt/synapse2/env/lib/python3.6/site-packages/twisted/python/context.py", line 85, in callWithContext
return func(*args,**kw)
File "/opt/synapse2/env/lib/python3.6/site-packages/twisted/enterprise/adbapi.py", line 306, in _runWithConnection
compat.reraise(excValue, excTraceback)
File "/opt/synapse2/env/lib/python3.6/site-packages/twisted/python/compat.py", line 464, in reraise
raise exception.with_traceback(traceback)
File "/opt/synapse2/env/lib/python3.6/site-packages/twisted/enterprise/adbapi.py", line 297, in _runWithConnection
result = func(conn, *args, **kw)
File "/opt/synapse2/env/lib/python3.6/site-packages/synapse/storage/database.py", line 746, in inner_func
return func(db_conn, *args, **kwargs)
File "/opt/synapse2/env/lib/python3.6/site-packages/synapse/storage/database.py", line 540, in new_transaction
r = func(cursor, *args, **kwargs)
File "/opt/synapse2/env/lib/python3.6/site-packages/synapse/storage/database.py", line 1422, in simple_select_onecol_txn
txn.execute(sql, list(keyvalues.values()))
File "/opt/synapse2/env/lib/python3.6/site-packages/synapse/storage/database.py", line 295, in execute
self._do_execute(self.txn.execute, sql, *args)
File "/opt/synapse2/env/lib/python3.6/site-packages/synapse/storage/database.py", line 321, in _do_execute
return func(sql, *args)
File "/opt/synapse2/env/lib/python3.6/site-packages/psycopg2/extensions.py", line 121, in getquoted
pobjs = [adapt(o) for o in self._seq]
File "/opt/synapse2/env/lib/python3.6/site-packages/synapse/types.py", line 220, in __iter__
raise ValueError("Attempted to iterate a %s" % (type(self).__name__,))
ValueError: Attempted to iterate a RoomID

# Fixed code
async def on_POST(
    self, request: SynapseRequest, room_identifier: str
) -> Tuple[int, JsonDict]:
    requester = await self.auth.get_user_by_req(request)
    await assert_user_is_admin(self.auth, requester.user)

    content = parse_json_object_from_request(request)

    assert_params_in_dict(content, ["user_id"])
    target_user = UserID.from_string(content["user_id"])

    if not self.hs.is_mine(target_user):
        raise SynapseError(400, "This endpoint can only be used with local users")

    if not await self.admin_handler.get_user(target_user):
        raise NotFoundError("User not found")

    # Get the room ID from the identifier.
    try:
        remote_room_hosts = [x.decode("ascii") for x in request.args[b"server_name"]]  # type: Optional[List[str]]
    except Exception:
        remote_room_hosts = None
    room_id, remote_room_hosts = await self.resolve_room_id(
        room_identifier, remote_room_hosts
    )

    fake_requester = create_requester(
        target_user, authenticated_entity=requester.authenticated_entity
    )

    # send invite if room has "JoinRules.INVITE"
    room_state = await self.state_handler.get_current_state(room_id)
    join_rules_event = room_state.get((EventTypes.JoinRules, ""))
    if join_rules_event:
        if not (join_rules_event.content.get("join_rule") == JoinRules.PUBLIC):
            # update_membership with an action of "invite" can raise a
            # ShadowBanError. This is not handled since it is assumed that
            # an admin isn't going to call this API with a shadow-banned user.
            await self.room_member_handler.update_membership(
                requester=requester,
                target=fake_requester.user,
                room_id=room_id,
                action="invite",
                remote_room_hosts=remote_room_hosts,
                ratelimit=False,
            )

    await self.room_member_handler.update_membership(
        requester=fake_requester,
        target=fake_requester.user,
        room_id=room_id,
        action="join",
        remote_room_hosts=remote_room_hosts,
        ratelimit=False,
    )

    return 200, {"room_id": room_id}