/** * $Id: PollsEntityProvider.java 127888 2013-07-29 11:54:18Z steve.swinsburg@gmail.com $ * $URL: https://source.sakaiproject.org/svn/polls/trunk/tool/src/java/org/sakaiproject/poll/tool/entityproviders/PollsEntityProvider.java $ * PollEntityProvider.java - polls - Aug 21, 2008 7:34:47 PM - azeckoski ************************************************************************** * Copyright (c) 2008, 2009 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.opensource.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.poll.tool.entityproviders; import java.io.OutputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import javax.servlet.http.HttpServletResponse; import lombok.Setter; import lombok.extern.apachecommons.CommonsLog; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.lang.StringUtils; import org.sakaiproject.entitybroker.EntityReference; import org.sakaiproject.entitybroker.EntityView; import org.sakaiproject.entitybroker.entityprovider.EntityProvider; import org.sakaiproject.entitybroker.entityprovider.annotations.EntityCustomAction; import org.sakaiproject.entitybroker.entityprovider.capabilities.ActionsExecutable; import org.sakaiproject.entitybroker.entityprovider.capabilities.AutoRegisterEntityProvider; import org.sakaiproject.entitybroker.entityprovider.capabilities.CollectionResolvable; import org.sakaiproject.entitybroker.entityprovider.capabilities.Describeable; import org.sakaiproject.entitybroker.entityprovider.capabilities.Outputable; import org.sakaiproject.entitybroker.entityprovider.capabilities.RequestStorable; import org.sakaiproject.entitybroker.entityprovider.extension.Formats; import org.sakaiproject.entitybroker.entityprovider.extension.RequestStorage; import org.sakaiproject.entitybroker.entityprovider.search.Restriction; import org.sakaiproject.entitybroker.entityprovider.search.Search; import org.sakaiproject.entitybroker.exception.EntityException; import org.sakaiproject.entitybroker.util.AbstractEntityProvider; import org.sakaiproject.event.api.UsageSession; import org.sakaiproject.event.api.UsageSessionService; import org.sakaiproject.poll.logic.PollListManager; import org.sakaiproject.poll.logic.PollVoteManager; import org.sakaiproject.poll.model.Option; import org.sakaiproject.poll.model.Poll; import org.sakaiproject.poll.model.Vote; import org.sakaiproject.user.api.UserDirectoryService; /** * Handles the polls tool. * * @author Aaron Zeckoski (azeckoski @ gmail.com) * @author Denny (denny.denny @ gmail.com) */ @CommonsLog public class PollsEntityProvider extends AbstractEntityProvider implements EntityProvider, AutoRegisterEntityProvider, RequestStorable, ActionsExecutable, Outputable, Describeable { @Setter private PollListManager pollListManager; @Setter private PollVoteManager pollVoteManager; @Setter private UsageSessionService usageSessionService; @Setter private UserDirectoryService userDirectoryService; @Setter private RequestStorage requestStorage = null; public static final String ENTITY_PREFIX = "polls"; @Override public String getEntityPrefix() { return ENTITY_PREFIX; } public String[] getHandledOutputFormats() { return new String[] { Formats.XML, Formats.JSON }; } public String[] getHandledInputFormats() { return new String[] { Formats.XML, Formats.JSON, Formats.HTML }; } /** * site/siteId */ @EntityCustomAction(action = "site", viewKey = EntityView.VIEW_LIST) public List<Poll> getPollsForSite(EntityView view) { // get siteId String siteId = view.getPathSegment(2); // check siteId supplied if (StringUtils.isBlank(siteId)) { throw new IllegalArgumentException( "siteId must be set in order to get the polls for a site, via the URL /polls/site/siteId"); } String[] siteIds = new String[] { siteId }; if (log.isDebugEnabled()) { log.debug("poll for site " + siteId); } String userId = developerHelperService.getCurrentUserId(); if (userId == null) { throw new EntityException( "No user is currently logged in so no polls data can be retrieved", siteId, HttpServletResponse.SC_UNAUTHORIZED); } boolean adminControl = false; String perm = PollListManager.PERMISSION_VOTE; if (adminControl) { perm = PollListManager.PERMISSION_ADD; } List<Poll> polls = pollListManager .findAllPollsForUserAndSitesAndPermission(userId, siteIds, perm); if (adminControl) { // add in options for (Poll p : polls) { List<Option> options = pollListManager.getOptionsForPoll(p .getPollId()); p.setOptions(options); } } else { // add in the indicators that this user has replied Long[] pollIds = new Long[polls.size()]; for (int i = 0; i < polls.size(); i++) { pollIds[i] = polls.get(i).getPollId(); } Map<Long, List<Vote>> voteMap = pollVoteManager.getVotesForUser( userId, pollIds); for (Poll poll : polls) { Long pollId = poll.getPollId(); List<Vote> l = voteMap.get(pollId); if (l != null) { poll.setCurrentUserVoted(true); poll.setCurrentUserVotes(l); } else { poll.setCurrentUserVoted(false); } } } return polls; } @EntityCustomAction(action = "my", viewKey = EntityView.VIEW_LIST) public List<?> getEntities(EntityReference ref, Search search) { System.out.println("get entities"); // get the setting which indicates if we are getting polls we can admin // or polls we can take boolean adminControl = false; Restriction adminRes = search.getRestrictionByProperty("admin"); if (adminRes != null) { adminControl = developerHelperService.convert( adminRes.getSingleValue(), boolean.class); } // get the location (if set) Restriction locRes = search .getRestrictionByProperty(CollectionResolvable.SEARCH_LOCATION_REFERENCE); // requestStorage.getStoredValueAsType(String.class, // "siteId"); String[] siteIds = null; if (locRes != null) { String siteId = developerHelperService.getLocationIdFromRef(locRes .getStringValue()); siteIds = new String[] { siteId }; } // get the user (if set) Restriction userRes = search .getRestrictionByProperty(CollectionResolvable.SEARCH_USER_REFERENCE); String userId = null; if (userRes != null) { String currentUser = developerHelperService .getCurrentUserReference(); String userReference = userRes.getStringValue(); if (userReference == null) { throw new IllegalArgumentException( "Invalid request: Cannot limit polls by user when the value is null"); } if (userReference.equals(currentUser) || developerHelperService.isUserAdmin(currentUser)) { userId = developerHelperService.getUserIdFromRef(userReference); // requestStorage.getStoredValueAsType(String.class, // "userId"); } else { throw new SecurityException( "Only the admin can get polls for other users, you requested polls for: " + userReference); } } else { userId = developerHelperService.getCurrentUserId(); if (userId == null) { throw new EntityException( "No user is currently logged in so no polls data can be retrieved", ref.getId(), HttpServletResponse.SC_UNAUTHORIZED); } } String perm = PollListManager.PERMISSION_VOTE; if (adminControl) { perm = PollListManager.PERMISSION_ADD; } List<Poll> polls = pollListManager .findAllPollsForUserAndSitesAndPermission(userId, siteIds, perm); if (adminControl) { // add in options for (Poll p : polls) { List<Option> options = pollListManager.getOptionsForPoll(p .getPollId()); p.setOptions(options); } } else { // add in the indicators that this user has replied Long[] pollIds = new Long[polls.size()]; for (int i = 0; i < polls.size(); i++) { pollIds[i] = polls.get(i).getPollId(); } Map<Long, List<Vote>> voteMap = pollVoteManager.getVotesForUser( userId, pollIds); for (Poll poll : polls) { Long pollId = poll.getPollId(); List<Vote> l = voteMap.get(pollId); if (l != null) { poll.setCurrentUserVoted(true); poll.setCurrentUserVotes(l); } else { poll.setCurrentUserVoted(false); } } } return polls; } /** * @param id * @return */ private Poll getPollById(String id) { Long pollId; try { pollId = Long.valueOf(id); } catch (NumberFormatException e) { throw new IllegalArgumentException("Invalid poll id (" + id + "), the id must be a number"); } Poll poll = pollListManager.getPollById(pollId, false); return poll; } @EntityCustomAction(action = "poll-view", viewKey = EntityView.VIEW_SHOW) public Poll getPollEntity(EntityView view, EntityReference ref) { String id = ref.getId(); log.debug(id); if (StringUtils.isBlank(id)) { log.warn("Poll id is not exist. Returning an empty poll object."); return new Poll(); } Poll poll = getPollById(id); if (poll == null) { throw new IllegalArgumentException( "No poll found for the given reference: " + id); } Long pollId = poll.getPollId(); String currentUserId = developerHelperService.getCurrentUserId(); boolean allowedManage = false; if (!developerHelperService.isEntityRequestInternal(id + "")) { if (!pollListManager.isPollPublic(poll)) { // this is not a public poll? (ie .anon role has poll.vote) String userReference = developerHelperService .getCurrentUserReference(); if (userReference == null) { throw new EntityException( "User must be logged in in order to access poll data", id, HttpServletResponse.SC_UNAUTHORIZED); } allowedManage = developerHelperService .isUserAllowedInEntityReference(userReference, PollListManager.PERMISSION_ADD, "/site/" + poll.getSiteId()); boolean allowedVote = developerHelperService .isUserAllowedInEntityReference(userReference, PollListManager.PERMISSION_VOTE, "/site/" + poll.getSiteId()); if (!allowedManage && !allowedVote) { throw new SecurityException("User (" + userReference + ") not allowed to access poll data: " + id); } } } log.debug(requestStorage == null); Boolean includeVotes = requestStorage.getStoredValueAsType( Boolean.class, "includeVotes"); if (includeVotes == null) { includeVotes = false; } if (includeVotes) { List<Vote> votes = pollVoteManager.getAllVotesForPoll(poll); poll.setVotes(votes); } Boolean includeOptions = requestStorage.getStoredValueAsType( Boolean.class, "includeOptions"); if (includeOptions == null) { includeOptions = false; } if (includeOptions) { List<Option> options = pollListManager.getOptionsForPoll(poll); poll.setOptions(options); } // add in the indicator that this user has replied if (currentUserId != null) { Map<Long, List<Vote>> voteMap = pollVoteManager.getVotesForUser( currentUserId, new Long[] { pollId }); List<Vote> l = voteMap.get(pollId); if (l != null) { poll.setCurrentUserVoted(true); poll.setCurrentUserVotes(l); } else { poll.setCurrentUserVoted(false); } } return poll; } /** * Note that details is the only optional field */ @EntityCustomAction(action = "poll-create", viewKey = EntityView.VIEW_NEW) public String createPollEntity(EntityReference ref, Map<String, Object> params) { Poll poll = new Poll(); // copy from params to Poll copyParamsToObject(params, poll); poll.setCreationDate(new Date()); if (poll.getId() == null) { poll.setId(UUID.randomUUID().toString()); } if (poll.getOwner() == null) { poll.setOwner(developerHelperService.getCurrentUserId()); } String siteId = developerHelperService.getCurrentLocationId(); if (poll.getSiteId() == null) { poll.setSiteId(siteId); } else { siteId = poll.getSiteId(); } String userReference = developerHelperService.getCurrentUserReference(); String location = "/site/" + siteId; boolean allowed = developerHelperService .isUserAllowedInEntityReference(userReference, PollListManager.PERMISSION_ADD, location); if (!allowed) { throw new SecurityException("Current user (" + userReference + ") cannot create polls in location (" + location + ")"); } pollListManager.savePoll(poll); return poll.getPollId() + ""; } @EntityCustomAction(action = "poll-update", viewKey = EntityView.VIEW_EDIT) public void updatePollEntity(EntityReference ref, Map<String, Object> params) { String id = ref.getId(); if (id == null) { throw new IllegalArgumentException( "The reference must include an id for updates (id is currently null)"); } String userReference = developerHelperService.getCurrentUserReference(); if (userReference == null) { throw new SecurityException("anonymous user cannot update poll: " + ref); } Poll current = getPollById(id); if (current == null) { throw new IllegalArgumentException( "No poll found to update for the given reference: " + ref); } Poll poll = new Poll(); copyParamsToObject(params, poll); String siteId = developerHelperService.getCurrentLocationId(); if (poll.getSiteId() == null) { poll.setSiteId(siteId); } else { siteId = poll.getSiteId(); } String location = "/site/" + siteId; // should this check a different permission? boolean allowed = developerHelperService .isUserAllowedInEntityReference(userReference, PollListManager.PERMISSION_ADD, location); if (!allowed) { throw new SecurityException("Current user (" + userReference + ") cannot update polls in location (" + location + ")"); } developerHelperService.copyBean(poll, current, 0, new String[] { "id", "pollId", "owner", "siteId", "creationDate", "reference", "url", "properties" }, true); pollListManager.savePoll(current); } @EntityCustomAction(action = "poll-delete", viewKey = EntityView.VIEW_SHOW) public Object deletePollEntity(EntityReference ref) { String id = ref.getId(); if (id == null) { throw new IllegalArgumentException( "The reference must include an id for deletes (id is currently null)"); } Poll poll = getPollById(id); if (poll == null) { throw new IllegalArgumentException( "No poll found for the given reference: " + ref); } try { pollListManager.deletePoll(poll); return String.format("Poll id %d removed", id); } catch (SecurityException e) { throw new SecurityException("The current user (" + developerHelperService.getCurrentUserReference() + ") is not allowed to delete this poll: " + ref); } } /** * /{pollId}/poll-options */ @EntityCustomAction(action = "poll-option-list", viewKey = EntityView.VIEW_SHOW) public List<?> getPollOptionList(EntityView view, EntityReference ref) { // get the pollId String id = ref.getId(); log.debug(id); // check siteId supplied if (StringUtils.isBlank(id)) { throw new IllegalArgumentException( "siteId must be set in order to get the polls for a site, via the URL /polls/site/siteId"); } Long pollId = null; try { pollId = Long.parseLong(id); } catch (UnsupportedOperationException e) { throw new IllegalArgumentException( "Invalid: pollId must be a long number: " + e.getMessage(), e); } // get the poll Poll poll = pollListManager.getPollById(pollId); if (poll == null) { throw new IllegalArgumentException("pollId (" + pollId + ") is invalid and does not match any known polls"); } else { boolean allowedPublic = pollListManager.isPollPublic(poll); if (!allowedPublic) { String userReference = developerHelperService .getCurrentUserReference(); if (userReference == null) { throw new EntityException( "User must be logged in in order to access poll data", id, HttpServletResponse.SC_UNAUTHORIZED); } else { boolean allowedManage = false; boolean allowedVote = false; allowedManage = developerHelperService .isUserAllowedInEntityReference(userReference, PollListManager.PERMISSION_ADD, "/site/" + poll.getSiteId()); allowedVote = developerHelperService .isUserAllowedInEntityReference(userReference, PollListManager.PERMISSION_VOTE, "/site/" + poll.getSiteId()); if (!(allowedManage || allowedVote)) { throw new SecurityException("User (" + userReference + ") not allowed to access poll data: " + id); } } } } // get the options List<Option> options = pollListManager.getOptionsForPoll(pollId); return options; } @EntityCustomAction(action = "option-view", viewKey = EntityView.VIEW_SHOW) public Object getOptionEntity(EntityReference ref) { String id = ref.getId(); if (id == null) { return new Option(); } String currentUser = developerHelperService.getCurrentUserReference(); if (currentUser == null) { throw new EntityException( "Anonymous users cannot view specific options", ref.getId(), HttpServletResponse.SC_UNAUTHORIZED); } Option option = getOptionById(id); if (developerHelperService.isEntityRequestInternal(ref.toString())) { // ok to retrieve internally } else { // need to security check if (developerHelperService.isUserAdmin(currentUser)) { // ok to view this vote } else { // not allowed to view throw new SecurityException("User (" + currentUser + ") cannot view option (" + ref + ")"); } } return option; } @EntityCustomAction(action = "option-create", viewKey = EntityView.VIEW_NEW) public String createOptionEntity(EntityReference ref, Map<String, Object> params) { String userReference = developerHelperService.getCurrentUserReference(); if (userReference == null) { throw new EntityException( "User must be logged in to create new options", ref.getId(), HttpServletResponse.SC_UNAUTHORIZED); } Option option = new Option(); // copy from params to Option copyParamsToObject(params, option); // check minimum settings if (option.getPollId() == null) { throw new IllegalArgumentException( "Poll ID must be set to create an option"); } // check minimum settings if (option.getOptionText() == null) { throw new IllegalArgumentException( "Poll Option text must be set to create an option"); } checkOptionPermission(userReference, option); // set default values option.setUUId(UUID.randomUUID().toString()); boolean saved = pollListManager.saveOption(option); if (!saved) { throw new IllegalStateException("Unable to save option (" + option + ") for user (" + userReference + "): " + ref); } return option.getId() + ""; } /** * Helper to copy from map of parameters to object. * * @param params * source * @param object * destination */ private void copyParamsToObject(Map<String, Object> params, Object object) { Class<?> c = object.getClass(); Method[] methods = c.getDeclaredMethods(); for (Method m : methods) { String name = m.getName(); Class<?>[] types = m.getParameterTypes(); if (name.startsWith("set") && (types.length == 1)) { String key = Character.toLowerCase(name.charAt(3)) + name.substring(4); Object value = params.get(key); if (value != null) { if (types[0].equals(Date.class)) { Date dateValue = new Date( Long.valueOf(value.toString())); try { m.invoke(object, new Object[] { dateValue }); } catch (IllegalAccessException e) { log.debug(e); } catch (IllegalArgumentException e) { log.debug(e); } catch (InvocationTargetException e) { log.debug(e); } } else { // use generic converter from BeanUtils try { BeanUtils.copyProperty(object, key, value); } catch (IllegalAccessException e) { log.debug(e); } catch (InvocationTargetException e) { log.debug(e); } } } } } } @EntityCustomAction(action = "option-update", viewKey = EntityView.VIEW_EDIT) public void updateOptionEntity(EntityReference ref, Map<String, Object> params) { String id = ref.getId(); if (id == null) { throw new IllegalArgumentException( "The reference must include an id for updates (id is currently null)"); } String userReference = developerHelperService.getCurrentUserReference(); if (userReference == null) { throw new EntityException("Anonymous user cannot update option", ref.getId(), HttpServletResponse.SC_UNAUTHORIZED); } Option current = getOptionById(id); if (current == null) { throw new IllegalArgumentException( "No option found to update for the given reference: " + ref); } Option option = new Option(); // copy from params to Option copyParamsToObject(params, option); checkOptionPermission(userReference, current); developerHelperService.copyBean(option, current, 0, new String[] { "id", "pollId", "UUId" }, true); boolean saved = pollListManager.saveOption(current); if (!saved) { throw new IllegalStateException("Unable to update option (" + option + ") for user (" + userReference + "): " + ref); } } @EntityCustomAction(action = "option-delete", viewKey = EntityView.VIEW_SHOW) public void deleteOptionEntity(EntityReference ref, Map<String, Object> params) { String id = ref.getId(); String userReference = developerHelperService.getCurrentUserReference(); if (userReference == null) { throw new EntityException("Anonymous user cannot delete option", ref.getId(), HttpServletResponse.SC_UNAUTHORIZED); } Option option = getOptionById(id); if (option == null) { throw new IllegalArgumentException( "No option found to delete for the given reference: " + ref); } checkOptionPermission(userReference, option); pollListManager.deleteOption(option); // return String.format("Poll option id %d removed", id); } /** * Checks if the given user can create/update/delete options * * @param userRef * @param option */ private void checkOptionPermission(String userRef, Option option) { if (option.getPollId() == null) { throw new IllegalArgumentException( "Poll Id must be set in the option to check permissions: " + option); } Long pollId = option.getPollId(); // validate poll exists Poll poll = pollListManager.getPollById(pollId, false); if (poll == null) { throw new IllegalArgumentException("Invalid poll id (" + pollId + "), could not find poll from option: " + option); } // check permissions String siteRef = "/site/" + poll.getSiteId(); if (!developerHelperService.isUserAllowedInEntityReference(userRef, PollListManager.PERMISSION_ADD, siteRef)) { throw new SecurityException( "User (" + userRef + ") is not allowed to create/update/delete options in this poll (" + pollId + ")"); } } /** * @param id * @return */ private Option getOptionById(String id) { Long optionId; try { optionId = Long.valueOf(id); } catch (NumberFormatException e) { throw new IllegalArgumentException("Cannot convert id (" + id + ") to long: " + e.getMessage(), e); } Option option = pollListManager.getOptionById(optionId); return option; } @EntityCustomAction(action = "vote-create", viewKey = EntityView.VIEW_NEW) public String createVoteEntity(EntityReference ref, Map<String, Object> params) { String userId = userDirectoryService.getCurrentUser().getId(); Vote vote = new Vote(); copyParamsToObject(params, vote); log.debug("got vote: " + vote.toString()); Long pollId = null; try { pollId = Long.valueOf((String) params.get("pollId")); } catch (Exception e) { log.warn(e); } if (pollId == null) { throw new IllegalArgumentException( "Poll Id must be set to create a vote"); } vote.setPollId(pollId); Long optionId = null; try { optionId = Long.valueOf((String) params.get("pollOption")); } catch (Exception e) { log.warn(e); } if (optionId == null) { throw new IllegalArgumentException( "Poll Option must be set to create a vote"); } if (!pollVoteManager.isUserAllowedVote(userId, pollId, false)) { throw new SecurityException("User (" + userId + ") is not allowed to vote in this poll (" + pollId + ")"); } vote.setPollOption(optionId); // validate option Option option = pollListManager.getOptionById(vote.getPollOption()); if (option == null) { throw new IllegalArgumentException("Invalid poll option (" + vote.getPollOption() + ") [cannot find option] in vote (" + vote + ") for user (" + userId + ")"); } else { if (!pollId.equals(option.getPollId())) { throw new IllegalArgumentException("Invalid poll option (" + vote.getPollOption() + ") [not in poll (" + pollId + ")] in vote (" + vote + ") for user (" + userId + ")"); } } // set default vote values vote.setVoteDate(new Date()); vote.setUserId(userId); if (vote.getSubmissionId() == null) { String sid = userId + ":" + UUID.randomUUID(); vote.setSubmissionId(sid); } // set the IP address UsageSession usageSession = usageSessionService.getSession(); if (usageSession != null) { vote.setIp(usageSession.getIpAddress()); } boolean saved = pollVoteManager.saveVote(vote); if (!saved) { throw new IllegalStateException("Unable to save vote (" + vote + ") for user (" + userId + "): " + ref); } return vote.getId() + ""; } @EntityCustomAction(action = "vote-view", viewKey = EntityView.VIEW_SHOW) public Object getVoteEntity(EntityReference ref) { String id = ref.getId(); String currentUser = developerHelperService.getCurrentUserReference(); log.debug("current user is: " + currentUser); if (currentUser == null || currentUser.length() == 0) { throw new EntityException( "Anonymous users cannot view specific votes", ref.getId(), HttpServletResponse.SC_UNAUTHORIZED); } // is this a new object? if (ref.getId() == null) { new Vote(); } Vote vote = getVoteById(id); String userId = developerHelperService.getUserIdFromRef(currentUser); if (developerHelperService.isUserAdmin(currentUser)) { // ok to view this vote } else if (userId.equals(vote.getUserId())) { // ok to view own } else if (developerHelperService.isEntityRequestInternal(ref .toString())) { // ok for all internal requests } else { // TODO - check vote location and perm? // not allowed to view throw new SecurityException("User (" + currentUser + ") cannot view vote (" + ref + ")"); } if (id == null) { return new Vote(); } return vote; } @EntityCustomAction(action = "vote-list", viewKey = EntityView.VIEW_LIST) public List<?> getVoteEntities(EntityReference ref, Search search) { String currentUserId = userDirectoryService.getCurrentUser().getId(); Restriction pollRes = search.getRestrictionByProperty("pollId"); if (pollRes == null || pollRes.getSingleValue() == null) { // throw new // IllegalArgumentException("Must include a non-null pollId in order to retreive a list of votes"); return null; } Long pollId = null; boolean viewVoters = false; if (developerHelperService.isUserAdmin(developerHelperService .getCurrentUserReference())) { viewVoters = true; } try { pollId = developerHelperService.convert(pollRes.getSingleValue(), Long.class); } catch (UnsupportedOperationException e) { throw new IllegalArgumentException( "Invalid: pollId must be a long number: " + e.getMessage(), e); } Poll poll = pollListManager.getPollById(pollId); if (poll == null) { throw new IllegalArgumentException("pollId (" + pollId + ") is invalid and does not match any known polls"); } List<Vote> votes = pollVoteManager.getAllVotesForPoll(poll); if (developerHelperService.isEntityRequestInternal(ref.toString())) { // ok for all internal requests } else if (!pollListManager.isAllowedViewResults(poll, currentUserId)) { // TODO - check vote location and perm? // not allowed to view throw new SecurityException("User (" + currentUserId + ") cannot view vote (" + ref + ")"); } if (viewVoters) { return votes; } else { return anonymizeVotes(votes); } } private List<?> anonymizeVotes(List<Vote> votes) { List<Vote> ret = new ArrayList<Vote>(); String userId = userDirectoryService.getCurrentUser().getId(); for (int i = 0; i < votes.size(); i++) { Vote vote = (Vote) votes.get(i); if (!userId.equals(vote.getUserId())) { Vote newVote = new Vote(); newVote.setPollId(vote.getPollId()); newVote.setPollOption(vote.getPollOption()); newVote.setSubmissionId(vote.getSubmissionId()); ret.add(newVote); } else { ret.add(vote); } } return ret; } /** * Allows a user to create multiple Vote objects at once, taking one or more * pollOption parameters. */ @EntityCustomAction(action = "vote", viewKey = EntityView.VIEW_NEW) public List<Vote> vote(EntityView view, EntityReference ref, String prefix, Search search, OutputStream out, Map<String, Object> params) { Long pollId = null; try { pollId = Long.valueOf((String) params.get("pollId")); } catch (NumberFormatException nfe) { throw new IllegalArgumentException("No pollId found."); } String userId = userDirectoryService.getCurrentUser().getId(); Poll poll = pollListManager.getPollById(pollId, false); if (poll == null) { throw new IllegalArgumentException( "No poll found to update for the given reference: " + ref); } if (!pollVoteManager.isUserAllowedVote(userId, poll.getPollId(), false)) { throw new SecurityException("User (" + userId + ") is not allowed to vote in this poll (" + poll.getPollId() + ")"); } Set<String> optionIds = new HashSet<String>(); Object param = params.get("pollOption"); if (param == null) { throw new IllegalArgumentException( "At least one pollOption parameter must be provided to vote."); } else if (param instanceof String) { optionIds.add((String) param); } else if (param instanceof Iterable<?>) { for (Object o : (Iterable<?>) param) if (o instanceof String) optionIds.add((String) o); else throw new IllegalArgumentException( "Each pollOption must be a String, not " + o.getClass().getName()); } else if (param instanceof Object[]) { for (Object o : (Object[]) param) if (o instanceof String) optionIds.add((String) o); else throw new IllegalArgumentException( "Each pollOption must be a String, not " + o.getClass().getName()); } else throw new IllegalArgumentException( "pollOption must be String, String[] or List<String>, not " + param.getClass().getName()); // Turn each option String into an Option, making sure that each is a // valid choice for the poll. We use a Map to make sure one cannot vote // more than once for any option by specifying it using equivalent // representations Map<Long, Option> options = new HashMap<Long, Option>(); for (String optionId : optionIds) { try { Option option = pollListManager.getOptionById(Long .valueOf(optionId)); if (!poll.getPollId().equals(option.getPollId())) throw new Exception(); options.put(option.getOptionId(), option); } catch (Exception e) { throw new IllegalArgumentException("Invalid pollOption: " + optionId); } } // Validate that the number of options voted for is within acceptable // bounds. if (options.size() < poll.getMinOptions()) throw new IllegalArgumentException("You must provide at least " + poll.getMinOptions() + " options, not " + options.size() + "."); if (options.size() > poll.getMaxOptions()) throw new IllegalArgumentException("You may provide at most " + poll.getMaxOptions() + " options, not " + options.size() + "."); // Create and save the Vote objects. UsageSession usageSession = usageSessionService.getSession(); List<Vote> votes = new ArrayList<Vote>(); for (Option option : options.values()) { Vote vote = new Vote(); vote.setVoteDate(new Date()); vote.setUserId(userId); vote.setPollId(poll.getPollId()); vote.setPollOption(option.getOptionId()); if (vote.getSubmissionId() == null) { String sid = userId + ":" + UUID.randomUUID(); vote.setSubmissionId(sid); } if (usageSession != null) vote.setIp(usageSession.getIpAddress()); boolean saved = pollVoteManager.saveVote(vote); if (!saved) { throw new IllegalStateException("Unable to save vote (" + vote + ") for user (" + userId + "): " + ref); } votes.add(vote); } return votes; } /** * @param id * @return */ private Vote getVoteById(String id) { Long voteId; try { voteId = Long.valueOf(id); } catch (NumberFormatException e) { throw new IllegalArgumentException("Cannot convert id (" + id + ") to long: " + e.getMessage(), e); } Vote vote = pollVoteManager.getVoteById(voteId); return vote; } }