zotonic_observer behaviour (zotonic_core v1.0.0-rc.17)

Summary

Callbacks

Modify the list of collaboration groups of a user. Called internally by the ACL modules when fetching the list of collaboration groups a user is member of.

Set the context to a typical authenticated user. Used by m_acl.erl

Check if a user is authorized to perform an operation on a an object (some resource or module). Observe this notification to do complex or more fine-grained authorization checks than you can do through the ACL rules admin interface. Defaults to false.

Check if a user is authorizded to perform an action on a property. Defaults to true.

Check if a user is the owner of a resource. id is the resource id.

Clear the associated access policy for the context.

Initialize context with the access policy for the user.

Return the groups for the current user.

Modify the list of user groups of a user. Called internally by the ACL modules when fetching the list of user groups a user is member of.

Render the javascript for a custom action event type. The custom event type must be a tuple, for example: {% wire type={live id=myid} action={...} %}</code\> Must return {ok, Javascript, Context}

An activity in Zotonic. When this is handled as a notification then return a list of patterns matching this activity. These patterns are then used to find interested subscribers.

Push a list of activities via a ‘channel’ (eg ‘email’) to a recipient. The activities are a list of #activity{} records.

Used in the admin to fetch the possible blocks for display

Used for fetching the menu in the admin.

Used in the admin to process a submitted resource form

Notify after logon of user with username, communicates valid or invalid password

Send a request to the client to login a user. The zotonic.auth.worker.js will

Send a request to the client to switch users. The zotonic.auth.worker.js will

Confirm a user id.

A user id has been confirmed.

Return the list of identity types that allow somebody to logon and become an active user of the system. Defaults to [ username_pw ]. In the future more types can be requested, think of ‘contact’ - to be able to contact someone.

User is about to log off. Modify (if needed) the logoff request context.

User logs on. Add user-related properties to the logon request context.

Update the given (accumulator) authentication options with the request options.

First for logon of user with username, called after successful password check.

First for logon of user with username, check for ratelimit, blocks etc.

First to check for password reset forms, return undefined, ok, or {error, Reason}.

First to validate a password. Return {ok, RscId} or {error, Reason}.

Authentication against some (external or internal) service was validated

Save (and update) the complete category hierarchy

Notification to signal an inserted comment. ‘comment_id’ is the id of the inserted comment, ‘id’ is the id of the resource commented on.

Check and possibly modify the http response security headers All headers are in lowercase.

Get available content types and their dispatch rules Example: {{<<”text”>>, <<”html”>>, []}, page} A special dispatch rule is ‘page_url’, which refers to the page_url property of the resource.

Set CORS headers on the HTTP response.

Add custom pivot fields to a resource’s search index (map) Result is a single tuple or list of tuples {pivotname, props}, where “pivotname” is the pivot defined in a call to z_pivot_rsc:define_custom_pivot/3 or a table with created using a SQL command during (eg.) in a module manage_schema/2 call. The name of the table is pivot_<pivotname\>. The props is either a property list or a map with column/value pairs.

Push some information to the debug page in the user-agent. Will be displayed with io_lib:format(“~p: ~p~n”, [What, Arg]), be careful with escaping information!

Final try for dispatch, try to match the request. Called when the site is known, but no match is found for the path

Try to find the site for the request Called when the request Host doesn’t match any active site.

Rewrite a URL before it will be dispatched using the z_sites_dispatcher

Handle a new file received in the ‘files/dropbox’ folder of a site. Unhandled files are deleted after an hour. If the handler returns ‘ok’ then the file is moved from the files/processing folder to files/handled. folder.

An edge has been deleted Note that the Context for this notification does not have the user who deleted the edge.

An edge has been inserted. Note that the Context for this notification does not have the user who created the edge.

An edge has been updated Note that the Context for this notification does not have the user who updated the edge.

Add a handler for receiving e-mail notifications

Bounced e-mail notification. The recipient is the e-mail that is bouncing. When the the message_nr is unknown the it is set to ‘undefined’. This can happen if it is a “late bounce”. If the recipient is defined then the Context is the depickled z_email:send/2 context.

Return the options for the DKIM signature on outgoing emails. Called during email encoding.

Drop an e-mail handler for a user/resource id. (notify). The notification, user and resource should be the same as when the handler was registered.

Add a handler for receiving e-mail notifications

Notify that we could NOT send an e-mail (there might be a bounce later...) The Context is the depickled z_email:send/2 context.

Check if an email address is blocked

Check if an email address is safe to send email to. The email address is not blocked and is not marked as bouncing.

Notification sent to a site when e-mail for that site is received

Add a handler for receiving e-mail notifications

Notify that we could NOT send an e-mail (there might be a bounce later...) The Context is the depickled z_email:send/2 context.

Email status notification, sent when the validity of an email recipient changes

mod_export - return the {ok, Disposition} for the content disposition.

mod_export - Determine the mime type for the export.

mod_export - fetch a row for the export, can return a list of rows, a binary, and optionally a continuation state. Where Values is [ term() ], i.e. a list of opaque values, to be formatted with #export_resource_format. Return the empty list of values to signify the end of the data stream.

mod_export - Encode a single data element.

mod_export - return the {ok, Filename} for the content disposition.

mod_export - Fetch the footer for the export. Should cleanup the continuation state, if needed.

mod_export - Fetch the header for the export.

mod_export - Check if the resource or dispatch is visible for export.

Broadcast some file changed, used for livereload by mod_development

Signal that the hierarchy underneath a resource has been changed by mod_menu

Access log event for http. Called from the z_stats.

Check if passwords are matching. Uses the password hashing algorithms.

Notify that a user’s identity has been updated by the identity model.

Request to send a verification to the user. Return ok or an error. Handled by mod_signup to send out verification emails. Identity may be undefined, or is an identity used for the verification.

Notify that a user’s identity has been verified. Signals to modules handling identities to mark this identity as verified. Handled by mod_admin_identity to call the m_identity model for this type/key.

Find an import definition for a CSV file by checking the filename of the to be imported file.

An external feed delivered a resource. First handler can import it. Return:: {ok, m_rsc:resource_id()}, {error, Reason}, or undefined

Notify that the session’s language has been changed

Try to detect the language of a translation. Set is_editable_only to false to detect any language, even if the language is not enabled for the site. Return atom() | undefined.

Check for logon options, called if logon_submit returns undefined. This is used to fetch external (or local) authentication links for a username. Return:: map()

Check where to go after a user logs on.

Handle a user logon. The posted query args are included. Return:: {ok, UserId} or {error, Reason}

Site configuration parameter was changed

Site configuration parameter was changed

Send a page to a mailinglist (notify) Use {single_test_address, Email} when sending to a specific e-mail address.

Send a welcome or goodbye message to the given recipient. The recipient is either a recipient-id or a recipient props. ‘what’ is send_welcome, send_confirm, send_goobye or silent.

Try to find a filename extension for a mime type (example: <<".jpg"\>\>)

Try to identify a file, returning a map with file properties.

Notification to translate or map a file after upload, before insertion into the database Used in mod_video to queue movies for conversion to mp4. You can set the post_insert_fun to something like fun(Id, Medium, Context) to receive the medium record as it is inserted.

Notification to import a medium record from external source. This is called for non-file medium records, for example embedded video. If the medium record is not recognized then it will not be imported. The handling module is responsible for sanitizing and inserting the medium record.

Modify the options for an image preview url or tag. This is called for every image url generation, except if the ‘original’ image option is passed. The mediaclass in the options is not yet expanded.

Notification that a medium file has been changed (notify) The id is the resource id, medium contains the medium’s complete property map.

See if there is a ‘still’ image preview of a media item. (eg posterframe of a movie) Return:: {ok, ResourceId} or undefined

Media update done notification. action is ‘insert’, ‘update’ or ‘delete’

Notification to translate or map a file after upload, before insertion into the database Used in mod_video to queue movies for conversion to mp4. You can set the post_insert_fun to something like fun(Id, Medium, Context) to receive the medium record as it is inserted.

Notification that a medium file has been uploaded. This is the moment to change properties, modify the file etc. The folded accumulator is the map with updated medium properties.

Notification that a medium file has been uploaded. This is the moment to change resource properties, modify the file etc. The folded accumulator is the map with updated resource properties.

Request to generate a HTML media viewer for a resource. The HTML data can not contain any Javascript, as it might be serialized. This could happen if the correct cookies are not yet set or if the media viewer is part of a direct DOM update.

Optionally wrap HTML with external content so that it adheres to the cookie/privacy settings of the current site visitor. Typically called with a ‘first’ by the code that generated the media viewer HTML, as that code has the knowledge if viewing the generated code has any privacy or cookie implications.

Fetch the menu id belonging to a certain resource

Save the menu tree of a menu resource

Delegates the request processing.

A module has been activated and started.

A module has been stopped and deactivated.

Fold for mapping non-iolist output to iolist values.

Fetch the url of a resource’s html representation

Foldr to change or add pivot fields for the main pivot table. The rsc contains all rsc properties for this resource, including pivot properties. Fold with a map containing the pivot fields.

Fold over the resource props map to extend/remove data to be pivoted

Pivot just before a m_rsc_update update. Used to pivot fields before the pivot itself.

Handle a javascript notification from the postback handler. The message is the the request, trigger the id of the element which triggered the postback, and target the id of the element which should receive possible updates. #postback_notify is also used as an event.

Refresh the context or request process for the given request or action

Let all modules add resource specific response headers to the request. The accumulator is the list of headers to be set.

Resource will be deleted. This notification is part of the delete transaction, it’s purpose is to clean up associated data.

Resource is read, opportunity to add computed fields Used in a foldr with the read properties as accumulator.

Fetch the data for an import of a resource. Returns data in the format used by m_rsc_export and m_rsc_import. Either returns the JSON data, the imported resource id, or the resource id and a map with a mapping from URIs to resource ids.

Foldr for a resource insert, these are the initial properties and will overrule the properties in the insert request. Use with care. The props are the properties of the later insert, after escaping/filtering but before the #rsc_update{} notification below.

Map to signal merging two resources. Move any information from the loser to the winner. The loser will be deleted.

Signal that a resource pivot has been done.

Send a notification that the resource ‘id’ is added to the query query_id.

An updated resource is about to be persisted. Observe this notification to change the resource properties before they are persisted.

An updated resource has just been persisted. Observe this notification to execute follow-up actions for a resource update.

Upload and replace the resource with the given data. The data is in the given format.

Sanitize an HTML element.

Sanitize an embed url. The hostpart is of the format: <<"youtube.com/v..."\>\>.

Add extra javascript with the {% script %} tag. (map) Used to let modules inject extra javascript depending on the arguments of the {% script %} tag. Must return an iolist()

Map a custom search term to a #search_sql_term{} record.

Map a custom search term to a #search_sql_term{} record.

Check and possibly modify the http response security headers All headers are in lowercase.

Refresh the context or request process for the given request or action

Set the language of the context to a user’s prefered language

Request a signup of a new or existing user. Arguments are similar to #signup_url{} Returns {ok, UserId} or {error, Reason}

signup_check Check if the signup can be handled, a fold over all modules. Fold argument/result is {ok, Props, SignupProps} or {error, Reason}

Signal that a user has been confirmed. (map, result is ignored)

Fetch the page a user is redirected to after signing up with a confirmed identity

Signal that a user has been signed up (map, result is ignored)

Signup failed, give the error page URL. Return {ok, Url} or undefined. Reason is returned by the signup handler for the particular signup method (username, facebook etc)

Handle a signup of a user, return the follow on page for after the signup. Return {ok, Url} ‘props’ is a map with properties for the person resource (email, name, etc) ‘signup_props’ is a proplist with ‘identity’ definitions and optional follow on url ‘ready_page’ An identity definition is {Kind, Identifier, IsUnique, IsVerified}

Request the SSL certificates for this site. The server_name property contains the hostname used by the client. (first) Returns either ‘undefined’ or a list of ssl options (type ssl:ssl_option())

Fetch list of handlers for survey submits.

Check if the current user is allowed to download a survey.

Check if a question (page block) is a submitting question.

Modify row with answers for export. The header columns are given and the values that are known are set in the folded value. The user_id is the user who filled in the answers for this row.

Add header columns for export. The values are the names of the answers and the text displayed above the column. The text format is for a complete export, the html format is for the limited result overview of the Survey Results Editor.

A survey has been filled in and submitted.

Delete a value from the typed key/value store

Get a value from the typed key/value store

Put a value into the typed key/value store

Request a translation of a list of strings. The resulting translations must be in the same order as the request. This notification is handled by modules that interface to external translation services like DeepL or Google Translate. Return {ok, List} | {error, Reason} | undefined.

Make a generated URL absolute, optionally called after url_rewrite by z_dispatcher

Determine the URL fetch options for fetching the content of an URL. Used by z_fetch.erl.

Rewrite a URL after it has been generated using the z_dispatcher

Set #context fields depending on the user and/or the preferences of the user.

Check if a user is enabled. Enabled users are allowed to log in. Return true, false or undefined. If undefined is returned, the user is considered enabled if the user resource is published.

Called just before validation of all query arguments by z_validation.

Callbacks

observe_acl_collab_groups_modify/3

(optional)
-callback observe_acl_collab_groups_modify(#acl_collab_groups_modify{id :: m_rsc:resource_id() | undefined,
                                                                     groups :: [m_rsc:resource_id()]},
                                           Acc,
                                           z:context()) ->
                                              Groups
                                              when Acc :: Groups, Groups :: [m_rsc:resource_id()].

Modify the list of collaboration groups of a user. Called internally by the ACL modules when fetching the list of collaboration groups a user is member of.

Type:

foldl

Return:

[ m_rsc:resource_id() ]

#acl_collab_groups_modify{} properties:

  • id: m_rsc:resource_id()|undefined
  • groups: list

observe_acl_context_authenticated/2

(optional)
-callback observe_acl_context_authenticated(#acl_context_authenticated{}, z:context()) ->
                                               z:context() | undefined.

Set the context to a typical authenticated user. Used by m_acl.erl

Type:

first

Return:

authenticated #context{} or undefined

#acl_context_authenticated{} properties: none

observe_acl_is_allowed/2

(optional)
-callback observe_acl_is_allowed(#acl_is_allowed{action :: view | update | delete | insert | use | atom(),
                                                 object :: term()},
                                 z:context()) ->
                                    boolean() | undefined.

Check if a user is authorized to perform an operation on a an object (some resource or module). Observe this notification to do complex or more fine-grained authorization checks than you can do through the ACL rules admin interface. Defaults to false.

Type:

first

Return:

true to allow the operation, false to deny it or undefined to let the next observer decide

#acl_is_allowed{} properties:

  • action: view|update|delete|insert|use|atom
  • object: term

Example

Deny anyone from viewing unpublished resource except those who have update rights on the resource (usually the creator and the administrator):

observe_acl_is_allowed(#acl_is_allowed{action = view, object = Id}, Context) ->
    case m_rsc:p_no_acl(Id, is_published_date, Context) of
        undefined ->
            %% Let next observer decide
            undefined;
        true ->
            %% Resource is published: let next observer decide
            undefined;
        false ->
            %% Resource is unpublished
            case z_acl:is_allowed(update, Id, Context) of
                true ->
                    %% User has update rights, so let next observer decide
                    undefined;
                false ->
                    %% Deny viewing rights on unpublished resource
                    false
            end
    end;
observe_acl_is_allowed(#acl_is_allowed{}, _Context) ->
    %% Fall through
    undefined.

In this observer, we return undefined in those cases where we do not want to deny access. We don’t grant the access right away but give the next observer the change to decide whether viewing is allowed (for instance, based on the resource’s category and content group and the user’s group).

observe_acl_is_allowed_prop/2

(optional)
-callback observe_acl_is_allowed_prop(#acl_is_allowed_prop{action ::
                                                               view | update | delete | insert | atom(),
                                                           object :: term(),
                                                           prop :: binary()},
                                      z:context()) ->
                                         boolean() | undefined.

Check if a user is authorizded to perform an action on a property. Defaults to true.

Type:

first

Return:

true to grant access, false to deny it, undefined to let the next observer decide

#acl_is_allowed_prop{} properties:

  • action: view|update|delete|insert|atom
  • object: term
  • prop: binary

observe_acl_is_owner/2

(optional)
-callback observe_acl_is_owner(#acl_is_owner{id :: m_rsc:resource_id(),
                                             creator_id :: m_rsc:resource_id(),
                                             user_id :: m_rsc:resource_id()},
                               z:context()) ->
                                  boolean() | undefined.

Check if a user is the owner of a resource. id is the resource id.

Type:

first

Return:

true, false or undefined to let the next observer decide

#acl_is_owner{} properties:

  • id: m_rsc:resource_id()
  • creator_id: m_rsc:resource_id()
  • user_id: m_rsc:resource_id()

observe_acl_logoff/2

(optional)
-callback observe_acl_logoff(#acl_logoff{}, z:context()) -> z:context() | undefined.

Clear the associated access policy for the context.

Type:

first

Return:

updated z:context() or undefined

#acl_logoff{} properties: none

observe_acl_logon/2

(optional)
-callback observe_acl_logon(#acl_logon{id :: m_rsc:resource_id(), options :: map()}, z:context()) ->
                               z:context() | undefined.

Initialize context with the access policy for the user.

Type:

first

Return:

updated z:context() or undefined

#acl_logon{} properties:

  • id: m_rsc:resource_id()
  • options: map

observe_acl_user_groups/2

(optional)
-callback observe_acl_user_groups(#acl_user_groups{}, z:context()) -> Groups | undefined
                                     when Groups :: [m_rsc:resource_id()].

Return the groups for the current user.

Type:

first

Return:

[ m_rsc:resource_id() ] or undefined

#acl_user_groups{} properties: none

observe_acl_user_groups_modify/3

(optional)
-callback observe_acl_user_groups_modify(#acl_user_groups_modify{id :: m_rsc:resource_id() | undefined,
                                                                 groups :: [m_rsc:resource_id()]},
                                         Acc,
                                         z:context()) ->
                                            Groups
                                            when Acc :: Groups, Groups :: [m_rsc:resource_id()].

Modify the list of user groups of a user. Called internally by the ACL modules when fetching the list of user groups a user is member of.

Type:

foldl

Return:

[ m_rsc:resource_id() ]

#acl_user_groups_modify{} properties:

  • id: m_rsc:resource_id()|undefined
  • groups: list

observe_action_event_type/2

(optional)
-callback observe_action_event_type(#action_event_type{event :: tuple(),
                                                       trigger_id :: string(),
                                                       trigger :: string(),
                                                       postback_js :: iolist(),
                                                       postback_pickled :: string() | binary(),
                                                       action_js :: iolist()},
                                    z:context()) ->
                                       Result
                                       when
                                           Result :: {ok, Javascript, z:context()} | undefined,
                                           Javascript :: iodata().

Render the javascript for a custom action event type. The custom event type must be a tuple, for example: {% wire type={live id=myid} action={...} %}</code\> Must return {ok, Javascript, Context}

Type:

first

Return:

#action_event_type{} properties:

  • event: tuple
  • trigger_id: string
  • trigger: string
  • postback_js: iolist
  • postback_pickled: string|binary
  • action_js: iolist

observe_activity/2

(optional)
-callback observe_activity(#activity{version :: pos_integer(),
                                     posted_time :: term(),
                                     actor :: term(),
                                     verb :: atom(),
                                     object :: term(),
                                     target :: term()},
                           z:context()) ->
                              Patterns
                              when Patterns :: [term()].

An activity in Zotonic. When this is handled as a notification then return a list of patterns matching this activity. These patterns are then used to find interested subscribers.

Type:

map

Return:

#activity{} properties:

  • version: pos_integer
  • posted_time: unknown
  • actor: unknown
  • verb: atom
  • object: unknown
  • target: unknown

observe_activity_send/2

(optional)
-callback observe_activity_send(#activity_send{recipient_id :: term(),
                                               channel :: term(),
                                               queue :: term(),
                                               activities ::
                                                   [#activity{version :: pos_integer(),
                                                              posted_time :: term(),
                                                              actor :: term(),
                                                              verb :: atom(),
                                                              object :: term(),
                                                              target :: term()}]},
                                z:context()) ->
                                   undefined | ok.

Push a list of activities via a ‘channel’ (eg ‘email’) to a recipient. The activities are a list of #activity{} records.

Type:

first

Return:

#activity_send{} properties:

  • recipient_id: unknown
  • channel: unknown
  • queue: unknown
  • activities: list

observe_admin_edit_blocks/3

