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
-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:
Return:
[ m_rsc:resource_id() ]
#acl_collab_groups_modify{} properties:
- id:
m_rsc:resource_id()|undefined - groups:
list
-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:
Return:
authenticated #context{} or undefined
#acl_context_authenticated{} properties: none
-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:
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).
-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:
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
-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:
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()
Clear the associated access policy for the context.
Type:
Return:
updated z:context() or undefined
#acl_logoff{} properties: none
-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:
Return:
updated z:context() or undefined
#acl_logon{} properties:
- id:
m_rsc:resource_id() - options:
map
-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:
Return:
[ m_rsc:resource_id() ] or undefined
#acl_user_groups{} properties: none
-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:
Return:
[ m_rsc:resource_id() ]
#acl_user_groups_modify{} properties:
- id:
m_rsc:resource_id()|undefined - groups:
list
-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:
Return:
#action_event_type{} properties:
- event:
tuple - trigger_id:
string - trigger:
string - postback_js:
iolist - postback_pickled:
string|binary - action_js:
iolist
-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:
Return:
#activity{} properties:
- version:
pos_integer - posted_time:
unknown - actor:
unknown - verb:
atom - object:
unknown - target:
unknown
-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:
Return:
#activity_send{} properties:
- recipient_id:
unknown - channel:
unknown - queue:
unknown - activities:
list
-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:
Return:
#admin_edit_blocks{} properties:
- id:
m_rsc:resource_id()
-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:
Return:
#admin_rscform{} properties:
- id:
m_rsc:resource_id() - is_a:
list
-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:
Return:
#auth_checked{} properties:
- id:
undefined|m_rsc:resource_id() - username:
binary - is_accepted:
boolean
-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:
Return:
ok | {error, term()}
#auth_client_logon_user{} properties:
- user_id:
m_rsc:resource_id() - url:
union
-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:
Return:
ok | {error, term()}
#auth_client_switch_user{} properties:
- user_id:
m_rsc:resource_id()
-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:
Return:
z:context()
#auth_confirm{} properties:
- id:
m_rsc:resource_id()
-callback observe_auth_confirm_done(#auth_confirm_done{id :: m_rsc:resource_id()}, z:context()) -> any().
A user id has been confirmed.
Type:
Return:
#auth_confirm_done{} properties:
- id:
m_rsc:resource_id()
-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:
Return:
[ atom() ]
#auth_identity_types{} properties:
- unknown:
unknown
-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:
Return:
z:context()
#auth_logoff{} properties:
- id:
m_rsc:resource_id()|undefined
-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:
Return:
z:context()
#auth_logon{} properties:
- id:
m_rsc:resource_id()
-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:
Return:
map()
#auth_options_update{} properties:
- request_options:
map
-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:
Return:
‘undefined’ | ok | {error, Reason}
#auth_postcheck{} properties:
- service:
atom - id:
m_rsc:resource_id() - query_args:
map
-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:
Return:
‘undefined’ | ok | {error, Reason}
#auth_precheck{} properties:
- username:
binary
-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:
Return:
#auth_reset{} properties:
- username:
undefined|binary
-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:
Return:
#auth_validate{} properties:
- username:
undefined|binary - password:
undefined|binary
-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:
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
-callback observe_category_hierarchy_save(#category_hierarchy_save{tree :: term()}, z:context()) -> any().
Save (and update) the complete category hierarchy
Type:
Return:
#category_hierarchy_save{} properties:
- tree:
unknown
-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:
Return:
#comment_insert{} properties:
- comment_id:
integer - id:
m_rsc:resource_id()
-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:
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
-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:
Return:
[{ContentType, DispatchRule}]
#content_types_dispatch{} properties:
- id:
m_rsc:resource()
-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:
Return:
#cors_headers{} properties:
- headers:
list
-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:
Return:
#custom_pivot{} properties:
- id:
m_rsc:resource_id()
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:
Return:
#debug{} properties:
- what:
unknown - unknown:
unknown
-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:
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
-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:
Return:
{ok, #dispatch_redirect{}} or undefined
#dispatch_host{} properties:
- host:
binary - path:
binary - method:
binary - protocol:
union
-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:
Return:
#dispatch_rewrite{} properties:
- is_dir:
boolean - path:
binary - host:
unknown
-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:
Return:
#dropbox_file{} properties:
- filename:
file:filename_all() - basename:
binary
-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:
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.
-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:
Return:
return value is ignored
#edge_insert{} properties:
- subject_id:
m_rsc:resource() - predicate:
atom - object_id:
m_rsc:resource() - edge_id:
pos_integer
-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:
Return:
return value is ignored
#edge_update{} properties:
- subject_id:
m_rsc:resource() - predicate:
atom - object_id:
m_rsc:resource() - edge_id:
pos_integer
-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:
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
-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:
Return:
#email_bounced{} properties:
- message_nr:
binary|undefined - recipient:
binary|undefined
-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:
Return:
list() options for the DKIM signature
#email_dkim_options{} properties: none
-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:
Return:
#email_drop_handler{} properties:
- notification:
unknown - user_id:
unknown - resource_id:
unknown
-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:
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
-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:
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
-callback observe_email_is_blocked(#email_is_blocked{recipient :: binary()}, z:context()) -> boolean() | undefined.
Check if an email address is blocked
Type:
Return:
#email_is_blocked{} properties:
- recipient:
binary
-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:
Return:
#email_is_recipient_ok{} properties:
- recipient:
binary
-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:
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
-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:
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()
-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:
Return:
#email_sent{} properties:
- message_nr:
binary - recipient:
binary - is_final:
boolean
-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:
Return:
#email_status{} properties:
- recipient:
binary - is_valid:
boolean - is_final:
boolean - is_manual:
boolean
-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:
Return:
{ok, <<”inline”>>} or {ok, <<”attachment”>>}
#export_resource_content_disposition{} properties:
- dispatch:
atom - id:
m_rsc:resource_id()|undefined - content_type:
binary
-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:
Return:
{ok, "text/csv"}) for the dispatch rule/id export.
#export_resource_content_type{} properties:
- dispatch:
atom - id:
m_rsc:resource_id()|undefined
-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:
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
-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:
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
-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:
Return:
{ok, Filename}} or undefined
#export_resource_filename{} properties:
- dispatch:
atom - id:
m_rsc:resource_id()|undefined - content_type:
binary
-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:
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
-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:
Return:
true or false
#export_resource_visible{} properties:
- dispatch:
atom - id:
m_rsc:resource_id()|undefined
-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:
Return:
return value is ignored
#filewatcher{} properties:
- verb:
modify|create|delete - file:
binary - basename:
binary - extension:
binary
-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:
Return:
#hierarchy_updated{} properties:
- root_id:
binary|integer - predicate:
atom - inserted_ids:
list - deleted_ids:
list
-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:
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
-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:
Return:
#identity_password_match{} properties:
- rsc_id:
m_rsc:resource_id()|undefined - password:
binary - hash:
m_identity:hash()|tuple
-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:
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
-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:
Return:
#identity_verification{} properties:
- user_id:
m_rsc:resource_id() - identity:
undefined|m_identity:identity()
-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:
Return:
#identity_verified{} properties:
- user_id:
m_rsc:resource_id() - type:
m_identity:type() - key:
m_identity:key()
-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:
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()
-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:
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
Notify that the session’s language has been changed
Type:
Return:
#language{} properties:
- language:
atom
-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:
Return:
#language_detect{} properties:
- text:
binary - is_editable_only:
boolean
-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:
Return:
#logon_options{} properties:
- payload:
map
-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:
Return:
a URL or undefined
#logon_ready_page{} properties:
- request_page:
union
-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:
Return:
#logon_submit{} properties:
- payload:
map
-callback observe_m_config_update(#m_config_update{module :: atom(), key :: term(), value :: term()}, z:context()) -> any().
Site configuration parameter was changed
Type:
Return:
return value is ignored
#m_config_update{} properties:
- module:
atom - key:
term - value:
term
-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:
Return:
return value is ignored
#m_config_update_prop{} properties:
- module:
unknown - key:
unknown - prop:
unknown - value:
unknown
-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:
Return:
#mailinglist_mailing{} properties:
- list_id:
union - email:
union - page_id:
m_rsc:resource() - options:
list
-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:
Return:
#mailinglist_message{} properties:
- what:
send_welcome|send_confirm|send_goodbye|silent - list_id:
m_rsc:resource() - recipient:
proplists:proplist()|integer
-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:
Return:
Extension (for example <<".png"\>\>) or undefined
#media_identify_extension{} properties:
- mime:
binary - preferred:
undefined|binary
-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:
Return:
map with binary keys, especially <<"mime"\>\>, <<"width"\>\>, <<"height"\>\>, <<"orientation"\>\>
#media_identify_file{} properties:
- filename:
file:filename_all() - original_filename:
binary - extension:
binary
-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:
Return:
modified #media_upload_preprocess{}
#media_import{} properties:
- url:
binary - host_rev:
list - mime:
binary - metadata:
tuple
-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:
Return:
ok | {error, term()}.
#media_import_medium{} properties:
- id:
m_rsc:resource_id() - medium:
map
-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:
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()
-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:
Return:
return value is ignored
#media_replace_file{} properties:
- id:
m_rsc:resource_id() - medium:
map|undefined
-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:
Return:
#media_stillimage{} properties:
- id:
m_rsc:resource_id()|undefined - props:
z_media_identify:media_info()
-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:
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
-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:
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
-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:
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
-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:
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()
-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:
Return:
{ok, Html} or undefined
#media_viewer{} properties:
- id:
unknown - props:
z_media_identify:media_info() - filename:
union - options:
list
-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:
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
-callback observe_middleware(#middleware{on :: request | welformed | handled}, Acc, z:context()) -> Result when Acc :: z:context(), Result :: z:context().
Delegates the request processing.
Type:
Return:
updated z:context()
#middleware{} properties:
- on:
request|welformed|handled
-callback observe_module_activate(#module_activate{module :: atom(), pid :: pid()}, z:context()) -> any().
A module has been activated and started.
Type:
Return:
#module_activate{} properties:
- module:
atom - pid:
pid
A module has been stopped and deactivated.
Type:
Return:
#module_deactivate{} properties:
- module:
atom
-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:
Return:
#output_html{} properties:
- html:
term
-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:
Return:
{ok, Url} or undefined
#page_url{} properties:
- id:
m_rsc:resource_id() - is_a:
list
-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:
Return:
#pivot_fields{} properties:
- id:
m_rsc:resource_id() - raw_props:
m_rsc:props()
-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:
Return:
#pivot_rsc_data{} properties:
- id:
m_rsc:resource_id()
-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:
Return:
#pivot_update{} properties:
- id:
m_rsc:resource_id() - raw_props:
m_rsc:props()
-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:
Return:
undefined or #context{} with the result of the postback
#postback_notify{} properties:
- message:
unknown - trigger:
unknown - target:
unknown - data:
unknown
-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:
Return:
#context{}
#request_context{} properties:
- phase:
union - document:
map
-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:
Return:
list( {binary(), binary()} )
#resource_headers{} properties:
- id:
m_rsc:resource_id()|undefined
-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:
Return:
#rsc_delete{} properties:
- id:
m_rsc:resource_id() - is_a:
list
-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:
Return:
#rsc_get{} properties:
- id:
m_rsc:resource_id()
-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:
Return:
{ok, map()} | {ok, m_rsc:resource_id()} | {ok, {m_rsc:resource_id(), map()}} | {error, term()} | undefined
#rsc_import_fetch{} properties:
- uri:
binary
-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:
Return:
proplist accumulator
#rsc_insert{} properties:
- props:
m_rsc:props()
-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:
Return:
#rsc_merge{} properties:
- winner_id:
m_rsc:resource_id() - loser_id:
m_rsc:resource_id() - is_merge_trans:
boolean
-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:
Return:
#rsc_pivot_done{} properties:
- id:
m_rsc:resource_id() - is_a:
list
-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:
Return:
return value is ignored
#rsc_query_item{} properties:
- query_id:
m_rsc:resource_id() - match_id:
m_rsc:resource_id()
-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:
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.
-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:
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.
-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:
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
-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:
Return:
#sanitize_element{} properties:
- element:
tuple - stack:
list
-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:
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.
-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:
Return:
#scomp_script_render{} properties:
- is_nostartup:
boolean - args:
list
-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:
Return:
#search_sql_term{}, [], or undefined
#search_query{} properties:
- name:
union - args:
union - offsetlimit:
tuple - unknown:
unknown - search:
union
See also
-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:
Return:
#search_sql_term{}, [], or undefined
#search_query_term{} properties:
- term:
binary - arg:
any
-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:
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.
-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:
Return:
#context{}
#session_context{} properties:
- request_type:
http|mqtt - payload:
union
-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:
Return:
#set_user_language{} properties:
- id:
m_rsc:resource_id()
-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:
Return:
#signup{} properties:
- id:
m_rsc:resource_id()|undefined - props:
map - signup_props:
list - request_confirm:
boolean
-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:
Return:
{ok, Props, SignupProps} or {error, Reason}
#signup_check{} properties:
- props:
map - signup_props:
list
-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:
Return:
#signup_confirm{} properties:
- id:
m_rsc:resource()
-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:
Return:
a URL or undefined
#signup_confirm_redirect{} properties:
- id:
m_rsc:resource()
-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:
Return:
#signup_done{} properties:
- id:
m_rsc:resource() - is_verified:
boolean - props:
map - signup_props:
list
-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:
Return:
#signup_failed_url{} properties:
- reason:
unknown
-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:
Return:
#signup_url{} properties:
- props:
map - signup_props:
list
-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:
Return:
#ssl_options{} properties:
- server_name:
binary
-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:
Return:
list with tuples: [ {handler_name, TitleForDisplay}, ... ]
#survey_get_handlers{} properties: none
-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:
Return:
true, false or undefined
#survey_is_allowed_results_download{} properties:
- id:
m_rsc:resource_id()
-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:
Return:
true, false or undefined
#survey_is_submit{} properties:
- block:
map
-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:
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
-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:
Return:
list( {binary(), binary() | #trans{}} )
#survey_result_columns{} properties:
- id:
m_rsc:resource_id() - handler:
binary|undefined - format:
html|text
-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:
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()
-callback observe_tkvstore_delete(#tkvstore_delete{type :: term(), key :: term()}, z:context()) -> any().
Delete a value from the typed key/value store
Type:
Return:
return value is ignored
#tkvstore_delete{} properties:
- type:
unknown - key:
unknown
-callback observe_tkvstore_get(#tkvstore_get{type :: term(), key :: term()}, z:context()) -> term() | undefined.
Get a value from the typed key/value store
Type:
Return:
#tkvstore_get{} properties:
- type:
unknown - key:
unknown
-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:
Return:
#tkvstore_put{} properties:
- type:
unknown - key:
unknown - value:
unknown
-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:
Return:
#translate{} properties:
- from:
atom - to:
atom - texts:
list
-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:
Return:
#url_abs{} properties:
- url:
unknown - dispatch:
unknown - dispatch_options:
unknown
-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:
Return:
z_url_fetch:options()
#url_fetch_options{} properties:
- method:
get|post|put|delete - host:
binary - url:
binary - options:
z_url_fetch:options()
-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:
Return:
#url_rewrite{} properties:
- dispatch:
atom - args:
list
-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:
Return:
#user_context{} properties:
- id:
m_rsc:resource_id()
-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:
Return:
#user_is_enabled{} properties:
- id:
m_rsc:resource_id()
-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:
Return:
{ok, list( {binary(), z:qvalue()} )} | {error, term()}
#validate_query_args{} properties: none
-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()].
-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.
-callback pid_observe_acl_logon(pid(), #acl_logon{id :: m_rsc:resource_id(), options :: map()}, z:context()) -> z:context() | undefined.
-callback pid_observe_acl_user_groups(pid(), #acl_user_groups{}, z:context()) -> Groups | undefined when Groups :: [m_rsc:resource_id()].
-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()].
-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().
-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()}].
-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.
-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.
-callback pid_observe_auth_confirm(pid(), #auth_confirm{id :: m_rsc:resource_id()}, Acc, z:context()) -> Result when Acc :: z:context(), Result :: z:context().
-callback pid_observe_auth_confirm_done(pid(), #auth_confirm_done{id :: m_rsc:resource_id()}, z:context()) -> any().
-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().
-callback pid_observe_auth_logon(pid(), #auth_logon{id :: m_rsc:resource_id()}, Acc, z:context()) -> Result when Acc :: z:context(), Result :: z:context().
-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.
-callback pid_observe_comment_insert(pid(), #comment_insert{comment_id :: integer(), id :: m_rsc:resource_id()}, z:context()) -> any().
-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()]}.
-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().
-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()}.
-callback pid_observe_dropbox_file(pid(), #dropbox_file{filename :: file:filename_all(), basename :: binary()}, z:context()) -> Result when Result :: ok | {ok, processing} | undefined.
-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().
-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().
-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().
-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().
-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.
-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().
-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().
-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().
-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().
-callback pid_observe_export_resource_visible(pid(), #export_resource_visible{dispatch :: atom(), id :: m_rsc:resource_id() | undefined}, z:context()) -> boolean() | undefined.
-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().
-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().
-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().
-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.
-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().
-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.
-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.
-callback pid_observe_language_detect(pid(), #language_detect{text :: binary(), is_editable_only :: boolean()}, z:context()) -> Result when Result :: z_language:language_code() | undefined.
-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().
-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().
-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.
-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.
-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().
-callback pid_observe_media_replace_file(pid(), #media_replace_file{id :: m_rsc:resource_id(), medium :: map() | undefined}, z:context()) -> any().
-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.
-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.
-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()}.
-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().
-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().
-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().
-callback pid_observe_page_url(pid(), #page_url{id :: m_rsc:resource_id(), is_a :: [atom()]}, z:context()) -> {ok, binary()} | undefined.
-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()}.
-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().
-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().
-callback pid_observe_rsc_delete(pid(), #rsc_delete{id :: m_rsc:resource_id(), is_a :: [atom()]}, z:context()) -> any().
-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().
-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.
-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().
-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().
-callback pid_observe_rsc_pivot_done(pid(), #rsc_pivot_done{id :: m_rsc:resource_id(), is_a :: [atom()]}, z:context()) -> any().
-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().
-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()}.
-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().
-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.
-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.
-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()}.
-callback pid_observe_set_user_language(pid(), #set_user_language{id :: m_rsc:resource_id()}, z:context()) -> z:context() | undefined.
-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.
-callback pid_observe_signup_confirm(pid(), #signup_confirm{id :: m_rsc:resource()}, z:context()) -> any().
-callback pid_observe_signup_confirm_redirect(pid(), #signup_confirm_redirect{id :: m_rsc:resource()}, z:context()) -> Result when Result :: URL | undefined, URL :: binary().
-callback pid_observe_ssl_options(pid(), #ssl_options{server_name :: binary()}, z:context()) -> SSLOptions | undefined when SSLOptions :: {ok, [ssl:tls_option()]}.
-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.
-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().
-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().
-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.
-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.
-callback pid_observe_user_context(pid(), #user_context{id :: m_rsc:resource_id()}, Acc, z:context()) -> Result when Acc :: z:context(), Result :: z:context().
-callback pid_observe_user_is_enabled(pid(), #user_is_enabled{id :: m_rsc:resource_id()}, z:context()) -> boolean() | undefined.