def __getitem__(self, name): log.debug( sys._getframe().f_code.co_name ) log.debug(type(name)) log.debug(name) name = unicode(name) try: principal = DBSession.query( self.stub_factory).filter( self.stub_factory.name == name).one() log.debug('principal found :: id={} name={} email={}'.format( principal.id, principal.name, principal.email)) return principal except NoResultFound: try: account = DBSession.query( self.factory).filter( self.factory.email == self.__name2email(name)).one() log.debug('account found id={} email={}'.format( account.id, account.email)) principal = DBSession.query( self.stub_factory).filter( self.stub_factory.id == account.id).one() log.debug('principal found :: id={} name={} email={}'.format( principal.id, principal.name, principal.email)) return principal except NoResultFound: log.error('KeyError') raise KeyError(name)
def fruit_categories_bunch(cls, order_by, how_many=10): # fruit_categories contain fruits ret = [] fruits = DBSession.query(Fruit).all() for r in DBSession.query(FruitCategory).all(): ret.append(cls.make_record(r, fruits)) return ret
def create_fruit(self, request): data = ast.literal_eval(request.body) fruit_category = \ DBSession.query(FruitCategory).filter_by( id=data['fruit_category']).first() name = str(uuid.uuid4()) fruit = Fruit(parent=fruit_category) fruit.__acl__ = SITE_ACL session = DBSession() session.add(fruit) workflow = get_workflow(fruit) if workflow: session.flush() workflow.transition_to_state(fruit, None, u'public') else: print '################ NO WORKFLOW for ', fruit.title session.flush() transaction.commit() fruit = DBSession.query(Fruit).filter_by(name=name).first() return {u'id': fruit.id, u'title': fruit.title, u'fruit_category': fruit.__parent__.id}
def default_search_content(search_term, request=None): searchstring = u'%%%s%%' % search_term # generic_filter can be applied to all Node (and subclassed) objects generic_filter = or_(Content.name.like(searchstring), Content.title.like(searchstring), Content.description.like(searchstring)) results = DBSession.query(Content).filter(generic_filter).all() # specific result contain objects matching additional criteria # but must not match the generic criteria (because these objects # are already in the generic_results) document_results = DBSession.query(Document).filter( and_(Document.body.like(searchstring), not_(generic_filter))) for results_set in [content_with_tags([searchstring]), document_results.all()]: [results.append(c) for c in results_set if not c in results] result_dicts = [] for result in results: if has_permission('view', result, request): result_dicts.append(dict( name=result.name, title=result.title, description=result.description, path=request.resource_path(result))) return result_dicts
def delete_nodes(self): """ Delete nodes view. Renders either a view to delete multiple nodes or delete the selected nodes and get back to the referrer of the request. :result: Either a redirect response or a dictionary passed to the template for rendering. :rtype: pyramid.httpexceptions.HTTPFound or dict """ if 'delete_nodes' in self.request.POST: ids = self.request.POST.getall('children-to-delete') if not ids: self.flash(_(u"Nothing was deleted."), 'info') for id in ids: item = DBSession.query(Node).get(id) self.flash(_(u'${title} was deleted.', mapping=dict(title=item.title)), 'success') del self.context[item.name] return self.back('@@contents') if 'cancel' in self.request.POST: self.flash(_(u'No changes were made.'), 'info') return self.back('@@contents') ids = self._selected_children(add_context=False) items = [] if ids is not None: items = DBSession.query(Node).filter(Node.id.in_(ids)).\ order_by(Node.position).all() return {'items': items, 'states': _states(self.context, self.request)}
def fruit_category(self, cls, id_wanted): r = DBSession.query(FruitCategory).filter_by(id=id_wanted).first() if r is not None: fruits = DBSession.query(Fruit).all() return self.make_record(r, fruits) else: return None
def delete_nodes(self): """ Delete nodes view. Renders either a view to delete multiple nodes or delete the selected nodes and get back to the referrer of the request. :result: Either a redirect response or a dictionary passed to the template for rendering. :rtype: pyramid.httpexceptions.HTTPFound or dict """ if "delete_nodes" in self.request.POST: ids = self.request.POST.getall("children-to-delete") if not ids: self.request.session.flash(_(u"Nothing deleted."), "info") for id in ids: item = DBSession.query(Node).get(id) self.request.session.flash(_(u"${title} deleted.", mapping=dict(title=item.title)), "success") del self.context[item.name] return self.back("@@contents") if "cancel" in self.request.POST: self.request.session.flash(_(u"No changes made."), "info") return self.back("@@contents") ids = self._selected_children(add_context=False) items = [] if ids is not None: items = DBSession.query(Node).filter(Node.id.in_(ids)).order_by(Node.position).all() return {"items": items, "states": _states(self.context, self.request)}
def edit_project(request, user, resume_id): t = request.POST["project"] if resume_id != int(request.POST['resume_id']): return Response(json.dumps({'__result':1})) #TODO use try/except if t == "new": resume = DBSession.query(resources.Resume).filter_by(user=user, id=resume_id).first() obj = resources.ProjectInfo() cstruct2project(request.POST, obj) resume.projects.append(obj) #flush to get the new id DBSession.flush() widget = ProjectWidget(resume_id, resume.projects) json_string = json.dumps({'__result':0}) return Response(json_string+"$"+widget.render()) elif t == "modify": cstruct = {} cstruct2project(request.POST, cstruct) DBSession.query(resources.ProjectInfo).filter_by(resume_id=resume_id, id=int(request.POST['id'])).\ update(cstruct, synchronize_session=False) resume = DBSession.query(resources.Resume).filter_by(user=user, id=resume_id).first() widget = ProjectWidget(resume_id, resume.projects) json_string = json.dumps({'__result':0}) return Response(json_string+"$"+widget.render()) elif t == "delete": project = DBSession.query(resources.ProjectInfo).filter_by(resume_id=resume_id, id=int(request.POST['id'])).first() oid = project.id DBSession.delete(project) return Response(json.dumps({'__result':0,'id':oid})) return Response(json.dumps({'__result':1}))
def edit_job(request, user, resume_id): t = request.POST["experience"] if resume_id != int(request.POST['resume_id']): #TODO raise error pass if t == "new": resume = DBSession.query(resources.Resume).filter_by(user=user, id=resume_id).first() job_schema = JobSchema() cstruct = job_schema.deserialize(request.POST) job_obj = resources.Job() cstruct2job(cstruct, job_obj) resume.jobs.append(job_obj) #flush to get the new id DBSession.flush() widget = JobsWidget(resume_id, resume.jobs) json_string = json.dumps({'__result':0}) return Response(json_string+"$"+widget.render()) elif t == "modify": job_schema = JobSchema() cstruct = job_schema.deserialize(request.POST) DBSession.query(resources.Job).filter_by(resume_id=resume_id, id=int(request.POST['id'])).\ update(cstruct, synchronize_session=False) resume = DBSession.query(resources.Resume).filter_by(user=user, id=resume_id).first() widget = JobsWidget(resume_id, resume.jobs) json_string = json.dumps({'__result':0}) return Response(json_string+"$"+widget.render()) elif t == "delete": job = DBSession.query(resources.Job).filter_by(resume_id=resume_id, id=int(request.POST['id'])).first() oid = job.id DBSession.delete(job) return Response(json.dumps({'__result':0,'id':oid})) return Response(json.dumps({'__result':1}))
def job_detail_view(context, request): jquery.need() pos_id = request.matchdict['id'] pos_id = int(pos_id) user = get_user(request) interest = "" if user.interest: interest = user.interest industry = "" if user.industry: industry = user.industry if interest == "" and industry == "": pos_like = DBSession.query(Position).all()[0:5] else: pos_like = DBSession.query(Position).join(CompanyInfo).filter( or_(Position.title.like(interest) , CompanyInfo.industry.like(industry)) )[0:5] pos = DBSession.query(Position).get(pos_id) return { 'pos': pos, 'pos_like': pos_like, }
def get_messages(type, context, request): jquery.need() cur_user = get_user(request) if not cur_user: return HTTPFound(location="/login?came_from=%s" % request.url) messages = [] if type == 'all_messages': messages = DBSession.query(Message).filter_by(reciever_id=cur_user.id).all() elif type == 'system_messages': messages = DBSession.query(Message).filter( and_( Message.reciever_id==cur_user.id, or_(Message.type==0 , Message.type==1 , Message.type==10) )).all() elif type == 'friend_messages': messages = DBSession.query(Message).filter_by(reciever_id=cur_user.id, type=2).all() elif type == 'view_invitation_person': messages = DBSession.query(Message).filter_by(reciever_id=cur_user.id, type=11).all() elif type == 'view_invitation_meetup': messages = DBSession.query(Message).filter_by(reciever_id=cur_user.id, type=12).all() elif type == 'view_invitation_code': messages = view_or_generate_inviation_code(user) return {'type': type, 'messages': messages}
def edit_education(request, user, resume_id): t = request.POST["education"] if resume_id != int(request.POST['resume_id']): #TODO raise error pass if t == 'new': resume = DBSession.query(resources.Resume).filter_by(user=user, id=resume_id).first() edu_schema = Education() cstruct = edu_schema.deserialize(request.POST) edu_obj = resources.Education() cstruct2edu(cstruct, edu_obj) resume.educations.append(edu_obj) #flush to get the new id DBSession.flush() widget = EducationsWidget(resume_id, resume.educations) json_string = json.dumps({'__result':0}) return Response(json_string+"$"+widget.render()) elif t == 'modify': edu_schema = Education() cstruct = edu_schema.deserialize(request.POST) DBSession.query(resources.Education).filter_by(resume_id=resume_id, id=int(request.POST['id'])).\ update(cstruct, synchronize_session=False) resume = DBSession.query(resources.Resume).filter_by(user=user, id=resume_id).first() widget = EducationsWidget(resume_id, resume.educations) json_string = json.dumps({'__result':0}) return Response(json_string+"$"+widget.render()) elif t == 'delete': edu = DBSession.query(resources.Education).filter_by(resume_id=resume_id, id=int(request.POST['id'])).first() oid = edu.id DBSession.delete(edu) return Response(json.dumps({'__result':0,'id':oid})) # raise error, not exists this operation return Response(json.dumps({'__result':1}))
def _get_product(self, sku, subsku): """return tuple product & variation""" product = DBSession.query( VendoProduct).filter_by(sku=sku).one() variation = DBSession.query( VendoProductVariation).filter_by(sub_sku=subsku).one() return product, variation
def create_fruit_category(self, request): data = ast.literal_eval(request.body) # Assume only one fruit_categories folder. fruit_categories_folder = \ DBSession.query(FruitCategoriesFolder).first() name = str(uuid.uuid4()) fruit_category = FruitCategory(name=name, title=data['title'], parent=fruit_categories_folder) fruit_category.__acl__ = SITE_ACL session = DBSession() session.add(fruit_category) workflow = get_workflow(fruit_category) if workflow: session.flush() workflow.transition_to_state(fruit_category, None, u'public') else: print '################ NO WORKFLOW for ', fruit_category.title session.flush() transaction.commit() fruit_category = \ DBSession.query(FruitCategory).filter_by(name=name).first() return {u'id': fruit_category.id, u'title': fruit_category.title}
def order_node(context, request): P = request.POST if 'order-up' in P or 'order-down' in P: up, down = P.get('order-up'), P.get('order-down') child = DBSession.query(Node).get(int(down or up)) if up is not None: mod = -1 else: # pragma: no cover mod = 1 index = context.children.index(child) context.children.pop(index) context.children.insert(index + mod, child) request.session.flash(_(u'${title} moved.', mapping=dict(title=child.title)), 'success') if not request.is_xhr: return HTTPFound(location=request.url) elif 'toggle-visibility' in P: child = DBSession.query(Node).get(int(P['toggle-visibility'])) child.in_navigation ^= True mapping = dict(title=child.title) if child.in_navigation: msg = _(u'${title} is now visible in the navigation.', mapping=mapping) else: msg = _(u'${title} is no longer visible in the navigation.', mapping=mapping) request.session.flash(msg, 'success') if not request.is_xhr: return HTTPFound(location=request.url) return {}
def rename_nodes(self): """ Rename nodes view. Renders either a view to change the titles and names for multiple nodes or handle the changes and get back to the referrer of the request. :result: Either a redirect response or a dictionary passed to the template for rendering. :rtype: pyramid.httpexceptions.HTTPFound or dict """ if "rename_nodes" in self.request.POST: ids = self.request.POST.getall("children-to-rename") for id in ids: item = DBSession.query(Node).get(id) name = self.request.POST[id + "-name"] title = self.request.POST[id + "-title"] if not name or not title: self.request.session.flash(_(u"Name and title are required."), "error") location = resource_url(self.context, self.request) + "@@rename_nodes" return HTTPFound(location=location) else: item.name = title_to_name(name, blacklist=self.context.keys()) item.title = title self.request.session.flash(_(u"Your changes have been saved."), "success") return self.back("@@contents") if "cancel" in self.request.POST: self.request.session.flash(_(u"No changes made."), "info") return self.back("@@contents") ids = self._selected_children(add_context=False) items = [] if ids is not None: items = DBSession.query(Node).filter(Node.id.in_(ids)).all() return {"items": items}
def admin_home_banners(context, request): jquery.need() user = get_user(request) if not user: return HTTPFound(location="/login?came_from=%s" % request.url) if 'method' in request.POST: # mt stands for meetup-type try: method = request.POST['method'] # del-banner if method == 'del-banner': mt_id = int(request.POST['banner-id']) to_op_mt = DBSession.query(Banner).filter_by(id=mt_id).first() banner_id = request.POST.get('banner-id', None) if not banner_id : return RetDict(errcode=RetDict.ERR_CODE_WRONG_PARAM) try: banner_id = int(banner_id) except ValueError,e: return RetDict(errcode=RetDict.ERR_CODE_WRONG_PARAM) banner = DBSession.query(Banner).filter_by(id=banner_id).first() if not banner: return RetDict(errcode=RetDict.ERR_CODE_WRONG_PARAM) DBSession.delete(banner) msg = u"成功删除BANNER %d" % banner_id request.session.flash(msg, 'success') return RetDict(retval=msg) except Exception,ex: err_msg = "错误:%s" % ex request.session.flash(err_msg, 'danger') return RetDict(errmsg=err_msg)
def delete(self, file_or_id: str) -> None: """Deletes a file. If the file didn't exist it will just do nothing. :param file_or_id: can be either ``DBStoredFile`` or a ``file_id`` """ file_id = self._get_file_id(file_or_id) DBSession.query(DBStoredFile).filter_by(file_id=file_id).delete()
def test_clear(self, db_session): from kotti import DBSession from kotti.resources import get_root from kotti.resources import Node child = get_root()['child'] = Node() assert DBSession.query(Node).filter(Node.name == u'child').all() == [ child] get_root().clear() assert DBSession.query(Node).filter(Node.name == u'child').all() == []
def delete_orphaned_tags(event): """Delete Tag instances / records when they are not associated with any content. :param event: event that trigerred this handler. :type event: :class:`ObjectAfterDelete` """ DBSession.query(Tag).filter(~Tag.content_tags.any()).delete( synchronize_session=False)
def test_container_methods(self): from kotti import DBSession from kotti.resources import get_root from kotti.resources import Node session = DBSession() # Test some of Node's container methods: root = get_root() self.assertEquals(root.keys(), []) child1 = Node(name=u'child1', parent=root) session.add(child1) self.assertEquals(root.keys(), [u'child1']) self.assertEquals(root[u'child1'], child1) del root[u'child1'] self.assertEquals(root.keys(), []) # When we delete a parent node, all its child nodes will be # released as well: root[u'child2'] = Node() root[u'child2'][u'subchild'] = Node() self.assertEquals( session.query(Node).filter(Node.name == u'subchild').count(), 1) del root[u'child2'] self.assertEquals( session.query(Node).filter(Node.name == u'subchild').count(), 0) # We can pass a tuple as the key to more efficiently reach # down to child objects: root[u'child3'] = Node() subchild33 = Node(name=u'subchild33', parent=root[u'child3']) session.add(subchild33) del root.__dict__['_children'] # force a different code path self.assertTrue( root[u'child3', u'subchild33'] is root[u'child3'][u'subchild33']) self.assertTrue( root[(u'child3', u'subchild33')] is subchild33) self.assertTrue( root[(u'child3', u'subchild33')] is subchild33) self.assertRaises(KeyError, root.__getitem__, (u'child3', u'bad-name')) root.children # force a different code path self.assertRaises(KeyError, root.__getitem__, (u'child3', u'bad-name')) del root[u'child3'] # Overwriting an existing Node is an error; first delete manually! child4 = Node(name=u'child4', parent=root) session.add(child4) self.assertEquals(root.keys(), [u'child4']) child44 = Node(name=u'child4') session.add(child44) root[u'child4'] = child44 self.assertRaises(SQLAlchemyError, session.flush)
def test_act(): # Step 1 Act test print 'Test Act' print DBSession.query(Act).count() act = Act(**_TEST_ATTRS) DBSession.add(act) print DBSession.query(Act).count() print 'Act.parts', act.parts # Step 2 Student test print 'Test Student' print DBSession.query(Student).count() stu = Student(name=u'test') DBSession.add(stu) print DBSession.query(Student).count() # Step 3 Participate test part = Participate() part.act_id = act.id part.user_id = stu.id DBSession.add(part) print 'Act.parts', act.parts DBSession.flush() #part = DBSession.query(Participate).first() #print 'Part user', part.user, part.act_id act = DBSession.query(Act).first() print 'query Act', act.id print 'Act.parts', act._parts
def test_add(self, db_session, events): from kotti import DBSession from kotti.resources import get_root from kotti.resources import Tag, TagsToContents root = get_root() root.tags = [u'tag 1', u'tag 2'] result = DBSession.query(Tag).filter(TagsToContents.item == root).all() assert result[0].items == [root] assert root.tags == [u'tag 1', u'tag 2'] assert len(DBSession.query(Tag).all()) == 2
def view_position_list(request, page_index=1, num_per_page=10): jquery.need() start = (page_index-1) * num_per_page count = DBSession.query(Position).count() positions = DBSession.query(Position).slice(start, num_per_page).all() return wrap_user2(request, { 'positions': positions, 'total_count': count, 'total_page': count/ num_per_page + 1, 'page_index': page_index })
def change_state(self): """ Change state view. Renders either a view to handle workflow changes for multiple nodes or handle the selected workflow changes and get back to the referrer of the request. :result: Either a redirect response or a dictionary passed to the template for rendering. :rtype: pyramid.httpexceptions.HTTPFound or dict """ if 'change_state' in self.request.POST: ids = self.request.POST.getall('children-to-change-state') to_state = self.request.POST.get('to-state', u'no-change') include_children = self.request.POST.get('include-children', None) if to_state != u'no-change': items = DBSession.query(Node).filter(Node.id.in_(ids)).all() for item in items: wf = get_workflow(item) if wf is not None: wf.transition_to_state(item, self.request, to_state) if include_children: childs = self._all_children(item, permission='state_change') for child in childs: wf = get_workflow(child) if wf is not None: wf.transition_to_state(child, self.request, to_state, ) self.request.session.flash( _(u'Your changes have been saved.'), 'success') else: self.request.session.flash(_(u'No changes made.'), 'info') return self.back('@@contents') if 'cancel' in self.request.POST: self.request.session.flash(_(u'No changes made.'), 'info') return self.back('@@contents') ids = self._selected_children(add_context=False) items = transitions = [] if ids is not None: wf = get_workflow(self.context) if wf is not None: items = DBSession.query(Node).filter(Node.id.in_(ids)).all() for item in items: trans_info = wf.get_transitions(item, self.request) for tran_info in trans_info: if tran_info not in transitions: transitions.append(tran_info) return {'items': items, 'states': _states(self.context, self.request), 'transitions': transitions, }
def test_container_methods(self, db_session): from kotti import DBSession from kotti.resources import get_root from kotti.resources import Node # Test some of Node's container methods: root = get_root() assert root.keys() == [] child1 = Node(name=u'child1', parent=root) DBSession.add(child1) assert root.keys() == [u'child1'] assert root[u'child1'] == child1 del root[u'child1'] assert root.keys() == [] # When we delete a parent node, all its child nodes will be # released as well: root[u'child2'] = Node() root[u'child2'][u'subchild'] = Node() assert ( DBSession.query(Node).filter(Node.name == u'subchild').count() == 1) del root[u'child2'] assert ( DBSession.query(Node).filter(Node.name == u'subchild').count() == 0) # We can pass a tuple as the key to more efficiently reach # down to child objects: root[u'child3'] = Node() subchild33 = Node(name=u'subchild33', parent=root[u'child3']) DBSession.add(subchild33) del root.__dict__['_children'] # force a different code path assert root[u'child3', u'subchild33'] is root[u'child3'][u'subchild33'] assert root[(u'child3', u'subchild33')] is subchild33 assert root[(u'child3', u'subchild33')] is subchild33 with raises(KeyError): root[u'child3', u'bad-name'] root.children # force a different code path with raises(KeyError): root[u'child3', u'bad-name'] del root[u'child3'] # Overwriting an existing Node is an error; first delete manually! child4 = Node(name=u'child4', parent=root) DBSession.add(child4) assert root.keys() == [u'child4'] child44 = Node(name=u'child4') DBSession.add(child44) root[u'child4'] = child44 with raises(SQLAlchemyError): DBSession.flush()
def view_company_list(request, page_index=1, num_per_page=10): jquery.need() start = (page_index-1) * num_per_page count = DBSession.query(CompanyInfo).count() companies = DBSession.query(CompanyInfo).slice(start, num_per_page).all() return wrap_user2(request, { 'companies': companies, 'total_count': count, 'total_page': count/ num_per_page + 1, 'page_index': page_index })
def set_groups(name, context, groups_to_set=()): """Set the list of groups for principal with given ``name`` and in given ``context``. """ name = unicode(name) from kotti.resources import LocalGroup DBSession.query(LocalGroup).filter( LocalGroup.node_id == context.id).filter( LocalGroup.principal_name == name).delete() for group_name in groups_to_set: DBSession.add(LocalGroup(context, name, unicode(group_name)))
def test_delete_content_deletes_orphaned_tags(self, db_session, events): from kotti import DBSession from kotti.resources import get_root from kotti.resources import Tag, Content root = get_root() root[u'content_1'] = Content() root[u'content_2'] = Content() root[u'content_1'].tags = [u'tag 1', u'tag 2'] root[u'content_2'].tags = [u'tag 2'] assert DBSession.query(Tag).count() == 2 del root[u'content_1'] assert DBSession.query(Tag).one().title == u'tag 2'
def cleanup_user_groups(event): """Remove a deleted group from the groups of a user/group and remove all local group entries of it.""" name = event.object.name if name.startswith("group:"): principals = get_principals() users_groups = [p for p in principals if name in principals[p].groups] for user_or_group in users_groups: principals[user_or_group].groups.remove(name) DBSession.query(LocalGroup).filter( LocalGroup.principal_name == name).delete()
def addable(self, context, request): resolver = DottedNameResolver() if hasattr(self, 'dotted_class'): resource_class = resolver.maybe_resolve(self.dotted_class) if resource_class: already_exists_box = DBSession.query(resource_class).\ filter(resource_class.parent_id == context.id).first() if already_exists_box is not None: return False else: return False else: return False return super(BoxManagerTypeInfo, self).addable(context, request)
def test_rename_to_empty_name(self): from kotti import DBSession from kotti.resources import Node from kotti.resources import Document from kotti.views.edit.actions import NodeActions root = DBSession.query(Node).get(1) child = root['child'] = Document(title=u"Child") request = DummyRequest() request.params['rename'] = u'on' request.params['name'] = u'' request.params['title'] = u'foo' NodeActions(child, request).rename_node() assert (request.session.pop_flash('error') == [ u'Name and title are required.' ])
def cut_nodes(self): """ Cut nodes view. Cut the current node or the selected nodes in the contents view and save the result in the session of the request. :result: Redirect response to the referrer of the request. :rtype: pyramid.httpexceptions.HTTPFound """ ids = self._selected_children() self.request.session['kotti.paste'] = (ids, 'cut') for id in ids: item = DBSession.query(Node).get(id) self.flash(_(u'${title} was cut.', mapping=dict(title=item.title)), 'success') if not self.request.is_xhr: return self.back()
def upgrade(): from alembic.context import get_bind conn = get_bind() if conn.engine.dialect.name == 'mysql': op.add_column('nodes', sa.Column('path', sa.Unicode(1000))) else: op.add_column('nodes', sa.Column('path', sa.Unicode(1000), index=True)) from kotti import DBSession from kotti.resources import Node for node in DBSession.query(Node).with_polymorphic([Node]): reversed_lineage = reversed(tuple(lineage(node))) node.path = u'/'.join( node.__name__ for node in reversed_lineage) or u'/'
def search(self, **kwargs): if not kwargs: return [] filters = [] for key, value in kwargs.items(): col = getattr(self.factory, key) if '*' in value: value = value.replace('*', '%').lower() filters.append(func.lower(col).like(value)) else: filters.append(col == value) query = DBSession.query(self.factory) query = query.filter(or_(*filters)) return query
def principals_with_local_roles(context, inherit=True): """Return a list of principal names that have local roles in the context. """ from resources import LocalGroup principals = set() items = [context] if inherit: items = lineage(context) for item in items: principals.update( r[0] for r in DBSession.query(LocalGroup.principal_name).filter( LocalGroup.node_id == item.id).group_by( LocalGroup.principal_name).all() if not r[0].startswith('role:')) return list(principals)
def nodes_tree(request, context=None, permission="view"): item_mapping = {} item_to_children = defaultdict(lambda: []) for node in DBSession.query(Content).with_polymorphic(Content): item_mapping[node.id] = node if request.has_permission(permission, node): item_to_children[node.parent_id].append(node) for children in item_to_children.values(): children.sort(key=lambda ch: ch.position) if context is None: node = item_to_children[None][0] else: node = context return NodesTree(node, request, item_mapping, item_to_children, permission)
def nodes_tree(request): item_mapping = {} item_to_children = defaultdict(lambda: []) for node in DBSession.query(Content).with_polymorphic(Content): item_mapping[node.id] = node if has_permission('view', node, request): item_to_children[node.parent_id].append(node) for children in item_to_children.values(): children.sort(key=lambda ch:ch.position) return NavigationNodeWrapper( item_to_children[None][0], request, item_mapping, item_to_children, )
def get_paste_items(context, request): from kotti.resources import Node items = [] info = request.session.get("kotti.paste") if info: ids, action = info for id in ids: item = DBSession.query(Node).get(id) if item is None or not item.type_info.addable(context, request): continue if action == "cut" and inside(context, item): continue if context == item: continue items.append(item) return items
def read(self, n=-1): """Reads ``n`` bytes from the file. If ``n`` is not specified or is ``-1`` the whole file content is read in memory and returned """ if self._data is _marker: file_id = DBSession.merge(self).file_id self._data = DBSession.query(DBStoredFile.data).\ filter_by(file_id=file_id).scalar() if n == -1: result = self._data[self._cursor:] else: result = self._data[self._cursor:self._cursor + n] self._cursor += len(result) return result
def test_paste_without_edit_permission(self): from kotti import DBSession from kotti.resources import Node from kotti.views.edit import paste_node root = DBSession.query(Node).get(1) request = DummyRequest() request.params['paste'] = u'on' self.config.testing_securitypolicy(permissive=False) # We need to have the 'edit' permission on the original object # to be able to cut and paste: request.session['kotti.paste'] = (1, 'cut') self.assertRaises(Forbidden, paste_node, root, request) # We don't need 'edit' permission if we're just copying: request.session['kotti.paste'] = (1, 'copy') response = paste_node(root, request) self.assertEqual(response.status, '302 Found')
def move(self, move): """ Do the real work to move the selected nodes up or down. Called by the up and the down view. :result: Redirect response to the referrer of the request. :rtype: pyramid.httpexceptions.HTTPFound """ ids = self._selected_children() if move == 1: ids.reverse() for id in ids: child = DBSession.query(Node).get(id) index = self.context.children.index(child) self.context.children.pop(index) self.context.children.insert(index + move, child) self.flash(_('${title} was moved.', mapping=dict(title=child.title)), 'success') if not self.request.is_xhr: return self.back()
def addable(self, context, request): resolver = DottedNameResolver() if hasattr(self, 'dotted_class'): resource_class = resolver.maybe_resolve(self.dotted_class) if resource_class: already_exists_action = DBSession.query(resource_class).\ filter(resource_class.parent_id == context.id).first() if already_exists_action is not None: return False else: return False else: return False if INavigationRoot.providedBy(context) and \ view_permitted(context, request, self.add_view): return True else: return False
def test_paste_without_edit_permission(self, config, db_session): from kotti import DBSession from kotti.resources import Node from kotti.views.edit.actions import NodeActions root = DBSession.query(Node).get(1) request = DummyRequest() request.params['paste'] = u'on' config.testing_securitypolicy(permissive=False) # We need to have the 'edit' permission on the original object # to be able to cut and paste: request.session['kotti.paste'] = ([1], 'cut') view = NodeActions(root, request) with raises(Forbidden): view.paste_nodes() # We don't need 'edit' permission if we're just copying: request.session['kotti.paste'] = ([1], 'copy') response = NodeActions(root, request).paste_nodes() assert response.status == '302 Found'
def populate(): """ Create the root node (:class:`~kotti.resources.Document`) and the 'about' subnode in the nodes tree if there are no nodes yet. """ lrm = LocalizerRequestMixin() lrm.registry = get_current_registry() lrm.locale_name = get_settings()['pyramid.default_locale_name'] localizer = lrm.localizer if DBSession.query(Node.id).count() == 0: localized_root_attrs = dict([(k, localizer.translate(v)) for k, v in _ROOT_ATTRS.iteritems()]) root = Document(**localized_root_attrs) root.__acl__ = SITE_ACL DBSession.add(root) localized_about_attrs = dict([(k, localizer.translate(v)) for k, v in _ABOUT_ATTRS.iteritems()]) root['about'] = Document(**localized_about_attrs) DBSession.flush() populate_users()
def set_visibility(self, show): """ Do the real work to set the visibility of nodes in the menu. Called by the show and the hide view. :result: Redirect response to the referrer of the request. :rtype: pyramid.httpexceptions.HTTPFound """ ids = self._selected_children() for id in ids: child = DBSession.query(Node).get(id) if child.in_navigation != show: child.in_navigation = show mapping = dict(title=child.title) if show: mg = _('${title} is now visible in the navigation.', mapping=mapping) else: mg = _('${title} is no longer visible in the navigation.', mapping=mapping) self.flash(mg, 'success') if not self.request.is_xhr: return self.back()
def order_node(context, request): P = request.POST session = DBSession() if 'order-up' in P or 'order-down' in P: up, down = P.get('order-up'), P.get('order-down') id = int(down or up) if up is not None: mod = -1 else: # pragma: no cover mod = 1 child = session.query(Node).get(id) index = context.children.index(child) context.children.pop(index) context.children.insert(index + mod, child) request.session.flash( _(u'${title} moved.', mapping=dict(title=child.title)), 'success') if not request.is_xhr: return HTTPFound(location=request.url) return {}
def search(self, match='any', **kwargs): """ Search the principal database. :param match: ``any`` to return all principals matching any search param, ``all`` to return only principals matching all params :type match: str :param kwargs: Search conditions, e.g. ``name='bob', active=True``. :type kwargs: varying. :result: SQLAlchemy query object :rtype: :class:`sqlalchemy.orm.query.Query`` """ if not kwargs: return [] filters = [] for key, value in kwargs.items(): col = getattr(self.factory, key) if isinstance(value, string_types) and '*' in value: value = value.replace('*', '%').lower() filters.append(func.lower(col).like(value)) else: filters.append(col == value) query = DBSession.query(self.factory) if match == 'any': query = query.filter(or_(*filters)) elif match == 'all': query = query.filter(and_(*filters)) else: raise ValueError('match must be either "any" or "all".') return query
def view_blog(self): macros = get_renderer('templates/macros.pt').implementation() query = DBSession.query(BlogEntry) query = query.filter(BlogEntry.parent_id == self.context.id) query = query.order_by(BlogEntry.date.desc()) items = query.all() items = [ item for item in items if has_permission('view', item, self.request) ] page = self.request.params.get('page', 1) use_pagination = get_setting('use_pagination') if use_pagination: items = Batch.fromPagenumber(items, pagesize=get_setting('pagesize'), pagenumber=int(page)) return { 'api': template_api(self.context, self.request), 'macros': macros, 'items': items, 'use_pagination': use_pagination, 'link_headline': get_setting('link_headline'), }
def paste_nodes(self): """ Paste nodes view. Paste formerly copied or cutted nodes into the current context. Note that a cutted node can not be pasted into itself. :result: Redirect response to the referrer of the request. :rtype: pyramid.httpexceptions.HTTPFound """ ids, action = self.request.session['kotti.paste'] for count, id in enumerate(ids): item = DBSession.query(Node).get(id) if item is not None: if action == 'cut': if not self.request.has_permission('edit', item): raise Forbidden() item.__parent__.children.remove(item) item.name = title_to_name(item.name, blacklist=list(self.context.keys())) self.context[item.name] = item if count is len(ids) - 1: del self.request.session['kotti.paste'] elif action == 'copy': copy = item.copy() name = copy.name if not name: # for root name = copy.title name = title_to_name(name, blacklist=list(self.context.keys())) copy.name = name self.context[name] = copy self.flash(_('${title} was pasted.', mapping=dict(title=item.title)), 'success') else: self.flash(_('Could not paste node. It no longer exists.'), 'error') DBSession.flush() if not self.request.is_xhr: return self.back()
def test_multi_delete(self): from kotti import DBSession from kotti.resources import Node from kotti.resources import Document from kotti.views.edit.actions import NodeActions root = DBSession.query(Node).get(1) root['child1'] = Document(title=u"Child 1") root['child2'] = Document(title=u"Child 2") request = DummyRequest() request.POST = MultiDict() id1 = str(root['child1'].id) id2 = str(root['child2'].id) request.POST.add('delete_nodes', u'delete_nodes') NodeActions(root, request).delete_nodes() assert request.session.pop_flash('info') ==\ [u'Nothing deleted.'] request.POST.add('children-to-delete', id1) request.POST.add('children-to-delete', id2) NodeActions(root, request).delete_nodes() assert request.session.pop_flash('success') ==\ [u'${title} deleted.', u'${title} deleted.']
def paste_node(context, request): session = DBSession() id, action = request.session['kotti.paste'] item = session.query(Node).get(id) if action == 'cut': if not has_permission('edit', item, request): raise Forbidden() item.__parent__.children.remove(item) context.children.append(item) del request.session['kotti.paste'] elif action == 'copy': copy = item.copy() name = copy.name if not name: # for root name = title_to_name(copy.title) while name in context.keys(): name = disambiguate_name(name) copy.name = name context.children.append(copy) request.session.flash( _(u'${title} pasted.', mapping=dict(title=item.title)), 'success') if not request.is_xhr: location = resource_url(context, request) return HTTPFound(location=location)
def migrate_storage(from_storage, to_storage): from depot.fields.sqlalchemy import _SQLAMutationTracker from depot.manager import DepotManager from kotti.util import _to_fieldstorage import logging log = logging.getLogger(__name__) old_default = DepotManager._default_depot DepotManager._default_depot = to_storage for klass, props in _SQLAMutationTracker.mapped_entities.items(): log.info("Migrating %r", klass) mapper = klass._sa_class_manager.mapper # use type column to avoid polymorphism issues, getting the same # Node item multiple times. type_ = camel_case_to_name(klass.__name__) for instance in DBSession.query(klass).filter_by(type=type_): for prop in props: uf = getattr(instance, prop) if not uf: continue pk = mapper.primary_key_from_instance(instance) log.info("Migrating %s for %r with pk %r", prop, klass, pk) filename = uf['filename'] content_type = uf['content_type'] data = _to_fieldstorage(fp=uf.file, filename=filename, mimetype=content_type, size=uf.file.content_length) setattr(instance, prop, data) DepotManager._default_depot = old_default
def default_get_root(request=None): return DBSession.query(Node).filter(Node.parent_id == None).one()
def delete_orphaned_tags(event): DBSession.query(Tag).filter(~Tag.content_tags.any()).delete( synchronize_session=False)
def upgrade(): from depot.manager import DepotManager from depot.fields.upload import UploadedFile from sqlalchemy import bindparam, Unicode, Column from kotti import DBSession, metadata files = sa.Table('files', metadata) files.c.data.type = sa.LargeBinary() # this restores to old column type dn = DepotManager.get_default() _saved = [] def process(thing): id, data, filename, mimetype = thing uploaded_file = UploadedFile({'depot_name': dn, 'files': []}) uploaded_file._thaw() uploaded_file.process_content( data, filename=filename, content_type=mimetype) _saved.append({'nodeid': id, 'data': uploaded_file.encode()}) log.info("Saved data for node id {}".format(id)) query = DBSession.query( files.c.id, files.c.data, files.c.filename, files.c.mimetype ).order_by(files.c.id).yield_per(10) window_size = 10 window_idx = 0 log.info("Starting migration of blob data") now = time.time() while True: start, stop = window_size * window_idx, window_size * (window_idx + 1) things = query.slice(start, stop).all() if things is None: break for thing in things: process(thing) if len(things) < window_size: break window_idx += 1 log.info("Files written on disk, saving information to DB") op.drop_column('files', 'data') op.add_column('files', Column('data', Unicode(4096))) files.c.data.type = Unicode(4096) update = files.update().where(files.c.id == bindparam('nodeid')).\ values({files.c.data: bindparam('data')}) def chunks(l, n): for i in range(0, len(l), n): yield l[i:i + n] for cdata in chunks(_saved, 10): DBSession.execute(update, cdata) log.info("Blob migration completed in {} seconds".format( int(time.time() - now)))
def content_with_tags(tag_terms): return DBSession.query(Content).join(TagsToContents).join(Tag).filter( or_(*[Tag.title.like(tag_term) for tag_term in tag_terms])).all()
def iterkeys(self): for (principal_name, ) in DBSession.query(self.factory.name): yield principal_name
def reset_content_owner(event): """Reset the owner of the content from the deleted owner.""" contents = DBSession.query(Content).filter( Content.owner == event.object.name).all() for content in contents: content.owner = None
def clear(self) -> None: DBSession.query(Node).filter(Node.parent == self).delete()