Create Roles pallet
subsocialdev opened this issue · 0 comments
subsocialdev commented
Permissions
pallet design
enum SpacePermission {
/// Create, update, grant and revoke roles in this space.
ManageRoles,
/// Create, update own and delete any subspaces in this space.
ManageSubspaces,
/// Create, update own and delete any root posts in this space.
ManagePosts,
/// Create, update own and delete any comments in this space.
ManageComments,
/// Act on behalf of this space within this space.
RepresentSpaceInternally,
/// Act on behalf of this space outside of this space.
RepresentSpaceExternally,
UpdateSpace,
BlockUsers, // or BlockActors
// TODO what about 'DeleteSpace'? (too dangerous)
// Related to subspaces in this space:
CreateSubspaces,
UpdateOwnSubspaces,
DeleteOwnSubspaces,
DeleteAnySubspaces,
// Related to posts in this space:
CreatePosts,
UpdateOwnPosts,
DeleteOwnPosts,
DeleteAnyPosts,
// Related to comments in this space:
CreateComments,
UpdateOwnComments,
DeleteOwnComments,
DeleteAnyComments,
/// Upvote on any post or comment in this space.
Upvote,
/// Upvote on any post or comment in this space.
Downvote,
/// Share any post or comment from this space to another outer space.
Share,
}
enum PostPermission {
// Related to comments on this post:
CreateComments,
UpdateOwnComments,
DeleteOwnComments,
// Related to this post and its comments:
Upvote,
Downvote,
Share,
}
Changes to Social
pallet
We can add permissions overrides directly to Space
and Post
structs. We already load Space
and root Post
(if adding a comment) in the extrinsic create_post()
. This means that if we have permissions overrides in the loaded Space
and root Post
then we don't need to do an extra read-request to Runtime storage – that is great performance optimization.
// NOTE: Currently it's called `Blog` struct.
struct Space {
// ... previous fields go here ...
/// Overrides the default permissions for everyone on this space.
/// If `None` then this space does not override the default permissions for everyone.
pub everyonePermissions: Option<BTreeSet<SpacePermission>>,
/// Overrides the default permissions for followers on this space.
/// If `None` then this space does not override the default permissions for followers.
pub followerPermissions: Option<BTreeSet<SpacePermission>>,
}
struct Post {
// ... previous fields go here ...
/// Overrides the default permissions for everyone on this post and its comments.
/// If `None` then this post does not override the default permissions for followers.
pub everyonePermissions: Option<BTreeSet<PostPermission>>,
/// Overrides the default permissions for followers on this post and its comments.
/// If `None` then this post does not override the default permissions for followers.
pub followerPermissions: Option<BTreeSet<PostPermission>>,
}
Roles
pallet design
type RoleId = u64;
struct Role<T: Trait> {
pub created: WhoAndWhen<T>,
pub updated: Option<WhoAndWhen<T>>,
pub id: RoleId,
pub space_id: SpaceId,
pub disabled: bool,
pub ipfs_hash: Vec<u8>,
pub permissions: BTreeSet<SpacePermission>,
}
pub struct RoleUpdate {
pub disabled: Option<bool>,
pub ipfs_hash: Option<Vec<u8>>,
pub permissions: Option<BTreeSet<SpacePermission>>,
}
// TODO Move this helper enum to `utils` pallet.
// TODO Maybe this enum to 'User'?
enum Actor<AccountId> {
Account(AccountId),
Space(SpaceId)
}
decl_storage! {
/// Get role details by ids id.
RoleById: map RoleId => Option<Role<T>>;
/// A list of all account ids and space ids that have this role.
ActorsByRoleId: map RoleId => Vec<Actor>;
/// A list of all role ids available in this space.
RoleIdsBySpaceId: map SpaceId => Vec<RoleId>;
/// A list of all role ids granted to this actor (either account of space) within this space.
InSpaceRoleIdsByActor: double_map (Actor, SpaceId) => Vec<RoleId>;
}
// Extrinsics
/// Create a new role within this space with the list of particular permissions.
/// `ipfs_hash` points to the off-chain content with such role info as name, description, color.
/// Only the space owner or an actor with `ManageRoles` permission can execute this extrinsic.
pub fn create_role(origin, space_id: SpaceId, permissions: BTreeSet<SpacePermission>, ipfs_hash: Vec<u8>) {}
/// Update an existing role on specified space.
/// It is possible to either update permissions by overriding existing permissions,
/// or update IPFS hash or both.
/// Only the space owner or an actor with `ManageRoles` permission can execute this extrinsic.
pub fn update_role(origin, role_id: RoleId, update: RoleUpdate) {}
/// Delete the role from all associated storage items.
/// Only the space owner or an actor with `ManageRoles` permission can execute this extrinsic.
pub fn delete_role(origin, role_id: RoleId, update: RoleUpdate) {}
/// Grant the role from the list of actors.
/// Only the space owner or an actor with `ManageRoles` permission can execute this extrinsic.
pub fn grant_role(origin, role_id: RoleId, actors: Vec<Actor>) {}
/// Revoke the role from the list of actors.
/// Only the space owner, an actor with `ManageRoles` permission or an actor that has this role can execute this extrinsic.
pub fn revoke_role(origin, role_id: RoleId, actors: Vec<Actor>) {}
/// Disable the role. If the role is disabled, their permissions should not be taken into account.
/// Should throw an error if the role is not enabled.
/// Only the space owner or an actor with `ManageRoles` permission can execute this extrinsic.
pub fn disable_role(origin, role_id: RoleId) {}
/// Enable the role. Should throw an error if the role is not disabled.
/// Only the space owner or an actor with `ManageRoles` permission can execute this extrinsic.
pub fn enable_role(origin, role_id: RoleId) {}
Open questions
- Think about creating a
RoleUpdate
struct (same as we do withPost
) - Think about a default role or permissions per Subsocial.
- Move
Permission
struct andEveryonePermissionsBySpaceId
withFollowerPermissionsBySpaceId
to a separate palletpermissions
? - Merge
EveryonePermissionsBySpaceId
withFollowerPermissionsBySpaceId
into a structSpacePermissions
?