def get(self, url_prefix, key): node = Node.get_by_id(key) if not node: abort(404) _type = node.type templates = configuration['templates'] template = None for k, v in templates.iteritems(): if _type in v['page-types']: template = k break if template is None: raise Exception("No template found for _types: %s" % str(_types)) url = template + '/detail.html' if hasattr(g, 'user') and g.user is not None and (g.user and hasattr(g.user, 'id') and (hasattr(node, 'created_by') and g.user.id == node.created_by) or g.user.is_admin()): show_edit = True else: show_edit = False comments = list(Node.find({'type': 'Comment', 'belongs_to': str(node._id)})) print '*** All Comments', comments return render_template(url, node=node, allcomments=comments, url_prefix=url_prefix, show_edit=show_edit)
def get(self, url_prefix): global url_prefixes categories = {} prefix_data = url_prefixes.get(url_prefix, None) if prefix_data is None: raise Exception("Unknown problem with,%s" % url_prefix) _types = prefix_data['page-types'] query = {'type': {"$in": _types}} nodes = Node.find(query) count = Node.find_count(query) print nodes print count # Assert that all _types belong to same template structure templates = configuration['templates'] template = None for k, v in templates.iteritems(): if all(_t in (pg_type for pg_type in v['page-types']) for _t in _types): template = k break if template is None: raise Exception("No template found for _types: %s" % str(_types)) url = template + '/list.html' for p in nodes: for t in p.tags: categories.setdefault(t, []) categories[t].append(p) return render_template(url, categories=categories, url_prefix=url_prefix)
def index(): activities = Node.find({'type':'Activity'}, limit=6) destinations = Node.find({'type': "Destination"}, limit=6) organisers = Node.find({"type": "EventOrganiser"}, limit=6) dealers = Node.find({"type": "Retailer"}, limit=6) articles = Node.find({"type": {"$in": ["Blog", "FitrangiSpecial"]}}, limit=6) return render_template('index.html', activities=activities, destinations=destinations, dealers=dealers, articles=articles, organisers=organisers)
def init_user_node(user, username): node = Node() node.name = username + u'的知识库' node.type = 'libeary' node.owner = user node.is_publish = False db.session.add(node) db.session.commit()
def add_node(node_name): node = Node(name=node_name) node.save() lEdge = Edge(top=node, bot=node, dist=0) lEdge.save() return node.id
def test_move_rigth(self, app, example_hierarchy): item = example_hierarchy[0]['children'].pop(0) item['parent_id'] = 7 example_hierarchy[2]['children'].append(item) with app.app_context(): Node.get_by_id(3).move(Node.get_by_id(7)) hierarchy = Node.get_hierarchy() assert hierarchy == example_hierarchy
def test_move_subtree(self, app, example_hierarchy): subtree = example_hierarchy.pop(1) subtree['parent_id'] = 2 example_hierarchy[0]['children'].append(subtree) with app.app_context(): Node.get_by_id(5).move(Node.get_by_id(2)) hierarchy = Node.get_hierarchy() assert hierarchy == example_hierarchy
def subtree(root_item_id): # disallow direct access to the root node if root_item_id == Node.get_root_id(): abort(404) node = Node.get_by_id(root_item_id) if node is None: abort(404) return jsonify(node.get_subtree())
def create(self, validated_data): if 'parent' in validated_data: parent_id = validated_data.pop('parent')['pk'] else: parent_id = None instance = Node(**validated_data) if parent_id: instance.parent_id = parent_id instance.save() return instance
def post(self): user = User.logged_in_user() if user: payload = request.json or {} comment = payload.get('comment') post_key = payload.get('key') author = Node.get_by_id(user.id) post = Node.get_by_id(post_key) comment_node = Service.create_comment(author, comment, post) return {'status': 'success', 'node': comment_node.__dict__, 'message': 'Successfully posted the comment'} else: return {'status': 'error', 'message': 'Please login first.'}
def test_update_note(self): Node(criteria='the first').save() Node(criteria='the second').save() serializer = NodeSerializer(Node.objects.last(), data={'predicate': 'snd', 'criteria': 'second', 'parent': 1}) if not serializer.is_valid(): self.fail(serializer.errors) serializer.save() node = Node.objects.last() self.assertEqual(node.predicate, 'snd') self.assertEqual(node.criteria, 'second') self.assertEqual(node.parent_id, 1)
def test_update_name(self, client, app): with app.app_context(): node = Node.create(name='old name', parent_node=Node.get_root_node()) updated_item = client.post(f'/item/{node.id}', json={ 'name': 'new name' }).get_json() assert updated_item == client.get(f'/item/{node.id}').get_json() assert updated_item == { 'id': node.id, 'name': 'new name', 'parent_id': None }
def node_list(): """ Lists or creates nodes. Notes: Before creating we make sure there isn't already a node with the same name. We also check to see if a name key exists on the request to prevent breaking the app. Returns: (list | object): List of all nodes or a newly created node. """ # ------------------------------------------ # GET # ------------------------------------------ if request.method == 'GET': root_node = Node.query.filter_by(name='Root') return jsonify([node.serialize for node in root_node]), 200 # ------------------------------------------ # POST # ------------------------------------------ if request.method == 'POST': name = request.json.get('name') if name and isinstance(name, str) and len(name) >= 5: node = Node.query.filter_by(name=name).first() if node: return jsonify(f'Node with name {name} already exists'), 400 else: # Grab root node. root_node = Node.query.filter_by(name='Root').first() # Create new node & make relationship node = Node(name) node.parent = root_node # Add new node to session. db.session.add(node) db.session.commit() return jsonify(node.serialize), 201 else: return jsonify('Name must be minimum of 5 Alpha characters'), 400
def post(self): user = User.logged_in_user() try: if user: payload = request.json or {} post_key = payload.get('key') title = payload.get('title') text = payload.get('text') published = payload.get('published') image = payload.get('image') post = Node.get_by_id(post_key) post.title = title post.text = text post.published = published post.save() if image: try: if image: image = image[image.index(',') + 1:] with open(os.getcwd() + '/app' + post.images[0],"wb") as f: f.write(image.decode('base64')) except Exception, e: print str(e) return {'status': 'error', 'message': 'Update the data but image could not be saved'} return {'status': 'success', 'node': post.__dict__, 'message': 'Successfully updated the post'} else:
def node(nodeid): current_node = Node.query.filter_by(id=nodeid).first_or_404() form = NodeForm() form.name.label = Label(field_id="name", text="Connect two nodes!") if form.validate_on_submit(): node2 = Node.query.filter_by(id=form.name.data).first() if node2 in current_node.sources(): current_node.remove_source(node2) db.session.commit() flash('Removed existing node as source') elif Node.query.filter_by(id=form.name.data).count() == 1: current_node.add_source( Node.query.filter_by(id=form.name.data).first()) db.session.commit() flash('Added existing node as source') else: project = current_node.project node = Node(name=form.name.data, project=project, created_by=current_user) current_node.add_source(node) db.session.add(node) db.session.commit() flash('Added new node as source') return redirect(url_for('main.node', nodeid=current_node.id)) return render_template('node.html', node=current_node, form=form, title=current_node.name)
def validate(self): if not Form.validate(self): return False if self.name.data == self.original_name: return True if self.name.data != Node.make_valid_name(self.name.data): self.name.errors.append(gettext('This name has invalid characters. Please use letters, numbers, dots and underscores only.')) return False org = Organization.query.filter_by(name = self.org_name).first() if org == None: self.name.errors.append(gettext('The organization name was not found')) return False env = org.envs.filter_by(name = self.env_name).first() if env == None: self.name.errors.append(gettext('The environment name was not found')) return False grp = env.groups.filter_by(name = self.grp_name).first() if grp == None: self.name.errors.append(gettext('The group name was not found')) return False node = grp.nodes.filter_by(name = self.name.data).first() if node != None: self.name.errors.append(gettext('The node name already exists')) return False return True
def test_post_tree_with_root_node(self): Node(criteria='criteria').save() response = self.client.post('/trees/', {'title': 'slug 1', 'description': 'yolo', 'root_node': 1}) self.assertEqual(response.status_code, 201) tree = Tree.objects.last() self.assertEqual(tree.root_node.criteria, 'criteria')
def search_list(): q = request.args.get("q") if not q: return forbidden("invalid q") data = {"nodes": [], "content": []} try: # 整理相关节点 tmp = [] sources, total, scores = Source.search(q, 1, 100) if total > 0: for item in sources.all(): tmp.extend(item.nodes) nodes, total, scores = Node.search(q, 1, 100) if total > 0: tmp.extend(nodes.all()) if tmp: # 数据去重后,获得完整内容 data["nodes"] = [item.tiny_to_json() for item in list(set(tmp))] # 整理相关内容 tops, total, scores = Top.search(q, 1, 100) if total > 0: data['content'] = [item.search_to_json() for item in tops.all()] return jsonify({"success": True, "data": data}) except: return forbidden("检索失败")
def create_sub_nodes(pk): """ Creates sub nodes for a specific node. Args: pk (int): Value of node id. Returns: (str): Text stating the new nodes were created. """ # Make sure the node exists. try: parent = get_object(Node, pk) except ObjectDoesntExist as error: return jsonify(error.message), 404 else: count = request.json.get('count') # Make sure they sent amount to generate. if count and isinstance(count, int): # Delete previous sub nodes. Node.query.filter_by(parent=parent).delete() db.session.commit() if count < 1 or count > 15: msg = 'Number of children to generate should be between 1-15' return jsonify(msg), 400 # Create new nodes. for i in range(count): node_name = str(randint(parent.min_num, parent.max_num)) node = Node(name=node_name) node.can_have_children = False node.parent = parent db.session.add(node) db.session.commit() # Return new node tree. return jsonify('New nodes Created.'), 200 else: return jsonify('Must send amount of children to generate'), 400
def test_delete_nodes(self): n1 = Node(name="Test Node") n2 = Node(name="Test Sink") n3 = Node(name="Test Source") db.session.add_all([n1, n2, n3]) n1.add_sink(n2) n1.add_source(n3) db.session.commit() self.assertFalse(Edge.query.all() == []) self.assertFalse(Node.query.all() == []) n1.delete() db.session.commit() self.assertEqual(Node.query.all(), [n2, n3]) self.assertEqual(Edge.query.all(), [])
def item_by_id(item_id): # disallow direct access to the root node if item_id == Node.get_root_id(): abort(404) node = Node.get_by_id(item_id) if node is None: abort(404) if request.method == 'GET': return jsonify(node.to_item()) if request.method == 'DELETE': node.delete() return '', 204 if request.method == 'POST': data = request.get_json() node = Node.get_by_id(item_id) if node is None: return api_message(404, 'Item not found') if 'name' in data and data['name'] != node.name: try: node = node.rename(data['name']) except ValueError as e: return api_message(400, str(e)) if 'parent_id' in data: parent_id = data['parent_id'] if parent_id is None: parent_id = Node.get_root_id() if parent_id != node.parent_id: parent_node = Node.get_by_id(parent_id) if parent_node is None: return api_message(404, 'Parent item not found') try: node = node.move(parent_node) except ValueError as e: return api_message(400, str(e)) return jsonify(node.to_item())
def test_delete_project(self): p = Project(name="Test Project") n0 = Node(name="n0", project=p) n1 = Node(name="n1", project=p) n2 = Node(name="n2", project=p) n3 = Node(name="n3") db.session.add_all([p, n0, n1, n2, n3]) n1.add_sink(n0) n1.add_source(n2) db.session.commit() self.assertEqual(p.nodes.all(), [n0, n1, n2]) p.delete() db.session.commit() self.assertEqual(Node.query.all(), [n3]) self.assertEqual(Edge.query.all(), []) self.assertEqual(Project.query.all(), [])
def create_master_and_slaves(self): # master self.node = Node(title="Node 1") self.node.save(propagate=True) # slaves self.slave_1 = Node(title="Slave 1") self.slave_1.save(propagate=False) self.slave_2 = Node(title="Slave 2") self.slave_2.save(propagate=False) # This setup requires explicite creation of M2M objects # node.slaves.create & node.slaves.add doesn't work Propagation(master=self.node, slave=self.slave_1).save() Propagation(master=self.node, slave=self.slave_2).save() # reload these manually, tests are throwing things off self.node = Node.objects.get(pk=self.node.pk) self.slave_1 = Node.objects.get(pk=self.slave_1.pk) self.slave_2 = Node.objects.get(pk=self.slave_2.pk)
def create_node(): data = request.get_json(force=True) node = Node() node.parent = data['parent'] node.name = data['text'] node.type = data['type'] node.owner_id = g.user.id db.session.add(node) db.session.flush() if node.type == 'file': note = Block() note.node_id = node.id note.content = "" db.session.add(note) db.session.commit() return jsonify({ 'id': node.id, 'text': node.name, 'type': node.type })
def test_create_node(self): Node(criteria='the first').save() serializer = NodeSerializer(data={'predicate': 'pred', 'criteria': 'crit', 'parent': Node.objects.first().id}) if not serializer.is_valid(): self.fail(serializer.errors) serializer.save() node = Node.objects.last() self.assertEqual(node.predicate, 'pred') self.assertEqual(node.criteria, 'crit')
def post(self): if (request.json['id'] == '') | (request.json['text'] == ''): return Response(status=400) unique = True for n in Node.query.filter_by(parent=request.json['id']).all(): if n.text == request.json['text']: unique = False if unique & bool(re.fullmatch(r'(?:\w+\s?)+\S', request.json['text'])): u = Node(parent=request.json['id'], text=request.json['text']) db.session.add(u) db.session.commit() return Response(status=201)
def test_name_uniqueness_accept(self, app): with app.app_context(): Node.create('Unique', Node.get_root_node()) try: Node.create('Unique', Node.get_root_node()) except ValueError: pytest.fail()
def test_create_tree(self): Node(criteria='my node').save() serializer = TreeSerializer(data={'title': 'a title', 'description': 'description', 'root_node': 1}) if not serializer.is_valid(): self.fail(serializer.errors) serializer.save() tree = Tree.objects.first() self.assertEqual(tree.slug, 'a-title') self.assertEqual(tree.title, 'a title') self.assertEqual(tree.description, 'description')
def test_update_tree_with_node(self): Tree(slug='a-slug', title='a slug').save() Node(criteria='yolo').save() serializer = TreeSerializer(Tree.objects.first(), data={'root_node': Node.objects.first().id}, partial=True) if not serializer.is_valid(): self.fail(serializer.errors) serializer.save() tree = Tree.objects.first() self.assertEqual(tree.root_node.criteria, 'yolo')
def item(): data = request.get_json() if 'name' not in data: return api_message(400, '"name" required') if 'parent_id' not in data: return api_message(400, '"parent_id" required') parent_id = data['parent_id'] if parent_id is None: parent_id = Node.get_root_id() parent_node = Node.get_by_id(parent_id) if parent_node is None: return api_message(400, 'Invalid "parent_id"') try: node = Node.create(name=data['name'], parent_node=parent_node) except ValueError as e: return api_message(400, str(e)) return '', 201, {'Location': url_for('.item_by_id', item_id=node.id)}
def add_node(request): ctx = {} provider = request.POST.get('new_provider') parent_id = request.POST.get('parent_id') parent_provider = request.POST.get('parent_provider') relation = request.POST.get('relation') relation_back = request.POST.get('relation_back') if request.method == 'POST' and relation != '': if provider == 'text': node = Node(user=request.user, text=request.POST.get('text')) node.save() make_relation(request.user, parent_id, parent_provider, node.id, provider, relation, relation_back) elif provider == 'url': url_text = request.POST.get('url') import hashlib m = hashlib.md5() m.update(url_text.encode('utf-8')) url_hash = m.hexdigest() try: title, image = get_url_info(url_text, url_hash) url = Url(user=request.user, url=url_text, name=title, image=image) url.url_hash = url_hash url.save() except: url = Url.objects.get(url_hash=url_hash) make_relation(request.user, parent_id, parent_provider, url_hash, provider, relation, relation_back) elif provider == 'file': # todo - add files new_path = os.path.join(parent_id, request.POST.get('name')) if os.path.isdir(parent_id) and os.path.isdir(new_path): os.mkdir(new_path) make_relation(request.user, parent_id, parent_provider, new_path, provider, relation, relation_back) return HttpResponseRedirect(request.META['HTTP_REFERER'])
def test_keep_name_unique(self, app, example_hierarchy): with app.app_context(): node3 = Node.get_by_id(3) node7 = Node.get_by_id(7) Node.create(name='I am unique within my tree', parent_node=node3) Node.create(name='I am unique within my tree', parent_node=node7) with pytest.raises(ValueError): node3.move(node7)
def upsert_result(result): node = Node.query.filter_by(name=result.result_item.name).first() # create node structure if node is None: node = Node( name=result.result_item.name, timestamp=result.result_item.timestamp ) db.session.add(node) for (key, sub_result_items) in result.sub_result_items.items(): parent_node = Node( name="Season {}".format(key), timestamp=min(map(lambda n: n.timestamp, sub_result_items.values())), parent=node ) db.session.add(parent_node) for (_, sub_result_item) in sub_result_items.items(): child_node = Node( name=sub_result_item.name, timestamp=sub_result_item.timestamp, parent=parent_node ) db.session.add(child_node) # register term term = NodeTerm( name=result.search_terms, node=node ) db.session.add(term) # commit upserts db.session.commit() return term
def test_create_node(self, app): expected_root_node = Node(id=1, name='root', parent_id=None, lft=0, rgt=3) expected_new_node = Node(id=2, name='new node', parent_id=1, lft=1, rgt=2, tree_id=2) with app.app_context(): new_node = Node.create(expected_new_node.name, Node.get_by_id(expected_new_node.parent_id)) assert new_node == Node.get_by_id(expected_new_node.id) root_node = Node.get_by_id(expected_root_node.id) assert root_node == expected_root_node and new_node == expected_new_node
def index(): form = NodeForm() nodes = Node.query.order_by(Node.id.desc()).all() node = Node() columns = node.serialize_columns() nod = [] for c in nodes: nod.append(c.as_dict()) form.cluster.choices = [(b.id, b.name) for b in Cluster.query.order_by('name').all()] base_url = url_for('node.index') action_url = url_for('node.add') return render_template('node.html', title='Node', rows=nod, columns=columns, base_url=base_url, action_url=action_url, per_page=current_app.config['ROWS_PER_PAGE'], form=form)
def handle(self, *args, **options): edges = load(os.path.join(data_dir, 'data/edges')) nodes = load(os.path.join(data_dir, 'data/nodes')) for node in nodes: Node(**node).save() for e in edges: edge = Edge( **{k: v for k, v in e.items() if k != 'start' and k != 'end'}) start, end = Node.objects.filter( pk=e['start']), Node.objects.filter(pk=e['end']) edge.save() edge.start.set(start) edge.end.set(end)
def add(): form = NodeForm() form.cluster.choices = [(b.id, b.name) for b in Cluster.query.order_by('name').all()] if form.validate_on_submit(): node_active = form.active.data node_name = re.sub('[^A-Za-z0-9_]+', '', form.nodename.data) node_cluster_id = form.cluster.data node = Node(name=node_name, active=node_active, cluster_id=node_cluster_id) db.session.add(node) db.session.commit() return redirect(url_for('node.index'))
def delete_nodes(): resp = ResponseFormater() query_args = dict() if "name" in request.args: query_args["name__in"] = list_parser(request.args.get("name")) else: resp.failed(msg='name not defined') return resp.get_response() o_nodes = Node.objects(**query_args) if o_nodes.count() < 1: resp.failed(msg='%s not found' % (request.args.get('name'))) return resp.get_response() s_nodes = ','.join(o_nodes.scalar('name')) o_nodes.delete() resp.succeed(msg='%s have been deleted' % (s_nodes)) return resp.get_response()
def project(projectid): project = Project.query.filter_by(id=projectid).first_or_404() nodeform = NodeForm() if nodeform.submit.data and nodeform.validate_on_submit(): node = Node(name=nodeform.name.data, project=project, created_by=current_user) db.session.add(node) db.session.commit() flash('Added new task.') return redirect(url_for('main.project', projectid=project.id)) nodes = Node.query.filter_by(project=project).all() return render_template('project.html', project=project, nodeform=nodeform, nodes=nodes, title=project.name)
def post(self): user = User.logged_in_user() try: if user: payload = request.json or {} post_key = payload.get('key') name = payload.get('name') username= payload.get('username') email= payload.get('email') phone= payload.get('phone') address= payload.get('address') facebook= payload.get('facebook') linkedin = payload.get('linkedin') _type = payload.get('type') details = payload.get('details') image = payload.get('image') profile = Node.get_by_id(post_key) profile.name = name profile.username = username profile.email = email profile.phone = phone profile.address = address profile.facebook = facebook profile.linkedin = linkedin profile.type = _type profile.details = details profile.save() if image: try: if image: image = image[image.index(',') + 1:] with open(os.getcwd() + '/app' + post.images[0],"wb") as f: f.write(image.decode('base64')) except Exception, e: print str(e) return {'status': 'error', 'message': 'Update the data but image could not be saved'} return {'status': 'success', 'node': profile.__dict__, 'message': 'Successfully updated the post'} else:
def create_complex_decision_tree(): tree = Tree(slug='slug', title='title', description='description') tree.save() root_node = Node(criteria='mood') root_node.save() tree.root_node = root_node tree.save() happy = Node(predicate='happy', criteria='how happy', parent=root_node) happy.save() very_happy = Node(predicate='very happy', criteria='i am glad to hear that', parent=happy) very_happy.save() kind_of_happy = Node(predicate='kind of happy', criteria='wish you were happier', parent=happy) kind_of_happy.save() sad = Node(predicate='sad', criteria='i am sorry to hear that', parent=root_node) sad.save() melancholy = Node(predicate='just ok', criteria='ok then!', parent=root_node) melancholy.save()
def db_fixture(local): _file = open('fixture.log', 'w') data = load_all(local) admins = Node.find({"type": "Admin"}) created_nodes = 0 if len(admins) is 0: print "not found' creating'" created_nodes += 1 admin_data = { 'name':'arshad', 'email': '*****@*****.**', 'phone': '2342342432423', 'address': '', 'website': '', 'facebook': '', 'profile_image': None, 'linkedin': '', 'username': '******', 'password': '******', 'is_verified': True, 'type': 'Admin', 'created_on': datetime.datetime.now(), 'followers': [], 'following': [], 'tags': ["enthusiast"] } admin = Node(admin_data) admin.save() else: admin = admins[0] print 'Admin ', admin.name aliases = generate_alias_wise_data() page_types = get_page_types() comparable_page_types = dict([(v.lower(), v) for v in page_types]) for d in data: title = d['title'] _type = aliases[d['type']] images = [] if d.get('image', None): image_path = d['image'] name = unicode(str(image_path.split('/')[-1])).encode('utf-8') _name = hashlib.md5(name).hexdigest() new_name = os.getcwd() + '/app/assets/files/media/images/%s' % _name images.append('/assets/files/media/images/%s' % _name) if not local or not os.path.exists(new_name): shutil.copy(image_path, new_name) _file.write("%s\n%s\n%s\nBREAK\n" % (d['image'], _name, new_name)) if _type in ['EventOrganiser', 'Enthusiast', 'Retailer']: node_data = { 'name':title , 'email': '', 'phone': '', 'address': '', 'website': '', 'facebook': '', 'profile_image': images[0] if len(images) > 0 else None, 'linkedin': '', 'username': title.lower().replace(' ', '-'), 'password': '******', 'is_verified': True, 'type': _type, 'created_on': datetime.datetime.now(), 'followers': [], 'following': [], 'tags': ["Enthusiast", _type] } query = {'name': title} else: tags = [_type] if d.get('category', None) is not None: category = d['category'] if len(category) > 0 and comparable_page_types.has_key(category.lower()): tags.append(comparable_page_types[category.lower()]) if d.get('activity', None) is not None: activity = d['activity'] if len(activity) > 0 and comparable_page_types.has_key(activity.lower()): tags.append(comparable_page_types[activity.lower()]) node_data = { 'images': images, 'videos':[], 'created_by': admin, 'title': title, 'text': d['data'] if len(d.get('data', '')) > 0 else '', 'published_on': datetime.datetime.now(), 'is_published': True, 'type': _type, 'tags': tags, 'page_access': 'public', 'related': [] } query = {'title': title} if Node.find_count(query) > 0: node = Node.find(query)[0] node.update(node_data) else: node = Node(node_data) node.save() created_nodes += 1 print "Created Nodes: ", created_nodes _file.close()
def edit_profile(key): if not hasattr(g, 'user') or g.user is None: return redirect(url_for('index')) node = Node.get_by_id(key) back = request.referrer return render_template('user/editor.html', profile=node, back=back)
class AppTestCase(TestCase): def setUp(self): pass def tearDown(self): # Dump the data that's in the node1 database print "Summary of what's available in database 2" print "=" * 50 for node in Node.objects.all().using("node1"): print "Record:", node, "Fields:", node._as_dict() def create_master_and_slaves(self): # master self.node = Node(title="Node 1") self.node.save(propagate=True) # slaves self.slave_1 = Node(title="Slave 1") self.slave_1.save(propagate=False) self.slave_2 = Node(title="Slave 2") self.slave_2.save(propagate=False) # This setup requires explicite creation of M2M objects # node.slaves.create & node.slaves.add doesn't work Propagation(master=self.node, slave=self.slave_1).save() Propagation(master=self.node, slave=self.slave_2).save() # reload these manually, tests are throwing things off self.node = Node.objects.get(pk=self.node.pk) self.slave_1 = Node.objects.get(pk=self.slave_1.pk) self.slave_2 = Node.objects.get(pk=self.slave_2.pk) def test_dirtyfields(self): """Make sure the dirty fields actually work""" self.create_master_and_slaves() self.node.active = False self.assertTrue(self.node.is_dirty()) # check the dirty fields, returning the original state as in the DB self.assertEquals(self.node.get_dirty_fields(), {'active': True}) def test_propagation_tracking(self): """Check the propagation of changes from master to slaves""" self.create_master_and_slaves() self.assertEquals(Propagation.changes.to_push().count(), 0) self.node.title="Changed title" self.node.save(propagate=True) # the slave versions are behind and should be pushed self.assertEquals(Propagation.changes.to_push().count(), 2) def test_no_propagation_when_nothings_changed(self): """Nothing should be changed if no fields have changed""" self.create_master_and_slaves() self.assertFalse(self.node.is_dirty()) self.node.save(propagate=True) self.assertEquals(Propagation.changes.to_push().count(), 0) def test_changes_being_propagated(self): """Using the History we should be able to see what's changed""" self.create_master_and_slaves() self.node.title="Changed Title" self.node.save(propagate=True)