Skip to content

Commit

Permalink
DMs: add unblock command
Browse files Browse the repository at this point in the history
for #1406
  • Loading branch information
snarfed committed Feb 2, 2025
1 parent 3326226 commit 3485c7d
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 23 deletions.
26 changes: 20 additions & 6 deletions dms.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
'ok',
'start',
'stop',
'unblock',
'username',
'yes',
)
Expand Down Expand Up @@ -188,7 +189,7 @@ def reply(text, type=None):
return reply(str(e))
return reply(f"Your username in {to_proto.PHRASE} has been set to {from_user.user_link(proto=to_proto, name=False, handle=True)}. It should appear soon!")

if cmd == 'block' and arg:
if cmd in ('block', 'unblock') and arg:
handle = arg
if not to_proto.owns_handle(handle) and handle.startswith('@'):
logging.info(f"doesn't look like a handle, trying without leading @")
Expand All @@ -198,17 +199,30 @@ def reply(text, type=None):
if not to_user:
return reply(f"Couldn't find {to_proto.PHRASE} user {handle}")

block_id = f'{from_user.key.id()}#bridgy-fed-block-{util.now().isoformat()}'
obj = Object(id=block_id, source_protocol=from_user.LABEL, our_as1={
'id': block_id,
obj_as1 = {
'objectType': 'activity',
'verb': 'block',
'actor': from_user.key.id(),
'object': to_user.key.id(),
})
}

if cmd == 'block':
msg = f"""OK, you're now blocking {to_user.user_link()} on {to_proto.PHRASE}."""
elif cmd == 'unblock':
obj_as1 = {
'objectType': 'activity',
'verb': 'undo',
'actor': from_user.key.id(),
'object': obj_as1,
}
msg = f"""OK, you're not blocking {to_user.user_link()} on {to_proto.PHRASE}."""

id = f'{from_user.key.id()}#bridgy-fed-{cmd}-{util.now().isoformat()}'
obj_as1['id'] = id
obj = Object(id=id, source_protocol=from_user.LABEL, our_as1=obj_as1)
obj.put()
from_user.deliver(obj, from_user=from_user)
return reply(f"""OK, you're now blocking {to_user.user_link()} in {to_proto.PHRASE}.""")
return reply(msg)

# are they requesting a user?
if not cmd:
Expand Down
3 changes: 2 additions & 1 deletion protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -1399,9 +1399,10 @@ def targets(from_cls, obj, from_user, crud_obj=None, internal=False):
is_reply = obj.type == 'comment' or in_reply_tos
is_self_reply = False

original_ids = []
if is_reply:
original_ids = in_reply_tos
else:
elif inner_obj_id:
if inner_obj_id == from_user.key.id():
inner_obj_id = from_user.profile_id()
original_ids = [inner_obj_id]
Expand Down
2 changes: 2 additions & 0 deletions templates/docs.html
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ <h3 id="general">Using</h3>
<li class="answer">
<p>You can use the <code>block</code> <a href="#dm-commands">DM command</a>. First, find the Bridgy Fed bot account for the network they're in. Then, DM that account <code>block [handle]</code>, where handle is the address of the user you want to block.</p>
<p>For example, if you're on the fediverse, and you want to block @badguy.bsky.social on Bluesky, find the @[email protected] account and send it a DM with the text <code>block badguy.bsky.social</code>.
<p>If you change your mind, you can unblock them with the <code>unblock</code> command, eg <code>unblock badguy.bsky.social</code>.
</li>

<li id="enhanced" class="question">The <code>*.brid.gy</code> domain in my bridged account's handle is ugly. Can I get rid of it and use my own domain/web site instead?</li>
Expand All @@ -385,6 +386,7 @@ <h3 id="general">Using</h3>
<li><em>[handle]</em>: <a href="#dm-request">ask it to DM a user to request that they bridge their account</a>
<li><em>did</em>: get your bridged Bluesky account's <a href="https://atproto.com/guides/identity#identifiers">DID</a> (only supported with the Bluesky bot)
<li><em>block [handle]</em>: <a href="#">block a user on another network who's not bridged into your network</a>
<li><em>unblock [handle]</em>: <a href="#">unblock a user on another network who's not bridged into your network</a>
</ul>
</li>

Expand Down
63 changes: 47 additions & 16 deletions tests/test_dms.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
'to': ['other.brid.gy'],
}

