co.mitro.core.servlets.GetPendingGroupApprovals.java Source code

Java tutorial

Introduction

Here is the source code for co.mitro.core.servlets.GetPendingGroupApprovals.java

Source

/*******************************************************************************
 * Copyright (c) 2013 Lectorius, Inc.
 * Authors:
 * Vijay Pandurangan (vijayp@mitro.co)
 * Evan Jones (ej@mitro.co)
 * Adam Hilss (ahilss@mitro.co)
 *
 *
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *     
 *     You can contact the authors at inbound@mitro.co.
 *******************************************************************************/
/**
 * 
 */
package co.mitro.core.servlets;

import java.io.IOException;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.annotation.WebServlet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import co.mitro.core.accesscontrol.AuthenticatedDB;
import co.mitro.core.exceptions.MitroServletException;
import co.mitro.core.server.data.DBGroup;
import co.mitro.core.server.data.DBIdentity;
import co.mitro.core.server.data.DBPendingGroup;
import co.mitro.core.server.data.RPC;
import co.mitro.core.server.data.RPC.AddPendingGroupRequest.MemberList;
import co.mitro.core.server.data.RPC.EditGroupRequest;
import co.mitro.core.server.data.RPC.GetPendingGroupApprovalsRequest;
import co.mitro.core.server.data.RPC.GetPendingGroupApprovalsResponse.PendingGroupApproval;
import co.mitro.core.server.data.RPC.GroupDiff;
import co.mitro.core.server.data.RPC.GroupDiff.GroupModificationType;
import co.mitro.core.server.data.RPC.MitroRPC;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 * @author vijayp
 * 
 */
@WebServlet("/api/GetPendingGroups")
public class GetPendingGroupApprovals extends MitroServlet {

    /**
     * 
     */
    private static final long serialVersionUID = 7257988672701779890L;
    private static final Logger logger = LoggerFactory.getLogger(GetPendingGroupApprovals.class);

