/plugin/src/main/java/com/atlassian/confluence/extra/userlister/UserLister.java
Java | 290 lines | 229 code | 54 blank | 7 comment | 23 complexity | dcd4756381637cb92574a78630651fb2 MD5 | raw file
- package com.atlassian.confluence.extra.userlister;
- import com.atlassian.confluence.content.render.xhtml.ConversionContext;
- import com.atlassian.confluence.content.render.xhtml.DefaultConversionContext;
- import com.atlassian.confluence.extra.userlister.model.UserList;
- import com.atlassian.confluence.languages.LocaleManager;
- import com.atlassian.confluence.macro.Macro;
- import com.atlassian.confluence.macro.MacroExecutionException;
- import com.atlassian.confluence.plugin.descriptor.web.conditions.PeopleDirectoryEnabledCondition;
- import com.atlassian.confluence.plugin.services.VelocityHelperService;
- import com.atlassian.confluence.security.PermissionManager;
- import com.atlassian.confluence.user.AuthenticatedUserThreadLocal;
- import com.atlassian.confluence.user.UserAccessor;
- import com.atlassian.confluence.util.i18n.I18NBean;
- import com.atlassian.confluence.util.i18n.I18NBeanFactory;
- import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
- import com.atlassian.renderer.RenderContext;
- import com.atlassian.renderer.TokenType;
- import com.atlassian.renderer.v2.RenderMode;
- import com.atlassian.renderer.v2.RenderUtils;
- import com.atlassian.renderer.v2.macro.BaseMacro;
- import com.atlassian.renderer.v2.macro.MacroException;
- import com.atlassian.sal.api.rdbms.TransactionalExecutorFactory;
- import com.atlassian.user.Group;
- import com.atlassian.user.search.page.Pager;
- import com.atlassian.user.search.page.PagerUtils;
- import org.apache.commons.lang3.ArrayUtils;
- import org.apache.commons.lang3.StringUtils;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.factory.annotation.Autowired;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.TreeSet;
- import java.util.stream.Collectors;
- import static java.util.stream.Collectors.toList;
- import static org.apache.commons.lang3.StringUtils.join;
- import static org.apache.commons.lang3.StringUtils.split;
- public class UserLister extends BaseMacro implements Macro {
- static final String USER_LISTER_LIMIT_PROPERTY = "confluence.extra.userlister.limit";
- private static final Logger logger = LoggerFactory.getLogger(UserLister.class);
- private static final int DEFAULT_USER_LISTER_LIMIT = 10000;
- private final UserAccessor userAccessor;
- private final UserListManager userListManager;
- private final LocaleManager localeManager;
- private final I18NBeanFactory i18NBeanFactory;
- private final VelocityHelperService velocityHelperService;
- private final PermissionManager permissionManager;
- private final TransactionalExecutorFactory transactionalExecutorFactory;
- private enum ListMode {
- ALL,
- ONLINE_ONLY,
- OFFLINE_ONLY
- }
- @Autowired
- public UserLister(
- final @ComponentImport UserAccessor userAccessor,
- final UserListManager userListManager,
- final @ComponentImport LocaleManager localeManager,
- final @ComponentImport I18NBeanFactory i18NBeanFactory,
- final @ComponentImport VelocityHelperService velocityHelperService,
- final @ComponentImport PermissionManager permissionManager,
- final @ComponentImport TransactionalExecutorFactory transactionalExecutorFactory) {
- this.userAccessor = userAccessor;
- this.userListManager = userListManager;
- this.localeManager = localeManager;
- this.i18NBeanFactory = i18NBeanFactory;
- this.velocityHelperService = velocityHelperService;
- this.permissionManager = permissionManager;
- this.transactionalExecutorFactory = transactionalExecutorFactory;
- }
- @Override
- public TokenType getTokenType(Map parameters, String body, RenderContext context) {
- return TokenType.BLOCK;
- }
- public boolean hasBody() {
- return false;
- }
- public RenderMode getBodyRenderMode() {
- return RenderMode.NO_RENDER;
- }
- private I18NBean getI18NBean() {
- return i18NBeanFactory.getI18NBean(localeManager.getLocale(AuthenticatedUserThreadLocal.get()));
- }
- private String getText(String key) {
- return getI18NBean().getText(key);
- }
- private String getText(String key, List params) {
- return getI18NBean().getText(key, params);
- }
- public String execute(Map parameters, String body, RenderContext renderContext) throws MacroException {
- try {
- return execute(parameters, body, new DefaultConversionContext(renderContext));
- } catch (MacroExecutionException e) {
- throw new MacroException(e);
- }
- }
- private String createCSVList(List<String> emptyGroups) {
- return getText("userlister.noresultsfoundforgroups", Collections.singletonList(join(emptyGroups, ',')));
- }
- private Set<String> getGroups(final String groupNames) {
- String[] groupNameArray = split(groupNames, ',');
- final Set<String> groups = Arrays.stream(groupNameArray)
- .map(String::trim)
- .filter(StringUtils::isNotBlank)
- .collect(Collectors.toSet());
- /* We need to check if the user specified * in the group(s) macro parameter.
- * If he/she did, we need to expand it to all groups in Confluence
- */
- if (groups.contains(UserList.ALL_GROUP_NAME)) {
- userAccessor.getGroups().forEach(group -> groups.add(group.getName()));
- /* Then remove the wildcard */
- groups.remove(UserList.ALL_GROUP_NAME);
- }
- return groups;
- }
- private Set<String> getAllowedGroups(Set<String> groups) {
- Set<String> allowedGroups = new TreeSet<>(groups);
- allowedGroups.removeAll(userListManager.getGroupBlackList());
- return allowedGroups;
- }
- private Set<String> getDeniedGroups(Set<String> groups) {
- Set<String> deniedGroups = new TreeSet<>(groups);
- deniedGroups.retainAll(userListManager.getGroupBlackList());
- return deniedGroups;
- }
- public String execute(Map<String, String> parameters, String body, ConversionContext conversionContext) throws MacroExecutionException {
- if (isPeopleDirectoryDisabled()) {
- return RenderUtils.blockError(
- getText("userlister.notpermitted.viewuserprofile"),
- ""
- );
- }
- //1. parse parameters from macro
- final String groupNames = StringUtils.defaultString(parameters.get("groups"), parameters.get("group"));
- final boolean returnOnlineUsers = Boolean.parseBoolean(StringUtils.trim(parameters.get("online")));
- final Boolean showWarning = Boolean.valueOf(StringUtils.defaultString(StringUtils.trim(parameters.get("showWarning")), "true"));
- final Set blackListedGroups = userListManager.getGroupBlackList();
- if (StringUtils.isBlank(groupNames)) {
- return getText("userlister.no.groups.specified");
- }
- if (ArrayUtils.contains(split(groupNames, ','), UserList.ALL_GROUP_NAME)
- && blackListedGroups.contains(UserList.ALL_GROUP_NAME)) {
- return getText("userlister.group.name.list.contains.asterisk");
- }
- final Set<String> groups = getGroups(groupNames);
- final Set<String> allowedGroups = getAllowedGroups(groups);
- final Set<String> deniedGroups = getDeniedGroups(groups);
- final Set<String> loggedInUsernames = userListManager.getLoggedInUsers();
- final List<UserList> groupList = new ArrayList<>();
- final List<String> emptyGroups = new ArrayList<>();
- final ListMode listMode = !parameters.containsKey("online")
- ? ListMode.ALL
- : (returnOnlineUsers ? ListMode.ONLINE_ONLY : ListMode.OFFLINE_ONLY);
- final int userLimit = Integer.getInteger(USER_LISTER_LIMIT_PROPERTY, DEFAULT_USER_LISTER_LIMIT);
- //run the batch query in a new readonly transaction to avoid unnecessary automatic flush
- String macroText = transactionalExecutorFactory.createExecutor(true, true).execute(connection -> {
- int userCount = 0;
- List<UserList> usersToBeLoaded = new ArrayList<>();
- for (String currentGroup : allowedGroups) {
- List<String> usernames = getUserNames(currentGroup, loggedInUsernames, listMode);
- userCount += usernames.size();
- if (userCount >= userLimit) {
- logger.warn(String.format("There are too many users in the specified groups. The limit is %s.", userLimit));
- return getText("userlister.too.many.users", Collections.singletonList(userLimit));
- }
- usersToBeLoaded.add(new UserList(currentGroup, userAccessor, usernames, loggedInUsernames));
- }
- for (UserList userList : usersToBeLoaded) {
- if (!userList.getUsers().isEmpty()) {
- groupList.add(userList);
- } else {
- emptyGroups.add(userList.getGroup());
- }
- }
- return null;
- }
- );
- if (StringUtils.isNotBlank(macroText)) {
- return macroText;
- }
- // now create a simple velocity context and render a template for the output
- Map<String, Object> contextMap = velocityHelperService.createDefaultVelocityContext();
- if (!deniedGroups.isEmpty())
- contextMap.put("deniedGroups", deniedGroups);
- contextMap.put("showWarning", showWarning);
- contextMap.put("userlists", groupList);
- if (listMode != ListMode.ALL) {
- contextMap.put("online", returnOnlineUsers);
- } else {
- contextMap.put("allUserStatuses", true);
- }
- if (emptyGroups.size() > 0) {
- contextMap.put("emptyGroups", createCSVList(emptyGroups));
- }
- try {
- return velocityHelperService.getRenderedTemplate("templates/extra/userlister/userlistermacro.vm", contextMap);
- } catch (Exception e) {
- logger.error("Error while trying to display UserList!", e);
- return getText("userlister.unable.to.render.result", Collections.singletonList(e.toString()));
- }
- }
- private List<String> getUserNames(String groupName, Collection loggedInUsers, ListMode listMode) {
- final List<String> usernames = getUserNamesByGroup(groupName);
- if (listMode == ListMode.ALL) {
- return usernames;
- }
- return usernames.stream().filter(username -> {
- final boolean online = loggedInUsers.contains(username);
- return (listMode == ListMode.ONLINE_ONLY) == online;
- }).collect(toList());
- }
- private List<String> getUserNamesByGroup(String groupName) {
- Pager<String> usernames = null;
- final Group group = userAccessor.getGroup(groupName);
- if (group != null) {
- usernames = userAccessor.getMemberNames(group);
- }
- return usernames == null ? Collections.emptyList() : PagerUtils.toList(usernames);
- }
- private boolean isPeopleDirectoryDisabled() {
- PeopleDirectoryEnabledCondition peopleDirectoryEnabledCondition = new PeopleDirectoryEnabledCondition();
- peopleDirectoryEnabledCondition.setPermissionManager(permissionManager);
- return peopleDirectoryEnabledCondition.isPeopleDirectoryDisabled(AuthenticatedUserThreadLocal.get());
- }
- public BodyType getBodyType() {
- return BodyType.NONE;
- }
- public OutputType getOutputType() {
- return OutputType.BLOCK;
- }
- }