mirror of
https://github.com/outline/outline.git
synced 2026-08-03 13:27:25 +03:00
fix: Crash on open share menu when receiving group membership over wss (#13186)
This commit is contained in:
@@ -132,6 +132,7 @@ function DocumentMemberList({ document, invitedInSession }: Props) {
|
||||
new Map(
|
||||
groupMemberships
|
||||
.inDocument(document.id)
|
||||
.filter((membership) => membership.group)
|
||||
.map((membership) => [membership.group.id, membership])
|
||||
).values()
|
||||
)
|
||||
|
||||
@@ -320,16 +320,21 @@ function useDocumentHandlers() {
|
||||
socket.on(
|
||||
"documents.add_user",
|
||||
async (event: PartialExcept<UserMembership, "id">) => {
|
||||
userMemberships.add(event);
|
||||
const membership = userMemberships.add(event);
|
||||
|
||||
if (event.userId === currentUserId) {
|
||||
invalidateChildPolicies(event.documentId!, { documents, policies });
|
||||
}
|
||||
|
||||
try {
|
||||
await documents.fetch(event.documentId!, {
|
||||
force: event.userId === currentUserId,
|
||||
});
|
||||
// The event only references related models by ID, load any that are
|
||||
// not already in memory so that the membership can be displayed.
|
||||
await Promise.all([
|
||||
documents.fetch(event.documentId!, {
|
||||
force: event.userId === currentUserId,
|
||||
}),
|
||||
membership.loadRelations({ withoutPolicies: true }),
|
||||
]);
|
||||
} catch (err) {
|
||||
Logger.error("Failed to fetch document after add_user", toError(err));
|
||||
}
|
||||
@@ -354,14 +359,25 @@ function useDocumentHandlers() {
|
||||
|
||||
socket.on(
|
||||
"documents.add_group",
|
||||
(event: PartialExcept<GroupMembership, "id">) => {
|
||||
groupMemberships.add(event);
|
||||
async (event: PartialExcept<GroupMembership, "id">) => {
|
||||
const membership = groupMemberships.add(event);
|
||||
|
||||
const group = groups.get(event.groupId!);
|
||||
|
||||
if (currentUserId && group?.users.some((u) => u.id === currentUserId)) {
|
||||
invalidateChildPolicies(event.documentId!, { documents, policies });
|
||||
}
|
||||
|
||||
try {
|
||||
// The event only references related models by ID, load any that are
|
||||
// not already in memory so that the membership can be displayed.
|
||||
await membership.loadRelations({ withoutPolicies: true });
|
||||
} catch (err) {
|
||||
Logger.error(
|
||||
"Failed to load relations after add_group",
|
||||
toError(err)
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -478,11 +494,16 @@ function useCollectionHandlers() {
|
||||
);
|
||||
|
||||
socket.on("collections.add_user", async (event: Membership) => {
|
||||
memberships.add(event);
|
||||
const membership = memberships.add(event);
|
||||
try {
|
||||
await collections.fetch(event.collectionId, {
|
||||
force: event.userId === currentUserId,
|
||||
});
|
||||
// The event only references related models by ID, load any that are not
|
||||
// already in memory so that the membership can be displayed.
|
||||
await Promise.all([
|
||||
collections.fetch(event.collectionId, {
|
||||
force: event.userId === currentUserId,
|
||||
}),
|
||||
membership.loadRelations({ withoutPolicies: true }),
|
||||
]);
|
||||
} catch (err) {
|
||||
Logger.error("Failed to fetch collection after add_user", toError(err));
|
||||
}
|
||||
@@ -498,9 +519,11 @@ function useCollectionHandlers() {
|
||||
});
|
||||
|
||||
socket.on("collections.add_group", async (event: GroupMembership) => {
|
||||
groupMemberships.add(event);
|
||||
const membership = groupMemberships.add(event);
|
||||
try {
|
||||
await collections.fetch(event.collectionId!);
|
||||
// The event only references related models by ID, load any that are not
|
||||
// already in memory so that the membership can be displayed.
|
||||
await membership.loadRelations({ withoutPolicies: true });
|
||||
} catch (err) {
|
||||
Logger.error(
|
||||
"Failed to fetch collection after add_group",
|
||||
@@ -593,9 +616,20 @@ function useGroupHandlers() {
|
||||
groups.remove(event.modelId);
|
||||
});
|
||||
|
||||
socket.on("groups.add_user", (event: PartialExcept<GroupUser, "id">) => {
|
||||
groupUsers.add(event);
|
||||
});
|
||||
socket.on(
|
||||
"groups.add_user",
|
||||
async (event: PartialExcept<GroupUser, "id">) => {
|
||||
const groupUser = groupUsers.add(event);
|
||||
|
||||
try {
|
||||
// The event only references related models by ID, load any that are
|
||||
// not already in memory so that the membership can be displayed.
|
||||
await groupUser.loadRelations({ withoutPolicies: true });
|
||||
} catch (err) {
|
||||
Logger.error("Failed to load relations after add_user", toError(err));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
socket.on("groups.remove_user", (event: PartialExcept<GroupUser, "id">) => {
|
||||
groupUsers.removeAll({
|
||||
|
||||
@@ -59,7 +59,7 @@ export default abstract class Model {
|
||||
const store = this.store.rootStore.getStoreForModelName(
|
||||
properties.relationClassResolver().modelName
|
||||
);
|
||||
if ("fetch" in store) {
|
||||
if ("canFetchById" in store && store.canFetchById) {
|
||||
const id = this[properties.idKey];
|
||||
if (id) {
|
||||
promises.push(store.fetch(id as string));
|
||||
@@ -69,7 +69,7 @@ export default abstract class Model {
|
||||
}
|
||||
|
||||
const policy = this.store.rootStore.policies.get(this.id);
|
||||
if (!policy && !options.withoutPolicies) {
|
||||
if (!policy && !options.withoutPolicies && this.store.canFetchById) {
|
||||
promises.push(this.store.fetch(this.id, { force: true }));
|
||||
}
|
||||
|
||||
|
||||
@@ -354,6 +354,13 @@ export default abstract class Store<T extends Model> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether individual models can be fetched by ID from this store.
|
||||
*/
|
||||
get canFetchById(): boolean {
|
||||
return this.actions.includes(RPCAction.Info);
|
||||
}
|
||||
|
||||
@action
|
||||
async fetch(
|
||||
id: string,
|
||||
|
||||
Reference in New Issue
Block a user