/**
* Copyright (c) 2008-2012 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.osedu.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sakaiproject.profile2.logic;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import lombok.Setter;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.sakaiproject.api.common.edu.person.SakaiPerson;
import org.sakaiproject.profile2.conversion.ProfileConverter;
import org.sakaiproject.profile2.dao.ProfileDao;
import org.sakaiproject.profile2.exception.ProfileNotDefinedException;
import org.sakaiproject.profile2.hbm.model.ProfileImageExternal;
import org.sakaiproject.profile2.hbm.model.ProfileImageUploaded;
import org.sakaiproject.profile2.model.BasicPerson;
import org.sakaiproject.profile2.model.CompanyProfile;
import org.sakaiproject.profile2.model.Person;
import org.sakaiproject.profile2.model.ProfilePrivacy;
import org.sakaiproject.profile2.model.SocialNetworkingInfo;
import org.sakaiproject.profile2.model.UserProfile;
import org.sakaiproject.profile2.types.EmailType;
import org.sakaiproject.profile2.types.PrivacyType;
import org.sakaiproject.profile2.util.ProfileConstants;
import org.sakaiproject.profile2.util.ProfileUtils;
import org.sakaiproject.user.api.User;
/**
* Implementation of ProfileLogic for Profile2.
*
* @author Steve Swinsburg (s.swinsburg@lancaster.ac.uk)
*
*/
public class ProfileLogicImpl implements ProfileLogic {
private static final Logger log = Logger.getLogger(ProfileLogicImpl.class);
/**
* {@inheritDoc}
*/
public UserProfile getUserProfile(final String userUuid) {
return getUserProfile(userUuid, null);
}
/**
* {@inheritDoc}
*/
public UserProfile getUserProfile(final String userUuid, final String siteId) {
//check auth and get currentUserUuid
String currentUserUuid = sakaiProxy.getCurrentUserId();
if(currentUserUuid == null) {
throw new SecurityException("Must be logged in to get a UserProfile.");
}
//get User
User u = sakaiProxy.getUserById(userUuid);
if(u == null) {
log.error("User " + userUuid + " does not exist.");
return null;
}
//setup obj
UserProfile p = new UserProfile();
p.setUserUuid(userUuid);
p.setDisplayName(u.getDisplayName());
p.setImageUrl(imageLogic.getProfileImageEntityUrl(userUuid, ProfileConstants.PROFILE_IMAGE_MAIN));
p.setImageThumbUrl(imageLogic.getProfileImageEntityUrl(userUuid, ProfileConstants.PROFILE_IMAGE_THUMBNAIL));
//get SakaiPerson
SakaiPerson sakaiPerson = sakaiProxy.getSakaiPerson(userUuid);
if(sakaiPerson == null) {
//no profile, return basic info only.
return p;
}
//transform
p = transformSakaiPersonToUserProfile(p, sakaiPerson);
//if person requested own profile or superuser, no need for privacy checks
//add the additional information and return
if(userUuid.equals(currentUserUuid) || sakaiProxy.isSuperUser()) {
p.setEmail(u.getEmail());
p.setStatus(statusLogic.getUserStatus(userUuid));
p.setSocialInfo(getSocialNetworkingInfo(userUuid));
p.setCompanyProfiles(getCompanyProfiles(userUuid));
return p;
}
//REMOVE the birth year if not allowed
if(!privacyLogic.isBirthYearVisible(userUuid)){
if(p.getDateOfBirth() != null) {
p.setDateOfBirth(ProfileUtils.stripYear(p.getDateOfBirth()));
} else {
p.setDateOfBirth(null);
}
}
//REMOVE basic info if not allowed
if(!privacyLogic.isActionAllowed(userUuid,currentUserUuid, PrivacyType.PRIVACY_OPTION_BASICINFO)) {
p.setNickname(null);
p.setDateOfBirth(null);
p.setPersonalSummary(null);
}
//ADD email if allowed, REMOVE contact info if not
if(privacyLogic.isActionAllowed(userUuid, currentUserUuid, PrivacyType.PRIVACY_OPTION_CONTACTINFO)) {
p.setEmail(u.getEmail());
} else if(siteId != null && sakaiProxy.isUserAllowedInSite(currentUserUuid, ProfileConstants.ROSTER_VIEW_EMAIL, siteId)) {
p.setEmail(u.getEmail());
} else {
p.setEmail(null);
p.setHomepage(null);
p.setHomephone(null);
p.setWorkphone(null);
p.setMobilephone(null);
p.setFacsimile(null);
}
//REMOVE staff info if not allowed
if(!privacyLogic.isActionAllowed(userUuid, currentUserUuid, PrivacyType.PRIVACY_OPTION_STAFFINFO)) {
p.setDepartment(null);
p.setPosition(null);
p.setSchool(null);
p.setRoom(null);
p.setStaffProfile(null);
p.setAcademicProfileUrl(null);
p.setUniversityProfileUrl(null);
p.setPublications(null);
}
//REMOVE student info if not allowed
if(!privacyLogic.isActionAllowed(userUuid, currentUserUuid, PrivacyType.PRIVACY_OPTION_STUDENTINFO)) {
p.setCourse(null);
p.setSubjects(null);
}
//REMOVE personal info if not allowed
if(!privacyLogic.isActionAllowed(userUuid, currentUserUuid, PrivacyType.PRIVACY_OPTION_PERSONALINFO)) {
p.setFavouriteBooks(null);
p.setFavouriteTvShows(null);
p.setFavouriteMovies(null);
p.setFavouriteQuotes(null);
}
//ADD social networking info if allowed
if(privacyLogic.isActionAllowed(userUuid, currentUserUuid, PrivacyType.PRIVACY_OPTION_SOCIALINFO)) {
p.setSocialInfo(getSocialNetworkingInfo(userUuid));
}
//ADD company info if activated and allowed, REMOVE business bio if not
if(sakaiProxy.isBusinessProfileEnabled()) {
if(privacyLogic.isActionAllowed(userUuid, currentUserUuid, PrivacyType.PRIVACY_OPTION_BUSINESSINFO)) {
p.setCompanyProfiles(getCompanyProfiles(userUuid));
} else {
p.setBusinessBiography(null);
}
} else {
p.setBusinessBiography(null);
}
//ADD profile status if allowed
if(privacyLogic.isActionAllowed(userUuid, currentUserUuid, PrivacyType.PRIVACY_OPTION_MYSTATUS)) {
p.setStatus(statusLogic.getUserStatus(userUuid));
}
return p;
}
/**
* {@inheritDoc}
*/
public boolean saveUserProfile(SakaiPerson sp) {
if(sakaiProxy.updateSakaiPerson(sp)) {
sendProfileChangeEmailNotification(sp.getAgentUuid());
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
public boolean addNewCompanyProfile(final CompanyProfile companyProfile) {
if(dao.addNewCompanyProfile(companyProfile)){
log.info("Added new company profile for user: " + companyProfile.getUserUuid());
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
public boolean updateCompanyProfile(final CompanyProfile companyProfile) {
if(dao.updateCompanyProfile(companyProfile)){
log.info("Saved company profile for user: "+ companyProfile.getUserUuid());
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
public List<CompanyProfile> getCompanyProfiles(final String userId) {
return dao.getCompanyProfiles(userId);
}
/**
* {@inheritDoc}
*/
public boolean removeCompanyProfile(String userId, long companyProfileId) {
if (userId == null || Long.valueOf(companyProfileId) == null) {
throw new IllegalArgumentException("Null argument in ProfileLogicImpl.removeCompanyProfile()");
}
CompanyProfile companyProfile = dao.getCompanyProfile(userId, companyProfileId);
if (companyProfile == null) {
log.error("CompanyProfile record does not exist for userId: "+ userId + ", companyProfileId: " + companyProfileId);
return false;
}
if(dao.removeCompanyProfile(companyProfile)){
log.info("User: " + userId + " removed company profile: "+ companyProfileId);
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
public SocialNetworkingInfo getSocialNetworkingInfo(final String userId) {
if(userId == null){
throw new IllegalArgumentException("Null argument in ProfileLogic.getSocialNetworkingInfo");
}
SocialNetworkingInfo socialNetworkingInfo = dao.getSocialNetworkingInfo(userId);
if (null == socialNetworkingInfo) {
socialNetworkingInfo = new SocialNetworkingInfo(userId);
}
return socialNetworkingInfo;
}
/**
* {@inheritDoc}
*/
public boolean saveSocialNetworkingInfo(SocialNetworkingInfo socialNetworkingInfo) {
if(dao.saveSocialNetworkingInfo(socialNetworkingInfo)) {
log.info("Updated social networking info for user: " + socialNetworkingInfo.getUserUuid());
return true;
}
return false;
}
/**
* {@inheritDoc}
*/
public BasicPerson getBasicPerson(String userUuid) {
return getBasicPerson(sakaiProxy.getUserById(userUuid));
}
/**
* {@inheritDoc}
*/
public BasicPerson getBasicPerson(User user) {
BasicPerson p = new BasicPerson();
p.setUuid(user.getId());
p.setDisplayName(user.getDisplayName());
p.setType(user.getType());
return p;
}
/**
* {@inheritDoc}
*/
public List<BasicPerson> getBasicPersons(List<User> users) {
List<BasicPerson> list = new ArrayList<BasicPerson>();
for(User u:users){
list.add(getBasicPerson(u));
}
return list;
}
/**
* {@inheritDoc}
*/
public Person getPerson(String userUuid) {
return getPerson(sakaiProxy.getUserById(userUuid));
}
/**
* {@inheritDoc}
*/
public Person getPerson(User user) {
//catch for non existent user
if(user == null){
return null;
}
Person p = new Person();
String userUuid = user.getId();
p.setUuid(userUuid);
p.setDisplayName(user.getDisplayName());
p.setType(user.getType());
p.setPreferences(preferencesLogic.getPreferencesRecordForUser(userUuid));
p.setPrivacy(privacyLogic.getPrivacyRecordForUser(userUuid));
p.setProfile(getUserProfile(userUuid));
return p;
}
/**
* {@inheritDoc}
*/
public List<Person> getPersons(List<User> users) {
List<Person> list = new ArrayList<Person>();
for(User u:users){
list.add(getPerson(u));
}
return list;
}
/**
* {@inheritDoc}
*/
public List<String> getAllSakaiPersonIds() {
return dao.getAllSakaiPersonIds();
}
/**
* {@inheritDoc}
*/
public int getAllSakaiPersonIdsCount() {
return dao.getAllSakaiPersonIdsCount();
}
//service init
public void init() {
log.info("Profile2: init()");
//do we need to run the image conversion utility?
if(sakaiProxy.isProfileConversionEnabled()) {
//run the profile image converter
converter.convertProfileImages();
}
// Should we import profile image URLs to be uploaded profile images?
if (sakaiProxy.isProfileImageImportEnabled()) {
if (sakaiProxy.getProfilePictureType() != ProfileConstants.PICTURE_SETTING_UPLOAD) {
log.warn("I'm set to import images but profile2.picture.type=upload is not set. Not importing.");
} else {
converter.importProfileImages();
}
}
//do we need to import profiles?
if(sakaiProxy.isProfileImportEnabled()) {
String csv = sakaiProxy.getProfileImportCsvPath();
//run the profile importer
converter.importProfiles(csv);
}
}
/**
* Convenience method to map a SakaiPerson object onto a UserProfile object
*
* @param sp input SakaiPerson
* @return returns a UserProfile representation of the SakaiPerson object
*/
private UserProfile transformSakaiPersonToUserProfile(UserProfile p, SakaiPerson sp) {
//map fields from SakaiPerson to UserProfile
//basic info
p.setNickname(sp.getNickname());
p.setDateOfBirth(sp.getDateOfBirth());
p.setPersonalSummary(sp.getNotes());
//contact info
p.setHomepage(sp.getLabeledURI());
p.setWorkphone(sp.getTelephoneNumber());
p.setHomephone(sp.getHomePhone());
p.setMobilephone(sp.getMobile());
p.setFacsimile(sp.getFacsimileTelephoneNumber());
//staff info
p.setDepartment(sp.getOrganizationalUnit());
p.setPosition(sp.getTitle());
p.setSchool(sp.getCampus());
p.setRoom(sp.getRoomNumber());
p.setStaffProfile(sp.getStaffProfile());
p.setAcademicProfileUrl(sp.getAcademicProfileUrl());
p.setUniversityProfileUrl(sp.getUniversityProfileUrl());
p.setPublications(sp.getPublications());
//student info
p.setCourse(sp.getEducationCourse());
p.setSubjects(sp.getEducationSubjects());
//personal info
p.setFavouriteBooks(sp.getFavouriteBooks());
p.setFavouriteTvShows(sp.getFavouriteTvShows());
p.setFavouriteMovies(sp.getFavouriteMovies());
p.setFavouriteQuotes(sp.getFavouriteQuotes());
//business info
p.setBusinessBiography(sp.getBusinessBiography());
return p;
}
/**
* Sends an email notification when a user changes their profile, if enabled.
* @param toUuid the uuid of the user who changed their profile
*/
private void sendProfileChangeEmailNotification(final String userUuid) {
//check if option is enabled
boolean enabled = Boolean.valueOf(sakaiProxy.getServerConfigurationParameter("profile2.profile.change.email.enabled", "false"));
if(!enabled) {
return;
}
//get the user to send to. THis will be translated into an internal ID. Since SakaiProxy.sendEmail takes a userId as a param
//it was easier to require an eid here (and thus the person needs to have an account) rather than create a new method that takes an email address.
String eidTo = sakaiProxy.getServerConfigurationParameter("profile2.profile.change.email.eid", null);
if(StringUtils.isBlank(eidTo)){
log.error("Profile change email notification is enabled but no user eid to send it to is set. Please set 'profile2.profile.change.email.eid' in sakai.properties");
return;
}
//get internal id for this user
String userUuidTo = sakaiProxy.getUserIdForEid(eidTo);
if(StringUtils.isBlank(userUuidTo)) {
log.error("Profile change email notification is setup with an invalid eid. Please adjust 'profile2.profile.change.email.eid' in sakai.properties");
return;
}
String emailTemplateKey = ProfileConstants.EMAIL_TEMPLATE_KEY_PROFILE_CHANGE_NOTIFICATION;
//create the map of replacement values for this email template
Map<String,String> replacementValues = new HashMap<String,String>();
replacementValues.put("userDisplayName", sakaiProxy.getUserDisplayName(userUuid));
replacementValues.put("localSakaiName", sakaiProxy.getServiceName());
replacementValues.put("profileLink", linkLogic.getEntityLinkToProfileHome(userUuid));
replacementValues.put("localSakaiUrl", sakaiProxy.getPortalUrl());
sakaiProxy.sendEmail(userUuidTo, emailTemplateKey, replacementValues);
return;
}
@Setter
private SakaiProxy sakaiProxy;
@Setter
private ProfileDao dao;
@Setter
private ProfilePreferencesLogic preferencesLogic;
@Setter
private ProfileStatusLogic statusLogic;
@Setter
private ProfilePrivacyLogic privacyLogic;
@Setter
private ProfileConnectionsLogic connectionsLogic;
@Setter
private ProfileImageLogic imageLogic;
@Setter
private ProfileConverter converter;
@Setter
private ProfileLinkLogic linkLogic;
}