Package com.atlassian.labs.speakeasy

Source Code of com.atlassian.labs.speakeasy.SpeakeasyServiceImpl

package com.atlassian.labs.speakeasy;

import com.atlassian.event.api.EventPublisher;
import com.atlassian.labs.speakeasy.external.PluginType;
import com.atlassian.labs.speakeasy.external.SpeakeasyService;
import com.atlassian.labs.speakeasy.external.UnauthorizedAccessException;
import com.atlassian.labs.speakeasy.manager.*;
import com.atlassian.labs.speakeasy.model.*;
import com.atlassian.labs.speakeasy.product.ProductAccessor;
import com.atlassian.labs.speakeasy.util.FeedBuilder;
import com.atlassian.labs.speakeasy.util.exec.KeyedSyncExecutor;
import com.atlassian.labs.speakeasy.util.exec.Operation;
import com.atlassian.plugin.ModuleDescriptor;
import com.atlassian.plugin.Plugin;
import com.atlassian.plugin.PluginAccessor;
import com.atlassian.plugin.webresource.UrlMode;
import com.atlassian.plugin.webresource.WebResourceManager;
import com.atlassian.sal.api.ApplicationProperties;
import com.atlassian.sal.api.user.UserManager;
import com.google.common.base.Predicate;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Lists.newArrayList;
import static java.util.Arrays.asList;

/**
*
*/
public class SpeakeasyServiceImpl implements SpeakeasyService
{
    private final ApplicationProperties applicationProperties;
    private final PluginAccessor pluginAccessor;
    private final PluginSystemManager pluginSystemManager;
    private final ProductAccessor productAccessor;
    private final BundleContext bundleContext;
    private final PermissionManager permissionManager;
    private final UserManager userManager;
    private final SettingsManager settingsManager;
    private final WebResourceManager webResourceManager;
    private final ModuleDescriptor unknownScreenshotDescriptor;
    private final ExtensionOperationManager extensionOperationManager;
    private final KeyedSyncExecutor<UserExtension, String> exec;
    private final ExtensionManager extensionManager;
    private static final Logger log = LoggerFactory.getLogger(SpeakeasyServiceImpl.class);
    private final SearchManager searchManager;

    public SpeakeasyServiceImpl(PluginAccessor pluginAccessor, PluginSystemManager pluginSystemManager, ProductAccessor productAccessor, BundleContext bundleContext, PermissionManager permissionManager, UserManager userManager, SettingsManager settingsManager, ApplicationProperties applicationProperties, WebResourceManager webResourceManager, ExtensionOperationManager extensionOperationManager, final ExtensionManager extensionManager, SearchManager searchManager)
    {
        this.pluginAccessor = pluginAccessor;
        this.pluginSystemManager = pluginSystemManager;
        this.productAccessor = productAccessor;
        this.bundleContext = bundleContext;
        this.permissionManager = permissionManager;
        this.userManager = userManager;
        this.settingsManager = settingsManager;
        this.applicationProperties = applicationProperties;
        this.webResourceManager = webResourceManager;
        this.extensionManager = extensionManager;
        this.extensionOperationManager = extensionOperationManager;
        this.searchManager = searchManager;
        this.exec = new KeyedSyncExecutor<UserExtension, String>()
        {
            @Override
            protected UserExtension getTarget(String pluginKey, String user) throws Exception
            {
                return getRemotePlugin(pluginKey, user);
            }

            @Override
            protected void handleException(String pluginKey, Exception ex)
            {
                if (ex instanceof PluginOperationFailedException ||
                    ex instanceof UnauthorizedAccessException)
                {
                    throw (RuntimeException) ex;
                }
                else
                {
                    throw new PluginOperationFailedException(ex.getMessage(), ex, pluginKey);
                }
            }

            @Override
            protected void afterSuccessfulOperation(UserExtension target, Object result)
            {
                if (result instanceof String)
                {
                    extensionManager.resetExtension((String) result);
                }
                else if (result instanceof List)
                {
                    extensionManager.resetExtensions((List<String>)result);
                }
            }
        };
        this.unknownScreenshotDescriptor = pluginAccessor.getPluginModule("com.atlassian.labs.speakeasy-plugin:shared");
    }

    public UserPlugins getRemotePluginList(String userName, String... modifiedKeys) throws UnauthorizedAccessException
    {
        return getRemotePluginList(userName, asList(modifiedKeys));
    }
    public UserPlugins getRemotePluginList(String userName, List<String> modifiedKeys) throws UnauthorizedAccessException
    {
        validateAccess(userName);
        Iterable<UserExtension> plugins = extensionManager.getAllUserExtensions(userName);
        UserPlugins userPlugins = new UserPlugins(filter(plugins, new AuthorAccessFilter(permissionManager.canAuthorExtensions(userName))));
        userPlugins.setUpdated(modifiedKeys);
        return userPlugins;
    }

