Implement Inbox Functionality in custom cq component? - aem

We want to develop a smooth-flowing workflow experience (but still use workflows). Currently, a user needs to use the sidekick to initiate the workflow, then to the inbox, which takes them back to the page to use the sidekick again. When they go to the inbox, they need to restrict to the model and path of the page. It would be nice for the user to only have to go to the content page and from there, launch the different workflow forms that need to happen, like a little "inbox" right on the page that is subject to the workflow.
I have written a custom component that can initiate the custom workflow. The custom component can also query the WorkFlowSession and obtain any active WorkItems for the current page that the component resides (using the WorkItemFilter interface). What I want to do is provide a link to the user to the next step in the workflow from the custom component, just like the inbox does.
Here is an example output from an WorkItem instance toString method:
21.05.2014 09:45:29.300 *ERROR* [0:0:0:0:0:0:0:1%0 [1400679929160] GET /content/test/mailing1.html HTTP/1.1] org.rand.whatcounts.EmailCampaignCoordinator Found workitem: -----------------------------
WorkItem Id: /etc/workflow/instances/2014-05-21/model_1400679794564399000/workItems/node4_etc_workflow_instances_2014-05-21_model_1400679794564399000
Workflow Id: /etc/workflow/instances/2014-05-21/model_1400679794564399000
Payload: /content/test/mailing1
Payload Type: JCR_PATH
key = historyEntryPath value = /etc/workflow/instances/2014-05-21/model_1400679794564399000/history/1400679924113
key = comment value =
My hope is that by using the workflow api items, I can create the link that the user could click on to proceed in the workflow (just like the inbox).
Thanks for listening!
Phillip

There are two ways to implement this
Java-Based Solution
I was able to figure out one way by looking at
http://localhost:4502/libs/cq/workflow/components/inbox/list/json.jsp
The important part of this jsp is that, given a workItem instance, you can get the path for your next step using the JcrPathBuilderManager:
pathBuilder.getPath(wi);
Using this, I was able to output a link to the next step in the workflow to the user (without having user go to their inbox).
Javascript/JSON Based Solution
I didn't go far with this solution (I didn't write any js) but this was my fall back position if I didn't find the java-solution listed above. Once could implement custom JS in CQ Component that would call the json feed for the user inbox, do some client side filtering (to restrict it to only items related to current page). The URL to the feed is
http://localhost:4502/libs/cq/workflow/content/inbox/list.json?start=0&limit=40
Thanks!

Related

Support multi-site approval based workflow on wagtail

Objective
We would like to setup multi-site wagtail with approval chain.
Develop -> QA -> Release -> Production
Description
A develop / content editor goes to the wagtail admin and creates the content. Once done, sends the request for approval to move to QA site.
QA moderator reviews the content on develop site. If approved, the content gets moved to QA site. The content carries over to next stage approval (release).
Same process ahead for next sites in approval chain.
Questions
Is it possible to setup a publish chain with approval policy in wagtail? I tried to research a bit but could only find "workflow" and "workflow tasks". Do I need to custom code a workflow task to be able to achieve this?
This should be possible but you will need to consider what you really want to do in regards to the 'move' step, do you want to actually move the Page instance to a new site in a new tree or copy the current (and its history) and move that copy Page OR make a copy to put in place of the Page that was moved.
Nonetheless, the documentation on how to add a new Task type is the best place to start, it walks you through custom Task types.
In the solution below however, I thought it would be simplest to create a new model that behaves exactly like GroupApprovalTask (the default task included, used for moderation) but add a field that links it to the Site model.
This way, in the admin UI the admin users can now create as many PublishSiteTask as you want, one for each Site (QA/Dev/Prod etc) and then each of those could be linked to different user groups. It is important to differentiate between the database model (a task type with some fields) and the instances (a task created in the UI) and the actual task instances that are created against each page revision (not page) as the workflow steps progress.
Code Example
models.py
from django.db import models, transaction
from wagtail.core.models import GroupApprovalTask, Page, Site
# ... other imports
class PublishSiteTask(GroupApprovalTask):
site = models.OneToOneField(Site, on_delete=models.CASCADE)
admin_form_fields = ['site'] + GroupApprovalTask.admin_form_fields
#transaction.atomic
def on_action(self, task_state, user, action_name, **kwargs):
"""Performs an action on a task state determined by the ``action_name`` string passed"""
if action_name == 'approve':
# get the page that this action is referring to via the task_state.page_revision
page = task_state.page_revision.as_page_object()
# find the new parent target at this task's site
# how this is done depends on the site/page structure
new_parent_target = self.site.root_page
# move the page to a new location
# note: this will actually move it from its current tree, you may want to make a copy first
page.move(new_parent_target)
# be sure to preserve any existing task behaviour
super().on_action(task_state, user, action_name, **kwargs)
Additional Links
Task class definition
GroupApprovalTask class definition
You may want to do some pre-work in the code to check that the page can actually move to the different Site, each Page has a method can_move_to that could help.
The move method referenced above is part of the Wagtail code but the full docs for that method can be found in the Treebeard API docs which Wagtail uses to manage the tree structure.

