Portal Developer Guide
The Portal application is implemented as a centraQuest app in apps/portal. It builds on the DMS client, the template manager, sessions, and configurable portal objects.
Runtime Structure
The main application class is PortalApp. It initializes the portal prefix, DMS client, template extensions, pubsub listener, request handlers, and installation bootstrap.
Key modules are:
| Module | Responsibility |
|---|---|
apps/portal/__init__.py | Application startup, routing, login, session handling, content delivery, admin endpoints. |
apps/portal/core.py | Page context, boxes, navigation, ACL helpers, template-facing API. |
apps/portal/lib.py | Template extensions for upload, edit, search, SQL/DQL queries, and portal utilities. |
apps/portal/init.py | Installation/bootstrap logic for portal objects and keywords. |
apps/portal/services.py | Legacy automation helpers for template-based folder initialization. |
Request Context
Each page request creates a PageRequestContext. The context exposes the current request, DMS client, ticket, page properties, boxes, content, language, navigation path, and helper methods to templates.
Templates usually access it as page.
Common template methods include:
| Method | Purpose |
|---|---|
page.zone(name) | Render all boxes assigned to a zone. |
page.zoneColumn(zones, css_class) | Render one or more zones into a wrapper. |
page.mainNavigation() | Iterate top-level navigation entries. |
page.subNavigation() | Iterate child pages. |
page.breadCrumb() | Iterate breadcrumb entries. |
page.includeTemplate(name=...) | Include another portal template. |
page.getProfile(profile_id, profile_type, obj_id) | Load a configured profile. |
page.userGroups() | Return normalized user roles/groups. |
page.hasAclAccess(props) | Check portal-level ACL visibility. |
Routing
Important routes are registered by PortalApp.registerHandlers().
| Route | Handler purpose |
|---|---|
/portal/login | Local login processing. |
/portal/logout | Session cleanup and redirect. |
/portal/main | Main portal template. |
/portal/page | Detail/page rendering. |
/portal/insert | Insert template. |
/portal/edit | Edit template. |
/portal/view | View template. |
/portal/search | Search template. |
/portal/admin | Portal administration. |
/portal/admin/users | User administration. |
/portal/admin/sessions | Session overview. |
/portal/admin/config | Portal configuration page. |
Authentication
The Portal supports several login flows:
- anonymous technical user before login
- local login via access manager
- configured SSO redirect through
portal_use_ssoandportal_sso_login_url - OpenID Connect auto-redirect through access manager configuration
OIDC auto-redirect can be skipped for local administration by using configured skip parameters such as local or no_sso.
Template Resolution
Portal templates are resolved from configured language, layout, master, edit, view, search, and box paths. Request parameters can override the master or edit template:
| Parameter | Effect |
|---|---|
mt | Selects a master template. |
et | Selects an edit template. |
Use this carefully. Template override parameters are powerful and should only be exposed where intended.
Template Extensions
portal.lib.register_template_extensions() registers helper classes for templates:
| Extension | Purpose |
|---|---|
portal.Upload | Render upload-related fields from a mask. |
portal.Edit | Render edit fields for an object. |
portal.Search | Execute portal search helpers. |
portal.Query | Execute configured SQL or DQL-backed queries. |
portal.Util | Date and working-day formatting utilities. |
Installations can add additional extensions through the global template_extension registry.
ACL Normalization
Portal ACL and user role values may arrive as strings, lists, dictionaries, JSON-like strings, or DQL result rows. The portal normalizes them before comparisons.
When adding new template logic, always normalize role-like values before converting them to sets. This avoids errors with multi-value fields and dictionary-shaped DQL results.
Customization Pattern
Customer-specific portal work should usually happen in customer configuration and template folders, not in apps/portal.
Use this order of preference:
- configuration values
- portal page and box objects
- customer-specific templates
- template extensions
- application code changes only when the behavior must become product behavior
Developer Checklist
When implementing a portal change:
- identify whether the change is product-wide or customer-specific
- check whether a config value already exists
- keep template logic small and readable
- normalize user roles and ACLs before comparing
- avoid exposing internal WebUI actions unless intentional
- test anonymous, logged-in, and administrator sessions
- test missing permissions and unpublished content