Programmatically adding portlets - liferay

Is it possible to add a portlet programmatically? If yes, please help me to understand the steps for that.

Liferay CE comes with the "sevencogs-hook" that contains code to set up the demo content, e.g. the "Seven Cogs" virtual company used to demo a Liferay site. This sets up a complete site programmatically. You can read that code and learn how users and pages are created, portlets are added to pages and configured to show what they are supposed to show. More than that: It's running code that can easily be read and is - as side effect - a nice piece of documentation.
http://svn.liferay.com/repos/public/plugins/trunk/hooks/sevencogs-hook/
Login: "guest", no password
or download the source for the version you're referring to.

Something like:
ThemeDisplay themeDisplay = (ThemeDisplay) request.getAttribute(WebKeys.THEME_DISPLAY);
Layout layout = themeDisplay.getLayout();
long plid = layout.getPlid();
long ownerId = PortletKeys.PREFS_OWNER_ID_DEFAULT;
int ownerType = PortletKeys.PREFS_OWNER_TYPE_LAYOUT;
long companyId = themeDisplay.getCompanyId();
String portletIdInc = layoutTypePortlet.addPortletId(userId, thisPortletID);
// Retrieve the portlet preferences portlet instance just created
PortletPreferences prefs = PortletPreferencesLocalServiceUtil
.getPreferences(companyId, ownerId, ownerType, plid, portletIdInc);
// set desired language
String languageId = LanguageUtil.getLanguageId(request);
String urlImage = .... ;
prefs.setValue("portlet-setup-title-" + languageId, report.getName());
prefs.setValue("portlet-setup-use-custom-title", "true");
prefs.setValue("src", report.getUrl());
prefs.setValue("img", urlImage);
prefs.store();
String targetColumn = "column-1";
// update the portlet preferences
PortletPreferencesLocalServiceUtil.updatePreferences(ownerId,
ownerType, plid, portletIdInc, prefs);
if (Validator.isNotNull(targetColumn) && Validator.isNotNull(portletIdInc)) {
layoutTypePortlet.movePortletId(userId, portletIdInc, targetColumn, 2);
}
LayoutServiceUtil.updateLayout(layout.getGroupId(), layout.isPrivateLayout(),
layout.getLayoutId(), layout.getTypeSettings());

Related

Liferay 7.2 render url of a portlet with instance

I have Liferay 7.2.
Jsp file for the view of a custom portlet.
I'm trying to generate a url from a custom portlet to link the document media portlet (com_liferay_document_library_web_portlet_DLPortlet).
I try
<liferay-portlet:actionURL name="newMyNew" portletName="com_liferay_document_library_web_portlet_DLPortlet" var="prueba2"></liferay-portlet:actionURL>
output:
http://localhost:8080/web/guest/home?p_p_id=com_liferay_document_library_web_portlet_DLPortlet&p_p_lifecycle=1&p_p_state=normal&p_p_mode=view&_com_liferay_document_library_web_portlet_DLPortlet_javax.portlet.action=newMyNew&p_auth=1IDKtzvU
But i need the instance ID of the Document Media portlet (com_liferay_document_library_web_portlet_DLPortlet) because i need that it receive the variables like folderId
i need this output:
http://localhost:8080/web/guest/home/-/document_library/jFOlAlmeJgMl/view/34527?_com_liferay_document_library_web_portlet_DLPortlet_INSTANCE_jFOlAlmeJgMl_redirect=http%3A%2F%2Flocalhost%3A8080%2Fweb%2Fguest%2Fhome%3Fp_p_id%3Dcom_liferay_document_library_web_portlet_DLPortlet_INSTANCE_jFOlAlmeJgMl%26p_p_lifecycle%3D0%26p_p_state%3Dnormal%26p_p_mode%3Dview
How can i do that?
I found the solution to get the instance id of portlet
List<Portlet> portletListDUE = layoutTypePortlet.getAllPortlets();
String portletInstanceId = "";
for(Portlet portletIn : portletListDUE) {
String portletNameOfInstance = portletIn.getPortletName();
if(portletNameOfInstance.equals("com_liferay_document_library_web_portlet_DLPortlet"))
{
portletInstanceId = portletIn.getInstanceId();
}
}