    public String getPluginFeed(String userName) throws UnauthorizedAccessException
    {
        validateAccess(userName);
        List<Plugin> plugins = extensionManager.getAllExtensionPlugins();
        return new FeedBuilder(plugins, bundleContext.getBundles()).
                serverName(applicationProperties.getDisplayName()).
                serverBaseUrl(applicationProperties.getBaseUrl()).
                profilePath(productAccessor.getProfilePath()).
                build();
    }

    public boolean doesPluginExist(String pluginKey)
    {
        return pluginAccessor.getPlugin(pluginKey) != null;
    }

    public UserExtension getRemotePlugin(String pluginKey, String userName) throws PluginOperationFailedException, UnauthorizedAccessException
    {
        validateAccess(userName);
        return extensionManager.getUserExtension(pluginKey, userName);
    }

    private Plugin getPlugin(String pluginKey)
    {
        validatePluginExists(pluginKey);
        return pluginAccessor.getPlugin(pluginKey);
    }

    public List<String> enableExtension(final String pluginKey, final String user) throws UnauthorizedAccessException
    {
        return enableExtension(pluginKey, user, true);
    }

    private List<String> enableExtension(final String pluginKey, final String user, final boolean sendNotification) throws UnauthorizedAccessException
    {
        validateAccess(user);
        validatePluginExists(pluginKey);
        List<String> keys = exec.forKey(pluginKey, user, new Operation<UserExtension,List<String>>()
        {
            public List<String> operateOn(UserExtension repo) throws Exception
            {
                validateAccessType(repo, "enable", repo.isCanEnable(), user);
                return extensionOperationManager.enable(repo, user, sendNotification);
            }
        });
        log.info("Allowed '{}' to access Speakeasy extension '{}'", user, pluginKey);
        return keys;
    }

    public String disableExtension(final String pluginKey, final String user) throws UnauthorizedAccessException
    {
        validateAccess(user);
        validatePluginExists(pluginKey);
        String key = exec.forKey(pluginKey, user, new Operation<UserExtension,String>()
        {
            public String operateOn(UserExtension repo) throws Exception
            {
                validateAccessType(repo, "disable", repo.isCanDisable(), user);
                return extensionOperationManager.disable(repo, user);
            }
        });
        log.info("Disallowed '{}' to access Speakeasy extension '{}'", user, pluginKey);
        return key;
    }

    public void disableAllExtensions(final String user) throws UnauthorizedAccessException
    {
        validateAccess(user);
        List<String> enabledKeys = extensionOperationManager.findAllEnabledExtensions(user);
        for (String key : enabledKeys)
        {
            exec.forKey(key, user, new Operation<UserExtension,Void>()
            {
                public Void operateOn(UserExtension repo) throws Exception
                {
                    extensionOperationManager.disable(repo, user);
                    return null;
                }
            });
        }
        extensionOperationManager.saveEnabledPlugins(enabledKeys, user);

        log.info("Disallowed  '{}' to access all Speakeasy extensions", user);
    }

    public void restoreAllExtensions(final String user) throws UnauthorizedAccessException
    {
        validateAccess(user);

        // do we care if they've enabled extensions since they unsubscribed?
        List<String> keysToRestore = extensionOperationManager.getEnabledPlugins(user);
        for (String key : keysToRestore)
        {
            enableExtension(key, user, false);
        }

        log.info("Restored '{}' access to all Speakeasy extensions", user);
    }

    public UserPlugins uninstallPlugin(String pluginKey, final String user) throws PluginOperationFailedException, UnauthorizedAccessException
    {
        validateAuthor(user);
        validatePluginExists(pluginKey);
        List<String> keysModified = exec.forKey(pluginKey, user, new Operation<UserExtension,List<String>>()
        {
            public List<String> operateOn(final UserExtension repo) throws Exception
            {
                return extensionOperationManager.uninstallExtension(repo, user, new Operation<String,Void>()
                {
                    public Void operateOn(String enablePluginKey) throws Exception
                    {
                        validateAccessType(repo, "uninstall", repo.isCanUninstall(), user);
                        enableExtension(enablePluginKey, user);
                        return null;
                    }
                });
            }
        });
        log.info("Uninstalled extension '{}' by user '{}'", pluginKey, user);
        return getRemotePluginList(user, keysModified);
    }

