This commit is contained in:
j3d1 2026-08-27 03:14:01 +02:00
parent 9685b4020e
commit 22931452e3
7 changed files with 28 additions and 21 deletions

View file

@ -1,8 +1,15 @@
from django.contrib import admin from django.contrib import admin
from django.contrib.auth.models import Group as DjangoPermissionGroup
from authentication.models import ToolshedUser, KnownIdentity, FriendRequestOutgoing, FriendRequestIncoming, \ from authentication.models import ToolshedUser, KnownIdentity, FriendRequestOutgoing, FriendRequestIncoming, \
AccountPreference, Group, GroupInvite, GroupInviteIncoming, GroupMembership AccountPreference, Group, GroupInvite, GroupInviteIncoming, GroupMembership
# django.contrib.auth's own permission-groups model is unused (this app authenticates via
# signature_auth, not Django's built-in permission system) and otherwise collides in the admin
# sidebar with our own Group (the actor-type group), which is registered below under the same
# "Groups" label.
admin.site.unregister(DjangoPermissionGroup)
class ToolshedUserAdmin(admin.ModelAdmin): class ToolshedUserAdmin(admin.ModelAdmin):
list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff', 'is_active', 'date_joined', 'domain') list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff', 'is_active', 'date_joined', 'domain')

View file

@ -50,13 +50,13 @@ def resolve_tag_handle(handle):
class FriendSerializer(serializers.ModelSerializer): class FriendSerializer(serializers.ModelSerializer):
username = serializers.SerializerMethodField() handle = serializers.SerializerMethodField()
class Meta: class Meta:
model = KnownIdentity model = KnownIdentity
fields = ['id', 'username', 'public_key'] fields = ['id', 'handle', 'public_key']
def get_username(self, obj): def get_handle(self, obj):
return obj.username + '@' + obj.domain return obj.username + '@' + obj.domain
@ -72,13 +72,13 @@ class FriendRequestSerializer(serializers.ModelSerializer):
class GroupMemberSerializer(serializers.ModelSerializer): class GroupMemberSerializer(serializers.ModelSerializer):
username = serializers.SerializerMethodField() handle = serializers.SerializerMethodField()
class Meta: class Meta:
model = KnownIdentity model = KnownIdentity
fields = ['id', 'username', 'public_key'] fields = ['id', 'handle', 'public_key']
def get_username(self, obj): def get_handle(self, obj):
return obj.username + '@' + obj.domain return obj.username + '@' + obj.domain

View file