Customizing the sharepoint document set

I have to customize sharepoint 2013 document set welcome page(document set properties web part) and
I am not able to find the document set home aspx page
Can I use any client context model to fetch the data and display doc set properties.
Just create a new content type inheriting from Document Set, add the extra columns and set which ones need to be shown on the welcome page via the Document Set settings link when editing the Content Type. Also under the Document Set settings page you can click on 'Customize the Welcome Page' which allows you to edit the page just like any other web part page.
On the second point the client context will need to be connected to the web that contains the list and specific document set you're after, the identity used to connect will need permissions to the document set.
Edit:
To customize the look and feel by injecting JavaScript/CSS you'll need to make use of the ScriptLink custom action.
This lets you inject a custom piece of JavaScript into all pages. In the script you'll need logic to determine if the custom CSS should be applied, and if so Inject it.
The C# for injecting a script block via ScriptLink Custom Action:
public void AddJsLink(ClientContext ctx, Web web)
{
string scenarioUrl = String.Format("{0}://{1}:{2}/Scripts", this.Request.Url.Scheme,
this.Request.Url.DnsSafeHost, this.Request.Url.Port);
string revision = Guid.NewGuid().ToString().Replace("-", "");
string jsLink = string.Format("{0}/{1}?rev={2}", scenarioUrl, "injectStyles.js", revision);
StringBuilder scripts = new StringBuilder(#"
var headID = document.getElementsByTagName('head')[0];
var");
scripts.AppendFormat(#"
newScript = document.createElement('script');
newScript.type = 'text/javascript';
newScript.src = '{0}';
headID.appendChild(newScript);", jsLink);
string scriptBlock = scripts.ToString();
var existingActions = web.UserCustomActions;
ctx.Load(existingActions);
ctx.ExecuteQuery();
var actions = existingActions.ToArray();
foreach (var action in actions)
{
if (action.Description == "injectnavigation" &&
action.Location == "ScriptLink")
{
action.DeleteObject();
ctx.ExecuteQuery();
}
}
var newAction = existingActions.Add();
newAction.Description = "injectnavigation";
newAction.Location = "ScriptLink";
newAction.ScriptBlock = scriptBlock;
newAction.Update();
ctx.Load(web, s => s.UserCustomActions);
ctx.ExecuteQuery();
}
Then your JavaScript would have something like:
if(window.location.href.indexOf(patternToMatchToDocSetpage)>-1) {
var link = document.createElement("link");
link.href = "http://example.com/mystyle.css";
link.type = "text/css";
link.rel = "stylesheet";
document.getElementsByTagName("head")[0].appendChild(link);
}
I'd advise you to take a look at the relevant PnP sample on script link injection

Liferay: How to find all Layouts with the specific JournalArticle in AssetPublisher portlets?

The requirements is easy. Someone publish a JournalArticle with some Tags (TagA, TagB). On the other pages (Layouts) we have AssetPublisher portles that show all JournalArticles with those Tags (e.g. TagA or TagB). The question is, how to get this layouts programmaticaly?
I solve it with recursive DynamicQuery, enjoy:
public static Set<Layout> getLayoutsWithThisTags(SortedSet<String> tags) throws SystemException, PortalException {
Set<Layout> layouts = new HashSet<Layout>();
//build DynamicQuery that contains "assetTags" as "queryName0", see configuration of AssetPublisher
DynamicQuery query = DynamicQueryFactoryUtil.forClass(com.liferay.portal.model.PortletPreferences.class, PortalClassLoaderUtil.getClassLoader())
.add(PropertyFactoryUtil.forName("preferences").like("%<preference><name>queryName0</name><value>assetTags</value></preference>%"))
.add(getTagConditions(tags));
Set<PortletPreferences> preferences = new HashSet<PortletPreferences>(PortletPreferencesLocalServiceUtil.dynamicQuery(query));
for (PortletPreferences portletPreferences : preferences) {
long plid = portletPreferences.getPlid();
layouts.add(LayoutLocalServiceUtil.getLayout(plid));
}
return layouts;
}
private static Criterion getTagConditions(SortedSet<String> tags) {
//create recursive OR-Criterion that contains any of the tags
Criterion criterion = RestrictionsFactoryUtil.or(
PropertyFactoryUtil.forName("preferences").like("%<preference><name>queryValues0</name>%<value>" + tags.first() +"</value>%"),
(tags.size() > 2) ? getTagConditions(tail(tags)) :
PropertyFactoryUtil.forName("preferences").like("%<preference><name>queryValues0</name>%<value>" + tags.last() +"</value>%"));
return criterion;
}
private static SortedSet<String> tail(SortedSet<String> tags) {
tags.remove(tags.first());
return tags;
}
for Portal with 250 Pages (Layouts) this code need 12ms.
Suddenly this came to my mind :-)
List assetPublisherLayouts;
List<Layout> layouts = LayoutLocalServiceUtil.getLayouts(groupId, privateLayout);
for (Layout layout : layouts)
{
if(layout.getTypeSettings().contains("101_INSTANCE")) {
assetPublisherLayouts.add(layout);
}
}
While 101 being the protlet ID for Asset publisher and it is instantiable..
I can think of two ways:
Using DynamicQuery to fetch Layouts that contain Asset Publisher portlets and then processing the Layout list retrieved for those specific layouts which have Asset Publisher with TagA & TagB.
The code might be something like this (disclaimer: it is just pseudo code :-)):
layoutDynamicQuery.add(RestrictionFactoryUtil.ilike("typeSettings","%101_INSTANCE%"));
List<Layout> layoutList = LayoutLocalServiceUtil.dynamicQuery(layoutDynamicQuery);
List<Layout> finalLayoutList = new ArrayList<Layout>();
for (Layout layout : layoutList) {
// 1) fetch portletIds for this layout
// 2) fetch relevant PortletPreferences for the instance-id for the AssetPublisher portlet, can use PortletPreferencesLocalServiceUtil
// 3) Check if the tags (TagA & TagB) are present in the preference retrieved.
// 4) if point-3 is true then: finalLayoutList.add(layout);
}
Using custom-sql to fetch the Layouts in a single complex sql query, by joining/subquerying required tables like AssetTags, Layout, PortletPreferences etc.
This is not a general requirement scenario in liferay, so it is obvious that there won't be a direct way of doing this.
Hope this proves to be of some help.