    public UserPlugins fork(String pluginKey, final String user, final String description) throws PluginOperationFailedException, UnauthorizedAccessException
    {
        validateAuthor(user);
        validatePluginExists(pluginKey);
        List<String> keysModified = exec.forKey(pluginKey, user, new Operation<UserExtension, List<String>>()
        {
            public List<String> operateOn(UserExtension repo) throws Exception
            {
                validateAccessType(repo, "fork", repo.isCanFork(), user);
                return extensionOperationManager.forkExtension(repo, user, description);
            }
        });
        log.info("Forked '{}' extension by '{}'", pluginKey, user);
        return getRemotePluginList(user, keysModified);
    }

    public File getPluginAsProject(String pluginKey, String user) throws UnauthorizedAccessException
    {
        try
        {
            validateAuthor(user);
            UserExtension plugin = getRemotePlugin(pluginKey, user);
            validateAccessType(plugin, "download", plugin.isCanDownload(), user);
            return pluginSystemManager.getPluginAsProject(pluginKey, plugin.getPluginType(), user);
        }
        catch (PluginOperationFailedException ex)
        {
            throw ex;
        }
        catch (RuntimeException ex)
        {
            throw new PluginOperationFailedException(ex.getMessage(), ex, pluginKey);
        }
    }

    public File getPluginArtifact(String pluginKey, String user) throws UnauthorizedAccessException
    {
        try
        {
            validateAuthor(user);
            UserExtension plugin = getRemotePlugin(pluginKey, user);
            validateAccessType(plugin, "download", plugin.isCanDownload(), user);
            return pluginSystemManager.getPluginArtifact(pluginKey, plugin.getPluginType());
        }
        catch (PluginOperationFailedException ex)
        {
            throw ex;
        }
        catch (RuntimeException ex)
        {
            throw new PluginOperationFailedException(ex.getMessage(), ex, pluginKey);
        }
    }

    public List<String> getPluginFileNames(String pluginKey, String user) throws UnauthorizedAccessException
    {
        try
        {
            validateAuthor(user);
            validatePluginExists(pluginKey);
            UserExtension plugin = getRemotePlugin(pluginKey, user);
            return newArrayList(filter(pluginSystemManager.getPluginFileNames(pluginKey, plugin.getPluginType()), new Predicate<String>()
            {
                public boolean apply(String input)
                {
                    return !input.contains("-min.");
                }
            }));
        }
        catch (PluginOperationFailedException ex)
        {
            throw ex;
        }
        catch (RuntimeException ex)
        {
            throw new PluginOperationFailedException(ex.getMessage(), ex, pluginKey);
        }
    }

    public Object getPluginFile(String pluginKey, String fileName, String user) throws UnauthorizedAccessException
    {
        try
        {
            validateAuthor(user);
            validatePluginExists(pluginKey);
            UserExtension plugin = getRemotePlugin(pluginKey, user);
            return pluginSystemManager.getPluginFile(pluginKey, plugin.getPluginType(), fileName);
        }
        catch (PluginOperationFailedException ex)
        {
            throw ex;
        }
        catch (RuntimeException ex)
        {
            throw new PluginOperationFailedException(ex.getMessage(), ex, pluginKey);
        }
    }

    public UserExtension saveAndRebuild(String pluginKey, final String fileName, final String contents, final String user) throws UnauthorizedAccessException
    {
        validateAuthor(user);
        validatePluginExists(pluginKey);
        String installedKey = exec.forKey(pluginKey, user, new Operation<UserExtension, String>()
        {
            public String operateOn(UserExtension repo) throws Exception
            {
                validateAccessType(repo, "edit", repo.isCanEdit(), user);
                return extensionOperationManager.saveAndRebuild(repo, fileName, contents, user);
            }
        });
        log.info("Saved and rebuilt extension '{}' by user '{}'", pluginKey, user);
        return getRemotePlugin(installedKey, user);
    }

    public UserPlugins favorite(final String pluginKey, final String user) throws UnauthorizedAccessException
    {
        validateAccess(user);
        validatePluginExists(pluginKey);
        String favoritedPluginKey = exec.forKey(pluginKey, user, new Operation<UserExtension, String>()
        {
            public String operateOn(UserExtension repo) throws Exception
            {
                validateAccessType(repo, "favorite", repo.isCanFavorite(), user);
                return extensionOperationManager.favorite(repo, user);
            }
        });
        log.info("Favorited '{}' by user '{}'", favoritedPluginKey, user);
        return getRemotePluginList(user, favoritedPluginKey);
    }

