Skip to content

Dsetool: Choices#837

Open
reinhardt wants to merge 25 commits intomainfrom
dsetool-choices
Open

Dsetool: Choices#837
reinhardt wants to merge 25 commits intomainfrom
dsetool-choices

Conversation

@reinhardt
Copy link
Contributor

@reinhardt reinhardt marked this pull request as ready for review May 7, 2025 07:45
@reinhardt reinhardt requested a review from ale-rt May 7, 2025 10:04
model.Choice.id == model.SurveyTreeItem.id,
sql.or_(
model.Choice.condition == None, # noqa: E711
model.Choice.condition.like(model.Option.zodb_path),
Copy link
Member

Choose a reason for hiding this comment

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

This is unclear to me...
You are using like, but AFAIK like requires a pattern to match.
Is model.Choice.condition.like(model.Option.zodb_path) containing an %?
If not, it seems to me that this is equivalent to:

model.Choice.condition == model.Option.zodb_path

If yes, it would be unexpected for me.

Copy link
Member

@ale-rt ale-rt left a comment

Choose a reason for hiding this comment

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

I did a first round of review on the code.
Disclaimer:

  • I do not understand much what is going
  • I never see the feature live
  • I just have a vague idea about what this feature should be

Comment on lines +11 to +12
def my_context(self):
return aq_inner(self.context)
Copy link
Member

Choose a reason for hiding this comment

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

I know this is copied from existing code, but I think this is redundant.

"url": option.absolute_url(),
"title": option.title,
}
for option in self.my_context.values()
Copy link
Member

Choose a reason for hiding this comment

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

What benefit is giving us to decrease the amount of information we have by converting a full object into a dict?
It seems to me that returning the option instances instead of the dicts would be better.
The advantages would be that you have more information and less code and indirection.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Consistency, I guess. It's done the same way with the solutions in the risk view.

<object meta_type="Conditional Dexterity FTI"
name="euphorie.choice"
/>
<object meta_type="Conditional Dexterity FTI"
Copy link
Member

Choose a reason for hiding this comment

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

Does this need to be a Conditional Dexterity FTI?
Or is an only addable in choices?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I guess it could also be a regular FTI. Currently there is no restriction.

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<object xmlns:i18n="http://xml.zope.org/namespaces/i18n"
meta_type="Dexterity FTI"
Copy link
Member

Choose a reason for hiding this comment

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

Should the meta_type be adapted as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

)
type = schema.Column(
Enum(["risk", "module"]),
Enum(["risk", "choice", "module"]),
Copy link
Member

Choose a reason for hiding this comment

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

I think that modifying an Enum requires an alembic upgrade, but I might be wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I used autogenerate to create the alembic upgrade and it didn't contain anything about the Enum. Also, it works fine as it is.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe you initialized the DB after the change in Python code was done?
Might I ask you to double check this?

This might help:

If after that's not the case and an upgrade is not needed, you can resolve this conversation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I haven't initialized this DB in years.

The type column is just a varchar, there's nothing to upgrade there.

 type            | character varying(6)   |           | not null |

@reinhardt reinhardt requested a review from ale-rt May 8, 2025 09:32
@reinhardt
Copy link
Contributor Author

Sorry, found another issue. Small fix incoming ...

@reinhardt
Copy link
Contributor Author

OK, ready for another round of review.

Comment on lines +27 to +28
if self.webhelpers.redirectOnSurveyUpdate():
return
Copy link
Member

Choose a reason for hiding this comment

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

I do not understand this if clause.
It seems to me the code is equivalent to:

Suggested change
if self.webhelpers.redirectOnSurveyUpdate():
return
self.webhelpers.redirectOnSurveyUpdate():

To me

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copied from

if self.webhelpers.redirectOnSurveyUpdate():

My guess is that it's to make sure that any code that might be added after this line is not executed if the redirect kicks in.

Comment on lines +41 to +44
_next = reply.get("next", None)
# In Safari browser we get a list
if isinstance(_next, list):
_next = _next.pop()
Copy link
Member

Choose a reason for hiding this comment

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

I like more what you did on the other view, where you have a dedicated _get_next method.
Any reason to not do the same here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The goal right now is only to move this from browser/risk.py so that we can use it for choices, too. Refactoring can be done later.

Comment on lines +22 to +26
return self.request.response.redirect(
"{session_url}/@@start".format(
session_url=self.webhelpers.traversed_session.absolute_url()
)
)
Copy link
Member

Choose a reason for hiding this comment

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

To make the code more readable I would add a def redirect method that would make this possible:

Suggested change
return self.request.response.redirect(
"{session_url}/@@start".format(
session_url=self.webhelpers.traversed_session.absolute_url()
)
)
return self.redirect("@@start")

or something similar, IDK.... self.webhelpers.redirect_to_session_path or whatever.
That can be useful also for the other view.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, but let's refactor later and also include browser/risk.py to keep things halfways consistent.

.first()
)
if not sql_module:
url = self.context.absolute_url() + "/@@identification"
Copy link
Member

Choose a reason for hiding this comment

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

I am big fan of fstring:

Suggested change
url = self.context.absolute_url() + "/@@identification"
url = f"{self.context.absolute_url()}/@@identification"

They should be even faster, but what you did has nothing wrong.

def is_visible(self):
if not self.condition:
return True
options = self.condition.split("|")
Copy link
Member

Choose a reason for hiding this comment

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

Apparently it is visible only if we have some paths.
What about calling this column allowed_paths?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't understand. Which column? Why rename it?

Copy link
Member

Choose a reason for hiding this comment

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

I don't understand. Which column? Why rename it?

The column condition. It seems that allowed_paths is a better name that will help us understand what's going on

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, sorry, that doesn't fit at all. It's a condition. If any of the options that correspond to the paths is picked, then the choice is visible.

return False
return True

def set_options_by_zodb_path(self, paths):
Copy link
Member

Choose a reason for hiding this comment

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

Skimming the code it seems to me that using sets might make the code more readable. Please have a thought about that

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I had a hard to getting this to run without errors, I'm reluctant to touch it again.

Copy link
Member

Choose a reason for hiding this comment

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

I see your point, would the code simplify if instead of having a relation to an Option we would just store the options as a | concatenated string?
Then the option table could just go away.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Then we can't do joins properly.

Copy link
Member

Choose a reason for hiding this comment

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

Are you making any joins in this PR.
AFAICS the code sort of enforces a 1 to 1 relationship between choices and options.
I might get the code wrong by just reading it.
Let's discuss this in a call.

reinhardt and others added 2 commits May 12, 2025 13:54
Co-authored-by: Alessandro Pisa <alessandro.pisa@gmail.com>
Co-authored-by: Alessandro Pisa <alessandro.pisa@gmail.com>
@reinhardt reinhardt requested a review from ale-rt May 12, 2025 12:03
<value_type type="plone.registry.field.TextLine" />
<default>{
"tiles": "\nnavtree [context.portal_type in ['euphorie.profilequestion', 'euphorie.module', 'euphorie.risk', 'euphorie.solution', 'euphorie.survey', 'euphorie.surveygroup', 'euphorie.folder', 'euphorie.documentation', 'euphorie.help', 'euphorie.page', 'euphorie.training_question', 'euphorie.choice', 'euphorie.option'] ]\neuphorie.usermgmt.navtree [context.portal_type=='euphorie.country' and request.getURL().endswith('@@manage-users')]",
"type": "group"
Copy link
Member

Choose a reason for hiding this comment

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

Generally speaking, I would not rewrite the record but modify it.
You decrease the risk that something modified by hand gets rewritten

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not possible to modify this by hand. Try it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants