- Timestamp:
- 16 Nov 2014, 11:53:02 (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
main/waeup.ikoba/trunk/src/waeup/ikoba/customers/browser.py
r11958 r11967 19 19 """ 20 20 21 import sys 21 22 import grok 23 import pytz 24 from urllib import urlencode 25 from datetime import datetime 26 from zope.event import notify 27 from zope.i18n import translate 28 from zope.catalog.interfaces import ICatalog 29 from zope.component import queryUtility, getUtility, createObject 30 from zope.schema.interfaces import ConstraintNotSatisfied, RequiredMissing 31 from zope.formlib.textwidgets import BytesDisplayWidget 32 from zope.security import checkPermission 33 from hurry.workflow.interfaces import IWorkflowInfo, IWorkflowState 22 34 from waeup.ikoba.interfaces import MessageFactory as _ 35 from waeup.ikoba.interfaces import IContactForm, IObjectHistory, IIkobaObject 23 36 from waeup.ikoba.browser.layout import ( 24 37 IkobaPage, IkobaEditFormPage, IkobaAddFormPage, IkobaDisplayFormPage, 25 IkobaForm, NullValidator) 38 IkobaForm, NullValidator, jsaction, action, UtilityView) 39 from waeup.ikoba.browser.pages import ContactAdminForm 26 40 from waeup.ikoba.browser.breadcrumbs import Breadcrumb 27 41 from waeup.ikoba.utils.helpers import get_current_principal, to_timezone, now 28 42 from waeup.ikoba.customers.interfaces import ( 29 ICustomer sContainer43 ICustomer, ICustomersContainer, ICustomerRequestPW 30 44 ) 31 45 from waeup.ikoba.customers.catalog import search 46 47 grok.context(IIkobaObject) 32 48 33 49 class CustomersBreadcrumb(Breadcrumb): … … 43 59 return None 44 60 return self.viewname 61 62 63 class CustomerBreadcrumb(Breadcrumb): 64 """A breadcrumb for the customer container. 65 """ 66 grok.context(ICustomer) 67 68 def title(self): 69 return self.context.display_fullname 45 70 46 71 class CustomersContainerPage(IkobaPage): … … 141 166 mapping = {'a':', '.join(deleted)})) 142 167 return 168 169 class CustomerAddFormPage(IkobaAddFormPage): 170 """Add-form to add a customer. 171 """ 172 grok.context(ICustomersContainer) 173 grok.require('waeup.manageCustomer') 174 grok.name('addcustomer') 175 form_fields = grok.AutoFields(ICustomer).select( 176 'firstname', 'middlename', 'lastname', 'reg_number') 177 label = _('Add customer') 178 pnav = 4 179 180 @action(_('Create customer record'), style='primary') 181 def addCustomer(self, **data): 182 customer = createObject(u'waeup.Customer') 183 self.applyData(customer, **data) 184 self.context.addCustomer(customer) 185 self.flash(_('Customer record created.')) 186 self.redirect(self.url(self.context[customer.customer_id], 'index')) 187 return 188 189 class LoginAsCustomerStep1(IkobaEditFormPage): 190 """ View to temporarily set a customer password. 191 """ 192 grok.context(ICustomer) 193 grok.name('loginasstep1') 194 grok.require('waeup.loginAsCustomer') 195 grok.template('loginasstep1') 196 pnav = 4 197 198 def label(self): 199 return _(u'Set temporary password for ${a}', 200 mapping = {'a':self.context.display_fullname}) 201 202 @action('Set password now', style='primary') 203 def setPassword(self, *args, **data): 204 kofa_utils = getUtility(IIkobaUtils) 205 password = kofa_utils.genPassword() 206 self.context.setTempPassword(self.request.principal.id, password) 207 self.context.writeLogMessage( 208 self, 'temp_password generated: %s' % password) 209 args = {'password':password} 210 self.redirect(self.url(self.context) + 211 '/loginasstep2?%s' % urlencode(args)) 212 return 213 214 class LoginAsCustomerStep2(IkobaPage): 215 """ View to temporarily login as customer with a temporary password. 216 """ 217 grok.context(ICustomer) 218 grok.name('loginasstep2') 219 grok.require('waeup.Public') 220 grok.template('loginasstep2') 221 login_button = _('Login now') 222 pnav = 4 223 224 def label(self): 225 return _(u'Login as ${a}', 226 mapping = {'a':self.context.customer_id}) 227 228 def update(self, SUBMIT=None, password=None): 229 self.password = password 230 if SUBMIT is not None: 231 self.flash(_('You successfully logged in as customer.')) 232 self.redirect(self.url(self.context)) 233 return 234 235 class CustomerBaseDisplayFormPage(IkobaDisplayFormPage): 236 """ Page to display customer base data 237 """ 238 grok.context(ICustomer) 239 grok.name('index') 240 grok.require('waeup.viewCustomer') 241 grok.template('basepage') 242 form_fields = grok.AutoFields(ICustomer).omit( 243 'password', 'suspended', 'suspended_comment') 244 pnav = 4 245 246 @property 247 def label(self): 248 if self.context.suspended: 249 return _('${a}: Base Data (account deactivated)', 250 mapping = {'a':self.context.display_fullname}) 251 return _('${a}: Base Data', 252 mapping = {'a':self.context.display_fullname}) 253 254 @property 255 def hasPassword(self): 256 if self.context.password: 257 return _('set') 258 return _('unset') 259 260 class ContactCustomerForm(ContactAdminForm): 261 grok.context(ICustomer) 262 grok.name('contactcustomer') 263 grok.require('waeup.viewCustomer') 264 pnav = 4 265 form_fields = grok.AutoFields(IContactForm).select('subject', 'body') 266 267 def update(self, subject=u'', body=u''): 268 super(ContactCustomerForm, self).update() 269 self.form_fields.get('subject').field.default = subject 270 self.form_fields.get('body').field.default = body 271 return 272 273 def label(self): 274 return _(u'Send message to ${a}', 275 mapping = {'a':self.context.display_fullname}) 276 277 @action('Send message now', style='primary') 278 def send(self, *args, **data): 279 try: 280 email = self.request.principal.email 281 except AttributeError: 282 email = self.config.email_admin 283 usertype = getattr(self.request.principal, 284 'user_type', 'system').title() 285 kofa_utils = getUtility(IIkobaUtils) 286 success = kofa_utils.sendContactForm( 287 self.request.principal.title,email, 288 self.context.display_fullname,self.context.email, 289 self.request.principal.id,usertype, 290 self.config.name, 291 data['body'],data['subject']) 292 if success: 293 self.flash(_('Your message has been sent.')) 294 else: 295 self.flash(_('An smtp server error occurred.'), type="danger") 296 return 297 298 class CustomerBaseManageFormPage(IkobaEditFormPage): 299 """ View to manage customer base data 300 """ 301 grok.context(ICustomer) 302 grok.name('manage_base') 303 grok.require('waeup.manageCustomer') 304 form_fields = grok.AutoFields(ICustomer).omit( 305 'customer_id', 'adm_code', 'suspended') 306 grok.template('basemanagepage') 307 label = _('Manage base data') 308 pnav = 4 309 310 def update(self): 311 super(CustomerBaseManageFormPage, self).update() 312 self.wf_info = IWorkflowInfo(self.context) 313 return 314 315 @action(_('Save'), style='primary') 316 def save(self, **data): 317 form = self.request.form 318 password = form.get('password', None) 319 password_ctl = form.get('control_password', None) 320 if password: 321 validator = getUtility(IPasswordValidator) 322 errors = validator.validate_password(password, password_ctl) 323 if errors: 324 self.flash( ' '.join(errors), type="danger") 325 return 326 changed_fields = self.applyData(self.context, **data) 327 # Turn list of lists into single list 328 if changed_fields: 329 changed_fields = reduce(lambda x,y: x+y, changed_fields.values()) 330 else: 331 changed_fields = [] 332 if password: 333 # Now we know that the form has no errors and can set password 334 IUserAccount(self.context).setPassword(password) 335 changed_fields.append('password') 336 fields_string = ' + '.join(changed_fields) 337 self.flash(_('Form has been saved.')) 338 if fields_string: 339 self.context.writeLogMessage(self, 'saved: % s' % fields_string) 340 return 341 342 class CustomerTriggerTransitionFormPage(IkobaEditFormPage): 343 """ View to manage customer base data 344 """ 345 grok.context(ICustomer) 346 grok.name('trigtrans') 347 grok.require('waeup.triggerTransition') 348 grok.template('trigtrans') 349 label = _('Trigger registration transition') 350 pnav = 4 351 352 def getTransitions(self): 353 """Return a list of dicts of allowed transition ids and titles. 354 355 Each list entry provides keys ``name`` and ``title`` for 356 internal name and (human readable) title of a single 357 transition. 358 """ 359 wf_info = IWorkflowInfo(self.context) 360 allowed_transitions = [t for t in wf_info.getManualTransitions()] 361 return [dict(name='', title=_('No transition'))] +[ 362 dict(name=x, title=y) for x, y in allowed_transitions] 363 364 @action(_('Save'), style='primary') 365 def save(self, **data): 366 form = self.request.form 367 if 'transition' in form and form['transition']: 368 transition_id = form['transition'] 369 wf_info = IWorkflowInfo(self.context) 370 wf_info.fireTransition(transition_id) 371 return 372 373 class CustomerActivatePage(UtilityView, grok.View): 374 """ Activate customer account 375 """ 376 grok.context(ICustomer) 377 grok.name('activate') 378 grok.require('waeup.manageCustomer') 379 380 def update(self): 381 self.context.suspended = False 382 self.context.writeLogMessage(self, 'account activated') 383 history = IObjectHistory(self.context) 384 history.addMessage('Customer account activated') 385 self.flash(_('Customer account has been activated.')) 386 self.redirect(self.url(self.context)) 387 return 388 389 def render(self): 390 return 391 392 class CustomerDeactivatePage(UtilityView, grok.View): 393 """ Deactivate customer account 394 """ 395 grok.context(ICustomer) 396 grok.name('deactivate') 397 grok.require('waeup.manageCustomer') 398 399 def update(self): 400 self.context.suspended = True 401 self.context.writeLogMessage(self, 'account deactivated') 402 history = IObjectHistory(self.context) 403 history.addMessage('Customer account deactivated') 404 self.flash(_('Customer account has been deactivated.')) 405 self.redirect(self.url(self.context)) 406 return 407 408 def render(self): 409 return 410 411 class CustomerHistoryPage(IkobaPage): 412 """ Page to display customer history 413 """ 414 grok.context(ICustomer) 415 grok.name('history') 416 grok.require('waeup.viewCustomer') 417 grok.template('customerhistory') 418 pnav = 4 419 420 @property 421 def label(self): 422 return _('${a}: History', mapping = {'a':self.context.display_fullname}) 423 424 class CustomerRequestPasswordPage(IkobaAddFormPage): 425 """Captcha'd registration page for applicants. 426 """ 427 grok.name('requestpw') 428 grok.require('waeup.Anonymous') 429 grok.template('requestpw') 430 form_fields = grok.AutoFields(ICustomerRequestPW).select( 431 'firstname','number','email') 432 label = _('Request password for first-time login') 433 434 def update(self): 435 # Handle captcha 436 self.captcha = getUtility(ICaptchaManager).getCaptcha() 437 self.captcha_result = self.captcha.verify(self.request) 438 self.captcha_code = self.captcha.display(self.captcha_result.error_code) 439 return 440 441 def _redirect(self, email, password, customer_id): 442 # Forward only email to landing page in base package. 443 self.redirect(self.url(self.context, 'requestpw_complete', 444 data = dict(email=email))) 445 return 446 447 def _pw_used(self): 448 # XXX: False if password has not been used. We need an extra 449 # attribute which remembers if customer logged in. 450 return True 451 452 @action(_('Send login credentials to email address'), style='primary') 453 def get_credentials(self, **data): 454 if not self.captcha_result.is_valid: 455 # Captcha will display error messages automatically. 456 # No need to flash something. 457 return 458 number = data.get('number','') 459 firstname = data.get('firstname','') 460 cat = getUtility(ICatalog, name='customers_catalog') 461 results = list( 462 cat.searchResults(reg_number=(number, number))) 463 if results: 464 customer = results[0] 465 if getattr(customer,'firstname',None) is None: 466 self.flash(_('An error occurred.'), type="danger") 467 return 468 elif customer.firstname.lower() != firstname.lower(): 469 # Don't tell the truth here. Anonymous must not 470 # know that a record was found and only the firstname 471 # verification failed. 472 self.flash(_('No customer record found.'), type="warning") 473 return 474 elif customer.password is not None and self._pw_used: 475 self.flash(_('Your password has already been set and used. ' 476 'Please proceed to the login page.'), 477 type="warning") 478 return 479 # Store email address but nothing else. 480 customer.email = data['email'] 481 notify(grok.ObjectModifiedEvent(customer)) 482 else: 483 # No record found, this is the truth. 484 self.flash(_('No customer record found.'), type="warning") 485 return 486 487 kofa_utils = getUtility(IKofaUtils) 488 password = kofa_utils.genPassword() 489 mandate = PasswordMandate() 490 mandate.params['password'] = password 491 mandate.params['user'] = customer 492 site = grok.getSite() 493 site['mandates'].addMandate(mandate) 494 # Send email with credentials 495 args = {'mandate_id':mandate.mandate_id} 496 mandate_url = self.url(site) + '/mandate?%s' % urlencode(args) 497 url_info = u'Confirmation link: %s' % mandate_url 498 msg = _('You have successfully requested a password for the') 499 if kofa_utils.sendCredentials(IUserAccount(customer), 500 password, url_info, msg): 501 email_sent = customer.email 502 else: 503 email_sent = None 504 self._redirect(email=email_sent, password=password, 505 customer_id=customer.customer_id) 506 ob_class = self.__implemented__.__name__.replace('waeup.kofa.','') 507 self.context.logger.info( 508 '%s - %s (%s) - %s' % (ob_class, number, customer.customer_id, email_sent)) 509 return 510 511 class CustomerRequestPasswordEmailSent(IkobaPage): 512 """Landing page after successful password request. 513 514 """ 515 grok.name('requestpw_complete') 516 grok.require('waeup.Public') 517 grok.template('requestpwmailsent') 518 label = _('Your password request was successful.') 519 520 def update(self, email=None, customer_id=None, password=None): 521 self.email = email 522 self.password = password 523 self.customer_id = customer_id 524 return
Note: See TracChangeset for help on using the changeset viewer.