    public UserPlugins unfavorite(final String pluginKey, final String user) throws UnauthorizedAccessException
    {
        validateAccess(user);
        validatePluginExists(pluginKey);
        String unfavoritedPluginkey = exec.forKey(pluginKey, user, new Operation<UserExtension, String>()
        {
            public String operateOn(UserExtension repo) throws Exception
            {
                validateAccessType(repo, "unfavorite", !repo.isCanFavorite(), user);
                return extensionOperationManager.unfavorite(repo, user);
            }
        });
        log.info("Unfavorited '{}' by user '{}'", unfavoritedPluginkey, user);
        return getRemotePluginList(user, unfavoritedPluginkey);
    }

    public UserPlugins enableGlobally(String pluginKey, final String user)
    {
        validateAccess(user);
        validateAdmin(user);
        validatePluginExists(pluginKey);
        exec.forKey(pluginKey, user, new Operation<UserExtension, Void>()
        {
            public Void operateOn(UserExtension repo) throws Exception
            {
                validateAccessType(repo, "enable globally", repo.isCanEnableGlobally(), user);
                extensionOperationManager.enableGlobally(repo, user);
                return null;
            }
        });
        log.info("Enabled extension '{}' globally by user '{}'", pluginKey, user);
        return getRemotePluginList(user, pluginKey);
    }

    public UserPlugins disableGlobally(String pluginKey, final String user)
    {
        validateAccess(user);
        validateAdmin(user);
        validatePluginExists(pluginKey);
        exec.forKey(pluginKey, user, new Operation<UserExtension, Void>()
        {
            public Void operateOn(UserExtension repo) throws Exception
            {
                validateAccessType(repo, "disable globally", repo.isCanDisableGlobally(), user);
                extensionOperationManager.disableGlobally(repo, user);
                return null;
            }
        });
        log.info("Disabled extension '{}' globally by user '{}'", pluginKey, user);
        return getRemotePluginList(user, pluginKey);
    }

    public void sendFeedback(final String pluginKey, final Feedback feedback, final String user) throws UnauthorizedAccessException
    {
        validateAccess(user);
        validatePluginExists(pluginKey);
        exec.forKey(pluginKey, user, new Operation<UserExtension, String>()
        {
            public String operateOn(UserExtension repo) throws Exception
            {
                extensionOperationManager.sendFeedback(repo, feedback, user);
                return null;
            }
        });
        log.info("Sent feedback for '{}' by user '{}'", pluginKey, user);
    }

    public void reportBroken(final String pluginKey, final Feedback feedback, final String user) throws UnauthorizedAccessException
    {
        validateAccess(user);
        validatePluginExists(pluginKey);
        exec.forKey(pluginKey, user, new Operation<UserExtension, String>()
        {
            public String operateOn(UserExtension repo) throws Exception
            {
                extensionOperationManager.reportBroken(repo, feedback, user);
                return null;
            }
        });
        log.info("Send broken report for '{}' by user '{}'", pluginKey, user);
    }

    public UserPlugins installPlugin(File uploadedFile, String user) throws UnauthorizedAccessException
    {
        return installPlugin(uploadedFile, null, user);
    }

    public UserPlugins installPlugin(final File uploadedFile, final String expectedPluginKey, final String user) throws UnauthorizedAccessException
    {
        validateAuthor(user);
        String installedPluginKey = exec.forKey(expectedPluginKey, user, new Operation<UserExtension, String>()
        {
            public String operateOn(UserExtension ext) throws Exception
            {
                if (ext != null)
                {
                    validateAccessType(ext, "upgrade", ext.isCanEdit(), user);
                }
                return extensionOperationManager.install(ext, uploadedFile, user);
            }
        });

        log.info("Installed extension '{}' by user '{}'", installedPluginKey, user);
        return getRemotePluginList(user, installedPluginKey);
    }

    public UserPlugins createExtension(String pluginKey, PluginType pluginType, String remoteUser, String description, String name) throws UnauthorizedAccessException
    {
        validateAuthor(remoteUser);
        validatePluginDoesNotExist(pluginKey);

        try
        {
            pluginSystemManager.createExtension(pluginType, pluginKey, remoteUser, description, name);
            List<String> modifiedKeys = new ArrayList<String>();
            modifiedKeys.add(pluginKey);
            log.info("Created extension '{}' by user '{}'", pluginKey, remoteUser);
            return getRemotePluginList(remoteUser, modifiedKeys);
        }
        catch (PluginOperationFailedException ex)
        {
            throw ex;
        }
        catch (RuntimeException ex)
        {
            throw new PluginOperationFailedException(ex.getMessage(), ex, pluginKey);
        }
    }