    /*
     * (non-Javadoc)
     * 
     * @see
     * co.mitro.core.servlets.MitroServlet#processCommand(co.mitro.core.server
     * .data.DBIdentity, java.lang.String, co.mitro.core.server.Manager)
     */
    @SuppressWarnings("deprecation")
    @Override
    protected MitroRPC processCommand(MitroRequestContext context)
            throws IOException, SQLException, MitroServletException {
        GetPendingGroupApprovalsRequest in = gson.fromJson(context.jsonRequest,
                GetPendingGroupApprovalsRequest.class);
        RPC.GetPendingGroupApprovalsResponse out = new RPC.GetPendingGroupApprovalsResponse();
        out.pendingAdditionsAndModifications = Lists.newArrayList();
        out.pendingDeletions = Lists.newArrayList();

        out.diffs = Collections.emptyMap();
        out.newOrgMembers = Collections.emptyList();
        out.deletedOrgMembers = Collections.emptyList();

        AuthenticatedDB userDb = AuthenticatedDB.deprecatedNew(context.manager, context.requestor);
        Set<DBGroup> orgs = userDb.getOrganizations();

        if (orgs.isEmpty()) {
            logger.warn("ignoring request from user who is not a member of any organizations");
            return out;
        } else {
            assert orgs.size() == 1;
        }

        final DBGroup org = orgs.iterator().next();
        assert (userDb.isOrganizationAdmin(org.getId()));

        List<DBPendingGroup> pendingDBGroups = context.manager.pendingGroupDao.queryForEq(DBPendingGroup.OWNING_ORG,
                org.getId());
        Map<String, PendingGroupApproval> pendingGroups = Maps.newHashMap();
        String nonce = null;
        String scope = null;
        for (DBPendingGroup databasePendingGroup : pendingDBGroups) {
            PendingGroupApproval pendingGroupOutput = new PendingGroupApproval();
            if (nonce == null) {
                nonce = databasePendingGroup.getSyncNonce();
            } else {
                assert (nonce.equals(databasePendingGroup.getSyncNonce())) : "only one nonce per sync data allowed "
                        + nonce + " " + databasePendingGroup.getSyncNonce();
            }

            // TODO: support multiple scopes per org by merging groups from multiple scopes.
            if (scope == null) {
                scope = databasePendingGroup.getScope();
            } else {
                assert scope.equals(databasePendingGroup.getScope()) : "non-unique scope detected: " + scope + ", "
                        + databasePendingGroup.getScope();
            }
            databasePendingGroup.fillPendingGroup(pendingGroupOutput);
            pendingGroups.put(pendingGroupOutput.groupName, pendingGroupOutput);
        }
        out.syncNonce = nonce;

        Map<String, DBGroup> existingGroups = Maps.newHashMap();
        Map<String, GroupDiff> diffs = Maps.newHashMap();
        Map<String, MemberList> groupNameToMemberListMap = Maps.newHashMap();
        AddPendingGroupServlet.calculatePendingGroupDiffs(context, pendingGroups.values(), org, existingGroups,
                diffs, groupNameToMemberListMap, scope);

        for (String groupName : Sets.union(pendingGroups.keySet(), diffs.keySet())) {
            if (pendingGroups.containsKey(groupName)) {
                if (!diffs.containsKey(groupName)) {
                    continue;
                }
                final PendingGroupApproval groupApprovalOut = pendingGroups.get(groupName);
                final GroupDiff gd = diffs.get(groupName);
                assert (!gd.groupModification.equals(GroupModificationType.IS_DELETED));
                if (gd.groupModification.equals(GroupModificationType.IS_NEW)) {
                    groupApprovalOut.matchedGroup = null;
                } else {
                    final DBGroup matchedGroup = existingGroups.get(groupName);
                    groupApprovalOut.matchedGroup = new EditGroupRequest();
                    GetGroup.fillEditGroupRequest(context.manager, matchedGroup, groupApprovalOut.matchedGroup,
                            in.deviceId);
                }
                out.pendingAdditionsAndModifications.add(groupApprovalOut);
            } else {
                assert (diffs.containsKey(groupName));
                final GroupDiff gd = diffs.get(groupName);
                assert (gd.groupModification.equals(GroupModificationType.IS_DELETED)); // otherwise it should have been handled above.
                EditGroupRequest groupToDelete = new EditGroupRequest();
                GetGroup.fillEditGroupRequest(context.manager, existingGroups.get(gd.groupName), groupToDelete,
                        in.deviceId);
                out.pendingDeletions.add(groupToDelete);
            }
        }

        if (!diffs.isEmpty()) {
            // TODO: eventually pull this out of a special ALL group that ought to be synced.
            Set<String> allUserNames = Sets.newHashSet();
            for (MemberList ml : groupNameToMemberListMap.values()) {
                allUserNames.addAll(ml.memberList);
            }
            // see which users we need to add to the org.
            Set<Integer> orgUserIds = MutateOrganization.getMemberIdsAndPrivateGroupIdsForOrg(context.manager, org)
                    .keySet();
            Set<String> existingOrgMembers = DBIdentity.getUserNamesFromIds(context.manager, orgUserIds);

            out.newOrgMembers = Lists.newArrayList(Sets.difference(allUserNames, existingOrgMembers));

            // TODO: if none of the groups that are synced is an ALL group, 
            // i.e. we're syncing a subset of the org, this will suggest 
            // deleting most org members, which is not good.  We need a better 
            // solution for this.
            out.deletedOrgMembers = Lists.newArrayList(Sets.difference(existingOrgMembers, allUserNames));
        } else {
            out.deletedOrgMembers = Collections.emptyList();
            out.newOrgMembers = Collections.emptyList();
        }
        out.diffs = diffs;
        out.orgId = org.getId();
        assert (out.diffs.size() == (out.pendingAdditionsAndModifications.size() + out.pendingDeletions.size()));
        return out;
    }

}