From ede29fb6c1d9d3f3e6a505289b961c21a7a83fa8 Mon Sep 17 00:00:00 2001 From: Gaetan Delannay Date: Tue, 29 May 2012 20:50:18 +0200 Subject: [PATCH] [gen] Bugfix while managing languages, ui improvements. --- gen/installer.py | 4 +- gen/mixins/ToolMixin.py | 15 ++++- gen/mixins/__init__.py | 10 ++- gen/model.py | 9 +-- gen/ui/appy.css | 26 ++++---- gen/ui/delete.png | Bin 239 -> 239 bytes gen/ui/edit.gif | Bin 475 -> 476 bytes gen/ui/footer.pt | 4 ++ gen/ui/page.pt | 2 +- gen/ui/plus.png | Bin 246 -> 251 bytes gen/ui/search.gif | Bin 189 -> 191 bytes gen/ui/template.pt | 13 ++-- gen/ui/widgets/ref.pt | 124 +++++++++++++++++------------------- gen/wrappers/UserWrapper.py | 29 +++++++-- 14 files changed, 140 insertions(+), 96 deletions(-) create mode 100644 gen/ui/footer.pt diff --git a/gen/installer.py b/gen/installer.py index f2fc513..50a262c 100644 --- a/gen/installer.py +++ b/gen/installer.py @@ -261,8 +261,8 @@ class ZopeInstaller: # may still be in the way for migration purposes. users = ('admin',) # We suppose there is at least a user. if not users: - appyTool.create('users', login='admin', firstName='admin', - name='admin', password1='admin', password2='admin', + appyTool.create('users', login='admin', password1='admin', + password2='admin', email='admin@appyframework.org', roles=['Manager']) appyTool.log('Admin user "admin" created.') diff --git a/gen/mixins/ToolMixin.py b/gen/mixins/ToolMixin.py index 5288cea..53982c9 100644 --- a/gen/mixins/ToolMixin.py +++ b/gen/mixins/ToolMixin.py @@ -121,6 +121,13 @@ class ToolMixin(BaseMixin): p_code.''' return languages.get(code)[2] + def changeLanguage(self): + '''Sets the language cookie with the new desired language code that is + in request["language"].''' + rq = self.REQUEST + rq.RESPONSE.setCookie('_ZopeLg', rq['language'], path='/') + return self.goto(rq['HTTP_REFERER']) + def getGlobalCssJs(self): '''Returns the list of CSS and JS files to include in the main template. The method ensures that appy.css and appy.js come first.''' @@ -231,6 +238,12 @@ class ToolMixin(BaseMixin): res = appyObj.showPortlet() except AttributeError: res = True + else: + appyObj = self.appy() + try: + res = appyObj.showPortletAt(context) + except AttributeError: + res = True return res def getObject(self, uid, appy=False, brain=False): @@ -979,7 +992,7 @@ class ToolMixin(BaseMixin): elem is the one-line user info as shown on every page; second line is the URL to edit user info.''' appyUser = self.appy().appyUser - res = [appyUser.title, appyUser.login] + res = [appyUser.title] rolesToShow = [r for r in appyUser.roles \ if r not in ('Authenticated', 'Member')] if rolesToShow: diff --git a/gen/mixins/__init__.py b/gen/mixins/__init__.py index c932738..9c87ac8 100644 --- a/gen/mixins/__init__.py +++ b/gen/mixins/__init__.py @@ -1345,10 +1345,16 @@ class BaseMixin: def getUserLanguage(self): '''Gets the language (code) of the current user.''' if not hasattr(self, 'REQUEST'): return 'en' - # Try first the "LANGUAGE" key from the request + # Try the value which comes from the cookie. Indeed, if such a cookie is + # present, it means that the user has explicitly chosen this language + # via the language selector. + rq = self.REQUEST + if '_ZopeLg' in rq.cookies: return rq.cookies['_ZopeLg'] + # Try the LANGUAGE key from the request: it corresponds to the language + # as configured in the user's browser. res = self.REQUEST.get('LANGUAGE', None) if res: return res - # Try then the HTTP_ACCEPT_LANGUAGE key from the request, which stores + # Try the HTTP_ACCEPT_LANGUAGE key from the request, which stores # language preferences as defined in the user's browser. Several # languages can be listed, from most to less wanted. res = self.REQUEST.get('HTTP_ACCEPT_LANGUAGE', None) diff --git a/gen/model.py b/gen/model.py index b5c4a52..7655e4c 100644 --- a/gen/model.py +++ b/gen/model.py @@ -93,7 +93,7 @@ class ModelClass: elif callable(value): className = wrapperName if (appyType.type == 'Ref') and appyType.isBack: - className = appyType.back.klass.__name__ + className = value.im_class.__name__ value = '%s.%s' % (className, value.__name__) typeArgs += '%s=%s,' % (name, value) return '%s(%s)' % (appyType.__class__.__name__, typeArgs) @@ -143,10 +143,13 @@ class User(ModelClass): 'password2', 'email', 'roles'] # All methods defined below are fake. Real versions are in the wrapper. title = gen.String(show=False, indexed=True) - gm = {'group': 'main', 'multiplicity': (1,1), 'width': 25} + gm = {'group': 'main', 'width': 25} def showName(self): pass name = gen.String(show=showName, **gm) firstName = gen.String(show=showName, **gm) + def showEmail(self): pass + email = gen.String(show=showEmail) + gm['multiplicity'] = (1,1) def showLogin(self): pass def validateLogin(self): pass login = gen.String(show=showLogin, validator=validateLogin, @@ -156,8 +159,6 @@ class User(ModelClass): password1 = gen.String(format=gen.String.PASSWORD, show=showPassword, validator=validatePassword, **gm) password2 = gen.String(format=gen.String.PASSWORD, show=showPassword, **gm) - def showEmail(self): pass - email = gen.String(show=showEmail, group='main', width=25) gm['multiplicity'] = (0, None) def showRoles(self): pass roles = gen.String(show=showRoles, indexed=True, diff --git a/gen/ui/appy.css b/gen/ui/appy.css index 499d4e9..4257a4c 100644 --- a/gen/ui/appy.css +++ b/gen/ui/appy.css @@ -1,16 +1,16 @@ body { font: 75% Helvetica,Arial,sans-serif; background-color: #EAEAEA; margin-top: 18px} pre { font: 100% Helvetica,Arial,sans-serif; margin: 0} -h1 { font-size: 14pt; margin:0;} -h2 { font-size: 13pt; margin:0; font-style: italic; font-weight: normal; - background-color: #d7dee4} -h3 { font-size: 12pt; margin:0; font-weight: bold;} -h4 { font-size: 11pt; margin:0;} +h1 { font-size: 14pt; margin-bottom:4px;} +h2 { font-size: 13pt; margin-bottom:4px; font-style: italic; + font-weight: normal; background-color: #d7dee4} +h3 { font-size: 12pt; margin-bottom:4px; font-weight: bold;} +h4 { font-size: 11pt; margin-bottom:4px;} h5 { font-size: 10pt; margin:0; font-style: italic; font-weight: normal; background-color: #d7dee4} h6 { font-size: 9pt; margin:0; font-weight: bold;} -a { text-decoration: none; color: #503737;} -a:visited { color: #503737;} +a { text-decoration: none; color: #436976;} +a:visited { color: #436976;} table { font-size: 100%; border-spacing: 0px; border-collapse:collapse;} form { margin: 0; padding: 0;} p { margin: 0;} @@ -40,7 +40,7 @@ ul { line-height: 1.2em; margin: 0 0 0.2em 0.6em; padding: 0; list-style: none outside none;} ul li { margin: 0; background-image: url("ui/li.gif"); padding-left: 10px; background-repeat: no-repeat; background-position: 0 4px;} -img {border: 0} +img { border: 0; vertical-align: middle} /* Styles that apply when viewing content of XHTML fields, that mimic styles that ckeditor uses for displaying XHTML content in the edit view. */ @@ -51,9 +51,10 @@ img {border: 0} .main { width: 900px; background-color: white; box-shadow: 3px 3px 3px #A9A9A9; border-style: solid; border-width: 1px; border-color: grey} .top { height: 75px; margin-left: 3em; vertical-align: top;} -.lang { margin-right: 3px; } -.userStrip { background-color: #d7dee4; height: 35px; - border-top: 1px solid #5F7983; border-bottom: 1px solid #5F7983; } +.lang { margin-right: 6px; } +.userStrip { background-color: #6282B3; height: 35px; + border-top: 3px solid #034984; border-bottom: 2px solid #034984; } +.userStripText { font-size: 110%; padding: 0 0.3em 0 0.3em; color: white } .login { margin-top: 2px; margin-bottom: 2px; color: black;} .buttons { margin-left: 4px;} .fakeButton { border: 1px solid #D7DEE4; background-color: #fde8e0; @@ -117,3 +118,6 @@ img {border: 0} .topSpace { margin-top: 15px;} .discreet { color: grey} .pageLink { padding-left: 6px; font-style: italic} +.footer { font-size: 95% } +.footer td { background-color: #CBCBC9; border-top: 1px solid grey; + padding: 0.4em 1em 0.5em } diff --git a/gen/ui/delete.png b/gen/ui/delete.png index 67a9af0e96ff31e76481d9ad0bb416d9d285b44d..f577d4c0948e9bc28b09b5e98dff6af53ced2d93 100644 GIT binary patch delta 91 zcmaFQ_?~fs8Snh<3@cSsz9b}k{WJUJL}v@GJFGH%3RX&j2X{_vH8pi$&Ee7F;aS5Q vEFmE=nW^EA2fKpeDTdU>qX#x6ltwTx+|6V);n~63!T41W0s@PI0tW*=i;)8b1d0L`mzjx{n3|lS apOU1AB&ME;DiNoNHcdp2w6(T`fdD(QqZ|wX delta 67 zcmV-J0KEU)1KR_zpaDBLfPaF6goTEOh>41ehyntPe*y;sK8unA1q6x$6_}cdmzkTL ZqM(zdh$N? + Made with Appy + diff --git a/gen/ui/page.pt b/gen/ui/page.pt index 5e13dd5..b30338b 100644 --- a/gen/ui/page.pt +++ b/gen/ui/page.pt @@ -289,7 +289,7 @@ - diff --git a/gen/ui/plus.png b/gen/ui/plus.png index edb583c78adb53920854066721ac2b6711c4655f..f3be15aabac35c4d18e29eba910cce2fdabe89cd 100644 GIT binary patch delta 179 zcmV;k08Ib(0s8@v7YYyv1^@s6CX`M(ks&>Q+yxvD2`>sr(2f8A0DDP9K~yNu&62SV zz#t3+-Q+X)c~0w%t4$Tt800Cq`4K~yNut&y=2 zz#s@kfnx_tSF_AWmRZfxCH$$(okXK&LL~_I{{sd + asLinks python: len(languages) <= 8"> @@ -94,7 +94,7 @@ - The user data strip + The user strip + Footer + +
@@ -103,7 +103,7 @@ The user login form for anonymous users
- -
diff --git a/gen/ui/widgets/ref.pt b/gen/ui/widgets/ref.pt index c9e053b..55cb3a6 100644 --- a/gen/ui/widgets/ref.pt +++ b/gen/ui/widgets/ref.pt @@ -156,76 +156,72 @@ - Display a fieldset in all other cases. + Display a table in all other cases. -
- - () - - The search icon if field is queryable - - - +
+ () + + The search icon if field is queryable + + +
- Appy (top) navigation - + Appy (top) navigation + - No object is present -