    public SearchResults search(String searchQuery, String remoteUsername)
    {
        // restrict to admins due to very inefficient search implementation
        validateAdmin(remoteUsername);
        return searchManager.search(searchQuery);
    }

    public Settings getSettings(String userName) throws UnauthorizedAccessException
    {
        validateAdmin(userName);
        return settingsManager.getSettings();
    }

    public boolean doesAnyGroupHaveAccess()
    {
        return !settingsManager.getSettings().getAccessGroups().isEmpty();
    }

    public Settings saveSettings(Settings settings, String userName) throws UnauthorizedAccessException
    {
        validateAdmin(userName);

        Settings savedSettings = settingsManager.setSettings(settings);
        log.info("Saved administration settings by user '{}'", userName);
        return savedSettings;
    }

    public boolean canAccessSpeakeasy(String username)
    {
        return permissionManager.canAccessSpeakeasy(username);
    }

    public boolean canAuthorExtensions(String user)
    {
        return permissionManager.canAuthorExtensions(user);
    }

    public String getScreenshotUrl(String pluginKey, String user) throws UnauthorizedAccessException
    {
        validateAccess(user);
        Plugin plugin = getPlugin(pluginKey);
        ModuleDescriptor<?> screenshotDescriptor = plugin.getModuleDescriptor("screenshot");
        if (screenshotDescriptor == null)
        {
            screenshotDescriptor = unknownScreenshotDescriptor;
        }
        return webResourceManager.getStaticPluginResource(screenshotDescriptor, "screenshot.png", UrlMode.ABSOLUTE);
    }

    private void validateAccess(String userName) throws UnauthorizedAccessException
    {
        if (!permissionManager.canAccessSpeakeasy(userName))
        {
            log.warn("Unauthorized Speakeasy access by '" + userName + "'");
            throw new UnauthorizedAccessException(userName, "Cannot access Speakeasy due to lack of permissions");
        }
    }

    private void validateAuthor(String userName) throws UnauthorizedAccessException
    {
        if (!permissionManager.canAuthorExtensions(userName))
        {
            log.warn("Unauthorized Speakeasy author access by '" + userName + "'");
            throw new UnauthorizedAccessException(userName, "Cannot access Speakeasy due to lack of permissions");
        }
    }

    private void validateAccessType(Extension ext, String type, boolean allowed, String user) throws UnauthorizedAccessException
    {
        if (!allowed)
        {
            log.warn("Unauthorized Speakeasy " + type + " access by '" + user + "' for extension '" + ext.getKey() + "'");
            throw new UnauthorizedAccessException(user, "Cannot " + type + " Speakeasy extension '" + ext.getName() + "' due to lack of permissions");
        }
    }

    private void validateAdmin(String userName) throws UnauthorizedAccessException
    {
        if (!userManager.isAdmin(userName))
        {
            log.warn("Unauthorized Speakeasy admin access by '" + userName + "'");
            throw new UnauthorizedAccessException(userName, "Cannot access Speakeasy due to lack of permissions");
        }
    }

    public void validatePluginExists(String pluginKey) throws PluginOperationFailedException
    {
        if (pluginAccessor.getPlugin(pluginKey) == null)
        {
            throw new PluginOperationFailedException("Extension '" + pluginKey + "' doesn't exists", null);
        }
    }

    public void validatePluginDoesNotExist(String pluginKey) throws PluginOperationFailedException
    {
        if (pluginAccessor.getPlugin(pluginKey) != null)
        {
            throw new PluginOperationFailedException("Extension '" + pluginKey + "' already exists", null);
        }
    }

    public boolean canEditPlugin(String name, String remoteUsername)
    {
        try
        {
            return canAuthorExtensions(remoteUsername) && getRemotePlugin(name, remoteUsername).isCanEdit();
        }
        catch (UnauthorizedAccessException e)
        {
            return false;
        }
    }

    private static class AuthorAccessFilter implements Predicate<Extension>
    {
        private final boolean hasAuthorAccess;

        public AuthorAccessFilter(boolean hasAuthorAccess)
        {
            this.hasAuthorAccess = hasAuthorAccess;
        }

        public boolean apply(Extension input)
        {
            return !input.isFork() || hasAuthorAccess;
        }
    }
}
TOP

Related Classes of com.atlassian.labs.speakeasy.SpeakeasyServiceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.