def _on_setup_widgets(self): e_type = self.attr('e_type') eids = self.attr('eids', []) ol = htmler.Ol() for eid in eids: if e_type == 'role': ol.append_child(htmler.Li(auth.get_role(uid=eid).name)) elif e_type == 'user': ol.append_child(htmler.Li(auth.get_user(uid=eid).login)) self.add_widget( widget.static.Text( uid='confirmation_text', text=lang.t('auth_admin@delete_{}_confirmation'.format( self.attr('e_type'))), )) self.add_widget(widget.static.HTML( uid='uids_text', em=ol, )) self.add_widget( widget.button.Link(uid='action_cancel', weight=100, form_area='footer', href=self.referer or self.redirect or router.base_url(), value=lang.t('auth_admin@cancel'), icon='fa fas fa-ban')) self.submit_button.color = 'btn btn-danger' self.submit_button.icon = 'fa fas fa-trash' self.submit_button.value = lang.t('auth_admin@delete')
def _on_setup_widgets(self): """Hook. """ from ._api import dispense_entity # List of items to process ol = htmler.Ol() for eid in self.attr('eids', self.attr('ids', [])): entity = dispense_entity(self.attr('model'), eid) self.add_widget( widget.input.Hidden(uid='eids-' + eid, name='eids', value=eid)) ol.append_child( htmler.Li(entity.odm_ui_mass_action_entity_description())) self.add_widget(widget.static.HTML(uid='eids-text', em=ol)) # Submit button submit_button = self.get_widget( 'action_submit') # type: widget.button.Submit submit_button.value = lang.t('odm_ui@continue') submit_button.icon = 'angle-double-right' # Cancel button self.add_widget( widget.button.Link(uid='action_cancel', weight=100, value=lang.t('odm_ui@cancel'), href=self.referer or self.redirect or router.base_url(), icon='fa fas fa-ban', form_area='footer'))
def _on_setup_widgets(self): self.add_widget( widget.input.Password( uid='password', weight=10, placeholder=lang.t('auth_ui_password@new_password'), prepend='<i class="fa fa-fw fa-lock"></i>', h_size='col col-sm-6' if _BS_VER == 4 else 'col-sm-6 col-sm-offset-3', h_size_row_css='justify-content-center' if _BS_VER == 4 else '', h_size_label=True, required=True, )) self.add_widget( widget.input.Password( uid='password_confirm', weight=20, placeholder=lang.t('auth_ui_password@password_confirm'), prepend='<i class="fa fa-fw fa-lock"></i>', h_size='col col-sm-6' if _BS_VER == 4 else 'col-sm-6 col-sm-offset-3', h_size_row_css='justify-content-center' if _BS_VER == 4 else '', h_size_label=True, required=True, )) submit_btn = self.get_widget('action_submit') submit_btn.value = lang.t('auth_ui_password@reset_password') submit_btn.icon = 'fa fa-key'
def on_auth_sign_up(user: auth.AbstractUser): # Set session notification router.session().add_success_message( lang.t('auth_ui@registration_form_success')) # Send a confirmation email to the user if auth.is_sign_up_confirmation_required(): msg = tpl.render( 'auth_ui@mail/{}/sign-up'.format(lang.get_current()), { 'user': user, 'confirm_url': router.rule_url('auth_ui@sign_up_confirm', {'code': user.confirmation_hash}) if not user.is_confirmed else None }) mail.Message(user.login, lang.t('auth_ui@confirm_registration'), msg).send() # Send a notification emails to admins if auth.is_sign_up_admins_notification_enabled(): for admin in auth.get_admin_users(): msg = tpl.render( 'auth_ui@mail/{}/sign-up-admin-notify'.format( lang.get_current()), { 'admin': admin, 'user': user, }) mail.Message(admin.login, lang.t('auth_ui@registration_admin_notify'), msg).send()
def exec(self): reporter = auth.get_current_user() if reporter.is_anonymous: raise self.forbidden() model = self.arg('model') try: entity = _api.dispense(model, self.arg('uid')) except odm.error.EntityNotFound: raise self.not_found() tpl_name = 'content@mail/{}/abuse'.format(lang.get_current()) subject = lang.t('content@mail_subject_abuse') for recipient in auth.find_users( query.Query(query.Eq('status', 'active'))): if not entity.odm_auth_check_entity_permissions( [PERM_MODIFY, PERM_DELETE], recipient): continue body = tpl.render(tpl_name, { 'reporter': reporter, 'recipient': recipient, 'entity': entity }) mail.Message(entity.author.login, subject, body).send() return {'message': lang.t('content@abuse_receipt_confirm')}
def _on_submit(self): try: user = auth.get_user(self.val('login')) if user.status != auth.USER_STATUS_ACTIVE: return token = util.random_password(64, True) _RESET_TOKENS_POOL.put(token, user.login, _RESET_TOKEN_TTL) reset_url = router.rule_url('auth_ui_password@reset', {'token': token}) msg_body = tpl.render( 'auth_ui_password@mail/{}/reset-password'.format( lang.get_current()), { 'user': user, 'reset_url': reset_url }) mail.Message( user.login, lang.t('auth_ui_password@reset_password_mail_subject'), msg_body).send() router.session().add_info_message( lang.t('auth_ui_password@check_email_for_instructions')) except auth.error.UserNotFound: pass
def _on_setup_widgets(self): app_id = '' app_secret = '' try: app_id = _api.get_app_id() app_secret = _api.get_app_secret() except (_error.AppIdNotSet, _error.AppSecretNotSet): pass self.add_widget( _widget.input.Text( uid='setting_app_id', weight=10, label=_lang.t('facebook@app_id'), required=True, help=_lang.t('facebook@app_id_setup_help'), rules=_validation.rule.Integer(), default=app_id, )) self.add_widget( _widget.input.Text( uid='setting_app_secret', weight=20, label=_lang.t('facebook@app_secret'), required=True, help=_lang.t('facebook@app_secret_setup_help'), rules=_validation.rule.Regex(pattern='[0-9a-f]{32}'), default=app_secret, )) super()._on_setup_widgets()
def exec(self) -> dict: # If the user is already authenticated if not auth.get_current_user().is_anonymous: raise self.forbidden( lang.t('auth_http_api@user_already_authenticated')) try: user = auth.sign_in(self.arg('driver'), self.args) r = {'status': True} if self.arg('access_token'): r['access_token'] = _get_access_token_info( auth.generate_access_token(user)) return r # User account is not active except (auth.error.UserNotActive, auth.error.UserNotConfirmed) as e: raise self.warning(e, 401) # Any other exception except Exception as e: # Don't expose reason of error to the outer world logger.error(e) raise self.unauthorized( lang.t('auth_http_api@authentication_error'))
def _update_themes(): import subprocess import semaver from os import path from pytsite import console, lang, pip, plugman from plugins import assetman from . import _api for theme in _api.get_all().values(): # Update theme from git repository if path.exists(path.join(theme.path, '.git')): console.print_info( lang.t('theming@updating_theme', {'name': theme.name})) subprocess.call(['git', '-C', theme.path, 'pull']) console.print_info( lang.t('theming@installing_theme_requirements', {'name': theme.name})) # Install/upgrade required pip packagers for p_name, p_ver in theme.requires['packages'].items(): pip.install(p_name, p_ver, True) # Install or update required plugins for p_name, p_ver in theme.requires['plugins'].items(): plugman.install(p_name, semaver.VersionRange(p_ver)) # Compile theme assets if assetman.is_package_registered(theme.package_name): assetman.build(theme.package_name)
def _on_setup_widgets(self): # Label self.add_widget( widget.static.HTML(uid='upload_header', weight=10, em=htmler.H2( lang.t('theming@install_or_update_theme')))) # Upload theme input self.add_widget( widget.input.File( uid='file', weight=11, max_files=1, upload_endpoint=http_api.endpoint('theming@install'), )) # Themes browser self.add_widget(_ThemesBrowser( uid='themes', weight=20, )) # Label self.add_widget( widget.static.HTML( uid='theme_settings_header', weight=30, em=htmler.H2(lang.t('theming@theme_settings')), )) # Logo self.add_widget( file_ui.widget.ImagesUpload( uid='setting_logo', weight=40, label=lang.t('theming@logo'), skip_missing=True, )) # Footer logo self.add_widget( file_ui.widget.ImagesUpload( uid='setting_logo_footer', weight=50, label=lang.t('theming@logo_footer'), skip_missing=True, )) # Favicon self.add_widget( file_ui.widget.ImagesUpload( uid='setting_favicon', weight=60, label=lang.t('theming@favicon'), skip_missing=True, )) super()._on_setup_widgets()
def get_user_statuses() -> tuple: """Get valid user statuses """ return ( ('active', lang.t('auth@status_active')), ('waiting', lang.t('auth@status_waiting')), ('disabled', lang.t('auth@status_disabled')), )
def setup_widgets(self): """Setup widgets """ # 'Submit' button for the last step if self.steps == self._current_step and self._submit_button: self.add_widget(self._submit_button) # 'Next' button for all steps except the last one if self._current_step < self.steps: self.add_widget( _widget.button.Submit(weight=200, uid='action_forward_' + str(self._current_step + 1), value=_lang.t('form@forward'), form_area='footer', color='primary', css='form-action-forward', icon='fa fas fa-fw fa-forward', data={ 'to-step': self._current_step + 1, })) # 'Back' button for all steps except the first one if self._current_step > 1: self.add_widget( _widget.button.Button(weight=100, uid='action_backward_' + str(self._current_step - 1), value=_lang.t('form@backward'), form_area='footer', form_step=self._current_step, css='form-action-backward', icon='fa fas fa-fw fa-backward', data={ 'to-step': self._current_step - 1, })) # Ask form instance to setup widgets self._on_setup_widgets() # Ask others to setup form's widgets _events.fire('form@setup_widgets.' + self.name, frm=self) # Restore widgets' values if self._cache: try: for k, v in _cache.get_pool('form.form_values').get_hash( self._uid).items(): try: self.get_widget(k).set_val(v) except _error.WidgetNotExistError: pass except _cache.error.KeyNotExist: pass return self
def __init__(self, uid: str, **kwargs): super().__init__(uid, **kwargs) self._max_slots = kwargs.get('max_slots', 100) self._modal_title = kwargs.get('modal_title', lang.t('auth_ui@select_user')) self._modal_ok_button_caption = kwargs.get('modal_ok_button_caption', lang.t('auth_ui@add')) self._modal_cancel_button_caption = kwargs.get( 'modal_cancel_button_caption')
def _on_setup_widgets(self): self.add_widget(_widget.input.Number( uid='setting_counter_id', weight=10, label=_lang.t('yandex_metrika@counter_id'), required=True, help=_lang.t('yandex_metrika@counter_id_setup_help'), rules=_validation.rule.Integer() )) super()._on_setup_widgets()
def _on_setup_widgets(self): self.add_widget( _widget.input.Text( uid='setting_tracking_id', weight=10, label=_lang.t('google_analytics@tracking_id'), required=True, help=_lang.t('google_analytics@tracking_id_setup_help'), rules=_validation.rule.Regex(pattern='UA-\d+-\d+'))) super()._on_setup_widgets()
def _on_setup_widgets(self): """Hook """ if not _api.get_drivers(): self.remove_widget('action_submit') self.add_widget(widget.static.Text( uid='error_message', text=lang.t('comments@no_comments_driver_installed'), )) return self.add_widget(widget.select.Select( uid='setting_driver', weight=10, label=lang.t('comments@driver'), h_size='col-xs-12 col-sm-6 col-md-4 col-lg-3', append_none_item=False, required=True, items=[(k, d.get_description()) for k, d in sorted(_api.get_drivers().items())], default=_api.get_driver().get_name(), )) self.add_widget(widget.select.Select( uid='setting_max_comment_depth', weight=20, label=lang.t('comments@max_comment_depth'), h_size='col-xs-12 col-sm-3 col-md-2 col-lg-1', append_none_item=False, required=True, items=[(str(x), str(x)) for x in range(0, 11)], default=4, )) self.add_widget(widget.input.Integer( uid='setting_min_comment_length', weight=30, label=lang.t('comments@min_comment_length'), h_size='col-xs-12 col-sm-3 col-md-2 col-lg-1', default=2, required=True, )) self.add_widget(widget.input.Integer( uid='setting_max_comment_length', weight=40, label=lang.t('comments@max_comment_length'), h_size='col-xs-12 col-sm-3 col-md-2 col-lg-1', default=2048, required=True, )) super()._on_setup_widgets()
def _on_setup_widgets(self): self.add_widget(_widget.input.Email( uid='email', weight=10, label=_lang.t('content_digest@your_email'), label_hidden=True, placeholder=_lang.t('content_digest@your_email'), required=True, )) self.submit_button.form_area = 'body' self.submit_button.value = _lang.t('content_digest@ok') self.submit_button.icon = None
def _on_setup_widgets(self): """Hook. """ self.add_widget( widget.input.Text( uid='setting_pub_id', weight=10, label=lang.t('addthis@pub_id'), required=True, help=lang.t('addthis@pub_id_setup_help'), rules=validation.rule.Regex(pattern='ra-[0-9a-f]{16}'))) super()._on_setup_widgets()
def _on_setup_form(self): if self.attr('e_type') not in ('role', 'user'): raise ValueError('Auth entity type is not specified') if not self.attr('eids'): raise ValueError('Entity IDs is not specified') if self.attr('e_type') == 'role': self.title = lang.t('auth_admin@delete_roles') else: self.title = lang.t('auth_admin@delete_users') lang.t('auth_admin@delete_roles')
def _on_setup_widgets(self): """Hook. """ self.add_widget( widget.input.Text( uid='setting_api_key', weight=10, label=lang.t('google_maps_ui@api_key'), help=lang.t('google_maps_ui@api_key_setup_help'), default=reg.get('google_maps.api_key'), )) super()._on_setup_widgets()
def insert_data_field(self, name: str, title: str = None, sortable: bool = True, pos: int = None): """Insert a data field """ title = lang.t(title) if title else lang.t(name) if pos is None: pos = len(self._data_fields) self._data_fields.insert(pos, (name, title, sortable))
def _render_sidebar(sidebar: admin.SideBar) -> htmler.Aside: """Render admin's sidebar """ aside = htmler.Aside(css='main-sidebar') sidebar_section_em = htmler.Section(css='sidebar') aside.append_child(sidebar_section_em) root_menu_ul = htmler.Ul(css='sidebar-menu') sidebar_section_em.append_child(root_menu_ul) sections, menus = sidebar.items # Do actual rendering for section in sections: li = htmler.Li(lang.t(section['title']), css='header', data_section_weight=section['weight']) root_menu_ul.append_child(li) # Building top level menu item for menu in menus[section['sid']]: # Link a = htmler.A( href=router.url(menu['path'], lang=lang.get_current())) # Icon if menu['icon']: a.append_child(htmler.I(css=menu['icon'])) # Title a.append_child(htmler.Span(lang.t(menu['title']))) # Label if menu['label']: label_class = 'label pull-right label-' + menu[ 'label_class'] a.append_child( htmler.Span(lang.t(menu['label']), css=label_class)) # List element li = htmler.Li(data_menu_weight=menu['weight']) # Active state if menu['active']: li.set_attr('css', 'active') li.append_child(a) root_menu_ul.append_child(li) return aside
def render(self) -> str: # 'Create' toolbar button if self._model_class.odm_ui_creation_allowed( ) and odm_auth.check_model_permissions(self._model, PERM_CREATE): create_form_url = router.rule_url( self._m_form_rule, { 'model': self._model, 'eid': 0, '__redirect': router.current_url(), }) title = lang.t('odm_ui@create') btn = htmler.A(href=create_form_url, css='btn btn-default btn-light add-button', title=title) btn.append_child(htmler.I(css='fa fas fa-fw fa-plus')) self._widget.toolbar.append_child(btn) self._widget.toolbar.append_child(htmler.Span(' ')) # 'Delete' toolbar button if self._model_class.odm_ui_deletion_allowed(): delete_form_url = router.rule_url(self._d_form_rule, {'model': self._model}) title = lang.t('odm_ui@delete_selected') btn = htmler.A( href=delete_form_url, css='hidden btn btn-danger mass-action-button sr-only', title=title) btn.append_child(htmler.I(css='fa fas fa-fw fa-remove fa-times')) self._widget.toolbar.append_child(btn) self._widget.toolbar.append_child(htmler.Span(' ')) # Additional toolbar buttons for btn_data in self._model_class.odm_ui_browser_mass_action_buttons(): ep = btn_data.get('ep') url = router.rule_url(ep) if ep else '#' css = 'btn btn-{} mass-action-button'.format( btn_data.get('color', 'default btn-light')) icon = 'fa fas fa-fw fa-' + btn_data.get('icon', 'question') button = htmler.A(href=url, css=css, title=btn_data.get('title')) if icon: button.append_child(htmler.I(css=icon)) self._widget.toolbar.append_child(button) self._widget.toolbar.append_child(htmler.Span(' ')) frm = htmler.Form(self._widget.render(), action='#', method='post', css='table-responsive odm-ui-browser') return frm.render()
def exec(self): if not auth.get_current_user().is_admin: raise self.forbidden() e_type = self.arg('e_type') if e_type == 'role': metatag.t_set('title', lang.t('auth_admin@roles')) form = _frm.BrowseRoles(self.request) elif e_type == 'user': metatag.t_set('title', lang.t('auth_admin@users')) form = _frm.BrowseUsers(self.request) else: raise self.server_error('Unknown auth entity type') return admin.render(tpl.render('auth_admin@form', {'form': form}))
def odm_ui_browser_entity_actions(self, browser) -> List[Dict]: """Get actions buttons data for single data row. """ r = [] if self.odm_ui_modification_allowed( ) and self.odm_auth_check_entity_permissions(PERM_MODIFY): r.append({ 'url': router.rule_url( browser.m_form_rule, { 'model': self.model, 'eid': str(self.id), '__redirect': router.rule_url(browser.browse_rule, {'model': self.model}), }), 'title': lang.t('odm_ui@modify'), 'icon': 'fa fas fa-fw fa-fw fa-edit', }) if self.odm_ui_deletion_allowed( ) and self.odm_auth_check_entity_permissions(PERM_DELETE): r.append({ 'url': router.rule_url( browser.d_form_rule, { 'model': self.model, 'ids': str(self.id), '__redirect': router.rule_url(browser.browse_rule, {'model': self.model}), }), 'title': lang.t('odm_ui@delete'), 'icon': 'fa fas fa-fw fa-fw fa-remove fa-times', 'color': 'danger', }) return r
def router_dispatch(): """'pytsite.router.dispatch' event handler. """ if _auth.get_current_user().has_role('dev'): if not _reg.get('tumblr.app_key') or not _reg.get('tumblr.app_secret'): _router.session().add_warning_message( _lang.t('tumblr@plugin_setup_required_warning'))
def enable(silent: bool = False): """Enable maintenance mode. """ if not is_enabled(): _cache_pool.put('enabled', True) if not silent: _console.print_success(_lang.t('pytsite.maintenance@maintenance_mode_enabled'))
def disable(silent: bool = False): """Disable maintenance mode. """ if is_enabled(): _cache_pool.rm('enabled') if not silent: _console.print_success(_lang.t('pytsite.maintenance@maintenance_mode_disabled'))
def on_router_dispatch(): try: api_key = google_maps.helpers.get_google_api_key() metatag.t_set('pytsite-google-maps-api-key', api_key) except google_maps.error.GoogleApiKeyNotDefined: if auth.get_current_user().has_role('dev'): router.session().add_warning_message(lang.t('google_maps_ui@plugin_setup_required_warning'))
def __init__(self, uid: str = None, **kwargs): """Init. """ kwargs.setdefault('title', lang.t('comments_odm@comments')) super().__init__(uid, **kwargs) self.css += ' pytsite-comments' thread_uid = kwargs.get('thread_uid') self._props.update({ 'authenticationURL': auth_ui.sign_in_url(), 'isUserAuthenticated': not auth.get_current_user().is_anonymous, 'settings': { 'maxBodyLength': comments.get_comment_max_body_length(), 'minBodyLength': comments.get_comment_min_body_length(), 'maxDepth': comments.get_comment_max_depth(), 'statuses': comments.get_comment_statuses(), 'permissions': comments.get_permissions(driver_name='odm') }, 'urls': { 'get': http_api.url('comments@get_comments', {'thread_uid': thread_uid}), 'post': http_api.url('comments@post_comment', {'thread_uid': thread_uid}), }, 'threadUID': kwargs.get('thread_uid'), 'title': kwargs.get('title'), })
def dump(tag: str) -> str: """Dump a tag """ if not _tags: raise RuntimeError('reset() should be called before') tid = _threading.get_id() if tag not in _tags[tid]: return '' # Page charset if tag == 'charset': r = '<meta charset="{}">\n'.format(_tags[tid][tag]) # Page title elif tag == 'title': r = '<title>{} | {}</title>\n'.format(_tags[tid][tag], _lang.t('app_name')) # OpenGraph tags elif tag.startswith('og:') or tag.startswith('author:') or tag.startswith('fb:'): r = '<meta property="{}" content="{}">'.format(tag, _tags[tid][tag]) # Page links elif tag == 'link': r = '' for value in _tags[tid][tag]: args_str = ' '.join(['{}="{}"'.format(k, v) for k, v in value.items()]) r += '<{} {}>\n'.format(tag, args_str) # Other else: r = '<meta name="{}" content="{}">'.format(tag, _tags[tid][tag]) return r
def _default_item_renderer(self, e: odm.Entity): caption = self._caption_field(e) if callable( self._caption_field) else e.f_get(self._caption_field) if self._translate_captions: caption = lang.t(caption) return super()._default_item_renderer((e.ref, caption))
def _do_validate(self): """Do actual validation of the rule. """ if self._value is None: return self._msg_args.update({ 'pattern': self._pattern, 'value': self._value }) if isinstance(self.value, (list, tuple)): self._msg_id += '_row' self.value = _util.cleanup_list(self.value) for k, v in enumerate(self.value): if not self._regex.match(v): raise _error.RuleError(self._msg_id, dict(self._msg_args, row=k + 1)) elif isinstance(self.value, dict): self._msg_id += '_row' self.value = _util.cleanup_dict(self.value) for k, v in self.value.items(): if not self._regex.match(v): raise _error.RuleError(self._msg_id, dict(self._msg_args, row=k + 1)) elif isinstance(self.value, str): value = self.value.strip() if value and not self._regex.match(value): raise _error.RuleError(self._msg_id, self._msg_args) else: msg = _lang.t('pytsite.validation@list_dict_str_expected', {'got': self.value.__class__.__name__}) raise TypeError(msg)
def get_comment_statuses() -> Mapping: """Get valid comment statuses. """ return { s: lang.t('comments@status_{}'.format(s)) for s in _COMMENT_STATUSES }
def update_stage_2(): # Install/update pip packages _console.print_info(_lang.t('pytsite.pip@updating_packages')) for pkg_name, pkg_ver in _package_info.requires_packages('app').items(): try: _api.install(pkg_name, pkg_ver, True, _reg.get('debug')) except _error.PackageInstallError as e: raise _console.error.CommandExecutionError(e)
def reset(title: str = None): """Reset tags """ tid = _threading.get_id() _tags[tid] = {} t_set('charset', 'UTF-8') t_set('title', title or _lang.t('pytsite.metatag@untitled_document')) t_set('viewport', 'width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0') t_set('pytsite-version', str(_package_info.version('pytsite')))
def exec(self): if self.args: packages = {} for pkg_spec in self.args: match = _PKG_SPEC_RE.findall(pkg_spec) if not match: raise _console.error.CommandExecutionError('Invalid package identifier: {}'.format(pkg_spec)) packages[match[0][0]] = match[0][1] else: packages = _package_info.requires_packages('app').items() for pkg_name, pkg_version in packages.items(): pkg_spec = '{}{}'.format(pkg_name, pkg_version) try: _console.print_info(_lang.t('pytsite.pip@package_installing', {'package': pkg_spec})) _pip.install(pkg_name, pkg_version, self.opt('upgrade'), self.opt('debug')) _console.print_success(_lang.t('pytsite.pip@package_successfully_installed', {'package': pkg_spec})) except _pip.error.Error as e: raise _console.error.CommandExecutionError(e)
def _do_validate(self): """Do actual validation of the rule. """ if self._value is None: return if not isinstance(self.value, list): msg = _lang.t('pytsite.validation@list_expected', {'got': self.value.__class__.__name__}) raise TypeError(msg) for row, sub_list in enumerate(self.value): if not isinstance(sub_list, list): msg = _lang.t('pytsite.validation@list_expected', {'got': self.value.__class__.__name__}) raise TypeError(msg) if self._index + 1 > len(sub_list): raise _error.RuleError(self._msg_id, dict(self._msg_args, row=row + 1, col=self._index + 1)) if not sub_list[self._index]: raise _error.RuleError(self._msg_id, dict(self._msg_args, row=row + 1, col=self._index + 1))
def _do_validate(self): """Do actual validation of the rule. """ if self._value is None or not self._keys: return if not isinstance(self._value, dict): raise TypeError(_lang.t('pytsite.validation@dict_expected', {'got': self.value.__class__.__name__})) for k in self._keys: if k not in self._value or not self._value[k]: raise _error.RuleError(self._msg_id, self._msg_args)
def _do_reload(): """Modify 'touch.reload' file """ touch_reload_path = _path.join(_reg.get('paths.storage'), 'touch.reload') _events.fire('pytsite.reload@before_reload') with open(touch_reload_path, 'wt') as f: f.write(_util.w3c_datetime_str()) _events.fire('pytsite.reload@reload') _console.print_info(_lang.t('pytsite.reload@app_is_reloading'))
def _do_validate(self): """Do actual validation of the rule. """ if self._value is None: return if not isinstance(self.value, list): msg = _lang.t('pytsite.validation@list_expected', {'got': self.value.__class__.__name__}) raise TypeError(msg) for row, sub_list in enumerate(self.value): if not isinstance(sub_list, list): msg = _lang.t('pytsite.validation@list_expected', {'got': self.value.__class__.__name__}) raise TypeError(msg) if self._index + 1 > len(sub_list): raise _error.RuleError(self._msg_id, {'row': row + 1, 'col': self._index + 1}) try: Url(sub_list[self._index], self._msg_id).validate() except _error.RuleError: raise _error.RuleError(self._msg_id, {'row': row + 1, 'col': self._index + 1})
def _do_validate(self): """Do actual validation of the rule. """ if self._value is None: return super()._do_validate() if isinstance(self._value, list): for k, v in enumerate(self._value): if not self._validate_str(v): raise _error.RuleError(self._msg_id, dict(self._msg_args, row=k + 1)) elif isinstance(self._value, dict): for k, v in self._value.items(): if not self._validate_str(v): raise _error.RuleError(self._msg_id, dict(self._msg_args, row=k + 1)) elif isinstance(self._value, str): if not self._validate_str(self._value): raise _error.RuleError(self._msg_id, self._msg_args) else: raise TypeError(_lang.t('pytsite.validation@list_dict_str_expected', {'got': type(self._value)}))
def _do_validate(self): if not self._value: return if isinstance(self._value, (list, tuple)): for k, v in enumerate(self._value): if not _util.is_url(v): self._msg_args['row'] = k + 1 raise _error.RuleError(self._msg_id, self._msg_args) elif isinstance(self._value, dict): for k, v in enumerate(self._value.items()): if not _util.is_url(v): self._msg_args['row'] = k + 1 raise _error.RuleError(self._msg_id, self._msg_args) elif isinstance(self._value, str): if not _util.is_url(self._value): raise _error.RuleError(self._msg_id, self._msg_args) else: raise TypeError(_lang.t('pytsite.validation@list_dict_str_expected', {'got': type(self._value)}))
def __str__(self): return _lang.t('pytsite.console@invalid_argument', {'arg_index': self._arg_index, 'arg_value': self._arg_value})
permissions.define_permission('app.settings.manage', 'app@manage_app_settings', 'app') # Settings settings.define('app', settings_form.Form, __name__ + '@application', 'fa fa-cube', 'app.settings.manage') # Index by section route router.add_rule('/section/<string:term_alias>', 'index_by_section', 'pytsite.content@index', { 'model': 'article', 'term_field': 'section', }) # Index by tag route router.add_rule('/tag/<string:term_alias>', 'article_index_by_tag', 'pytsite.content@index', { 'model': 'article', 'term_field': 'tags', }) # Prepare language related tpl globals language_nav = {} search_input = {} for l in lang.langs(): language_nav[l] = str(widget.select.LanguageNav('language-nav', dropdown=True, language=l)) search_input[l] = str(content.widget.Search('search-article', model='article', title=lang.t('app@search', language=l), language=l)) # Tpl globals tpl.register_global('language_nav', language_nav) tpl.register_global('search_input', search_input) tpl.register_global('get_content_sections', lambda: list(content.get_sections())) tpl.register_global('get_content_pages', lambda: list(content.find('page').get()))
def exec(self, args: tuple = (), **kwargs): """Execute the command. """ app_path = _reg.get('paths.app') config_path = _reg.get('paths.config') stage = self.opt('stage') stop_after = self.opt('stop-after') _chdir(app_path) _maintenance.enable() d = self._get_update_data() if not d['update_in_progress']: d['pytsite_version_from'] = str(_package_info.version('pytsite')) d['app_version_from'] = str(_package_info.version('app')) d['update_in_progress'] = True self._set_update_data(d) # Stage 1: update pip and PytSite if stage == 1: _console.print_info(_lang.t('pytsite.update@updating_environment')) # Update pip _pip.install('pip', None, True, self.opt('debug')) # Update PytSite _pip.install('pytsite', _package_info.requires_pytsite('app'), True, self.opt('debug')) d['pytsite_version_to'] = str(_package_info.version('pytsite', False)) self._set_update_data(d) # Notify listeners _events.fire('pytsite.update@stage_1') if stop_after != 1: _subprocess.call(['./console', 'update', '--stage=2']) else: _maintenance.disable() # Stage 2: update application and configuration elif stage == 2: # Notify listeners about PytSite update _events.fire('pytsite.update@pytsite', v_from=_semver.Version(d['pytsite_version_from'])) # Update configuration if _path.exists(_path.join(config_path, '.git')): _console.print_info(_lang.t('pytsite.update@updating_configuration')) _subprocess_run(['git', '-C', config_path, 'pull']) # Update application if _path.exists(_path.join(app_path, '.git')): _console.print_info(_lang.t('pytsite.update@updating_application')) _subprocess_run(['git', '-C', app_path, 'pull']) d['app_version_to'] = str(_package_info.version('app', False)) self._set_update_data(d) # Notify listeners _events.fire('pytsite.update@stage_2') if stop_after != 2: _subprocess.call(['./console', 'update', '--stage=3']) else: _maintenance.disable() # Stage 3: finish update process elif stage == 3: _console.print_info(_lang.t('pytsite.update@applying_updates')) # Notify listeners about application update _events.fire('pytsite.update@app', v_from=_semver.Version(d['app_version_from'])) # Notify listeners _events.fire('pytsite.update@update') # Application's update hook import app if hasattr(app, 'app_update') and callable(app.app_update): app.app_update(v_from=_semver.Version(d['app_version_from'])) # Mark that update was finished successfully d['update_in_progress'] = False self._set_update_data(d) # Disable maintenance mode _maintenance.disable() # Reload the application _reload.reload()
def __str__(self): return _lang.t('pytsite.console@options_not_specified', {'opts_list': self._opts_list})
def __str__(self): return _lang.t('pytsite.console@required_option_not_specified', {'opt_name': self._opt_name})
def __str__(self): return _lang.t('pytsite.console@invalid_option', {'opt_name': self._opt_name})
def __str__(self) -> str: return _lang.t(self._msg_id, self._msg_args)
def on_pytsite_update_stage_2(): # Update all installed plugins _console.print_info(_lang.t('pytsite.plugman@updating_plugins')) _console.run_command('plugman:install', {'reload': False})
def __str__(self): return _lang.t(self._msg_id, {'arg_index': self._arg_index})
def on_pytsite_load(): update_info = _api.get_update_info() if not update_info: return # If there waiting updates exist, reload the application if _reg.get('env.type') == 'wsgi': _logger.warn('Application needs to be loaded in console to finish plugins update') return failed_plugins = [] # Call 'plugin_pre_install()' hooks for p_name, info in update_info.items(): v_to = _semver.Version(info['version_to']) try: # Check if the plugin is installed and loaded plugin = _api.get(p_name) # Call plugin_pre_install() hook if hasattr(plugin, 'plugin_pre_install') and callable(plugin.plugin_pre_install): plugin.plugin_pre_install() # Fire 'pre_install' event _events.fire('pytsite.plugman@pre_install', name=p_name, version=v_to) except _error.PluginNotLoaded as e: _logger.error(e) _console.print_warning(_lang.t('pytsite.plugman@plugin_install_error', { 'plugin': p_name, 'version': v_to, 'msg': str(e), })) failed_plugins.append(p_name) continue # Finish installing/updating plugins for p_name, info in update_info.items(): if p_name in failed_plugins: continue plugin = _api.get(p_name) v_from = _semver.Version(info['version_from']) v_to = _semver.Version(info['version_to']) try: _logger.info(_lang.t('pytsite.plugman@installing_plugin', { 'plugin': p_name, 'version': v_to, })) # Call plugin_install() hook if hasattr(plugin, 'plugin_install') and callable(plugin.plugin_install): plugin.plugin_install() # Fire 'install' event _events.fire('pytsite.plugman@install', name=p_name, version=v_to) _console.print_success(_lang.t('pytsite.plugman@plugin_install_success', { 'plugin': p_name, 'version': v_to, })) except Exception as e: _logger.error(e) _console.print_warning(_lang.t('pytsite.plugman@plugin_install_error', { 'plugin': p_name, 'version': v_to, 'msg': str(e), })) continue # Update plugin if v_from != '0.0.0': try: _console.print_info(_lang.t('pytsite.plugman@updating_plugin', { 'plugin': p_name, 'v_from': v_from, 'v_to': v_to, })) # Call plugin_update() hook if hasattr(plugin, 'plugin_update') and callable(plugin.plugin_update): plugin.plugin_update(v_from=v_from) # Fire 'update' event _events.fire('pytsite.plugman@update', name=p_name, v_from=v_from) _console.print_success(_lang.t('pytsite.plugman@plugin_update_success', { 'plugin': p_name, 'version': v_to, })) except Exception as e: _console.print_warning(_lang.t('pytsite.plugman@plugin_update_error', { 'plugin': p_name, 'version': v_to, 'msg': str(e), })) continue # Remove info from update queue _api.rm_update_info(p_name)