(optional)
-callback observe_admin_edit_blocks(#admin_edit_blocks{id :: m_rsc:resource_id()}, Acc, z:context()) ->
                                       Result
                                       when
                                           Acc :: BlockGroups,
                                           Result :: BlockGroups,
                                           BlockGroups :: [{Prio, SectionTitle, BlockTypes}],
                                           Prio :: integer(),
                                           SectionTitle :: binary() | string() | z:trans(),
                                           BlockTypes :: [{atom(), binary() | string() | z:trans()}].

Used in the admin to fetch the possible blocks for display

Type:

foldl

Return:

#admin_edit_blocks{} properties:

  • id: m_rsc:resource_id()

observe_admin_menu/3

(optional)
-callback observe_admin_menu(#admin_menu{}, Acc, z:context()) -> Result
                                when Acc :: MenuItems, Result :: MenuItems, MenuItems :: [term()].

Used for fetching the menu in the admin.

Type:

foldl

Return:

list of admin menu items

#admin_menu{} properties: none

Example

By observing this notification, you can add your own menu items to the admin menu. The admin_menu notification is a fold which build up the menu, allowing each callback to add and remove menu items as they wish.

For example, this add a menu separator and an “edit homepage” button to the “content” submenu:

-include_lib("zotonic_core/include/zotonic.hrl").
-include_lib("zotonic_mod_admin/include/admin_menu.hrl").

observe_admin_menu(#admin_menu{}, Acc, _Context) ->
[
    #menu_separator{parent=admin_content},
    #menu_item{
        id=admin_edit_homepage,
        parent=admin_content,
        label="Edit homepage",
        url={admin_edit_rsc, [{id, page_home}]}
    } |Acc
].

The default submenu names are admin_content, admin_structure, admin_modules, admin_auth and admin_system, but you are free to add your own submenus.

observe_admin_rscform/3

(optional)
-callback observe_admin_rscform(#admin_rscform{id :: m_rsc:resource_id(), is_a :: [atom()]},
                                Acc,
                                z:context()) ->
                                   Result
                                   when Acc :: Props, Result :: Props, Props :: [{binary(), z:qvalue()}].

Used in the admin to process a submitted resource form

Type:

first

Return:

#admin_rscform{} properties:

  • id: m_rsc:resource_id()
  • is_a: list

observe_auth_checked/2

(optional)
-callback observe_auth_checked(#auth_checked{id :: undefined | m_rsc:resource_id(),
                                             username :: binary(),
                                             is_accepted :: boolean()},
                               z:context()) ->
                                  any().

Notify after logon of user with username, communicates valid or invalid password

Type:

notify_sync

Return:

#auth_checked{} properties:

  • id: undefined|m_rsc:resource_id()
  • username: binary
  • is_accepted: boolean

observe_auth_client_logon_user/2

(optional)
-callback observe_auth_client_logon_user(#auth_client_logon_user{user_id :: m_rsc:resource_id(),
                                                                 url :: binary() | undefined},
                                         z:context()) ->
                                            Result
                                            when Result :: ok | {error, term()} | undefined.

Send a request to the client to login a user. The zotonic.auth.worker.js will

send a request to controller_authentication to exchange the one time token with a z.auth cookie for the given user. The client will redirect to the Url.

Type:

first

Return:

ok | {error, term()}

#auth_client_logon_user{} properties:

  • user_id: m_rsc:resource_id()
  • url: union

observe_auth_client_switch_user/2

(optional)
-callback observe_auth_client_switch_user(#auth_client_switch_user{user_id :: m_rsc:resource_id()},
                                          z:context()) ->
                                             Result
                                             when Result :: ok | {error, term()} | undefined.

Send a request to the client to switch users. The zotonic.auth.worker.js will

send a request to controller_authentication to perform the switch.

Type:

first

Return:

ok | {error, term()}

#auth_client_switch_user{} properties:

  • user_id: m_rsc:resource_id()

observe_auth_confirm/3

(optional)
-callback observe_auth_confirm(#auth_confirm{id :: m_rsc:resource_id()}, Acc, z:context()) -> Result
                                  when Acc :: z:context(), Result :: z:context().

Confirm a user id.

Type:

foldl

Return:

z:context()

#auth_confirm{} properties:

  • id: m_rsc:resource_id()

observe_auth_confirm_done/2

(optional)
-callback observe_auth_confirm_done(#auth_confirm_done{id :: m_rsc:resource_id()}, z:context()) -> any().

A user id has been confirmed.

Type:

notify

Return:

#auth_confirm_done{} properties:

  • id: m_rsc:resource_id()

observe_auth_identity_types/3

(optional)
-callback observe_auth_identity_types(#auth_identity_types{type :: user}, Acc, z:context()) -> Result
                                         when Acc :: [atom()], Result :: [atom()].

Return the list of identity types that allow somebody to logon and become an active user of the system. Defaults to [ username_pw ]. In the future more types can be requested, think of ‘contact’ - to be able to contact someone.

Type:

foldl

Return:

[ atom() ]

#auth_identity_types{} properties:

  • unknown: unknown

observe_auth_logoff/3

(optional)
-callback observe_auth_logoff(#auth_logoff{id :: m_rsc:resource_id() | undefined}, Acc, z:context()) ->
                                 Result
                                 when Acc :: z:context(), Result :: z:context().

User is about to log off. Modify (if needed) the logoff request context.

Type:

foldl

Return:

z:context()

#auth_logoff{} properties:

  • id: m_rsc:resource_id()|undefined

observe_auth_logon/3

(optional)
-callback observe_auth_logon(#auth_logon{id :: m_rsc:resource_id()}, Acc, z:context()) -> Result
                                when Acc :: z:context(), Result :: z:context().

User logs on. Add user-related properties to the logon request context.

Type:

foldl

Return:

z:context()

#auth_logon{} properties:

  • id: m_rsc:resource_id()

observe_auth_options_update/3

(optional)
-callback observe_auth_options_update(#auth_options_update{request_options :: map()}, Acc, z:context()) ->
                                         Result
                                         when Acc :: map(), Result :: map().

Update the given (accumulator) authentication options with the request options.

Note that the request options are from the client and are unsafe.

Type:

foldl

Return:

map()

#auth_options_update{} properties:

  • request_options: map

observe_auth_postcheck/2

(optional)
-callback observe_auth_postcheck(#auth_postcheck{service :: atom(),
                                                 id :: m_rsc:resource_id(),
                                                 query_args :: map()},
                                 z:context()) ->
                                    Result
                                    when Result :: ok | {error, term()} | undefined.

First for logon of user with username, called after successful password check.

Type:

first

Return:

‘undefined’ | ok | {error, Reason}

#auth_postcheck{} properties:

  • service: atom
  • id: m_rsc:resource_id()
  • query_args: map

observe_auth_precheck/2

(optional)
-callback observe_auth_precheck(#auth_precheck{username :: binary()}, z:context()) -> Result
                                   when Result :: ok | {error, term()} | undefined.

First for logon of user with username, check for ratelimit, blocks etc.

Type:

first

Return:

‘undefined’ | ok | {error, Reason}

#auth_precheck{} properties:

  • username: binary

observe_auth_reset/2

(optional)
-callback observe_auth_reset(#auth_reset{username :: undefined | binary()}, z:context()) -> Result
                                when Result :: ok | {error, term()} | undefined.

First to check for password reset forms, return undefined, ok, or {error, Reason}.

Type:

first

Return:

#auth_reset{} properties:

  • username: undefined|binary

observe_auth_validate/2

(optional)
-callback observe_auth_validate(#auth_validate{username :: undefined | binary(),
                                               password :: undefined | binary()},
                                z:context()) ->
                                   Result
                                   when Result :: {ok, m_rsc:resource_id()} | {error, term()} | undefined.

First to validate a password. Return {ok, RscId} or {error, Reason}.

Type:

first

Return:

#auth_validate{} properties:

  • username: undefined|binary
  • password: undefined|binary

observe_auth_validated/2

(optional)
-callback observe_auth_validated(#auth_validated{service :: atom(),
                                                 service_uid :: binary(),
                                                 service_props :: map(),
                                                 props :: m_rsc:props(),
                                                 identities :: [map()],
                                                 ensure_username_pw :: boolean(),
                                                 is_connect :: boolean(),
                                                 is_signup_confirmed :: boolean()},
                                 z:context()) ->
                                    Result
                                    when
                                        Result ::
                                            {ok, m_rsc:resource_id()} |
                                            {ok, z:context()} |
                                            {error, term()} |
                                            undefined.

Authentication against some (external or internal) service was validated

Type:

first

Return:

#auth_validated{} properties:

  • service: atom
  • service_uid: binary
  • service_props: map
  • unknown: unknown
  • identities: list
  • ensure_username_pw: boolean
  • is_connect: boolean
  • is_signup_confirmed: boolean

observe_category_hierarchy_save/2

(optional)
-callback observe_category_hierarchy_save(#category_hierarchy_save{tree :: term()}, z:context()) -> any().

Save (and update) the complete category hierarchy

Type:

notify

Return:

#category_hierarchy_save{} properties:

  • tree: unknown

observe_comment_insert/2

(optional)
-callback observe_comment_insert(#comment_insert{comment_id :: integer(), id :: m_rsc:resource_id()},
                                 z:context()) ->
                                    any().

Notification to signal an inserted comment. ‘comment_id’ is the id of the inserted comment, ‘id’ is the id of the resource commented on.

Type:

notify

Return:

#comment_insert{} properties:

  • comment_id: integer
  • id: m_rsc:resource_id()

observe_content_security_header(Default, Acc, Context)

(optional)
-callback observe_content_security_header(Default, Acc, Context) -> Result
                                             when
                                                 Default ::
                                                     #content_security_header{child_src :: [binary()],
                                                                              connect_src :: [binary()],
                                                                              default_src :: [binary()],
                                                                              font_src :: [binary()],
                                                                              frame_src :: [binary()],
                                                                              img_src :: [binary()],
                                                                              manifest_src :: [binary()],
                                                                              media_src :: [binary()],
                                                                              object_src :: [binary()],
                                                                              script_src :: [binary()],
                                                                              script_src_elem :: [binary()],
                                                                              script_src_attr :: [binary()],
                                                                              style_src :: [binary()],
                                                                              style_src_elem :: [binary()],
                                                                              style_src_attr :: [binary()],
                                                                              worker_src :: [binary()],
                                                                              base_uri :: [binary()],
                                                                              sandbox :: [binary()],
                                                                              frame_ancestors :: [binary()],
                                                                              form_action :: [binary()],
                                                                              report_to :: [binary()]},
                                                 Acc ::
                                                     #content_security_header{child_src :: [binary()],
                                                                              connect_src :: [binary()],
                                                                              default_src :: [binary()],
                                                                              font_src :: [binary()],
                                                                              frame_src :: [binary()],
                                                                              img_src :: [binary()],
                                                                              manifest_src :: [binary()],
                                                                              media_src :: [binary()],
                                                                              object_src :: [binary()],
                                                                              script_src :: [binary()],
                                                                              script_src_elem :: [binary()],
                                                                              script_src_attr :: [binary()],
                                                                              style_src :: [binary()],
                                                                              style_src_elem :: [binary()],
                                                                              style_src_attr :: [binary()],
                                                                              worker_src :: [binary()],
                                                                              base_uri :: [binary()],
                                                                              sandbox :: [binary()],
                                                                              frame_ancestors :: [binary()],
                                                                              form_action :: [binary()],
                                                                              report_to :: [binary()]},
                                                 Context :: z:context(),
                                                 Result ::
                                                     #content_security_header{child_src :: [binary()],
                                                                              connect_src :: [binary()],
                                                                              default_src :: [binary()],
                                                                              font_src :: [binary()],
                                                                              frame_src :: [binary()],
                                                                              img_src :: [binary()],
                                                                              manifest_src :: [binary()],
                                                                              media_src :: [binary()],
                                                                              object_src :: [binary()],
                                                                              script_src :: [binary()],
                                                                              script_src_elem :: [binary()],
                                                                              script_src_attr :: [binary()],
                                                                              style_src :: [binary()],
                                                                              style_src_elem :: [binary()],
                                                                              style_src_attr :: [binary()],
                                                                              worker_src :: [binary()],
                                                                              base_uri :: [binary()],
                                                                              sandbox :: [binary()],
                                                                              frame_ancestors :: [binary()],
                                                                              form_action :: [binary()],
                                                                              report_to :: [binary()]}.

Check and possibly modify the http response security headers All headers are in lowercase.

Type:

first

Return:

#content_security_header{} properties:

  • child_src: list
  • connect_src: list
  • default_src: list
  • font_src: list
  • frame_src: list
  • img_src: list
  • manifest_src: list
  • media_src: list
  • object_src: list
  • script_src: list
  • script_src_elem: list
  • script_src_attr: list
  • style_src: list
  • style_src_elem: list
  • style_src_attr: list
  • worker_src: list
  • base_uri: list
  • sandbox: list
  • frame_ancestors: list
  • form_action: list
  • report_to: list

observe_content_types_dispatch/3

(optional)
-callback observe_content_types_dispatch(#content_types_dispatch{id :: m_rsc:resource()}, Acc, Context) ->
                                            Result
                                            when
                                                Acc :: [{ContentType, atom()}],
                                                Context :: z:context(),
                                                Result :: [{ContentType, atom()}],
                                                ContentType :: {binary(), binary(), list()}.

Get available content types and their dispatch rules Example: {{<<”text”>>, <<”html”>>, []}, page} A special dispatch rule is ‘page_url’, which refers to the page_url property of the resource.

Type:

foldr

Return:

[{ContentType, DispatchRule}]

#content_types_dispatch{} properties:

  • id: m_rsc:resource()

observe_cors_headers/2

(optional)
-callback observe_cors_headers(#cors_headers{headers :: [{binary(), binary()}]}, z:context()) -> Result
                                  when
                                      Result :: #cors_headers{headers :: [{binary(), binary()}]} | undefined.

Set CORS headers on the HTTP response.

Type:

first

Return:

#cors_headers{} properties:

  • headers: list

observe_custom_pivot/2

(optional)
-callback observe_custom_pivot(#custom_pivot{id :: m_rsc:resource_id()}, z:context()) -> Pivots
                                  when
                                      Pivots :: [Pivot] | Pivot | ok | none | undefined,
                                      Pivot :: {atom(), PivotFields},
                                      PivotFields :: proplists:proplist() | map().

Add custom pivot fields to a resource’s search index (map) Result is a single tuple or list of tuples {pivotname, props}, where “pivotname” is the pivot defined in a call to z_pivot_rsc:define_custom_pivot/3 or a table with created using a SQL command during (eg.) in a module manage_schema/2 call. The name of the table is pivot_<pivotname\>. The props is either a property list or a map with column/value pairs.

The table MUST have an id column, with a foreign key constraint to the rsc table. If you define the pivot table using z_pivot_rsc:define_custom_pivot/3 then this column and foreign key constraint are automatically added.

Type:

map

Return:

#custom_pivot{} properties:

  • id: m_rsc:resource_id()

observe_debug/2

(optional)
-callback observe_debug(#debug{what :: term(), arg :: term()}, z:context()) -> any().

Push some information to the debug page in the user-agent. Will be displayed with io_lib:format(“~p: ~p~n”, [What, Arg]), be careful with escaping information!

Type:

first

Return:

#debug{} properties:

  • what: unknown
  • unknown: unknown

observe_development_make/2

(optional)
-callback observe_development_make(development_make, z:context()) -> any().

observe_development_reload/2

(optional)
-callback observe_development_reload(development_reload, z:context()) -> any().

observe_dispatch/2

(optional)
-callback observe_dispatch(#dispatch{host :: binary(),
                                     path :: binary(),
                                     method :: binary(),
                                     protocol :: http | https,
                                     tracer_pid :: pid() | undefined},
                           z:context()) ->
                              {ok, Result} | undefined
                              when
                                  Result ::
                                      m_rsc:resource_id() |
                                      #dispatch_match{dispatch_name :: atom(),
                                                      mod :: atom(),
                                                      mod_opts :: list(),
                                                      path_tokens :: [binary()],
                                                      bindings :: [{atom(), binary() | true}]} |
                                      #dispatch_redirect{location :: binary(), is_permanent :: boolean()}.

Final try for dispatch, try to match the request. Called when the site is known, but no match is found for the path

Type:

first

Return:

{ok, RscId::integer()}, {ok, #dispatch_match{}}, {ok, #dispatch_redirect{}} or undefined

#dispatch{} properties:

  • host: binary
  • path: binary
  • method: binary
  • protocol: union
  • tracer_pid: union

observe_dispatch_host/2

(optional)
-callback observe_dispatch_host(#dispatch_host{host :: binary(),
                                               path :: binary(),
                                               method :: binary(),
                                               protocol :: http | https},
                                z:context()) ->
                                   {ok, #dispatch_redirect{location :: binary(), is_permanent :: boolean()}} |
                                   undefined.

Try to find the site for the request Called when the request Host doesn’t match any active site.

Type:

first

Return:

{ok, #dispatch_redirect{}} or undefined

#dispatch_host{} properties:

  • host: binary
  • path: binary
  • method: binary
  • protocol: union

observe_dispatch_rewrite/3

(optional)
-callback observe_dispatch_rewrite(#dispatch_rewrite{is_dir :: boolean(), path :: binary(), host :: term()},
                                   Acc,
                                   z:context()) ->
                                      Acc1
                                      when
                                          Acc :: {Tokens, Bindings},
                                          Tokens :: [binary()],
                                          Bindings :: list(),
                                          Acc1 :: {Tokens1, Bindings1},
                                          Tokens1 :: [binary()],
                                          Bindings1 :: list().

Rewrite a URL before it will be dispatched using the z_sites_dispatcher

Type:

foldl

Return:

#dispatch_rewrite{} properties:

  • is_dir: boolean
  • path: binary
  • host: unknown

observe_dropbox_file/2

(optional)
-callback observe_dropbox_file(#dropbox_file{filename :: file:filename_all(), basename :: binary()},
                               z:context()) ->
                                  Result
                                  when Result :: ok | {ok, processing} | undefined.

Handle a new file received in the ‘files/dropbox’ folder of a site. Unhandled files are deleted after an hour. If the handler returns ‘ok’ then the file is moved from the files/processing folder to files/handled. folder.

Type:

first

Return:

#dropbox_file{} properties:

  • filename: file:filename_all()
  • basename: binary

observe_edge_delete/2

(optional)
-callback observe_edge_delete(#edge_delete{subject_id :: m_rsc:resource(),
                                           predicate :: atom(),
                                           object_id :: m_rsc:resource(),
                                           edge_id :: pos_integer()},
                              z:context()) ->
                                 any().

An edge has been deleted Note that the Context for this notification does not have the user who deleted the edge.

Type:

notify

Return:

return value is ignored

#edge_delete{} properties:

  • subject_id: m_rsc:resource()
  • predicate: atom
  • object_id: m_rsc:resource()
  • edge_id: pos_integer

Example

Perform some action when an edge is deleted:

-include_lib("zotonic_core/include/zotonic.hrl").
-export([observe_edge_delete/2]).

observe_edge_delete(#edge_delete{edge_id = Id}, Context) ->
    %% Consult the edge_log table to get the late edge's details
    Edge = z_db:assoc_row("select * from edge_log where edge_id = $1", [Id], Context)),

    ?DEBUG(Edge),
    %% logged is when the deletion was logged; created is when the edge was
    %% originally created
    %% [{id,11},{op,<<"DELETE">>},{edge_id,25},{subject_id,341},{predicate_id,300},{predicate,<<"about">>},{object_id,338},{seq,1000000},{logged,{{2016,10,13},{10,23,21}}},{created,{{2016,10,13},{10,23,13}}}]

    %% Do something...

    ok.

observe_edge_insert/2

(optional)
-callback observe_edge_insert(#edge_insert{subject_id :: m_rsc:resource(),
                                           predicate :: atom(),
                                           object_id :: m_rsc:resource(),
                                           edge_id :: pos_integer()},
                              z:context()) ->
                                 any().

An edge has been inserted. Note that the Context for this notification does not have the user who created the edge.

Type:

notify

Return:

return value is ignored

#edge_insert{} properties:

  • subject_id: m_rsc:resource()
  • predicate: atom
  • object_id: m_rsc:resource()
  • edge_id: pos_integer

observe_edge_update/2

(optional)
-callback observe_edge_update(#edge_update{subject_id :: m_rsc:resource(),
                                           predicate :: atom(),
                                           object_id :: m_rsc:resource(),
                                           edge_id :: pos_integer()},
                              z:context()) ->
                                 any().

An edge has been updated Note that the Context for this notification does not have the user who updated the edge.

Type:

notify

Return:

return value is ignored

#edge_update{} properties:

  • subject_id: m_rsc:resource()
  • predicate: atom
  • object_id: m_rsc:resource()
  • edge_id: pos_integer

observe_email_add_handler/2

(optional)
-callback observe_email_add_handler(#email_add_handler{notification :: term(),
                                                       user_id :: term(),
                                                       resource_id :: term()},
                                    z:context()) ->
                                       Result
                                       when Result :: {ok, LocalForm :: binary()} | undefined.

Add a handler for receiving e-mail notifications

Type:

first

Return:

{ok, LocalFrom}, the unique localpart of an e-mail address on this server.

#email_add_handler{} properties:

  • notification: unknown
  • user_id: unknown
  • resource_id: unknown

observe_email_bounced/2

(optional)
-callback observe_email_bounced(#email_bounced{message_nr :: binary() | undefined,
                                               recipient :: binary() | undefined},
                                z:context()) ->
                                   any().

Bounced e-mail notification. The recipient is the e-mail that is bouncing. When the the message_nr is unknown the it is set to ‘undefined’. This can happen if it is a “late bounce”. If the recipient is defined then the Context is the depickled z_email:send/2 context.

Type:

notify

Return:

#email_bounced{} properties:

  • message_nr: binary|undefined
  • recipient: binary|undefined

observe_email_dkim_options/2

(optional)
-callback observe_email_dkim_options(#email_dkim_options{}, z:context()) -> Result
                                        when
                                            Result :: DKIMOptions | undefined,
                                            DKIMOptions :: [{atom(), term()}].

Return the options for the DKIM signature on outgoing emails. Called during email encoding.

Type:

first

Return:

list() options for the DKIM signature

#email_dkim_options{} properties: none

observe_email_drop_handler/2

(optional)
-callback observe_email_drop_handler(#email_drop_handler{notification :: term(),
                                                         user_id :: term(),
                                                         resource_id :: term()},
                                     z:context()) ->
                                        any().

Drop an e-mail handler for a user/resource id. (notify). The notification, user and resource should be the same as when the handler was registered.

Type:

first

Return:

#email_drop_handler{} properties:

  • notification: unknown
  • user_id: unknown
  • resource_id: unknown

observe_email_ensure_handler/2

(optional)
-callback observe_email_ensure_handler(#email_ensure_handler{notification :: term(),
                                                             user_id :: term(),
                                                             resource_id :: term()},
                                       z:context()) ->
                                          Result
                                          when Result :: {ok, LocalForm :: binary()} | undefined.

Add a handler for receiving e-mail notifications

Type:

first

Return:

{ok, LocalFrom}, the unique localpart of an e-mail address on this server.

#email_ensure_handler{} properties:

  • notification: unknown
  • user_id: unknown
  • resource_id: unknown

observe_email_failed/2

(optional)
-callback observe_email_failed(#email_failed{message_nr :: binary(),
                                             recipient :: binary(),
                                             is_final :: boolean(),
                                             reason ::
                                                 bounce | retry | illegal_address | smtphost |
                                                 sender_disabled | error,
                                             retry_ct :: non_neg_integer() | undefined,
                                             status :: binary() | {error, term()} | undefined},
                               z:context()) ->
                                  any().

