Files
Copilot f6e25b0d32 Add "Email display" preference to control email address visibility (#11103)
* Initial plan

* Add emailDisplay TeamPreference to control email address visibility

Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>

* Add tests for emailDisplay TeamPreference policy logic

Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>

* tweaks

* Add Everyone setting, tests

* PR feedback

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>
Co-authored-by: Tom Moor <tom@getoutline.com>
2026-01-08 10:15:36 -05:00

106 lines
2.1 KiB
TypeScript

import { TeamPreference, EmailDisplay } from "@shared/types";
import { User, Team } from "@server/models";
import { allow } from "./cancan";
import {
and,
isTeamAdmin,
isTeamMember,
isTeamModel,
isTeamMutable,
or,
} from "./utils";
allow(User, "read", User, isTeamModel);
allow(User, "listUsers", Team, (actor, team) =>
and(
//
isTeamModel(actor, team),
!actor.isGuest
)
);
allow(User, "inviteUser", Team, (actor, team) =>
and(
isTeamModel(actor, team),
isTeamMutable(actor),
!actor.isGuest,
!actor.isViewer,
actor.isAdmin || !!team?.getPreference(TeamPreference.MembersCanInvite)
)
);
allow(User, ["update", "readDetails", "listApiKeys"], User, (actor, user) =>
or(
//
isTeamAdmin(actor, user),
actor.id === user?.id
)
);
allow(User, "readEmail", User, (actor, user) => {
const emailDisplay =
actor.team?.getPreference(TeamPreference.EmailDisplay) ??
EmailDisplay.Members;
if (emailDisplay === EmailDisplay.None) {
return or(isTeamAdmin(actor, user), actor.id === user?.id);
}
if (emailDisplay === EmailDisplay.Members) {
return or(
isTeamAdmin(actor, user),
isTeamMember(actor, user),
actor.id === user?.id
);
}
// EmailDisplay.Everyone
return or(
//
isTeamModel(actor, user),
actor.id === user?.id
);
});
allow(User, "delete", User, (actor, user) =>
or(
isTeamAdmin(actor, user),
and(
actor.id === user?.id,
!!actor.team.getPreference(TeamPreference.MembersCanDeleteAccount)
)
)
);
allow(User, ["activate", "suspend"], User, (actor, user) =>
and(isTeamAdmin(actor, user), user?.id !== actor.id)
);
allow(User, "promote", User, (actor, user) =>
and(
//
isTeamAdmin(actor, user),
!user?.isAdmin,
!user?.isSuspended,
user?.id !== actor.id
)
);
allow(User, "demote", User, (actor, user) =>
and(
//
isTeamAdmin(actor, user),
!user?.isSuspended,
user?.id !== actor.id
)
);
allow(User, "resendInvite", User, (actor, user) =>
and(
//
isTeamAdmin(actor, user),
!!user?.isInvited
)
);