Get all users from active directory to sharepoint

I have to populate my autocomplete PeopleEditor-like control based on brililant ASPTokenInput with all people from my AD domain. Reflecting PeopleEditor shows a real mess in their Active Directory search engine and all potentially helpful classes are internal.
My test method works fine, but I need to get ALL users from AD(not sharepoint site ones) to populate my list:
public string GetUsers(string filter)
{
var spWeb = SPContext.Current.Web;
SPUserCollection allusers = spWeb.AllUsers;
List<SPUser> users = allusers.Cast<SPUser>().ToList();
var query = from spUser in users.Select(usr => new {id = usr.ID, name = usr.Name})
.Where(p => p.name.IndexOf(filter, StringComparison.InvariantCultureIgnoreCase) >= 0)
select new {id = spUser.id.ToString(), spUser.name};
return new JavaScriptSerializer().Serialize(query);
}
How can I query active directory like this? Is it possible to retrieve all AD connection settings from sharepoint itself? I need just id and user name to fill my dropdownlist Converting this to SPUserCollection is another big deal.
It would be great to use some built-in SP methods like this:
[SubsetCallableExcludeMember(SubsetCallableExcludeMemberType.UnsupportedSPType)]
public static IList<SPPrincipalInfo> SearchWindowsPrincipals(SPWebApplication webApp, string input, SPPrincipalType scopes, int maxCount, out bool reachMaxCount)
Solution was simple, the only thing I needed was SharePoint Group search implementation (If specified in Field Editor Control). SP has a nice built-in method, so I use it.
/// <summary>
/// Provides searching for AD or SharePoint group if specified in field setting
/// </summary>
public static class ActiveDirectorySearchProvider
{
public static IList<SPPrincipalInfo> Search(string filter, string selectionGroup, string principalType)
{
var site = SPContext.Current.Site.WebApplication;
bool reachmaxcount;
var scope = SPUtils.GetSpPrincipalType(principalType);
if (!String.IsNullOrEmpty(selectionGroup)) //search for users in SPGroup if present
{
var rawSPGroupList = SPUtility.GetPrincipalsInGroup(SPContext.Current.Web, selectionGroup, 100,
out reachmaxcount).ToList();
string lowerFilter = filter.ToLowerInvariant();
var filteredGroupList =
rawSPGroupList.Where(
pInfo =>
pInfo.LoginName.Substring(pInfo.LoginName.IndexOf('\\') + 1).StartsWith(lowerFilter) ||
pInfo.DisplayName.ToLowerInvariant().StartsWith(lowerFilter) ||
pInfo.DisplayName.ToLowerInvariant().Substring(pInfo.DisplayName.IndexOf(' ') + 1).StartsWith(
lowerFilter)).ToList();
return filteredGroupList;
}
return SPUtility.SearchWindowsPrincipals(site, filter, scope, 100, out reachmaxcount); //Search in AD instead
}
I can think of two options here.
You can use System.DirectoryServices and query all users from your Active Directory in your c# code.
You can setup User Profile Sync so that your SharePoint user DB is upto date.

Programmatically insert a List as a webpart in a webpart page in WSS 3.0

I tried searching on the net to programmatically insert a List as a webpart in a webpart page but was not lucky enough.
Any thoughts or ideas how i could Programmatically insert a List as a webpart in a webpart page
Many Thanks!
First add these using statements.
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebPartPages;
Then in your code
// First get the list
SPSite site = new SPSite("http://myserver");
SPWeb web = site.OpenWeb();
SPList list = web.Lists["MyCustomlist"];
// Create a webpart
ListViewWebPart wp = new ListViewWebPart();
wp.ZoneID = "Top"; // Replace this ith the correct zone on your page.
wp.ListName = list.ID.ToString("B").ToUpper();
wp.ViewGuid = list.DefaultView.ID.ToString("B").ToUpper();
// Get the web part collection
SPWebPartCollection coll =
web.GetWebPartCollection("default.aspx", // replace this with the correct page.
Storage.Shared);
// Add the web part
coll.Add(wp);
If you want to use a custom view, try playing with this:
SPView view = list.GetUncustomizedViewByBaseViewId(0);
wp.ListViewXml = view.HtmlSchemaXml;
Hope it helps,
W0ut
You need to perform two steps to add a web part to a page. First you have to create the list you want to show on the page. Therefore you can use the Add() method of the web site's list collection (SPListCollection).
To show the list on the web part page you have to add a ListViewWebPart to the web part page using the SPLimitedWebPartManager of the page.
To make this more re-usable as part of a feature receiver, you could pass in the splist and spview as part of a method:
static public void AddEventsListViewWebPart(PublishingPage page, string webPartZoneId, int zoneIndex, string webPartTitle, PartChromeType webPartChromeType, string listName, string viewname)
{
using (SPLimitedWebPartManager wpManager = page.ListItem.File.GetLimitedWebPartManager(PersonalizationScope.Shared))
{
SPWeb web = page.PublishingWeb.Web;
SPList myList = web.Lists.TryGetList(listName);
using (XsltListViewWebPart lvwp = new XsltListViewWebPart())
{
lvwp.ListName = myList.ID.ToString("B").ToUpperInvariant();
lvwp.Title = webPartTitle;
// Specify the view
SPView view = myList.Views[viewname];
lvwp.ViewGuid = view.ID.ToString("B").ToUpperInvariant();
lvwp.TitleUrl = view.Url;
lvwp.Toolbar = "None";
lvwp.ChromeType = webPartChromeType;
wpManager.AddWebPart(lvwp, webPartZoneId, zoneIndex);
}
}
}
And then call it during feature activation:
AddEventsListViewWebPart(welcomePage, "Right", 1, "Events", PartChromeType.TitleOnly, "Events", "Calendar");

Resources