-- from http://stackoverflow.com/questions/41522159/typed-hierarchical-access-control-system
import Policy
import Data.Monoid ((<>))
ownersCanEdit, contributorsCanView, myPolicy :: Policy
ownersCanEdit = mkPolicy Owner Edit
contributorsCanView = mkPolicy Contributor View
ownersCantEdit = mkPolicy Owner None
myPolicy = ownersCantEdit <> ownersCanEdit <> contributorsCanView
publicPolicy :: Policy
publicPolicy = mkPolicy Public Edit
canPublicView :: Policy -> Bool
canPublicView = Public `can` View
main = do
print $ canPublicView myPolicy
print $ (Owner `can` Edit) myPolicy
print $ (Owner `can` Edit) publicPolicy
print $ (Contributor `can` View) ownersCanEdit
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Policy (
Role(..),
Level(..),
Policy,
mkPolicy,
can
) where
import Data.Semigroup (Max(..))
data Role = Public | Contributor | Owner
deriving (Eq, Ord, Show, Read, Enum, Bounded)
data Level = None | View | Edit
deriving (Eq, Ord, Show, Read, Enum, Bounded)
newtype Policy = Policy (Role -> Max Level) deriving (Monoid)
mkPolicy :: Role -> Level -> Policy
mkPolicy r l = Policy (Max . pol) where
pol :: Role -> Level
pol r'
| r' >= r = l
| otherwise = minBound
can :: Role -> Level -> Policy -> Bool
(r `can` l) (Policy f) = getMax (f r) >= l