To determine the permission for an object, Gjallar has to know the user using that object. In the webbapp, the current user is retrieved from the session. It is possible to override the default behaviour on any level:
- Q2Object - A derived object class can override readCheck/writeCheck.
- Q2Session - A derived session class can override isReadable:/isWritable:.
- Q2User - A derived user class can override canRead:/canWrite:
The handling of permissions in the base classes is described below.
Ultimately a permission test ends in asking the user what access level is given for this object in a process.
The test if a user has permission to an object: aUser getAccessLevelFor: anObject in: aProcess returns the allowed level; Write/Read/None.
All Q2Objects should know the current process context. Most Q2Objects have the process stored or easy accessible. The exception is imported objects, that have to be wrapped in a process context to handle different permissions in different processes. Q2Object implements “process” as ^nil, and the subclasses should override this method.
When we know that anObject knows its process we can use:
aUser canRead: anObject, or aUser canWrite: anObject
Q2User>>canRead: anObject is implemented as:
"Can this user read this object?"
| process |
process := anObject process.
^(self canAccess: process) and: [
(self getAccessLevelFor: anObject in: process) >= Q2Permission read]
Q2FullAccessUser>>canRead: anObject is implemented as: ^true
In the webapp we always have a current user. This is stored in the current Q2Session which implements isReadable: anObject.
^ anObject ifNil: [true] ifNotNil: [self currentUser canRead: anObject]
The current session is easy available allowing:
This could be implemented as: self session isReadable: anObject.
But, we need to be able to check collections of objects for permissions. When this is needed the current session is not available from the collection itself, so we have to use another Q2Object to get the session. The Q2Object>>readCheck: is used for this. For example in: Q2User>>allReadableCases
"All cases based on processes I can access
and the permissions in those processes."
| allCases |
allCases := OrderedCollection new.
self processes do: [:p | allCases addAll: (self readCheck: (p allCases asSet))].
The implementation of Q2Object>>readCheck: is:
| s |
s := self session.
(anObject isCollection) ifTrue: [^ anObject select: [:each | s isReadable: each]].
^ (s isReadable: anObject) ifTrue: [anObject] ifFalse: [nil]
Q2Object>>readCheck: should only be used with a collection as argument and of course from the Q2Object>>readCheck method.
If an imported object is about to be tested for permissions, it can be wrapped in an object knowing the process with: Q2Object>>readCheckIn: aProcess.