faustram
(Fausto Rambotti)
December 5, 2017, 10:10am
1
Hi all, Is it possible to have different views for different users on the same content type?
This is the scenario that I want:
UserA can login and be redirected to "istanceOfMyCT" which show ViewA (it can be even the default view);
UserB can login and be redirected to "istanceOfMyCT" (the same one istance used by UserA), but for this user show ViewB.
I already tryed to achieve this by using a specific role with a dedicated permission but this solution is not perfect:
The user with correct rights can see her dedicated view, but only him (not even "admin" can see the dedicated view);
The dedicate view is rendered whitout the any theme (I use the default, barcelloneta).
Any suggestions?
zopyx
(Andreas Jung)
December 5, 2017, 10:35am
2
Look at collective.onlogin addon for performing a login redirection after login. The implementation of the redirect switch based on some conditions is up to,you....and remember being „admin“ is like being god..god sees everything and there is no way to deny access to the superuser.
-aj
dieter
(Dieter Maurer)
December 5, 2017, 11:24am
3
Sure: You define a view which delegates to different views depending on the user.
I.e., it may contain code like the following:
from AccessControl import getSecurityManager
class SwitchingView(BrowserView):
...
def __call__(self):
user = getSecurityManager().getUser()
view_class = view_class1 if user == ... else
view_class2 if user == ... else
view_classn
return view_class(self.context, self.request).__call__()
2 Likes
espenmn
(Espen)
December 5, 2017, 12:03pm
4
I think there are quite a few ways of doing this.
The lazy ways are probably using CSS and/or TAL and hide/show things or redirect to another view
The proper way is probably more like how plone link is doing it:
if not url:
return uid, fragment
# resolve uid
paths = url.split("/")
paths_lower = [_item.lower() for _item in paths]
if "resolveuid" in paths_lower:
ri = paths_lower.index("resolveuid")
if ri + 1 != len(paths):
uid = paths[ri + 1]
if uid == "":
uid = None
if not uid:
return uid, fragment
# resolve fragment
parts = urlparse(uid)
This file has been truncated. show original
So, if it is possible, just make two (or more) templates.pt
probably, you dont need all the code in the link view, maybe just something like:
from plone import api
class SomeView(BrowserView):
indexA = ViewPageTemplateFile('templateA.pt')
indexB = ViewPageTemplateFile('templateB.pt')
def __call__(self):
if plone.api.group.get_roles contains 'something':
return self.indexA()
if something else:
return self.indexB()
…
else:
faustram
(Fausto Rambotti)
December 5, 2017, 2:59pm
5
Thank you! This is what I'm searching.
faustram
(Fausto Rambotti)
December 8, 2017, 9:38am
6
For completeness: with at least 2 target classes, each with its template, it is necessary to remove the template declaration from configure.zcml
<browser:page
name="switched_view"
for="*"
layer="zope.interface.Interface"
class=".views.SwitchViewPerUser"
permission="zope2.View"
/>
And write classes like this
class SwitchViewPerUser(DefaultView):
...
def __call__(self):
user = getSecurityManager().getUser()
username = user.getUserName()
target_view_class = MyFirstView
if username == "userA":
pass
elif username == "userB":
target_view_class = MySecondView
return target_view_class(self.context, self.request).__call__()
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
class MyFirstView(DefaultView):
template = ViewPageTemplateFile('templates/first.pt')
def __call__(self):
...
return self.template()
class MySecondView(DefaultView):
""" Similar to MyFirstView """
obviously the user must have the rights to access the CT.
To redirect the user at login I followed the documentation and modified the postlogin.py
.
espenmn
(Espen)
December 8, 2017, 5:52pm
7
You only need to (should) set the template one place: so only set it in ZCML if it it 'always the same'.
Without knowing much: Do you 'really need all this stuff'.
Unless you need to do 'a lot of stuff, you only need to change 'template'.
Even then, you can do thing like:
<div>${view/something1}</div>
in template one
and
<div>${view/something2}</div>
in template2
and define them in 'SwitchView' as
def something1(self):
return 'something'
def something2(self):
return 'something,too'
Then, you probably dont have to 'duplicate so much code'
Also: you can do a 'normal' redirect, like the link view does.
PS: it is also possible to have two views with the same class and define the templates in ZCML
<browser:page
name="view1"
class=".views.MyView"
template="view1.pt'
<browser:page
name="view2"
class=".views.MyView"
template="view2.pt'
dieter
(Dieter Maurer)
December 8, 2017, 9:29pm
8
I am responsible for the .__call__()
suffix. It fact, it can be shortened to ()
.
The important thing for Fausto it to get different views for different users. You are right that it can be done in a template, too. However, logic is usually better in Python code than template code.
faustram
(Fausto Rambotti)
December 11, 2017, 8:46am
9
Yes: I need to have distinct "views", each one with her template.
And yes: I need to do 'a lot of stuff' and so I prefer to do the great part of work in the business-logic with python.
Anyhow, I thanks every one for the precious advices.
espenmn
(Espen)
January 24, 2018, 3:56pm
10
I just made a 'user list' where (the two) 'Managers' can see 'all fields' while 'normal members' just sees a few fields.
I use a slightly different approach, please correct me if it is 'wrong'
template = ViewPageTemplateFile('medlemmer_view.pt')
m_template = ViewPageTemplateFile('medlemmer_full_view.pt')
def __call__(self, *args, **kw):
#current = api.user.get_current()
if api.user.get_permissions()['Manage portal']:
return self.m_template(self.context)
return self.template(self.context)
1letter
(Jan)
January 24, 2018, 10:43pm
11
If you only hide fields for particluar users, then use the Permission Setting like described in plone.autoforms