How to populate fields of an online form

I created a custom record (child of Inventory item) and an online form.
The final goal it's to send a link to a user (not a netsuite user) to display the different informations of this custom record. The user will be able to update some values and submit the form.
I saw it's possible to link a script file to this form, but I need the ID of the record to load it and populate every field of the form.
With normal forms, we have the internalid of the record as an URL param but in this case there is nothing in the URL .
Do you know any way to achieve that ?
A solution for the final goal could be:
Create an empty Suitelet (provides external link for User). Or refer to step 4 for contents.
Stored on the Custom record or via script (created in step 3) you can add to the external link, to include the record type and id as url parameters (&recordtype=customrecord&recid=12345). Be sure to avoid reserved parameter names.
Create a UserEvent, Client, or Scheduled Script to send email to User based on your requirements (in the email include the custom external suitelet link). User will click on the link and land on a NetSuite looking webpage (not requiring credentials).
Modify empty Suitelet. Suitelet should when context.request.method===GET: get parameters, load record(s), get data from record(s), create form, display data to User, display fields for User to enter data, add submit and refresh/cancel button, write/display the form with all fields. Upon submission (when context.request.method is not GET) you can use record.submit method to update the custom record(s).
NetSuite Suite Answer Id 74607 has a Sample Custom Form Suitelet Script from that can be very helpful.

Can "Request Publication" request go to a group other than the admin group in AEM6.1?

When a user does not have rights to publish a page, he sees "Request publication" button in Touch UI editor mode. When he clicks on "Request Publication", the workflow "Request for activation" starts and go to the admin's inbox. I want the page to go to some other group for publishing. How can I achieve this?
As shown in the image above, you can change the user/group to be anyone/anything in your instance.
You just need to change properties of default "Request for Activation" workflow.
However, it is recommended to make a new workflow of your own so that upgrades and patches don't revert your changes.
On the /libs/cq/workflow/content/console.html page with all available workflows. You should find workflow that you are interested in.
In you case it is possibly http://localhost:4502/cf#/etc/workflow/models/request_for_activation.html
On this page you can workflow config which contains several steps. Open for editing Request for activation step, switch to tab Arguments and then you can change Name patterns field. It should be regex pattern e.g. .*approver.* for all groups which contains approver in name.
As a variant you can custom workflow or step. In this case you need to figure out by you self how to configure it but usually it is something similar.

How to send email when user is created from BCC ATG?

On creation of new external user from ATG BCC, I need to include some logic like encrypting password and sending email to user. Achieved this functionality by extending GSAPropertyDescriptor class and overriding its getPropertyValue(RepositoryItemImpl pItem, Object pValue) method.
Problem is, this method is getting called only when we click on create button from "General" tab present in users section, but not on click of same create button from other tabs like "Commerce", "Orgs & Roles", "User Segments" and "Advanced".
Please suggest!!
It is not a good idea to override getPropertyValue of an item for this implementation. The right way to do this is to work with the formhandler that is responsible for saving the user. It is a bit tricky to find this formhandler. It will be in the atg/web/viewmapping/ViewMappingRepository/ of the BCC instance. In this repository there will be lots of formhandlers configured for different purposes. You have to pick the one relevant for the user edit. Here is an example of what you might find there:
With this, you go to appropriate Formhanlder, like /atg/web/assetmanager/editor/profile/UserFormHandler mentioned here. And override that component in your module with your own implementation. Once that is done, you'll have the control of the action. You can do your work and pass on the control to super class (the original implementation).
Regards,
Jags