Notify that we could NOT send an e-mail (there might be a bounce later...) The Context is the depickled z_email:send/2 context.

Type:

notify

Return:

#email_failed{} properties:

  • message_nr: binary
  • recipient: binary
  • is_final: boolean
  • reason: bounce|retry|illegal_address|smtphost|sender_disabled|error
  • retry_ct: non_neg_integer|undefined
  • status: binary|tuple|undefined

observe_email_is_blocked/2

(optional)
-callback observe_email_is_blocked(#email_is_blocked{recipient :: binary()}, z:context()) ->
                                      boolean() | undefined.

Check if an email address is blocked

Type:

first

Return:

#email_is_blocked{} properties:

  • recipient: binary

observe_email_is_recipient_ok/2

(optional)
-callback observe_email_is_recipient_ok(#email_is_recipient_ok{recipient :: binary()}, z:context()) ->
                                           boolean() | undefined.

Check if an email address is safe to send email to. The email address is not blocked and is not marked as bouncing.

Type:

first

Return:

#email_is_recipient_ok{} properties:

  • recipient: binary

observe_email_received/2

(optional)
-callback observe_email_received(#email_received{to :: binary(),
                                                 from :: undefined | binary(),
                                                 localpart :: binary(),
                                                 localtags :: [binary()],
                                                 domain :: binary(),
                                                 reference :: binary(),
                                                 email ::
                                                     #email{to ::
                                                                list() |
                                                                string() |
                                                                binary() |
                                                                m_rsc:resource_id() |
                                                                undefined,
                                                            cc :: list() | string() | binary() | undefined,
                                                            bcc :: list() | string() | binary() | undefined,
                                                            from :: binary() | string(),
                                                            reply_to ::
                                                                binary() | string() | message_id | undefined,
                                                            headers :: [{binary(), binary()}],
                                                            body :: term(),
                                                            raw :: term(),
                                                            subject :: iodata() | undefined,
                                                            text :: iodata() | undefined,
                                                            html :: iodata() | undefined,
                                                            text_tpl ::
                                                                template_compiler:template() | undefined,
                                                            html_tpl ::
                                                                template_compiler:template() | undefined,
                                                            vars :: list(),
                                                            attachments :: list(),
                                                            queue :: boolean()},
                                                 headers :: [{binary(), binary()}],
                                                 is_bulk :: boolean(),
                                                 is_auto :: boolean(),
                                                 decoded :: term(),
                                                 raw :: term()},
                                 z:context()) ->
                                    Result
                                    when
                                        Result ::
                                            undefined |
                                            {ok, MsgId :: binary()} |
                                            {ok, term()} |
                                            ok |
                                            {error, term()} |
                                            undefined.

Notification sent to a site when e-mail for that site is received

Type:

first

Return:

#email_received{} properties:

  • to: binary
  • from: undefined|binary
  • localpart: binary
  • localtags: list
  • domain: binary
  • reference: binary
  • email: record
  • headers: list
  • is_bulk: boolean
  • is_auto: boolean
  • decoded: unknown
  • raw: unknown

observe_email_send_encoded/2

(optional)
-callback observe_email_send_encoded(#email_send_encoded{message_nr :: binary(),
                                                         from :: binary(),
                                                         to :: binary(),
                                                         encoded :: binary(),
                                                         options :: gen_smtp_client:options()},
                                     z:context()) ->
                                        Result
                                        when
                                            Result ::
                                                {ok, binary()} |
                                                {ok, term()} |
                                                {error, Reason, {FailureType, Host, Message}} |
                                                {error, term()} |
                                                smtp | undefined,
                                            Reason :: term(),
                                            FailureType :: permanent_failure | temporary_failure,
                                            Host :: string() | binary(),
                                            Message :: term().

Add a handler for receiving e-mail notifications

Type:

first

Return:

{ok, LocalFrom}, the unique localpart of an e-mail address on this server.

#email_send_encoded{} properties:

  • message_nr: binary
  • from: binary
  • to: binary
  • encoded: binary
  • options: gen_smtp_client:options()

observe_email_sent/2

(optional)
-callback observe_email_sent(#email_sent{message_nr :: binary(),
                                         recipient :: binary(),
                                         is_final :: boolean()},
                             z:context()) ->
                                any().

Notify that we could NOT send an e-mail (there might be a bounce later...) The Context is the depickled z_email:send/2 context.

Type:

notify

Return:

#email_sent{} properties:

  • message_nr: binary
  • recipient: binary
  • is_final: boolean

observe_email_status/2

(optional)
-callback observe_email_status(#email_status{recipient :: binary(),
                                             is_valid :: boolean(),
                                             is_final :: boolean(),
                                             is_manual :: boolean()},
                               z:context()) ->
                                  any().

Email status notification, sent when the validity of an email recipient changes

Type:

notify

Return:

#email_status{} properties:

  • recipient: binary
  • is_valid: boolean
  • is_final: boolean
  • is_manual: boolean

observe_export_resource_content_disposition/2

(optional)
-callback observe_export_resource_content_disposition(#export_resource_content_disposition{dispatch ::
                                                                                               atom(),
                                                                                           id ::
                                                                                               m_rsc:resource_id() |
                                                                                               undefined,
                                                                                           content_type ::
                                                                                               binary()},
                                                      z:context()) ->
                                                         Result
                                                         when
                                                             Result :: {ok, Disposition} | undefined,
                                                             Disposition :: binary().

mod_export - return the {ok, Disposition} for the content disposition.

Type:

first

Return:

{ok, <<”inline”>>} or {ok, <<”attachment”>>}

#export_resource_content_disposition{} properties:

  • dispatch: atom
  • id: m_rsc:resource_id()|undefined
  • content_type: binary

observe_export_resource_content_type/2

(optional)
-callback observe_export_resource_content_type(#export_resource_content_type{dispatch :: atom(),
                                                                             id ::
                                                                                 m_rsc:resource_id() |
                                                                                 undefined},
                                               z:context()) ->
                                                  Result
                                                  when Result :: {ok, binary() | string()} | undefined.

mod_export - Determine the mime type for the export.

Type:

first

Return:

{ok, "text/csv"}) for the dispatch rule/id export.

#export_resource_content_type{} properties:

  • dispatch: atom
  • id: m_rsc:resource_id()|undefined

observe_export_resource_data/2

(optional)
-callback observe_export_resource_data(#export_resource_data{dispatch :: atom(),
                                                             id :: m_rsc:resource_id() | undefined,
                                                             content_type :: binary(),
                                                             state :: term()},
                                       z:context()) ->
                                          Result
                                          when
                                              Result ::
                                                  {ok, binary() | Values} |
                                                  {ok, binary() | Values, State} |
                                                  {error, term()} |
                                                  undefined,
                                              Values :: [term()],
                                              State :: term().

mod_export - fetch a row for the export, can return a list of rows, a binary, and optionally a continuation state. Where Values is [ term() ], i.e. a list of opaque values, to be formatted with #export_resource_format. Return the empty list of values to signify the end of the data stream.

Type:

first

Return:

{ok, Values|binary()}, {ok, Values|binary(), ContinuationState} or {error, Reason}

#export_resource_data{} properties:

  • dispatch: atom
  • id: m_rsc:resource_id()|undefined
  • content_type: binary
  • state: term

observe_export_resource_encode/2

(optional)
-callback observe_export_resource_encode(#export_resource_encode{dispatch :: atom(),
                                                                 id :: m_rsc:resource_id() | undefined,
                                                                 content_type :: binary(),
                                                                 data :: term(),
                                                                 state :: term()},
                                         z:context()) ->
                                            Result
                                            when
                                                Result ::
                                                    {ok, binary()} |
                                                    {ok, binary(), State} |
                                                    {error, term()} |
                                                    undefined,
                                                State :: term().

mod_export - Encode a single data element.

Type:

first

Return:

{ok, binary()}, {ok, binary(), ContinuationState} or {error, Reason}

#export_resource_encode{} properties:

  • dispatch: atom
  • id: m_rsc:resource_id()|undefined
  • content_type: binary
  • data: term
  • state: term

observe_export_resource_filename/2

(optional)
-callback observe_export_resource_filename(#export_resource_filename{dispatch :: atom(),
                                                                     id :: m_rsc:resource_id() | undefined,
                                                                     content_type :: binary()},
                                           z:context()) ->
                                              Result
                                              when Result :: {ok, binary() | string()} | undefined.

mod_export - return the {ok, Filename} for the content disposition.

Type:

first

Return:

{ok, Filename}} or undefined

#export_resource_filename{} properties:

  • dispatch: atom
  • id: m_rsc:resource_id()|undefined
  • content_type: binary

observe_export_resource_footer/2

(optional)
-callback observe_export_resource_footer(#export_resource_footer{dispatch :: atom(),
                                                                 id :: m_rsc:resource_id() | undefined,
                                                                 content_type :: binary(),
                                                                 state :: term()},
                                         z:context()) ->
                                            Result
                                            when Result :: {ok, binary()} | {error, term()} | undefined.

mod_export - Fetch the footer for the export. Should cleanup the continuation state, if needed.

Type:

first

Return:

{ok, binary()} or {error, Reason}

#export_resource_footer{} properties:

  • dispatch: atom
  • id: m_rsc:resource_id()|undefined
  • content_type: binary
  • state: term

observe_export_resource_header/2

(optional)
-callback observe_export_resource_header(#export_resource_header{dispatch :: atom(),
                                                                 id :: m_rsc:resource_id() | undefined,
                                                                 content_type :: binary()},
                                         z:context()) ->
                                            Result
                                            when
                                                Result ::
                                                    {ok, binary() | [binary()]} |
                                                    {ok, binary() | [binary()], State} |
                                                    {error, term()} |
                                                    undefined,
                                                State :: term().

mod_export - Fetch the header for the export.

Type:

first

Return:

{ok, list()|binary()}, {ok, list()|binary(), ContinuationState} or {error, Reason}

#export_resource_header{} properties:

  • dispatch: atom
  • id: m_rsc:resource_id()|undefined
  • content_type: binary

observe_export_resource_visible/2

(optional)
-callback observe_export_resource_visible(#export_resource_visible{dispatch :: atom(),
                                                                   id :: m_rsc:resource_id() | undefined},
                                          z:context()) ->
                                             boolean() | undefined.

mod_export - Check if the resource or dispatch is visible for export.

Type:

first

Return:

true or false

#export_resource_visible{} properties:

  • dispatch: atom
  • id: m_rsc:resource_id()|undefined

observe_filewatcher/2

(optional)
-callback observe_filewatcher(#filewatcher{verb :: modify | create | delete,
                                           file :: binary(),
                                           basename :: binary(),
                                           extension :: binary()},
                              z:context()) ->
                                 any().

Broadcast some file changed, used for livereload by mod_development

Type:

notify

Return:

return value is ignored

#filewatcher{} properties:

  • verb: modify|create|delete
  • file: binary
  • basename: binary
  • extension: binary

observe_hierarchy_updated/2

(optional)
-callback observe_hierarchy_updated(#hierarchy_updated{root_id :: binary() | integer(),
                                                       predicate :: atom(),
                                                       inserted_ids :: [integer()],
                                                       deleted_ids :: [integer()]},
                                    z:context()) ->
                                       any().

Signal that the hierarchy underneath a resource has been changed by mod_menu

Type:

notify

Return:

#hierarchy_updated{} properties:

  • root_id: binary|integer
  • predicate: atom
  • inserted_ids: list
  • deleted_ids: list

observe_http_log_access/2

(optional)
-callback observe_http_log_access(#http_log_access{timestamp :: erlang:timestamp(),
                                                   status :: undefined | non_neg_integer(),
                                                   status_category ::
                                                       xxx | '1xx' | '2xx' | '3xx' | '4xx' | '5xx',
                                                   method :: binary(),
                                                   metrics :: map()},
                                  z:context()) ->
                                     any().

Access log event for http. Called from the z_stats.

Type:

notify_sync

Return:

#http_log_access{} properties:

  • timestamp: erlang:timestamp()
  • status: undefined|non_neg_integer
  • status_category: xxx|1xx|2xx|3xx|4xx|5xx
  • method: binary
  • metrics: map

observe_identity_password_match/2

(optional)
-callback observe_identity_password_match(#identity_password_match{rsc_id :: m_rsc:resource_id() | undefined,
                                                                   password :: binary(),
                                                                   hash ::
                                                                       m_identity:hash() |
                                                                       {hash, atom() | binary(), binary()}},
                                          z:context()) ->
                                             undefined | boolean().

Check if passwords are matching. Uses the password hashing algorithms.

Type:

first

Return:

#identity_password_match{} properties:

  • rsc_id: m_rsc:resource_id()|undefined
  • password: binary
  • hash: m_identity:hash()|tuple

observe_identity_update_done/2

(optional)
-callback observe_identity_update_done(#identity_update_done{action :: insert | update | delete | verify,
                                                             rsc_id :: m_rsc:resource_id(),
                                                             type :: binary(),
                                                             key :: m_identity:key() | undefined,
                                                             is_verified :: boolean() | undefined},
                                       z:context()) ->
                                          any().

Notify that a user’s identity has been updated by the identity model.

Type:

notify

Return:

#identity_update_done{} properties:

  • action: insert|update|delete|verify
  • rsc_id: m_rsc:resource_id()
  • type: binary
  • key: m_identity:key()|undefined
  • is_verified: boolean|undefined

observe_identity_verification/2

(optional)
-callback observe_identity_verification(#identity_verification{user_id :: m_rsc:resource_id(),
                                                               identity :: undefined | m_identity:identity()},
                                        z:context()) ->
                                           Result
                                           when Result :: ok | {error, term()} | undefined.

Request to send a verification to the user. Return ok or an error. Handled by mod_signup to send out verification emails. Identity may be undefined, or is an identity used for the verification.

Type:

first

Return:

#identity_verification{} properties:

  • user_id: m_rsc:resource_id()
  • identity: undefined|m_identity:identity()

observe_identity_verified/2

(optional)
-callback observe_identity_verified(#identity_verified{user_id :: m_rsc:resource_id(),
                                                       type :: m_identity:type(),
                                                       key :: m_identity:key()},
                                    z:context()) ->
                                       any().

Notify that a user’s identity has been verified. Signals to modules handling identities to mark this identity as verified. Handled by mod_admin_identity to call the m_identity model for this type/key.

Type:

notify

Return:

#identity_verified{} properties:

  • user_id: m_rsc:resource_id()
  • type: m_identity:type()
  • key: m_identity:key()

observe_import_csv_definition/2

(optional)
-callback observe_import_csv_definition(#import_csv_definition{basename :: binary(),
                                                               filename :: file:filename_all()},
                                        z:context()) ->
                                           Result
                                           when
                                               Result ::
                                                   {ok,
                                                    #import_data_def{colsep :: 0..255,
                                                                     skip_first_row :: boolean(),
                                                                     columns :: list(),
                                                                     importdef ::
                                                                         [#{props => list(),
                                                                            edges => list()}],
                                                                     importstate :: term(),
                                                                     importmodule :: module() | undefined}} |
                                                   ok |
                                                   {error, term()} |
                                                   undefined.

Find an import definition for a CSV file by checking the filename of the to be imported file.

Type:

first

Return:

#import_csv_definition{} or undefined (in which case the column headers are used as property names)

#import_csv_definition{} properties:

  • basename: binary
  • filename: file:filename_all()

observe_import_resource/2

(optional)
-callback observe_import_resource(#import_resource{source :: atom() | binary(),
                                                   source_id :: integer() | binary(),
                                                   source_url :: binary(),
                                                   source_user_id :: binary() | integer(),
                                                   user_id :: integer(),
                                                   name :: binary(),
                                                   props :: m_rsc:props_all(),
                                                   urls :: list(),
                                                   media_urls :: list(),
                                                   data :: any()},
                                  z:context()) ->
                                     Result
                                     when Result :: {ok, m_rsc:resource_id()} | {error, term()} | undefined.

An external feed delivered a resource. First handler can import it. Return:: {ok, m_rsc:resource_id()}, {error, Reason}, or undefined

Type:

first

Return:

#import_resource{} properties:

  • source: atom|binary
  • source_id: integer|binary
  • source_url: binary
  • source_user_id: binary|integer
  • user_id: integer
  • name: binary
  • props: m_rsc:props_all()
  • urls: list
  • media_urls: list
  • data: any

observe_language/2

(optional)
-callback observe_language(#language{language :: atom()}, z:context()) -> any().

Notify that the session’s language has been changed

Type:

notify

Return:

#language{} properties:

  • language: atom

observe_language_detect/2

(optional)
-callback observe_language_detect(#language_detect{text :: binary(), is_editable_only :: boolean()},
                                  z:context()) ->
                                     Result
                                     when Result :: z_language:language_code() | undefined.

Try to detect the language of a translation. Set is_editable_only to false to detect any language, even if the language is not enabled for the site. Return atom() | undefined.

Type:

first

Return:

#language_detect{} properties:

  • text: binary
  • is_editable_only: boolean

observe_logon_options/3

(optional)
-callback observe_logon_options(#logon_options{payload :: #{binary() => term()}}, Acc, Context) -> Result
                                   when Acc :: map(), Context :: z:context(), Result :: map().

Check for logon options, called if logon_submit returns undefined. This is used to fetch external (or local) authentication links for a username. Return:: map()

Type:

foldl

Return:

#logon_options{} properties:

  • payload: map

observe_logon_ready_page/2

(optional)
-callback observe_logon_ready_page(#logon_ready_page{request_page :: binary() | undefined}, z:context()) ->
                                      Result
                                      when Result :: binary() | undefined.

Check where to go after a user logs on.

Type:

first

Return:

a URL or undefined

#logon_ready_page{} properties:

  • request_page: union

observe_logon_submit/2

(optional)
-callback observe_logon_submit(#logon_submit{payload :: #{binary() => term()}}, z:context()) -> Result
                                  when
                                      Result ::
                                          {ok, UserId :: m_rsc:resource_id()} | {error, term()} | undefined.

Handle a user logon. The posted query args are included. Return:: {ok, UserId} or {error, Reason}

Type:

first

Return:

#logon_submit{} properties:

  • payload: map

observe_m_config_update/2

(optional)
-callback observe_m_config_update(#m_config_update{module :: atom(), key :: term(), value :: term()},
                                  z:context()) ->
                                     any().

Site configuration parameter was changed

Type:

notify

Return:

return value is ignored

#m_config_update{} properties:

  • module: atom
  • key: term
  • value: term

observe_m_config_update_prop/2

(optional)
-callback observe_m_config_update_prop(#m_config_update_prop{module :: term(),
                                                             key :: term(),
                                                             prop :: term(),
                                                             value :: term()},
                                       z:context()) ->
                                          any().

Site configuration parameter was changed

Type:

notify

Return:

return value is ignored

#m_config_update_prop{} properties:

  • module: unknown
  • key: unknown
  • prop: unknown
  • value: unknown

observe_mailinglist_mailing/2

(optional)
-callback observe_mailinglist_mailing(#mailinglist_mailing{list_id :: m_rsc:resource() | undefined,
                                                           email :: binary() | string() | undefined,
                                                           page_id :: m_rsc:resource(),
                                                           options ::
                                                               [{is_match_language, boolean()} |
                                                                {is_send_all, boolean()}]},
                                      z:context()) ->
                                         any().

Send a page to a mailinglist (notify) Use {single_test_address, Email} when sending to a specific e-mail address.

Type:

first

Return:

#mailinglist_mailing{} properties:

  • list_id: union
  • email: union
  • page_id: m_rsc:resource()
  • options: list

observe_mailinglist_message/2

(optional)
-callback observe_mailinglist_message(#mailinglist_message{what ::
                                                               send_welcome | send_confirm | send_goodbye |
                                                               silent,
                                                           list_id :: m_rsc:resource(),
                                                           recipient :: proplists:proplist() | integer()},
                                      z:context()) ->
                                         any().

Send a welcome or goodbye message to the given recipient. The recipient is either a recipient-id or a recipient props. ‘what’ is send_welcome, send_confirm, send_goobye or silent.

Type:

notify

Return:

#mailinglist_message{} properties:

  • what: send_welcome|send_confirm|send_goodbye|silent
  • list_id: m_rsc:resource()
  • recipient: proplists:proplist()|integer

observe_media_identify_extension/2

(optional)
-callback observe_media_identify_extension(#media_identify_extension{mime :: binary(),
                                                                     preferred :: undefined | binary()},
                                           z:context()) ->
                                              Result
                                              when Result :: Extension | undefined, Extension :: binary().

