Skip to content

Commit f1f8127

Browse files
ramonskixispa
andauthored
Customized User/Groups Preferences in Site Configuration (#2117)
* Customized userprefs controlpanel * Custom groups controlpanel * styling and formatting * Hide settings tabs * Custom group membership control panel * Groupdetails customized * Custom userdata panel * Customized user group membership * Changelog updated * Align checkbox center and middle Co-authored-by: Jordi Puiggené <[email protected]>
1 parent 06ad1e4 commit f1f8127

15 files changed

+1495
-0
lines changed

CHANGES.rst

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Changelog
55
2.3.0 (unreleased)
66
------------------
77

8+
- #2117 Customized User/Groups Preferences in Site Configuration
89
- #2115 Fix insufficient privileges for instrument QC viewlet
910
- #2114 Allow Multi Analysis Results Entry
1011
- #2111 Replace header table with customizable sample header viewlet

src/senaite/core/browser/configure.zcml

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
<include package=".portlets"/>
3333
<include package=".samples"/>
3434
<include package=".setup"/>
35+
<include package=".usergroup"/>
3536
<include package=".viewlets"/>
3637
<include package=".widgets"/>
3738

src/senaite/core/browser/usergroup/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<configure
2+
xmlns="http://namespaces.zope.org/zope"
3+
xmlns:browser="http://namespaces.zope.org/browser"
4+
xmlns:zcml="http://namespaces.zope.org/zcml">
5+
6+
<!-- Users Controlpanel -->
7+
<browser:page
8+
name="usergroup-userprefs"
9+
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
10+
class=".usergroups_usersoverview.UsersOverviewControlPanel"
11+
permission="plone.app.controlpanel.UsersAndGroups"
12+
template="templates/usergroups_usersoverview.pt"
13+
layer="senaite.core.interfaces.ISenaiteCore"
14+
/>
15+
16+
<!-- Groups Controlpanel -->
17+
<browser:page
18+
name="usergroup-groupprefs"
19+
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
20+
class=".usergroups_groupsoverview.GroupsOverviewControlPanel"
21+
permission="plone.app.controlpanel.UsersAndGroups"
22+
template="templates/usergroups_groupsoverview.pt"
23+
layer="senaite.core.interfaces.ISenaiteCore"
24+
/>
25+
26+
<!-- Group Membership -->
27+
<browser:page
28+
name="usergroup-groupmembership"
29+
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
30+
class="Products.CMFPlone.controlpanel.browser.usergroups_groupmembership.GroupMembershipControlPanel"
31+
permission="plone.app.controlpanel.UsersAndGroups"
32+
template="templates/usergroups_groupmembership.pt"
33+
layer="senaite.core.interfaces.ISenaiteCore"
34+
/>
35+
36+
<!-- Group Details -->
37+
<browser:page
38+
name="usergroup-groupdetails"
39+
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
40+
class="Products.CMFPlone.controlpanel.browser.usergroups_groupdetails.GroupDetailsControlPanel"
41+
permission="plone.app.controlpanel.UsersAndGroups"
42+
template="templates/usergroups_groupdetails.pt"
43+
layer="senaite.core.interfaces.ISenaiteCore"
44+
/>
45+
46+
<!-- User Configlet -->
47+
<browser:page
48+
name="user-information"
49+
for="plone.app.layout.navigation.interfaces.INavigationRoot"
50+
class=".userdatapanel.UserDataConfiglet"
51+
permission="plone.app.controlpanel.UsersAndGroups"
52+
layer="senaite.core.interfaces.ISenaiteCore"
53+
/>
54+
55+
<!-- User Group Membership -->
56+
<browser:page
57+
name="usergroup-usermembership"
58+
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
59+
class="Products.CMFPlone.controlpanel.browser.usergroups_usermembership.UserMembershipControlPanel"
60+
permission="plone.app.controlpanel.UsersAndGroups"
61+
template="templates/usergroups_usermembership.pt"
62+
layer="senaite.core.interfaces.ISenaiteCore"
63+
/>
64+
65+
66+
</configure>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
2+
xmlns:tal="http://xml.zope.org/namespaces/tal"
3+
xmlns:metal="http://xml.zope.org/namespaces/metal"
4+
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
5+
lang="en"
6+
metal:use-macro="here/prefs_main_template/macros/master"
7+
i18n:domain="plone">
8+
9+
<div metal:fill-slot="prefs_configlet_content">
10+
11+
<article id="content">
12+
13+
<a
14+
id="setup-link"
15+
href=""
16+
class="link-parent"
17+
tal:attributes="href string:$portal_url/@@usergroup-userprefs"
18+
i18n:translate="label_up_to_usersoverview">
19+
Up to Users Overview
20+
</a>
21+
22+
<h1 class="documentFirstHeading" tal:content="view/label | nothing" />
23+
24+
<div metal:use-macro="context/global_statusmessage/macros/portal_message">
25+
Portal status message
26+
</div>
27+
28+
<div id="content-core">
29+
<div class="autotabs">
30+
<div class="autotoc-nav"
31+
tal:define="view_name view/__name__;
32+
userquery python:view.makeQuery()">
33+
<a href="${portal_url}/@@user-information${userquery}"
34+
tal:define="selected python:view_name=='user-information'"
35+
tal:attributes="class python:'autotoc-level-1' + (' active' if selected else '')"
36+
i18n:translate="title_personal_information_form">Personal Information</a>
37+
<!-- <a href="${portal_url}/@@user-preferences${userquery}"
38+
tal:define="selected python:view_name=='user-preferences'"
39+
tal:attributes="class python:'autotoc-level-1' + (' active' if selected else '')"
40+
i18n:translate="">Personal Preferences</a> -->
41+
<a href="${portal_url}/@@usergroup-usermembership${userquery}"
42+
i18n:translate="label_group_memberships">Group Memberships</a>
43+
</div>
44+
<metal:b use-macro="context/@@ploneform-macros/titlelessform" />
45+
</div>
46+
</div>
47+
48+
</article>
49+
50+
</div>
51+
52+
</html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
2+
xmlns:tal="http://xml.zope.org/namespaces/tal"
3+
xmlns:metal="http://xml.zope.org/namespaces/metal"
4+
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
5+
lang="en"
6+
metal:use-macro="context/prefs_main_template/macros/master"
7+
i18n:domain="plone">
8+
9+
<body>
10+
11+
<metal:main fill-slot="prefs_configlet_content"
12+
tal:define="template_id string:@@usergroup-groupdetails;
13+
portal_roles view/portal_roles;
14+
groupquery python:view.makeQuery(groupname=view.groupname);
15+
groupkeyquery python:view.makeQuery(key=view.groupname)">
16+
17+
18+
<!-- When no group is specified, this gets used as the add group page page -->
19+
<article id="content" tal:condition="not:view/group">
20+
<metal:block metal:use-macro="template/macros/props">
21+
<metal:title metal:fill-slot="content-title">
22+
<h1 class="documentFirstHeading"
23+
i18n:translate="heading_create_group">Create a Group</h1>
24+
</metal:title>
25+
26+
<metal:name metal:fill-slot="name">
27+
<div class="field">
28+
<label for="addname" i18n:translate="label_name">Name</label>
29+
30+
<span class="fieldRequired" title="Required"
31+
i18n:attributes="title title_required;"
32+
i18n:translate="label_required">(Required)</span>
33+
34+
<div class="formHelp" i18n:translate="help_groupname">
35+
A unique identifier for the group. Can not be changed after creation.
36+
</div>
37+
38+
<input type="text" name="addname" value="groupname"
39+
id="addname"
40+
tal:attributes="value view/groupname | string:"/>
41+
</div>
42+
</metal:name>
43+
</metal:block>
44+
</article>
45+
46+
<article id="content" tal:condition="view/group | nothing">
47+
<metal:block define-macro="props">
48+
49+
<a id="setup-link"
50+
href="${portal_url}/@@usergroup-groupprefs"
51+
class="link-parent"
52+
i18n:translate="label_up_to_groups_overview">
53+
Up to Groups Overview
54+
</a>
55+
56+
<h1 class="documentFirstHeading"
57+
i18n:translate="heading_edit_groupproperties"
58+
metal:define-slot="content-title">Group: <span i18n:name="groupname" tal:replace="view/grouptitle|nothing"/></h1>
59+
60+
<div metal:use-macro="context/global_statusmessage/macros/portal_message">
61+
Portal status message
62+
</div>
63+
64+
<div id="content-core"
65+
tal:define="token context/@@authenticator/token">
66+
<div class="autotabs">
67+
68+
<div class="autotoc-nav">
69+
<a href="${portal_url}/@@usergroup-groupmembership?${groupquery}"
70+
i18n:translate="label_group_members">Group Members</a>
71+
<a class="active"
72+
href="${portal_url}/@@usergroup-groupdetails?${groupquery}"
73+
i18n:translate="label_group_properties">Group Properties</a>
74+
<!-- <a href="${portal_url}/@@manage-group-portlets?${groupkeyquery}&_authenticator=${token}"
75+
i18n:translate="label_group_portlets">Group Portlets</a>
76+
<a href="${portal_url}/@@manage-group-dashboard?${groupkeyquery}&_authenticator=${token}"
77+
i18n:translate="label_group_dashboard">Group Dashboard</a> -->
78+
</div>
79+
80+
<form action=""
81+
id="createGroup"
82+
name="groups"
83+
method="post"
84+
class="pat-formunloadalert pat-formautofocus"
85+
tal:attributes="action string:$portal_url/$template_id"
86+
tal:define="targetobject context/portal_groupdata;">
87+
88+
<fieldset>
89+
<div class="field" metal:define-slot="name">
90+
<label for="groupname" i18n:translate="label_name">Name</label>
91+
92+
<div tal:content="view/groupname | string:" />
93+
<input type="hidden" name="groupname" value="groupname"
94+
id="groupname"
95+
tal:attributes="value view/groupname | string:"/>
96+
</div>
97+
98+
<tal:set tal:condition="targetobject/management_page_charset|nothing"
99+
tal:define="dummy python:request.set('management_page_charset_tag','')" />
100+
101+
<tal:set tal:condition="not:targetobject/management_page_charset|nothing">
102+
<tal:defines define="dummy python:request.set('management_page_charset','UTF-8');
103+
dummy python:request.set('management_page_charset_tag','UTF-8:');" />
104+
</tal:set>
105+
106+
<tal:properties repeat="property targetobject/propertyMap">
107+
<div class="field"
108+
tal:define="id property/id;
109+
type property/type;
110+
propertyvalue python:view.get_group_property(id);">
111+
112+
<label for="value"
113+
tal:attributes="for id"
114+
i18n:translate=""
115+
tal:content="python:targetobject.propertyLabel(id).capitalize()">Property Value</label>
116+
117+
<div tal:define="propertyitem python:targetobject.getProperty(id);
118+
disabled python:None if (not view.group or view.group.canWriteProperty(id)) else 'disabled';"
119+
tal:condition="python:'w' in property.get('mode', 'awd')">
120+
121+
<input type="text" name="id" size="35"
122+
tal:condition="python:type in ('int', 'long')"
123+
tal:attributes="name string:$id:$type;
124+
id id;
125+
value python:propertyvalue if propertyvalue else '';
126+
disabled disabled;" />
127+
128+
<input type="text" name="id" size="35"
129+
tal:condition="python:type in ('float','date')"
130+
tal:attributes="name string:$id:${request/management_page_charset_tag}$type;
131+
id id;
132+
value python:propertyvalue if propertyvalue else '';
133+
disabled disabled;" />
134+
135+
<input type="text" name="string and ustring" size="35"
136+
tal:condition="python:type in ('string','ustring')"
137+
tal:attributes="name string:$id:${request/management_page_charset_tag}$type;
138+
id id;
139+
value python:propertyvalue if propertyvalue else '';
140+
disabled disabled;" />
141+
142+
<input type="checkbox"
143+
class="noborder"
144+
name="id"
145+
id="cb-checkbox"
146+
tal:condition="python: type in ('boolean',)"
147+
tal:attributes="name string:$id:$type;
148+
id id;
149+
checked python:'checked' if propertyvalue else '';
150+
disabled disabled;" />
151+
152+
<input name="tokens and utokens" value="" type="text" size="35"
153+
tal:condition="python:type in ('tokens', 'utokens')"
154+
tal:attributes="name string:$id:${request/management_page_charset_tag}$type;
155+
value python:propertyvalue if propertyvalue else '';
156+
disabled disabled;" />
157+
158+
<textarea name="text and utext"
159+
rows="6"
160+
cols="35"
161+
tal:condition="python: type in ('text', 'utext')"
162+
tal:attributes="name string:$id:${request/management_page_charset_tag}$type;
163+
disabled disabled;"
164+
tal:content="propertyvalue">some data</textarea>
165+
166+
<textarea name="lines and ulines"
167+
rows="6"
168+
cols="35"
169+
tal:condition="python: type in ('lines', 'ulines')"
170+
tal:attributes="name string:$id:${request/management_page_charset_tag}$type;
171+
disabled disabled;"
172+
tal:content="python: propertyvalue and '\n'.join(propertyvalue) or ''">
173+
</textarea>
174+
175+
176+
<tal:selections tal:condition="python:type in ('selection', 'multiple selection')"
177+
tal:define="select_variable python:property.get('select_variable','');
178+
select_value python:select_variable and path('context/%s' %select_variable) or [];">
179+
180+
<select name="selection" tal:condition="python:type in ('selection',)"
181+
tal:attributes="name string:$id:${request/management_page_charset_tag}text;
182+
disabled disabled;">
183+
<tal:values repeat="option select_value">
184+
<option tal:attributes="SELECTED python:'SELECTED' if propertyvalue==option else ''"
185+
tal:content="option">value</option>
186+
</tal:values>
187+
</select>
188+
189+
<select name="multiple selection" multiple="multiple" tal:condition="python:type in ('multiple selection',)"
190+
tal:attributes="name string:$id:${request/management_page_charset_tag}list:string;
191+
size python:min(7, len(select_value));
192+
disabled disabled;">
193+
<tal:values repeat="option select_value">
194+
<option tal:attributes="SELECTED python:'selected' if (propertyvalue and option in propertyvalue) else ''"
195+
tal:content="option">value</option>
196+
</tal:values>
197+
</select>
198+
199+
</tal:selections>
200+
201+
</div>
202+
203+
</div>
204+
</tal:properties>
205+
206+
<input type="hidden" name="form.submitted" value="1" />
207+
208+
<div class="formControls">
209+
<input class="context btn btn-sm mt-3"
210+
type="submit"
211+
name="form.button.Save"
212+
value="Save"
213+
i18n:attributes="value label_save;" />
214+
</div>
215+
</fieldset>
216+
217+
<input tal:replace="structure context/@@authenticator/authenticator" />
218+
</form>
219+
</div>
220+
</div>
221+
</metal:block>
222+
</article>
223+
224+
</metal:main>
225+
226+
</body>
227+
</html>

0 commit comments

Comments
 (0)