How do I correctly Implement an event on successful form Submission using Google Tag Manager and Sitecore's Web Forms for Marketers?

I am attempting to track successful form Submissions using an event in Google Analytics via Google Tag Manager. My current setup successfully tracks when users submit the form. However, the event still fires even when the form submission is invalid and does not submit (ie a user hasn't filled out all of the required fields, clicks the submit button, the form attempts to validate, but comes back to the user with errors instead of submitting). I have the Check Validation feature on my listener checked which theoretically should keep the tag from firing if the form submission is prevented, so it's not the obvious error.
The form in question is created with Sitecore's Web Forms for Marketers. Colleagues of mine have had similar unsolved issues with their WFFM forms.
This particular form is used to gate content so that only users who fill out the form will have access to the content resource. So for example if I go to www.mydomain.com/resource I will be redirected to www.mydomain.com/form where if I fill out all of my information correctly and submit it I will then be redirected to the resource that I was originally attempting to view at www.mydomain.com/resource.
Here's my setup:
Tag 1
Name: Form Submission Listener
Type: Form Submit Listener
Wait For Tags: Checked
Max Wait Time: 2000 milliseconds
Check Validation: Checked
No advanced Settings
Firing Rule: On form pages by URL
Tag 2
Name: Event Form Submission
Type: Universal Analytics
Tracking ID: UA-.....
Enable Display Advertising Features: Checked
Track Type: Event
Category: Form
Action: Submission
Label: {{Form resource URL}}
Non-Interaction Hit: False
No More Settings
No Advanced Settings
Firing Rules: {{event}} equals gtm.formSubmit
Theoretically the Check Validation check box should prevent the tag from firing if the form does not successfully submit, but in the case of this form it does not. The tag fires regardless of whether the form submits or not.
Apologies that I cannot link to the form as it is for a client and behind security.
We were able to find an answer to our question via the Sitecore forums, but I wanted to pass it along for your benefit.
From Sitecore:
The Web Forms module provides the double level validation, 1-client validation, 2-server validation.
By default, the client validation is disable for the Required Field validator. So, when you press Submit, the form posts to the server, and returns with the validation error. It's a possible reason why Google Analytics considers that as a form submit.
Find the following item in the Master database:
/sitecore/system/Modules/Web Forms for Marketers/Settings/System/System Validation/NotEmpty
Find the "Enable Client Script" checkbox and enable it.
Save and publish the item.
Check whether the issue was fixed.
This fixed the issue for all of our text based fields. It did not fix the issue for the one checkbox on the form. I've followed up with sitecore on this, but I figured that I'd update here in the meantime.
With only the checkbox remaining I was also able to use a a macro and add to my original firing rule in google tag manager so that the event would not fire if the checkbox was not checked.
I created a Custom Javascript Macro called Radio Button Checked (not sure it's the best, but it worked), and added a new condition to my original Form Submission Rule: {{Radio Button Checked}} equals true
The macro:
function() {
var radioName = "radioButtonName";
try {
var buttons = document.getElementsByName(radioName);
for (var i = 0;i < buttons.length;i++){
if(buttons[i].checked) {
return true;
}
}
} catch(e) {}
return false;
}
EDIT: Sitecore got back to me about the checkbox issue.
From Sitecore:
Currently the CheckBox field type doesn't have the client-side validation. I registered it as a bug for the WFFM module. I'll let you know as soon as it's fixed.
They let me know also that this isn't something that will be fixed near-term so I need to continue using my GTM workaround for the check box field.
The Google Chrome plugin "Tag Assistant" is super helpful in debugging these sorts of issues. It will show you what (if any) structural or implementation issues exist on a given page that might be preventing your intended tracking behavior (https://chrome.google.com/webstore/detail/tag-assistant-by-google/kejbdjndbnbjgmefkgdddjlbokphdefk?hl=en)
My gut feel is that this issue is not specifically related to WFFM, but may be due to the implementation of the Tag Manager code on the page. I seem to recall having an issue like this when the Tag Manager include code gets dumped inside the auto-generated .NET tag when using WebForms in general. Google's docs (https://developers.google.com/tag-manager/quickstart) say to put it immediately after the opening tag, and I recall that being my issue with tracking form submits.
This is all from memory, so I could be wrong, but it's something else to check.
Good luck!