Try to find a filename extension for a mime type (example: <<".jpg"\>\>)

Type:

first

Return:

Extension (for example <<".png"\>\>) or undefined

#media_identify_extension{} properties:

  • mime: binary
  • preferred: undefined|binary

observe_media_identify_file/2

(optional)
-callback observe_media_identify_file(#media_identify_file{filename :: file:filename_all(),
                                                           original_filename :: binary(),
                                                           extension :: binary()},
                                      z:context()) ->
                                         Result
                                         when
                                             Result :: MimeData | undefined,
                                             MimeData :: #{binary() => term()}.

Try to identify a file, returning a map with file properties.

Type:

first

Return:

map with binary keys, especially <<"mime"\>\>, <<"width"\>\>, <<"height"\>\>, <<"orientation"\>\>

#media_identify_file{} properties:

  • filename: file:filename_all()
  • original_filename: binary
  • extension: binary

observe_media_import/2

(optional)
-callback observe_media_import(#media_import{url :: binary(),
                                             host_rev :: [binary()],
                                             mime :: binary(),
                                             metadata :: tuple()},
                               z:context()) ->
                                  Result
                                  when
                                      Result ::
                                          #media_import_props{prio :: pos_integer(),
                                                              category :: atom(),
                                                              module :: atom(),
                                                              description :: binary() | z:trans(),
                                                              rsc_props :: map(),
                                                              medium_props :: z_media_identify:media_info(),
                                                              medium_url :: binary(),
                                                              preview_url :: binary() | undefined,
                                                              importer :: atom()} |
                                          [#media_import_props{prio :: pos_integer(),
                                                               category :: atom(),
                                                               module :: atom(),
                                                               description :: binary() | z:trans(),
                                                               rsc_props :: map(),
                                                               medium_props :: z_media_identify:media_info(),
                                                               medium_url :: binary(),
                                                               preview_url :: binary() | undefined,
                                                               importer :: atom()}] |
                                          undefined.

Notification to translate or map a file after upload, before insertion into the database Used in mod_video to queue movies for conversion to mp4. You can set the post_insert_fun to something like fun(Id, Medium, Context) to receive the medium record as it is inserted.

Type:

first

Return:

modified #media_upload_preprocess{}

#media_import{} properties:

  • url: binary
  • host_rev: list
  • mime: binary
  • metadata: tuple

observe_media_import_medium/2

(optional)
-callback observe_media_import_medium(#media_import_medium{id :: m_rsc:resource_id(), medium :: map()},
                                      z:context()) ->
                                         Result
                                         when Result :: ok | {error, term()} | undefined.

Notification to import a medium record from external source. This is called for non-file medium records, for example embedded video. If the medium record is not recognized then it will not be imported. The handling module is responsible for sanitizing and inserting the medium record.

Type:

first

Return:

ok | {error, term()}.

#media_import_medium{} properties:

  • id: m_rsc:resource_id()
  • medium: map

observe_media_preview_options/3

(optional)
-callback observe_media_preview_options(#media_preview_options{id :: m_rsc:resource_id() | undefined,
                                                               width :: non_neg_integer(),
                                                               height :: non_neg_integer(),
                                                               options :: proplists:proplist()},
                                        Acc,
                                        z:context()) ->
                                           Result
                                           when
                                               Acc :: ImageOptions,
                                               Result :: ImageOptions,
                                               ImageOptions :: proplists:proplist().

Modify the options for an image preview url or tag. This is called for every image url generation, except if the ‘original’ image option is passed. The mediaclass in the options is not yet expanded.

Type:

foldl

Return:

modified property list of image options

#media_preview_options{} properties:

  • id: m_rsc:resource_id()|undefined
  • width: non_neg_integer
  • height: non_neg_integer
  • options: proplists:proplist()

observe_media_replace_file/2

(optional)
-callback observe_media_replace_file(#media_replace_file{id :: m_rsc:resource_id(),
                                                         medium :: map() | undefined},
                                     z:context()) ->
                                        any().

Notification that a medium file has been changed (notify) The id is the resource id, medium contains the medium’s complete property map.

Type:

notify

Return:

return value is ignored

#media_replace_file{} properties:

  • id: m_rsc:resource_id()
  • medium: map|undefined

observe_media_stillimage/2

(optional)
-callback observe_media_stillimage(#media_stillimage{id :: m_rsc:resource_id() | undefined,
                                                     props :: z_media_identify:media_info()},
                                   z:context()) ->
                                      Result
                                      when Result :: {ok, m_rsc:resource_id()} | undefined.

See if there is a ‘still’ image preview of a media item. (eg posterframe of a movie) Return:: {ok, ResourceId} or undefined

Type:

first

Return:

#media_stillimage{} properties:

  • id: m_rsc:resource_id()|undefined
  • props: z_media_identify:media_info()

observe_media_update_done/2

(optional)
-callback observe_media_update_done(#media_update_done{action :: insert | update | delete,
                                                       id :: m_rsc:resource_id(),
                                                       pre_is_a :: [atom()],
                                                       post_is_a :: [atom()],
                                                       pre_props :: map() | undefined,
                                                       post_props :: map() | undefined},
                                    z:context()) ->
                                       any().

Media update done notification. action is ‘insert’, ‘update’ or ‘delete’

Type:

notify

Return:

#media_update_done{} properties:

  • action: insert|update|delete
  • id: m_rsc:resource_id()
  • pre_is_a: list
  • post_is_a: list
  • pre_props: map|undefined
  • post_props: map|undefined

observe_media_upload_preprocess/2

(optional)
-callback observe_media_upload_preprocess(#media_upload_preprocess{id :: m_rsc:resource_id() | insert_rsc,
                                                                   mime :: binary(),
                                                                   file :: file:filename_all() | undefined,
                                                                   original_filename ::
                                                                       file:filename_all() | undefined,
                                                                   medium :: z_media_identify:media_info(),
                                                                   post_insert_fun :: function() | undefined},
                                          z:context()) ->
                                             Result
                                             when
                                                 Result ::
                                                     #media_upload_preprocess{id ::
                                                                                  m_rsc:resource_id() |
                                                                                  insert_rsc,
                                                                              mime :: binary(),
                                                                              file ::
                                                                                  file:filename_all() |
                                                                                  undefined,
                                                                              original_filename ::
                                                                                  file:filename_all() |
                                                                                  undefined,
                                                                              medium ::
                                                                                  z_media_identify:media_info(),
                                                                              post_insert_fun ::
                                                                                  function() | undefined} |
                                                     undefined.

Notification to translate or map a file after upload, before insertion into the database Used in mod_video to queue movies for conversion to mp4. You can set the post_insert_fun to something like fun(Id, Medium, Context) to receive the medium record as it is inserted.

Type:

first

Return:

modified #media_upload_preprocess{}

#media_upload_preprocess{} properties:

  • id: union
  • mime: binary
  • file: file:filename_all()|undefined
  • original_filename: file:filename_all()|undefined
  • medium: z_media_identify:media_info()
  • post_insert_fun: function|undefined

observe_media_upload_props/3

(optional)
-callback observe_media_upload_props(#media_upload_props{id :: m_rsc:resource_id() | insert_rsc,
                                                         mime :: binary(),
                                                         archive_file :: file:filename_all() | undefined,
                                                         options :: list()},
                                     Acc,
                                     z:context()) ->
                                        Result
                                        when
                                            Acc :: MediumRecord,
                                            Result :: MediumRecord,
                                            MediumRecord :: #{binary() => term()}.

Notification that a medium file has been uploaded. This is the moment to change properties, modify the file etc. The folded accumulator is the map with updated medium properties.

Type:

foldl

Return:

modified medium properties map

#media_upload_props{} properties:

  • id: m_rsc:resource_id()|insert_rsc
  • mime: binary
  • archive_file: file:filename_all()|undefined
  • options: list

observe_media_upload_rsc_props/3

(optional)
-callback observe_media_upload_rsc_props(#media_upload_rsc_props{id :: m_rsc:resource_id() | insert_rsc,
                                                                 mime :: binary(),
                                                                 archive_file :: term(),
                                                                 options :: list(),
                                                                 medium :: z_media_identify:media_info()},
                                         Acc,
                                         z:context()) ->
                                            Result
                                            when
                                                Acc :: RscProps,
                                                Result :: RscProps,
                                                RscProps :: m_rsc:props().

Notification that a medium file has been uploaded. This is the moment to change resource properties, modify the file etc. The folded accumulator is the map with updated resource properties.

Type:

foldl

Return:

modified resource properties map

#media_upload_rsc_props{} properties:

  • id: m_rsc:resource_id()|insert_rsc
  • mime: binary
  • archive_file: unknown
  • options: list
  • medium: z_media_identify:media_info()

observe_media_viewer/2

(optional)
-callback observe_media_viewer(#media_viewer{id :: term(),
                                             props :: z_media_identify:media_info(),
                                             filename :: file:filename_all() | undefined,
                                             options :: list()},
                               z:context()) ->
                                  Result
                                  when Result :: {ok, HTML} | undefined, HTML :: iodata().

Request to generate a HTML media viewer for a resource. The HTML data can not contain any Javascript, as it might be serialized. This could happen if the correct cookies are not yet set or if the media viewer is part of a direct DOM update.

Type:

first

Return:

{ok, Html} or undefined

#media_viewer{} properties:

  • id: unknown
  • props: z_media_identify:media_info()
  • filename: union
  • options: list

observe_media_viewer_consent/2

(optional)
-callback observe_media_viewer_consent(#media_viewer_consent{id :: m_rsc:resource_id() | undefined,
                                                             consent :: functional | stats | all,
                                                             html :: iodata(),
                                                             viewer_props :: z_media_identify:media_info(),
                                                             viewer_options :: list()},
                                       z:context()) ->
                                          Result
                                          when Result :: {ok, HTML} | undefined, HTML :: iodata().

Optionally wrap HTML with external content so that it adheres to the cookie/privacy settings of the current site visitor. Typically called with a ‘first’ by the code that generated the media viewer HTML, as that code has the knowledge if viewing the generated code has any privacy or cookie implications.

Type:

first

Return:

{ok, HTML} or undefined

#media_viewer_consent{} properties:

  • id: m_rsc:resource_id()|undefined
  • consent: union
  • html: iodata
  • viewer_props: z_media_identify:media_info()
  • viewer_options: list

observe_menu_rsc/2

