Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hardens editable_future_graph against nodegroup changes #11570 #11609

Open
wants to merge 25 commits into
base: dev/8.0.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions arches/app/media/js/viewmodels/graph-settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ define([

self.resource_data = ko.observableArray([]);
self.relatable_resources = ko.computed(function() {
return _.each(self.resource_data(), function(resource) {
chrabyrd marked this conversation as resolved.
Show resolved Hide resolved
resource.isRelatable = ko.observable(resource.is_relatable);
}).filter(resource => !resource.graph.source_identifier_id);
return _.each(
self.resource_data().sort((a, b) => a.graph.name.localeCompare(b.graph.name)),
function(resource) {
resource.isRelatable = ko.observable(resource.is_relatable);
}
).filter(resource => !resource.graph.source_identifier_id);
});

self.designerViewModel = params.designerViewModel;
Expand Down
3 changes: 0 additions & 3 deletions arches/app/models/card.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,6 @@ def save(self):
edge.ontologyproperty = self.ontologyproperty
edge.save()

self.nodegroup.cardinality = self.cardinality
self.nodegroup.save()

super(Card, self).save()
for widget in self.widgets:
widget.save()
Expand Down
665 changes: 217 additions & 448 deletions arches/app/models/graph.py

Large diffs are not rendered by default.

38 changes: 38 additions & 0 deletions arches/app/models/migrations/11570_harden_editble_future_graphs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Generated by Django 5.1.2 on 2024-11-13 18:17
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filename: edtible -> editable


import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("models", "10437_node_alias_not_null"),
]

operations = [
migrations.AlterField(
model_name="resource2resourceconstraint",
name="resourceclassfrom",
field=models.ForeignKey(
blank=True,
db_column="resourceclassfrom",
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="resxres_contstraint_classes_from",
to="models.node",
),
),
migrations.AlterField(
model_name="resource2resourceconstraint",
name="resourceclassto",
field=models.ForeignKey(
blank=True,
db_column="resourceclassto",
null=True,
on_delete=django.db.models.deletion.CASCADE,
related_name="resxres_contstraint_classes_to",
to="models.node",
),
),
]
84 changes: 55 additions & 29 deletions arches/app/models/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -855,37 +855,63 @@ def is_collector(self):
)

def get_relatable_resources(self):
return [
(
constraint.resourceclassto
if constraint.resourceclassfrom_id == self.pk
else constraint.resourceclassfrom
)
for constraint in (
self.resxres_contstraint_classes_from.filter(
resourceclassto__isnull=False
query_id = (
self.source_identifier_id if self.source_identifier_id else self.nodeid
)

constraints = Resource2ResourceConstraint.objects.filter(
Q(resourceclassto_id=query_id) | Q(resourceclassfrom_id=query_id)
).select_related("resourceclassfrom", "resourceclassto")

filtered_constraints = set()
for r2r in constraints:
if r2r.resourceclassto_id == query_id and r2r.resourceclassfrom is not None:
filtered_constraints.add(r2r.resourceclassfrom)
elif (
r2r.resourceclassfrom_id == query_id and r2r.resourceclassto is not None
):
filtered_constraints.add(r2r.resourceclassto)

return list(filtered_constraints)

def set_relatable_resources(self, new_ids):
new_ids = set(new_ids)

old_ids = set()
for res in self.get_relatable_resources():
if res.source_identifier_id is not None:
old_ids.add(res.source_identifier_id)
if res.nodeid is not None:
old_ids.add(res.nodeid)

self_ids = set(
id for id in (self.source_identifier_id, self.nodeid) if id is not None
)
jacobtylerwalls marked this conversation as resolved.
Show resolved Hide resolved

ids_to_delete = old_ids - new_ids
ids_to_create = new_ids - old_ids

if ids_to_delete and self_ids:
Resource2ResourceConstraint.objects.filter(
(
Q(resourceclassto_id__in=self_ids)
& Q(resourceclassfrom_id__in=ids_to_delete)
)
| self.resxres_contstraint_classes_to.filter(
resourceclassfrom__isnull=False
| (
Q(resourceclassto_id__in=ids_to_delete)
& Q(resourceclassfrom_id__in=self_ids)
)
)
]
).delete()

def set_relatable_resources(self, new_ids):
old_ids = [res.nodeid for res in self.get_relatable_resources()]
for old_id in old_ids:
if old_id not in new_ids:
Resource2ResourceConstraint.objects.filter(
Q(resourceclassto_id=self.nodeid)
| Q(resourceclassfrom_id=self.nodeid),
Q(resourceclassto_id=old_id) | Q(resourceclassfrom_id=old_id),
).delete()
for new_id in new_ids:
if new_id not in old_ids:
new_r2r = Resource2ResourceConstraint.objects.create(
resourceclassfrom_id=self.nodeid, resourceclassto_id=new_id
if ids_to_create:
new_constraints = [
Resource2ResourceConstraint(
resourceclassfrom_id=self.source_identifier_id or self.nodeid,
resourceclassto_id=id_to_create,
)
new_r2r.save()
for id_to_create in ids_to_create
]
Resource2ResourceConstraint.objects.bulk_create(new_constraints)
chrabyrd marked this conversation as resolved.
Show resolved Hide resolved

def serialize(self, fields=None, exclude=None, **kwargs):
ret = JSONSerializer().handle_model(
Expand Down Expand Up @@ -1110,15 +1136,15 @@ class Resource2ResourceConstraint(models.Model):
blank=True,
null=True,
related_name="resxres_contstraint_classes_from",
on_delete=models.SET_NULL,
on_delete=models.CASCADE,
)
resourceclassto = models.ForeignKey(
Node,
db_column="resourceclassto",
blank=True,
null=True,
related_name="resxres_contstraint_classes_to",
on_delete=models.SET_NULL,
on_delete=models.CASCADE,
)

def __init__(self, *args, **kwargs):
Expand Down
10 changes: 4 additions & 6 deletions arches/app/views/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,12 +685,13 @@ def post(self, request, graphid):
try:
data = JSONDeserializer().deserialize(request.body)

source_graph.update_from_editable_future_graph()
source_graph.publish(notes=data.get("notes"), user=request.user)
updated_graph = source_graph.update_from_editable_future_graph(
editable_future_graph=editable_future_graph
)
updated_graph.publish(notes=data.get("notes"), user=request.user)

return JSONResponse(
{
"graph": editable_future_graph,
"title": _("Success!"),
"message": _(
"The graph has been updated. Please click the OK button to reload the page."
Expand All @@ -709,7 +710,6 @@ def post(self, request, graphid):
source_graph.revert()
return JSONResponse(
{
"graph": editable_future_graph,
"title": _("Success!"),
"message": _(
"The graph has been reverted. Please click the OK button to reload the page."
Expand All @@ -734,7 +734,6 @@ def post(self, request, graphid):

return JSONResponse(
{
"graph": source_graph,
"title": _("Success!"),
"message": _(
"The published graphs have been successfully updated."
Expand All @@ -756,7 +755,6 @@ def post(self, request, graphid):

return JSONResponse(
{
"graph": source_graph,
"title": _("Success!"),
"message": _("The graph has been successfully restored."),
}
Expand Down
Loading
Loading