diff --git a/docs/backend/generic-setup.md b/docs/backend/generic-setup.md new file mode 100644 index 0000000000..6c4496b742 --- /dev/null +++ b/docs/backend/generic-setup.md @@ -0,0 +1,1596 @@ +--- +myst: + html_meta: + "description": "How does GenericSetup work" + "property=og:description": "How does GenericSetup work" + "property=og:title": "GenericSetup" + "keywords": "Plone 6, backend, GenericSetup" +--- + +(genericsetup-label)= + +# GenericSetup + +This chapter describes how to use GenericSetup to modify the Plone site during add-on package installation and uninstallation. + + +## Usage overview + +GenericSetup is mainly used to prepare the Plone site for add-on packages, by: + +- registering Registry entries, such as resources and configuration +- setting various properties +- registering portlets +- registering `portal_catalog` search query indexes +- providing upgrade steps for add-on version upgrades +- enable specific behaviors +- and other preparations + +GenericSetup provides XML-based rules to change the site settings. +GenericSetup XML files are usually in a {file}`profiles/default` folder inside the add-on package. + +All run-time through-the-web ({term}`TTW`) configurable items—for example, viewlet order through the `/@@manage-viewlets` page—are made repeatable using GenericSetup profile files. + +You can always change the configuration options through either Plone or the {term}`Zope Management Interface` (ZMI), and then export the resulting profile as an XML file. +To export, navigate to {menuselection}`Site Setup --> Management Interface`, then click {guilabel}`portal_setup`, and finally click the {guilabel}`Export` tab to select the steps to export. + +Directly editing XML profile files does not change anything on the site, even after a Zope restart. +This is because run-time TTW configurable items are stored in the database, instead of the file system. + +If you edit profile files, you need to either reimport the edited files using the `portal_setup` tool or fully rerun the add-on package installer by navigating to {menuselection}`Site Setup --> Add-ons`. +The import or rerun will read XML files and change the Plone database accordingly. + +```{note} +ZCML changes affect loaded Python code in all sites inside Zope, whereas GenericSetup XML files affect only one Plone site and its database. +GenericSetup XML files are always database changes. + +Creating relationships between ZCML and site-specific behavior is usually done using {doc}`layers `. +ZCML directives, like viewlets and views, are registered to be active only on a certain layer using the `layer` attribute. +When GenericSetup XML is imported through `portal_setup`, or the add-on package installer is run for a Plone site, the layer is activated for the particular site only, enabling all views registered for this layer. +``` + +```{note} +The {file}`metadata.xml` file, which contains add-on dependency and version information, is read during Plone start up. +If this file has problems, your add-on might not appear in the add-on installer control panel. +``` + +```{seealso} +- [GenericSetup package page](https://pypi.python.org/pypi/Products.GenericSetup) +- [GenericSetup source code](https://github.com/zopefoundation/Products.GenericSetup) +``` + + +## Create a profile + +Use the `` directive in your add-on package's {file}`configure.zcml`. +The name for the default profile executed by the Plone add-on installer is `default`. + +If you need different profiles, for example, for unit testing, you can declare them here. + +XML files for the `default` profile go in the {file}`profiles/default` folder inside your add-on package. + +```xml + + + + + +``` + +### Multiple profiles + +When you have more than one profile in your add-on package, the add-ons control panel decides which one to use when you install it. + +When there is a `default` profile, it's used as the installation profile, except when this `default` profile is marked in an `INonInstallable` utility. +In this case, it's ignored, and Plone falls back to using the first profile sorted alphabetically by `name`. + +```{versionchanged} Plone 5.1 +The profile `name` of `default` now takes precedence over the `name` of the first profile sorted alphabetically. +In previous versions, the first profile sorted alphabetically by `name` was chosen without regard to the `default` name. +``` + + +## Add-on properties + +Add-on packages may contain any of the following items. + +- A default GenericSetup XML profile, which is automatically run when the package is installed using the quick-installer. + The profile name is usually `default`. +- Other profiles, which the user may install using the ZMI {guilabel}`portal_setup` under the {guilabel}`Import` tab, or which can be manually enabled for unit tests. +- A `pre_handler` or `post_handler` when you use GenericSetup 1.8.2 or later. + See {ref}`genericsetup-custom-installer-code-label`. +- Custom import steps to process additional XML files. + See {ref}`genericsetup-custom-import-steps`. + + +## List available profiles + +List all known profiles for the Plone instance. + +```python +from plone import api +setup_tool = api.portal.get_tool("portal_setup") + +profiles = setup_tool.listProfileInfo() +for profile in profiles: + print(str(profile)) +``` + +Sample results: + +```python +{'product': 'PluggableAuthService', + 'description': 'Content for an empty PAS (plugins registry only).', + 'for': , + 'title': 'Empty PAS Content Profile', + 'version': 'PluggableAuthService-1.5.3', + 'path': 'profiles/empty', + 'type': 1, + 'id': 'PluggableAuthService:empty'} +{'product': 'Products.CMFPlone', + 'description': u'Profile for a default Plone.', + 'for': , + 'title': u'Plone Site', + 'version': u'3.1.7', + 'path': u'/home/moo/sits/parts/plone/CMFPlone/profiles/default', + 'type': 1, + 'id': u'Products.CMFPlone:plone'} +... +``` + + +## Install a profile + +This section describes how to install a profile and enable add-ons for unit tests. + + +### `plone.app.testing` + +See [Product and profile installation](https://github.com/plone/plone.app.testing#product-and-profile-installation). + + +### Manual installation + +You might want to install profiles manually if they need to be enabled only for certain tests. + +The profile name is in the format `profile-${package_name}:${profile id}`. + +For example, this runs the `extended` profile of the `your.addonpackage` package. + +```python +from plone import api +setup_tool.runAllImportStepsFromProfile('your.addonpackage:extended') +``` + +```{versionchanged} Products.GenericSetup 1.8.0 +Since `Products.GenericSetup` 1.8.0, the `profile-` prefix is optional. +In previous versions, the prefix was required, for example, `profile-your.addonpackage:extended`. +GenericSetup supports both forms. +``` + + +## Missing upgrade procedure + +In the {guilabel}`Add-ons` control panel, you may see a warning that your add-on package is [missing an upgrade procedure](https://stackoverflow.com/questions/15316583/how-to-define-a-procedure-to-upgrade-an-add-on). + +This means you need to write some {ref}`genericsetup-upgrade-steps-label`. + + +(genericsetup-uninstall-profile-label)= + +## Uninstall profile + +When you uninstall an add-on in the control panel, Plone looks for a profile with the name `uninstall` and applies it. + +```{note} +If there is no `uninstall` profile, a warning is displayed before installing the add-on. +If you do install the add-on, no uninstall button will be shown. +``` + + +## Dependencies + +A GenericSetup profile can contain dependencies to other add-on package installers and profiles. + +For example, if you want to declare a dependency to the `your.addonpackage` package that it is automatically installed when your add-on is installed, then use the declaration below. +This way you can be sure that all layers, portlets, and other features which require database changes are usable from `your.addonpackage` when it is run. + +Edit {file}`metadata.xml`. + +```xml + + + 1000 + + profile-your.addonpackage:default + + +``` + +`your.addonpackage` declares the profile in its {file}`configure.zcml`. + +```xml + +``` + +```{warning} +Unlike other GenericSetup XML files, {file}`metadata.xml` is read on startup and cached. +Always restart Plone after editing {file}`metadata.xml`. + +If your {file}`metadata.xml` file contains syntax errors or dependencies to a missing or non-existent package, then your add-on will disappear from the installation control panel. +``` + +```{note} +For some old add-ons in the `Products.*` Python namespace, you must not include the full package name in the dependencies. + +This is true when this add-on has registered its profile in Python instead of ZCML, and it has used only part of its package name. + +In most cases you *do* need to use the full `Products.xxx` name. +``` + +The following code example shows how to declare a dependency on the `simple` profile of `Products.PluggableAuthService`. + +```xml + + + 1000 + + + profile-PluggableAuthService:simple + + +``` + + +## Metadata version numbers + +The metadata `version` number in your {file}`metadata.xml` indicates the version of your add-on package. +It's used to determine whether the add-on package needs to be upgraded. + +Upgrade steps are executed in the Python version sort order, according to [Version specifiers](https://packaging.python.org/en/latest/specifications/version-specifiers/). + +```{note} +Legacy add-on packages might not have a version number. +In old versions of GenericSetup, sorting was done alphabetically, not according to the Python version specifiers. +If you experience problems with upgrade steps, you might need to upgrade GenericSetup, or add a metadata `version` number to align with your package's version number. +``` + +```{seealso} +{ref}`genericsetup-upgrade-steps-label` +``` + + +(genericsetup-custom-installer-code-label)= + +## Custom installer code + +GenericSetup provides a way to run custom Python code before or after your add-on package is installed. +The following examples show how to do this. + +First, edit {file}`configure.zcml`, adding a `pre_handler` and `post_handler` attribute to the `registerProfile` element. + +```{code-block} xml +:linenos: +:emphasize-lines: 11-13 + + + + + + +``` + +Then edit {file}`setuphandlers.py`, adding the Python functions `run_before` and `run_after` according to the `pre_handler` and `post_handler` attributes. + +```python +def run_before(context): + # This is run before running the first import step of + # the default profile. The context is portal_setup. + # Add custom code here... + +def run_after(context): + # This is run after running the last import step of + # the default profile. The context is portal_setup. + # ... +``` + +(genericsetup-custom-import-steps)= + +## Custom import steps + +You can register a custom import step. +This is a Python function which will be run for _every_ GenericSetup profile. +It provides a way to extend the possible changes that can be made when a profile is installed. + +```{tip} +If you only want to run custom code when one add-on is installed, use {ref}`genericsetup-custom-installer-code-label` instead. +``` + +By convention, custom import steps are usually placed in a {file}`setuphandlers.py` file. + +```python + +def run_custom_code(site): + """Run custom add-on package installation code to modify Plone + site object and others + + @param site: Plone site + """ + +def setup_various(context): + """ + @param context: Products.GenericSetup.context.DirectoryImportContext instance + """ + portal = context.getSite() + + run_custom_code(portal) +``` + +This function is registered as a custom `genericsetup:importStep` in {file}`configure.zcml`. + +```xml + + + + + +``` + +````{tip} +When you write a custom `importStep`, remember to write uninstallation code as well. +```{seealso} +{ref}`genericsetup-uninstall-profile-label` +``` +```` + +### Control the import step execution order + +You can make sure that other import steps are processed before yours by using the `depends` directive. + +For instance, if your import step depends on a content type to be installed first, you must use: + +```xml + + + + + + + +``` + +```{tip} +The name that you need, is usually the name of the related xml file, but with the `.xml` stripped. +For the `catalog.xml` the import step name is `catalog`. +But there are exceptions. + +For the `types.xml` and the `types` directory, the import step name is `typeinfo`. + +See {ref}`genericsetup-generic-setup-files-label` for a list. +``` + + +(genericsetup-upgrade-steps-label)= + +## Upgrade Steps + +You can define upgrade steps to run code when someone upgrades your package from version *x* to *y*. + +As an example, let's say that the new version of your.addonpackage defines a *price* field on a content type *MyType* to be a string, +but previously (version 1.1 and earlier) it was a float. + +Code that uses this field and assumes it to be a float will break after the upgrade, you'd like to automatically convert existing values for the field to string. + +You could do this in a script, but having a GenericSetup upgrade step means non-technical people can do it as well. + +Once you have the script, it's code can be to put in an upgrade step. + +### Increment Profile Version + +First increase the number of the version in the `profiles/default/metadata.xml`. +This version number should be an integer. + +Package version are different because they add sense like the status of the add-on: is it stable, is it in development, in beta, which branch is it. + +A profile version indicates only that you have to migrate data in the database. + +### Add Upgrade Step + +Next we add an upgrade step: + +```xml + + + + + +``` + +- You can use a wildcard character for *source* to indicate an upgrade for any previous version. + Since Products.GenericSetup 1.7.6 this works fine. + To run the upgrade step only when upgrading from a specific version, use that version's number. +- The optional `sortkey` can be used to indicate the order in which upgrade steps from the same source to destination are run. + +### Add Upgrade Code + +The code for the upgrade method itself is best placed in a *upgrades.py* module: + +```python +from plone import api +import logging + +PROFILE_ID = 'profile-your.addonpackage:default' + + +def convert_price_to_string(context, logger=None): + """Method to convert float Price fields to string. + + When called from the import_various method, 'context' is + the plone site and 'logger' is the portal_setup logger. + + But this method will be used as upgrade step, in which case 'context' + will be portal_setup and 'logger' will be None.""" + + if logger is None: + # Called as upgrade step: define our own logger. + logger = logging.getLogger('your.addonpackage') + + # Run the catalog.xml step as that may have defined new metadata + # columns. We could instead add to + # the registration of our import step in zcml, but doing it in + # code makes this method usable as upgrade step as well. + # Remove these lines when you have no catalog.xml file. + setup = api.portal.get_tool('portal_setup') + setup.runImportStepFromProfile(PROFILE_ID, 'catalog') + + catalog = api.portal.get_tool('portal_catalog') + brains = catalog(portal_type='MyType') + count = 0 + for brain in brains: + current_price = brain.getPrice + if type(current_price) != type('a string'): + obj = brain.getObject() + obj.setPrice(str(current_price)) + obj.reindexObject() + count += 1 + + setup.runImportStepFromProfile(PROFILE_ID, 'catalog') + logger.info('%s fields converted.' % count) +``` + +Other examples of using generic setup to run import steps are below. + +If you want to call `types.xml` use `typeinfo`: + +```python +setup.runImportStepFromProfile(PROFILE_ID, 'typeinfo') +``` + +If you want to call `workflow.xml` use `workflow`: + +```python +setup.runImportStepFromProfile(PROFILE_ID, 'workflow') +``` + +The ids of the various default import steps are defined in several places. + +Some of the most used ones are here: + +- +- + +After restarting Zope, your upgrade step should be visible in the ZMI: +the `portal_setup` tool has a tab `Upgrades`. + +Select your package profile to see which upgrade steps Zope knows about for your add-on. + +### upgradeDepends + +In an upgrade step you can apply a specific import step from your profile: + +```xml + +``` + +You can apply multiple steps, separated by a space: + +```xml + +``` + +You can apply steps from a different profile: + +```xml + +``` + +You can apply a complete profile: + +```xml + +``` + +### Combining Upgrade Steps + +You can create many upgrade steps under one migration. + +This is useful when you want to have the ability to re-run some parts of the migration and make your code more re-useable (for example cook css resource of your theme). + +Here is an example of many upgrade steps you can have to achieve on a site policy: + +```xml + + + + + + + + + + + + + +``` + + +## Best Practices + +### The `purge` attribute + +When importing items such as property sheets, make sure not to override other profile settings: set the `purge` attribute to False. + +This will *add* the listed items to the property instead of resetting the property. + +Example: + +```xml + + + + +``` + +### The `remove` Attribute + +The `remove` attribute can be used to remove an item. + +```xml + +``` + +There are dangers: + +- Some importers do not support the `remove` keyword. + They ignore it and add the item blindly. + This should be regarded as a bug in the importer. + Please report it. +- Some importers check the truth value of the attribute, some just check the presence. + `remove="false"` may mean the item stays and may mean it gets removed. + Best is to either use `remove="true"` or leave the entire keyword away. + +### Only Use The Configuration That You Need + +When you export your site's configuration, it will include things that you don't need. + +For example, if you only need to change the 'Allow anonymous to view about' property, this is what your `propertiestool.xml` should look like: + +```xml + + + + True + + +``` + + +### i18n domains in GenericSetup xml files + +In your GenericSetup profile you can have several xml files. +In some of these it makes sense to do translations. + +In most of those cases you must use the `plone` domain, but in some you can use your own domain. + +```{note} +You are always allowed to use the `plone` domain, but if the xml file supports a separate domain it is best to use that. +``` + +- `actions.xml`: use **your own** domain. + +Example: + +``` + + Duck Test + Action: test a duck + ... + +``` + +```{note} +In the portal_actions tool, in the ZMI, you will see an i18n domain specified for each action. +``` + +- `catalog.xml`: no i18n needed +- `componentregistry.xml`: no i18n needed +- `contenttyperegistry.xml`: no i18n needed +- `controlpanel.xml`: use **your own** domain. + +Example: + +``` + + + + Manage portal + + +``` + +- `diff_tool.xml`: no i18n needed +- `factorytool.xml`: no i18n needed +- `metadata.xml`: no i18n needed +- `portlets.xml`: use the **plone** domain. +- `properties.xml`: no i18n needed +- `propertiestool.xml`: no i18n needed +- `rolemap.xml`: no i18n needed +- `skins.xml`: no i18n needed +- `toolset.xml`: no i18n needed +- `types`: use **your own** domain +- `viewlets.xml`: no i18n needed +- `workflows`: use the **plone** domain + + +(genericsetup-generic-setup-files-label)= + +## Generic Setup Files + + +### actions.xml + +Install actions in the `portal_actions` tool. + +Example: + +```xml + + + + + Check in + + string:${object_url}/@@content-checkin + string:${portal_url}/++resource++checkout.png + python:path('object/@@iterate_control').checkin_allowed() + + + + True + + + +``` + +These actions are used in various parts of Plone. + +These are the object categories in standard Plone: + +`document_actions` + +: Document actions, like rss and print. + +`site_actions` + +: Site actions, like sitemap, accessibility, contact. + +`object` + +: Object tabs, like contents, sharing tab. + +`object_buttons` + +: Object buttons, like delete, rename. + +`portal_tabs` + +: Portal tabs, like Home. + +`user` + +: User actions, like preferences, login, join. + +For adding controlpanel actions, see [controlpanel.xml] instead. + +The objects support `insert-before` and `insert-after` for inserting the action object before or after another action object. + +For removing, use `remove="true"` (or `True`). + +Uninstall example: + +```xml + + + + + + +``` + +```{note} +You can use your own i18n domain. +``` + +### browserlayer.xml + +This registers a specific browser layer, which allows components to be available only when your add-on package is installed. + +```xml + + + + +``` + +For removing, use `remove="true"` (or `True`). + +Uninstall example: + +```xml + + + + +``` + +### componentregistry.xml + + +Register {term}`Zope Component Architecture` components in the local component registry of the Plone Site. +The items can be adapters, subscribers or utilities. + +This can also be done in ZCML, which puts it in the global registry that is defined at startup. + +The difference is, when you put it in {file}`componentregistry.xml`, the item is only added to a specific Plone Site when you install the package in the add-ons control panel. + +Example: + +```xml + + + + + + +``` + +```{note} +A subscriber can either have a handler or a factory, not both. +A factory must have a provides and may have a name. +A subscriber will fail with a provides. +``` + +```{note} +If something does not get added, its provider is probably blacklisted. +This list is defined by `Products.GenericSetup.interfaces.IComponentsHandlerBlacklist` utilities. +In standard Plone 5, these interfaces are blacklisted as providers: + +- `Products.GenericSetup.interfaces.IComponentsHandlerBlacklist` +- `plone.portlets.interfaces.IPortletManager` +- `plone.portlets.interfaces.IPortletManagerRenderer` +- `plone.portlets.interfaces.IPortletType` +``` + +Uninstall example: + +```xml + + + + + + +``` + +```{note} +The presence of the `remove` keyword is enough. +Even if it is empty or contains `false` as value, the item is removed. +``` + + +### contentrules.xml + +TODO + + +### controlpanel.xml + +```xml + + + + + Manage portal + + + +``` + +This creates an action in the Site Setup control panel in Plone. +Actions are bundled in categories. + +- `Plone` (Plone Configuration) +- `plone-advanced` (Advanced) +- `plone-content` (Content) +- `plone-general` (General) +- `plone-security` (Security) +- `plone-users` (Users) +- `Products` (Add-on Configuration) + +Any other categories are not displayed in the overview control panel. + +For add-ons, the category `Products` is recommended. + +The `action_id` must be unique over all categories. + +Only one permission is allowed. + +Uninstall example: + +```xml + + + + +``` + +```{note} +The action is removed if the `remove` keyword is `true`. +Upper or lower case does not matter. + +The action is visible if the `visible` keyword is `true`. +Upper or lower case does not matter. +``` + +```{note} +You can use your own i18n domain. +``` + +Code is in `Products.CMFPlone.exportimport.controlpanel` and `Products.CMFPlone.PloneControlPanel`. + + +### diff_tool.xml + +This is the configuration from `plone.app.contenttypes`: + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +This configures how the difference between two versions of a field are shown on the history tab. + +The configuration is stored in the `portal_diff` tool. + +A new `difftype` can be registered by calling `Products.CMFDiffTool.CMFDiffTool.registerDiffType`. +The available `difftypes` in Plone are: + +- `Lines Diff` +- `Binary Diff` +- `Field Diff` +- `List Diff` +- `HTML Diff` +- `Compound Diff for Dexterity types` + +```{note} +There is no uninstall version. +The `remove` keyword is not supported. +The `portal_diff` tool does not show configuration for portal_types that no longer exist. +``` + +Code is in `Products.CMFDiffTool.exportimport.difftool`. + + +### metadata.xml + +The `metadata.xml` file is read during Plone start-up. + +If this file has problems your add-on package might not appear in the installer control panel. + +The `metadata.xml` file contains add-on dependency and version information. + +```xml + + + 1000 + + profile-your.addonpackage:default + + +``` + +The dependencies are optional. + +There is no import step that reads this file. +The `portal_setup` tool uses this information when installing a profile. + +It installs the profiles that are listed as dependencies, before installing your own profile. + +Since `Products.GenericSetup` 1.8.0, dependency profiles that are already installed, are not installed again. + +Instead, their upgrade steps, are applied, if they have them. + +After your profile is installed, `portal_setup` stores the version number. +This is used when determining if any upgrade steps are available for your profile. + +When you search for `metadata.xml` in the documentation, you will find more information in context. + +```{note} +There is no uninstall version of `metadata.xml`. +An `uninstall` profile can have its own `metadata.xml` with a version and even profiles. +But for dependencies no `purge` or `remove` keyword is supported. +``` + + +### portal_placeful_workflow + +This handles the `portal_placeful_workflow.xml` file and the `portal_placeful_workflow` directory. + +This install or configures a placeful workflow. + +For this to work, you must install Workflow Policy Support (CMFPlacefulWorkflow) in the Add-ons control panel. This package is included in standard Plone, but does not come installed by default. + +Standard `portal_placeful_workflow.xml` from `Products.CMFPlacefulWorkflow`: + +```xml + + + + 1 + + + + + +``` + +Standard `portal_placeful_workflow/simple-publication.xml` from `Products.CMFPlacefulWorkflow`: + +```xml + + + Simple publication + + + + + + + + + + + + + + + + +``` + +Uninstall example: + +```xml + + + + +``` + +The import handler is in `Products.CMFPlacefulWorkflow.exportimport.importWorkflowPolicies`. + +### portlets.xml + +Code is in `plone.app.portlets.exportimport.portlets`. + +```{eval-rst} +.. automodule:: plone.app.portlets.exportimport.portlets + +``` + +### propertiestool.xml + +```{deprecated} 5.0 +Most properties are now handled in the configuration registry and can be configured in `registry.xml`. +``` + +In `propertiestool.xml` you can change all values of the `portal_properties` tool. +Example: + +```xml + + + + False + TinyMCE + + +``` + +Uninstall example: + +```xml + + + + + + + + +``` + +### pluginregistry.xml + +This configures PAS plugin orderings and active plugins. +It isn't part of Plone itself, it is used by other frameworks and can be used in Plone with a little extra configuration. + +First, you need a monkey patch in your `` __init__.py` `` to point the importer at where Plone keeps its PAS plugins. + +```python +from Products.PluginRegistry import exportimport +from Products.PluginRegistry.interfaces import IPluginRegistry + + +def getRegistry(site): + return IPluginRegistry(site.acl_users.plugins) + +exportimport._getRegistry = getRegistry +``` + +Secondly, code to handle the import step needs to be activated in Plone: + +```xml + +``` + +Now you can use `pluginregistry.xml` in your generic setup profiles: + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +### registry.xml + +This edits the configuration registry. + +```{note} +The name of this import step is `plone.app.registry`, **not** `registry`. +``` + +Example for adding all records of an interface: + +```xml + + + + +``` + +Example for adding an individual record: + +```xml + + + + + Timeout + 0 + + 100 + + +``` + +Uninstall example: + +```xml + + + + + +``` + +The item is removed if the `remove` keyword is `true`. +Upper or lower case does not matter. + +Existing values of lists are purged by default. +The values are not purged if the `purge` keyword is `false`. + +Upper or lower case does not matter. + +For more examples, see the [plone.app.registry documentation](https://pypi.python.org/pypi/plone.app.registry#using-genericsetup-to-manipulate-the-registry). + +Code is in `plone.app.registry.exportimport.handler`. + +### repositorytool.xml + +This handles the versioning policy of content. + +The default configuration in Plone is: + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +Code is in `Products.CMFEditions.exportimport.repository`. + +### rolemap.xml + +In `rolemap.xml` you define new roles and grant permissions. +Both are optional. + +```xml + + + + + + + + + + + + + + + + + + + + + +``` + +The roles above are the standard roles in Plone 5. +In your profile you only need to list other roles. + +The permission must already exist on the Zope level, otherwise you get an error when installing your profile: + +``` +ValueError: The permission Pass the bridge is invalid. +``` + +A permission is created on the Zope level when it is used in code. +See {ref}`backend-security-permissions-label`. + +When a role in a permission does not exist, it is silently ignored. +The roles listed in a permission are not added. + +They replace all existing roles. + +With `acquire="true"` (or `True`, `yes`, `1`) roles are also acquired from the Zope root. + +````{note} +There is no uninstall version for `rolemap.xml`. +`purge` and `remove` are not supported. +You can set different values for a permission if this makes sense in your case. +This will reset the permission to the same settings as on the Zope level: + +```xml + +``` +```` + +### sharing.xml + +The sharing.xml file let you add custom roles to the sharing tab. +For reference, visit {doc}`/backend/security`. + + +### typeinfo + +This handles the `types.xml` file and the `types` directory. + +```{note} +The name of this import step is `typeinfo`, **not** `types`. +``` + +Partial example from `plone.app.contenttypes`: + +```xml + + + + + + + + + + + + +``` + +This adds content types in the `portal_types` tool. +The `meta_type` can be: + +- `Dexterity FTI` for Dexterity content, including the Plone Site itself. + This is probably what you want. +- `Factory-based Type Information with dynamic views` for custom content types that use dynamic views (the ability to choose a view in the Display menu). +- `Factory-based Type Information` for custom content types that do not need dynamic views. + +The `types.xml` should be accompanied by a `types` folder with details information on the new types. +If you are editing an already existing type, then `types.xml` is not needed: +a file in the `types` folder is enough. + +If the object name in `types.xml` is `Collection` then you must add a file `types/Collection.xml`. +This file is in `plone.app.contenttypes`: + +```xml + + + + + Collection + Collection + True + False + + False + plone.app.contenttypes.addCollection + plone.app.contenttypes.content.Collection + + + plone.app.contenttypes.schema:collection.xml + + + + + + + + + + + + + + listing_view + False + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +Uninstall example: + +```xml + + + + +``` + +````{note} +The `remove` keyword is supported for actions. +`remove=""` is enough, but recommended is to use `remove="true"`. + +The `view_methods` property is a list that is always imported fresh. +Elements that are not in the list, are removed. +If you only want to add an element and want to keep any existing elements, +you can tell it not to purge: + +```xml + + + +``` + +This does not work for the `allowed_content_types`: they are always purged. +```` + +```{note} +You can use your own i18n domain. +``` + +### viewlets.xml + +```{eval-rst} +.. automodule:: plone.app.viewletmanager.exportimport.storage + +``` + +### workflows.xml + +This handles the `workflows.xml` file and the `workflows` directory. + +Example from `Products/CMFPlone/profiles/default/workflows.xml` in Plone 5.0: + +```xml + + + Contains workflow definitions for your portal + + + + + + + + + + + + + + + + +``` + +This adds six workflows in the `portal_workflow` tool. +It sets the default workflow to `simple_publication_workflow`. + +It sets several types to not use any workflow. + +Next to this, the `workflows` directory is checked. +This contains sub directories with the same name as the workflows. +Each sub directory contains a file `definition.xml` with the definition for this workflow. + +See {doc}`/backend/workflows`. diff --git a/docs/backend/index.md b/docs/backend/index.md index 3e7dd32784..74d38c60f8 100644 --- a/docs/backend/index.md +++ b/docs/backend/index.md @@ -23,6 +23,7 @@ configuration-registry content-types/index control-panels fields +generic-setup global-utils indexing upgrading/index diff --git a/docs/developer-guide/create-a-backend-add-on.md b/docs/developer-guide/create-a-backend-add-on.md new file mode 100644 index 0000000000..1a535cde1a --- /dev/null +++ b/docs/developer-guide/create-a-backend-add-on.md @@ -0,0 +1,149 @@ +--- +myst: + html_meta: + "description": "How to create a backend add-on" + "property=og:description": "How to create a backend add-on" + "property=og:title": "Create a backend add-on" + "keywords": "Plone 6, backend, add-on" +--- + +(create-a-backend-add-on-label)= + +# Create a backend add-on + +This section explains how a developer can create an {term}`add-on` for the Plone backend. + +## System requirements + +Follow the section {ref}`create-project-cookieplone-system-requirements` to set up your system. + +## Generate the add-on project with `plonecli` + +Choose your desired local development base folder and run the following command to create an add-on project with `plonecli`. + +```shell +uvx plonecli create addon +``` + +```console +> uvx plonecli create addon collective.addon +RUN: bobtemplates.plone:addon -O collective.addon + +Welcome to mr.bob interactive mode. Before we generate directory structure, +some questions need to be answered. + +Answer with a question mark to display help. +Values in square brackets at the end of the questions show the default value if +there is no answer. + + +--> Package description [An add-on for Plone]: + +--> Plone version [6.0.0]: + +--> Python version for virtualenv [python3]: + +--> Do you want me to activate VS Code support? (y/n) [y]: + + + +isort-apply: successful: +isort-apply: install_deps> python -I -m pip install isort -c constraints.txt +isort-apply: commands[0]> isort /Users//Development/collective.addon/src +/Users//Development/collective.addon/setup.py +Fixing /Users//Development/collective.addon/src/collective/addon/testing.py +Fixing /Users//Development/collective.addon/src/collective/addon/tests/test_setup.py + isort-apply: OK (2.57=setup[1.94]+cmd[0.63] seconds) + congratulations :) (2.59 seconds) + + +Identified `/` as project root containing a file system root. +Sources to be formatted: "Users//Development/collective.addon/src", + "Users//Development/collective.addon/setup.py" +src/collective/__init__.py wasn't modified on disk since last run. +src/collective/addon/browser/__init__.py wasn't modified on disk since last run. +src/collective/addon/locales/__init__.py wasn't modified on disk since last run. +src/collective/addon/tests/__init__.py wasn't modified on disk since last run. +src/collective/addon/interfaces.py already well formatted, good job. +reformatted src/collective/addon/__init__.py +reformatted src/collective/addon/setuphandlers.py +reformatted src/collective/addon/testing.py +reformatted setup.py +reformatted src/collective/addon/locales/update.py +reformatted src/collective/addon/tests/test_setup.py + +All done! ✨ 🍰 ✨ +6 files reformatted, 5 files left unchanged. + +black-enforce: successful: +black-enforce: install_deps> python -I -m pip install black -c constraints.txt +black-enforce: commands[0]> black -v src setup.py + black-enforce: OK (2.60=setup[2.12]+cmd[0.48] seconds) + congratulations :) (2.61 seconds) + + +git init is disabled! +Generated file structure at /Users//Development/collective.addon/collective.addon +``` + +Plonecli creates a folder with the name of the add-on, in this example, `collective.addon`. + +You can now continue to add subtemplates to your addon. + + +(create-a-backend-add-on-add-subtemplate-label)= + +## Add `plonecli` subtemplate to an addon + +The generated addon contains a {file}`bobtemplate.cfg` file which lets you add several subtemplates with `plonecli`. + +Run the following command to list the available subtemplates. + +```shell +uvx plonecli -l +``` + +```shell +> uvx plonecli -l +Available mr.bob templates: + - addon + - behavior + - content_type + - controlpanel + - form + - indexer + - mockup_pattern + - portlet + - restapi_service + - site_initialization + - subscriber + - svelte_app + - theme + - theme_barceloneta + - theme_basic + - upgrade_step + - view + - viewlet + - vocabulary + - buildout + ``` + + All templates below `addon` can be added to your newly created addon with: + + ```shell + uvx plonecli add + ``` + +Currently documented subtemplates: + +- behavior: {ref}`backend-behaviors-label` +- content_type: {ref}`creating-content-types-label` +- controlpanel: {ref}`control-panels-label` +- form: {ref}`forms-label` +- mockup_pattern: {ref}`mockup-and-patternslib-label` +- theme_barceloneta: {ref}`create-a-theme-add-on-label` + + +The addon also contains a {term}`GenericSetup` default install/uninstall profile. + +See {ref}`genericsetup-label` for more information. diff --git a/docs/developer-guide/create-a-distribution.md b/docs/developer-guide/create-a-distribution.md index 8a272d5665..9b99a78f83 100644 --- a/docs/developer-guide/create-a-distribution.md +++ b/docs/developer-guide/create-a-distribution.md @@ -19,10 +19,9 @@ For a conceptual guide, see {doc}`/conceptual-guides/distributions`. ``` -## Create a backend add-on +## Use a backend add-on -These instructions assume that you already have created a Plone backend add-on package, -and now you want to add a distribution to it. +These instructions assume that you have already {doc}`created a Plone backend add-on package `, and now you want to add a distribution to it. A Plone distribution exists inside a Python package that can be installed by `pip`. diff --git a/docs/developer-guide/index.md b/docs/developer-guide/index.md index 22eb2c572f..6556302dd6 100644 --- a/docs/developer-guide/index.md +++ b/docs/developer-guide/index.md @@ -1,26 +1,95 @@ --- myst: html_meta: - "description": "Plone developer guide" - "property=og:description": "Plone developer guide" - "property=og:title": "Developer guide" - "keywords": "Plone 6, developer guide, development" + "description": "Plone development guide" + "property=og:description": "Plone development guide" + "property=og:title": "Development guide" + "keywords": "Plone 6, development guide, developer, development" --- -# Developer guide +# Development guide + +```{note} +This part of the documentation is under revision, consolidating documentation for development from its various locations into in one section. +Until then, you can use the [search feature](https://6.docs.plone.org/search.html?q=development). +You can also help with this effort, even if it is to report that something is missing, by [creating an issue](https://github.com/plone/documentation/issues/new?assignees=&labels=&projects=&template=new-issue-form.yml). +``` This part of the documentation provides information for how to develop in Plone. +This development guide points you, as a developer, to the appropriate resource. + + +## Tests + +Tests ensure that your project functions as expected, and that changes to the code base during development don't break anything. + + +### Volto + +- {doc}`Volto acceptance tests ` +- {doc}`Volto unit tests ` +- {ref}`testing-the-add-on-label` + + +### Classic UI ```{note} -This part of the documentation is under construction. -You can find documentation for development in various locations through the [search feature](https://6.docs.plone.org/search.html?q=development). -You can help consolidate all of development documentation here, even if it is to let us know what is missing, by [creating an issue](https://github.com/plone/documentation/issues/new?assignees=&labels=&projects=&template=new-issue-form.yml). +Classic UI testing for Plone 6 is in the process of being written. ``` +### Backend + +```{note} +Backend testing for Plone 6 is in the process of being written. +Until it is complete, Plone 5 documentation is the authoritative source for writing tests for the Plone backend. +``` + +- {doc}`Backend tests ` (Plone 5) + + +## Create an add-on + +- {doc}`create-a-backend-add-on` +- {doc}`/volto/development/add-ons/create-an-add-on-18` + + +## Create a Plone distribution + +{doc}`create-a-distribution` + + +## Create content types + +- {doc}`/backend/content-types/creating-content-types` +- {doc}`plone5:develop/plone/content/index` (Plone 5) + + +## Register views + +{doc}`plone5:develop/plone/views/index` (Plone 5) + + +## Register API services + +{doc}`backend/configuration-registry` + + +## {term}`ZCA` +% TODO: This is a mixture of conceptual and how-to guides. Move its parts where they belong and rewrite. +{doc}`plone5:develop/addons/components/index` (Plone 5) + + +## {term}`ZCML` +% TODO: This is a mixture of conceptual and how-to guides. Move its parts where they belong and rewrite. +{doc}`plone5:develop/addons/components/zcml` (Plone 5) + + ```{toctree} :maxdepth: 2 +:hidden: +create-a-backend-add-on develop-volto-add-ons-index create-a-distribution standardize-python-project-configuration diff --git a/docs/glossary.md b/docs/glossary.md index 1ee4f8e3c2..a3bdbdb78b 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -159,6 +159,7 @@ Dexterity Dublin Core The Dublin Core Schema is a small set of vocabulary terms that can be used to describe web resources (video, images, web pages, etc.), as well as physical resources such as books or CDs, and objects like artworks. +Zope Management Interface ZMI The {term}`Zope` Management Interface. The ZMI is a direct interface into the backend software stack of Plone. diff --git a/styles/config/vocabularies/Plone/accept.txt b/styles/config/vocabularies/Plone/accept.txt index c0b583ac1c..a4a79779a6 100644 --- a/styles/config/vocabularies/Plone/accept.txt +++ b/styles/config/vocabularies/Plone/accept.txt @@ -61,6 +61,7 @@ transpilation transpile[drs]{0,1} [Uu]ncomment [Uu]nhide +uninstallation unregister untranspiled UUID