(optional)
-callback observe_menu_rsc(#menu_rsc{id :: m_rsc:resource()}, z:context()) -> m_rsc:resource() | undefined.

Fetch the menu id belonging to a certain resource

Type:

first

Return:

#menu_rsc{} properties:

  • id: m_rsc:resource()

observe_menu_save/2

(optional)
-callback observe_menu_save(#menu_save{id :: term(), tree :: term()}, z:context()) -> any().

Save the menu tree of a menu resource

Type:

notify

Return:

#menu_save{} properties:

  • id: unknown
  • tree: unknown

observe_middleware/3

(optional)
-callback observe_middleware(#middleware{on :: request | welformed | handled}, Acc, z:context()) -> Result
                                when Acc :: z:context(), Result :: z:context().

Delegates the request processing.

Type:

foldl

Return:

updated z:context()

#middleware{} properties:

  • on: request|welformed|handled

observe_module_activate/2

(optional)
-callback observe_module_activate(#module_activate{module :: atom(), pid :: pid()}, z:context()) -> any().

A module has been activated and started.

Type:

notify

Return:

#module_activate{} properties:

  • module: atom
  • pid: pid

observe_module_deactivate/2

(optional)
-callback observe_module_deactivate(#module_deactivate{module :: atom()}, z:context()) -> any().

A module has been stopped and deactivated.

Type:

notify

Return:

#module_deactivate{} properties:

  • module: atom

observe_module_ready/2

(optional)
-callback observe_module_ready(module_ready, z:context()) -> any().

observe_output_html/3

(optional)
-callback observe_output_html(#output_html{html :: term()}, Acc, z:context()) -> Result
                                 when
                                     Acc :: {MixedHtml, Context},
                                     Result :: {MixedHtml, Context},
                                     Context :: z:context(),
                                     MixedHtml :: binary() | list().

Fold for mapping non-iolist output to iolist values.

Used when outputting a rendered HTML tree. Folded accumulator is: { MixedHtml, Context }

Type:

foldl

Return:

#output_html{} properties:

  • html: term

observe_page_url/2

(optional)
-callback observe_page_url(#page_url{id :: m_rsc:resource_id(), is_a :: [atom()]}, z:context()) ->
                              {ok, binary()} | undefined.

Fetch the url of a resource’s html representation

Type:

first

Return:

{ok, Url} or undefined

#page_url{} properties:

  • id: m_rsc:resource_id()
  • is_a: list

observe_pivot_fields/3

(optional)
-callback observe_pivot_fields(#pivot_fields{id :: m_rsc:resource_id(), raw_props :: m_rsc:props()},
                               Acc,
                               z:context()) ->
                                  Result
                                  when Acc :: #{binary() => term()}, Result :: #{binary() => term()}.

Foldr to change or add pivot fields for the main pivot table. The rsc contains all rsc properties for this resource, including pivot properties. Fold with a map containing the pivot fields.

Type:

foldl

Return:

#pivot_fields{} properties:

  • id: m_rsc:resource_id()
  • raw_props: m_rsc:props()

observe_pivot_rsc_data/3

(optional)
-callback observe_pivot_rsc_data(#pivot_rsc_data{id :: m_rsc:resource_id()}, Acc, z:context()) -> Result
                                    when Acc :: m_rsc:props(), Result :: m_rsc:props().

Fold over the resource props map to extend/remove data to be pivoted

Type:

foldl

Return:

#pivot_rsc_data{} properties:

  • id: m_rsc:resource_id()

observe_pivot_update/3

(optional)
-callback observe_pivot_update(#pivot_update{id :: m_rsc:resource_id(), raw_props :: m_rsc:props()},
                               Acc,
                               z:context()) ->
                                  Result
                                  when Acc :: m_rsc:props(), Result :: m_rsc:props().

Pivot just before a m_rsc_update update. Used to pivot fields before the pivot itself.

Type:

foldr

Return:

#pivot_update{} properties:

  • id: m_rsc:resource_id()
  • raw_props: m_rsc:props()

observe_postback_notify/2

(optional)
-callback observe_postback_notify(#postback_notify{message :: term(),
                                                   trigger :: term(),
                                                   target :: term(),
                                                   data :: term()},
                                  z:context()) ->
                                     Result
                                     when Result :: z:context() | undefined.

Handle a javascript notification from the postback handler. The message is the the request, trigger the id of the element which triggered the postback, and target the id of the element which should receive possible updates. #postback_notify is also used as an event.

Type:

first

Return:

undefined or #context{} with the result of the postback

#postback_notify{} properties:

  • message: unknown
  • trigger: unknown
  • target: unknown
  • data: unknown

observe_request_context/3

(optional)
-callback observe_request_context(#request_context{phase :: init | refresh | auth_status, document :: map()},
                                  Acc,
                                  z:context()) ->
                                     Result
                                     when Acc :: z:context(), Result :: z:context().

Refresh the context or request process for the given request or action

Called for every request that is not anonymous and before every MQTT relay from the client. Example: mod_development uses this to set flags in the process dictionary.

Type:

foldl

Return:

#context{}

#request_context{} properties:

  • phase: union
  • document: map

observe_resource_headers/3

(optional)
-callback observe_resource_headers(#resource_headers{id :: m_rsc:resource_id() | undefined}, Acc, Context) ->
                                      Result
                                      when
                                          Acc :: [{binary(), binary()}],
                                          Context :: z:context(),
                                          Result :: [{binary(), binary()}].

Let all modules add resource specific response headers to the request. The accumulator is the list of headers to be set.

Type:

foldl

Return:

list( {binary(), binary()} )

#resource_headers{} properties:

  • id: m_rsc:resource_id()|undefined

observe_rsc_delete/2

(optional)
-callback observe_rsc_delete(#rsc_delete{id :: m_rsc:resource_id(), is_a :: [atom()]}, z:context()) -> any().

Resource will be deleted. This notification is part of the delete transaction, it’s purpose is to clean up associated data.

Type:

notify

Return:

#rsc_delete{} properties:

  • id: m_rsc:resource_id()
  • is_a: list

observe_rsc_get/3

(optional)
-callback observe_rsc_get(#rsc_get{id :: m_rsc:resource_id()}, Acc, z:context()) -> Result
                             when Acc :: m_rsc:props(), Result :: map().

Resource is read, opportunity to add computed fields Used in a foldr with the read properties as accumulator.

Type:

foldr

Return:

#rsc_get{} properties:

  • id: m_rsc:resource_id()

observe_rsc_import_fetch/2

(optional)
-callback observe_rsc_import_fetch(#rsc_import_fetch{uri :: binary()}, z:context()) -> Result
                                      when
                                          Result ::
                                              {ok, map()} |
                                              {ok, m_rsc:resource_id()} |
                                              {ok, {m_rsc:resource_id(), map()}} |
                                              {error, term()} |
                                              undefined.

Fetch the data for an import of a resource. Returns data in the format used by m_rsc_export and m_rsc_import. Either returns the JSON data, the imported resource id, or the resource id and a map with a mapping from URIs to resource ids.

Type:

first

Return:

{ok, map()} | {ok, m_rsc:resource_id()} | {ok, {m_rsc:resource_id(), map()}} | {error, term()} | undefined

#rsc_import_fetch{} properties:

  • uri: binary

observe_rsc_insert/3

(optional)
-callback observe_rsc_insert(#rsc_insert{props :: m_rsc:props()}, Acc, z:context()) -> Result
                                when Acc :: m_rsc:props(), Result :: m_rsc:props().

Foldr for a resource insert, these are the initial properties and will overrule the properties in the insert request. Use with care. The props are the properties of the later insert, after escaping/filtering but before the #rsc_update{} notification below.

Type:

foldr

Return:

proplist accumulator

#rsc_insert{} properties:

  • props: m_rsc:props()

observe_rsc_merge/2

(optional)
-callback observe_rsc_merge(#rsc_merge{winner_id :: m_rsc:resource_id(),
                                       loser_id :: m_rsc:resource_id(),
                                       is_merge_trans :: boolean()},
                            z:context()) ->
                               any().

Map to signal merging two resources. Move any information from the loser to the winner. The loser will be deleted.

Type:

notify_sync

Return:

#rsc_merge{} properties:

  • winner_id: m_rsc:resource_id()
  • loser_id: m_rsc:resource_id()
  • is_merge_trans: boolean

observe_rsc_pivot_done/2

(optional)
-callback observe_rsc_pivot_done(#rsc_pivot_done{id :: m_rsc:resource_id(), is_a :: [atom()]}, z:context()) ->
                                    any().

Signal that a resource pivot has been done.

Type:

notify

Return:

#rsc_pivot_done{} properties:

  • id: m_rsc:resource_id()
  • is_a: list

observe_rsc_query_item/2

(optional)
-callback observe_rsc_query_item(#rsc_query_item{query_id :: m_rsc:resource_id(),
                                                 match_id :: m_rsc:resource_id()},
                                 z:context()) ->
                                    any().

Send a notification that the resource ‘id’ is added to the query query_id.

Type:

notify

Return:

return value is ignored

#rsc_query_item{} properties:

  • query_id: m_rsc:resource_id()
  • match_id: m_rsc:resource_id()

observe_rsc_update/3

(optional)
-callback observe_rsc_update(#rsc_update{action :: insert | update,
                                         id :: m_rsc:resource_id(),
                                         props :: m_rsc:props()},
                             Acc,
                             z:context()) ->
                                Result
                                when
                                    Acc :: {ok, map()} | {error, term()},
                                    Result :: {ok, map()} | {error, term()}.

An updated resource is about to be persisted. Observe this notification to change the resource properties before they are persisted.

The props are the resource’s props _before_ the update, but _after_ filtering and sanitization. The folded value is {ok, UpdateProps} for the update itself.

Type:

foldr

Return:

{ok, UpdateProps} or {error, term()}

#rsc_update{} properties:

  • action: insert|update
  • id: m_rsc:resource_id()
  • props: m_rsc:props()

An updated resource is about to be persisted. Observe this notification to change the resource properties before they are persisted.

Arguments

#rsc_update

action

Either insert or update.

id

Id of the resource.

props

Map with resource properties.

{ok, UpdateProps} | {error, Reason}

And/remove resource properties before the update is persisted.

Context

Site context

Example

Add a property before the resource is persisted:

observe_rsc_update(#rsc_update{action = insert, id = Id}, {ok, Props}, Context) ->
    %% Set an extra property
    {ok, Props#{ <<"extra_property">> => <<"special value!">> }}.
observe_rsc_update(#rsc_update{action = insert, id = Id}, {error, _} = Error, Context) ->
    Error.

observe_rsc_update_done/2

(optional)
-callback observe_rsc_update_done(#rsc_update_done{action :: insert | update | delete,
                                                   id :: m_rsc:resource_id(),
                                                   pre_is_a :: list(),
                                                   post_is_a :: list(),
                                                   pre_props :: m_rsc:props(),
                                                   post_props :: m_rsc:props()},
                                  z:context()) ->
                                     any().

An updated resource has just been persisted. Observe this notification to execute follow-up actions for a resource update.

Type:

notify

Return:

return value is ignored

#rsc_update_done{} properties:

  • action: insert|update|delete
  • id: m_rsc:resource_id()
  • pre_is_a: list
  • post_is_a: list
  • pre_props: m_rsc:props()
  • post_props: m_rsc:props()

pre_is_a

List of resource categories before the update.

post_is_a

List of resource categories after the update.

pre_props

Map of properties before the update.

post_props

Map of properties after the update.

Example

Add some default edges when a resource is created:

observe_rsc_update_done(#rsc_update_done{action = insert, id = Id, post_is_a = PostIsA, post_props = Props}, Context) ->
    case lists:member(activity, PostIsA) of
        false ->
            ok;
        true ->
            m_my_rsc:create_default_edges(Id, Context),
            ok
    end;
observe_rsc_update_done(#rsc_update_done{}, _Context) ->
    %% Fall through
    ok.

observe_rsc_upload/2

(optional)
-callback observe_rsc_upload(#rsc_upload{id :: m_rsc:resource() | undefined,
                                         format :: json | bert,
                                         data :: binary() | map()},
                             z:context()) ->
                                Result
                                when
                                    Result ::
                                        {ok, m_rsc:resource_id()} | {error, badarg | term()} | undefined.

Upload and replace the resource with the given data. The data is in the given format.

Type:

first

Return:

{ok, Id} or {error, Reason}, return {error, badarg} when the data is corrupt.

#rsc_upload{} properties:

  • id: m_rsc:resource()|undefined
  • format: json|bert
  • data: binary|map

observe_sanitize_element/3

(optional)
-callback observe_sanitize_element(#sanitize_element{element :: {binary(), [{binary(), binary()}], list()},
                                                     stack :: list()},
                                   Acc,
                                   z:context()) ->
                                      Result
                                      when
                                          Acc :: Element,
                                          Result :: Element,
                                          Element :: {binary(), [{binary(), binary()}], list()}.

Sanitize an HTML element.

Type:

foldl

Return:

#sanitize_element{} properties:

  • element: tuple
  • stack: list

observe_sanitize_embed_url/2

(optional)
-callback observe_sanitize_embed_url(#sanitize_embed_url{hostpath :: binary()}, z:context()) -> URL
                                        when URL :: undefined | binary().

Sanitize an embed url. The hostpart is of the format: <<"youtube.com/v..."\>\>.

Type:

first

Return:

undefined, false or a binary with a acceptable hostpath

#sanitize_embed_url{} properties:

  • hostpath: binary

This notification is used to sanitize embed urls passed with the media import routines.

Example usage in a module, where URLs from some public broadcasters are allowed:

-export([
    observe_sanitize_embed_url/2
]).

observe_sanitize_embed_url(#sanitize_embed_url{hostpath= <<"media.vara.nl/", _/binary>> = Url}, _Context) ->
    Url;
observe_sanitize_embed_url(#sanitize_embed_url{hostpath= <<"biografie.vara.nl/", _/binary>> = Url}, _Context) ->
    Url;
observe_sanitize_embed_url(#sanitize_embed_url{hostpath= <<"js.vpro.nl/", _/binary>> = Url}, _Context) ->
    Url;
observe_sanitize_embed_url(#sanitize_embed_url{hostpath= <<"embed.vpro.nl/", _/binary>> = Url}, _Context) ->
    Url;
observe_sanitize_embed_url(_, _Context) ->
    undefined.

Note the undefined returned if no other patterns match. This allows other modules to check for different patterns.

observe_scomp_script_render/2

(optional)
-callback observe_scomp_script_render(#scomp_script_render{is_nostartup :: boolean(), args :: list()},
                                      z:context()) ->
                                         iodata().

Add extra javascript with the {% script %} tag. (map) Used to let modules inject extra javascript depending on the arguments of the {% script %} tag. Must return an iolist()

Type:

map

Return:

#scomp_script_render{} properties:

  • is_nostartup: boolean
  • args: list

observe_search_query/2

(optional)
-callback observe_search_query(#search_query{name :: binary() | undefined,
                                             args :: map() | undefined,
                                             offsetlimit ::
                                                 {Offset :: pos_integer(), Limit :: pos_integer()},
                                             options :: z_search:search_options(),
                                             search ::
                                                 {SearchName :: atom(), SearchProps :: list()} | undefined},
                               z:context()) ->
                                  Result
                                  when
                                      Result ::
                                          #search_sql{select :: iodata(),
                                                      from :: iodata(),
                                                      where :: iodata(),
                                                      order :: iodata(),
                                                      group_by :: iodata(),
                                                      limit :: term(),
                                                      tables :: list(),
                                                      args :: list(),
                                                      cats :: list(),
                                                      cats_exclude :: list(),
                                                      cats_exact :: list(),
                                                      run_func :: function() | undefined,
                                                      post_func ::
                                                          fun((#search_result{search_name ::
                                                                                  binary() | atom(),
                                                                              search_args ::
                                                                                  map() |
                                                                                  proplists:proplist(),
                                                                              result :: list(),
                                                                              page :: pos_integer(),
                                                                              pagelen ::
                                                                                  pos_integer() | undefined,
                                                                              options ::
                                                                                  z_search:search_options(),
                                                                              total ::
                                                                                  non_neg_integer() |
                                                                                  undefined,
                                                                              pages ::
                                                                                  non_neg_integer() |
                                                                                  undefined,
                                                                              is_total_estimated ::
                                                                                  boolean(),
                                                                              next :: pos_integer() | false,
                                                                              prev :: pos_integer(),
                                                                              facets ::
                                                                                  #{binary() => map()} |
                                                                                  undefined},
                                                               #search_sql{},
                                                               z:context()) ->
                                                                  #search_result{search_name ::
                                                                                     binary() | atom(),
                                                                                 search_args ::
                                                                                     map() |
                                                                                     proplists:proplist(),
                                                                                 result :: list(),
                                                                                 page :: pos_integer(),
                                                                                 pagelen ::
                                                                                     pos_integer() |
                                                                                     undefined,
                                                                                 options ::
                                                                                     z_search:search_options(),
                                                                                 total ::
                                                                                     non_neg_integer() |
                                                                                     undefined,
                                                                                 pages ::
                                                                                     non_neg_integer() |
                                                                                     undefined,
                                                                                 is_total_estimated ::
                                                                                     boolean(),
                                                                                 next ::
                                                                                     pos_integer() | false,
                                                                                 prev :: pos_integer(),
                                                                                 facets ::
                                                                                     #{binary() => map()} |
                                                                                     undefined}) |
                                                          undefined,
                                                      extra :: list(),
                                                      assoc :: boolean(),
                                                      search_sql_terms :: list() | undefined} |
                                          #search_result{search_name :: binary() | atom(),
                                                         search_args :: map() | proplists:proplist(),
                                                         result :: list(),
                                                         page :: pos_integer(),
                                                         pagelen :: pos_integer() | undefined,
                                                         options :: z_search:search_options(),
                                                         total :: non_neg_integer() | undefined,
                                                         pages :: non_neg_integer() | undefined,
                                                         is_total_estimated :: boolean(),
                                                         next :: pos_integer() | false,
                                                         prev :: pos_integer(),
                                                         facets :: #{binary() => map()} | undefined} |
                                          list() |
                                          undefined.

Map a custom search term to a #search_sql_term{} record.

Type:

first

Return:

#search_sql_term{}, [], or undefined

#search_query{} properties:

  • name: union
  • args: union
  • offsetlimit: tuple
  • unknown: unknown
  • search: union

See also

Custom search, Search

observe_search_query_term/2

(optional)
-callback observe_search_query_term(#search_query_term{term :: binary(), arg :: any()}, z:context()) ->
                                       Result
                                       when
                                           Result ::
                                               #search_sql_term{label :: term(),
                                                                select :: term(),
                                                                tables :: term(),
                                                                join_inner :: term(),
                                                                join_left :: term(),
                                                                where :: term(),
                                                                sort :: term(),
                                                                asort :: term(),
                                                                zsort :: term(),
                                                                cats :: term(),
                                                                cats_exclude :: term(),
                                                                cats_exact :: term(),
                                                                extra :: term(),
                                                                args :: term()} |
                                               QueryTerm |
                                               [QueryTerm] |
                                               undefined,
                                           QueryTerm :: #{binary() => term()}.

Map a custom search term to a #search_sql_term{} record.

Type:

first

Return:

#search_sql_term{}, [], or undefined

#search_query_term{} properties:

  • term: binary
  • arg: any

observe_security_headers/2

(optional)
-callback observe_security_headers(#security_headers{headers :: [{binary(), binary()}]}, z:context()) ->
                                      Result
                                      when
                                          Result ::
                                              #security_headers{headers :: [{binary(), binary()}]} |
                                              undefined.

Check and possibly modify the http response security headers All headers are in lowercase.

Type:

first

Return:

#security_headers{} properties:

  • headers: list

This is called when the security headers are set for the request, which is done at the start of the request handling, before any controller callback is called.

That is done so early to ensure that any returned payload has all required security headers.

The default security header list is:

[
    % Content-Security-Policy is not added by default
    % {<<"content-security-policy">>, <<"script-src 'self' 'nonce-'">>}
    {<<"x-xss-protection">>, <<"1">>},
    {<<"x-content-type-options">>, <<"nosniff">>},
    {<<"x-permitted-cross-domain-policies">>, <<"none">>},
    {<<"referrer-policy">>, <<"strict-origin-when-cross-origin">>},
    {<<"x-frame-options">>, <<"sameorigin">>}
]

If the controller option allow_frame is set to true then the x-frame-options header is not added.

The security_headers notification does a first to fetch the security headers. The default headers are passed in the headers field of the notification.

If the notification returns a list with <<"content-security-policy"\>\> then in the value of the Content-Security-Policy header the string 'nonce-' is replaced with the unique nonce for the request.

The nonce can de added to script tags:

<script type="text/javascript" nonce="{{ m.req.csp_nonce }}">
    // Inline javascript here
</script>

It can be requested in Erlang code using:

CSPNonce = z_context:csp_nonce(Context).

Or via the m_req model:

CSPNonce = m_req:get(csp_nonce, Context).

Note that the nonce is only set iff the Context is a HTTP request context. It is not set for MQTT contexts.

observe_session_context/3

(optional)
-callback observe_session_context(#session_context{request_type :: http | mqtt,
                                                   payload :: undefined | term()},
                                  Acc,
                                  z:context()) ->
                                     Result
                                     when Acc :: z:context(), Result :: z:context().

Refresh the context or request process for the given request or action

Called for every request that is not anonymous and before every MQTT relay from the client. Example: mod_development uses this to set flags in the process dictionary.

Type:

foldl

Return:

#context{}

#session_context{} properties:

  • request_type: http|mqtt
  • payload: union

observe_set_user_language/2

(optional)
-callback observe_set_user_language(#set_user_language{id :: m_rsc:resource_id()}, z:context()) ->
                                       z:context() | undefined.

Set the language of the context to a user’s prefered language

Type:

first

Return:

#set_user_language{} properties:

  • id: m_rsc:resource_id()

observe_signup/2

(optional)
-callback observe_signup(#signup{id :: m_rsc:resource_id() | undefined,
                                 props :: map(),
                                 signup_props :: list(),
                                 request_confirm :: boolean()},
                         z:context()) ->
                            Result
                            when Result :: {ok, UserId :: m_rsc:resource_id()} | {error, term()} | undefined.

Request a signup of a new or existing user. Arguments are similar to #signup_url{} Returns {ok, UserId} or {error, Reason}

Type:

first

Return:

#signup{} properties:

  • id: m_rsc:resource_id()|undefined
  • props: map
  • signup_props: list
  • request_confirm: boolean

observe_signup_check/3

(optional)
-callback observe_signup_check(signup_check, Acc, Context) -> Result
                                  when
                                      Acc :: {ok, Props, SignupProps} | {error, term()},
                                      Context :: z:context(),
                                      Result :: {ok, Props, SignupProps} | {error, term()},
                                      Props :: map(),
                                      SignupProps :: list().

signup_check Check if the signup can be handled, a fold over all modules. Fold argument/result is {ok, Props, SignupProps} or {error, Reason}

Type:

foldl

Return:

{ok, Props, SignupProps} or {error, Reason}

#signup_check{} properties:

  • props: map
  • signup_props: list

observe_signup_confirm/2

(optional)
-callback observe_signup_confirm(#signup_confirm{id :: m_rsc:resource()}, z:context()) -> any().

Signal that a user has been confirmed. (map, result is ignored)

Type:

notify

Return:

#signup_confirm{} properties:

  • id: m_rsc:resource()

observe_signup_confirm_redirect/2

(optional)
-callback observe_signup_confirm_redirect(#signup_confirm_redirect{id :: m_rsc:resource()}, z:context()) ->
                                             Result
                                             when Result :: URL | undefined, URL :: binary().

Fetch the page a user is redirected to after signing up with a confirmed identity

Type:

first

Return:

a URL or undefined

#signup_confirm_redirect{} properties:

  • id: m_rsc:resource()

observe_signup_done/2

(optional)
-callback observe_signup_done(#signup_done{id :: m_rsc:resource(),
                                           is_verified :: boolean(),
                                           props :: map(),
                                           signup_props :: list()},
                              z:context()) ->
                                 any().

Signal that a user has been signed up (map, result is ignored)

Type:

map

Return:

#signup_done{} properties:

  • id: m_rsc:resource()
  • is_verified: boolean
  • props: map
  • signup_props: list

observe_signup_failed_url/2

(optional)
-callback observe_signup_failed_url(#signup_failed_url{reason :: term()}, z:context()) -> Result
                                       when Result :: {ok, Url :: binary()} | undefined.

Signup failed, give the error page URL. Return {ok, Url} or undefined. Reason is returned by the signup handler for the particular signup method (username, facebook etc)

Type:

first

Return:

#signup_failed_url{} properties:

  • reason: unknown

observe_signup_url/2

(optional)
-callback observe_signup_url(#signup_url{props :: map(), signup_props :: list()}, z:context()) -> Result
                                when Result :: {ok, Url :: binary()} | undefined.

Handle a signup of a user, return the follow on page for after the signup. Return {ok, Url} ‘props’ is a map with properties for the person resource (email, name, etc) ‘signup_props’ is a proplist with ‘identity’ definitions and optional follow on url ‘ready_page’ An identity definition is {Kind, Identifier, IsUnique, IsVerified}

Type:

first

Return:

#signup_url{} properties:

  • props: map
  • signup_props: list

observe_ssl_options/2

(optional)
-callback observe_ssl_options(#ssl_options{server_name :: binary()}, z:context()) -> SSLOptions | undefined
                                 when SSLOptions :: {ok, [ssl:tls_option()]}.

Request the SSL certificates for this site. The server_name property contains the hostname used by the client. (first) Returns either ‘undefined’ or a list of ssl options (type ssl:ssl_option())

Type:

first

Return:

#ssl_options{} properties:

  • server_name: binary

observe_survey_get_handlers/3

(optional)
-callback observe_survey_get_handlers(#survey_get_handlers{}, Acc, z:context()) -> Result
                                         when
                                             Acc :: Handlers,
                                             Result :: Handlers,
                                             Handlers :: [{HandlerName, DisplayTitle}],
                                             HandlerName :: atom(),
                                             DisplayTitle :: binary().

Fetch list of handlers for survey submits.

Type:

foldr

Return:

list with tuples: [ {handler_name, TitleForDisplay}, ... ]

#survey_get_handlers{} properties: none

observe_survey_is_allowed_results_download/2

(optional)
-callback observe_survey_is_allowed_results_download(#survey_is_allowed_results_download{id ::
                                                                                             m_rsc:resource_id()},
                                                     z:context()) ->
                                                        Result
                                                        when Result :: boolean() | undefined.

Check if the current user is allowed to download a survey.

Type:

first

Return:

true, false or undefined

#survey_is_allowed_results_download{} properties:

  • id: m_rsc:resource_id()

observe_survey_is_submit/2

(optional)
-callback observe_survey_is_submit(#survey_is_submit{block :: map()}, z:context()) -> Result
                                      when Result :: boolean() | undefined.

Check if a question (page block) is a submitting question.

Type:

first

Return:

true, false or undefined

#survey_is_submit{} properties:

  • block: map

observe_survey_result_column_values/3

(optional)
-callback observe_survey_result_column_values(#survey_result_column_values{id :: m_rsc:resource_id(),
                                                                           handler :: binary() | undefined,
                                                                           format :: html | text,
                                                                           user_id :: m_rsc:resource_id(),
                                                                           answer :: proplists:proplist(),
                                                                           columns ::
                                                                               [{binary(),
                                                                                 binary() |
                                                                                 #trans{tr ::
                                                                                            [{atom(),
                                                                                              binary()}]}}]},
                                              Acc,
                                              z:context()) ->
                                                 Result
                                                 when
                                                     Acc :: ColumnValues,
                                                     Result :: ColumnValues,
                                                     ColumnValues :: #{QuestionName => Value},
                                                     QuestionName :: binary(),
                                                     Value :: iodata().

Modify row with answers for export. The header columns are given and the values that are known are set in the folded value. The user_id is the user who filled in the answers for this row.

Type:

foldl

Return:

#{ binary() =\> iodata() }

#survey_result_column_values{} properties:

  • id: m_rsc:resource_id()
  • handler: binary|undefined
  • format: html|text
  • user_id: m_rsc:resource_id()
  • answer: proplists:proplist()
  • columns: list

observe_survey_result_columns/3

(optional)
-callback observe_survey_result_columns(#survey_result_columns{id :: m_rsc:resource_id(),
                                                               handler :: binary() | undefined,
                                                               format :: html | text},
                                        Acc,
                                        z:context()) ->
                                           Result
                                           when
                                               Acc :: Columns,
                                               Result :: Columns,
                                               Columns :: [{QuestionName, Title}],
                                               QuestionName :: binary(),
                                               Title :: binary() | z:trans().

Add header columns for export. The values are the names of the answers and the text displayed above the column. The text format is for a complete export, the html format is for the limited result overview of the Survey Results Editor.

Type:

foldl

Return:

list( {binary(), binary() | #trans{}} )

#survey_result_columns{} properties:

  • id: m_rsc:resource_id()
  • handler: binary|undefined
  • format: html|text

observe_survey_submit/2

(optional)
-callback observe_survey_submit(#survey_submit{id :: m_rsc:resource_id(),
                                               handler :: binary() | undefined,
                                               answers :: list(),
                                               missing :: list(),
                                               answers_raw :: list(),
                                               submit_args :: proplists:proplist()},
                                z:context()) ->
                                   Result
                                   when
                                       Result ::
                                           ok |
                                           {ok,
                                            z:context() |
                                            #render{template :: template_compiler:template(),
                                                    is_all :: boolean(),
                                                    vars :: proplists:proplist()}} |
                                           {save,
                                            z:context() |
                                            #render{template :: template_compiler:template(),
                                                    is_all :: boolean(),
                                                    vars :: proplists:proplist()}} |
                                           {error, term()} |
                                           undefined.

A survey has been filled in and submitted.

Type:

first

Return:

undefined, ok, {ok, Context | #render{}}, {save, Context | #render{} or {error, term()}

#survey_submit{} properties:

  • id: m_rsc:resource_id()
  • handler: binary|undefined
  • answers: list
  • missing: list
  • answers_raw: list
  • submit_args: proplists:proplist()

observe_tkvstore_delete/2

(optional)
-callback observe_tkvstore_delete(#tkvstore_delete{type :: term(), key :: term()}, z:context()) -> any().

Delete a value from the typed key/value store

Type:

notify

Return:

return value is ignored

#tkvstore_delete{} properties:

  • type: unknown
  • key: unknown

observe_tkvstore_get/2

(optional)
-callback observe_tkvstore_get(#tkvstore_get{type :: term(), key :: term()}, z:context()) ->
                                  term() | undefined.

Get a value from the typed key/value store

Type:

first

Return:

#tkvstore_get{} properties:

  • type: unknown
  • key: unknown

observe_tkvstore_put/2

(optional)
-callback observe_tkvstore_put(#tkvstore_put{type :: term(), key :: term(), value :: term()}, z:context()) ->
                                  ok | undefined.

Put a value into the typed key/value store

Type:

first

Return:

#tkvstore_put{} properties:

  • type: unknown
  • key: unknown
  • value: unknown

observe_translate/2

(optional)
-callback observe_translate(#translate{from :: atom(), to :: atom(), texts :: [binary()]}, z:context()) ->
                               Result
                               when
                                   Result :: {ok, Translations} | {error, term()} | undefined,
                                   Translations :: [{binary(), undefined | binary()}].

Request a translation of a list of strings. The resulting translations must be in the same order as the request. This notification is handled by modules that interface to external translation services like DeepL or Google Translate. Return {ok, List} | {error, Reason} | undefined.

Type:

first

Return:

#translate{} properties:

  • from: atom
  • to: atom
  • texts: list

observe_url_abs/2

(optional)
-callback observe_url_abs(#url_abs{url :: term(), dispatch :: term(), dispatch_options :: term()},
                          z:context()) ->
                             URL | undefined
                             when URL :: binary().

Make a generated URL absolute, optionally called after url_rewrite by z_dispatcher

Type:

first

Return:

#url_abs{} properties:

  • url: unknown
  • dispatch: unknown
  • dispatch_options: unknown

observe_url_fetch_options/2

(optional)
-callback observe_url_fetch_options(#url_fetch_options{method :: get | post | put | delete,
                                                       host :: binary(),
                                                       url :: binary(),
                                                       options :: z_url_fetch:options()},
                                    z:context()) ->
                                       Result
                                       when Result :: z_url_fetch:options() | undefined.

Determine the URL fetch options for fetching the content of an URL. Used by z_fetch.erl.

Type:

first

Return:

z_url_fetch:options()

#url_fetch_options{} properties:

  • method: get|post|put|delete
  • host: binary
  • url: binary
  • options: z_url_fetch:options()

observe_url_rewrite/3

(optional)
-callback observe_url_rewrite(#url_rewrite{dispatch :: atom(), args :: list()}, Acc, z:context()) -> Result
                                 when Acc :: binary(), Result :: binary().

Rewrite a URL after it has been generated using the z_dispatcher

Type:

foldl

Return:

#url_rewrite{} properties:

  • dispatch: atom
  • args: list

observe_user_context/3

(optional)
-callback observe_user_context(#user_context{id :: m_rsc:resource_id()}, Acc, z:context()) -> Result
                                  when Acc :: z:context(), Result :: z:context().

Set #context fields depending on the user and/or the preferences of the user.

Type:

foldl

Return:

#user_context{} properties:

  • id: m_rsc:resource_id()

observe_user_is_enabled/2

(optional)
-callback observe_user_is_enabled(#user_is_enabled{id :: m_rsc:resource_id()}, z:context()) ->
                                     boolean() | undefined.

Check if a user is enabled. Enabled users are allowed to log in. Return true, false or undefined. If undefined is returned, the user is considered enabled if the user resource is published.

Type:

first

Return:

#user_is_enabled{} properties:

  • id: m_rsc:resource_id()

observe_validate_query_args/3

(optional)
-callback observe_validate_query_args(#validate_query_args{}, Acc, z:context()) -> Result
                                         when
                                             Acc :: {ok, Args} | {error, term()},
                                             Result :: {ok, Args} | {error, term()},
                                             Args :: [{binary(), z:qvalue()}].

Called just before validation of all query arguments by z_validation.

This is the moment to filter any illegal arguments or change query arguments.

Type:

foldl

Return:

{ok, list( {binary(), z:qvalue()} )} | {error, term()}

#validate_query_args{} properties: none

pid_observe_acl_collab_groups_modify/4

(optional)
-callback pid_observe_acl_collab_groups_modify(pid(),
                                               #acl_collab_groups_modify{id ::
                                                                             m_rsc:resource_id() | undefined,
                                                                         groups :: [m_rsc:resource_id()]},
                                               Acc,
                                               z:context()) ->
                                                  Groups
                                                  when Acc :: Groups, Groups :: [m_rsc:resource_id()].

pid_observe_acl_context_authenticated/3

(optional)
-callback pid_observe_acl_context_authenticated(pid(), #acl_context_authenticated{}, z:context()) ->
                                                   z:context() | undefined.

pid_observe_acl_is_allowed/3

(optional)
-callback pid_observe_acl_is_allowed(pid(),
                                     #acl_is_allowed{action ::
                                                         view | update | delete | insert | use | atom(),
                                                     object :: term()},
                                     z:context()) ->
                                        boolean() | undefined.

pid_observe_acl_is_allowed_prop/3

(optional)
-callback pid_observe_acl_is_allowed_prop(pid(),
                                          #acl_is_allowed_prop{action ::
                                                                   view | update | delete | insert | atom(),
                                                               object :: term(),
                                                               prop :: binary()},
                                          z:context()) ->
                                             boolean() | undefined.

pid_observe_acl_is_owner/3

(optional)
-callback pid_observe_acl_is_owner(pid(),
                                   #acl_is_owner{id :: m_rsc:resource_id(),
                                                 creator_id :: m_rsc:resource_id(),
                                                 user_id :: m_rsc:resource_id()},
                                   z:context()) ->
                                      boolean() | undefined.

pid_observe_acl_logoff/3

(optional)
-callback pid_observe_acl_logoff(pid(), #acl_logoff{}, z:context()) -> z:context() | undefined.

pid_observe_acl_logon/3

(optional)
-callback pid_observe_acl_logon(pid(), #acl_logon{id :: m_rsc:resource_id(), options :: map()}, z:context()) ->
                                   z:context() | undefined.

pid_observe_acl_user_groups/3

(optional)
-callback pid_observe_acl_user_groups(pid(), #acl_user_groups{}, z:context()) -> Groups | undefined
                                         when Groups :: [m_rsc:resource_id()].

pid_observe_acl_user_groups_modify/4

(optional)
-callback pid_observe_acl_user_groups_modify(pid(),
                                             #acl_user_groups_modify{id :: m_rsc:resource_id() | undefined,
                                                                     groups :: [m_rsc:resource_id()]},
                                             Acc,
                                             z:context()) ->
                                                Groups
                                                when Acc :: Groups, Groups :: [m_rsc:resource_id()].

pid_observe_action_event_type/3

(optional)
-callback pid_observe_action_event_type(pid(),
                                        #action_event_type{event :: tuple(),
                                                           trigger_id :: string(),
                                                           trigger :: string(),
                                                           postback_js :: iolist(),
                                                           postback_pickled :: string() | binary(),
                                                           action_js :: iolist()},
                                        z:context()) ->
                                           Result
                                           when
                                               Result :: {ok, Javascript, z:context()} | undefined,
                                               Javascript :: iodata().

pid_observe_activity/3

(optional)
-callback pid_observe_activity(pid(),
                               #activity{version :: pos_integer(),
                                         posted_time :: term(),
                                         actor :: term(),
                                         verb :: atom(),
                                         object :: term(),
                                         target :: term()},
                               z:context()) ->
                                  Patterns
                                  when Patterns :: [term()].

pid_observe_activity_send/3

(optional)
-callback pid_observe_activity_send(pid(),
                                    #activity_send{recipient_id :: term(),
                                                   channel :: term(),
                                                   queue :: term(),
                                                   activities ::
                                                       [#activity{version :: pos_integer(),
                                                                  posted_time :: term(),
                                                                  actor :: term(),
                                                                  verb :: atom(),
                                                                  object :: term(),
                                                                  target :: term()}]},
                                    z:context()) ->
                                       undefined | ok.

pid_observe_admin_edit_blocks/4

(optional)
-callback pid_observe_admin_edit_blocks(pid(),
                                        #admin_edit_blocks{id :: m_rsc:resource_id()},
                                        Acc,
                                        z:context()) ->
                                           Result
                                           when
                                               Acc :: BlockGroups,
                                               Result :: BlockGroups,
                                               BlockGroups :: [{Prio, SectionTitle, BlockTypes}],
                                               Prio :: integer(),
                                               SectionTitle :: binary() | string() | z:trans(),
                                               BlockTypes :: [{atom(), binary() | string() | z:trans()}].

pid_observe_admin_menu/4

(optional)
-callback pid_observe_admin_menu(pid(), #admin_menu{}, Acc, z:context()) -> Result
                                    when Acc :: MenuItems, Result :: MenuItems, MenuItems :: [term()].

pid_observe_admin_rscform/4

(optional)
-callback pid_observe_admin_rscform(pid(),
                                    #admin_rscform{id :: m_rsc:resource_id(), is_a :: [atom()]},
                                    Acc,
                                    z:context()) ->
                                       Result
                                       when Acc :: Props, Result :: Props, Props :: [{binary(), z:qvalue()}].

pid_observe_auth_checked/3

(optional)
-callback pid_observe_auth_checked(pid(),
                                   #auth_checked{id :: undefined | m_rsc:resource_id(),
                                                 username :: binary(),
                                                 is_accepted :: boolean()},
                                   z:context()) ->
                                      any().

pid_observe_auth_client_logon_user/3

(optional)
-callback pid_observe_auth_client_logon_user(pid(),
                                             #auth_client_logon_user{user_id :: m_rsc:resource_id(),
                                                                     url :: binary() | undefined},
                                             z:context()) ->
                                                Result
                                                when Result :: ok | {error, term()} | undefined.

pid_observe_auth_client_switch_user/3

(optional)
-callback pid_observe_auth_client_switch_user(pid(),
                                              #auth_client_switch_user{user_id :: m_rsc:resource_id()},
                                              z:context()) ->
                                                 Result
                                                 when Result :: ok | {error, term()} | undefined.

pid_observe_auth_confirm/4

(optional)
-callback pid_observe_auth_confirm(pid(), #auth_confirm{id :: m_rsc:resource_id()}, Acc, z:context()) ->
                                      Result
                                      when Acc :: z:context(), Result :: z:context().

pid_observe_auth_confirm_done/3

(optional)
-callback pid_observe_auth_confirm_done(pid(), #auth_confirm_done{id :: m_rsc:resource_id()}, z:context()) ->
                                           any().

pid_observe_auth_identity_types/4

(optional)
-callback pid_observe_auth_identity_types(pid(), #auth_identity_types{type :: user}, Acc, z:context()) ->
                                             Result
                                             when Acc :: [atom()], Result :: [atom()].

pid_observe_auth_logoff/4

(optional)
-callback pid_observe_auth_logoff(pid(),
                                  #auth_logoff{id :: m_rsc:resource_id() | undefined},
                                  Acc,
                                  z:context()) ->
                                     Result
                                     when Acc :: z:context(), Result :: z:context().

pid_observe_auth_logon/4

(optional)
-callback pid_observe_auth_logon(pid(), #auth_logon{id :: m_rsc:resource_id()}, Acc, z:context()) -> Result
                                    when Acc :: z:context(), Result :: z:context().

pid_observe_auth_options_update/4

(optional)
-callback pid_observe_auth_options_update(pid(),
                                          #auth_options_update{request_options :: map()},
                                          Acc,
                                          z:context()) ->
                                             Result
                                             when Acc :: map(), Result :: map().

pid_observe_auth_postcheck/3

(optional)
-callback pid_observe_auth_postcheck(pid(),
                                     #auth_postcheck{service :: atom(),
                                                     id :: m_rsc:resource_id(),
                                                     query_args :: map()},
                                     z:context()) ->
                                        Result
                                        when Result :: ok | {error, term()} | undefined.

pid_observe_auth_precheck/3

(optional)
-callback pid_observe_auth_precheck(pid(), #auth_precheck{username :: binary()}, z:context()) -> Result
                                       when Result :: ok | {error, term()} | undefined.

pid_observe_auth_reset/3

(optional)
-callback pid_observe_auth_reset(pid(), #auth_reset{username :: undefined | binary()}, z:context()) ->
                                    Result
                                    when Result :: ok | {error, term()} | undefined.

pid_observe_auth_validate/3

(optional)
-callback pid_observe_auth_validate(pid(),
                                    #auth_validate{username :: undefined | binary(),
                                                   password :: undefined | binary()},
                                    z:context()) ->
                                       Result
                                       when
                                           Result :: {ok, m_rsc:resource_id()} | {error, term()} | undefined.

pid_observe_auth_validated/3

(optional)
-callback pid_observe_auth_validated(pid(),
                                     #auth_validated{service :: atom(),
                                                     service_uid :: binary(),
                                                     service_props :: map(),
                                                     props :: m_rsc:props(),
                                                     identities :: [map()],
                                                     ensure_username_pw :: boolean(),
                                                     is_connect :: boolean(),
                                                     is_signup_confirmed :: boolean()},
                                     z:context()) ->
                                        Result
                                        when
                                            Result ::
                                                {ok, m_rsc:resource_id()} |
                                                {ok, z:context()} |
                                                {error, term()} |
                                                undefined.

pid_observe_category_hierarchy_save/3

(optional)
-callback pid_observe_category_hierarchy_save(pid(), #category_hierarchy_save{tree :: term()}, z:context()) ->
                                                 any().

pid_observe_comment_insert/3

(optional)
-callback pid_observe_comment_insert(pid(),
                                     #comment_insert{comment_id :: integer(), id :: m_rsc:resource_id()},
                                     z:context()) ->
                                        any().

pid_observe_content_security_header/4

(optional)
-callback pid_observe_content_security_header(pid(), Default, Acc, Context) -> Result
                                                 when
                                                     Default ::
                                                         #content_security_header{child_src :: [binary()],
                                                                                  connect_src :: [binary()],
                                                                                  default_src :: [binary()],
                                                                                  font_src :: [binary()],
                                                                                  frame_src :: [binary()],
                                                                                  img_src :: [binary()],
                                                                                  manifest_src :: [binary()],
                                                                                  media_src :: [binary()],
                                                                                  object_src :: [binary()],
                                                                                  script_src :: [binary()],
                                                                                  script_src_elem ::
                                                                                      [binary()],
                                                                                  script_src_attr ::
                                                                                      [binary()],
                                                                                  style_src :: [binary()],
                                                                                  style_src_elem ::
                                                                                      [binary()],
                                                                                  style_src_attr ::
                                                                                      [binary()],
                                                                                  worker_src :: [binary()],
                                                                                  base_uri :: [binary()],
                                                                                  sandbox :: [binary()],
                                                                                  frame_ancestors ::
                                                                                      [binary()],
                                                                                  form_action :: [binary()],
                                                                                  report_to :: [binary()]},
                                                     Acc ::
                                                         #content_security_header{child_src :: [binary()],
                                                                                  connect_src :: [binary()],
                                                                                  default_src :: [binary()],
                                                                                  font_src :: [binary()],
                                                                                  frame_src :: [binary()],
                                                                                  img_src :: [binary()],
                                                                                  manifest_src :: [binary()],
                                                                                  media_src :: [binary()],
                                                                                  object_src :: [binary()],
                                                                                  script_src :: [binary()],
                                                                                  script_src_elem ::
                                                                                      [binary()],
                                                                                  script_src_attr ::
                                                                                      [binary()],
                                                                                  style_src :: [binary()],
                                                                                  style_src_elem ::
                                                                                      [binary()],
                                                                                  style_src_attr ::
                                                                                      [binary()],
                                                                                  worker_src :: [binary()],
                                                                                  base_uri :: [binary()],
                                                                                  sandbox :: [binary()],
                                                                                  frame_ancestors ::
                                                                                      [binary()],
                                                                                  form_action :: [binary()],
                                                                                  report_to :: [binary()]},
                                                     Context :: z:context(),
                                                     Result ::
                                                         #content_security_header{child_src :: [binary()],
                                                                                  connect_src :: [binary()],
                                                                                  default_src :: [binary()],
                                                                                  font_src :: [binary()],
                                                                                  frame_src :: [binary()],
                                                                                  img_src :: [binary()],
                                                                                  manifest_src :: [binary()],
                                                                                  media_src :: [binary()],
                                                                                  object_src :: [binary()],
                                                                                  script_src :: [binary()],
                                                                                  script_src_elem ::
                                                                                      [binary()],
                                                                                  script_src_attr ::
                                                                                      [binary()],
                                                                                  style_src :: [binary()],
                                                                                  style_src_elem ::
                                                                                      [binary()],
                                                                                  style_src_attr ::
                                                                                      [binary()],
                                                                                  worker_src :: [binary()],
                                                                                  base_uri :: [binary()],
                                                                                  sandbox :: [binary()],
                                                                                  frame_ancestors ::
                                                                                      [binary()],
                                                                                  form_action :: [binary()],
                                                                                  report_to :: [binary()]}.

pid_observe_content_types_dispatch/4

(optional)
-callback pid_observe_content_types_dispatch(pid(),
                                             #content_types_dispatch{id :: m_rsc:resource()},
                                             Acc, Context) ->
                                                Result
                                                when
                                                    Acc :: [{ContentType, atom()}],
                                                    Context :: z:context(),
                                                    Result :: [{ContentType, atom()}],
                                                    ContentType :: {binary(), binary(), list()}.

pid_observe_cors_headers/3

(optional)
-callback pid_observe_cors_headers(pid(), #cors_headers{headers :: [{binary(), binary()}]}, z:context()) ->
                                      Result
                                      when
                                          Result ::
                                              #cors_headers{headers :: [{binary(), binary()}]} | undefined.

pid_observe_custom_pivot/3

(optional)
-callback pid_observe_custom_pivot(pid(), #custom_pivot{id :: m_rsc:resource_id()}, z:context()) -> Pivots
                                      when
                                          Pivots :: [Pivot] | Pivot | ok | none | undefined,
                                          Pivot :: {atom(), PivotFields},
                                          PivotFields :: proplists:proplist() | map().

pid_observe_debug/3

(optional)
-callback pid_observe_debug(pid(), #debug{what :: term(), arg :: term()}, z:context()) -> any().

pid_observe_development_make/3

(optional)
-callback pid_observe_development_make(pid(), development_make, z:context()) -> any().

pid_observe_development_reload/3

(optional)
-callback pid_observe_development_reload(pid(), development_reload, z:context()) -> any().

pid_observe_dispatch/3

(optional)
-callback pid_observe_dispatch(pid(),
                               #dispatch{host :: binary(),
                                         path :: binary(),
                                         method :: binary(),
                                         protocol :: http | https,
                                         tracer_pid :: pid() | undefined},
                               z:context()) ->
                                  {ok, Result} | undefined
                                  when
                                      Result ::
                                          m_rsc:resource_id() |
                                          #dispatch_match{dispatch_name :: atom(),
                                                          mod :: atom(),
                                                          mod_opts :: list(),
                                                          path_tokens :: [binary()],
                                                          bindings :: [{atom(), binary() | true}]} |
                                          #dispatch_redirect{location :: binary(),
                                                             is_permanent :: boolean()}.

pid_observe_dispatch_host/3

(optional)
-callback pid_observe_dispatch_host(pid(),
                                    #dispatch_host{host :: binary(),
                                                   path :: binary(),
                                                   method :: binary(),
                                                   protocol :: http | https},
                                    z:context()) ->
                                       {ok,
                                        #dispatch_redirect{location :: binary(), is_permanent :: boolean()}} |
                                       undefined.

pid_observe_dispatch_rewrite/4

(optional)
-callback pid_observe_dispatch_rewrite(pid(),
                                       #dispatch_rewrite{is_dir :: boolean(),
                                                         path :: binary(),
                                                         host :: term()},
                                       Acc,
                                       z:context()) ->
                                          Acc1
                                          when
                                              Acc :: {Tokens, Bindings},
                                              Tokens :: [binary()],
                                              Bindings :: list(),
                                              Acc1 :: {Tokens1, Bindings1},
                                              Tokens1 :: [binary()],
                                              Bindings1 :: list().

pid_observe_dropbox_file/3

(optional)
-callback pid_observe_dropbox_file(pid(),
                                   #dropbox_file{filename :: file:filename_all(), basename :: binary()},
                                   z:context()) ->
                                      Result
                                      when Result :: ok | {ok, processing} | undefined.

pid_observe_edge_delete/3

(optional)
-callback pid_observe_edge_delete(pid(),
                                  #edge_delete{subject_id :: m_rsc:resource(),
                                               predicate :: atom(),
                                               object_id :: m_rsc:resource(),
                                               edge_id :: pos_integer()},
                                  z:context()) ->
                                     any().

pid_observe_edge_insert/3

(optional)
-callback pid_observe_edge_insert(pid(),
                                  #edge_insert{subject_id :: m_rsc:resource(),
                                               predicate :: atom(),
                                               object_id :: m_rsc:resource(),
                                               edge_id :: pos_integer()},
                                  z:context()) ->
                                     any().

pid_observe_edge_update/3

(optional)
-callback pid_observe_edge_update(pid(),
                                  #edge_update{subject_id :: m_rsc:resource(),
                                               predicate :: atom(),
                                               object_id :: m_rsc:resource(),
                                               edge_id :: pos_integer()},
                                  z:context()) ->
                                     any().

pid_observe_email_add_handler/3

(optional)
-callback pid_observe_email_add_handler(pid(),
                                        #email_add_handler{notification :: term(),
                                                           user_id :: term(),
                                                           resource_id :: term()},
                                        z:context()) ->
                                           Result
                                           when Result :: {ok, LocalForm :: binary()} | undefined.

pid_observe_email_bounced/3

(optional)
-callback pid_observe_email_bounced(pid(),
                                    #email_bounced{message_nr :: binary() | undefined,
                                                   recipient :: binary() | undefined},
                                    z:context()) ->
                                       any().

pid_observe_email_dkim_options/3

(optional)
-callback pid_observe_email_dkim_options(pid(), #email_dkim_options{}, z:context()) -> Result
                                            when
                                                Result :: DKIMOptions | undefined,
                                                DKIMOptions :: [{atom(), term()}].

pid_observe_email_drop_handler/3

(optional)
-callback pid_observe_email_drop_handler(pid(),
                                         #email_drop_handler{notification :: term(),
                                                             user_id :: term(),
                                                             resource_id :: term()},
                                         z:context()) ->
                                            any().

pid_observe_email_ensure_handler/3

(optional)
-callback pid_observe_email_ensure_handler(pid(),
                                           #email_ensure_handler{notification :: term(),
                                                                 user_id :: term(),
                                                                 resource_id :: term()},
                                           z:context()) ->
                                              Result
                                              when Result :: {ok, LocalForm :: binary()} | undefined.

pid_observe_email_failed/3

(optional)
-callback pid_observe_email_failed(pid(),
                                   #email_failed{message_nr :: binary(),
                                                 recipient :: binary(),
                                                 is_final :: boolean(),
                                                 reason ::
                                                     bounce | retry | illegal_address | smtphost |
                                                     sender_disabled | error,
                                                 retry_ct :: non_neg_integer() | undefined,
                                                 status :: binary() | {error, term()} | undefined},
                                   z:context()) ->
                                      any().

pid_observe_email_is_blocked/3

(optional)
-callback pid_observe_email_is_blocked(pid(), #email_is_blocked{recipient :: binary()}, z:context()) ->
                                          boolean() | undefined.

pid_observe_email_is_recipient_ok/3

(optional)
-callback pid_observe_email_is_recipient_ok(pid(),
                                            #email_is_recipient_ok{recipient :: binary()},
                                            z:context()) ->
                                               boolean() | undefined.

pid_observe_email_received/3

(optional)
-callback pid_observe_email_received(pid(),
                                     #email_received{to :: binary(),
                                                     from :: undefined | binary(),
                                                     localpart :: binary(),
                                                     localtags :: [binary()],
                                                     domain :: binary(),
                                                     reference :: binary(),
                                                     email ::
                                                         #email{to ::
                                                                    list() |
                                                                    string() |
                                                                    binary() |
                                                                    m_rsc:resource_id() |
                                                                    undefined,
                                                                cc ::
                                                                    list() | string() | binary() | undefined,
                                                                bcc ::
                                                                    list() | string() | binary() | undefined,
                                                                from :: binary() | string(),
                                                                reply_to ::
                                                                    binary() |
                                                                    string() |
                                                                    message_id | undefined,
                                                                headers :: [{binary(), binary()}],
                                                                body :: term(),
                                                                raw :: term(),
                                                                subject :: iodata() | undefined,
                                                                text :: iodata() | undefined,
                                                                html :: iodata() | undefined,
                                                                text_tpl ::
                                                                    template_compiler:template() | undefined,
                                                                html_tpl ::
                                                                    template_compiler:template() | undefined,
                                                                vars :: list(),
                                                                attachments :: list(),
                                                                queue :: boolean()},
                                                     headers :: [{binary(), binary()}],
                                                     is_bulk :: boolean(),
                                                     is_auto :: boolean(),
                                                     decoded :: term(),
                                                     raw :: term()},
                                     z:context()) ->
                                        Result
                                        when
                                            Result ::
                                                undefined |
                                                {ok, MsgId :: binary()} |
                                                {ok, term()} |
                                                ok |
                                                {error, term()} |
                                                undefined.

pid_observe_email_send_encoded/3

(optional)
-callback pid_observe_email_send_encoded(pid(),
                                         #email_send_encoded{message_nr :: binary(),
                                                             from :: binary(),
                                                             to :: binary(),
                                                             encoded :: binary(),
                                                             options :: gen_smtp_client:options()},
                                         z:context()) ->
                                            Result
                                            when
                                                Result ::
                                                    {ok, binary()} |
                                                    {ok, term()} |
                                                    {error, Reason, {FailureType, Host, Message}} |
                                                    {error, term()} |
                                                    smtp | undefined,
                                                Reason :: term(),
                                                FailureType :: permanent_failure | temporary_failure,
                                                Host :: string() | binary(),
                                                Message :: term().

pid_observe_email_sent/3

(optional)
-callback pid_observe_email_sent(pid(),
                                 #email_sent{message_nr :: binary(),
                                             recipient :: binary(),
                                             is_final :: boolean()},
                                 z:context()) ->
                                    any().

pid_observe_email_status/3

(optional)
-callback pid_observe_email_status(pid(),
                                   #email_status{recipient :: binary(),
                                                 is_valid :: boolean(),
                                                 is_final :: boolean(),
                                                 is_manual :: boolean()},
                                   z:context()) ->
                                      any().

pid_observe_export_resource_content_disposition/3

(optional)
-callback pid_observe_export_resource_content_disposition(pid(),
                                                          #export_resource_content_disposition{dispatch ::
                                                                                                   atom(),
                                                                                               id ::
                                                                                                   m_rsc:resource_id() |
                                                                                                   undefined,
                                                                                               content_type ::
                                                                                                   binary()},
                                                          z:context()) ->
                                                             Result
                                                             when
                                                                 Result :: {ok, Disposition} | undefined,
                                                                 Disposition :: binary().

pid_observe_export_resource_content_type/3

(optional)
-callback pid_observe_export_resource_content_type(pid(),
                                                   #export_resource_content_type{dispatch :: atom(),
                                                                                 id ::
                                                                                     m_rsc:resource_id() |
                                                                                     undefined},
                                                   z:context()) ->
                                                      Result
                                                      when Result :: {ok, binary() | string()} | undefined.

pid_observe_export_resource_data/3

(optional)
-callback pid_observe_export_resource_data(pid(),
                                           #export_resource_data{dispatch :: atom(),
                                                                 id :: m_rsc:resource_id() | undefined,
                                                                 content_type :: binary(),
                                                                 state :: term()},
                                           z:context()) ->
                                              Result
                                              when
                                                  Result ::
                                                      {ok, binary() | Values} |
                                                      {ok, binary() | Values, State} |
                                                      {error, term()} |
                                                      undefined,
                                                  Values :: [term()],
                                                  State :: term().

pid_observe_export_resource_encode/3

(optional)
-callback pid_observe_export_resource_encode(pid(),
                                             #export_resource_encode{dispatch :: atom(),
                                                                     id :: m_rsc:resource_id() | undefined,
                                                                     content_type :: binary(),
                                                                     data :: term(),
                                                                     state :: term()},
                                             z:context()) ->
                                                Result
                                                when
                                                    Result ::
                                                        {ok, binary()} |
                                                        {ok, binary(), State} |
                                                        {error, term()} |
                                                        undefined,
                                                    State :: term().

pid_observe_export_resource_filename/3

(optional)
-callback pid_observe_export_resource_filename(pid(),
                                               #export_resource_filename{dispatch :: atom(),
                                                                         id ::
                                                                             m_rsc:resource_id() | undefined,
                                                                         content_type :: binary()},
                                               z:context()) ->
                                                  Result
                                                  when Result :: {ok, binary() | string()} | undefined.

