dappforce/subsocial-solochain

Create Roles pallet

subsocialdev opened this issue · 0 comments

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 with Post)
  • Think about a default role or permissions per Subsocial.
  • Move Permission struct and EveryonePermissionsBySpaceId with FollowerPermissionsBySpaceId to a separate pallet permissions?
  • Merge EveryonePermissionsBySpaceId with FollowerPermissionsBySpaceId into a struct SpacePermissions?