diff --git a/docs/changes.rst b/docs/changes.rst
index 0f228dfa..4ba050c3 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -4,6 +4,12 @@ Changelog
11.0.0 (unreleased)
-------------------
+- Add ``quaive-publish`` page with the text for publishing a survey to the client.
+ [maurits]
+
+- Add views to create or edit content from within Quaive.
+ [maurits]
+
- Add ``@navtree`` REST API endpoint.
[maurits]
diff --git a/src/osha/oira/configure.zcml b/src/osha/oira/configure.zcml
index 2af2dcbd..5b55a357 100644
--- a/src/osha/oira/configure.zcml
+++ b/src/osha/oira/configure.zcml
@@ -33,6 +33,7 @@
+
diff --git a/src/osha/oira/ploneintranet/__init__.py b/src/osha/oira/ploneintranet/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/osha/oira/ploneintranet/configure.zcml b/src/osha/oira/ploneintranet/configure.zcml
new file mode 100644
index 00000000..4a7f8615
--- /dev/null
+++ b/src/osha/oira/ploneintranet/configure.zcml
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/osha/oira/ploneintranet/interfaces.py b/src/osha/oira/ploneintranet/interfaces.py
new file mode 100644
index 00000000..1b1c481e
--- /dev/null
+++ b/src/osha/oira/ploneintranet/interfaces.py
@@ -0,0 +1,5 @@
+from zope.interface import Interface
+
+
+class IQuaiveForm(Interface):
+ """Marker interface for views that are designed to be embedded in Quaive"""
diff --git a/src/osha/oira/ploneintranet/quaive_create.py b/src/osha/oira/ploneintranet/quaive_create.py
new file mode 100644
index 00000000..1b296dbe
--- /dev/null
+++ b/src/osha/oira/ploneintranet/quaive_create.py
@@ -0,0 +1,128 @@
+from euphorie.content.browser.country import AddView as EuphorieCountryAddView
+from euphorie.content.browser.module import AddView as EuphorieModuleAddView
+from euphorie.content.browser.survey import AddView as EuphorieSurveyAddView
+from euphorie.content.browser.surveygroup import AddView as EuphorieSurveyGroupAddView
+from osha.oira.content.browser.risk import AddView as EuphorieRiskAddView
+from osha.oira.content.browser.sector import AddView as EuphorieSectorAddView
+from osha.oira.content.browser.solution import AddView as EuphorieSolutionAddView
+from osha.oira.ploneintranet.interfaces import IQuaiveForm
+from plone import api
+from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
+from zope.i18nmessageid import MessageFactory
+from zope.interface import alsoProvides
+from zope.interface import implementer
+
+
+from euphorie.content.browser.profilequestion import ( # isort:skip
+ AddView as EuphorieProfileQuestionAddView,
+)
+
+_ = MessageFactory("nuplone")
+
+
+@implementer(IQuaiveForm)
+class QuaiveCreateFormMixin:
+ template = ViewPageTemplateFile("templates/quaive-panel-form.pt")
+
+ def update(self):
+ super().update()
+ for group in getattr(self, "groups", []):
+ # This is needed to pick up the custom Quaive widgets
+ alsoProvides(group, IQuaiveForm)
+
+
+class QuaiveCreateViewMixin:
+ def __init__(self, context, request):
+ portal_type = self.__name__.rpartition("-")[-1]
+ fti = api.portal.get_tool("portal_types")[portal_type]
+ super().__init__(context, request, fti)
+
+
+class QuaiveCreateEuphorieSectorForm(QuaiveCreateFormMixin, EuphorieSectorAddView.form):
+ template = ViewPageTemplateFile("templates/quaive-form.pt")
+
+ def updateWidgets(self):
+ super().updateWidgets()
+ self.widgets["logo"].field.description = _(
+ "help_sector_logo",
+ default=(
+ "The logo will appear on the client side app "
+ "that your user group will see. "
+ "Make sure your image is of format png, jpg or gif "
+ "and does not contain any special characters. "
+ "The new logo will only become visible "
+ "after you've saved your changes and published the OiRA tool."
+ ),
+ )
+
+
+class QuaiveCreateEuphorieSectorView(QuaiveCreateViewMixin, EuphorieSectorAddView):
+ form = QuaiveCreateEuphorieSectorForm
+
+
+class QuaiveCreateEuphorieCountryForm(
+ QuaiveCreateFormMixin, EuphorieCountryAddView.form
+):
+ pass
+
+
+class QuaiveCreateEuphorieCountryView(QuaiveCreateViewMixin, EuphorieCountryAddView):
+ form = QuaiveCreateEuphorieCountryForm
+
+
+class QuaiveCreateEuphorieRiskForm(QuaiveCreateFormMixin, EuphorieRiskAddView.form):
+ template = ViewPageTemplateFile("templates/quaive-form.pt")
+
+
+class QuaiveCreateEuphorieRiskView(QuaiveCreateViewMixin, EuphorieRiskAddView):
+ form = QuaiveCreateEuphorieRiskForm
+
+
+class QuaiveCreateEuphorieSurveyGroupForm(
+ QuaiveCreateFormMixin, EuphorieSurveyGroupAddView.form
+):
+ pass
+
+
+class QuaiveCreateEuphorieSurveyGroupView(
+ QuaiveCreateViewMixin, EuphorieSurveyGroupAddView
+):
+ form = QuaiveCreateEuphorieSurveyGroupForm
+
+
+class QuaiveCreateEuphorieSurveyForm(QuaiveCreateFormMixin, EuphorieSurveyAddView.form):
+ template = ViewPageTemplateFile("templates/quaive-form.pt")
+
+
+class QuaiveCreateEuphorieSurveyView(QuaiveCreateViewMixin, EuphorieSurveyAddView):
+ form = QuaiveCreateEuphorieSurveyForm
+
+
+class QuaiveCreateEuphorieModuleForm(QuaiveCreateFormMixin, EuphorieModuleAddView.form):
+ template = ViewPageTemplateFile("templates/quaive-form.pt")
+
+
+class QuaiveCreateEuphorieModuleView(QuaiveCreateViewMixin, EuphorieModuleAddView):
+ form = QuaiveCreateEuphorieModuleForm
+
+
+class QuaiveCreateEuphorieProfileQuestionForm(
+ QuaiveCreateFormMixin, EuphorieProfileQuestionAddView.form
+):
+ template = ViewPageTemplateFile("templates/quaive-form.pt")
+
+
+class QuaiveCreateEuphorieProfileQuestionView(
+ QuaiveCreateViewMixin, EuphorieProfileQuestionAddView
+):
+ form = QuaiveCreateEuphorieProfileQuestionForm
+
+
+class QuaiveCreateEuphorieSolutionForm(
+ QuaiveCreateFormMixin, EuphorieSolutionAddView.form
+):
+ template = ViewPageTemplateFile("templates/quaive-form.pt")
+
+
+class QuaiveCreateEuphorieSolutionView(QuaiveCreateViewMixin, EuphorieSolutionAddView):
+ form = QuaiveCreateEuphorieSolutionForm
diff --git a/src/osha/oira/ploneintranet/quaive_edit.py b/src/osha/oira/ploneintranet/quaive_edit.py
new file mode 100644
index 00000000..563609af
--- /dev/null
+++ b/src/osha/oira/ploneintranet/quaive_edit.py
@@ -0,0 +1,41 @@
+from euphorie.content.browser.country import EditForm as CountryEditForm
+from euphorie.content.browser.module import EditForm as ModuleEditForm
+from euphorie.content.browser.profilequestion import EditForm as ProfileQuestionEditForm
+from osha.oira.content.browser.risk import EditForm as RiskEditForm
+from osha.oira.content.browser.sector import EditForm as SectorEditForm
+from osha.oira.content.browser.solution import EditForm as SolutionEditForm
+from osha.oira.content.browser.survey import EditForm as SurveyEditForm
+from osha.oira.ploneintranet.quaive_mixin import QuaiveEditFormMixin
+from plone.dexterity.browser.edit import DefaultEditForm
+
+
+class CountryQuaiveEditForm(QuaiveEditFormMixin, CountryEditForm):
+ """Custom edit form designed to be embedded in Quaive"""
+
+
+class ModuleQuaiveEditForm(QuaiveEditFormMixin, ModuleEditForm):
+ """Custom edit form designed to be embedded in Quaive"""
+
+
+class ProfileQuestionQuaiveEditForm(QuaiveEditFormMixin, ProfileQuestionEditForm):
+ """Custom edit form designed to be embedded in Quaive"""
+
+
+class RiskQuaiveEditForm(QuaiveEditFormMixin, RiskEditForm):
+ """Custom edit form designed to be embedded in Quaive"""
+
+
+class SectorQuaiveEditForm(QuaiveEditFormMixin, SectorEditForm):
+ """Custom edit form designed to be embedded in Quaive"""
+
+
+class SolutionQuaiveEditForm(QuaiveEditFormMixin, SolutionEditForm):
+ """Custom edit form designed to be embedded in Quaive"""
+
+
+class SurveyQuaiveEditForm(QuaiveEditFormMixin, SurveyEditForm):
+ """Custom edit form designed to be embedded in Quaive"""
+
+
+class SurveyGroupQuaiveEditForm(QuaiveEditFormMixin, DefaultEditForm):
+ """Custom edit form designed to be embedded in Quaive"""
diff --git a/src/osha/oira/ploneintranet/quaive_mixin.py b/src/osha/oira/ploneintranet/quaive_mixin.py
new file mode 100644
index 00000000..ebc148a5
--- /dev/null
+++ b/src/osha/oira/ploneintranet/quaive_mixin.py
@@ -0,0 +1,24 @@
+from osha.oira.ploneintranet.interfaces import IQuaiveForm
+from zope.interface import alsoProvides
+from zope.interface import implementer
+
+
+@implementer(IQuaiveForm)
+class QuaiveEditFormMixin:
+ @property
+ def template(self):
+ return self.index
+
+ def nextURL(self):
+ return f"{self.context.absolute_url()}/@@{self.__name__}"
+
+ @property
+ def is_edit_form(self):
+ """Is this the main edit form or is it some other form?"""
+ return self.__name__ == "quaive-edit"
+
+ def update(self):
+ super().update()
+ for group in getattr(self, "groups", []):
+ # This is needed to pick up the custom Quaive widgets
+ alsoProvides(group, IQuaiveForm)
diff --git a/src/osha/oira/ploneintranet/quaive_publish.py b/src/osha/oira/ploneintranet/quaive_publish.py
new file mode 100644
index 00000000..c5d6ca35
--- /dev/null
+++ b/src/osha/oira/ploneintranet/quaive_publish.py
@@ -0,0 +1,52 @@
+from euphorie.client.browser.publish import PublishSurvey
+from osha.oira.ploneintranet.quaive_mixin import QuaiveEditFormMixin
+
+
+class PublishSurveyQuaiveForm(QuaiveEditFormMixin, PublishSurvey):
+ """Page for publishing a survey, designed to be embedded in Quaive.
+
+ Note: this only displays some text, it does not actually do anything.
+ This text snippets are copied from 'euphorie.client.browser.templates.publish.pt'.
+ The logic for which text snippets to show, is defined in the PublishSurvey
+ view that we inherit from.
+
+ Now some background on what happens when publishing a survey, to make it a
+ bit easier to follow.
+
+ You have this path:
+
+ sectors/country/sector/surveygroup/survey
+
+ Here 'surveygroup' is of type euphorie.surveygroup, which in portal_types
+ has title 'OiRA Tool' and description 'A survey'.
+
+ 'survey' is of type euphorie.survey, which in portal_type has title
+ 'OiRA Tool version' and description 'A version of an OiRA Tool.'
+
+ So if you get confused, you are not the only one...
+
+ On the OiRA client side, you have this path:
+
+ client/country/sector/survey
+
+ So on the client side, survey groups do not exist.
+ When you publish a survey, its review_state is set to 'published'
+ and its contents are copied to client/country/sector/survey
+ where it overrides whatever is there.
+ So when you publish a new version of a tool, the old version is gone
+ from the client. So only one tool version can really be seen as
+ being published.
+
+ But: the review_state of the old version as it was within the sector's
+ folder, is not changed: it is still 'published'.
+
+ An event handler in src/euphorie/content/surveygroup.py sets the id of
+ the survey as 'published' on the survey group:
+
+ >>> app.Plone.sectors.eu['covid-19']['covid-19'].published
+ 'second-version-based-on-import'
+
+ I think this should change the review state of the previous survey to
+ 'draft' though. Or really of all sibling surveys (tool versions).
+ But that may be too drastic.
+ """
diff --git a/src/osha/oira/ploneintranet/templates/quaive-form.pt b/src/osha/oira/ploneintranet/templates/quaive-form.pt
new file mode 100644
index 00000000..039eeeba
--- /dev/null
+++ b/src/osha/oira/ploneintranet/templates/quaive-form.pt
@@ -0,0 +1,551 @@
+
+
+ ${view/label}
+
+
+
+
+
diff --git a/src/osha/oira/ploneintranet/templates/quaive-publish.pt b/src/osha/oira/ploneintranet/templates/quaive-publish.pt
new file mode 100644
index 00000000..7c71b34a
--- /dev/null
+++ b/src/osha/oira/ploneintranet/templates/quaive-publish.pt
@@ -0,0 +1,33 @@
+
+ This is copied from 'euphorie.client.browser.templates.publish.pt'.
+ It could be nice to have these texts shared.
+
+
+
Are you sure you want to publish this OiRA Tool? After publication
+ the OiRA Tool will appear in the online client and be accessible by all users.
+
+
Are you sure you want to republish this OiRA Tool? This will make
+ all changes made public.
+
Are you sure you want to publish this OiRA Tool version? This will
+ replace the current version.
+
The structure of your OiRA tool has changed.
+ If you publish now, existing users of this OiRA tool will lose parts of their answers.
+ Please contact the OiRA team if you need assistance on this subject.
+ You can also refer to the chapter “Re-working a published OiRA tool” of the OiRA manual.
+
+ We must generate the authenticator token on this side.
+
After publication the OiRA Tool will be available at
+ ${view/client_url}.
+
+
diff --git a/src/osha/oira/ploneintranet/z3cform/__init__.py b/src/osha/oira/ploneintranet/z3cform/__init__.py
new file mode 100644
index 00000000..e34dce71
--- /dev/null
+++ b/src/osha/oira/ploneintranet/z3cform/__init__.py
@@ -0,0 +1,9 @@
+_applied = False
+
+if not _applied:
+ from z3c.form.form import Form
+
+ # Zap the totally useless 'There were some errors' message.
+ Form.formErrorsMessage = None
+ del Form
+ _applied = True
diff --git a/src/osha/oira/ploneintranet/z3cform/configure.zcml b/src/osha/oira/ploneintranet/z3cform/configure.zcml
new file mode 100644
index 00000000..c8c4449b
--- /dev/null
+++ b/src/osha/oira/ploneintranet/z3cform/configure.zcml
@@ -0,0 +1,176 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/osha/oira/ploneintranet/z3cform/templates/checkbox_input.pt b/src/osha/oira/ploneintranet/z3cform/templates/checkbox_input.pt
new file mode 100644
index 00000000..61a3085b
--- /dev/null
+++ b/src/osha/oira/ploneintranet/z3cform/templates/checkbox_input.pt
@@ -0,0 +1,46 @@
+
+
+
+
+
diff --git a/src/osha/oira/ploneintranet/z3cform/templates/checkboxlist_input.pt b/src/osha/oira/ploneintranet/z3cform/templates/checkboxlist_input.pt
new file mode 100644
index 00000000..26bb13ae
--- /dev/null
+++ b/src/osha/oira/ploneintranet/z3cform/templates/checkboxlist_input.pt
@@ -0,0 +1,46 @@
+
+
+
+
diff --git a/src/osha/oira/ploneintranet/z3cform/templates/conditional_text_input.pt b/src/osha/oira/ploneintranet/z3cform/templates/conditional_text_input.pt
new file mode 100644
index 00000000..123bc720
--- /dev/null
+++ b/src/osha/oira/ploneintranet/z3cform/templates/conditional_text_input.pt
@@ -0,0 +1,43 @@
+
+
+ This is a conditional text input widget.
+
+ It is used to display a text input that is only visible when a certain condition is met.
+ The condition is defined in the schema of the form.
+
+ Never set the required attribute to true here.
+ Backend validation takes care of that.
+
+ If you set the required attributehere, the form will not submit if the input is not visible
+ and pat-validation is active.
+
+
+
diff --git a/src/osha/oira/ploneintranet/z3cform/templates/conditional_textarea_input.pt b/src/osha/oira/ploneintranet/z3cform/templates/conditional_textarea_input.pt
new file mode 100644
index 00000000..a793e99f
--- /dev/null
+++ b/src/osha/oira/ploneintranet/z3cform/templates/conditional_textarea_input.pt
@@ -0,0 +1,41 @@
+
+
+ This is a conditional text area widget.
+
+ It is used to display a textarea that is only visible when a certain condition is met.
+ The condition is defined in the schema of the form.
+
+ Never set the required attribute to true here.
+ Backend validation takes care of that.
+
+ If you set the required attributehere, the form will not submit if the textarea is not visible
+ and pat-validation is active.
+
+
+
+
diff --git a/src/osha/oira/ploneintranet/z3cform/templates/date_input.pt b/src/osha/oira/ploneintranet/z3cform/templates/date_input.pt
new file mode 100644
index 00000000..5a202ef2
--- /dev/null
+++ b/src/osha/oira/ploneintranet/z3cform/templates/date_input.pt
@@ -0,0 +1,22 @@
+
+
+
diff --git a/src/osha/oira/ploneintranet/z3cform/templates/datetime_input.pt b/src/osha/oira/ploneintranet/z3cform/templates/datetime_input.pt
new file mode 100644
index 00000000..c667161b
--- /dev/null
+++ b/src/osha/oira/ploneintranet/z3cform/templates/datetime_input.pt
@@ -0,0 +1,22 @@
+
+
+
diff --git a/src/osha/oira/ploneintranet/z3cform/templates/error.pt b/src/osha/oira/ploneintranet/z3cform/templates/error.pt
new file mode 100644
index 00000000..fb4ed5c2
--- /dev/null
+++ b/src/osha/oira/ploneintranet/z3cform/templates/error.pt
@@ -0,0 +1,8 @@
+
+ Error
+
diff --git a/src/osha/oira/ploneintranet/z3cform/templates/form.pt b/src/osha/oira/ploneintranet/z3cform/templates/form.pt
new file mode 100644
index 00000000..85e523dc
--- /dev/null
+++ b/src/osha/oira/ploneintranet/z3cform/templates/form.pt
@@ -0,0 +1,72 @@
+
+
+
+ ${view/label}
+
+