pid_observe_export_resource_footer/3

(optional)
-callback pid_observe_export_resource_footer(pid(),
                                             #export_resource_footer{dispatch :: atom(),
                                                                     id :: m_rsc:resource_id() | undefined,
                                                                     content_type :: binary(),
                                                                     state :: term()},
                                             z:context()) ->
                                                Result
                                                when Result :: {ok, binary()} | {error, term()} | undefined.

pid_observe_export_resource_header/3

(optional)
-callback pid_observe_export_resource_header(pid(),
                                             #export_resource_header{dispatch :: atom(),
                                                                     id :: m_rsc:resource_id() | undefined,
                                                                     content_type :: binary()},
                                             z:context()) ->
                                                Result
                                                when
                                                    Result ::
                                                        {ok, binary() | [binary()]} |
                                                        {ok, binary() | [binary()], State} |
                                                        {error, term()} |
                                                        undefined,
                                                    State :: term().

pid_observe_export_resource_visible/3

(optional)
-callback pid_observe_export_resource_visible(pid(),
                                              #export_resource_visible{dispatch :: atom(),
                                                                       id :: m_rsc:resource_id() | undefined},
                                              z:context()) ->
                                                 boolean() | undefined.

pid_observe_filewatcher/3

(optional)
-callback pid_observe_filewatcher(pid(),
                                  #filewatcher{verb :: modify | create | delete,
                                               file :: binary(),
                                               basename :: binary(),
                                               extension :: binary()},
                                  z:context()) ->
                                     any().