DM_EFAKE_ALICE_REQUESTS_OTHER_BOB = {
DM_ALICE_REQUESTS_BOB = {
**DM_BASE,
'content': ' other:handle:bob ',
}
Expand All @@ -30,17 +30,23 @@
<p>If you do nothing, your account won't be bridged, and users on efake-phrase won't be able to see or interact with you.
<p>Bridgy Fed will only send you this message once."""

DM_EFAKE_ALICE_SET_USERNAME_OTHER = {
DM_ALICE_SET_USERNAME_OTHER = {
**DM_BASE,
'content': 'username new-handle',
}
ALICE_USERNAME_CONFIRMATION_CONTENT = 'Your username in other-phrase has been set to <a class="h-card u-author" rel="me" href="web:other:efake:alice" title="other:handle:efake:handle:alice">other:handle:efake:handle:alice</a>. It should appear soon!'

DM_EFAKE_ALICE_BLOCK_BOB = {
DM_ALICE_BLOCK_BOB = {
**DM_BASE,
'content': 'block other:handle:bob',
}
ALICE_BLOCK_CONFIRMATION_CONTENT = """OK, you're now blocking <a class="h-card u-author" rel="me" href="web:other:bob" title="other:handle:bob">other:handle:bob</a> in other-phrase."""
ALICE_BLOCK_CONFIRMATION_CONTENT = """OK, you're now blocking <a class="h-card u-author" rel="me" href="web:other:bob" title="other:handle:bob">other:handle:bob</a> on other-phrase."""

DM_ALICE_UNBLOCK_BOB = {
**DM_BASE,
'content': 'unblock other:handle:bob',
}
ALICE_UNBLOCK_CONFIRMATION_CONTENT = """OK, you're not blocking <a class="h-card u-author" rel="me" href="web:other:bob" title="other:handle:bob">other:handle:bob</a> on other-phrase."""


class DmsTest(TestCase):
Expand Down Expand Up @@ -221,7 +227,7 @@ def test_receive_no_yes_sets_enabled_protocols(self):
def test_receive_prompt_sends_request_dm(self):
alice, bob = self.make_alice_bob()

obj = Object(our_as1=DM_EFAKE_ALICE_REQUESTS_OTHER_BOB)
obj = Object(our_as1=DM_ALICE_REQUESTS_BOB)
self.assertEqual(('OK', 200), receive(from_user=alice, obj=obj))

self.assert_replied(OtherFake, alice, '?', ALICE_REQUEST_CONFIRMATION_CONTENT)
Expand Down Expand Up @@ -281,7 +287,7 @@ def test_receive_prompt_fetch_user(self):
enabled_protocols=['other'], obj_as1={'x': 'y'})
OtherFake.fetchable['other:bob'] = {'x': 'y'}

obj = Object(our_as1=DM_EFAKE_ALICE_REQUESTS_OTHER_BOB)
obj = Object(our_as1=DM_ALICE_REQUESTS_BOB)
self.assertEqual(('OK', 200), receive(from_user=alice, obj=obj))
self.assert_replied(OtherFake, alice, '?', ALICE_REQUEST_CONFIRMATION_CONTENT)
self.assert_sent(ExplicitFake, OtherFake(id='other:bob'),
Expand All @@ -294,7 +300,7 @@ def test_receive_prompt_user_doesnt_exist(self):
enabled_protocols=['other'], obj_as1={'x': 'y'})
OtherFake.fetchable = {}

obj = Object(our_as1=DM_EFAKE_ALICE_REQUESTS_OTHER_BOB)
obj = Object(our_as1=DM_ALICE_REQUESTS_BOB)
self.assertEqual(('OK', 200), receive(from_user=alice, obj=obj))
self.assert_replied(OtherFake, alice, '?', "Couldn't find other-phrase user other:handle:bob")
self.assertEqual([], OtherFake.sent)
Expand All @@ -305,7 +311,7 @@ def test_receive_prompt_from_user_not_bridged(self):
alice.enabled_protocols = ['fake']
alice.put()

obj = Object(our_as1=DM_EFAKE_ALICE_REQUESTS_OTHER_BOB)
obj = Object(our_as1=DM_ALICE_REQUESTS_BOB)
self.assertEqual(('OK', 200), receive(from_user=alice, obj=obj))
self.assert_replied(OtherFake, alice, '?', "Looks like you're not bridged to other-phrase yet!")
self.assertEqual([], OtherFake.sent)
Expand All @@ -316,7 +322,7 @@ def test_receive_prompt_already_bridged(self):
bob.enabled_protocols = ['efake']
bob.put()

obj = Object(our_as1=DM_EFAKE_ALICE_REQUESTS_OTHER_BOB)
obj = Object(our_as1=DM_ALICE_REQUESTS_BOB)
self.assertEqual(('OK', 200), receive(from_user=alice, obj=obj))
self.assert_replied(OtherFake, alice, '?', """<a class="h-card u-author" rel="me" href="web:efake:other:bob" title="other:handle:bob &middot; efake:handle:other:handle:bob"><span style="unicode-bidi: isolate">other:handle:bob</span> &middot; efake:handle:other:handle:bob</a> is already bridged into efake-phrase.""")
self.assertEqual([], OtherFake.sent)
Expand All @@ -326,7 +332,7 @@ def test_receive_prompt_already_requested(self):
bob.sent_dms = [DM(protocol='efake', type='request_bridging')]
bob.put()

