def exec(self): model = self.arg('model') for row in self.arg('rows'): e = odm.dispense(model, row['__id']) e.f_set_multiple({ '_parent': odm.dispense(model, row['__parent']) if row['__parent'] else None, 'order': row['order'], }) e.save() return {'status': True}
def add_to_field(self, field_name: str, value): if field_name == 'follows': if not self.is_follows(value): odm.dispense('follower').f_set('follower', self).f_set('follows', value).save() elif field_name == 'blocked_users': if not self.is_blocks(value): odm.dispense('blocked_user').f_set('blocker', self).f_set( 'blocked', value).save() else: self._entity.f_add(field_name, value) return self
def create_comment( self, thread_uid: str, body: str, author: auth.model.AbstractUser, status: str = 'published', parent_uid: str = None) -> comments.model.AbstractComment: """Create a new comment """ body = body.strip() comment = odm.dispense('comment') # type: _model.ODMComment comment.f_set('thread_uid', thread_uid) comment.f_set('body', body) comment.f_set('author', author.uid) comment.f_set('status', status) comment.save() if parent_uid: parent = odm.get_by_ref('comment:' + parent_uid) if parent.depth == comments.get_comment_max_depth(): raise RuntimeError('Comment depth is too big') try: auth.switch_user_to_system() parent.append_child(comment).save() finally: auth.restore_user() return _model.Comment(comment)
def _find_entities(args: dict) -> Iterable[_model.UIEntity]: models = args['model'] sort_by = args['sort_by'] sort_order = args['sort_order'] f = odm.mfind(models) if sort_by: f.sort([(sort_by, sort_order)]) exclude = args.get('exclude') if exclude: f.ninc('_ref', exclude) # Let model's class adjust finder for model in models: mock = odm.dispense(model) # type: _model.UIEntity mock.odm_ui_widget_select_search_entities(f, args) # Collect entities entities = [] for entity in f.get(): # type: _model.UIEntity if entity.odm_ui_widget_select_search_entities_is_visible(args): entities.append(entity) if len(entities) - 1 == args['limit']: break # Do additional sorting, because MongoDB does not sort all languages properly if entities and sort_by and isinstance(entities[0].get_field(sort_by), odm.field.String): entities = sorted(entities, key=lambda e: _pyuca_col.sort_key(e.f_get(sort_by)), reverse=sort_order == odm.I_DESC) return entities
def plugin_update(v_from: _Version): # Field 'uid' added to users and roles if v_from <= '2.3': from pytsite import console, mongodb from plugins import odm for c in ('users', 'roles'): col = mongodb.get_collection(c) for d in col.find(): col.update_one({'_id': d['_id']}, {'$set': {'uid': str(d['_id'])}}) console.print_info('Document updated: {}:{}'.format(c, d['_id'])) odm.clear_cache('role') odm.clear_cache('user') odm.reindex('role') odm.reindex('user') if v_from <= '3.2': import re from pytsite import console, mongodb from plugins import odm for c in ('users', 'roles'): col = mongodb.get_collection(c) for d in col.find(): col.update_one({'_id': d['_id']}, {'$set': {'uid': d['_ref']}}) console.print_info('Document updated: {}:{}'.format(c, d['_id'])) odm.clear_cache('role') odm.clear_cache('user') odm.reindex('role') odm.reindex('user') db_obj_id_re = re.compile('[a-z:]+([0-9a-f]{24})$') for m in odm.get_registered_models(): mock = odm.dispense(m) for f_name, f in mock.fields.items(): for d in mock.collection.find(): f_new_value = None if isinstance(f, field.User) and d[f_name]: f_new_value = '{}:{}'.format('user', db_obj_id_re.sub('\\1', d[f_name])) if isinstance(f, (field.Users, field.Roles)) and d[f_name]: auth_model = 'role' if isinstance(f, field.Roles) else 'user' f_new_value = ['{}:{}'.format(auth_model, db_obj_id_re.sub('\\1', v)) for v in d[f_name]] if f_new_value: mock.collection.update_one({'_id': d['_id']}, {'$set': {f_name: f_new_value}}) console.print_info('Document updated: {}:{}'.format(m, d['_id'])) odm.clear_cache(m) if v_from <= '3.4': from plugins import odm odm.reindex('role') odm.reindex('user')
def dispense_entity(model: str, entity_id: str = None) -> _model.UIEntity: """Dispense entity. """ entity = odm.dispense(model, entity_id) if not isinstance(entity, _model.UIEntity): raise TypeError("Model '{}' must extend 'odm_ui.model.UIEntity'".format(model)) return entity
def dispense(model: str, eid: str = None) -> Content: """Dispense a content entity """ e = odm.dispense(model, eid) if not isinstance(e, Content): raise TypeError("Model '{}' is not registered as a content model".format(model)) return e
def exec(self): """Unsubscribe from content digest """ s = _odm.dispense('content_digest_subscriber', self.arg('sid')) if s: s.f_set('enabled', False).save() _router.session().add_success_message( _lang.t('content_digest@unsubscription_successful')) return self.redirect(_router.base_url())
def create_role(self, name: str, description: str = '') -> auth.AbstractRole: """Create a new role. """ role_entity = odm.dispense('role') # type: _model.ODMRole role_entity.f_set('name', name).f_set('description', description).save() return self._role_cls(role_entity)
def create_user(self, login: str, password: str = None) -> auth.AbstractUser: user_entity = odm.dispense('user') # type: _model.ODMUser user_entity.f_set_multiple({ 'login': login, 'password': password, }) return self._user_cls(user_entity)
def _dispense_entity(ref: str = None, model: str = None) -> _Entity: # Load entity try: entity = _odm.get_by_ref(ref) if ref else _odm.dispense(model) if not entity: raise _http.error.NotFound('Entity not found') if not isinstance(entity, _model.HTTPAPIEntityMixin): raise _http.error.Forbidden("Model '{}' does not support transfer via HTTP".format(entity.model)) return entity except _odm.error.ModelNotRegistered as e: raise _http.error.NotFound(e)
def create(self, file_path: str, mime: str, name: str = None, description: str = None, propose_path: str = None, **kwargs) -> _file.model.AbstractFile: # Generate unique file path in storage # Determine extension from MIME if not _os.path.splitext(name): name += _guess_extension(mime) abs_target_path = _build_store_path(name, mime, propose_path) # Make sure that directory on the filesystem exists target_dir = _os.path.dirname(abs_target_path) if not _os.path.exists(target_dir): _os.makedirs(target_dir, 0o755, True) # Copy file to the storage _shutil.copy(file_path, abs_target_path) # Create ODM entity if _IMG_MIME_RE.search(mime): odm_entity = _odm.dispense('file_image') # type: _model.ImageFileODMEntity else: odm_entity = _odm.dispense('file') # type: _model.AnyFileODMEntity storage_dir = _reg.get('paths.storage') odm_entity.f_set('path', abs_target_path.replace(storage_dir + '/', '')) odm_entity.f_set('name', name) odm_entity.f_set('description', description) odm_entity.f_set('mime', mime) odm_entity.f_set('length', _os.path.getsize(file_path)) odm_entity.save() if isinstance(odm_entity, _model.ImageFileODMEntity): return _model.ImageFile(odm_entity) elif isinstance(odm_entity, _model.AnyFileODMEntity): return _model.AnyFile(odm_entity)
def _get_entities(self) -> List[odm.Entity]: entities = [] for e in self._get_finder(): if str(e) not in self._exclude: entities.append(e) # Do additional sorting of string fields, because MongoDB does not sort properly all languages if self._sort_field and isinstance( odm.dispense(self._model).get_field(self._sort_field), odm.field.String): rev = True if self._sort_order == odm.I_DESC else False entities = sorted(entities, key=lambda ent: _pyuca_col.sort_key( ent.f_get(self._sort_field)), reverse=rev) return entities
def on_register(cls, model: str): super().on_register(model) mock = odm.dispense(model) # type: OwnedEntity def _on_user_pre_delete(user: auth.AbstractUser): if mock.has_field('author'): e = odm.find(model).eq('author', user).first() if e: raise errors.ForbidDeletion( lang.t('odm_auth@forbid_user_deletion', { 'user': user.login, 'entity': e, })) # Check for registered lang package lang_pkg_name = cls.lang_package_name() if not lang.is_package_registered(lang_pkg_name): raise RuntimeError( f"In order to use '{model}' ODM model the '{lang_pkg_name}' lang package must be registered" ) # Register permissions group perm_group = cls.odm_auth_permissions_group() # Register permissions if perm_group: for perm_name in mock.odm_auth_permissions(): # Per-user permission can be registered only if entity has 'author' field if perm_name.endswith('_own') and not mock.has_field('author'): raise ValueError( f"Permission '{perm_name}' cannot be registered for model '{model}' " f"because model does not define 'author' field") p_name = 'odm_auth@' + perm_name + '.' + model p_description = cls.resolve_lang_msg_id('odm_auth_' + perm_name + '_' + model) permissions.define_permission(p_name, p_description, perm_group) # Event handlers auth.on_user_pre_delete(_on_user_pre_delete)
def dispense(model: str, title: str, alias: str = None, language: str = None, parent: Term = None) -> Term: """Dispense a new term or raise exception if term with specified alias already exists """ if alias and get(model, alias=alias, language=language): raise _error.TermExists(model, alias, language or lang.get_current()) term = odm.dispense(model) # type: Term term.title = title.strip() term.parent = parent if term.has_field('language'): term.language = language or lang.get_current() if term.has_field('alias') and alias: term.alias = alias or util.transform_str_2(title, language) return term
def exec(self) -> dict: lng = _lang.get_current() email = _validation.rule.Email(value=self.arg('email')).validate() # Search for subscriber s = _odm.find('content_digest_subscriber').eq('email', email).eq( 'language', lng).first() # Create new subscriber if not s: s = _odm.dispense('content_digest_subscriber').f_set( 'email', email).f_set('language', lng).save() # Enable subscriber s.f_set('enabled', True).save() return { '__alert': _lang.t('content_digest@digest_subscription_success'), '__reset': True, }
def _on_setup_form(self): """Hook. """ super()._on_setup_form() model = self.attr('model') if not self.name: self.name = 'odm_ui_delete_' + model # Check permissions for eid in self.attr('eids', self.attr('ids', [])): e = odm.dispense(model, eid) # type: odm_auth.OwnedEntity if not e.odm_auth_check_entity_permissions(PERM_DELETE): raise http.error.Forbidden() # Form title model_class = odm.get_model_class(model) # type: _model.UIEntity self.title = model_class.t('odm_ui_form_title_delete_' + model) # Form CSS self.css += ' odm-ui-mass-d-form'
def _put(self, key: str, value: Any): """Set setting's value """ key_split = key.split('.') key_split_len = len(key_split) if key_split_len > 2: raise RuntimeError( 'No more than one dot is currently supported by this registry driver: {}' .format(key)) entity = odm.find('setting').eq('uid', key_split[0]).first() if not entity: entity = odm.dispense('setting').f_set('uid', key_split[0]) if key_split_len == 2: stored_value = dict(entity.f_get('value')) stored_value[key_split[1]] = value entity.f_set('value', stored_value) else: entity.f_set('value', value) entity.save()
def on_register(cls, model: str): """Hook """ super().on_register(model) def on_content_generate(entity: content.model.Content): # Section if entity.has_field('section') and entity.has_field('language'): sections = list(section.get(entity.language)) if not len(sections): raise RuntimeError('No sections found') shuffle(sections) entity.f_set('section', sections[0]) # Tags if entity.has_field('tags') and entity.has_field('language'): # Generate tags tags = list(tag.get(5, entity.language)) if tags: shuffle(tags) entity.f_set('tags', tags) # Counters for cnt_name in ('views', 'comments', 'likes', 'bookmarks'): f_name = cnt_name + '_count' if entity.has_field(f_name): entity.f_set(f_name, int(random() * 1000)) # Define 'set_starred' permission if odm.dispense(model).has_field('starred'): perm_name = 'article@set_starred.' + model perm_description = cls.resolve_lang_msg_id('content_perm_set_starred_' + model) permissions.define_permission(perm_name, perm_description, cls.odm_auth_permissions_group()) events.listen('content@generate', on_content_generate)