pid_observe_hierarchy_updated/3

(optional)
-callback pid_observe_hierarchy_updated(pid(),
                                        #hierarchy_updated{root_id :: binary() | integer(),
                                                           predicate :: atom(),
                                                           inserted_ids :: [integer()],
                                                           deleted_ids :: [integer()]},
                                        z:context()) ->
                                           any().

pid_observe_http_log_access/3

(optional)
-callback pid_observe_http_log_access(pid(),
                                      #http_log_access{timestamp :: erlang:timestamp(),
                                                       status :: undefined | non_neg_integer(),
                                                       status_category ::
                                                           xxx | '1xx' | '2xx' | '3xx' | '4xx' | '5xx',
                                                       method :: binary(),
                                                       metrics :: map()},
                                      z:context()) ->
                                         any().

pid_observe_identity_password_match/3

(optional)
-callback pid_observe_identity_password_match(pid(),
                                              #identity_password_match{rsc_id ::
                                                                           m_rsc:resource_id() | undefined,
                                                                       password :: binary(),
                                                                       hash ::
                                                                           m_identity:hash() |
                                                                           {hash,
                                                                            atom() | binary(),
                                                                            binary()}},
                                              z:context()) ->
                                                 undefined | boolean().

pid_observe_identity_update_done/3

(optional)
-callback pid_observe_identity_update_done(pid(),
                                           #identity_update_done{action :: insert | update | delete | verify,
                                                                 rsc_id :: m_rsc:resource_id(),
                                                                 type :: binary(),
                                                                 key :: m_identity:key() | undefined,
                                                                 is_verified :: boolean() | undefined},
                                           z:context()) ->
                                              any().

pid_observe_identity_verification/3

(optional)
-callback pid_observe_identity_verification(pid(),
                                            #identity_verification{user_id :: m_rsc:resource_id(),
                                                                   identity ::
                                                                       undefined | m_identity:identity()},
                                            z:context()) ->
                                               Result
                                               when Result :: ok | {error, term()} | undefined.

pid_observe_identity_verified/3

(optional)
-callback pid_observe_identity_verified(pid(),
                                        #identity_verified{user_id :: m_rsc:resource_id(),
                                                           type :: m_identity:type(),
                                                           key :: m_identity:key()},
                                        z:context()) ->
                                           any().

pid_observe_import_csv_definition/3

(optional)
-callback pid_observe_import_csv_definition(pid(),
                                            #import_csv_definition{basename :: binary(),
                                                                   filename :: file:filename_all()},
                                            z:context()) ->
                                               Result
                                               when
                                                   Result ::
                                                       {ok,
                                                        #import_data_def{colsep :: 0..255,
                                                                         skip_first_row :: boolean(),
                                                                         columns :: list(),
                                                                         importdef ::
                                                                             [#{props => list(),
                                                                                edges => list()}],
                                                                         importstate :: term(),
                                                                         importmodule ::
                                                                             module() | undefined}} |
                                                       ok |
                                                       {error, term()} |
                                                       undefined.

pid_observe_import_resource/3

(optional)
-callback pid_observe_import_resource(pid(),
                                      #import_resource{source :: atom() | binary(),
                                                       source_id :: integer() | binary(),
                                                       source_url :: binary(),
                                                       source_user_id :: binary() | integer(),
                                                       user_id :: integer(),
                                                       name :: binary(),
                                                       props :: m_rsc:props_all(),
                                                       urls :: list(),
                                                       media_urls :: list(),
                                                       data :: any()},
                                      z:context()) ->
                                         Result
                                         when
                                             Result ::
                                                 {ok, m_rsc:resource_id()} | {error, term()} | undefined.

pid_observe_language/3

(optional)
-callback pid_observe_language(pid(), #language{language :: atom()}, z:context()) -> any().

pid_observe_language_detect/3

(optional)
-callback pid_observe_language_detect(pid(),
                                      #language_detect{text :: binary(), is_editable_only :: boolean()},
                                      z:context()) ->
                                         Result
                                         when Result :: z_language:language_code() | undefined.

pid_observe_logon_options/4

(optional)
-callback pid_observe_logon_options(pid(), #logon_options{payload :: #{binary() => term()}}, Acc, Context) ->
                                       Result
                                       when Acc :: map(), Context :: z:context(), Result :: map().

pid_observe_logon_ready_page/3

(optional)
-callback pid_observe_logon_ready_page(pid(),
                                       #logon_ready_page{request_page :: binary() | undefined},
                                       z:context()) ->
                                          Result
                                          when Result :: binary() | undefined.

pid_observe_logon_submit/3

(optional)
-callback pid_observe_logon_submit(pid(), #logon_submit{payload :: #{binary() => term()}}, z:context()) ->
                                      Result
                                      when
                                          Result ::
                                              {ok, UserId :: m_rsc:resource_id()} |
                                              {error, term()} |
                                              undefined.

pid_observe_m_config_update/3

(optional)
-callback pid_observe_m_config_update(pid(),
                                      #m_config_update{module :: atom(), key :: term(), value :: term()},
                                      z:context()) ->
                                         any().

pid_observe_m_config_update_prop/3

(optional)
-callback pid_observe_m_config_update_prop(pid(),
                                           #m_config_update_prop{module :: term(),
                                                                 key :: term(),
                                                                 prop :: term(),
                                                                 value :: term()},
                                           z:context()) ->
                                              any().

pid_observe_mailinglist_mailing/3

(optional)
-callback pid_observe_mailinglist_mailing(pid(),
                                          #mailinglist_mailing{list_id :: m_rsc:resource() | undefined,
                                                               email :: binary() | string() | undefined,
                                                               page_id :: m_rsc:resource(),
                                                               options ::
                                                                   [{is_match_language, boolean()} |
                                                                    {is_send_all, boolean()}]},
                                          z:context()) ->
                                             any().

pid_observe_mailinglist_message/3

(optional)
-callback pid_observe_mailinglist_message(pid(),
                                          #mailinglist_message{what ::
                                                                   send_welcome | send_confirm |
                                                                   send_goodbye | silent,
                                                               list_id :: m_rsc:resource(),
                                                               recipient :: proplists:proplist() | integer()},
                                          z:context()) ->
                                             any().

pid_observe_media_identify_extension/3

(optional)
-callback pid_observe_media_identify_extension(pid(),
                                               #media_identify_extension{mime :: binary(),
                                                                         preferred :: undefined | binary()},
                                               z:context()) ->
                                                  Result
                                                  when
                                                      Result :: Extension | undefined, Extension :: binary().

pid_observe_media_identify_file/3

(optional)
-callback pid_observe_media_identify_file(pid(),
                                          #media_identify_file{filename :: file:filename_all(),
                                                               original_filename :: binary(),
                                                               extension :: binary()},
                                          z:context()) ->
                                             Result
                                             when
                                                 Result :: MimeData | undefined,
                                                 MimeData :: #{binary() => term()}.

pid_observe_media_import/3

(optional)
-callback pid_observe_media_import(pid(),
                                   #media_import{url :: binary(),
                                                 host_rev :: [binary()],
                                                 mime :: binary(),
                                                 metadata :: tuple()},
                                   z:context()) ->
                                      Result
                                      when
                                          Result ::
                                              #media_import_props{prio :: pos_integer(),
                                                                  category :: atom(),
                                                                  module :: atom(),
                                                                  description :: binary() | z:trans(),
                                                                  rsc_props :: map(),
                                                                  medium_props ::
                                                                      z_media_identify:media_info(),
                                                                  medium_url :: binary(),
                                                                  preview_url :: binary() | undefined,
                                                                  importer :: atom()} |
                                              [#media_import_props{prio :: pos_integer(),
                                                                   category :: atom(),
                                                                   module :: atom(),
                                                                   description :: binary() | z:trans(),
                                                                   rsc_props :: map(),
                                                                   medium_props ::
                                                                       z_media_identify:media_info(),
                                                                   medium_url :: binary(),
                                                                   preview_url :: binary() | undefined,
                                                                   importer :: atom()}] |
                                              undefined.

pid_observe_media_import_medium/3

(optional)
-callback pid_observe_media_import_medium(pid(),
                                          #media_import_medium{id :: m_rsc:resource_id(), medium :: map()},
                                          z:context()) ->
                                             Result
                                             when Result :: ok | {error, term()} | undefined.

pid_observe_media_preview_options/4

(optional)
-callback pid_observe_media_preview_options(pid(),
                                            #media_preview_options{id :: m_rsc:resource_id() | undefined,
                                                                   width :: non_neg_integer(),
                                                                   height :: non_neg_integer(),
                                                                   options :: proplists:proplist()},
                                            Acc,
                                            z:context()) ->
                                               Result
                                               when
                                                   Acc :: ImageOptions,
                                                   Result :: ImageOptions,
                                                   ImageOptions :: proplists:proplist().

pid_observe_media_replace_file/3

(optional)
-callback pid_observe_media_replace_file(pid(),
                                         #media_replace_file{id :: m_rsc:resource_id(),
                                                             medium :: map() | undefined},
                                         z:context()) ->
                                            any().

pid_observe_media_stillimage/3

(optional)
-callback pid_observe_media_stillimage(pid(),
                                       #media_stillimage{id :: m_rsc:resource_id() | undefined,
                                                         props :: z_media_identify:media_info()},
                                       z:context()) ->
                                          Result
                                          when Result :: {ok, m_rsc:resource_id()} | undefined.

pid_observe_media_update_done/3

(optional)
-callback pid_observe_media_update_done(pid(),
                                        #media_update_done{action :: insert | update | delete,
                                                           id :: m_rsc:resource_id(),
                                                           pre_is_a :: [atom()],
                                                           post_is_a :: [atom()],
                                                           pre_props :: map() | undefined,
                                                           post_props :: map() | undefined},
                                        z:context()) ->
                                           any().

pid_observe_media_upload_preprocess/3

(optional)
-callback pid_observe_media_upload_preprocess(pid(),
                                              #media_upload_preprocess{id ::
                                                                           m_rsc:resource_id() | insert_rsc,
                                                                       mime :: binary(),
                                                                       file ::
                                                                           file:filename_all() | undefined,
                                                                       original_filename ::
                                                                           file:filename_all() | undefined,
                                                                       medium ::
                                                                           z_media_identify:media_info(),
                                                                       post_insert_fun ::
                                                                           function() | undefined},
                                              z:context()) ->
                                                 Result
                                                 when
                                                     Result ::
                                                         #media_upload_preprocess{id ::
                                                                                      m_rsc:resource_id() |
                                                                                      insert_rsc,
                                                                                  mime :: binary(),
                                                                                  file ::
                                                                                      file:filename_all() |
                                                                                      undefined,
                                                                                  original_filename ::
                                                                                      file:filename_all() |
                                                                                      undefined,
                                                                                  medium ::
                                                                                      z_media_identify:media_info(),
                                                                                  post_insert_fun ::
                                                                                      function() | undefined} |
                                                         undefined.

pid_observe_media_upload_props/4

(optional)
-callback pid_observe_media_upload_props(pid(),
                                         #media_upload_props{id :: m_rsc:resource_id() | insert_rsc,
                                                             mime :: binary(),
                                                             archive_file :: file:filename_all() | undefined,
                                                             options :: list()},
                                         Acc,
                                         z:context()) ->
                                            Result
                                            when
                                                Acc :: MediumRecord,
                                                Result :: MediumRecord,
                                                MediumRecord :: #{binary() => term()}.

pid_observe_media_upload_rsc_props/4

(optional)
-callback pid_observe_media_upload_rsc_props(pid(),
                                             #media_upload_rsc_props{id :: m_rsc:resource_id() | insert_rsc,
                                                                     mime :: binary(),
                                                                     archive_file :: term(),
                                                                     options :: list(),
                                                                     medium :: z_media_identify:media_info()},
                                             Acc,
                                             z:context()) ->
                                                Result
                                                when
                                                    Acc :: RscProps,
                                                    Result :: RscProps,
                                                    RscProps :: m_rsc:props().

pid_observe_media_viewer/3

(optional)
-callback pid_observe_media_viewer(pid(),
                                   #media_viewer{id :: term(),
                                                 props :: z_media_identify:media_info(),
                                                 filename :: file:filename_all() | undefined,
                                                 options :: list()},
                                   z:context()) ->
                                      Result
                                      when Result :: {ok, HTML} | undefined, HTML :: iodata().

