def fire_actions(self, *args, **kwargs): mgr = cherrypy.session['Admin'].getGroupManager() group_id = self.fields['id'].value group_name = recoder.u2c(self.fields['name'].value) if not group_id: if ('name' in self.changed_data): props = [('group_name', group_name)] log_req = utils.create_log_request('CreateRegistrarGroup', properties = props) out_props = [] try: gid = mgr.createGroup(group_name) out_props.append(('group_id', gid)) log_req.result = 'Success' except Registry.Registrar.InvalidValue: log_req.result = 'Fail' raise UpdateFailedError( _(u"Could not create group. Perhaps you've entered " "a name of an already existing group (or name of " "a deleted one, which is currently invalid too)?")) finally: log_req.close(properties=out_props) else: group_id = int(group_id) if 'DELETE' in self.changed_data: props = [('group_name', group_name), ('group_id', group_id)] log_req = utils.create_log_request('DeleteRegistrarGroup', properties = props) try: mgr.deleteGroup(group_id) log_req.result = 'Success' except Registry.Registrar.InvalidValue, e: log_req.result = 'Fail' error(e) raise UpdateFailedError(_(u'Group %s is not empty.') % group_name) finally: log_req.close()
def unblock(self, id): context = DictLookup() try: reg_id = int(id) except (TypeError, ValueError): context.message = _("Required_integer_as_parameter") raise CustomView(self._render('error', ctx=context)) return_message = [ _(u'You can return back to '), a(attr(href=f_urls[self.classname] + 'detail/?id=%s' % reg_id), _('registrar.')) ] admin = cherrypy.session.get('Admin') if not admin.isRegistrarBlocked(reg_id): context.message = [_("This registrar is not blocked.") ] + return_message return self._render('error', ctx=context) else: log_req = utils.create_log_request('RegistrarUpdate', [['blocked', 'False']], [[self.classname, reg_id]]) try: admin.unblockRegistrar(reg_id, log_req.request_id) log_req.result = 'Success' finally: log_req.close() context.main = [_("Registrar successfully unblocked.") ] + return_message return self._render('base', ctx=context)
def unblock(self, id): context = DictLookup() try: reg_id = int(id) except (TypeError, ValueError): context.message = _("Required_integer_as_parameter") raise CustomView(self._render('error', ctx=context)) return_message = [ _(u'You can return back to '), a(attr(href=f_urls[self.classname] + 'detail/?id=%s' % reg_id), _('registrar.')) ] admin = cherrypy.session.get('Admin') if not admin.isRegistrarBlocked(reg_id): context.message = [_("This registrar is not blocked.")] + return_message return self._render('error', ctx=context) else: log_req = utils.create_log_request('RegistrarUpdate', [['blocked', 'False']], [[self.classname, reg_id]]) try: admin.unblockRegistrar(reg_id, log_req.request_id) log_req.result = 'Success' finally: log_req.close() context.main = [_("Registrar successfully unblocked.")] + return_message return self._render('base', ctx=context)
def printout(self, handle, **kwd): lang_code = config.lang[:2] if lang_code == 'cs': # conversion between cs and cz identifier of lagnguage lang_code = 'cz' context = {'main': div()} context['main'].add( script( attr(type='text/javascript'), 'scwLanguage = "%s"; //sets language of js_calendar' % lang_code, 'scwDateOutputFormat = "%s"; // set output format for js_calendar' % config.js_calendar_date_format)) if cherrypy.request.method == 'POST': form = ObjectPrintoutForm(data=kwd) if form.is_valid(): for_time = form.cleaned_data['for_time'] props = [('handle', handle), ('for_time', for_time)] log_req = create_log_request('RecordStatement', properties=props) try: return self._get_printout_pdf(handle, for_time) except Registry.RecordStatement.OBJECT_NOT_FOUND: form.add_error( 'for_time', _('Object "{}" was not found for the given date.'. format(handle))) finally: log_req.close() else: form = ObjectPrintoutForm() context['heading'] = _('Download printout') context['form'] = form return self._render('printout', context)
def _create_check(self, contact_id, test_suite_handle, redirect_to_contact=True): check_nperm_func('add.contactcheck_%s' % test_suite_handle, raise_err=True) try: contact_id = int(contact_id) except (TypeError, ValueError): context = { 'main': _('Requires integer as parameter (got %s).' % contact_id) } raise CustomView(self._render('base', ctx=context)) log_req = create_log_request( 'ContactCheckEnqueue', properties=[['test_suit_handle', test_suite_handle]], references=[('contact', int(contact_id))]) try: cherrypy.session['Verification'].enqueueContactCheck( contact_id, test_suite_handle, log_req.request_id) log_req.result = 'Success' messages.success( _('New %s contact check has been created.' % test_suite_handle)) if redirect_to_contact: raise cherrypy.HTTPRedirect(f_urls['contact'] + 'detail/?id=%s' % contact_id) finally: log_req.close()
def _create_log_req_for_object_view(self, request_type=None, properties=None, references=None, **kwd): ''' To avoid code duplication - this is common for all views (like detail) which are taking id of an object. request_type - default is view detail It checks if ID is integer, returns errorpage if not otherwise creates new log request with references and object_id in properties. (note: object_id in properties will be obsolete when references will be everywhere) ''' context = {} try: object_id = int(kwd.get('id')) except (TypeError, ValueError): context['message'] = _("Required_integer_as_parameter") raise CustomView(self._render('error', ctx=context)) if request_type is None: request_type = f_name_actiondetailname[self.classname] if properties is None: properties = [] if references is None: references = [] properties.append(('object_id', object_id)) object_type = f_name_req_object_type.get(self.classname) if object_type: references.append((object_type, object_id)) log_req = utils.create_log_request(request_type, properties=properties, references=references) return log_req
def _process_valid_form(self, form, reg, reg_id, context, log_request_name): props = self._construct_changed_fields(form) in_refs = [] if reg_id: in_refs = [('registrar', int(reg_id))] log_req = utils.create_log_request(log_request_name, properties=props, references=in_refs) out_refs = [] try: registrar = self._fill_registrar_struct_from_form( reg, form.cleaned_data) corba_reg = recoder.u2c(registrar) result = {'reg_id': None} form.fire_actions(updated_registrar=corba_reg, result=result) if result[ 'reg_id'] != reg_id: # new registrar created, add him to out_refs out_refs.append(('registrar', result['reg_id'])) reg_id = result['reg_id'] log_req.result = 'Success' except editforms.UpdateFailedError, e: form.non_field_errors().append(str(e)) context['form'] = form log_req.result = 'Fail' return context
def _update_check(self, check, post_data): status_action = post_data['status_action'] if status_action not in get_status_action( check.test_suite_handle, check.status_history[-1].status): raise CustomView( self._render('error', ctx={ 'message': _('Unknown status_action "%s" to resolve.' % status_action) })) status, action = status_action.split(':') props = [['check_handle', check.check_handle], ['status', status], ['action', action]] log_req = create_log_request('ContactCheckResolve', properties=props, references=[('contact', check.contact_id) ]) try: if status == 'confirm_enqueue': cherrypy.session['Verification'].confirmEnqueueingContactCheck( u2c(check.check_handle), log_req.request_id) messages.success(_('Contact check has been enqueue.')) else: cherrypy.session['Verification'].resolveContactCheckStatus( u2c(check.check_handle), u2c(status), log_req.request_id) messages.success( _('Contact check has been resolved as {}.').format( ContactCheckEnums.CHECK_STATUS_NAMES[status])) if action == 'add_manual': self._create_check(check.contact_id, 'manual', redirect_to_contact=False) elif action == 'add_thank_you': self._create_check(check.contact_id, 'thank_you', redirect_to_contact=False) elif action == 'delete_domains': cherrypy.session[ 'Verification'].deleteDomainsAfterFailedManualCheck( u2c(check.check_handle)) messages.success( _('All domains held by the contact {} were deleted.'). format(check.contact_handle)) log_req.result = 'Success' raise cherrypy.HTTPRedirect(f_urls['contactcheck'] + 'detail/%s/' % check.check_handle) finally: log_req.close()
def initialize_log_req(self): if self.log_input_props_names: for prop_name in self.log_input_props_names: prop_value = self.form.cleaned_data[prop_name] if isinstance(prop_value, types.ListType): self.props.extend([(prop_name, prop_item_value) for prop_item_value in self.form.cleaned_data[prop_name]]) else: self.props.append((prop_name, prop_value)) self.log_req = utils.create_log_request(self.log_req_type, properties=self.props, references=self.refs)
def fire_actions(self, *args, **kwargs): mgr = cherrypy.session['Admin'].getGroupManager() group_id = self.fields['id'].value group_name = recoder.u2c(self.fields['name'].value) if not group_id: if ('name' in self.changed_data): props = [('group_name', group_name)] log_req = utils.create_log_request('CreateRegistrarGroup', properties=props) out_props = [] try: gid = mgr.createGroup(group_name) out_props.append(('group_id', gid)) log_req.result = 'Success' except Registry.Registrar.InvalidValue: log_req.result = 'Fail' raise UpdateFailedError( _(u"Could not create group. Perhaps you've entered " "a name of an already existing group (or name of " "a deleted one, which is currently invalid too)?")) finally: log_req.close(properties=out_props) else: group_id = int(group_id) if 'DELETE' in self.changed_data: props = [('group_name', group_name), ('group_id', group_id)] log_req = utils.create_log_request('DeleteRegistrarGroup', properties=props) try: mgr.deleteGroup(group_id) log_req.result = 'Success' except Registry.Registrar.InvalidValue, e: log_req.result = 'Fail' error(e) raise UpdateFailedError( _(u'Group %s is not empty.') % group_name) finally: log_req.close()
def _get_contact_checks(self, test_suit=None, contact_id=None): log_req = create_log_request( 'ContactCheckFilter', references=[('contact', int(contact_id))] if contact_id else None) try: if contact_id: checks = cherrypy.session['Verification'].getChecksOfContact( contact_id, None, 100) else: checks = cherrypy.session['Verification'].getActiveChecks( test_suit) log_req.result = 'Success' return checks finally: log_req.close()
def login(self, *args, **kwd): """ The 'gateway' to the rest of Daphne. Handles authentication and login form processing." """ if cherrypy.session.get('corbaSessionString'): # Already logged in, redirect to /summary. self._handle_double_login() raise cherrypy.HTTPRedirect('/summary/') if kwd: if cherrypy.request.method == 'GET' and kwd.get('next'): form = LoginForm(action='/login/', method='post') form.fields['next'].value = kwd['next'] else: form = LoginForm(kwd, action='/login/', method='post') else: form = LoginForm(action='/login/', method='post') if form.is_valid(): admin = self._init_login(form) log_req = utils.create_log_request( 'Login', [['username', form.cleaned_data.get('login')]]) out_props = [] try: # May raise a HTTPRedirect self._authenticate(form, admin) user, corba_session_string = self._authorize(form, admin) out_props.append(['session_id', corba_session_string]) log_req.result = 'Success' except (AuthenticationError, AuthorizationError), exc: form.non_field_errors().append(str(exc)) if config.debug: form.non_field_errors().append( noesc( escape(unicode(traceback.format_exc())).replace( '\n', '<br/>'))) if log_req: log_req.result = 'Fail' self._remove_session_data() else: self._fill_session_data(form, user, corba_session_string) if log_req: log_req.result = 'Success' # Login completed, go to the next page. raise cherrypy.HTTPRedirect( form.cleaned_data.get('next', "/summary/")) finally:
def dig(self, **kwd): context = {} handle = kwd.get('handle', None) if not handle: raise cherrypy.HTTPRedirect(f_urls[self.classname]) log_req = utils.create_log_request('DomainDig', properties=[("handle", handle)]) try: query = dns.message.make_query(handle, 'ANY') resolver = dns.resolver.get_default_resolver().nameservers[0] dig = dns.query.udp(query, resolver).to_text() log_req.result = 'Success' except Exception, e: #TODO(tomas): Log an error? #TODO(tomas): Remove ugly legacy general exception handling. context['main'] = _("Object_not_found") return self._render('base', ctx=context)
def login(self, *args, **kwd): """ The 'gateway' to the rest of Daphne. Handles authentication and login form processing." """ if cherrypy.session.get('corbaSessionString'): # Already logged in, redirect to /summary. self._handle_double_login() raise cherrypy.HTTPRedirect('/summary/') if kwd: if cherrypy.request.method == 'GET' and kwd.get('next'): form = LoginForm(action='/login/', method='post') form.fields['next'].value = kwd['next'] else: form = LoginForm(kwd, action='/login/', method='post') else: form = LoginForm(action='/login/', method='post') if form.is_valid(): admin = self._init_login(form) log_req = utils.create_log_request('Login', [['username', form.cleaned_data.get('login')]]) out_props = [] try: # May raise a HTTPRedirect self._authenticate(form, admin) user, corba_session_string = self._authorize(form, admin) out_props.append(['session_id', corba_session_string]) log_req.result = 'Success' except (AuthenticationError, AuthorizationError), exc: form.non_field_errors().append(str(exc)) if config.debug: form.non_field_errors().append(noesc(escape(unicode( traceback.format_exc())).replace('\n', '<br/>'))) if log_req: log_req.result = 'Fail' self._remove_session_data() else: self._fill_session_data(form, user, corba_session_string) if log_req: log_req.result = 'Success' # Login completed, go to the next page. raise cherrypy.HTTPRedirect(form.cleaned_data.get('next', "/summary/")) finally:
def _process_valid_form(self, form, reg, reg_id, context, log_request_name): props = self._construct_changed_fields(form) in_refs = [] if reg_id: in_refs = [('registrar', int(reg_id))] log_req = utils.create_log_request(log_request_name, properties=props, references=in_refs) out_refs = [] try: registrar = self._fill_registrar_struct_from_form(reg, form.cleaned_data) corba_reg = recoder.u2c(registrar) result = {'reg_id': None} form.fire_actions(updated_registrar=corba_reg, result=result) if result['reg_id'] != reg_id: # new registrar created, add him to out_refs out_refs.append(('registrar', result['reg_id'])) reg_id = result['reg_id'] log_req.result = 'Success' except editforms.UpdateFailedError, e: form.non_field_errors().append(str(e)) context['form'] = form log_req.result = 'Fail' return context
props = [('group_name', group_name), ('group_id', group_id)] log_req = utils.create_log_request('DeleteRegistrarGroup', properties=props) try: mgr.deleteGroup(group_id) log_req.result = 'Success' except Registry.Registrar.InvalidValue, e: log_req.result = 'Fail' error(e) raise UpdateFailedError( _(u'Group %s is not empty.') % group_name) finally: log_req.close() elif 'name' in self.changed_data: props = [('group_name', group_name), ('group_id', group_id)] log_req = utils.create_log_request('UpdateRegistrarGroup', properties=props) try: mgr.updateGroup(group_id, group_name) log_req.result = 'Success' except Registry.Registrar.InvalidValue, e: log_req.result = 'Fail' error(e) raise UpdateFailedError( _(u'Updating group %s has failed.') % group_name) finally: log_req.close() class GroupManagerEditForm(EditForm): groups = FormSetField(label=_('Registrar groups'), form_class=RegistrarGroupsEditForm,
def detail(self, *args, **kwd): # path can be 'detail/ID/' or 'detail/ID/resolve/' if (not 1 <= len(args) <= 2) or (len(args) > 1 and args[1] != 'resolve'): return self._render('404_not_found') check_handle = args[0] if len(args) > 1: # cache lock is just helping users so they don't work on the same Check, but it's optional: if cache: cache_key = RESOLVE_LOCK_CACHE_KEY % check_handle stored = cache.add( cache_key, cherrypy.session['user'].login, config.verification_check_lock_default_duration) current_resolving_user = cache.get(cache_key) # resolve only if memcache is not running (return value 0) or lock was acquired (return value True) or # the current user is the user who has the lock: if (stored == 0 and type(stored) == type(0)) or stored is True \ or current_resolving_user == cherrypy.session['user'].login: resolve = True else: messages.warning( 'This check is currently being resolved by the user "%s"' % current_resolving_user) raise cherrypy.HTTPRedirect(f_urls['contactcheck'] + 'detail/%s/' % check_handle) else: resolve = True else: # read only mode resolve = False post_data = kwd if cherrypy.request.method == 'POST' else None if resolve and post_data: req_type = 'ContactCheckUpdateTestStatuses' else: req_type = 'ContactCheckDetail' log_req = create_log_request( req_type, properties=[['check_handle', check_handle]]) out_props = [] check = None try: check = c2u(cherrypy.session['Verification'].getContactCheckDetail( check_handle)) if resolve: check_nperm_func('change.contactcheck_%s' % check.test_suite_handle, raise_err=True) else: check_nperm_func('read.contactcheck_%s' % check.test_suite_handle, raise_err=True) if resolve: if self._is_check_post_closed(check): messages.warning( _('This contact check was already resolved.')) raise cherrypy.HTTPRedirect(f_urls['contactcheck'] + 'detail/%s/' % check.check_handle) elif self._is_check_pre_run(check) and check.status_history[ -1].status != 'enqueue_req': messages.warning(_('This contact check was not yet run.')) raise cherrypy.HTTPRedirect(f_urls['contactcheck'] + 'detail/%s/' % check.check_handle) initial = { test_data.test_handle: test_data.status_history[-1].status for test_data in check.test_list } form = self._generate_update_tests_form_class(check)( post_data, initial=initial) if form.is_valid(): changed_statuses = {} for test_data in check.test_list: status_in_form = form.cleaned_data[ test_data.test_handle] if status_in_form != test_data.status_history[ -1].status: changed_statuses[ test_data.test_handle] = status_in_form if changed_statuses: cherrypy.session[ 'Verification'].updateContactCheckTests( u2c(check.check_handle), u2c([ Registry.AdminContactVerification. ContactTestUpdate(test_handle, status) for test_handle, status in changed_statuses.items() ]), u2c(log_req.request_id)) log_req.result = 'Success' out_props += [['changed_statuses', '']] + [[ key, val, True ] for key, val in changed_statuses.items()] self._update_check(check, post_data) else: log_req.result = 'Fail' else: form = None log_req.result = 'Success' detail = VerificationCheckDetail(check=check, resolve=resolve, form=form) try: contact_detail = get_detail('contact', check.contact_id) except ccReg.Admin.ObjectNotFound: contact_detail = None context = DictLookup({ 'test_suit_name': ContactCheckEnums.SUITE_NAMES.get(check.test_suite_handle), 'check': check, 'contact_url': f_urls['contact'] + 'detail/?id=%s' % check.contact_id, 'detail': detail, 'contact_detail': contact_detail, 'ajax_json_filter_url': f_urls['contactcheck'] + 'json_filter/%s/' % check.contact_id, }) if cherrypy.session.get('history', False): context.update({ 'table_tag': self._get_checks_table_tag(), 'messages_list': self._get_check_messages_list(check) }) return self._render('detail', ctx=context) except Registry.AdminContactVerification.INVALID_CHECK_HANDLE: log_req.result = 'Fail' return self._render('404_not_found') finally: log_req.close(properties=out_props, references=[('contact', check.contact_id)] if check else None)
group_id = int(group_id) if 'DELETE' in self.changed_data: props = [('group_name', group_name), ('group_id', group_id)] log_req = utils.create_log_request('DeleteRegistrarGroup', properties = props) try: mgr.deleteGroup(group_id) log_req.result = 'Success' except Registry.Registrar.InvalidValue, e: log_req.result = 'Fail' error(e) raise UpdateFailedError(_(u'Group %s is not empty.') % group_name) finally: log_req.close() elif 'name' in self.changed_data: props = [('group_name', group_name), ('group_id', group_id)] log_req = utils.create_log_request('UpdateRegistrarGroup', properties = props) try: mgr.updateGroup(group_id, group_name) log_req.result = 'Success' except Registry.Registrar.InvalidValue, e: log_req.result = 'Fail' error(e) raise UpdateFailedError(_(u'Updating group %s has failed.') % group_name) finally: log_req.close() class GroupManagerEditForm(EditForm): groups = FormSetField( label=_('Registrar groups'), form_class=RegistrarGroupsEditForm,
def _get_list(self, context, cleaned_filters=None, in_log_props=None, **kwd): log_req = create_log_request(f_name_actionfiltername[self.__class__.__name__.lower()], properties=in_log_props) try: out_props = [] table = self._get_itertable() show_result = True try: page = int(kwd.get('page', 1)) except (ValueError, TypeError): page = 1 try: sort_col = kwd.get('sort_col') if sort_col is not None: sort_col = int(kwd.get('sort_col')) except (ValueError, TypeError): sort_col = 1 try: sort_dir = bool(int(kwd.get('sort_dir', 1))) except (ValueError, TypeError): sort_dir = True if cleaned_filters is not None: table.set_filter(cleaned_filters) if kwd.get('save_input'): # save filter props = (('name', kwd['save_input']), ('type', f_name_actionfiltername[self.__class__.__name__.lower()])) save_log_req = create_log_request('SaveFilter', properties = props) try: table.save_filter(kwd['save_input']) save_log_req.result = 'Success' finally: save_log_req.close() context['main'].add(_('Filter saved as "%s"') % kwd['save_input']) show_result = False else: # normal setting filter table.reload() if kwd.get('filter_id'): # load filter # Do not log filter load (Jara's decision - it would just clutter # the log output). table.load_filter(int(kwd.get('filter_id'))) if kwd.get('show_form') or not table.all_fields_filled(): show_result = False filter_data = table.get_filter_data() form_class = self._get_filterform_class() context['form'] = UnionFilterForm( filter_data, data_cleaned=True, form_class=form_class) else: table.reload() if kwd.get('cf'): table.clear_filter() if kwd.get('reload'): table.reload() if kwd.get('load'): # load current filter from backend cleaned_filter_data = table.get_filter_data() form_class = self._get_filterform_class() form = UnionFilterForm( cleaned_filter_data, form_class=form_class, data_cleaned=True) context['form'] = form context['show_form'] = kwd.get('show_form') if config.debug: context['main'].add( 'kwd_json_data_loaded:', cleaned_filter_data) if kwd.get('list_all'): table.clear_filter() table._table.add() table.reload() if sort_col is not None: table.set_sort(sort_col, sort_dir) log_req.result = 'Success' if show_result: out_props.append(('result_size', table.num_rows)) if table.num_rows == 0: context['result'] = _("No_entries_found") if table.num_rows == 1: rowId = table.get_row_id(0) raise (cherrypy.HTTPRedirect(f_urls[self.classname] + 'detail/?id=%s' % rowId)) if kwd.get('txt', None): cherrypy.response.headers["Content-Type"] = "text/plain" cherrypy.response.headers["Content-Disposition"] = \ "inline; filename=%s_%s.txt" % (self.classname, time.strftime('%Y-%m-%d')) return fileGenerator(table) elif kwd.get('csv', None): cherrypy.response.headers["Content-Type"] = "text/plain" cherrypy.response.headers["Content-Disposition"] = \ "attachement; filename=%s_%s.csv" % ( self.classname, time.strftime('%Y-%m-%d')) return fileGenerator(table) table.set_page(page) context['itertable'] = table except ccReg.Filters.SqlQueryTimeout, e: context['main'].add(h1(_('Timeout')), p(_('Database timeout, please try to be more specific about requested data.')))
form.action = '/login/' return self._render('login', {'form': form}) @login_required def logout(self): if cherrypy.session.get('Admin'): try: corba_session_string = cherrypy.session['corbaSessionString'] cherrypy.session['Admin'].destroySession(corba_session_string) except CORBA.TRANSIENT, e: debug('Admin.destroySession call failed, backend server ' 'is not running.\n%s' % e) if cherrypy.session.get('Logger'): try: log_req = utils.create_log_request('Logout') log_req.result = 'Success' log_req.close() utils.get_logger().close_session( session_id=cherrypy.session.get('logger_session_id')) except (omniORB.CORBA.SystemException, ccReg.Admin.ServiceUnavailable, LoggingException): # Let the user logout even when logging is critical (otherwise # they're stuck in Daphne and they have to manually delete the # session). error("Failed to log logout action!") self._remove_session_data() raise cherrypy.HTTPRedirect('/') class Summary(AdifPage):
@login_required def logout(self): if cherrypy.session.get('Admin'): try: corba_session_string = cherrypy.session['corbaSessionString'] cherrypy.session['Admin'].destroySession( corba_session_string) except CORBA.TRANSIENT, e: debug('Admin.destroySession call failed, backend server ' 'is not running.\n%s' % e) if cherrypy.session.get('Logger'): try: log_req = utils.create_log_request('Logout') log_req.result = 'Success' log_req.close() utils.get_logger().close_session(session_id=cherrypy.session.get('logger_session_id')) except (omniORB.CORBA.SystemException, ccReg.Admin.ServiceUnavailable, LoggingException): # Let the user logout even when logging is critical (otherwise # they're stuck in Daphne and they have to manually delete the # session). error("Failed to log logout action!") self._remove_session_data() raise cherrypy.HTTPRedirect('/') class Summary(AdifPage):