/** * 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.tool.pages; import java.util.ArrayList; import java.util.List; import javax.servlet.http.Cookie; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.apache.wicket.AttributeModifier; import org.apache.wicket.Component; import org.apache.wicket.RestartResponseException; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.extensions.ajax.markup.html.AjaxLazyLoadPanel; import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow; import org.apache.wicket.extensions.ajax.markup.html.tabs.AjaxTabbedPanel; import org.apache.wicket.extensions.markup.html.tabs.AbstractTab; import org.apache.wicket.extensions.markup.html.tabs.ITab; import org.apache.wicket.markup.html.IHeaderResponse; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.panel.EmptyPanel; import org.apache.wicket.markup.html.panel.FeedbackPanel; import org.apache.wicket.markup.html.panel.Panel; import org.apache.wicket.model.Model; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.model.StringResourceModel; import org.sakaiproject.api.common.edu.person.SakaiPerson; import org.sakaiproject.profile2.exception.ProfileNotDefinedException; import org.sakaiproject.profile2.exception.ProfilePreferencesNotDefinedException; import org.sakaiproject.profile2.model.MyProfilePanelState; import org.sakaiproject.profile2.model.ProfilePreferences; import org.sakaiproject.profile2.model.SocialNetworkingInfo; import org.sakaiproject.profile2.model.UserProfile; import org.sakaiproject.profile2.tool.components.NotifyingAjaxLazyLoadPanel; import org.sakaiproject.profile2.tool.components.ProfileImageRenderer; import org.sakaiproject.profile2.tool.models.FriendAction; import org.sakaiproject.profile2.tool.pages.panels.ChangeProfilePictureUpload; import org.sakaiproject.profile2.tool.pages.panels.ChangeProfilePictureUrl; import org.sakaiproject.profile2.tool.pages.panels.FriendsFeed; import org.sakaiproject.profile2.tool.pages.panels.GalleryFeed; import org.sakaiproject.profile2.tool.pages.panels.KudosPanel; import org.sakaiproject.profile2.tool.pages.panels.MyProfilePanel; import org.sakaiproject.profile2.tool.pages.panels.MyStatusPanel; import org.sakaiproject.profile2.tool.pages.panels.MyWallPanel; import org.sakaiproject.profile2.tool.pages.panels.ViewWallPanel; import org.sakaiproject.profile2.tool.pages.windows.AddFriend; import org.sakaiproject.profile2.util.ProfileConstants; public class MyProfile extends BasePage { private static final long serialVersionUID = 1L; private static final Logger log = Logger.getLogger(MyProfile.class); /** * Default constructor if viewing own */ public MyProfile() { log.debug("MyProfile()"); //get user for this profile and render it String userUuid = sakaiProxy.getCurrentUserId(); renderMyProfile(userUuid); } /** * This constructor is called if we are viewing someone elses but in edit mode. * This will only be called if we were a superuser editing someone else's profile. * An additional catch is also in place. * @param userUuid uuid of other user */ public MyProfile(final String userUuid) { log.debug("MyProfile(" + userUuid +")"); //double check only super users if(!sakaiProxy.isSuperUser()) { log.error("MyProfile: user " + sakaiProxy.getCurrentUserId() + " attempted to access MyProfile for " + userUuid + ". Redirecting..."); throw new RestartResponseException(new MyProfile()); } //render for given user renderMyProfile(userUuid); } /** * Does the actual rendering of the page * @param userUuid */ private void renderMyProfile(final String userUuid) { //don't do this for super users viewing other people's profiles as otherwise there is no way back to own profile if(!sakaiProxy.isSuperUserAndProxiedToUser(userUuid)) { disableLink(myProfileLink); } //add the feedback panel for any error messages FeedbackPanel feedbackPanel = new FeedbackPanel("feedbackPanel"); add(feedbackPanel); feedbackPanel.setVisible(false); //hide by default //get the prefs record, or a default if none exists yet final ProfilePreferences prefs = preferencesLogic.getPreferencesRecordForUser(userUuid); //if null, throw exception if(prefs == null) { throw new ProfilePreferencesNotDefinedException("Couldn't create default preferences record for " + userUuid); } //get SakaiPerson for this user SakaiPerson sakaiPerson = sakaiProxy.getSakaiPerson(userUuid); //if null, create one if(sakaiPerson == null) { log.warn("No SakaiPerson for " + userUuid + ". Creating one."); sakaiPerson = sakaiProxy.createSakaiPerson(userUuid); //if its still null, throw exception if(sakaiPerson == null) { throw new ProfileNotDefinedException("Couldn't create a SakaiPerson for " + userUuid); } //post create event sakaiProxy.postEvent(ProfileConstants.EVENT_PROFILE_NEW, userUuid, true); } //post view event sakaiProxy.postEvent(ProfileConstants.EVENT_PROFILE_VIEW_OWN, "/profile/"+userUuid, false); //get some values from SakaiPerson or SakaiProxy if empty //SakaiPerson returns NULL strings if value is not set, not blank ones //these must come from Account to keep it all in sync //we *could* get a User object here and get the values. String userDisplayName = sakaiProxy.getUserDisplayName(userUuid); /* String userFirstName = sakaiProxy.getUserFirstName(userId); String userLastName = sakaiProxy.getUserLastName(userId); */ String userEmail = sakaiProxy.getUserEmail(userUuid); //create instance of the UserProfile class //we then pass the userProfile in the constructor to the child panels final UserProfile userProfile = new UserProfile(); //get rest of values from SakaiPerson and setup UserProfile userProfile.setUserUuid(userUuid); userProfile.setNickname(sakaiPerson.getNickname()); userProfile.setDateOfBirth(sakaiPerson.getDateOfBirth()); userProfile.setDisplayName(userDisplayName); //userProfile.setFirstName(userFirstName); //userProfile.setLastName(userLastName); //userProfile.setMiddleName(sakaiPerson.getInitials()); userProfile.setEmail(userEmail); userProfile.setHomepage(sakaiPerson.getLabeledURI()); userProfile.setHomephone(sakaiPerson.getHomePhone()); userProfile.setWorkphone(sakaiPerson.getTelephoneNumber()); userProfile.setMobilephone(sakaiPerson.getMobile()); userProfile.setFacsimile(sakaiPerson.getFacsimileTelephoneNumber()); userProfile.setDepartment(sakaiPerson.getOrganizationalUnit()); userProfile.setPosition(sakaiPerson.getTitle()); userProfile.setSchool(sakaiPerson.getCampus()); userProfile.setRoom(sakaiPerson.getRoomNumber()); userProfile.setCourse(sakaiPerson.getEducationCourse()); userProfile.setSubjects(sakaiPerson.getEducationSubjects()); userProfile.setStaffProfile(sakaiPerson.getStaffProfile()); userProfile.setAcademicProfileUrl(sakaiPerson.getAcademicProfileUrl()); userProfile.setUniversityProfileUrl(sakaiPerson.getUniversityProfileUrl()); userProfile.setPublications(sakaiPerson.getPublications()); // business fields userProfile.setBusinessBiography(sakaiPerson.getBusinessBiography()); userProfile.setCompanyProfiles(profileLogic.getCompanyProfiles(userUuid)); userProfile.setFavouriteBooks(sakaiPerson.getFavouriteBooks()); userProfile.setFavouriteTvShows(sakaiPerson.getFavouriteTvShows()); userProfile.setFavouriteMovies(sakaiPerson.getFavouriteMovies()); userProfile.setFavouriteQuotes(sakaiPerson.getFavouriteQuotes()); userProfile.setPersonalSummary(sakaiPerson.getNotes()); // social networking fields SocialNetworkingInfo socialInfo = profileLogic.getSocialNetworkingInfo(userProfile.getUserUuid()); if(socialInfo == null){ socialInfo = new SocialNetworkingInfo(); } userProfile.setSocialInfo(socialInfo); //PRFL-97 workaround. SakaiPerson table needs to be upgraded so locked is not null, but this handles it if not upgraded. if(sakaiPerson.getLocked() == null) { userProfile.setLocked(false); this.setLocked(false); } else { this.setLocked(sakaiPerson.getLocked()); userProfile.setLocked(this.isLocked()); } //what type of picture changing method do we use? int profilePictureType = sakaiProxy.getProfilePictureType(); //change picture panel (upload or url depending on property) final Panel changePicture; //render appropriate panel with appropriate constructor ie if superUser etc if(profilePictureType == ProfileConstants.PICTURE_SETTING_UPLOAD) { if(sakaiProxy.isSuperUserAndProxiedToUser(userUuid)){ changePicture = new ChangeProfilePictureUpload("changePicture", userUuid); } else { changePicture = new ChangeProfilePictureUpload("changePicture"); } } else if (profilePictureType == ProfileConstants.PICTURE_SETTING_URL) { if(sakaiProxy.isSuperUserAndProxiedToUser(userUuid)){ changePicture = new ChangeProfilePictureUrl("changePicture", userUuid); } else { changePicture = new ChangeProfilePictureUrl("changePicture"); } } else if (profilePictureType == ProfileConstants.PICTURE_SETTING_OFFICIAL) { //cannot edit anything if using official images changePicture = new EmptyPanel("changePicture"); } else { //no valid option for changing picture was returned from the Profile2 API. log.error("Invalid picture type returned: " + profilePictureType); changePicture = new EmptyPanel("changePicture"); } changePicture.setOutputMarkupPlaceholderTag(true); changePicture.setVisible(false); add(changePicture); //add the current picture add(new ProfileImageRenderer("photo", userUuid, prefs)); //change profile image button AjaxLink<Void> changePictureLink = new AjaxLink<Void>("changePictureLink") { private static final long serialVersionUID = 1L; public void onClick(AjaxRequestTarget target) { //show the panel changePicture.setVisible(true); target.addComponent(changePicture); //resize iframe to fit it target.appendJavascript("resizeFrame('grow');"); } }; changePictureLink.add(new Label("changePictureLabel", new ResourceModel("link.change.profile.picture"))); //is picture changing disabled? (property, or locked) if((!sakaiProxy.isProfilePictureChangeEnabled() || userProfile.isLocked()) && !sakaiProxy.isSuperUser()) { changePictureLink.setEnabled(false); changePictureLink.setVisible(false); } //if using official images, is the user allowed to select an alternate? //or have they specified the official image in their preferences. if(sakaiProxy.isOfficialImageEnabledGlobally() && (!sakaiProxy.isUsingOfficialImageButAlternateSelectionEnabled() || prefs.isUseOfficialImage())) { changePictureLink.setEnabled(false); changePictureLink.setVisible(false); } add(changePictureLink); /* SIDELINKS */ WebMarkupContainer sideLinks = new WebMarkupContainer("sideLinks"); int visibleSideLinksCount = 0; //ADMIN: ADD AS CONNECTION if(sakaiProxy.isSuperUserAndProxiedToUser(userUuid)) { //init boolean friend = false; boolean friendRequestToThisPerson = false; boolean friendRequestFromThisPerson = false; String currentUserUuid = sakaiProxy.getCurrentUserId(); String nickname = userProfile.getNickname(); if(StringUtils.isBlank(nickname)) { nickname=""; } //setup model to store the actions in the modal windows final FriendAction friendActionModel = new FriendAction(); //setup friend status friend = connectionsLogic.isUserXFriendOfUserY(userUuid, currentUserUuid); if(!friend) { friendRequestToThisPerson = connectionsLogic.isFriendRequestPending(currentUserUuid, userUuid); } if(!friend && !friendRequestToThisPerson) { friendRequestFromThisPerson = connectionsLogic.isFriendRequestPending(userUuid, currentUserUuid); } WebMarkupContainer addFriendContainer = new WebMarkupContainer("addFriendContainer"); final ModalWindow addFriendWindow = new ModalWindow("addFriendWindow"); //link final AjaxLink<Void> addFriendLink = new AjaxLink<Void>("addFriendLink") { private static final long serialVersionUID = 1L; public void onClick(AjaxRequestTarget target) { addFriendWindow.show(target); } }; final Label addFriendLabel = new Label("addFriendLabel"); addFriendLink.add(addFriendLabel); addFriendContainer.add(addFriendLink); //setup link/label and windows if(friend) { addFriendLabel.setDefaultModel(new ResourceModel("text.friend.confirmed")); addFriendLink.add(new AttributeModifier("class", true, new Model<String>("instruction icon connection-confirmed"))); addFriendLink.setEnabled(false); } else if (friendRequestToThisPerson) { addFriendLabel.setDefaultModel(new ResourceModel("text.friend.requested")); addFriendLink.add(new AttributeModifier("class", true, new Model<String>("instruction icon connection-request"))); addFriendLink.setEnabled(false); } else if (friendRequestFromThisPerson) { //TODO (confirm pending friend request link) //could be done by setting the content off the addFriendWindow. //will need to rename some links to make more generic and set the onClick and setContent in here for link and window addFriendLabel.setDefaultModel(new ResourceModel("text.friend.pending")); addFriendLink.add(new AttributeModifier("class", true, new Model<String>("instruction icon connection-request"))); addFriendLink.setEnabled(false); } else { addFriendLabel.setDefaultModel(new StringResourceModel("link.friend.add.name", null, new Object[]{ nickname } )); addFriendLink.add(new AttributeModifier("class", true, new Model<String>("icon connection-add"))); addFriendWindow.setContent(new AddFriend(addFriendWindow.getContentId(), addFriendWindow, friendActionModel, currentUserUuid, userUuid)); } sideLinks.add(addFriendContainer); //ADD FRIEND MODAL WINDOW HANDLER addFriendWindow.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() { private static final long serialVersionUID = 1L; public void onClose(AjaxRequestTarget target){ if(friendActionModel.isRequested()) { //friend was successfully requested, update label and link addFriendLabel.setDefaultModel(new ResourceModel("text.friend.requested")); addFriendLink.add(new AttributeModifier("class", true, new Model<String>("instruction"))); addFriendLink.setEnabled(false); target.addComponent(addFriendLink); } } }); add(addFriendWindow); visibleSideLinksCount++; //ADMIN: LOCK/UNLOCK A PROFILE WebMarkupContainer lockProfileContainer = new WebMarkupContainer("lockProfileContainer"); final Label lockProfileLabel = new Label("lockProfileLabel"); final AjaxLink<Void> lockProfileLink = new AjaxLink<Void>("lockProfileLink") { private static final long serialVersionUID = 1L; public void onClick(AjaxRequestTarget target) { //toggle it to be opposite of what it currently is, update labels and icons boolean locked = isLocked(); if(sakaiProxy.toggleProfileLocked(userUuid, !locked)) { setLocked(!locked); log.info("MyProfile(): SuperUser toggled lock status of profile for " + userUuid + " to " + !locked); lockProfileLabel.setDefaultModel(new ResourceModel("link.profile.locked." + isLocked())); add(new AttributeModifier("title", true, new ResourceModel("text.profile.locked." + isLocked()))); if(isLocked()){ add(new AttributeModifier("class", true, new Model<String>("icon locked"))); } else { add(new AttributeModifier("class", true, new Model<String>("icon unlocked"))); } target.addComponent(this); } } }; //set init icon for locked if(isLocked()){ lockProfileLink.add(new AttributeModifier("class", true, new Model<String>("icon locked"))); } else { lockProfileLink.add(new AttributeModifier("class", true, new Model<String>("icon unlocked"))); } lockProfileLink.add(lockProfileLabel); //setup link/label and windows with special property based on locked status lockProfileLabel.setDefaultModel(new ResourceModel("link.profile.locked." + isLocked())); lockProfileLink.add(new AttributeModifier("title", true, new ResourceModel("text.profile.locked." + isLocked()))); lockProfileContainer.add(lockProfileLink); sideLinks.add(lockProfileContainer); visibleSideLinksCount++; } else { //blank components WebMarkupContainer addFriendContainer = new WebMarkupContainer("addFriendContainer"); addFriendContainer.add(new AjaxLink("addFriendLink") { public void onClick(AjaxRequestTarget target) {} }).add(new Label("addFriendLabel")); sideLinks.add(addFriendContainer); add(new WebMarkupContainer("addFriendWindow")); WebMarkupContainer lockProfileContainer = new WebMarkupContainer("lockProfileContainer"); lockProfileContainer.add(new AjaxLink("lockProfileLink") { public void onClick(AjaxRequestTarget target) {} }).add(new Label("lockProfileLabel")); sideLinks.add(lockProfileContainer); } //hide entire list if no links to show if(visibleSideLinksCount == 0) { sideLinks.setVisible(false); } add(sideLinks); //status panel Panel myStatusPanel = new MyStatusPanel("myStatusPanel", userProfile); add(myStatusPanel); List<ITab> tabs = new ArrayList<ITab>(); AjaxTabbedPanel tabbedPanel = new AjaxTabbedPanel("myProfileTabs", tabs) { private static final long serialVersionUID = 1L; // overridden so we can add tooltips to tabs @Override protected WebMarkupContainer newLink(String linkId, final int index) { WebMarkupContainer link = super.newLink(linkId, index); if (ProfileConstants.TAB_INDEX_PROFILE == index) { link.add(new AttributeModifier("title", true, new ResourceModel("link.tab.profile.tooltip"))); } else if (ProfileConstants.TAB_INDEX_WALL == index) { link.add(new AttributeModifier("title", true, new ResourceModel("link.tab.wall.tooltip"))); } return link; } }; Cookie tabCookie = getWebRequestCycle().getWebRequest().getCookie(ProfileConstants.TAB_COOKIE); if (sakaiProxy.isProfileFieldsEnabled()) { tabs.add(new AbstractTab(new ResourceModel("link.tab.profile")) { private static final long serialVersionUID = 1L; @Override public Panel getPanel(String panelId) { setTabCookie(ProfileConstants.TAB_INDEX_PROFILE); MyProfilePanelState panelState = new MyProfilePanelState(); panelState.showBusinessDisplay = sakaiProxy.isBusinessProfileEnabled(); panelState.showSocialNetworkingDisplay = sakaiProxy.isSocialProfileEnabled(); panelState.showInterestsDisplay = sakaiProxy.isInterestsProfileEnabled(); panelState.showStaffDisplay = sakaiProxy.isStaffProfileEnabled(); panelState.showStudentDisplay = sakaiProxy.isStudentProfileEnabled(); return new MyProfilePanel(panelId, userProfile,panelState); } }); } if (true == sakaiProxy.isWallEnabledGlobally()) { tabs.add(new AbstractTab(new ResourceModel("link.tab.wall")) { private static final long serialVersionUID = 1L; @Override public Panel getPanel(String panelId) { setTabCookie(ProfileConstants.TAB_INDEX_WALL); if (true == sakaiProxy.isSuperUser()) { return new MyWallPanel(panelId, userUuid); } else { return new MyWallPanel(panelId); } } }); if (true == sakaiProxy.isWallDefaultProfilePage() && null == tabCookie) { tabbedPanel.setSelectedTab(ProfileConstants.TAB_INDEX_WALL); } } if (null != tabCookie) { try { tabbedPanel.setSelectedTab(Integer.parseInt(tabCookie.getValue())); } catch (IndexOutOfBoundsException e) { //do nothing. This will be thrown if the cookie contains a value > the number of tabs but thats ok. } } add(tabbedPanel); //kudos panel add(new AjaxLazyLoadPanel("myKudos"){ private static final long serialVersionUID = 1L; @Override public Component getLazyLoadComponent(String markupId) { if(prefs.isShowKudos()){ int score = kudosLogic.getKudos(userUuid); if(score > 0) { return new KudosPanel(markupId, userUuid, userUuid, score); } } return new EmptyPanel(markupId); } }); //friends feed panel for self - lazy loaded add(new NotifyingAjaxLazyLoadPanel("friendsFeed") { private static final long serialVersionUID = 1L; @Override public Component getLazyLoadComponent(String markupId) { return new FriendsFeed(markupId, userUuid, userUuid); } @Override public void renderHead(IHeaderResponse response) { response.renderOnDomReadyJavascript("resizeFrame('grow');"); } }); //gallery feed panel add(new NotifyingAjaxLazyLoadPanel("galleryFeed") { private static final long serialVersionUID = 1L; @Override public Component getLazyLoadComponent(String markupId) { if (sakaiProxy.isProfileGalleryEnabledGlobally() && prefs.isShowGalleryFeed()) { return new GalleryFeed(markupId, userUuid, userUuid) .setOutputMarkupId(true); } else { return new EmptyPanel(markupId); } } @Override public void renderHead(IHeaderResponse response) { response.renderOnDomReadyJavascript("resizeFrame('grow');"); } }); } private boolean locked; public boolean isLocked() { return locked; } public void setLocked(boolean locked) { this.locked = locked; } }