pid_observe_media_viewer_consent/3

(optional)
-callback pid_observe_media_viewer_consent(pid(),
                                           #media_viewer_consent{id :: m_rsc:resource_id() | undefined,
                                                                 consent :: functional | stats | all,
                                                                 html :: iodata(),
                                                                 viewer_props ::
                                                                     z_media_identify:media_info(),
                                                                 viewer_options :: list()},
                                           z:context()) ->
                                              Result
                                              when Result :: {ok, HTML} | undefined, HTML :: iodata().

pid_observe_menu_rsc/3

(optional)
-callback pid_observe_menu_rsc(pid(), #menu_rsc{id :: m_rsc:resource()}, z:context()) ->
                                  m_rsc:resource() | undefined.

pid_observe_menu_save/3

(optional)
-callback pid_observe_menu_save(pid(), #menu_save{id :: term(), tree :: term()}, z:context()) -> any().

pid_observe_middleware/4

(optional)
-callback pid_observe_middleware(pid(), #middleware{on :: request | welformed | handled}, Acc, z:context()) ->
                                    Result
                                    when Acc :: z:context(), Result :: z:context().

pid_observe_module_activate/3

(optional)
-callback pid_observe_module_activate(pid(), #module_activate{module :: atom(), pid :: pid()}, z:context()) ->
                                         any().

pid_observe_module_deactivate/3

(optional)
-callback pid_observe_module_deactivate(pid(), #module_deactivate{module :: atom()}, z:context()) -> any().

pid_observe_module_ready/3

(optional)
-callback pid_observe_module_ready(pid(), module_ready, z:context()) -> any().

pid_observe_output_html/4

(optional)
-callback pid_observe_output_html(pid(), #output_html{html :: term()}, Acc, z:context()) -> Result
                                     when
                                         Acc :: {MixedHtml, Context},
                                         Result :: {MixedHtml, Context},
                                         Context :: z:context(),
                                         MixedHtml :: binary() | list().

pid_observe_page_url/3

(optional)
-callback pid_observe_page_url(pid(), #page_url{id :: m_rsc:resource_id(), is_a :: [atom()]}, z:context()) ->
                                  {ok, binary()} | undefined.

pid_observe_pivot_fields/4

(optional)
-callback pid_observe_pivot_fields(pid(),
                                   #pivot_fields{id :: m_rsc:resource_id(), raw_props :: m_rsc:props()},
                                   Acc,
                                   z:context()) ->
                                      Result
                                      when Acc :: #{binary() => term()}, Result :: #{binary() => term()}.

pid_observe_pivot_rsc_data/4

(optional)
-callback pid_observe_pivot_rsc_data(pid(), #pivot_rsc_data{id :: m_rsc:resource_id()}, Acc, z:context()) ->
                                        Result
                                        when Acc :: m_rsc:props(), Result :: m_rsc:props().

pid_observe_pivot_update/4

(optional)
-callback pid_observe_pivot_update(pid(),
                                   #pivot_update{id :: m_rsc:resource_id(), raw_props :: m_rsc:props()},
                                   Acc,
                                   z:context()) ->
                                      Result
                                      when Acc :: m_rsc:props(), Result :: m_rsc:props().

pid_observe_postback_notify/3

(optional)
-callback pid_observe_postback_notify(pid(),
                                      #postback_notify{message :: term(),
                                                       trigger :: term(),
                                                       target :: term(),
                                                       data :: term()},
                                      z:context()) ->
                                         Result
                                         when Result :: z:context() | undefined.

pid_observe_request_context/4

(optional)
-callback pid_observe_request_context(pid(),
                                      #request_context{phase :: init | refresh | auth_status,
                                                       document :: map()},
                                      Acc,
                                      z:context()) ->
                                         Result
                                         when Acc :: z:context(), Result :: z:context().

pid_observe_rsc_delete/3

(optional)
-callback pid_observe_rsc_delete(pid(),
                                 #rsc_delete{id :: m_rsc:resource_id(), is_a :: [atom()]},
                                 z:context()) ->
                                    any().

pid_observe_rsc_get/4

(optional)
-callback pid_observe_rsc_get(pid(),
                              #rsc_delete{id :: m_rsc:resource_id(), is_a :: [atom()]},
                              Acc,
                              z:context()) ->
                                 Result
                                 when Acc :: m_rsc:props(), Result :: m_rsc:props().

pid_observe_rsc_import_fetch/3

(optional)
-callback pid_observe_rsc_import_fetch(pid(), #rsc_import_fetch{uri :: binary()}, z:context()) -> Result
                                          when
                                              Result ::
                                                  {ok, map()} |
                                                  {ok, m_rsc:resource_id()} |
                                                  {ok, {m_rsc:resource_id(), map()}} |
                                                  {error, term()} |
                                                  undefined.

pid_observe_rsc_insert/4

(optional)
-callback pid_observe_rsc_insert(pid(), #rsc_insert{props :: m_rsc:props()}, Acc, z:context()) -> Result
                                    when Acc :: m_rsc:props(), Result :: m_rsc:props().

pid_observe_rsc_merge/3

(optional)
-callback pid_observe_rsc_merge(pid(),
                                #rsc_merge{winner_id :: m_rsc:resource_id(),
                                           loser_id :: m_rsc:resource_id(),
                                           is_merge_trans :: boolean()},
                                z:context()) ->
                                   any().

pid_observe_rsc_pivot_done/3

(optional)
-callback pid_observe_rsc_pivot_done(pid(),
                                     #rsc_pivot_done{id :: m_rsc:resource_id(), is_a :: [atom()]},
                                     z:context()) ->
                                        any().

pid_observe_rsc_query_item/3

(optional)
-callback pid_observe_rsc_query_item(pid(),
                                     #rsc_query_item{query_id :: m_rsc:resource_id(),
                                                     match_id :: m_rsc:resource_id()},
                                     z:context()) ->
                                        any().

pid_observe_rsc_update/4

(optional)
-callback pid_observe_rsc_update(pid(),
                                 #rsc_update{action :: insert | update,
                                             id :: m_rsc:resource_id(),
                                             props :: m_rsc:props()},
                                 Acc,
                                 z:context()) ->
                                    Result
                                    when
                                        Acc :: {ok, map()} | {error, term()},
                                        Result :: {ok, map()} | {error, term()}.

pid_observe_rsc_update_done/3

(optional)
-callback pid_observe_rsc_update_done(pid(),
                                      #rsc_update_done{action :: insert | update | delete,
                                                       id :: m_rsc:resource_id(),
                                                       pre_is_a :: list(),
                                                       post_is_a :: list(),
                                                       pre_props :: m_rsc:props(),
                                                       post_props :: m_rsc:props()},
                                      z:context()) ->
                                         any().

pid_observe_rsc_upload/3

(optional)
-callback pid_observe_rsc_upload(pid(),
                                 #rsc_upload{id :: m_rsc:resource() | undefined,
                                             format :: json | bert,
                                             data :: binary() | map()},
                                 z:context()) ->
                                    Result
                                    when
                                        Result ::
                                            {ok, m_rsc:resource_id()} | {error, badarg | term()} | undefined.

pid_observe_sanitize_element/4

(optional)
-callback pid_observe_sanitize_element(pid(),
                                       #sanitize_element{element ::
                                                             {binary(), [{binary(), binary()}], list()},
                                                         stack :: list()},
                                       Acc,
                                       z:context()) ->
                                          Result
                                          when
                                              Acc :: Element,
                                              Result :: Element,
                                              Element :: {binary(), [{binary(), binary()}], list()}.

pid_observe_sanitize_embed_url/3

(optional)
-callback pid_observe_sanitize_embed_url(pid(), #sanitize_embed_url{hostpath :: binary()}, z:context()) ->
                                            URL
                                            when URL :: undefined | binary().

pid_observe_scomp_script_render/3

(optional)
-callback pid_observe_scomp_script_render(pid(),
                                          #scomp_script_render{is_nostartup :: boolean(), args :: list()},
                                          z:context()) ->
                                             iodata().

pid_observe_search_query/3

(optional)
-callback pid_observe_search_query(pid(),
                                   #search_query{name :: binary() | undefined,
                                                 args :: map() | undefined,
                                                 offsetlimit ::
                                                     {Offset :: pos_integer(), Limit :: pos_integer()},
                                                 options :: z_search:search_options(),
                                                 search ::
                                                     {SearchName :: atom(), SearchProps :: list()} |
                                                     undefined},
                                   z:context()) ->
                                      Result
                                      when
                                          Result ::
                                              #search_sql{select :: iodata(),
                                                          from :: iodata(),
                                                          where :: iodata(),
                                                          order :: iodata(),
                                                          group_by :: iodata(),
                                                          limit :: term(),
                                                          tables :: list(),
                                                          args :: list(),
                                                          cats :: list(),
                                                          cats_exclude :: list(),
                                                          cats_exact :: list(),
                                                          run_func :: function() | undefined,
                                                          post_func ::
                                                              fun((#search_result{search_name ::
                                                                                      binary() | atom(),
                                                                                  search_args ::
                                                                                      map() |
                                                                                      proplists:proplist(),
                                                                                  result :: list(),
                                                                                  page :: pos_integer(),
                                                                                  pagelen ::
                                                                                      pos_integer() |
                                                                                      undefined,
                                                                                  options ::
                                                                                      z_search:search_options(),
                                                                                  total ::
                                                                                      non_neg_integer() |
                                                                                      undefined,
                                                                                  pages ::
                                                                                      non_neg_integer() |
                                                                                      undefined,
                                                                                  is_total_estimated ::
                                                                                      boolean(),
                                                                                  next ::
                                                                                      pos_integer() | false,
                                                                                  prev :: pos_integer(),
                                                                                  facets ::
                                                                                      #{binary() => map()} |
                                                                                      undefined},
                                                                   #search_sql{},
                                                                   z:context()) ->
                                                                      #search_result{search_name ::
                                                                                         binary() | atom(),
                                                                                     search_args ::
                                                                                         map() |
                                                                                         proplists:proplist(),
                                                                                     result :: list(),
                                                                                     page :: pos_integer(),
                                                                                     pagelen ::
                                                                                         pos_integer() |
                                                                                         undefined,
                                                                                     options ::
                                                                                         z_search:search_options(),
                                                                                     total ::
                                                                                         non_neg_integer() |
                                                                                         undefined,
                                                                                     pages ::
                                                                                         non_neg_integer() |
                                                                                         undefined,
                                                                                     is_total_estimated ::
                                                                                         boolean(),
                                                                                     next ::
                                                                                         pos_integer() |
                                                                                         false,
                                                                                     prev :: pos_integer(),
                                                                                     facets ::
                                                                                         #{binary() => map()} |
                                                                                         undefined}) |
                                                              undefined,
                                                          extra :: list(),
                                                          assoc :: boolean(),
                                                          search_sql_terms :: list() | undefined} |
                                              #search_result{search_name :: binary() | atom(),
                                                             search_args :: map() | proplists:proplist(),
                                                             result :: list(),
                                                             page :: pos_integer(),
                                                             pagelen :: pos_integer() | undefined,
                                                             options :: z_search:search_options(),
                                                             total :: non_neg_integer() | undefined,
                                                             pages :: non_neg_integer() | undefined,
                                                             is_total_estimated :: boolean(),
                                                             next :: pos_integer() | false,
                                                             prev :: pos_integer(),
                                                             facets :: #{binary() => map()} | undefined} |
                                              list() |
                                              undefined.

pid_observe_search_query_term/3

(optional)
-callback pid_observe_search_query_term(pid(),
                                        #search_query_term{term :: binary(), arg :: any()},
                                        z:context()) ->
                                           Result
                                           when
                                               Result ::
                                                   #search_sql_term{label :: term(),
                                                                    select :: term(),
                                                                    tables :: term(),
                                                                    join_inner :: term(),
                                                                    join_left :: term(),
                                                                    where :: term(),
                                                                    sort :: term(),
                                                                    asort :: term(),
                                                                    zsort :: term(),
                                                                    cats :: term(),
                                                                    cats_exclude :: term(),
                                                                    cats_exact :: term(),
                                                                    extra :: term(),
                                                                    args :: term()} |
                                                   QueryTerm |
                                                   [QueryTerm] |
                                                   undefined,
                                               QueryTerm :: #{binary() => term()}.

pid_observe_security_headers/3

(optional)
-callback pid_observe_security_headers(pid(),
                                       #security_headers{headers :: [{binary(), binary()}]},
                                       z:context()) ->
                                          Result
                                          when
                                              Result ::
                                                  #security_headers{headers :: [{binary(), binary()}]} |
                                                  undefined.

pid_observe_session_context/4

(optional)
-callback pid_observe_session_context(pid(),
                                      #session_context{request_type :: http | mqtt,
                                                       payload :: undefined | term()},
                                      Acc,
                                      z:context()) ->
                                         Result
                                         when Acc :: z:context(), Result :: z:context().

pid_observe_set_user_language/3

(optional)
-callback pid_observe_set_user_language(pid(), #set_user_language{id :: m_rsc:resource_id()}, z:context()) ->
                                           z:context() | undefined.

pid_observe_signup/3

(optional)
-callback pid_observe_signup(pid(),
                             #signup{id :: m_rsc:resource_id() | undefined,
                                     props :: map(),
                                     signup_props :: list(),
                                     request_confirm :: boolean()},
                             z:context()) ->
                                Result
                                when
                                    Result ::
                                        {ok, UserId :: m_rsc:resource_id()} | {error, term()} | undefined.

pid_observe_signup_check/4

(optional)
-callback pid_observe_signup_check(pid(), signup_check, Acc, Context) -> Result
                                      when
                                          Acc :: {ok, Props, SignupProps} | {error, term()},
                                          Context :: z:context(),
                                          Result :: {ok, Props, SignupProps} | {error, term()},
                                          Props :: map(),
                                          SignupProps :: list().

pid_observe_signup_confirm/3

(optional)
-callback pid_observe_signup_confirm(pid(), #signup_confirm{id :: m_rsc:resource()}, z:context()) -> any().

pid_observe_signup_confirm_redirect/3

(optional)
-callback pid_observe_signup_confirm_redirect(pid(),
                                              #signup_confirm_redirect{id :: m_rsc:resource()},
                                              z:context()) ->
                                                 Result
                                                 when Result :: URL | undefined, URL :: binary().

pid_observe_signup_done/3

(optional)
-callback pid_observe_signup_done(pid(),
                                  #signup_done{id :: m_rsc:resource(),
                                               is_verified :: boolean(),
                                               props :: map(),
                                               signup_props :: list()},
                                  z:context()) ->
                                     any().

pid_observe_signup_failed_url/3

(optional)
-callback pid_observe_signup_failed_url(pid(), #signup_failed_url{reason :: term()}, z:context()) -> Result
                                           when Result :: {ok, Url :: binary()} | undefined.

pid_observe_signup_url/3

(optional)
-callback pid_observe_signup_url(pid(), #signup_url{props :: map(), signup_props :: list()}, z:context()) ->
                                    Result
                                    when Result :: {ok, Url :: binary()} | undefined.

pid_observe_ssl_options/3

(optional)
-callback pid_observe_ssl_options(pid(), #ssl_options{server_name :: binary()}, z:context()) ->
                                     SSLOptions | undefined
                                     when SSLOptions :: {ok, [ssl:tls_option()]}.

pid_observe_survey_get_handlers/4

(optional)
-callback pid_observe_survey_get_handlers(pid(), #survey_get_handlers{}, Acc, z:context()) -> Result
                                             when
                                                 Acc :: Handlers,
                                                 Result :: Handlers,
                                                 Handlers :: [{HandlerName, DisplayTitle}],
                                                 HandlerName :: atom(),
                                                 DisplayTitle :: binary().

pid_observe_survey_is_allowed_results_download/3

(optional)
-callback pid_observe_survey_is_allowed_results_download(pid(),
                                                         #survey_is_allowed_results_download{id ::
                                                                                                 m_rsc:resource_id()},
                                                         z:context()) ->
                                                            Result
                                                            when Result :: boolean() | undefined.

pid_observe_survey_is_submit/3

(optional)
-callback pid_observe_survey_is_submit(pid(), #survey_is_submit{block :: map()}, z:context()) -> Result
                                          when Result :: boolean() | undefined.

pid_observe_survey_result_column_values/4

(optional)
-callback pid_observe_survey_result_column_values(pid(),
                                                  #survey_result_column_values{id :: m_rsc:resource_id(),
                                                                               handler ::
                                                                                   binary() | undefined,
                                                                               format :: html | text,
                                                                               user_id ::
                                                                                   m_rsc:resource_id(),
                                                                               answer ::
                                                                                   proplists:proplist(),
                                                                               columns ::
                                                                                   [{binary(),
                                                                                     binary() |
                                                                                     #trans{tr ::
                                                                                                [{atom(),
                                                                                                  binary()}]}}]},
                                                  Acc,
                                                  z:context()) ->
                                                     Result
                                                     when
                                                         Acc :: ColumnValues,
                                                         Result :: ColumnValues,
                                                         ColumnValues :: #{QuestionName => Value},
                                                         QuestionName :: binary(),
                                                         Value :: iodata().

pid_observe_survey_result_columns/4

(optional)
-callback pid_observe_survey_result_columns(pid(),
                                            #survey_result_columns{id :: m_rsc:resource_id(),
                                                                   handler :: binary() | undefined,
                                                                   format :: html | text},
                                            Acc,
                                            z:context()) ->
                                               Result
                                               when
                                                   Acc :: Columns,
                                                   Result :: Columns,
                                                   Columns :: [{QuestionName, Title}],
                                                   QuestionName :: binary(),
                                                   Title :: binary() | z:trans().

pid_observe_survey_submit/3

(optional)
-callback pid_observe_survey_submit(pid(),
                                    #survey_submit{id :: m_rsc:resource_id(),
                                                   handler :: binary() | undefined,
                                                   answers :: list(),
                                                   missing :: list(),
                                                   answers_raw :: list(),
                                                   submit_args :: proplists:proplist()},
                                    z:context()) ->
                                       Result
                                       when
                                           Result ::
                                               ok |
                                               {ok,
                                                z:context() |
                                                #render{template :: template_compiler:template(),
                                                        is_all :: boolean(),
                                                        vars :: proplists:proplist()}} |
                                               {save,
                                                z:context() |
                                                #render{template :: template_compiler:template(),
                                                        is_all :: boolean(),
                                                        vars :: proplists:proplist()}} |
                                               {error, term()} |
                                               undefined.

pid_observe_tkvstore_delete/3

(optional)
-callback pid_observe_tkvstore_delete(pid(), #tkvstore_delete{type :: term(), key :: term()}, z:context()) ->
                                         any().

pid_observe_tkvstore_get/3

(optional)
-callback pid_observe_tkvstore_get(pid(), #tkvstore_get{type :: term(), key :: term()}, z:context()) ->
                                      term() | undefined.

pid_observe_tkvstore_put/3

(optional)
-callback pid_observe_tkvstore_put(pid(),
                                   #tkvstore_put{type :: term(), key :: term(), value :: term()},
                                   z:context()) ->
                                      ok | undefined.

pid_observe_translate/3

(optional)
-callback pid_observe_translate(pid(),
                                #translate{from :: atom(), to :: atom(), texts :: [binary()]},
                                z:context()) ->
                                   Result
                                   when
                                       Result :: {ok, Translations} | {error, term()} | undefined,
                                       Translations :: [{binary(), undefined | binary()}].

pid_observe_url_abs/3

(optional)
-callback pid_observe_url_abs(pid(),
                              #url_abs{url :: term(), dispatch :: term(), dispatch_options :: term()},
                              z:context()) ->
                                 URL | undefined
                                 when URL :: binary().

pid_observe_url_fetch_options/3

(optional)
-callback pid_observe_url_fetch_options(pid(),
                                        #url_fetch_options{method :: get | post | put | delete,
                                                           host :: binary(),
                                                           url :: binary(),
                                                           options :: z_url_fetch:options()},
                                        z:context()) ->
                                           Result
                                           when Result :: z_url_fetch:options() | undefined.

pid_observe_url_rewrite/4

(optional)
-callback pid_observe_url_rewrite(pid(), #url_rewrite{dispatch :: atom(), args :: list()}, Acc, z:context()) ->
                                     Result
                                     when Acc :: binary(), Result :: binary().

pid_observe_user_context/4

(optional)
-callback pid_observe_user_context(pid(), #user_context{id :: m_rsc:resource_id()}, Acc, z:context()) ->
                                      Result
                                      when Acc :: z:context(), Result :: z:context().

pid_observe_user_is_enabled/3

(optional)
-callback pid_observe_user_is_enabled(pid(), #user_is_enabled{id :: m_rsc:resource_id()}, z:context()) ->
                                         boolean() | undefined.

pid_observe_validate_query_args/4

(optional)
-callback pid_observe_validate_query_args(pid(), #validate_query_args{}, Acc, z:context()) -> Result
                                             when
                                                 Acc :: {ok, Args} | {error, term()},
                                                 Result :: {ok, Args} | {error, term()},
                                                 Args :: [{binary(), z:qvalue()}].