+ No object is present +

- - +
+ + -
- Show forward or backward reference(s) - - - - - - - - - - Actions - - - - -
- - -
- - - - - - - - - - - - - - -
-
+ Show forward or backward reference(s) + + + + + + + + + + Actions + + + + +
+ + +
+ + + + + + + + + + + + + + +
+
- Appy (bottom) navigation - - -
- A carriage return needed in some cases. + Appy (bottom) navigation +
diff --git a/gen/wrappers/UserWrapper.py b/gen/wrappers/UserWrapper.py index e0382f7..07c5a58 100644 --- a/gen/wrappers/UserWrapper.py +++ b/gen/wrappers/UserWrapper.py @@ -51,6 +51,27 @@ class UserWrapper(AbstractWrapper): # wants to edit information about himself. if self.user.has_role('Owner', self): return 'edit' + def setPassword(self, newPassword=None): + '''Sets a p_newPassword for self. If p_newPassword is not given, we + generate one. This method returns the generated password (or simply + p_newPassword if no generation occurred).''' + if newPassword: + msgPart = 'changed' + else: + newPassword = self.getField('password1').generatePassword() + msgPart = 'generated' + login = self.login + zopeUser = self.o.acl_users.getUserById(login) + tool = self.tool.o + zopeUser.__ = tool._encryptPassword(newPassword) + if self.user.getId() == login: + # The user for which we change the password is the currently logged + # user. So update the authentication cookie, too. + tool._updateCookie(login, newPassword) + self.log('Password %s by "%s" for "%s".' % \ + (msgPart, self.user.getId(), login)) + return newPassword + def getGrantableRoles(self): '''Returns the list of roles that the admin can grant to a user.''' res = [] @@ -70,7 +91,7 @@ class UserWrapper(AbstractWrapper): return self._callCustom('validate', new, errors) def onEdit(self, created): - self.title = self.firstName + ' ' + self.name + self.title = self.login aclUsers = self.o.acl_users login = self.login if created: @@ -89,11 +110,7 @@ class UserWrapper(AbstractWrapper): zopeUser.roles = self.roles # Update the password if the user has entered new ones. rq = self.request - if rq.has_key('password1'): - tool = self.tool.o - zopeUser.__ = tool._encryptPassword(rq['password1']) - # Update the cookie value - tool._updateCookie(login, rq['password1']) + if rq.has_key('password1'): self.setPassword(rq['password1']) self.password1 = self.password2 = '' # "self" must be owned by its Zope user. if 'Owner' not in self.o.get_local_roles_for_userid(login):