obj = Object(our_as1=DM_EFAKE_ALICE_REQUESTS_OTHER_BOB)
obj = Object(our_as1=DM_ALICE_REQUESTS_BOB)
self.assertEqual(('OK', 200), receive(from_user=alice, obj=obj))
self.assert_replied(OtherFake, alice, '?', """We've already sent <a class="h-card u-author" rel="me" href="web:other:bob" title="other:handle:bob">other:handle:bob</a> a DM. Fingers crossed!""")
self.assertEqual([], OtherFake.sent)
Expand All @@ -338,7 +344,7 @@ def test_receive_prompt_request_rate_limit(self):
eve = self.make_user(id='other:eve', cls=OtherFake, obj_as1={'x': 'y'})
frank = self.make_user(id='other:frank', cls=OtherFake, obj_as1={'x': 'y'})

obj = Object(our_as1=DM_EFAKE_ALICE_REQUESTS_OTHER_BOB)
obj = Object(our_as1=DM_ALICE_REQUESTS_BOB)
self.assertEqual(('OK', 200), receive(from_user=alice, obj=obj))

obj = Object(our_as1={
Expand Down Expand Up @@ -381,7 +387,7 @@ def test_receive_prompt_wrong_protocol(self):
@mock.patch('ids.translate_handle', side_effect=ValueError('nope'))
def test_receive_prompt_not_supported_in_target_protocol(self, _):
alice, bob = self.make_alice_bob()
obj = Object(our_as1=DM_EFAKE_ALICE_REQUESTS_OTHER_BOB)
obj = Object(our_as1=DM_ALICE_REQUESTS_BOB)

self.assertEqual(('OK', 200), receive(from_user=alice, obj=obj))
self.assert_replied(OtherFake, alice, '?', "Sorry, Bridgy Fed doesn't yet support bridging handle other:handle:bob from other-phrase to efake-phrase.")
Expand All @@ -392,7 +398,7 @@ def test_receive_username(self):
alice = self.make_user(id='efake:alice', cls=ExplicitFake,
enabled_protocols=['other'], obj_as1={'x': 'y'})

obj = Object(our_as1=DM_EFAKE_ALICE_SET_USERNAME_OTHER)
obj = Object(our_as1=DM_ALICE_SET_USERNAME_OTHER)
self.assertEqual(('OK', 200), receive(from_user=alice, obj=obj))
self.assert_replied(OtherFake, alice, '?', ALICE_USERNAME_CONFIRMATION_CONTENT)
self.assertEqual({'efake:alice': 'new-handle'}, OtherFake.usernames)
Expand All @@ -416,7 +422,7 @@ def test_receive_username_fails(self, _):
alice = self.make_user(id='efake:alice', cls=ExplicitFake,
enabled_protocols=['other'], obj_as1={'x': 'y'})

obj = Object(our_as1=DM_EFAKE_ALICE_SET_USERNAME_OTHER)
obj = Object(our_as1=DM_ALICE_SET_USERNAME_OTHER)
self.assertEqual(('OK', 200), receive(from_user=alice, obj=obj))
self.assert_replied(OtherFake, alice, '?', 'nopey')
self.assertEqual({}, OtherFake.usernames)
Expand Down Expand Up @@ -470,7 +476,7 @@ def test_receive_did_atproto(self):
def test_receive_block(self):
alice, bob = self.make_alice_bob()

obj = Object(our_as1=DM_EFAKE_ALICE_BLOCK_BOB)
obj = Object(our_as1=DM_ALICE_BLOCK_BOB)
self.assertEqual(('OK', 200), receive(from_user=alice, obj=obj))

self.assert_replied(OtherFake, alice, '?', ALICE_BLOCK_CONFIRMATION_CONTENT)
Expand All @@ -491,7 +497,7 @@ def test_receive_block_handle_at_symbol(self):
alice, bob = self.make_alice_bob()

obj = Object(our_as1={
**DM_EFAKE_ALICE_BLOCK_BOB,
**DM_ALICE_BLOCK_BOB,
'content': ' block @other:handle:bob ',
})
self.assertEqual(('OK', 200), receive(from_user=alice, obj=obj))
Expand All @@ -504,3 +510,28 @@ def test_receive_block_handle_at_symbol(self):
'actor': 'efake:alice',
'object': 'other:bob',
})], OtherFake.sent)

def test_receive_unblock(self):
alice, bob = self.make_alice_bob()

obj = Object(our_as1=DM_ALICE_UNBLOCK_BOB)
self.assertEqual(('OK', 200), receive(from_user=alice, obj=obj))

self.assert_replied(OtherFake, alice, '?', ALICE_UNBLOCK_CONFIRMATION_CONTENT)

unblock_as1 = {
'objectType': 'activity',
'verb': 'undo',
'id': 'efake:alice#bridgy-fed-unblock-2022-01-02T03:04:05+00:00',
'actor': 'efake:alice',
'object': {
'objectType': 'activity',
'verb': 'block',
'actor': 'efake:alice',
'object': 'other:bob',
},
}
self.assert_object(id='efake:alice#bridgy-fed-unblock-2022-01-02T03:04:05+00:00',
our_as1=unblock_as1, source_protocol='efake',
ignore=['copies'])
self.assertEqual([('other:bob:target', unblock_as1)], OtherFake.sent)

0 comments on commit 3485c7d

Please sign in to comment.