I am trying to create a Site for the Organization when the Organization is created using hook and adding listener to Organization entity.
I created site using GroupLocalServiceUtil and set up siteName = String.valueOf(org.getOrganizationId()) + "LFR_ORGANIZATION" + org.getName() like in DB.
Also I have set className and classPK like it is done when you create site to organization in liferay, but nothing happens. Site creates successfully, but it isn't connected with the Organization.
UPD.
Liferay 6.1 GA1
public Group addSite(Organization org) throws PortalException, SystemException
{
ServiceContext serviceContext = new ServiceContext();
String siteName = String.valueOf(org.getOrganizationId()) + "LFR_ORGANIZATION" + org.getName();
Group newSite = GroupLocalServiceUtil.addGroup(
getDefaultUserId(),
"com.liferay.portal.model.Organization", // Class Name
org.getOrganizationId(), // Class PK
siteName , // Name
"", // Description
GroupConstants.TYPE_SITE_PRIVATE, // Type
org.getTreePath(), // Friendly URL
true, // Site
true, // Active
serviceContext);
OrganizationUtil.addGroup(org.getPrimaryKey(), newSite);
return newSite;
}
How can I create such an Organizational Site programmatically?
In Liferay 6.1, it appears that when you create an Organization there is already a backing group. That group may not be visible depending on the boolean site parameter you pass:
OrganiztionLocalServiceUtil.addOrganization(
long userId, long parentOrganizationId, String name, String type,
boolean recursable, long regionId, long countryId, int statusId,
String comments, boolean site, ServiceContext serviceContext)
To make that Site visible for pages, simply call:
OrganiztionLocalServiceUtil.updateOrganization(
long companyId, long organizationId, long parentOrganizationId,
String name, String type, boolean recursable, long regionId,
long countryId, int statusId, String comments, boolean site,
ServiceContext serviceContext)
with site parameter set to true.
Related
Having a folder name e.g. "images", how can i get the folderId attribute of this folder? I need the folderId so i can then use the DLFolderLocalServiceUtil interface and methods to query for the files in the dir
This should work
Long parentFolderId = DLFolderConstants.DEFAULT_PARENT_FOLDER_ID; // if the id of the parent is set to default
DLFolder dir = DLFolderLocalServiceUtil.getFolder(groupId, parentFolderId, dirName);
see: DLFolderLocalServiceUtil
Where groupId is the id of the site the request is coming from, you can get it using themeDisplay:
ThemeDisplay themeDisplay =
(ThemeDisplay)request.getAttribute(WebKeys.THEME_DISPLAY);
long groupId = themeDisplay.getLayout().getGroupId();
and parentFolderId is the id of the folder containg the folder you're searching for and it is set when you add a new folder using:
DLFolder newFolder=addFolder(long userId, long groupId, long repositoryId, boolean mountPoint, long parentFolderId, String name,
String description, boolean hidden, ServiceContext serviceContext)
I have customized sign-up page using a hook.
I want to add the security question in the sign up page where as the default security question is set when user logs-in Liferay the first time.
So how can I add security question in the sign-up page instead on first time login?
Firstly, you have to customize the create_account.jsp page, adding the same select boxes and inputs normally found on update_reminder_query.jsp: that is, you have to add the UI for entering the password reminder while creating the account.
After that, you have to save those values for the new User, and you can probably hook the UserLocalService implementation, adding the code to update the reminder query. A thing like this should work:
public class UserLocalServiceImpl extends UserLocalServiceWrapper {
public UserLocalServiceImpl(UserLocalService userLocalService) {
super(userLocalService);
}
#Override
public User addUser(
long creatorUserId, long companyId, boolean autoPassword,
String password1, String password2, boolean autoScreenName,
String screenName, String emailAddress, long facebookId,
String openId, Locale locale, String firstName, String middleName,
String lastName, int prefixId, int suffixId, boolean male,
int birthdayMonth, int birthdayDay, int birthdayYear,
String jobTitle, long[] groupIds, long[] organizationIds,
long[] roleIds, long[] userGroupIds, boolean sendEmail,
ServiceContext serviceContext)
throws PortalException, SystemException {
// User
User user = super.addUser(
creatorUserId, companyId, autoPassword, password1, password2,
autoScreenName, screenName, emailAddress, facebookId, openId,
locale, firstName, middleName, lastName, prefixId, suffixId, male,
birthdayMonth, birthdayDay, birthdayYear, jobTitle, groupIds,
organizationIds, roleIds, userGroupIds, sendEmail, serviceContext);
// Reminder query
String question = ParamUtil.getString(
serviceContext, "reminderQueryQuestion");
String answer = ParamUtil.getString(
serviceContext, "reminderQueryAnswer");
if (Validator.isNotNull(question) || Validator.isNotNull(answer)) {
if (question.equals(UsersAdminUtil.CUSTOM_QUESTION)) {
question = ParamUtil.getString(
serviceContext, "reminderQueryCustomQuestion");
}
updateReminderQuery(user.getUserId(), question, answer);
}
return user;
}
}
You could override the CreateAccount Struts actions, but I think it's safer to do this thing in the service, in order to be transactional in case of errors (for example, if the User does not enter an answer for the reminder query)... but you should check it to be sure!
Also, you'll probably have to customize the Struts action anyway, in order to deal with a possible UserReminderQueryException...
Under Web content I set my structure to have an application field: "Documents an media".
Through this field user can add various files which are then displayed in my .xhtml.
User can make this "Documents and media" field repeatable to add more files.
How could I iterate through all added files and get their relative paths.
If my Documents and media field is not repeatable I can get relative path like this:
public String getWebContentTitle(String title, String nodeName) throws PortalException, SystemException {
FacesContext context = FacesContext.getCurrentInstance();
ThemeDisplay themeDisplay = (ThemeDisplay) context.getExternalContext().getRequestMap().get(WebKeys.THEME_DISPLAY);
long groupId = themeDisplay.getScopeGroupId();
JournalArticle article = JournalArticleLocalServiceUtil.getArticleByUrlTitle(groupId, formatUrlTitle(title));
String languageKey = context.getExternalContext().getRequestLocale().toString();
JournalArticleDisplay articleDisplay = JournalContentUtil.getDisplay(groupId, article.getArticleId(), article.getTemplateId(), languageKey, themeDisplay);
JournalArticle journalArticle = JournalArticleLocalServiceUtil.getArticle(groupId, article.getArticleId());
String myContent = journalArticle.getContentByLocale(languageKey);
if (nodeName != null) {
String nodeText=getParseValue(nodeName, journalArticle, myContent);
return nodeText;
} else
{
String ret=articleDisplay.getContent();
return ret;
}
}
private String getParseValue(String fieldname, JournalArticle article, String locale) {
String nodeText = "";
try {
Document document = SAXReaderUtil.read(article.getContentByLocale(locale));
Node node = document.selectSingleNode("/root/dynamic-element[#name='" + fieldname +"']/dynamic-content");
nodeText = node.getText();
} catch(Exception e){
}
return nodeText;
}
This method return relative path to my added document (say horses.pdf).
How could I get relative paths to more documents added through "Documents and media field", which is repeatable and has defined specific Variable name (say HorsesPdfs?)
Any help would be greatly appreciated!
You could try
DLAppLocalServiceUtil.getFileEntries(REPOSITORY_ID, FOLDER_ID), probably better than DLFileEntry as its the new approach that takes workflows in consideration.
Where
REPOSITORY_ID = parent group, which is by default LR´s one GroupLocalServiceUtil.getGroup(COMPANY_ID, GroupConstants.GUEST).getGroupId()
COMPANY_ID = PortalUtil.getDefaultCompanyId(); //If just one instance, if not, better to play with CompanyLocalServiceUtil to match your Id
For FOLDER ID, you can use root older of LR´s Doc & Media which is
FOLDER_ID = DLFolderConstants.DEFAULT_PARENT_FOLDER_ID; //or find it e.g DLAppLocalServiceUtil.getFolder( repositoryId, DLFolderConstants.DEFAULT_PARENT_FOLDER_ID, FOLDER_NAME).getFolderId(); if you programtically used addFolder(long userId, long repositoryId, long parentFolderId, String name, String description, ServiceContext serviceContext)
I'm using Service Builder in my portlet. Here is my addProduct method in PRProductLocalServiceBaseImpl:
public class PRProductLocalServiceImpl extends PRProductLocalServiceBaseImpl {
public PRProduct addProduct(long companyID, long groupID, String productName, String serialNumber, long userID) throws SystemException, PortalException{
PRProduct product = prProductPersistence.create(counterLocalService.increment(PRProduct.class.getName()));
resourceLocalService.addResources(companyID, groupID, userID, PRProduct.class.getName(), product.getPrimaryKey(), false, true, true);
product.setProductName(productName);
product.setSerialNumber(serialNumber);
product.setCompanyId(companyID);
product.setGroupId(groupID);
return prProductPersistence.update(product, false);
}
}
When I call this method from my portlet class and pass 1 as companyID it gives "No Role exists with the key {companyId=1, name=Owner}". and here is my portlet class:
public void addProduct(ActionRequest actionReaquest, ActionResponse actionResponse)
{
PortletSession session = actionReaquest.getPortletSession();
try
{
String productName = actionReaquest.getParameter("productName");
String userID = actionReaquest.getParameter("userID");
String companyID = actionReaquest.getParameter("companyID");
String groupID = actionReaquest.getParameter("groupID");
String serialNumber = actionReaquest.getParameter("serialNumber");
PRProduct product = PRProductLocalServiceUtil.addProduct(Long.parseLong(companyID), Long.parseLong(groupID), productName,
serialNumber, Long.parseLong(userID));
session.setAttribute("errorMessage", "Product added successfully");
actionResponse.setRenderParameter("jspPage", "/ProductAdded.jsp");
}
catch(Exception e)
{
session.setAttribute("errorMessage", e.getMessage());
actionResponse.setRenderParameter("jspPage", "/ProductAdded.jsp");
}
}
Can any body help? Any help is appreciated in advance.
Have checked to see if the Company ID is in fact 1?
The best way to get the current Liferay User ID, Group ID, and Company ID is by the ThemeDisplayobject. So instead of using your code:
String userID = actionReaquest.getParameter("userID");
String companyID = actionReaquest.getParameter("companyID");
String groupID = actionReaquest.getParameter("groupID");
You should use:
ThemeDisplay themeDisplay = (ThemeDisplay) actionReaquest.getAttribute(WebKeys.THEME_DISPLAY);
long realUserId = themeDisplay.getRealUserId();
long companyId = themeDisplay.getCompanyId();
long groupId = themeDisplay.getScopeGroupId();
This way you'll get the values from Liferay, rather than having to pass them in yourself. It also means you don't have to a Long.parseLong() to get the Long value of a String.
See if this helps! It's also better practice to do it this way for any future portlets. The ThemeDisplay objects holds a lot of useful information!
Also minor thing, it's spelt "request" not "reaquest" :)
Probably you need to add the content as an admin user or Owner user, below is the example to ass the content as the admin user set the adminUser permission before adding the content, try same for Owner:
User adminUser = UserLocalServiceUtil.getUserByEmailAddress(companyId,"test#liferay.com");
permissionChecker = PermissionCheckerFactoryUtil.create(adminUser);
PermissionThreadLocal.setPermissionChecker(permissionChecker);
or just fetch the owner the using code below:
Role role=com.liferay.portal.service.RoleLocalServiceUtil.getRole(long companyId,"Owner");
and update the add method add one more argument in add method i.e. serviceContext and all role(owner) in it,as we do while adding User in liferay.
I have done impersonation in SharePoint quite a bit in the past by doing something such as the following.
SPWeb web = SPContext.Current.Web;
string currentWebUrl = web.Url;
SPUser user = web.EnsureUser(loginToImpersonate);
using (SPSite site = new SPSite(currentWebUrl, user.UserToken)
{
using (SPWeb impersonatedWeb = site.OpenWeb())
{
// Any SharePoint access here to 'impersonatedWeb'
// is impersonated as 'loginToImpersonate'
}
}
Note that this does not require the password of the user you are impersonating, but does require certain code access security to run. As a side note the EnsureUser call also requires the current user to be an admin, but there are other methods that can be used in place of EnsureUser to get the SPUser object (trying to keep my code fragment simple for this question).
Now that I've set the stage... I now want to do either a FullTextSQLQuery or a KeywordQuery against either the MOSS or WSS query engine and get security trimmed results based on an impersonated user. Both objects can take a SPSite on the constructor, but ignore my impersonation logic. They go with the currently logged in user instead (HTTPContext.Current.User).
There are other constructors as well: application name (string) and for MOSS there's one with a ServerContext to the SSP, but I don't think these will help at all.
I've used Reflector on the KeywordQuery class and its base Query class and it gets pretty ugly pretty quick. I believe the actual logic that determines the user is down in unmanaged code.
So, is it possible for me to do this?
You need real Windows impersonation to do this. The SPSite impersonation is not real impersonation - it just tells the WSS object model to write another user id to the created and modified fields in the content database.
For Windows impersonation you will unfortunately need both the login and password unless you want to impersonate the application pool account using SPSecurity.RunWithElevatedPrivileges
You can implement Windows impersonation as follows:
using (Impersonator imp = new Impersonator("user", "domain", "password"))
{
// Do stuff impersonated
}
where the Impersonator class is implemented as:
public sealed class Impersonator : IDisposable
{
private WindowsImpersonationContext impersonationContext;
public Impersonator(string user, string domain, string password)
{
WindowsIdentity id = Logon(user, domain, password);
impersonationContext = id.Impersonate();
}
public void Dispose()
{
if (impersonationContext != null)
{
impersonationContext.Undo();
impersonationContext = null;
}
}
private WindowsIdentity Logon(string user, string domain, string password)
{
WindowsIdentity identity;
IntPtr handle = IntPtr.Zero;
bool logonSucceeded = LogonUser(
user, domain, password,
8, // LOGON32_LOGON_NETWORK_CLEARTEXT
0, // LOGON32_PROVIDER_DEFAULT
ref handle);
if (!logonSucceeded)
{
int errorCode = Marshal.GetLastWin32Error();
throw new UnauthorizedAccessException("User logon failed. Error Number: " + errorCode);
}
identity = new WindowsIdentity(handle);
CloseHandle(handle);
return identity;
}
[DllImport("advapi32.dll", SetLastError = true)]
private static extern bool LogonUser(string lpszUsername,
string lpszDomain,
string lpszPassword,
int dwLogonType,
int dwLogonProvider,
ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool CloseHandle(IntPtr handle);
}
It turns out that you can do impersonated search in SharePoint without a password. We figured this out back in August of 2009 and I have been remiss in updating Stack Overflow with the answer.
See http://wiki.threewill.com/display/is/2010/06/18/Connect+to+SharePoint+-+Forwarding+User+Identities for the details and pay special attention to the special requirements. Note that this does work with both SharePoint 2007 and SharePoint 2010.
Many thanks to my coworker Eric Bowden who did all of the work!
There actually is another way to do impersonation when performing searches using the object model. I was able to get it to work by doing impersonation when running with elevated priveleges. see my post here: http://vishalseth.com/post/2013/11/05/Impersonated-Searching-against-SharePoint.aspx