@ -63,20 +63,20 @@ class FriendApiTestCase(UserTestMixin, ToolshedTestCase):
reply = client.get('/api/friends/', self.f['local_user1']) reply = client.get('/api/friends/', self.f['local_user1'])
self.assertEqual(reply.status_code, 200) self.assertEqual(reply.status_code, 200)
self.assertEqual(len(reply.json()), 2) self.assertEqual(len(reply.json()), 2)
self.assertEqual(reply.json()[0]['username'], str(self.f['local_user2'])) self.assertEqual(reply.json()[0]['handle'], str(self.f['local_user2']))
self.assertEqual(reply.json()[1]['username'], str(self.f['ext_user1'])) self.assertEqual(reply.json()[1]['handle'], str(self.f['ext_user1']))
def test_friend_list_internal2(self): def test_friend_list_internal2(self):
reply = client.get('/api/friends/', self.f['local_user2']) reply = client.get('/api/friends/', self.f['local_user2'])
self.assertEqual(reply.status_code, 200) self.assertEqual(reply.status_code, 200)
self.assertEqual(len(reply.json()), 1) self.assertEqual(len(reply.json()), 1)
self.assertEqual(reply.json()[0]['username'], str(self.f['local_user1'])) self.assertEqual(reply.json()[0]['handle'], str(self.f['local_user1']))
def test_friend_list_external(self): def test_friend_list_external(self):
reply = client.get('/api/friends/', self.f['ext_user1']) reply = client.get('/api/friends/', self.f['ext_user1'])
self.assertEqual(reply.status_code, 200) self.assertEqual(reply.status_code, 200)
self.assertEqual(len(reply.json()), 1) self.assertEqual(len(reply.json()), 1)
self.assertEqual(reply.json()[0]['username'], str(self.f['local_user1'])) self.assertEqual(reply.json()[0]['handle'], str(self.f['local_user1']))
def test_friend_delete(self): def test_friend_delete(self):
reply = client.delete('/api/friends/{}/'.format(self.f['local_user2'].public_identity.id), reply = client.delete('/api/friends/{}/'.format(self.f['local_user2'].public_identity.id),

View file

@ -16,20 +16,20 @@ class IdMapTestCase(UserTestMixin, GroupTestMixin, ToolshedTestCase):
reply = client.get('/api/idmap/', self.f['local_user1']) reply = client.get('/api/idmap/', self.f['local_user1'])
self.assertEqual(reply.status_code, 200) self.assertEqual(reply.status_code, 200)
identities = reply.json()['identities'] identities = reply.json()['identities']
self.assertIn(str(self.f['local_user1']), [i['username'] for i in identities]) self.assertIn(str(self.f['local_user1']), [i['handle'] for i in identities])
def test_idmap_includes_friends(self): def test_idmap_includes_friends(self):
self.f['local_user1'].friends.add(self.f['local_user2'].public_identity) self.f['local_user1'].friends.add(self.f['local_user2'].public_identity)
reply = client.get('/api/idmap/', self.f['local_user1']) reply = client.get('/api/idmap/', self.f['local_user1'])
self.assertEqual(reply.status_code, 200) self.assertEqual(reply.status_code, 200)
identities = reply.json()['identities'] identities = reply.json()['identities']
self.assertIn(str(self.f['local_user2']), [i['username'] for i in identities]) self.assertIn(str(self.f['local_user2']), [i['handle'] for i in identities])
def test_idmap_excludes_non_friends(self): def test_idmap_excludes_non_friends(self):
reply = client.get('/api/idmap/', self.f['local_user1']) reply = client.get('/api/idmap/', self.f['local_user1'])
self.assertEqual(reply.status_code, 200) self.assertEqual(reply.status_code, 200)
identities = reply.json()['identities'] identities = reply.json()['identities']
self.assertNotIn(str(self.f['local_user2']), [i['username'] for i in identities]) self.assertNotIn(str(self.f['local_user2']), [i['handle'] for i in identities])
def test_idmap_includes_member_groups(self): def test_idmap_includes_member_groups(self):
self.prepare_groups() self.prepare_groups()

View file

@ -39,7 +39,7 @@ export default {
computed: { computed: {
...mapGetters(['allUserProfiles']), ...mapGetters(['allUserProfiles']),
displayUsername() { displayUsername() {
return this.user.username || this.user.owner || ''; return this.user.handle || this.user.owner || '';
}, },
profilePictureUrl() { profilePictureUrl() {
// Check for explicitly set profile picture from allUserProfiles getter // Check for explicitly set profile picture from allUserProfiles getter

View file

@ -370,11 +370,11 @@ export default createStore({
servers.add(home) servers.add(home)
for (const friend of friends) { for (const friend of friends) {
try { try {
const s = await dispatch('lookupServer', {username: friend.username}) const s = await dispatch('lookupServer', {username: friend.handle})
servers.add(new ServerSet(s, state.unreachable_neighbors)) servers.add(new ServerSet(s, state.unreachable_neighbors))
} catch (e) { } catch (e) {
// Skip an unresolvable/unreachable friend rather than aborting the whole lookup. // Skip an unresolvable/unreachable friend rather than aborting the whole lookup.
console.error('could not resolve server for friend', friend.username, e) console.error('could not resolve server for friend', friend.handle, e)
} }
} }
return servers return servers
@ -893,13 +893,13 @@ export default createStore({
groupInventoryItems: (state) => (groupHandle) => state.item_map['/' + groupHandle] || [], groupInventoryItems: (state) => (groupHandle) => state.item_map['/' + groupHandle] || [],
groupStorageLocations: (state) => (groupHandle) => state.location_map['/' + groupHandle] || [], groupStorageLocations: (state) => (groupHandle) => state.location_map['/' + groupHandle] || [],
identityIdByHandle(state) { identityIdByHandle(state) {
return Object.fromEntries(state.idmap.identities.map(i => [i.username, i.id])) return Object.fromEntries(state.idmap.identities.map(i => [i.handle, i.id]))
}, },
groupIdByHandle(state) { groupIdByHandle(state) {
return Object.fromEntries(state.idmap.groups.map(g => [g.handle, g.id])) return Object.fromEntries(state.idmap.groups.map(g => [g.handle, g.id]))
}, },
identityHandleById(state) { identityHandleById(state) {
return Object.fromEntries(state.idmap.identities.map(i => [i.id, i.username])) return Object.fromEntries(state.idmap.identities.map(i => [i.id, i.handle]))
}, },
groupHandleById(state) { groupHandleById(state) {
return Object.fromEntries(state.idmap.groups.map(g => [g.id, g.handle])) return Object.fromEntries(state.idmap.groups.map(g => [g.id, g.handle]))

View file

@ -142,8 +142,8 @@ export default {
const friendsList = Array.isArray(friends) ? friends : Object.values(friends); const friendsList = Array.isArray(friends) ? friends : Object.values(friends);
friendsList.map((friend) => { friendsList.map((friend) => {
this.lookupServer(friend).then((server) => { this.lookupServer(friend).then((server) => {
this.friends[friend.username] = {...friend, server: server} this.friends[friend.handle] = {...friend, server: server}
this.fetchFriendProfile({username: friend.username}); this.fetchFriendProfile({username: friend.handle});
}) })
}) })
}) })
@ -175,7 +175,7 @@ export default {
tryDropFriend(friend) { tryDropFriend(friend) {
this.dropFriend(friend).then((ok) => { this.dropFriend(friend).then((ok) => {
if (ok) { if (ok) {
delete this.friends[friend.username] delete this.friends[friend.handle]
} }
}).catch(() => { }).catch(() => {
}) })