User structural refactoring

6.19.x
Yevhenii Voevodin 2016-06-27 09:24:06 +03:00
parent 5e0aa31691
commit d1aa2cfed7
117 changed files with 5253 additions and 2633 deletions

View File

@ -29,7 +29,7 @@ import org.eclipse.che.api.git.GitUserResolver;
import org.eclipse.che.api.project.server.ProjectApiModule;
import org.eclipse.che.api.ssh.server.HttpSshServiceClient;
import org.eclipse.che.api.ssh.server.SshServiceClient;
import org.eclipse.che.api.user.server.dao.PreferenceDao;
import org.eclipse.che.api.user.server.spi.PreferenceDao;
import org.eclipse.che.commons.lang.Pair;
import org.eclipse.che.everrest.CheAsynchronousJobPool;
import org.eclipse.che.api.git.LocalGitUserResolver;

View File

@ -15,6 +15,7 @@ import com.google.inject.multibindings.Multibinder;
import com.google.inject.name.Names;
import org.eclipse.che.api.machine.shared.Constants;
import org.eclipse.che.api.user.server.ProfileService;
import org.eclipse.che.inject.DynaModule;
import org.everrest.guice.ServiceBindingHelper;
@ -30,7 +31,8 @@ public class WsMasterModule extends AbstractModule {
bind(org.eclipse.che.api.ssh.server.SshService.class);
bind(org.eclipse.che.api.machine.server.recipe.RecipeService.class);
bind(org.eclipse.che.api.user.server.UserService.class);
bind(org.eclipse.che.api.user.server.UserProfileService.class);
bind(org.eclipse.che.api.user.server.ProfileService.class);
bind(org.eclipse.che.api.user.server.PreferencesService.class);
bind(org.eclipse.che.api.workspace.server.stack.StackLoader.class);
bind(org.eclipse.che.api.workspace.server.stack.StackService.class);
bind(org.eclipse.che.api.workspace.server.WorkspaceService.class);

View File

@ -0,0 +1,38 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.model.user;
import java.util.Map;
/**
* Defines the user's profile model.
*
* <p>User's profile describes an additional user information such as his
* job title or company name which is not related to application business logic.
* If it is necessary to manage business logic related attributes then
* user's preferences should be used instead.
*
* @author Yevhenii Voevodin
* @see User
*/
public interface Profile {
/**
* Returns the identifier of the user {@link User#getId()}
* whom this profile belongs to.
*/
String getUserId();
/**
* Returns the user profile attributes (e.g. job title).
*/
Map<String, String> getAttributes();
}

View File

@ -0,0 +1,61 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.core.model.user;
import org.eclipse.che.commons.annotation.Nullable;
import java.util.List;
/**
* Defines the user model.
*
* @author Yevhenii Voevodin
*/
public interface User {
/**
* Returns the identifier of the user (e.g. "user0x124567890").
* The identifier value is unique and mandatory.
*/
String getId();
/**
* Returns the user's email (e.g. user@codenvy.com).
* The email is unique, mandatory and updatable.
*/
String getEmail();
/**
* Returns the user's name (e.g. name_example).
* The name is unique, mandatory and updatable.
*/
String getName();
/**
* Returns the list of the user's aliases, the aliases are the values
* which identify user in the system with third party ids (e.g. if user is registered
* within google oauth the aliases list may contain 'google:user_identifier' alias).
*
* <p>Note that user's {@link #getEmail() email} and {@link #getName() name}
* are not a part of the result, and returned list never contains those values.
* Also note that returned aliases are unique, so there are no two users
* who have the alias in common.
*/
List<String> getAliases();
/**
* Returns the user's password.
* The returned value may be the password placeholder such as 'none' or
* even null, depends on the context.
*/
@Nullable
String getPassword();
}

View File

@ -18,5 +18,6 @@
<source path="machine"/>
<source path="project"/>
<source path="workspace"/>
<source path="user"/>
</module>

View File

@ -21,10 +21,32 @@
<artifactId>che-core-commons-test</artifactId>
<packaging>jar</packaging>
<name>Che Core :: Commons :: Utilities for tests</name>
<properties>
<findbugs.failonerror>true</findbugs.failonerror>
</properties>
<dependencies>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,59 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.commons.test.tck;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
import org.testng.IModuleFactory;
import org.testng.ITestContext;
import java.util.ServiceLoader;
/**
* Abstract class for those Guice {@link Module modules} which provide
* TCK tests components, which will be injected directly into the test class.
*
* <p>The {@link ServiceLoader} mechanism is used for loading such modules
* and for injecting them later. So each module which is TCK module must
* provide the implementations list(as described by {@code ServiceLoader} mechanism)
* in the file named <i>org.eclipse.che.commons.test.tck.TckModule</i> usually under
* <i>test/resources/META-INF/services</i> directory, then the {@link TckModuleFactory}
* will recognise and load it.
*
* @author Yevhenii Voevodin
* @see TckModuleFactory
*/
public abstract class TckModule extends AbstractModule {
/**
* It is guaranteed that this field is always present and
* can be reused by implementation, the value is equal to the
* {@link IModuleFactory#createModule(ITestContext, Class)} first
* parameter and will be set by {@link TckModuleFactory} immediately after module
* implementation is loaded by {@link ServiceLoader}.
*/
private ITestContext testContext;
/** Returns the {@link ITestContext context} of currently executing test suite. */
protected ITestContext getTestContext() {
return testContext;
}
/**
* Sets the context of currently executing test suite.
* This method designed to be used by {@link TckModuleFactory} for setting
* the context before installing modules.
*/
void setTestContext(ITestContext testContext) {
this.testContext = testContext;
}
}

View File

@ -0,0 +1,127 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.commons.test.tck;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
import org.testng.IModuleFactory;
import org.testng.ITestContext;
import java.util.Iterator;
import java.util.ServiceLoader;
import static java.lang.String.format;
/**
* The factory is designed to instantiate {@link TckModule tck modules}
* using {@link ServiceLoader} mechanism. The components
* provided by those modules will be injected into a test class
* whether it's necessary to do so.
*
* <p>The factory expects at least one implementation of {@code TckModule}
* to be configured, if it doesn't find any of the {@code TckModule}
* implementations then it will report an appropriate exception
* and TckTest will fail(as it requires components to be injected into it).
* If it finds more than one {@code TckModule} implementation it will
* use all of the found.
*
* <p>The usage example:
* <pre>
* package org.eclipse.mycomponent;
*
* &#064;org.testng.annotations.Guice(moduleFactory = TckModuleFactory.class)
* // Good practice to define suiteName for TCK tests as it makes easier
* // to implement logic related to certain tests in ITestNGListener implementations
* &#064;org.testng.annotations.Test(suiteName = "MySuite")
* class SubjectTest {
*
* &#064;javax.inject.Inject
* private Component1 component1.
* &#064;javax.inject.Inject
* private Component2 component2;
*
* &#064;org.testng.annotations.Test
* public void test() {
* // use components
* }
* }
*
* class MyTckModule extends TckModule {
* public void configure() {
* bind(Component1.class).to(...);
* bind(Component2.class).toInstance(new Component2(() -> testContext.getAttribute("server_url").toString()));
* }
* }
*
* // Allows to add pre/post test actions like db server start/stop
* class DBServerListener implements ITestListener {
* // ...
* public void onStart(ITestContext context) {
* String url = dbServer.start();
* context.setAttribute("server_url", url)l
* }
*
* public void onFinish(ITestContext context) {
* dbServer.stop();
* }
* // ...
* }
* </pre>
*
* <p>Configuring:
* <pre>
* <i>META-INF/services/org.eclipse.che.commons.test.tck.TckModule</i>
* org.eclipse.mycomponent.MyTckModule
*
* <i>META-INF/services/org.testng.ITestNGListener</i>
* org.eclipse.mycomponent.DBServerListener
* </pre>
*
* @author Yevhenii Voevodin
* @see org.testng.annotations.Guice
* @see IModuleFactory
*/
public class TckModuleFactory implements IModuleFactory {
@Override
public Module createModule(ITestContext context, Class<?> testClass) {
final Iterator<TckModule> moduleIterator = ServiceLoader.load(TckModule.class).iterator();
if (!moduleIterator.hasNext()) {
throw new IllegalStateException(format("Couldn't find a TckModule configuration. " +
"You probably forgot to configure resources/META-INF/services/%s, or even " +
"provide an implementation of the TckModule which is required by the tck test class %s",
TckModule.class.getName(),
testClass.getName()));
}
return new CompoundModule(context, moduleIterator);
}
private static class CompoundModule extends AbstractModule {
private final ITestContext testContext;
private final Iterator<TckModule> moduleIterator;
private CompoundModule(ITestContext testContext, Iterator<TckModule> moduleIterator) {
this.testContext = testContext;
this.moduleIterator = moduleIterator;
}
@Override
protected void configure() {
bind(ITestContext.class).toInstance(testContext);
while (moduleIterator.hasNext()) {
final TckModule module = moduleIterator.next();
module.setTestContext(testContext);
install(module);
}
}
}
}

View File

@ -0,0 +1,51 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.commons.test.tck.repository;
import java.util.Collection;
/**
* The interface which allows to create TCK tests for DAO interfaces
* by providing operations for creating/removing batch of elements.
* The interface is designed to work with entities, which means
* that entity marshaling and unmarshalling to/from db objects must be
* tested by implementation separately.
*
* @param <T>
* the type of the object managed by the repository
* @author Yevhenii Voevodin
*/
public interface TckRepository<T> {
/**
* Creates all the given {@code entities} in the storage.
*
* <p>Note that implementation must fail if it is impossible to
* create any of the given entities.
*
* @param entities
* elements to create
* @throws TckRepositoryException
* when any error occurs during the storing
*/
void createAll(Collection<? extends T> entities) throws TckRepositoryException;
/**
* Clears the storage.
*
* <p>Note that implementation must fail if it is impossible to
* remove all the entities.
*
* @throws TckRepositoryException
* when any error occurs during the clearing
*/
void removeAll() throws TckRepositoryException;
}

View File

@ -0,0 +1,31 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.commons.test.tck.repository;
import java.util.Collection;
/**
* Thrown when any error occurs during {@link TckRepository#createAll(Collection)}
* or {@link TckRepository#removeAll()} invocation. Usually wraps exceptions
* occurred during the storing/removing.
*
* @author Yevhenii Voevodin
*/
public class TckRepositoryException extends Exception {
public TckRepositoryException(String message) {
super(message);
}
public TckRepositoryException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -0,0 +1,50 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.commons.test.tck;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
/**
* Listener representing fake db server url injection for testing "attributes sharing"
* using {@link ITestContext} test suite instance.
*
* @author Yevhenii Voevodin
*/
public class DBServerListener implements ITestListener {
public static final String DB_SERVER_URL_ATTRIBUTE_NAME = "db_server_url";
public static final String DB_SERVER_URL = "localhost:12345";
@Override
public void onStart(ITestContext context) {
context.setAttribute(DB_SERVER_URL_ATTRIBUTE_NAME, DB_SERVER_URL);
}
@Override
public void onFinish(ITestContext context) {}
@Override
public void onTestStart(ITestResult result) {}
@Override
public void onTestSuccess(ITestResult result) {}
@Override
public void onTestFailure(ITestResult result) {}
@Override
public void onTestSkipped(ITestResult result) {}
@Override
public void onTestFailedButWithinSuccessPercentage(ITestResult result) {}
}

View File

@ -0,0 +1,48 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.commons.test.tck;
import org.eclipse.che.commons.test.tck.repository.TckRepository;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import javax.inject.Inject;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
/**
* Tests for {@code org.eclipse.che.commons.test.tck.*} package.
*
* @author Yevhenii Voevodin
*/
@Guice(moduleFactory = TckModuleFactory.class)
public class TckComponentsTest {
@Inject
private TckRepository<Entity> tckRepository;
@Inject
private DBUrlProvider dbUrlProvider;
@Test
public void testComponentsAreInjected() {
assertNotNull(tckRepository, "TckRepository is not injected");
assertNotNull(dbUrlProvider, "DBUrlProvider is not injected");
assertEquals(dbUrlProvider.getUrl(), DBServerListener.DB_SERVER_URL, "Value is set to ITestContext");
}
public interface Entity {}
public interface DBUrlProvider {
String getUrl();
}
}

View File

@ -0,0 +1,36 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.commons.test.tck;
import com.google.inject.TypeLiteral;
import org.eclipse.che.commons.test.tck.TckComponentsTest.Entity;
import org.eclipse.che.commons.test.tck.repository.TckRepository;
import org.eclipse.che.commons.test.tck.repository.TckRepositoryException;
import java.util.Collection;
/**
* @author Yevhenii Voevodin
*/
public class TestModule1 extends TckModule {
@Override
public void configure() {
bind(new TypeLiteral<TckRepository<Entity>>() {}).toInstance(new TckRepository<Entity>() {
@Override
public void createAll(Collection<? extends Entity> entities) throws TckRepositoryException {}
@Override
public void removeAll() throws TckRepositoryException {}
});
}
}

View File

@ -8,25 +8,19 @@
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.shared.model;
package org.eclipse.che.commons.test.tck;
import java.util.List;
import java.util.Map;
import org.eclipse.che.commons.test.tck.TckComponentsTest.DBUrlProvider;
import static org.eclipse.che.commons.test.tck.DBServerListener.DB_SERVER_URL_ATTRIBUTE_NAME;
/**
* @author gazarenkov
* @author Yevhenii Voevodin
*/
public interface Membership {
public class TestModule2 extends TckModule {
String getScope();
List<String> getRoles();
String getUserId();
String getUserName();
String getSubjectId();
Map<String, String> getSubjectProperties();
@Override
public void configure() {
bind(DBUrlProvider.class).toInstance(() -> getTestContext().getAttribute(DB_SERVER_URL_ATTRIBUTE_NAME).toString());
}
}

View File

@ -0,0 +1,2 @@
org.eclipse.che.commons.test.tck.TestModule1
org.eclipse.che.commons.test.tck.TestModule2

View File

@ -0,0 +1 @@
org.eclipse.che.commons.test.tck.DBServerListener

View File

@ -0,0 +1,39 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.api.user;
import org.eclipse.che.api.promises.client.Promise;
import javax.validation.constraints.NotNull;
import java.util.Map;
/**
* GWT client for preferences service;
*
* @author Yevhenii Voevodin
*/
public interface PreferencesServiceClient {
/**
* Updates user's preferences using the merge strategy.
*
* @param prefsToUpdate
* preferences update
* @return a promise that resolves all the user's preferences, or rejects with an error
*/
Promise<Map<String, String>> updatePreferences(@NotNull Map<String, String> prefsToUpdate);
/**
* Gets user preferences.
*
* @return a promise that resolves preferences, or rejects with an error
*/
Promise<Map<String, String>> getPreferences();
}

View File

@ -0,0 +1,67 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.api.user;
import com.google.inject.Inject;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.ide.json.JsonHelper;
import org.eclipse.che.ide.rest.AsyncRequestFactory;
import org.eclipse.che.ide.rest.RestContext;
import org.eclipse.che.ide.rest.StringMapUnmarshaller;
import org.eclipse.che.ide.ui.loaders.request.LoaderFactory;
import java.util.Map;
import static org.eclipse.che.ide.MimeType.APPLICATION_JSON;
import static org.eclipse.che.ide.rest.HTTPHeader.ACCEPT;
import static org.eclipse.che.ide.rest.HTTPHeader.CONTENT_TYPE;
/**
* Default implementation of {@link PreferencesServiceClient}.
*
* @author Yevhenii Voevodin
*/
public class PreferencesServiceClientImpl implements PreferencesServiceClient {
private final String PREFERENCES_PATH;
private final LoaderFactory loaderFactory;
private final AsyncRequestFactory asyncRequestFactory;
@Inject
protected PreferencesServiceClientImpl(@RestContext String restContext,
LoaderFactory loaderFactory,
AsyncRequestFactory asyncRequestFactory) {
this.loaderFactory = loaderFactory;
this.asyncRequestFactory = asyncRequestFactory;
PREFERENCES_PATH = restContext + "/preferences";
}
@Override
public Promise<Map<String, String>> getPreferences() {
return asyncRequestFactory.createGetRequest(PREFERENCES_PATH)
.header(ACCEPT, APPLICATION_JSON)
.header(CONTENT_TYPE, APPLICATION_JSON)
.loader(loaderFactory.newLoader("Getting user's preferences..."))
.send(new StringMapUnmarshaller());
}
@Override
public Promise<Map<String, String>> updatePreferences(Map<String, String> update) {
final String data = JsonHelper.toJson(update);
return asyncRequestFactory.createPutRequest(PREFERENCES_PATH, null)
.header(ACCEPT, APPLICATION_JSON)
.header(CONTENT_TYPE, APPLICATION_JSON)
.data(data)
.loader(loaderFactory.newLoader("Updating user's preferences..."))
.send(new StringMapUnmarshaller());
}
}

View File

@ -20,9 +20,9 @@ export class AddRegistryController {
* Default constructor.
* @ngInject for Dependency injection
*/
constructor($mdDialog, cheProfile, cheNotification) {
constructor($mdDialog, chePreferences, cheNotification) {
this.$mdDialog = $mdDialog;
this.cheProfile = cheProfile;
this.chePreferences = chePreferences;
this.cheNotification = cheNotification;
}
@ -41,7 +41,7 @@ export class AddRegistryController {
return;
}
let promise = this.cheProfile.addRegistry(this.registryUrl, this.registryUserName, this.registryUserPassword);
let promise = this.chePreferences.addRegistry(this.registryUrl, this.registryUserName, this.registryUserPassword);
promise.then(() => {
this.$mdDialog.hide();

View File

@ -22,16 +22,16 @@ export class DockerRegistryListController {
* Default constructor that is using resource
* @ngInject for Dependency injection
*/
constructor($mdDialog, $document, cheProfile, cheNotification) {
constructor($mdDialog, $document, chePreferences, cheNotification) {
this.$mdDialog = $mdDialog;
this.$document = $document;
this.cheProfile = cheProfile;
this.chePreferences = chePreferences;
this.cheNotification = cheNotification;
this.registries = cheProfile.getRegistries();
this.registries = chePreferences.getRegistries();
this.isLoading = true;
let promise = cheProfile.fetchPreferences();
let promise = chePreferences.fetchPreferences();
promise.then(() => {
this.isLoading = false;
}, (error) => {
@ -91,7 +91,7 @@ export class DockerRegistryListController {
.targetEvent(event);
this.$mdDialog.show(confirm).then(() => {
this.isLoading = true;
let promise = this.cheProfile.removeRegistry(registry.url);
let promise = this.chePreferences.removeRegistry(registry.url);
promise.then(() => {
this.isLoading = false;
}, (error) => {

View File

@ -40,13 +40,13 @@ let initModule = angular.module('userDashboard', ['ngAnimate', 'ngCookies', 'ngT
initModule.config(['$routeProvider', ($routeProvider) => {
$routeProvider.accessWhen = (path, route) => {
route.resolve || (route.resolve = {});
route.resolve.app = ['cheBranding', '$q', 'cheProfile', (cheBranding, $q, cheProfile) => {
route.resolve.app = ['cheBranding', '$q', 'chePreferences', (cheBranding, $q, chePreferences) => {
var deferred = $q.defer();
let profilePreferences = cheProfile.getPreferences();
if (profilePreferences && profilePreferences.$resolved) {
let preferences = chePreferences.getPreferences();
if (preferences && preferences.$resolved) {
deferred.resolve();
} else {
profilePreferences.$promise.then(() => {
preferences.$promise.then(() => {
deferred.resolve();
}, (error) => {
deferred.reject(error);
@ -61,13 +61,13 @@ initModule.config(['$routeProvider', ($routeProvider) => {
$routeProvider.accessOtherWise = (route) => {
route.resolve || (route.resolve = {});
route.resolve.app = ['$q', 'cheProfile', ($q, cheProfile) => {
route.resolve.app = ['$q', 'chePreferences', ($q, chePreferences) => {
var deferred = $q.defer();
let profilePreferences = cheProfile.getPreferences();
if (profilePreferences && profilePreferences.$resolved) {
let preferences = chePreferences.getPreferences();
if (preferences && preferences.$resolved) {
deferred.resolve();
} else {
profilePreferences.$promise.then(() => {
preferences.$promise.then(() => {
deferred.resolve();
}, (error) => {
deferred.reject(error);

View File

@ -26,11 +26,11 @@ export class CheNavBarCtrl {
this.links = [{href: '#/create-workspace', name: 'New Workspace'}];
this.profile = cheAPI.getProfile().getProfile();
if (this.profile.attributes) {
this.email = this.profile.attributes.email;
if (this.profile.email) {
this.email = this.profile.email;
} else {
this.profile.$promise.then(() => {
this.email = this.profile.attributes.email ? this.profile.attributes.email : 'N/A ';
this.email = this.profile.email ? this.profile.email : 'N/A ';
}, () => {
this.email = 'N/A ';
});

View File

@ -49,9 +49,9 @@ export class ListProjectsCtrl {
}
});
let profilePreferences = cheAPI.getProfile().getPreferences();
let preferences = cheAPI.getPreferences().getPreferences();
this.profileCreationDate = profilePreferences['che:created'];
this.profileCreationDate = preferences['che:created'];
this.menuOptions = [
{

View File

@ -28,9 +28,9 @@ export class WorkspaceDetailsProjectsCtrl {
this.namespace = $route.current.params.namespace;
this.workspaceName = $route.current.params.workspaceName;
let profilePreferences = cheAPI.getProfile().getPreferences();
let preferences = cheAPI.getPreferences().getPreferences();
this.profileCreationDate = profilePreferences['che:created'];
this.profileCreationDate = preferences['che:created'];
if (!this.cheWorkspace.getWorkspacesById().get(this.workspaceId)) {
let promise = this.cheWorkspace.fetchWorkspaceDetails(this.workspaceId);

View File

@ -32,7 +32,8 @@ export class CheProfileBuilder {
* @returns {CheProfileBuilder}
*/
withEmail(email) {
return this.withAttribute('email', email);
this.profile.email = email;
return this;
}
/**

View File

@ -18,6 +18,7 @@ import {CheRecipeTemplate} from './che-recipe-template.factory';
import {CheStack} from './che-stack.factory';
import {CheWebsocket} from './che-websocket.factory';
import {CheProfile} from './che-profile.factory';
import {ChePreferences} from './che-preferences.factory';
import {CheService} from './che-service.factory';
import {CheSvn} from './che-svn.factory';
import {CheHttpBackend} from './test/che-http-backend';
@ -35,6 +36,7 @@ export class ApiConfig {
register.factory('cheWorkspace', CheWorkspace);
register.factory('cheProjectTemplate', CheProjectTemplate);
register.factory('cheProfile', CheProfile);
register.factory('chePreferences', ChePreferences);
register.factory('cheWebsocket', CheWebsocket);
register.factory('cheRecipe', CheRecipe);
register.factory('cheRecipeTemplate', CheRecipeTemplate);

View File

@ -22,10 +22,11 @@ export class CheAPI {
* Default constructor that is using resource
* @ngInject for Dependency injection
*/
constructor(cheWorkspace, cheProfile, cheProjectTemplate, cheWebsocket, cheSvn, cheService,
constructor(cheWorkspace, cheProfile, chePreferences, cheProjectTemplate, cheWebsocket, cheSvn, cheService,
cheAdminPlugins, cheAdminService, cheRecipe, cheRecipeTemplate, cheStack, cheOAuthProvider) {
this.cheWorkspace = cheWorkspace;
this.cheProfile = cheProfile;
this.chePreferences = chePreferences;
this.cheProjectTemplate = cheProjectTemplate;
this.cheWebsocket = cheWebsocket;
this.cheSvn = cheSvn;
@ -63,6 +64,14 @@ export class CheAPI {
return this.cheProfile;
}
/**
* The Che Preferences API
* @returns {ChePreferences|*}
*/
getPreferences() {
return this.chePreferences;
}
/**
* The Che Project Template API
* @returns {CheProjectTemplate|*}

View File

@ -0,0 +1,190 @@
/*
* Copyright (c) 2015-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*/
'use strict';
/**
* This class is handling the preferences API retrieval
* @author Yevhenii Voevodin
*/
export class ChePreferences {
/**
* Default constructor that is using resource
* @ngInject for Dependency injection
*/
constructor($resource, $http, $window) {
this.$window = $window;
// keep resource
this.$resource = $resource;
// http is used for sending data with DELETE method (angular is not sending any data by default with DELETE)
this.$http = $http;
// remote call
this.remotePreferencesAPI = this.$resource('/api/preferences', {}, {
getPreferences: {method: 'GET', url: '/api/preferences'},
updatePreferences: {method: 'POST', url: '/api/preferences'}
});
// fetch the preferences when we're initialized
this.fetchPreferences();
//registry array
this.registries = [];
}
/**
* Gets the preferences
* @return preferences
*/
getPreferences() {
return this.preferences;
}
/**
* Update the preferences
* @param properties
*/
updatePreferences(properties) {
angular.extend(this.preferences, properties);
return this.preferences.$save();
}
/**
* Remove preferences properties
* @param properties (list of keys)
*/
removePreferences(properties) {
// delete method doesn't send body when it is defined in $resources
// that's why direct $http call is used.
this.$http({
url: '/api/preferences',
method: 'DELETE',
headers: {'Content-Type': 'application/json;charset=utf-8'},
data: properties}).then(resp => {
this.fetchPreferences();
})
}
/**
* Gets the preferences data
*/
fetchPreferences() {
let preferences = this.remotePreferencesAPI.getPreferences();
// if we don't yet have data
if (!this.preferences) {
// set preferences for using promise in controllers during first request
this.preferences = preferences;
}
let preferencesPromise = this.preferences.$promise;
preferencesPromise.then((preferences) => {
// update preferences data if we have new value
this.preferences = preferences;
});
return preferencesPromise;
}
/**
* Gets the registries
* @return registries
*/
getRegistries() {
return this.registries;
}
/**
* Add a registry
* @param registryUrl
* @param userName
* @param userEmail
* @param userPassword
* @returns {*} the promise
*/
addRegistry(registryUrl, userName, userPassword) {
let credentials = {};
credentials[registryUrl] = {
username: userName,
password: userPassword
};
if (this.preferences.dockerCredentials) {
let remoteCredentialsJson = this.$window.atob(this.preferences.dockerCredentials);
let remoteCredentials = angular.fromJson(remoteCredentialsJson);
if (remoteCredentials[registryUrl]) {
delete remoteCredentials[registryUrl];
}
angular.extend(credentials, remoteCredentials);
}
let credentialsBase64 = this.$window.btoa(angular.toJson(credentials));
let preferences = {dockerCredentials: credentialsBase64};
let promise = this.updatePreferences(preferences);
promise.then((preferences) => {
this.preferences = preferences;
this._updateRegistries(preferences);
});
return promise;
}
/**
* Remove the registry by its URL
* @param registryUrl
* @returns {*} the promise
*/
removeRegistry(registryUrl) {
let credentialsJson = this.$window.atob(this.preferences.dockerCredentials);
let credentials = angular.fromJson(credentialsJson);
delete credentials[registryUrl];
let credentialsBase64 = this.$window.btoa(angular.toJson(credentials));
let preferences = {dockerCredentials: credentialsBase64};
let promise = this.updatePreferences(preferences);
promise.then((preferences) => {
this.preferences = preferences;
this._updateRegistries(preferences);
});
return promise;
}
/**
* Update registry array from preferences
* @param preferences
*/
_updateRegistries(preferences) {
this.registries.length = 0;
if (preferences.dockerCredentials) {
let credentialsJson = this.$window.atob(preferences.dockerCredentials);
let credentials = angular.fromJson(credentialsJson);
for (var key in credentials) {
let credential = {
url: key,
username: credentials[key].username,
password: credentials[key].password
};
this.registries.push(credential);
}
}
}
}

View File

@ -0,0 +1,137 @@
/*
* Copyright (c) 2015-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*/
'use strict';
/**
* Test of the ChePreferences
*/
describe('ChePreferences', function () {
/**
* Preferences Factory for the test
*/
var factory;
/**
* API builder.
*/
var apiBuilder;
/**
* Backend for handling http operations
*/
var httpBackend;
/**
* che backend
*/
var cheBackend;
/**
* setup module
*/
beforeEach(angular.mock.module('userDashboard'));
/**
* Inject factory and http backend
*/
beforeEach(inject(function (chePreferences, cheAPIBuilder, cheHttpBackend) {
factory = chePreferences;
apiBuilder = cheAPIBuilder;
cheBackend = cheHttpBackend;
httpBackend = cheHttpBackend.getHttpBackend();
}));
/**
* Check assertion after the test
*/
afterEach(function () {
httpBackend.verifyNoOutstandingExpectation();
httpBackend.verifyNoOutstandingRequest();
});
/**
* Check that we're able to fetch preferences
*/
it('Fetch preferences', function () {
// providing request
// add default preferences on Http backend
let defaultPreferences = { pref1 : "value1", pref2 : "value2"};
cheBackend.addDefaultPreferences(defaultPreferences);
// setup backend
cheBackend.setup();
// fetch preferences
factory.fetchPreferences();
// expecting GETs
httpBackend.expectGET('/api/preferences');
// flush command
httpBackend.flush();
// now, check preferences
let preferences = factory.getPreferences();
expect(preferences["pref1"]).toEqual("value1");
expect(preferences["pref2"]).toEqual("value2");
}
);
/**
* Check that we're able to update preferences
*/
it('Update preferences', function () {
let defaultPreferences = { pref1 : "value1" };
// setup backend
cheBackend.setup();
cheBackend.setPreferences(defaultPreferences);
// fetch preferences
factory.updatePreferences(defaultPreferences);
// expecting POST
httpBackend.expectPOST('/api/preferences');
// flush command
httpBackend.flush();
// now, check preferences
let preferences = factory.getPreferences();
expect(preferences["pref1"]).toEqual("value1");
}
);
/**
* Check that we're able to delete preferences
*/
it('Remove preferences', function () {
let defaultPreferences = { pref1 : "value1", pref2 : "value2" };
cheBackend.addDefaultPreferences(defaultPreferences);
// setup backend
cheBackend.setup();
// r
factory.removePreferences(["pref1"]);
// expecting POST
httpBackend.expectDELETE('/api/preferences');
// flush command
httpBackend.flush();
}
);
});

View File

@ -21,9 +21,8 @@ export class CheProfile {
* Default constructor that is using resource
* @ngInject for Dependency injection
*/
constructor($resource, $http, $window) {
constructor($resource, $http) {
this.$resource = $resource;
this.$window = $window;
// http is used for sending data with DELETE method (angular is not sending any data by default with DELETE)
this.$http = $http;
@ -31,22 +30,13 @@ export class CheProfile {
// remote call
this.remoteProfileAPI = this.$resource('/api/profile', {}, {
getById: {method: 'GET', url: '/api/profile/:userId'},
setAttributes: {method: 'POST', url: '/api/profile'}
setAttributes: {method: 'PUT', url: '/api/profile/attributes'}
});
// remote call for preferences
this.remoteProfilePreferencesAPI = this.$resource('/api/profile/prefs');
this.profileIdMap = new Map();
// fetch the profile when we're initialized
this.fetchProfile();
// fetch the profilePreferences when we're initialized
this.fetchPreferences();
//registry array
this.registries = [];
}
@ -58,129 +48,6 @@ export class CheProfile {
return this.profile;
}
/**
* Gets the preferences
* @return preferences
*/
getPreferences() {
return this.profilePreferences;
}
/**
* Update the preferences
* @param properties
* @returns {*} the promise
*/
updatePreferences(properties) {
angular.extend(this.profilePreferences, properties);
return this.profilePreferences.$save();
}
/**
* Gets the registries
* @return registries
*/
getRegistries() {
return this.registries;
}
/**
* Add a registry
* @param registryUrl
* @param userName
* @param userEmail
* @param userPassword
* @returns {*} the promise
*/
addRegistry(registryUrl, userName, userPassword) {
let credentials = {};
credentials[registryUrl] = {
username: userName,
password: userPassword
};
if (this.profilePreferences.dockerCredentials) {
let remoteCredentialsJson = this.$window.atob(this.profilePreferences.dockerCredentials);
let remoteCredentials = angular.fromJson(remoteCredentialsJson);
if (remoteCredentials[registryUrl]) {
delete remoteCredentials[registryUrl];
}
angular.extend(credentials, remoteCredentials);
}
let credentialsBase64 = this.$window.btoa(angular.toJson(credentials));
let preferences = {dockerCredentials: credentialsBase64};
let promise = this.updatePreferences(preferences);
promise.then((profilePreferences) => {
this.profilePreferences = profilePreferences;
this._updateRegistries(profilePreferences);
});
return promise;
}
/**
* Remove the registry by its URL
* @param registryUrl
* @returns {*} the promise
*/
removeRegistry(registryUrl) {
let credentialsJson = this.$window.atob(this.profilePreferences.dockerCredentials);
let credentials = angular.fromJson(credentialsJson);
delete credentials[registryUrl];
let credentialsBase64 = this.$window.btoa(angular.toJson(credentials));
let preferences = {dockerCredentials: credentialsBase64};
let promise = this.updatePreferences(preferences);
promise.then((profilePreferences) => {
this.profilePreferences = profilePreferences;
this._updateRegistries(profilePreferences);
});
return promise;
}
/**
* Update registry array from profile preferences
* @param profilePreferences
*/
_updateRegistries(profilePreferences) {
this.registries.length = 0;
if (profilePreferences.dockerCredentials) {
let credentialsJson = this.$window.atob(profilePreferences.dockerCredentials);
let credentials = angular.fromJson(credentialsJson);
for (var key in credentials) {
let credential = {
url: key,
username: credentials[key].username,
password: credentials[key].password
};
this.registries.push(credential);
}
}
}
/**
* Remove preferences properties
* @param properties (list of keys)
*/
removePreferences(properties) {
this.$http({
url: '/api/profile/prefs',
method: 'DELETE',
headers: {'Content-Type': 'application/json;charset=utf-8'},
data: properties
});
this.fetchPreferences();
}
/**
* Gets the full name if it possible
* @returns {string} full name
@ -223,28 +90,6 @@ export class CheProfile {
return profilePromise;
}
/**
* Gets the preferences data
*/
fetchPreferences() {
let profilePreferences = this.remoteProfilePreferencesAPI.get();
// if we don't yet have data
if (!this.profilePreferences) {
// set profilePreferences for using promise in controllers during first request
this.profilePreferences = profilePreferences;
}
let profilePrefsPromise = this.profilePreferences.$promise;
profilePrefsPromise.then((profilePreferences) => {
// update profilePreferences data if we have new value
this.profilePreferences = profilePreferences;
this._updateRegistries(profilePreferences);
});
return profilePrefsPromise;
}
/**
* Set the profile attributes data
* @param attributes

View File

@ -82,8 +82,6 @@ describe('CheProfile', function () {
// expecting GETs
httpBackend.expectGET('/api/profile');
httpBackend.expectGET('/api/profile/prefs');
// flush command
httpBackend.flush();
@ -92,7 +90,7 @@ describe('CheProfile', function () {
// check id, email, firstName and lastName in profile attributes
expect(profile.id).toEqual(profileId);
expect(profile.attributes.email).toEqual(email);
expect(profile.email).toEqual(email);
expect(profile.attributes.firstName).toEqual(firstName);
expect(profile.attributes.lastName).toEqual(lastName);
}
@ -112,8 +110,8 @@ describe('CheProfile', function () {
// fetch profile
factory.setAttributes(testAttributes);
// expecting a POST
httpBackend.expectPOST('/api/profile');
// expecting a PUT
httpBackend.expectPUT('/api/profile/attributes');
// flush command
httpBackend.flush();

View File

@ -61,12 +61,15 @@ export class CheHttpBackend {
//profiles
this.httpBackend.when('GET', '/api/profile').respond(this.defaultProfile);
this.httpBackend.when('GET', '/api/profile/prefs').respond(this.defaultProfilePrefs);
var profileKeys = this.profilesMap.keys();
for (let key of profileKeys) {
this.httpBackend.when('GET', '/api/profile/' + key).respond(this.profilesMap.get(key));
}
//preferences
this.httpBackend.when('GET', '/api/preferences').respond(this.defaultPreferences);
this.httpBackend.when('DELETE', '/api/preferences').respond();
/// project details
var projectDetailsKeys = this.projectDetailsMap.keys();
for (let projectKey of projectDetailsKeys) {
@ -177,6 +180,23 @@ export class CheHttpBackend {
this.defaultProfile = profile;
}
/**
* Add the given preferences
* @param preferences
*/
addDefaultPreferences(preferences) {
this.defaultPreferences = preferences;
}
/**
* Add the given preferences
* @param preferences
*/
setPreferences(preferences) {
this.httpBackend.when('POST', '/api/preferences').respond(preferences);
this.defaultPreferences = preferences;
}
/**
* Add the given profile
* @param profile
@ -191,7 +211,7 @@ export class CheHttpBackend {
* @param attributes
*/
setAttributes(attributes) {
this.httpBackend.when('POST', '/api/profile').respond(attributes);
this.httpBackend.when('PUT', '/api/profile/attributes').respond(attributes);
this.defaultProfile.attributes = attributes;
}
@ -312,4 +332,3 @@ export class CheHttpBackend {
}
}

View File

@ -23,18 +23,18 @@ export class CheLearnMoreCtrl {
* Default constructor that is using resource
* @ngInject for Dependency injection
*/
constructor($scope, $element, $attrs, $compile, cheProfile) {
constructor($scope, $element, $attrs, $compile, chePreferences) {
this.items = [];
this.WIDGET_PREFERENCES_PREFIX = 'learn-widget-';
this.cheProfile = cheProfile;
this.chePreferences = chePreferences;
// current index is first one
this.currentIndex = 0;
let preferences = this.cheProfile.getPreferences();
let preferences = this.chePreferences.getPreferences();
let promise = preferences.$promise;
promise.then(() => {
@ -87,7 +87,7 @@ export class CheLearnMoreCtrl {
let checkKey = this.WIDGET_PREFERENCES_PREFIX + key;
var properties = {};
properties[checkKey] = value;
this.cheProfile.updatePreferences(properties);
this.chePreferences.updatePreferences(properties);
// also update icon state
this.stateIcons[key] = value;
@ -104,7 +104,7 @@ export class CheLearnMoreCtrl {
// check if key is stored in preferences
// if there,
if (key) {
let preferences = this.cheProfile.getPreferences();
let preferences = this.chePreferences.getPreferences();
let promise = preferences.$promise;
promise.then(() => {

View File

@ -10,7 +10,8 @@
*******************************************************************************/
package org.eclipse.che.ide.api.app;
import org.eclipse.che.api.user.shared.dto.ProfileDescriptor;
import org.eclipse.che.api.user.shared.dto.ProfileDto;
import com.google.inject.Singleton;
import java.util.Map;
@ -22,17 +23,17 @@ import java.util.Map;
@Singleton
public class CurrentUser {
private ProfileDescriptor profileDescriptor;
private ProfileDto profileDescriptor;
private Map<String, String> preferences;
public CurrentUser() {
}
public CurrentUser(ProfileDescriptor profileDescriptor) {
public CurrentUser(ProfileDto profileDescriptor) {
this(profileDescriptor, null);
}
public CurrentUser(ProfileDescriptor profileDescriptor, Map<String, String> preferences) {
public CurrentUser(ProfileDto profileDescriptor, Map<String, String> preferences) {
this.profileDescriptor = profileDescriptor;
this.preferences = preferences;
}
@ -42,11 +43,11 @@ public class CurrentUser {
*
* @return
*/
public ProfileDescriptor getProfile() {
public ProfileDto getProfile() {
return profileDescriptor;
}
public void setProfile(ProfileDescriptor profileDescriptor) {
public void setProfile(ProfileDto profileDescriptor) {
this.profileDescriptor = profileDescriptor;
}

View File

@ -0,0 +1,39 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.api.user;
import org.eclipse.che.api.promises.client.Promise;
import javax.validation.constraints.NotNull;
import java.util.Map;
/**
* GWT client for preferences service;
*
* @author Yevhenii Voevodin
*/
public interface PreferencesServiceClient {
/**
* Updates user's preferences using the merge strategy.
*
* @param prefsToUpdate
* preferences update
* @return a promise that resolves all the user's preferences, or rejects with an error
*/
Promise<Map<String, String>> updatePreferences(@NotNull Map<String, String> prefsToUpdate);
/**
* Gets user preferences.
*
* @return a promise that resolves preferences, or rejects with an error
*/
Promise<Map<String, String>> getPreferences();
}

View File

@ -0,0 +1,67 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.api.user;
import com.google.inject.Inject;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.ide.json.JsonHelper;
import org.eclipse.che.ide.rest.AsyncRequestFactory;
import org.eclipse.che.ide.rest.RestContext;
import org.eclipse.che.ide.rest.StringMapUnmarshaller;
import org.eclipse.che.ide.ui.loaders.request.LoaderFactory;
import java.util.Map;
import static org.eclipse.che.ide.MimeType.APPLICATION_JSON;
import static org.eclipse.che.ide.rest.HTTPHeader.ACCEPT;
import static org.eclipse.che.ide.rest.HTTPHeader.CONTENT_TYPE;
/**
* Default implementation of {@link PreferencesServiceClient}.
*
* @author Yevhenii Voevodin
*/
public class PreferencesServiceClientImpl implements PreferencesServiceClient {
private final String PREFERENCES_PATH;
private final LoaderFactory loaderFactory;
private final AsyncRequestFactory asyncRequestFactory;
@Inject
protected PreferencesServiceClientImpl(@RestContext String restContext,
LoaderFactory loaderFactory,
AsyncRequestFactory asyncRequestFactory) {
this.loaderFactory = loaderFactory;
this.asyncRequestFactory = asyncRequestFactory;
PREFERENCES_PATH = restContext + "/preferences";
}
@Override
public Promise<Map<String, String>> getPreferences() {
return asyncRequestFactory.createGetRequest(PREFERENCES_PATH)
.header(ACCEPT, APPLICATION_JSON)
.header(CONTENT_TYPE, APPLICATION_JSON)
.loader(loaderFactory.newLoader("Getting user's preferences..."))
.send(new StringMapUnmarshaller());
}
@Override
public Promise<Map<String, String>> updatePreferences(Map<String, String> update) {
final String data = JsonHelper.toJson(update);
return asyncRequestFactory.createPutRequest(PREFERENCES_PATH, null)
.header(ACCEPT, APPLICATION_JSON)
.header(CONTENT_TYPE, APPLICATION_JSON)
.data(data)
.loader(loaderFactory.newLoader("Updating user's preferences..."))
.send(new StringMapUnmarshaller());
}
}

View File

@ -10,8 +10,7 @@
*******************************************************************************/
package org.eclipse.che.ide.api.user;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.user.shared.dto.ProfileDescriptor;
import org.eclipse.che.api.user.shared.dto.ProfileDto;
import org.eclipse.che.ide.rest.AsyncRequestCallback;
import javax.validation.constraints.NotNull;
@ -29,7 +28,7 @@ public interface UserProfileServiceClient {
*
* @param callback
*/
void getCurrentProfile(AsyncRequestCallback<ProfileDescriptor> callback);
void getCurrentProfile(AsyncRequestCallback<ProfileDto> callback);
/**
* Update current user's profile.
@ -38,7 +37,7 @@ public interface UserProfileServiceClient {
* attributes to update
* @param callback
*/
void updateCurrentProfile(@NotNull Map<String, String> updates, AsyncRequestCallback<ProfileDescriptor> callback);
void updateCurrentProfile(@NotNull Map<String, String> updates, AsyncRequestCallback<ProfileDto> callback);
/**
* Get profile by id.
@ -47,26 +46,8 @@ public interface UserProfileServiceClient {
* profile's id
* @param callback
*/
void getProfileById(@NotNull String id, AsyncRequestCallback<ProfileDescriptor> callback);
void getProfileById(@NotNull String id, AsyncRequestCallback<ProfileDto> callback);
/**
* Get user preferences
*
* @param callback
* which contains some action with user preferences
* @deprecated use {@link #getPreferences()}
*/
@Deprecated
void getPreferences(AsyncRequestCallback<Map<String, String>> callback);
/**
* Get user preferences
*
* @return the promise which either uses preferences for some actions or rejects with an error
*/
Promise<Map<String, String>> getPreferences();
/**
/**
* Update profile.
@ -77,25 +58,5 @@ public interface UserProfileServiceClient {
* attributes to update
* @param callback
*/
void updateProfile(@NotNull String id, Map<String, String> updates, AsyncRequestCallback<ProfileDescriptor> callback);
/**
* Update preferences.
*
* @param prefsToUpdate
* preferences to update
* @param callback
* which contains some action with user preferences
* @deprecated use {@link #updatePreferences(Map)}
*/
@Deprecated
void updatePreferences(@NotNull Map<String, String> prefsToUpdate, AsyncRequestCallback<Map<String, String>> callback);
/**
* Update preferences.
*
* @param prefsToUpdate
* @return promise which either uses preferences for some actions or rejects with an error
*/
Promise<Map<String, String>> updatePreferences(@NotNull Map<String, String> prefsToUpdate);
void updateProfile(@NotNull String id, Map<String, String> updates, AsyncRequestCallback<ProfileDto> callback);
}

View File

@ -13,7 +13,7 @@ package org.eclipse.che.ide.api.user;
import com.google.inject.Inject;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.user.shared.dto.ProfileDescriptor;
import org.eclipse.che.api.user.shared.dto.ProfileDto;
import org.eclipse.che.ide.json.JsonHelper;
import org.eclipse.che.ide.rest.AsyncRequestCallback;
import org.eclipse.che.ide.rest.AsyncRequestFactory;
@ -35,7 +35,6 @@ import static org.eclipse.che.ide.rest.HTTPHeader.CONTENT_TYPE;
*/
public class UserProfileServiceClientImpl implements UserProfileServiceClient {
private final String PROFILE;
private final String PREFS;
private final LoaderFactory loaderFactory;
private final AsyncRequestFactory asyncRequestFactory;
@ -46,12 +45,11 @@ public class UserProfileServiceClientImpl implements UserProfileServiceClient {
this.loaderFactory = loaderFactory;
this.asyncRequestFactory = asyncRequestFactory;
PROFILE = restContext + "/profile/";
PREFS = PROFILE + "prefs";
}
/** {@inheritDoc} */
@Override
public void getCurrentProfile(AsyncRequestCallback<ProfileDescriptor> callback) {
public void getCurrentProfile(AsyncRequestCallback<ProfileDto> callback) {
asyncRequestFactory.createGetRequest(PROFILE)
.header(ACCEPT, APPLICATION_JSON)
.loader(loaderFactory.newLoader("Retrieving current user's profile..."))
@ -60,7 +58,7 @@ public class UserProfileServiceClientImpl implements UserProfileServiceClient {
/** {@inheritDoc} */
@Override
public void updateCurrentProfile(@NotNull Map<String, String> updates, AsyncRequestCallback<ProfileDescriptor> callback) {
public void updateCurrentProfile(@NotNull Map<String, String> updates, AsyncRequestCallback<ProfileDto> callback) {
asyncRequestFactory.createPostRequest(PROFILE, null)
.header(ACCEPT, APPLICATION_JSON)
.header(CONTENT_TYPE, APPLICATION_JSON)
@ -71,7 +69,7 @@ public class UserProfileServiceClientImpl implements UserProfileServiceClient {
/** {@inheritDoc} */
@Override
public void getProfileById(@NotNull String id, AsyncRequestCallback<ProfileDescriptor> callback) {
public void getProfileById(@NotNull String id, AsyncRequestCallback<ProfileDto> callback) {
String requestUrl = PROFILE + id;
asyncRequestFactory.createGetRequest(requestUrl)
@ -80,27 +78,9 @@ public class UserProfileServiceClientImpl implements UserProfileServiceClient {
.send(callback);
}
@Override
public void getPreferences(AsyncRequestCallback<Map<String, String>> callback) {
asyncRequestFactory.createGetRequest(PREFS)
.header(ACCEPT, APPLICATION_JSON)
.header(CONTENT_TYPE, APPLICATION_JSON)
.loader(loaderFactory.newLoader("Getting user's preferences..."))
.send(callback);
}
@Override
public Promise<Map<String, String>> getPreferences() {
return asyncRequestFactory.createGetRequest(PREFS)
.header(ACCEPT, APPLICATION_JSON)
.header(CONTENT_TYPE, APPLICATION_JSON)
.loader(loaderFactory.newLoader("Getting user's preferences..."))
.send(new StringMapUnmarshaller());
}
/** {@inheritDoc} */
@Override
public void updateProfile(@NotNull String id, Map<String, String> updates, AsyncRequestCallback<ProfileDescriptor> callback) {
public void updateProfile(@NotNull String id, Map<String, String> updates, AsyncRequestCallback<ProfileDto> callback) {
String requestUrl = PROFILE + id;
asyncRequestFactory.createPostRequest(requestUrl, null)
@ -110,28 +90,4 @@ public class UserProfileServiceClientImpl implements UserProfileServiceClient {
.loader(loaderFactory.newLoader("Updating user's profile..."))
.send(callback);
}
/** {@inheritDoc} */
@Override
public void updatePreferences(@NotNull Map<String, String> update, AsyncRequestCallback<Map<String, String>> callback) {
final String data = JsonHelper.toJson(update);
asyncRequestFactory.createPostRequest(PREFS, null)
.header(ACCEPT, APPLICATION_JSON)
.header(CONTENT_TYPE, APPLICATION_JSON)
.data(data)
.loader(loaderFactory.newLoader("Updating user's preferences..."))
.send(callback);
}
/** {@inheritDoc} */
@Override
public Promise<Map<String, String>> updatePreferences(@NotNull Map<String, String> update) {
final String data = JsonHelper.toJson(update);
return asyncRequestFactory.createPostRequest(PREFS, null)
.header(ACCEPT, APPLICATION_JSON)
.header(CONTENT_TYPE, APPLICATION_JSON)
.data(data)
.loader(loaderFactory.newLoader("Updating user's preferences..."))
.send(new StringMapUnmarshaller());
}
}

View File

@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.che.ide.api.user;
import org.eclipse.che.api.user.shared.dto.UserDescriptor;
import org.eclipse.che.api.user.shared.dto.UserDto;
import org.eclipse.che.ide.rest.AsyncRequestCallback;
import javax.validation.constraints.NotNull;
@ -31,14 +31,14 @@ public interface UserServiceClient {
* if <code>true</code> - is temporary user
* @param callback
*/
void createUser(@NotNull String token, boolean isTemporary, AsyncRequestCallback<UserDescriptor> callback);
void createUser(@NotNull String token, boolean isTemporary, AsyncRequestCallback<UserDto> callback);
/**
* Get current user's information.
*
* @param callback
*/
void getCurrentUser(AsyncRequestCallback<UserDescriptor> callback);
void getCurrentUser(AsyncRequestCallback<UserDto> callback);
/**
* Update user's password.
@ -56,7 +56,7 @@ public interface UserServiceClient {
* user's id
* @param callback
*/
void getUserById(@NotNull String id, AsyncRequestCallback<UserDescriptor> callback);
void getUserById(@NotNull String id, AsyncRequestCallback<UserDto> callback);
/**
* Get user's information by its alias.
@ -65,7 +65,7 @@ public interface UserServiceClient {
* user's alias
* @param callback
*/
void getUserByAlias(@NotNull String alias, AsyncRequestCallback<UserDescriptor> callback);
void getUserByAlias(@NotNull String alias, AsyncRequestCallback<UserDto> callback);
/**
* Remove user.

View File

@ -12,7 +12,7 @@ package org.eclipse.che.ide.api.user;
import com.google.inject.Inject;
import org.eclipse.che.api.user.shared.dto.UserDescriptor;
import org.eclipse.che.api.user.shared.dto.UserDto;
import org.eclipse.che.ide.MimeType;
import org.eclipse.che.ide.rest.AsyncRequestCallback;
import org.eclipse.che.ide.rest.AsyncRequestFactory;
@ -52,7 +52,7 @@ public class UserServiceClientImpl implements UserServiceClient {
/** {@inheritDoc} */
@Override
public void createUser(@NotNull String token, boolean isTemporary, AsyncRequestCallback<UserDescriptor> callback) {
public void createUser(@NotNull String token, boolean isTemporary, AsyncRequestCallback<UserDto> callback) {
StringBuilder requestUrl = new StringBuilder(CREATE);
requestUrl.append("?token=").append(token).append("&temporary=").append(isTemporary);
@ -64,7 +64,7 @@ public class UserServiceClientImpl implements UserServiceClient {
/** {@inheritDoc} */
@Override
public void getCurrentUser(AsyncRequestCallback<UserDescriptor> callback) {
public void getCurrentUser(AsyncRequestCallback<UserDto> callback) {
asyncRequestFactory.createGetRequest(USER)
.header(ACCEPT, MimeType.APPLICATION_JSON)
@ -86,7 +86,7 @@ public class UserServiceClientImpl implements UserServiceClient {
/** {@inheritDoc} */
@Override
public void getUserById(@NotNull String id, AsyncRequestCallback<UserDescriptor> callback) {
public void getUserById(@NotNull String id, AsyncRequestCallback<UserDto> callback) {
String requestUrl = USER + id;
asyncRequestFactory.createGetRequest(requestUrl)
@ -97,7 +97,7 @@ public class UserServiceClientImpl implements UserServiceClient {
/** {@inheritDoc} */
@Override
public void getUserByAlias(@NotNull String alias, AsyncRequestCallback<UserDescriptor> callback) {
public void getUserByAlias(@NotNull String alias, AsyncRequestCallback<UserDto> callback) {
String requestUrl = FIND + "?alias=" + alias;
asyncRequestFactory.createGetRequest(requestUrl)

View File

@ -41,6 +41,8 @@ import org.eclipse.che.ide.api.project.ProjectTypeServiceClient;
import org.eclipse.che.ide.api.project.ProjectTypeServiceClientImpl;
import org.eclipse.che.ide.api.ssh.SshServiceClient;
import org.eclipse.che.ide.api.ssh.SshServiceClientImpl;
import org.eclipse.che.ide.api.user.PreferencesServiceClient;
import org.eclipse.che.ide.api.user.PreferencesServiceClientImpl;
import org.eclipse.che.ide.api.user.UserProfileServiceClient;
import org.eclipse.che.ide.api.user.UserProfileServiceClientImpl;
import org.eclipse.che.ide.api.user.UserServiceClient;
@ -333,6 +335,7 @@ public class CoreGinModule extends AbstractGinModule {
private void configurePlatformApiGwtClients() {
bind(UserServiceClient.class).to(UserServiceClientImpl.class).in(Singleton.class);
bind(UserProfileServiceClient.class).to(UserProfileServiceClientImpl.class).in(Singleton.class);
bind(PreferencesServiceClient.class).to(PreferencesServiceClientImpl.class).in(Singleton.class);
bind(GitServiceClient.class).to(GitServiceClientImpl.class).in(Singleton.class);
bind(OAuthServiceClient.class).to(OAuthServiceClientImpl.class).in(Singleton.class);
bind(FactoryServiceClient.class).to(FactoryServiceClientImpl.class).in(Singleton.class);

View File

@ -10,8 +10,8 @@
*******************************************************************************/
package org.eclipse.che.ide.core;
import org.eclipse.che.api.user.shared.dto.ProfileDto;
import org.eclipse.che.ide.api.user.UserProfileServiceClient;
import org.eclipse.che.api.user.shared.dto.ProfileDescriptor;
import org.eclipse.che.ide.api.app.CurrentUser;
import org.eclipse.che.ide.api.component.Component;
import org.eclipse.che.ide.rest.AsyncRequestCallback;
@ -40,10 +40,10 @@ public class ProfileComponent implements Component {
@Override
public void start(final Callback<Component, Exception> callback) {
AsyncRequestCallback<ProfileDescriptor> asyncRequestCallback = new AsyncRequestCallback<ProfileDescriptor>(
dtoUnmarshallerFactory.newUnmarshaller(ProfileDescriptor.class)) {
AsyncRequestCallback<ProfileDto> asyncRequestCallback = new AsyncRequestCallback<ProfileDto>(
dtoUnmarshallerFactory.newUnmarshaller(ProfileDto.class)) {
@Override
protected void onSuccess(final ProfileDescriptor profile) {
protected void onSuccess(final ProfileDto profile) {
currentUser.setProfile(profile);
callback.onSuccess(ProfileComponent.this);
}

View File

@ -17,7 +17,7 @@ import org.eclipse.che.api.promises.client.Function;
import org.eclipse.che.api.promises.client.FunctionException;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.promises.client.js.Promises;
import org.eclipse.che.ide.api.user.UserProfileServiceClient;
import org.eclipse.che.ide.api.user.PreferencesServiceClient;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.ide.api.preferences.PreferencesManager;
@ -31,22 +31,22 @@ import java.util.Map;
*/
@Singleton
public class PreferencesManagerImpl implements PreferencesManager {
private final UserProfileServiceClient userProfileService;
private final Map<String, String> changedPreferences;
private final Map<String, String> changedPreferences;
private final PreferencesServiceClient preferencesService;
private Map<String, String> persistedPreferences;
/**
* Create preferences manager
*
* @param userProfileService
* @param preferencesService
* user preference service client
*/
@Inject
protected PreferencesManagerImpl(UserProfileServiceClient userProfileService) {
protected PreferencesManagerImpl(PreferencesServiceClient preferencesService) {
this.persistedPreferences = new HashMap<>();
this.changedPreferences = new HashMap<>();
this.userProfileService = userProfileService;
this.preferencesService = preferencesService;
}
/** {@inheritDoc} */
@ -72,9 +72,9 @@ public class PreferencesManagerImpl implements PreferencesManager {
return Promises.resolve(null);
}
return userProfileService.updatePreferences(changedPreferences).thenPromise(new Function<Map<String,String>, Promise<Void>>() {
return preferencesService.updatePreferences(changedPreferences).thenPromise(new Function<Map<String, String>, Promise<Void>>() {
@Override
public Promise<Void> apply(Map<String,String> result) throws FunctionException {
public Promise<Void> apply(Map<String, String> result) throws FunctionException {
persistedPreferences.putAll(changedPreferences);
changedPreferences.clear();
return Promises.resolve(null);
@ -85,7 +85,7 @@ public class PreferencesManagerImpl implements PreferencesManager {
/** {@inheritDoc} */
@Override
public Promise<Map<String, String>> loadPreferences() {
return userProfileService.getPreferences().then(new Function<Map<String, String>, Map<String, String>>() {
return preferencesService.getPreferences().then(new Function<Map<String, String>, Map<String, String>>() {
@Override
public Map<String, String> apply(Map<String, String> preferences) throws FunctionException {
persistedPreferences = preferences;

View File

@ -13,7 +13,7 @@ package org.eclipse.che.plugin.docker.client;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.user.server.dao.PreferenceDao;
import org.eclipse.che.api.user.server.PreferenceManager;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.dto.server.DtoFactory;
@ -35,11 +35,11 @@ public class UserSpecificDockerRegistryCredentialsProvider {
private static final Logger LOG = LoggerFactory.getLogger(UserSpecificDockerRegistryCredentialsProvider.class);
private PreferenceDao preferenceDao;
private PreferenceManager preferenceManager;
@Inject
public UserSpecificDockerRegistryCredentialsProvider(PreferenceDao preferenceDao) {
this.preferenceDao = preferenceDao;
public UserSpecificDockerRegistryCredentialsProvider(PreferenceManager preferenceManager) {
this.preferenceManager = preferenceManager;
}
/**
@ -52,11 +52,11 @@ public class UserSpecificDockerRegistryCredentialsProvider {
@Nullable
public AuthConfigs getCredentials() {
try {
String encodedCredentials = preferenceDao.getPreferences(EnvironmentContext.getCurrent()
.getSubject()
.getUserId(),
DOCKER_REGISTRY_CREDENTIALS_KEY)
.get(DOCKER_REGISTRY_CREDENTIALS_KEY);
String encodedCredentials = preferenceManager.find(EnvironmentContext.getCurrent()
.getSubject()
.getUserId(),
DOCKER_REGISTRY_CREDENTIALS_KEY)
.get(DOCKER_REGISTRY_CREDENTIALS_KEY);
String credentials = encodedCredentials != null ? new String(Base64.getDecoder().decode(encodedCredentials), "UTF-8") : "{}";
return DtoFactory.newDto(AuthConfigs.class).withConfigs(

View File

@ -11,7 +11,7 @@
package org.eclipse.che.plugin.docker.client;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.user.server.dao.PreferenceDao;
import org.eclipse.che.api.user.server.PreferenceManager;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.commons.subject.SubjectImpl;
import org.eclipse.che.dto.server.DtoFactory;
@ -41,13 +41,13 @@ public class UserSpecificDockerRegistryCredentialsProviderTest {
private static final String DOCKER_REGISTRY_CREDENTIALS_KEY = "dockerCredentials";
@Mock
private PreferenceDao preferenceDao;
private PreferenceManager preferenceManager;
private UserSpecificDockerRegistryCredentialsProvider dockerCredentials;
@BeforeClass
private void before() {
dockerCredentials = new UserSpecificDockerRegistryCredentialsProvider(preferenceDao);
dockerCredentials = new UserSpecificDockerRegistryCredentialsProvider(preferenceManager);
}
@Test
@ -101,7 +101,7 @@ public class UserSpecificDockerRegistryCredentialsProviderTest {
preferences.put(DOCKER_REGISTRY_CREDENTIALS_KEY, base64encodedCredentials);
EnvironmentContext.getCurrent().setSubject(new SubjectImpl("name", "id", "token1234", false));
when(preferenceDao.getPreferences(anyObject(), anyObject())).thenReturn(preferences);
when(preferenceManager.find(anyObject(), anyObject())).thenReturn(preferences);
}
}

View File

@ -19,7 +19,7 @@ import org.eclipse.che.api.machine.server.MachineInstanceProviders;
import org.eclipse.che.api.machine.server.MachineManager;
import org.eclipse.che.api.machine.server.MachineRegistry;
import org.eclipse.che.api.machine.server.MachineService;
import org.eclipse.che.api.machine.server.dao.SnapshotDao;
import org.eclipse.che.api.machine.server.spi.SnapshotDao;
import org.eclipse.che.api.machine.server.exception.MachineException;
import org.eclipse.che.api.machine.server.spi.impl.SnapshotImpl;
import org.eclipse.che.api.machine.server.model.impl.MachineImpl;
@ -128,7 +128,7 @@ public class ServiceTest {
.withHostConfig(new HostConfig().withPortBindings(
singletonMap("5000/tcp", new PortBinding[]{new PortBinding().withHostPort("5000")})));
registryContainerId = docker.createContainer(containerConfig, null).getId();
registryContainerId = docker.createContainer(containerConfig, null).getUserId();
docker.startContainer(registryContainerId, null);
}
@ -192,7 +192,7 @@ public class ServiceTest {
}
@Override
public String getId() {
public String getUserId() {
return USER;
}
@ -208,7 +208,7 @@ public class ServiceTest {
@AfterMethod
public void tearDown() throws Exception {
for (MachineStateImpl machine : new ArrayList<>(machineManager.getMachinesStates())) {
machineManager.destroy(machine.getId(), false);
machineManager.destroy(machine.getUserId(), false);
}
EnvironmentContext.reset();
}
@ -224,7 +224,7 @@ public class ServiceTest {
.withType("Dockerfile")
.withScript("FROM ubuntu\nCMD tail -f /dev/null\n")));
waitMachineIsRunning(machine.getId());
waitMachineIsRunning(machine.getUserId());
}
@Test(dependsOnMethods = "saveSnapshotTest", enabled = false)
@ -242,27 +242,27 @@ public class ServiceTest {
final MachineStateDescriptor machine = machineService
.createMachineFromSnapshot(newDto(SnapshotMachineCreationMetadata.class).withSnapshotId(SNAPSHOT_ID));
waitMachineIsRunning(machine.getId());
waitMachineIsRunning(machine.getUserId());
}
@Test
public void getMachineTest() throws Exception {
final MachineImpl machine = createMachineAndWaitRunningState();
final MachineDescriptor machineById = machineService.getMachineById(machine.getId());
final MachineDescriptor machineById = machineService.getMachineById(machine.getUserId());
assertEquals(machineById.getId(), machine.getId());
assertEquals(machineById.getUserId(), machine.getUserId());
}
@Test
public void getMachinesTest() throws Exception {
Set<String> expected = new HashSet<>();
expected.add(createMachineAndWaitRunningState().getId());
expected.add(createMachineAndWaitRunningState().getId());
expected.add(createMachineAndWaitRunningState().getUserId());
expected.add(createMachineAndWaitRunningState().getUserId());
Set<String> actual = machineManager.getMachinesStates()
.stream()
.map(MachineImpl::getId)
.map(MachineImpl::getUserId)
.collect(Collectors.toSet());
assertEquals(actual, expected);
}
@ -271,14 +271,14 @@ public class ServiceTest {
public void destroyMachineTest() throws Exception {
final MachineImpl machine = createMachineAndWaitRunningState();
machineService.destroyMachine(machine.getId());
machineService.destroyMachine(machine.getUserId());
assertEquals(machineService.getMachineStateById(machine.getId()).getStatus(), MachineStatus.DESTROYING);
assertEquals(machineService.getMachineStateById(machine.getUserId()).getStatus(), MachineStatus.DESTROYING);
int counter = 0;
while (++counter < 1000) {
try {
machineManager.getMachine(machine.getId());
machineManager.getMachine(machine.getUserId());
} catch (NotFoundException e) {
return;
}
@ -293,7 +293,7 @@ public class ServiceTest {
// use machine manager instead of machine service because it returns future with snapshot
// that allows check operation result
final SnapshotImpl snapshot = machineManager.save(machine.getId(), USER, "test description");
final SnapshotImpl snapshot = machineManager.save(machine.getUserId(), USER, "test description");
for (int i = 0; snapshot.getInstanceKey() == null && i < 10; ++i) {
Thread.sleep(500);
@ -337,13 +337,13 @@ public class ServiceTest {
final MachineImpl machine = createMachineAndWaitRunningState();
String commandInMachine = "echo \"command in machine\" && tail -f /dev/null";
machineService.executeCommandInMachine(machine.getId(),
machineService.executeCommandInMachine(machine.getUserId(),
DtoFactory.newDto(CommandDto.class).withCommandLine(commandInMachine),
null);
Thread.sleep(500);
final List<MachineProcessDto> processes = machineService.getProcesses(machine.getId());
final List<MachineProcessDto> processes = machineService.getProcesses(machine.getUserId());
assertEquals(processes.size(), 1);
assertEquals(processes.get(0).getCommandLine(), commandInMachine);
}
@ -357,12 +357,12 @@ public class ServiceTest {
commands.add("sleep 10000");
for (String command : commands) {
machineService.executeCommandInMachine(machine.getId(), DtoFactory.newDto(CommandDto.class).withCommandLine(command), null);
machineService.executeCommandInMachine(machine.getUserId(), DtoFactory.newDto(CommandDto.class).withCommandLine(command), null);
}
Thread.sleep(500);
final List<MachineProcessDto> processes = machineService.getProcesses(machine.getId());
final List<MachineProcessDto> processes = machineService.getProcesses(machine.getUserId());
assertEquals(processes.size(), 2);
Set<String> actualCommandLines = new HashSet<>(2);
for (MachineProcessDto process : processes) {
@ -377,19 +377,19 @@ public class ServiceTest {
final MachineImpl machine = createMachineAndWaitRunningState();
String commandInMachine = "echo \"command in machine\" && tail -f /dev/null";
machineService.executeCommandInMachine(machine.getId(),
machineService.executeCommandInMachine(machine.getUserId(),
DtoFactory.newDto(CommandDto.class).withCommandLine(commandInMachine),
null);
Thread.sleep(500);
final List<MachineProcessDto> processes = machineService.getProcesses(machine.getId());
final List<MachineProcessDto> processes = machineService.getProcesses(machine.getUserId());
assertEquals(processes.size(), 1);
assertEquals(processes.get(0).getCommandLine(), commandInMachine);
machineService.stopProcess(machine.getId(), processes.get(0).getPid());
machineService.stopProcess(machine.getUserId(), processes.get(0).getPid());
assertTrue(machineService.getProcesses(machine.getId()).isEmpty());
assertTrue(machineService.getProcesses(machine.getUserId()).isEmpty());
}
@Test(expectedExceptions = NotFoundException.class, expectedExceptionsMessageRegExp = "Process with pid .* not found")
@ -397,17 +397,17 @@ public class ServiceTest {
final MachineImpl machine = createMachineAndWaitRunningState();
String commandInMachine = "echo \"command in machine\" && tail -f /dev/null";
machineService.executeCommandInMachine(machine.getId(),
machineService.executeCommandInMachine(machine.getUserId(),
DtoFactory.newDto(CommandDto.class).withCommandLine(commandInMachine),
null);
Thread.sleep(500);
final List<MachineProcessDto> processes = machineService.getProcesses(machine.getId());
final List<MachineProcessDto> processes = machineService.getProcesses(machine.getUserId());
assertEquals(processes.size(), 1);
assertEquals(processes.get(0).getCommandLine(), commandInMachine);
machineService.stopProcess(machine.getId(), processes.get(0).getPid() + 100);
machineService.stopProcess(machine.getUserId(), processes.get(0).getPid() + 100);
}
private MachineImpl createMachineAndWaitRunningState() throws Exception {
@ -423,7 +423,7 @@ public class ServiceTest {
.withDev(false)
.withDisplayName("displayName" + System.currentTimeMillis())
, false);
waitMachineIsRunning(machine.getId());
waitMachineIsRunning(machine.getUserId());
return machine;
}

View File

@ -142,7 +142,7 @@ public class GitHubAuthenticatorImpl implements OAuth2Authenticator, OAuthCallba
private void generateSshKeys(final OAuthStatus authStatus) {
final SshKeyUploader githubKeyUploader = registry.getUploader(GITHUB_HOST);
if (githubKeyUploader != null) {
String userId = appContext.getCurrentUser().getProfile().getId();
String userId = appContext.getCurrentUser().getProfile().getUserId();
githubKeyUploader.uploadKey(userId, new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {

View File

@ -16,7 +16,8 @@ import com.google.gwtmockito.GwtMockitoTestRunner;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.ssh.shared.dto.SshPairDto;
import org.eclipse.che.api.user.shared.dto.ProfileDescriptor;
import org.eclipse.che.api.user.shared.dto.ProfileDto;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.app.CurrentUser;
import org.eclipse.che.ide.api.dialogs.ConfirmCallback;
@ -141,14 +142,14 @@ public class GitHubAuthenticatorImplTest {
SshKeyUploader sshKeyUploader = mock(SshKeyUploader.class);
CurrentUser user = mock(CurrentUser.class);
ProfileDescriptor profile = mock(ProfileDescriptor.class);
ProfileDto profile = mock(ProfileDto.class);
when(view.isGenerateKeysSelected()).thenReturn(true);
when(registry.getUploader(GITHUB_HOST)).thenReturn(sshKeyUploader);
when(appContext.getCurrentUser()).thenReturn(user);
when(user.getProfile()).thenReturn(profile);
when(profile.getId()).thenReturn(userId);
when(profile.getUserId()).thenReturn(userId);
gitHubAuthenticator.onAuthenticated(authStatus);
@ -164,11 +165,11 @@ public class GitHubAuthenticatorImplTest {
OAuthStatus authStatus = mock(OAuthStatus.class);
CurrentUser user = mock(CurrentUser.class);
ProfileDescriptor profile = mock(ProfileDescriptor.class);
ProfileDto profile = mock(ProfileDto.class);
when(view.isGenerateKeysSelected()).thenReturn(false);
when(appContext.getCurrentUser()).thenReturn(user);
when(user.getProfile()).thenReturn(profile);
when(profile.getId()).thenReturn(userId);
when(profile.getUserId()).thenReturn(userId);
gitHubAuthenticator.authenticate(null, getCallBack());
gitHubAuthenticator.onAuthenticated(authStatus);
@ -184,13 +185,13 @@ public class GitHubAuthenticatorImplTest {
SshKeyUploader keyProvider = mock(SshKeyUploader.class);
CurrentUser user = mock(CurrentUser.class);
ProfileDescriptor profile = mock(ProfileDescriptor.class);
ProfileDto profile = mock(ProfileDto.class);
when(view.isGenerateKeysSelected()).thenReturn(true);
when(registry.getUploader(GITHUB_HOST)).thenReturn(keyProvider);
when(appContext.getCurrentUser()).thenReturn(user);
when(user.getProfile()).thenReturn(profile);
when(profile.getId()).thenReturn(userId);
when(profile.getUserId()).thenReturn(userId);
gitHubAuthenticator.authenticate(null, getCallBack());
gitHubAuthenticator.onAuthenticated(authStatus);
@ -213,14 +214,14 @@ public class GitHubAuthenticatorImplTest {
SshKeyUploader keyProvider = mock(SshKeyUploader.class);
CurrentUser user = mock(CurrentUser.class);
ProfileDescriptor profile = mock(ProfileDescriptor.class);
ProfileDto profile = mock(ProfileDto.class);
MessageDialog messageDialog = mock(MessageDialog.class);
when(view.isGenerateKeysSelected()).thenReturn(true);
when(registry.getUploader(GITHUB_HOST)).thenReturn(keyProvider);
when(appContext.getCurrentUser()).thenReturn(user);
when(user.getProfile()).thenReturn(profile);
when(profile.getId()).thenReturn(userId);
when(profile.getUserId()).thenReturn(userId);
when(dialogFactory.createMessageDialog(anyString(), anyString(), Matchers.<ConfirmCallback>anyObject())).thenReturn(messageDialog);
gitHubAuthenticator.authenticate(null, getCallBack());
@ -248,14 +249,14 @@ public class GitHubAuthenticatorImplTest {
SshKeyUploader keyUploader = mock(SshKeyUploader.class);
CurrentUser user = mock(CurrentUser.class);
ProfileDescriptor profile = mock(ProfileDescriptor.class);
ProfileDto profile = mock(ProfileDto.class);
MessageDialog messageDialog = mock(MessageDialog.class);
when(view.isGenerateKeysSelected()).thenReturn(true);
when(registry.getUploader(GITHUB_HOST)).thenReturn(keyUploader);
when(appContext.getCurrentUser()).thenReturn(user);
when(user.getProfile()).thenReturn(profile);
when(profile.getId()).thenReturn(userId);
when(profile.getUserId()).thenReturn(userId);
when(dialogFactory.createMessageDialog(anyString(), anyString(), Matchers.<ConfirmCallback>anyObject())).thenReturn(messageDialog);
when(pair.getName()).thenReturn(GITHUB_HOST);
when(pair.getService()).thenReturn(SshKeyManagerPresenter.VCS_SSH_SERVICE);

View File

@ -20,7 +20,9 @@ import org.eclipse.che.api.project.shared.dto.ProjectImporterDescriptor;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.user.UserServiceClient;
import org.eclipse.che.api.user.shared.dto.ProfileDescriptor;
import org.eclipse.che.api.user.shared.dto.ProfileDto;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto;
import org.eclipse.che.ide.api.app.AppContext;
import org.eclipse.che.ide.api.app.CurrentUser;
import org.eclipse.che.ide.api.notification.NotificationManager;
@ -500,11 +502,11 @@ public class GithubImporterPagePresenterTest {
public void onLoadRepoClickedWhenAuthorizeIsFailed() throws Exception {
String userId = "userId";
CurrentUser user = mock(CurrentUser.class);
ProfileDescriptor profile = mock(ProfileDescriptor.class);
ProfileDto profile = mock(ProfileDto.class);
when(appContext.getCurrentUser()).thenReturn(user);
when(user.getProfile()).thenReturn(profile);
when(profile.getId()).thenReturn(userId);
when(profile.getUserId()).thenReturn(userId);
final Throwable exception = mock(UnauthorizedException.class);
@ -553,12 +555,12 @@ public class GithubImporterPagePresenterTest {
final Throwable exception = mock(UnauthorizedException.class);
String userId = "userId";
CurrentUser user = mock(CurrentUser.class);
ProfileDescriptor profile = mock(ProfileDescriptor.class);
ProfileDto profile = mock(ProfileDto.class);
doReturn(exception).when(promiseError).getCause();
when(appContext.getCurrentUser()).thenReturn(user);
when(user.getProfile()).thenReturn(profile);
when(profile.getId()).thenReturn(userId);
when(profile.getUserId()).thenReturn(userId);
presenter.onLoadRepoClicked();

View File

@ -53,9 +53,9 @@ public interface IWorkingSet extends /*IPersistableElement,*/ IAdaptable {
* Currently, this is one of the icons specified in the extensions
* of the org.eclipse.ui.workingSets extension point.
* The extension is identified using the value returned by
* <code>getId()</code>.
* <code>getUserId()</code>.
* Returns <code>null</code> if no icon has been specified in the
* extension or if <code>getId()</code> returns <code>null</code>.
* extension or if <code>getUserId()</code> returns <code>null</code>.
*
* @return the working set icon or <code>null</code>.
* @since 2.1
@ -69,9 +69,9 @@ public interface IWorkingSet extends /*IPersistableElement,*/ IAdaptable {
* Currently, this is one of the icons specified in the extensions
* of the org.eclipse.ui.workingSets extension point.
* The extension is identified using the value returned by
* <code>getId()</code>.
* <code>getUserId()</code>.
* Returns <code>null</code> if no icon has been specified in the
* extension or if <code>getId()</code> returns <code>null</code>.
* extension or if <code>getUserId()</code> returns <code>null</code>.
*
* @return the working set icon or <code>null</code>.
* @since 3.3

View File

@ -17,8 +17,8 @@ import com.google.inject.Inject;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.api.user.shared.dto.ProfileDto;
import org.eclipse.che.ide.api.user.UserProfileServiceClient;
import org.eclipse.che.api.user.shared.dto.ProfileDescriptor;
import org.eclipse.che.ide.api.workspace.WorkspaceServiceClient;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto;
import org.eclipse.che.ide.extension.machine.client.machine.Machine;
@ -66,11 +66,11 @@ public class MachineInfoPresenter implements TabPresenter {
*/
public void update(@NotNull Machine machine) {
Unmarshallable<ProfileDescriptor> profileUnMarshaller = unmarshallerFactory.newUnmarshaller(ProfileDescriptor.class);
Unmarshallable<ProfileDto> profileUnMarshaller = unmarshallerFactory.newUnmarshaller(ProfileDto.class);
userProfile.getCurrentProfile(new AsyncRequestCallback<ProfileDescriptor>(profileUnMarshaller) {
userProfile.getCurrentProfile(new AsyncRequestCallback<ProfileDto>(profileUnMarshaller) {
@Override
protected void onSuccess(ProfileDescriptor result) {
protected void onSuccess(ProfileDto result) {
Map<String, String> attributes = result.getAttributes();
String firstName = attributes.get(FIRST_NAME_KEY);

View File

@ -13,8 +13,8 @@ package org.eclipse.che.ide.extension.machine.client.perspective.widgets.machine
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.user.shared.dto.ProfileDto;
import org.eclipse.che.ide.api.user.UserProfileServiceClient;
import org.eclipse.che.api.user.shared.dto.ProfileDescriptor;
import org.eclipse.che.ide.api.workspace.WorkspaceServiceClient;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto;
@ -62,22 +62,22 @@ public class MachineInfoPresenterTest {
//additional mocks
@Mock
private Machine machine;
private Machine machine;
@Mock
private AcceptsOneWidget container;
private AcceptsOneWidget container;
@Mock
private Unmarshallable<ProfileDescriptor> profileUnmarshaller;
private Unmarshallable<ProfileDto> profileUnmarshaller;
@Mock
private Unmarshallable<WorkspaceDto> wsUnmarshaller;
private Unmarshallable<WorkspaceDto> wsUnmarshaller;
@Mock
private ProfileDescriptor profileDescriptor;
private ProfileDto profileDescriptor;
@Mock
private WorkspaceDto wsDescriptor;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Promise<WorkspaceDto> promise;
@Captor
private ArgumentCaptor<AsyncRequestCallback<ProfileDescriptor>> profileCaptor;
private ArgumentCaptor<AsyncRequestCallback<ProfileDto>> profileCaptor;
@Captor
private ArgumentCaptor<AsyncRequestCallback<WorkspaceDto>> wsCaptor;
@ -88,7 +88,7 @@ public class MachineInfoPresenterTest {
public void setUp() {
when(machine.getWorkspaceId()).thenReturn(SOME_TEXT);
when(unmarshallerFactory.newUnmarshaller(ProfileDescriptor.class)).thenReturn(profileUnmarshaller);
when(unmarshallerFactory.newUnmarshaller(ProfileDto.class)).thenReturn(profileUnmarshaller);
when(unmarshallerFactory.newUnmarshaller(WorkspaceDto.class)).thenReturn(wsUnmarshaller);
}
@ -98,9 +98,9 @@ public class MachineInfoPresenterTest {
presenter.update(machine);
verify(unmarshallerFactory).newUnmarshaller(ProfileDescriptor.class);
verify(unmarshallerFactory).newUnmarshaller(ProfileDto.class);
verify(userProfile).getCurrentProfile(Matchers.<AsyncRequestCallback<ProfileDescriptor>>anyObject());
verify(userProfile).getCurrentProfile(Matchers.<AsyncRequestCallback<ProfileDto>>anyObject());
verify(machine).getWorkspaceId();
verify(wsService).getWorkspace(eq(SOME_TEXT));
@ -119,7 +119,7 @@ public class MachineInfoPresenterTest {
presenter.update(machine);
verify(userProfile).getCurrentProfile(profileCaptor.capture());
AsyncRequestCallback<ProfileDescriptor> callback = profileCaptor.getValue();
AsyncRequestCallback<ProfileDto> callback = profileCaptor.getValue();
//noinspection NonJREEmulationClassesInClientCode
Method method = callback.getClass().getDeclaredMethod("onSuccess", Object.class);
@ -144,7 +144,7 @@ public class MachineInfoPresenterTest {
presenter.update(machine);
verify(userProfile).getCurrentProfile(profileCaptor.capture());
AsyncRequestCallback<ProfileDescriptor> callback = profileCaptor.getValue();
AsyncRequestCallback<ProfileDto> callback = profileCaptor.getValue();
//noinspection NonJREEmulationClassesInClientCode
Method method = callback.getClass().getDeclaredMethod("onSuccess", Object.class);

View File

@ -178,7 +178,7 @@ public class SshKeyManagerPresenter extends AbstractPreferencePagePresenter impl
CurrentUser user = appContext.getCurrentUser();
final SshKeyUploader githubUploader = registry.getUploaders().get(GITHUB_HOST);
if (user != null && githubUploader != null) {
githubUploader.uploadKey(user.getProfile().getId(), new AsyncCallback<Void>() {
githubUploader.uploadKey(user.getProfile().getUserId(), new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
refreshKeys();

View File

@ -10,9 +10,8 @@
*******************************************************************************/
package org.eclipse.che.plugin.svn.server.credentials;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.user.server.dao.PreferenceDao;
import org.eclipse.che.api.user.server.spi.PreferenceDao;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.commons.subject.Subject;
@ -45,7 +44,7 @@ public class CurrentUserPreferencesAccessImpl implements CurrentUserPreferencesA
content.put(key, value);
try {
this.preferencesDao.setPreferences(currentSubject.getUserId(), content);
} catch (final ServerException | NotFoundException e) {
} catch (final ServerException e) {
throw new PreferencesAccessException(e);
}
}

View File

@ -20,7 +20,7 @@ import org.eclipse.che.api.project.server.FolderEntry;
import org.eclipse.che.api.project.server.importer.ProjectImporter;
import org.eclipse.che.api.project.server.type.ProjectTypeDef;
import org.eclipse.che.api.project.server.type.ValueProviderFactory;
import org.eclipse.che.api.user.server.dao.UserProfileDao;
import org.eclipse.che.api.user.server.spi.ProfileDao;
import org.eclipse.che.api.vfs.VirtualFile;
import org.eclipse.che.api.vfs.VirtualFileSystem;
import org.eclipse.che.commons.lang.NameGenerator;
@ -47,7 +47,8 @@ import static org.mockito.Mockito.when;
public class SubversionProjectImporterTest {
@Mock
private UserProfileDao userProfileDao;
private ProfileDao userProfileDao;
@Mock
private CredentialsProvider credentialsProvider;
@Mock
@ -73,7 +74,7 @@ public class SubversionProjectImporterTest {
.to(SubversionValueProviderFactory.class);
bind(SshKeyProvider.class).toInstance(sshKeyProvider);
bind(UserProfileDao.class).toInstance(userProfileDao);
bind(ProfileDao.class).toInstance(userProfileDao);
bind(CredentialsProvider.class).toInstance(credentialsProvider);
bind(RepositoryUrlProvider.class).toInstance(repositoryUrlProvider);
}

View File

@ -15,8 +15,8 @@ import com.google.common.io.Files;
import org.eclipse.che.api.core.util.LineConsumer;
import org.eclipse.che.api.core.util.LineConsumerFactory;
import org.eclipse.che.api.user.server.dao.Profile;
import org.eclipse.che.api.user.server.dao.UserProfileDao;
import org.eclipse.che.api.user.server.model.impl.ProfileImpl;
import org.eclipse.che.api.user.server.spi.ProfileDao;
import org.eclipse.che.api.vfs.VirtualFileSystem;
import org.eclipse.che.api.vfs.VirtualFileSystemProvider;
import org.eclipse.che.api.vfs.impl.file.LocalVirtualFileSystemProvider;
@ -163,7 +163,7 @@ public class TestUtils {
* @throws Exception
* if anything goes wrong
*/
public static void createTestUser(final UserProfileDao userProfileDao) throws Exception {
public static void createTestUser(final ProfileDao userProfileDao) throws Exception {
// set current user
EnvironmentContext.getCurrent().setSubject(new SubjectImpl("codenvy", "codenvy", null, false));
@ -175,7 +175,7 @@ public class TestUtils {
profileAttributes.put("email", "che@eclipse.org");
Mockito.when(userProfileDao.getById("codenvy"))
.thenReturn(new Profile().withId("codenvy").withUserId("codenvy").withAttributes(profileAttributes));
.thenReturn(new ProfileImpl("codenvy", profileAttributes));
}
/**

View File

@ -186,6 +186,12 @@
<artifactId>che-core-api-ssh-shared</artifactId>
<version>${che.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-user</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-user</artifactId>

View File

@ -12,7 +12,7 @@ package org.eclipse.che.api.git;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.git.shared.GitUser;
import org.eclipse.che.api.user.server.dao.PreferenceDao;
import org.eclipse.che.api.user.server.spi.PreferenceDao;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -40,7 +40,7 @@ import org.eclipse.che.api.project.shared.dto.ItemReference;
import org.eclipse.che.api.project.shared.dto.MoveOptions;
import org.eclipse.che.api.project.shared.dto.SourceEstimation;
import org.eclipse.che.api.project.shared.dto.TreeElement;
import org.eclipse.che.api.user.server.dao.UserDao;
import org.eclipse.che.api.user.server.spi.UserDao;
import org.eclipse.che.api.vfs.VirtualFile;
import org.eclipse.che.api.vfs.VirtualFileSystem;
import org.eclipse.che.api.vfs.impl.file.DefaultFileWatcherNotificationHandler;

View File

@ -17,8 +17,7 @@ import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.UnauthorizedException;
import org.eclipse.che.api.core.rest.HttpJsonRequestFactory;
import org.eclipse.che.api.user.server.UserProfileService;
import org.eclipse.che.api.user.server.dao.PreferenceDao;
import org.eclipse.che.api.user.server.spi.PreferenceDao;
import org.eclipse.che.commons.env.EnvironmentContext;
import javax.inject.Inject;
@ -44,12 +43,12 @@ public class RemotePreferenceDao implements PreferenceDao {
@Inject
public RemotePreferenceDao(@Named("api.endpoint") String apiUrl, HttpJsonRequestFactory requestFactory) {
this.prefsUrl = apiUrl + "/profile/prefs";
this.prefsUrl = apiUrl + "/preferences";
this.requestFactory = requestFactory;
}
@Override
public void setPreferences(String userId, Map<String, String> preferences) throws ServerException, NotFoundException {
public void setPreferences(String userId, Map<String, String> preferences) throws ServerException {
requireNonNull(preferences, "Required non-null preferences");
checkUserId(requireNonNull(userId, "Required non-null user id"));
try {

View File

@ -11,10 +11,9 @@
package org.eclipse.che;
import org.eclipse.che.api.core.rest.DefaultHttpJsonRequestFactory;
import org.eclipse.che.api.user.server.UserProfileService;
import org.eclipse.che.api.user.server.dao.PreferenceDao;
import org.eclipse.che.api.user.server.dao.UserDao;
import org.eclipse.che.api.user.server.dao.UserProfileDao;
import org.eclipse.che.api.user.server.PreferenceManager;
import org.eclipse.che.api.user.server.PreferencesService;
import org.eclipse.che.api.user.server.ProfileService;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.commons.subject.Subject;
import org.eclipse.che.commons.subject.SubjectImpl;
@ -41,7 +40,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* Tests that {@link RemotePreferenceDao} uses correct methods of {@link UserProfileService}.
* Tests that {@link RemotePreferenceDao} uses correct methods of {@link ProfileService}.
*
* @author Yevhenii Voevodin
*/
@ -53,16 +52,10 @@ public class RemotePreferenceDaoCompatibilityTest {
private static final Subject TEST_SUBJECT = new SubjectImpl("name", "id", "token", false);
@Mock
private PreferenceDao preferenceDaoMock;
@Mock
private UserDao userDao;
@Mock
private UserProfileDao userProfileDao;
private PreferenceManager preferenceManager;
@InjectMocks
private UserProfileService profileService;
private PreferencesService preferenceService;
@BeforeMethod
private void setUp() {
@ -77,7 +70,7 @@ public class RemotePreferenceDaoCompatibilityTest {
remoteDao.getPreferences(TEST_SUBJECT.getUserId());
verify(preferenceDaoMock).getPreferences(TEST_SUBJECT.getUserId());
verify(preferenceManager).find(TEST_SUBJECT.getUserId());
}
@Test
@ -86,7 +79,7 @@ public class RemotePreferenceDaoCompatibilityTest {
remoteDao.getPreferences(TEST_SUBJECT.getUserId(), "filter");
verify(preferenceDaoMock).getPreferences(TEST_SUBJECT.getUserId(), "filter");
verify(preferenceManager).find(TEST_SUBJECT.getUserId(), "filter");
}
@Test
@ -96,7 +89,7 @@ public class RemotePreferenceDaoCompatibilityTest {
remoteDao.setPreferences(TEST_SUBJECT.getUserId(), prefs);
verify(preferenceDaoMock).setPreferences(TEST_SUBJECT.getUserId(), prefs);
verify(preferenceManager).save(TEST_SUBJECT.getUserId(), prefs);
}
@Test
@ -105,7 +98,7 @@ public class RemotePreferenceDaoCompatibilityTest {
remoteDao.remove(TEST_SUBJECT.getUserId());
verify(preferenceDaoMock).remove(TEST_SUBJECT.getUserId());
verify(preferenceManager).remove(TEST_SUBJECT.getUserId());
}
@Filter

View File

@ -31,7 +31,7 @@ import org.eclipse.che.api.factory.server.builder.FactoryBuilder;
import org.eclipse.che.api.factory.server.snippet.SnippetGenerator;
import org.eclipse.che.api.factory.shared.dto.Author;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.user.server.dao.UserDao;
import org.eclipse.che.api.user.server.spi.UserDao;
import org.eclipse.che.api.workspace.server.WorkspaceManager;
import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;

View File

@ -13,7 +13,7 @@ package org.eclipse.che.api.factory.server.impl;
import org.eclipse.che.api.core.BadRequestException;
import org.eclipse.che.api.factory.server.FactoryAcceptValidator;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.user.server.dao.PreferenceDao;
import org.eclipse.che.api.user.server.spi.PreferenceDao;
import javax.inject.Inject;
import javax.inject.Singleton;

View File

@ -20,7 +20,7 @@ import org.eclipse.che.api.factory.shared.dto.Ide;
import org.eclipse.che.api.factory.shared.dto.OnAppLoaded;
import org.eclipse.che.api.factory.shared.dto.OnProjectsLoaded;
import org.eclipse.che.api.factory.shared.dto.Policies;
import org.eclipse.che.api.user.server.dao.PreferenceDao;
import org.eclipse.che.api.user.server.spi.PreferenceDao;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import java.io.UnsupportedEncodingException;
@ -30,7 +30,6 @@ import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.lang.Boolean.parseBoolean;
import static java.lang.String.format;

View File

@ -15,7 +15,7 @@ import org.eclipse.che.api.core.ForbiddenException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.factory.server.FactoryCreateValidator;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.user.server.dao.PreferenceDao;
import org.eclipse.che.api.user.server.spi.PreferenceDao;
import org.eclipse.che.api.workspace.server.WorkspaceValidator;
import javax.inject.Inject;

View File

@ -26,8 +26,8 @@ import org.eclipse.che.api.factory.shared.dto.Button;
import org.eclipse.che.api.factory.shared.dto.ButtonAttributes;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.machine.shared.dto.CommandDto;
import org.eclipse.che.api.user.server.dao.User;
import org.eclipse.che.api.user.server.dao.UserDao;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
import org.eclipse.che.api.user.server.spi.UserDao;
import org.eclipse.che.api.workspace.server.WorkspaceManager;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
@ -161,7 +161,11 @@ public class FactoryServiceTest {
factoryBuilder = spy(new FactoryBuilder(new SourceStorageParametersValidator()));
doNothing().when(factoryBuilder).checkValid(any(Factory.class));
when(factoryParametersResolverHolder.getFactoryParametersResolvers()).thenReturn(factoryParametersResolvers);
when(userDao.getById(anyString())).thenReturn(new User().withName(JettyHttpServer.ADMIN_USER_NAME));
when(userDao.getById(anyString())).thenReturn(new UserImpl(null,
null,
JettyHttpServer.ADMIN_USER_NAME,
null,
null));
factoryService = new FactoryService(factoryStore,
createValidator,
acceptValidator,

View File

@ -26,9 +26,9 @@ import org.eclipse.che.api.factory.shared.dto.OnAppClosed;
import org.eclipse.che.api.factory.shared.dto.OnAppLoaded;
import org.eclipse.che.api.factory.shared.dto.OnProjectsLoaded;
import org.eclipse.che.api.factory.shared.dto.Policies;
import org.eclipse.che.api.user.server.dao.PreferenceDao;
import org.eclipse.che.api.user.server.dao.User;
import org.eclipse.che.api.user.server.dao.UserDao;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
import org.eclipse.che.api.user.server.spi.PreferenceDao;
import org.eclipse.che.api.user.server.spi.UserDao;
import org.eclipse.che.api.workspace.shared.dto.ProjectConfigDto;
import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto;
@ -86,7 +86,7 @@ public class FactoryBaseValidatorTest {
.withCreator(newDto(Author.class)
.withUserId("userid"));
User user = new User().withId("userid");
UserImpl user = new UserImpl("userid");
when(userDao.getById("userid")).thenReturn(user);
validator = new TesterFactoryBaseValidator(preferenceDao);

View File

@ -13,8 +13,8 @@ package org.eclipse.che.api.factory.server.impl;
import org.eclipse.che.api.core.ApiException;
import org.eclipse.che.api.core.model.workspace.WorkspaceConfig;
import org.eclipse.che.api.factory.shared.dto.Factory;
import org.eclipse.che.api.user.server.dao.PreferenceDao;
import org.eclipse.che.api.user.server.dao.UserDao;
import org.eclipse.che.api.user.server.spi.PreferenceDao;
import org.eclipse.che.api.user.server.spi.UserDao;
import org.eclipse.che.api.workspace.server.WorkspaceValidator;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;

View File

@ -10,7 +10,7 @@
*******************************************************************************/
package org.eclipse.che.api.factory.server.impl;
import org.eclipse.che.api.user.server.dao.PreferenceDao;
import org.eclipse.che.api.user.server.spi.PreferenceDao;
/**
* @author Sergii Kabashniuk

View File

@ -41,6 +41,10 @@
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-dto</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-model</artifactId>
</dependency>
</dependencies>
<build>
<resources>

View File

@ -1,52 +0,0 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.shared.dto;
import org.eclipse.che.api.user.shared.model.Membership;
import org.eclipse.che.dto.shared.DTO;
import java.util.List;
import java.util.Map;
/**
*
*
* @author andrew00x
*/
@DTO
public interface MembershipDto extends Membership {
@Override
String getUserId();
void setUserId(String id);
MembershipDto withUserId(String id);
@Override
String getScope();
@Override
String getUserName();
@Override
String getSubjectId();
@Override
Map<String, String> getSubjectProperties();
@Override
List<String> getRoles();
void setRoles(List<String> roles);
MembershipDto withRoles(List<String> roles);
}

View File

@ -10,43 +10,47 @@
*******************************************************************************/
package org.eclipse.che.api.user.shared.dto;
import org.eclipse.che.api.core.model.user.Profile;
import org.eclipse.che.api.core.rest.shared.dto.Link;
import org.eclipse.che.dto.server.DtoFactory;
import org.eclipse.che.dto.shared.DTO;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
import java.util.Map;
/**
* @author andrew00x
* This object used for transporting profile data to/from client.
*
* @author Yevhenii Voevodin
* @see Profile
* @see DtoFactory
*/
@DTO
public interface ProfileDescriptor {
void setId(String id);
@ApiModelProperty("Profile ID")
String getId();
ProfileDescriptor withId(String id);
@ApiModelProperty("User ID")
String getUserId();
public interface ProfileDto extends Profile {
void setUserId(String id);
ProfileDescriptor withUserId(String id);
@ApiModelProperty("Profile ID")
String getUserId();
ProfileDto withUserId(String id);
@ApiModelProperty("Profile attributes")
Map<String, String> getAttributes();
void setAttributes(Map<String, String> attributes);
ProfileDescriptor withAttributes(Map<String, String> attributes);
ProfileDto withAttributes(Map<String, String> attributes);
List<Link> getLinks();
void setLinks(List<Link> links);
ProfileDescriptor withLinks(List<Link> links);
ProfileDto withLinks(List<Link> links);
String getEmail();
ProfileDto withEmail(String email);
}

View File

@ -10,56 +10,62 @@
*******************************************************************************/
package org.eclipse.che.api.user.shared.dto;
import org.eclipse.che.api.core.model.user.User;
import org.eclipse.che.api.core.rest.shared.dto.Link;
import org.eclipse.che.dto.server.DtoFactory;
import org.eclipse.che.dto.shared.DTO;
import io.swagger.annotations.ApiModelProperty;
import java.util.List;
/**
* @author andrew00x
* This object used for transporting user data to/from client.
*
* @author Yevhenii Voevodin
* @see User
* @see DtoFactory
*/
@DTO
public interface UserDescriptor {
public interface UserDto extends User {
@ApiModelProperty("User ID")
String getId();
void setId(String id);
UserDescriptor withId(String id);
UserDto withId(String id);
@ApiModelProperty("User alias which is used for oAuth")
List<String> getAliases();
void setAliases(List<String> aliases);
UserDescriptor withAliases(List<String> aliases);
UserDto withAliases(List<String> aliases);
@ApiModelProperty("User email")
String getEmail();
void setEmail(String email);
UserDescriptor withEmail(String email);
UserDto withEmail(String email);
@ApiModelProperty("User name")
String getName();
void setName(String name);
UserDescriptor withName(String name);
UserDto withName(String name);
@ApiModelProperty("User password")
String getPassword();
void setPassword(String password);
UserDescriptor withPassword(String password);
UserDto withPassword(String password);
List<Link> getLinks();
void setLinks(List<Link> links);
UserDescriptor withLinks(List<Link> links);
UserDto withLinks(List<Link> links);
}

View File

@ -48,6 +48,10 @@
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-dto</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-model</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-api-user-shared</artifactId>
@ -56,10 +60,19 @@
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-lang</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.core</groupId>
<artifactId>che-core-commons-test</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.restassured</groupId>
<artifactId>rest-assured</artifactId>
@ -99,4 +112,35 @@
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Skip tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<excludes>
<exclude>**/spi/tck/*.*</exclude>
</excludes>
</configuration>
</plugin>
<!-- Create the test jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
<configuration>
<includes>
<include>**/spi/tck/*.*</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -11,30 +11,32 @@
package org.eclipse.che.api.user.server;
/**
* Constants for User API and UserProfile API
* Constants for User/Profile/Preferences API.
*
* @author Eugene Voevodin
* @author Yevhenii Voevodin
* @author Max Shaposhnik
*/
public final class Constants {
public static final String LINK_REL_GET_CURRENT_USER_PROFILE = "current user profile";
public static final String LINK_REL_UPDATE_CURRENT_USER_PROFILE = "update current user profile";
public static final String LINK_REL_GET_USER_PROFILE_BY_ID = "user profile by id";
public static final String LINK_REL_UPDATE_USER_PROFILE_BY_ID = "update user profile by id";
public static final String LINK_REL_INROLE = "in role";
public static final String LINK_REL_CREATE_USER = "create user";
public static final String LINK_REL_GET_CURRENT_USER = "get current";
public static final String LINK_REL_UPDATE_PASSWORD = "update password";
public static final String LINK_REL_REMOVE_PREFERENCES = "remove preferences";
public static final String LINK_REL_REMOVE_ATTRIBUTES = "remove attributes";
public static final String LINK_REL_GET_USER_BY_ID = "get user by id";
public static final String LINK_REL_GET_USER_BY_EMAIL = "get user by email";
public static final String LINK_REL_REMOVE_USER_BY_ID = "remove user by id";
public static final String LINK_REL_UPDATE_PREFERENCES = "update prefs";
public static final int ID_LENGTH = 16;
public static final int PASSWORD_LENGTH = 10;
/** Profile link relationships. */
public static final String LINK_REL_CURRENT_PROFILE = "current_profile";
public static final String LINK_REL_CURRENT_PROFILE_ATTRIBUTES = "current_profile.attributes";
public static final String LINK_REL_PROFILE = "profile";
public static final String LINK_REL_PROFILE_ATTRIBUTES = "profile.attributes";
private Constants() {
}
/** User links relationships. */
public static final String LINK_REL_USER = "user";
public static final String LINK_REL_CURRENT_USER = "current_user";
public static final String LINK_REL_CURRENT_USER_PASSWORD = "current_user.password";
public static final String LINK_REL_CURRENT_USER_SETTINGS = "current_user.settings";
/** Preferences links relationships. */
public static final String LINK_REL_PREFERENCES = "preferences";
public static final String LINK_REL_SELF = "self";
public static final int ID_LENGTH = 16;
public static final int PASSWORD_LENGTH = 10;
private Constants() {}
}

View File

@ -10,8 +10,8 @@
*******************************************************************************/
package org.eclipse.che.api.user.server;
import org.eclipse.che.api.user.server.dao.User;
import org.eclipse.che.api.user.shared.dto.UserDescriptor;
import org.eclipse.che.api.core.model.user.User;
import org.eclipse.che.api.user.shared.dto.UserDto;
import org.eclipse.che.dto.server.DtoFactory;
/**
@ -22,10 +22,10 @@ import org.eclipse.che.dto.server.DtoFactory;
public final class DtoConverter {
/**
* Converts {@link User} to {@link UserDescriptor}.
* Converts {@link User} to {@link UserDto}.
*/
public static UserDescriptor toDescriptor(User user) {
return DtoFactory.getInstance().createDto(UserDescriptor.class)
public static UserDto asDto(User user) {
return DtoFactory.getInstance().createDto(UserDto.class)
.withId(user.getId())
.withEmail(user.getEmail())
.withName(user.getName())

View File

@ -0,0 +1,176 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server;
import com.google.common.util.concurrent.Striped;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.user.server.spi.PreferenceDao;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import static java.util.Objects.requireNonNull;
/**
* Preferences manager layer, simplifies preferences service by
* taking all the business logic out from the service and making that logic easily
* reusable throughout the system.
*
* <p>The manager doesn't perform any bean validations and it
* is expected that all the incoming objects are valid, nevertheless
* this exactly the right place for performing business validations.
*
* @author Yevhenii Voevodin
*/
@Singleton
public class PreferenceManager {
private static final Striped<Lock> UPDATE_REENTRANT_LOCKS = Striped.lazyWeakLock(32);
@Inject
private PreferenceDao preferenceDao;
/**
* Associates the given {@code preferences} with the given {@code userId}.
*
* <p>Note that this method will override all the existing properties
* for the user with id {@code userId}.
*
* @param userId
* the user id whom the {@code preferences} belong to
* @param preferences
* the preferences to associate with the {@code userId}
* @throws NullPointerException
* when either {@code userId} or {@code preferences} is null
* @throws ServerException
* when any error occurs
*/
public void save(String userId, Map<String, String> preferences) throws ServerException {
requireNonNull(userId, "Required non-null user id");
requireNonNull(preferences, "Required non-null preferences");
preferenceDao.setPreferences(userId, preferences);
}
/**
* Updates the preferences of the user by merging given {@code preferences}
* with the existing preferences. If user doesn't have any preferences
* then the given {@code preferences} will be associated with the user.
*
* @param userId
* the user whose preferences should be updated
* @param preferences
* preferences update
* @return all the user's preferences including the update
* @throws NullPointerException
* when either {@code userId} or {@code preferences} is null
* @throws ServerException
* when any error occurs
*/
public Map<String, String> update(String userId, Map<String, String> preferences) throws ServerException {
requireNonNull(userId, "Required non-null user id");
requireNonNull(preferences, "Required non-null preferences");
// Holding reference to prevent garbage collection
// this reentrantLock helps to avoid race-conditions when parallel updates are applied
final Lock reentrantLock = UPDATE_REENTRANT_LOCKS.get(userId);
reentrantLock.lock();
try {
final Map<String, String> found = preferenceDao.getPreferences(userId);
found.putAll(preferences);
preferenceDao.setPreferences(userId, found);
return found;
} finally {
reentrantLock.unlock();
}
}
/**
* Finds user's preferences.
*
* @param userId
* user id to find preferences
* @return found preferences or empty map, if there are no preferences related to user
* @throws NullPointerException
* when {@code userId} is null
* @throws ServerException
* when any error occurs
*/
public Map<String, String> find(String userId) throws ServerException {
requireNonNull(userId, "Required non-null user id");
return preferenceDao.getPreferences(userId);
}
/**
* Finds user's preferences.
*
* @param userId
* user id to find preferences
* @param keyFilter
* regex which is used to filter preferences by keys, so
* result contains only the user's preferences that match {@code keyFilter} regex
* @return found preferences filtered by {@code keyFilter} or an empty map
* if there are no preferences related to user
* @throws NullPointerException
* when {@code userId} is null
* @throws ServerException
* when any error occurs
*/
public Map<String, String> find(String userId, String keyFilter) throws ServerException {
requireNonNull(userId, "Required non-null user id");
return preferenceDao.getPreferences(userId, keyFilter);
}
/**
* Removes(clears) user's preferences.
*
* @param userId
* the id of the user to remove preferences
* @throws NullPointerException
* when {@code userId} is null
* @throws ServerException
* when any error occurs
*/
public void remove(String userId) throws ServerException {
requireNonNull(userId, "Required non-null user id");
preferenceDao.remove(userId);
}
/**
* Removes the preferences with the given {@code names}.
*
* @param userId
* the id of the user to remove preferences
* @param names
* the names to remove
* @throws NullPointerException
* when either {@code userId} or {@code names} is null
* @throws ServerException
* when any error occurs
*/
public void remove(String userId, List<String> names) throws ServerException {
requireNonNull(userId, "Required non-null user id");
requireNonNull(names, "Required non-null preference names");
// Holding reference to prevent garbage collection
// this reentrantLock helps to avoid race-conditions when parallel updates are applied
final Lock reentrantLock = UPDATE_REENTRANT_LOCKS.get(userId);
reentrantLock.lock();
try {
final Map<String, String> preferences = preferenceDao.getPreferences(userId);
names.forEach(preferences::remove);
preferenceDao.setPreferences(userId, preferences);
} finally {
reentrantLock.unlock();
}
}
}

View File

@ -0,0 +1,124 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.eclipse.che.api.core.BadRequestException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.rest.Service;
import org.eclipse.che.api.core.rest.annotations.GenerateLink;
import org.eclipse.che.commons.env.EnvironmentContext;
import javax.annotation.security.RolesAllowed;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import java.util.List;
import java.util.Map;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_PREFERENCES;
/**
* Preferences REST API.
*
* @author Yevhenii Voevodin
*/
@Path("/preferences")
@Api(value = "/preferences", description = "Preferences REST API")
public class PreferencesService extends Service {
@Inject
private PreferenceManager preferenceManager;
@GET
@Produces(APPLICATION_JSON)
@GenerateLink(rel = LINK_REL_PREFERENCES)
@ApiOperation(value = "Gets preferences of logged in user",
notes = "If not all the preferences needed then 'filter' may be used, " +
"basically it is regex for filtering preferences by names")
@ApiResponses({@ApiResponse(code = 200, message = "Preferences successfully fetched"),
@ApiResponse(code = 500, message = "Internal Server Error")})
public Map<String, String> find(@ApiParam("Regex for filtering preferences by names, e.g. '.*github.*' " +
"will return all the preferences which name contains github")
@QueryParam("filter")
String filter) throws ServerException {
if (filter == null) {
return preferenceManager.find(userId());
}
return preferenceManager.find(userId(), filter);
}
@POST
@Consumes(APPLICATION_JSON)
@GenerateLink(rel = LINK_REL_PREFERENCES)
@ApiOperation(value = "Saves preferences of logged in user",
notes = "All the existing user's preferences will be override by this method")
@ApiResponses({@ApiResponse(code = 204, message = "Preferences successfully saved"),
@ApiResponse(code = 400, message = "Request doesn't contain new preferences"),
@ApiResponse(code = 500, message = "Couldn't save preferences due to internal server error")})
public void save(Map<String, String> preferences) throws BadRequestException, ServerException {
if (preferences == null) {
throw new BadRequestException("Required non-null new preferences");
}
preferenceManager.save(userId(), preferences);
}
@PUT
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@GenerateLink(rel = LINK_REL_PREFERENCES)
@ApiOperation(value = "Updates preferences of logged in user",
notes = "The merge strategy is used for update, which means that " +
"existing preferences with keys equal to update preference keys will " +
"be replaces with new values, and new preferences will be added")
@ApiResponses({@ApiResponse(code = 200, message = "Preferences successfully updated, response contains " +
"all the user preferences"),
@ApiResponse(code = 400, message = "Request doesn't contain preferences update"),
@ApiResponse(code = 500, message = "Couldn't update preferences due to internal server error")})
public Map<String, String> update(Map<String, String> preferences) throws ServerException, BadRequestException {
if (preferences == null) {
throw new BadRequestException("Required non-null preferences update");
}
return preferenceManager.update(userId(), preferences);
}
@DELETE
@Consumes(APPLICATION_JSON)
@GenerateLink(rel = LINK_REL_PREFERENCES)
@ApiOperation(value = "Remove preferences of logged in user.",
notes = "If names are not specified, then all the user's preferences will be removed, " +
"otherwise only the preferences which names are listed")
@ApiResponses({@ApiResponse(code = 204, message = "Preferences successfully removed"),
@ApiResponse(code = 500, message = "Couldn't remove preferences due to internal server error")})
public void removePreferences(@ApiParam("Preferences to remove") List<String> names) throws ServerException {
if (names == null || names.isEmpty()) {
preferenceManager.remove(userId());
} else {
preferenceManager.remove(userId(), names);
}
}
private static String userId() {
return EnvironmentContext.getCurrent().getSubject().getUserId();
}
}

View File

@ -0,0 +1,83 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server;
import org.eclipse.che.api.core.rest.ServiceContext;
import org.eclipse.che.api.core.rest.shared.dto.Link;
import org.eclipse.che.api.user.shared.dto.ProfileDto;
import javax.inject.Singleton;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.UriBuilder;
import java.util.ArrayList;
import java.util.List;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.eclipse.che.api.core.util.LinksHelper.createLink;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_CURRENT_PROFILE;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_CURRENT_PROFILE_ATTRIBUTES;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_PROFILE_ATTRIBUTES;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_SELF;
/**
* Creates and injects links to the {@link ProfileDto} object.
*
* @author Yevhenii Voevodin
*/
@Singleton
public class ProfileLinksInjector {
public ProfileDto injectLinks(ProfileDto profileDto, ServiceContext serviceContext) {
final UriBuilder uriBuilder = serviceContext.getServiceUriBuilder();
final List<Link> links = new ArrayList<>(5);
links.add(createLink(HttpMethod.GET,
uriBuilder.clone()
.path(ProfileService.class, "getCurrent")
.build()
.toString(),
null,
APPLICATION_JSON,
LINK_REL_CURRENT_PROFILE));
links.add(createLink(HttpMethod.GET,
uriBuilder.clone()
.path(ProfileService.class, "getById")
.build(profileDto.getUserId())
.toString(),
null,
APPLICATION_JSON,
LINK_REL_SELF));
links.add(createLink(HttpMethod.PUT,
uriBuilder.clone()
.path(ProfileService.class, "updateAttributes")
.build()
.toString(),
APPLICATION_JSON,
APPLICATION_JSON,
LINK_REL_CURRENT_PROFILE_ATTRIBUTES));
links.add(createLink(HttpMethod.DELETE,
uriBuilder.clone()
.path(ProfileService.class, "removeAttributes")
.build(profileDto.getUserId())
.toString(),
APPLICATION_JSON,
APPLICATION_JSON,
LINK_REL_CURRENT_PROFILE_ATTRIBUTES));
links.add(createLink(HttpMethod.PUT,
uriBuilder.clone()
.path(ProfileService.class, "updateAttributesById")
.build(profileDto.getUserId())
.toString(),
APPLICATION_JSON,
APPLICATION_JSON,
LINK_REL_PROFILE_ATTRIBUTES));
return profileDto.withLinks(links);
}
}

View File

@ -0,0 +1,115 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.user.Profile;
import org.eclipse.che.api.core.model.user.User;
import org.eclipse.che.api.user.server.model.impl.ProfileImpl;
import org.eclipse.che.api.user.server.spi.ProfileDao;
import javax.inject.Inject;
import javax.inject.Singleton;
import static java.util.Objects.requireNonNull;
/**
* Preferences manager layer, simplifies prefernces service by
* taking all the business logic out from the service and making that logic
* easily reusable throughout the system.
*
* <p>The manager doesn't perform any bean validations and it
* is expected that all the incoming objects are valid, nevertheless
* this exactly the right place for performing business validations.
*
* @author Yevhenii Voevodin
*/
@Singleton
public class ProfileManager {
@Inject
private ProfileDao profileDao;
/**
* Finds the profile related to the user with given {@code userId}.
*
* @param userId
* the id to search the user's profile
* @return found profile
* @throws NullPointerException
* when {@code userId} is null
* @throws NotFoundException
* when there is no profile for the user with the id {@code userId}
* @throws ServerException
* when any other error occurs
*/
public Profile getById(String userId) throws NotFoundException, ServerException {
requireNonNull(userId, "Required non-null user id");
return profileDao.getById(userId);
}
/**
* Creates a new user's profile .
*
* @param profile
* new profile
* @throws NullPointerException
* when profile is null
* @throws ConflictException
* when profile for the user {@code profile.getUserId()} already exists
* @throws ServerException
* when any other error occurs
*/
public void create(Profile profile) throws ServerException, ConflictException {
requireNonNull(profile, "Required non-null profile");
profileDao.create(new ProfileImpl(profile));
}
/**
* Updates current profile using replace strategy.
*
* <p>Note that {@link Profile#getEmail()} can't be updated using this method
* as it is mirrored from the {@link User#getEmail()}.
*
* @param profile
* profile update
* @throws NullPointerException
* when {@code profile} is null
* @throws NotFoundException
* when there is no profile for the user with the id {@code profile.getUserId()}
* @throws ServerException
* when any other error occurs
*/
public void update(Profile profile) throws NotFoundException, ServerException {
requireNonNull(profile, "Required non-null profile");
profileDao.update(new ProfileImpl(profile));
}
/**
* Removes the user's profile.
*
* <p>Note that this method won't throw any exception when
* user doesn't have the corresponding profile.
*
* @param userId
* the id of the user, whose profile should be removed
* @throws NullPointerException
* when {@code id} is null
* @throws ServerException
* when any other error occurs
*/
public void remove(String userId) throws ServerException {
requireNonNull(userId, "Required non-null user id");
profileDao.remove(userId);
}
}

View File

@ -0,0 +1,173 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server;
import org.eclipse.che.api.core.BadRequestException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.user.Profile;
import org.eclipse.che.api.core.model.user.User;
import org.eclipse.che.api.core.rest.Service;
import org.eclipse.che.api.core.rest.annotations.GenerateLink;
import org.eclipse.che.api.user.server.model.impl.ProfileImpl;
import org.eclipse.che.api.user.shared.dto.ProfileDto;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.dto.server.DtoFactory;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;
import java.util.List;
import java.util.Map;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_CURRENT_PROFILE;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_CURRENT_PROFILE_ATTRIBUTES;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
/**
* Profile REST API.
*
* @author Yevhenii Voevodin
*/
@Api(value = "/profile", description = "Profile REST API")
@Path("/profile")
public class ProfileService extends Service {
@Inject
private ProfileManager profileManager;
@Inject
private UserManager userManager;
@Inject
private ProfileLinksInjector linksInjector;
@Context
private SecurityContext context;
@GET
@Produces(APPLICATION_JSON)
@GenerateLink(rel = LINK_REL_CURRENT_PROFILE)
@ApiOperation("Get profile of the logged in user")
@ApiResponses({@ApiResponse(code = 200, message = "The response contains requested profile entity"),
@ApiResponse(code = 404, message = "Currently logged in user doesn't have profile"),
@ApiResponse(code = 500, message = "Couldn't retrieve profile due to internal server error")})
public ProfileDto getCurrent() throws ServerException, NotFoundException {
final ProfileImpl profile = new ProfileImpl(profileManager.getById(userId()));
return linksInjector.injectLinks(asDto(profile, userManager.getById(profile.getUserId())), getServiceContext());
}
@GET
@Path("/{id}")
@Produces(APPLICATION_JSON)
@GenerateLink(rel = LINK_REL_CURRENT_PROFILE)
@ApiOperation("Get profile by user's id")
@ApiResponses({@ApiResponse(code = 200, message = "The response contains requested profile entity"),
@ApiResponse(code = 404, message = "Profile for the user with requested identifier doesn't exist"),
@ApiResponse(code = 500, message = "Couldn't retrieve profile due to internal server error")})
public ProfileDto getById(@ApiParam("User identifier")
@PathParam("id")
String userId) throws NotFoundException, ServerException {
return linksInjector.injectLinks(asDto(profileManager.getById(userId), userManager.getById(userId)), getServiceContext());
}
@PUT
@Path("/{id}/attributes")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Update the profile attributes of the user with requested identifier",
notes = "The replace strategy is used for the update, so all the existing profile " +
"attributes will be override by the profile update")
@ApiResponses({@ApiResponse(code = 200, message = "The profile successfully updated and the response contains " +
"newly updated profile entity"),
@ApiResponse(code = 404, message = "When profile for the user with requested identifier doesn't exist"),
@ApiResponse(code = 500, message = "Couldn't retrieve profile due to internal server error")})
public ProfileDto updateAttributesById(@ApiParam("Id of the user")
@PathParam("id")
String userId,
@ApiParam("New profile attributes")
Map<String, String> updates) throws NotFoundException,
ServerException,
BadRequestException {
if (updates == null) {
throw new BadRequestException("Update attributes required");
}
final ProfileImpl profile = new ProfileImpl(profileManager.getById(userId));
profile.setAttributes(updates);
profileManager.update(profile);
return linksInjector.injectLinks(asDto(profile, userManager.getById(userId)), getServiceContext());
}
@PUT
@Path("/attributes")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@GenerateLink(rel = LINK_REL_CURRENT_PROFILE_ATTRIBUTES)
@ApiOperation(value = "Update the profile attributes of the currently logged in user",
notes = "The replace strategy is used for the update, so all the existing profile " +
"attributes will be override with incoming values")
public ProfileDto updateAttributes(@ApiParam("New profile attributes")
Map<String, String> updates) throws NotFoundException,
ServerException,
BadRequestException {
if (updates == null) {
throw new BadRequestException("Update attributes required");
}
final ProfileImpl profile = new ProfileImpl(profileManager.getById(userId()));
profile.setAttributes(updates);
profileManager.update(profile);
return linksInjector.injectLinks(asDto(profile, userManager.getById(profile.getUserId())), getServiceContext());
}
@DELETE
@Path("/attributes")
@GenerateLink(rel = LINK_REL_CURRENT_PROFILE_ATTRIBUTES)
@Consumes(APPLICATION_JSON)
@ApiOperation(value = "Remove profile attributes which names are equal to given",
notes = "If names list is not send, all the attributes will be removed, " +
"if there are no attributes which names equal to some of the given names, " +
"then those names are skipped.")
@ApiResponses({@ApiResponse(code = 204, message = "Attributes successfully removed"),
@ApiResponse(code = 500, message = "Couldn't remove attributes due to internal server error")})
public void removeAttributes(@ApiParam("The names of the profile attributes to remove")
List<String> names) throws NotFoundException, ServerException {
final Profile profile = profileManager.getById(userId());
final Map<String, String> attributes = profile.getAttributes();
if (names == null) {
attributes.clear();
} else {
names.forEach(attributes::remove);
}
profileManager.update(profile);
}
private static ProfileDto asDto(Profile profile, User user) {
return DtoFactory.newDto(ProfileDto.class)
.withUserId(profile.getUserId())
.withEmail(user.getEmail())
.withAttributes(profile.getAttributes());
}
private static String userId() {
return EnvironmentContext.getCurrent().getSubject().getUserId();
}
}

View File

@ -11,7 +11,7 @@
package org.eclipse.che.api.user.server;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.user.server.dao.User;
import org.eclipse.che.api.core.model.user.User;
/**
* Validates token.
@ -22,7 +22,7 @@ import org.eclipse.che.api.user.server.dao.User;
public interface TokenValidator {
/**
* Validates {@param token}
* Validates {@code token}.
*
* @return user email
* @throws ConflictException

View File

@ -13,96 +13,88 @@ package org.eclipse.che.api.user.server;
import org.eclipse.che.api.core.rest.ServiceContext;
import org.eclipse.che.api.core.rest.shared.dto.Link;
import org.eclipse.che.api.core.util.LinksHelper;
import org.eclipse.che.api.user.shared.dto.UserDescriptor;
import org.eclipse.che.api.user.shared.dto.UserDto;
import javax.inject.Singleton;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.UriBuilder;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.List;
import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_GET_CURRENT_USER;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_GET_CURRENT_USER_PROFILE;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_GET_USER_BY_EMAIL;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_GET_USER_BY_ID;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_GET_USER_PROFILE_BY_ID;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_REMOVE_USER_BY_ID;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_UPDATE_PASSWORD;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_CURRENT_USER;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_CURRENT_USER_PASSWORD;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_CURRENT_USER_SETTINGS;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_PREFERENCES;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_PROFILE;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_SELF;
/**
* Helps to inject {@link UserService} related links.
*
* @author Anatoliy Bazko
* @author Yevhenii Voevodin
*/
public final class LinksInjector {
@Singleton
public class UserLinksInjector {
public static UserDescriptor injectLinks(UserDescriptor userDescriptor, ServiceContext serviceContext) {
public UserDto injectLinks(UserDto userDto, ServiceContext serviceContext) {
final UriBuilder uriBuilder = serviceContext.getBaseUriBuilder();
final List<Link> links = new LinkedList<>();
final List<Link> links = new ArrayList<>(6);
links.add(LinksHelper.createLink(HttpMethod.GET,
uriBuilder.clone().path(UserProfileService.class)
.path(UserProfileService.class, "getCurrent")
.build()
uriBuilder.clone()
.path(UserService.class)
.path(UserService.class, "getById")
.build(userDto.getId())
.toString(),
null,
APPLICATION_JSON,
LINK_REL_GET_CURRENT_USER_PROFILE));
LINK_REL_SELF));
links.add(LinksHelper.createLink(HttpMethod.GET,
uriBuilder.clone().path(UserService.class)
uriBuilder.clone()
.path(UserService.class)
.path(UserService.class, "getCurrent")
.build()
.toString(),
null,
APPLICATION_JSON,
LINK_REL_GET_CURRENT_USER));
LINK_REL_CURRENT_USER));
links.add(LinksHelper.createLink(HttpMethod.POST,
uriBuilder.clone().path(UserService.class)
uriBuilder.clone()
.path(UserService.class)
.path(UserService.class, "updatePassword")
.build()
.toString(),
APPLICATION_FORM_URLENCODED,
null,
LINK_REL_UPDATE_PASSWORD));
LINK_REL_CURRENT_USER_PASSWORD));
links.add(LinksHelper.createLink(HttpMethod.GET,
uriBuilder.clone().path(UserService.class)
.path(UserService.class, "getById")
.build(userDescriptor.getId())
uriBuilder.clone()
.path(ProfileService.class)
.path(ProfileService.class, "getById")
.build(userDto.getId())
.toString(),
null,
APPLICATION_JSON,
LINK_REL_GET_USER_BY_ID));
LINK_REL_PROFILE));
links.add(LinksHelper.createLink(HttpMethod.GET,
uriBuilder.clone().path(UserProfileService.class)
.path(UserProfileService.class, "getById")
.build(userDescriptor.getId())
uriBuilder.clone()
.path(UserService.class)
.path(UserService.class, "getSettings")
.build()
.toString(),
null,
APPLICATION_JSON,
LINK_REL_GET_USER_PROFILE_BY_ID));
if (userDescriptor.getEmail() != null) {
links.add(LinksHelper.createLink(HttpMethod.GET,
uriBuilder.clone().path(UserService.class)
.path(UserService.class, "getByAlias")
.queryParam("email", userDescriptor.getEmail())
.build()
.toString(),
null,
APPLICATION_JSON,
LINK_REL_GET_USER_BY_EMAIL));
}
links.add(LinksHelper.createLink(HttpMethod.DELETE,
uriBuilder.clone().path(UserService.class)
.path(UserService.class, "remove")
.build(userDescriptor.getId())
LINK_REL_CURRENT_USER_SETTINGS));
links.add(LinksHelper.createLink(HttpMethod.GET,
uriBuilder.clone().path(PreferencesService.class)
.path(PreferencesService.class, "find")
.build()
.toString(),
null,
null,
LINK_REL_REMOVE_USER_BY_ID));
return userDescriptor.withLinks(links);
APPLICATION_JSON,
LINK_REL_PREFERENCES));
return userDto.withLinks(links);
}
private LinksInjector() {}
}

View File

@ -10,167 +10,218 @@
*******************************************************************************/
package org.eclipse.che.api.user.server;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.user.server.dao.PreferenceDao;
import org.eclipse.che.api.user.server.dao.Profile;
import org.eclipse.che.api.user.server.dao.User;
import org.eclipse.che.api.user.server.dao.UserDao;
import org.eclipse.che.api.user.server.dao.UserProfileDao;
import org.eclipse.che.api.core.model.user.Profile;
import org.eclipse.che.api.core.model.user.User;
import org.eclipse.che.api.user.server.model.impl.ProfileImpl;
import org.eclipse.che.api.user.server.spi.PreferenceDao;
import org.eclipse.che.api.user.server.spi.ProfileDao;
import org.eclipse.che.api.user.server.spi.UserDao;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.MoreObjects.firstNonNull;
import static java.lang.String.format;
import static java.lang.System.currentTimeMillis;
import static java.util.Objects.requireNonNull;
import static org.eclipse.che.api.user.server.Constants.ID_LENGTH;
import static org.eclipse.che.api.user.server.Constants.PASSWORD_LENGTH;
import static org.eclipse.che.commons.lang.NameGenerator.generate;
/**
* Facade for User related operations.
* Facade for {@link User} and {@link Profile} related operations.
*
* @author Max Shaposhnik (mshaposhnik@codenvy.com)
* @author Yevhenii Voevodin
*/
@Singleton
public class UserManager {
private static final Logger LOG = LoggerFactory.getLogger(UserManager.class);
private final UserDao userDao;
private final UserProfileDao profileDao;
private final PreferenceDao preferenceDao;
private final Set<String> reservedNames;
private final UserDao userDao;
private final ProfileDao profileDao;
private final PreferenceDao preferencesDao;
private final Set<String> reservedNames;
@Inject
public UserManager(UserDao userDao,
UserProfileDao profileDao,
PreferenceDao preferenceDao,
ProfileDao profileDao,
PreferenceDao preferencesDao,
@Named("user.reserved_names") String[] reservedNames) {
this.userDao = userDao;
this.profileDao = profileDao;
this.preferenceDao = preferenceDao;
this.preferencesDao = preferencesDao;
this.reservedNames = Sets.newHashSet(reservedNames);
}
/**
* Creates new user.
* Creates new user and his profile.
*
* @param user
* POJO representation of user entity
* @param newUser
* created user
* @throws NullPointerException
* when {@code newUser} is null
* @throws ConflictException
* when given user cannot be created
* when user with such name/email/alias already exists
* @throws ServerException
* when any other error occurs
*/
public void create(User user, boolean isTemporary) throws ConflictException, ServerException {
if (reservedNames.contains(user.getName().toLowerCase())) {
throw new ConflictException(String.format("Username \"%s\" is reserved", user.getName()));
public User create(User newUser, boolean isTemporary) throws ConflictException, ServerException {
requireNonNull(newUser, "Required non-null user");
if (reservedNames.contains(newUser.getName().toLowerCase())) {
throw new ConflictException(String.format("Username '%s' is reserved", newUser.getName()));
}
user.withId(generate("user", ID_LENGTH))
.withPassword(firstNonNull(user.getPassword(), generate("", PASSWORD_LENGTH)));
userDao.create(user);
profileDao.create(new Profile(user.getId()));
final Map<String, String> preferences = new HashMap<>(4);
preferences.put("temporary", Boolean.toString(isTemporary));
preferences.put("codenvy:created", Long.toString(System.currentTimeMillis()));
final UserImpl user = new UserImpl(generate("user", ID_LENGTH),
newUser.getEmail(),
newUser.getName(),
firstNonNull(newUser.getPassword(), generate("", PASSWORD_LENGTH)),
newUser.getAliases());
try {
preferenceDao.setPreferences(user.getId(), preferences);
} catch (NotFoundException e) {
LOG.warn(format("Cannot set creation time preferences for user %s.", user.getId()), e);
userDao.create(user);
profileDao.create(new ProfileImpl(user.getId()));
preferencesDao.setPreferences(user.getId(), ImmutableMap.of("temporary", Boolean.toString(isTemporary),
"codenvy:created", Long.toString(currentTimeMillis())));
} catch (ConflictException | ServerException x) {
// optimistic rollback(won't remove profile if userDao.remove failed)
// remove operation is not-found-safe so if any exception
// during the either user or profile creation occurs remove all entities
// NOTE: this logic must be replaced with transaction management
try {
userDao.remove(user.getId());
profileDao.remove(user.getId());
preferencesDao.remove(user.getId());
} catch (ConflictException | ServerException rollbackEx) {
LOG.error(format("An attempt to clean up resources due to user creation failure was unsuccessful." +
"Now the system may be in inconsistent state. " +
"User with id '%s' must not exist",
user.getId()),
rollbackEx);
}
throw x;
}
return user;
}
/**
* Updates user by replacing an existing user entity with a new one.
*
* @param user
* user update
* @throws NullPointerException
* when {@code user} is null
* @throws NotFoundException
* when user with id {@code user.getId()} is not found
* @throws ConflictException
* when user's new alias/email/name is not unique
* @throws ServerException
* when any other error occurs
*/
public void update(User user) throws NotFoundException, ServerException, ConflictException {
requireNonNull(user, "Required non-null user");
userDao.update(new UserImpl(user));
}
/**
* Gets user from persistent layer by his identifier
* Finds user by given {@code id}.
*
* @param id
* user identifier
* @return user POJO
* @return user instance
* @throws NullPointerException
* when {@code id} is null
* @throws NotFoundException
* when user doesn't exist
* @throws ServerException
* when any other error occurs
*/
public User getById(String id) throws NotFoundException, ServerException {
requireNonNull(id, "Required non-null id");
return userDao.getById(id);
}
/**
* Updates already present in persistent layer user.
*
* @param user
* POJO representation of user entity
* @throws NotFoundException
* when user is not found
* @throws ConflictException
* when given user cannot be updated
* @throws ServerException
* when any other error occurs
*
*/
public void update(User user) throws NotFoundException, ServerException, ConflictException {
userDao.update(user);
}
/**
* Gets user from persistent layer by any of his aliases
* Finds user by given {@code alias}.
*
* @param alias
* user name or alias
* @return user POJO
* user alias
* @return user instance
* @throws NullPointerException
* when {@code alias} is null
* @throws NotFoundException
* when user doesn't exist
* @throws ServerException
* when any other error occurs
*/
public User getByAlias(String alias) throws NotFoundException, ServerException {
requireNonNull(alias, "Required non-null alias");
return userDao.getByAlias(alias);
}
/**
* Gets user from persistent layer by his username
* Finds user by given {@code name}.
*
* @param userName
* @param name
* user name
* @return user POJO
* @return user instance
* @throws NullPointerException
* when {@code name} is null
* @throws NotFoundException
* when user doesn't exist
* @throws ServerException
* when any other error occurs
*/
public User getByName(String userName) throws NotFoundException, ServerException {
return userDao.getByName(userName);
public User getByName(String name) throws NotFoundException, ServerException {
requireNonNull(name, "Required non-null name");
return userDao.getByName(name);
}
/**
* Finds user by given {@code email}.
*
* @param email
* user email
* @return user instance
* @throws NullPointerException
* when {@code email} is null
* @throws NotFoundException
* when user doesn't exist
* @throws ServerException
* when any other error occurs
*/
public User getByEmail(String email) throws NotFoundException, ServerException {
requireNonNull(email, "Required non-null email");
return userDao.getByEmail(email);
}
/**
* Removes user from persistent layer by his identifier.
* Removes user and his dependencies by given {@code id}.
*
* @param id
* user identifier
* @throws NullPointerException
* when {@code id} is null
* @throws ConflictException
* when given user cannot be deleted
* @throws ServerException
* when any other error occurs
*/
public void remove(String id) throws NotFoundException, ServerException, ConflictException {
public void remove(String id) throws ServerException, ConflictException {
requireNonNull(id, "Required non-null id");
profileDao.remove(id);
preferencesDao.remove(id);
userDao.remove(id);
}
}

View File

@ -1,442 +0,0 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import com.google.common.util.concurrent.Striped;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.rest.Service;
import org.eclipse.che.api.core.rest.annotations.Description;
import org.eclipse.che.api.core.rest.annotations.GenerateLink;
import org.eclipse.che.api.core.rest.annotations.Required;
import org.eclipse.che.api.core.rest.shared.dto.Link;
import org.eclipse.che.api.core.util.LinksHelper;
import org.eclipse.che.api.user.server.dao.PreferenceDao;
import org.eclipse.che.api.user.server.dao.Profile;
import org.eclipse.che.api.user.server.dao.User;
import org.eclipse.che.api.user.server.dao.UserDao;
import org.eclipse.che.api.user.server.dao.UserProfileDao;
import org.eclipse.che.api.user.shared.dto.ProfileDescriptor;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.commons.subject.Subject;
import org.eclipse.che.dto.server.DtoFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.UriBuilder;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.Lock;
import static com.google.common.base.Strings.nullToEmpty;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_GET_CURRENT_USER_PROFILE;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_GET_USER_PROFILE_BY_ID;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_REMOVE_ATTRIBUTES;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_REMOVE_PREFERENCES;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_UPDATE_CURRENT_USER_PROFILE;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_UPDATE_PREFERENCES;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_UPDATE_USER_PROFILE_BY_ID;
/**
* User Profile API
*
* @author Eugene Voevodin
* @author Max Shaposhnik
*/
@Api(value = "/profile",
description = "User profile manager")
@Path("/profile")
public class UserProfileService extends Service {
private static final Logger LOG = LoggerFactory.getLogger(UserProfileService.class);
// Assuming 1000 concurrent users at most trying to update their preferences (if more they will wait for another user to finish).
// Using the lazy weak version of Striped so the locks will be created on demand and not eagerly, and garbage collected when not needed anymore.
private static final Striped<Lock> preferencesUpdateLocksByUser = Striped.lazyWeakLock(1000);
private final UserProfileDao profileDao;
private final UserDao userDao;
private final PreferenceDao preferenceDao;
@Inject
public UserProfileService(UserProfileDao profileDao, PreferenceDao preferenceDao, UserDao userDao) {
this.profileDao = profileDao;
this.userDao = userDao;
this.preferenceDao = preferenceDao;
}
/**
* <p>Returns {@link ProfileDescriptor} for current user profile.</p>
* <p>By default user email will be added to attributes with key <i>'email'</i>.</p>
*
* @return descriptor of profile
* @throws ServerException
* when some error occurred while retrieving/updating profile
* @see ProfileDescriptor
* @see #updateCurrent(Map)
*/
@ApiOperation(value = "Get user profile",
notes = "Get user profile details.",
response = ProfileDescriptor.class)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 500, message = "Internal Server Error")})
@GET
@GenerateLink(rel = LINK_REL_GET_CURRENT_USER_PROFILE)
@Produces(APPLICATION_JSON)
public ProfileDescriptor getCurrent() throws NotFoundException, ServerException {
final User user = userDao.getById(currentUser().getUserId());
final Profile profile = profileDao.getById(user.getId());
profile.getAttributes().put("email", user.getEmail());
return toDescriptor(profile);
}
/**
* Returns preferences for current user
*/
@ApiOperation(value = "Get user preferences",
notes = "Get user preferences, like SSH keys, recently opened project and files. It is possible " +
"to use a filter, e.g. CodenvyAppState or ssh.key.public.github.com to get the last opened project " +
"or a public part of GitHub SSH key (if any)",
response = ProfileDescriptor.class)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 500, message = "Internal Server Error")})
@GET
@Path("/prefs")
@Produces(APPLICATION_JSON)
public Map<String, String> getPreferences(@ApiParam(value = "Filer")
@QueryParam("filter") String filter) throws ServerException {
if (filter != null) {
return preferenceDao.getPreferences(currentUser().getUserId(), filter);
}
return preferenceDao.getPreferences(currentUser().getUserId());
}
/**
* Updates attributes of current user profile.
*
* @param updates
* attributes to update
* @return descriptor of updated profile
* @throws ServerException
* when some error occurred while retrieving/persisting profile
* @see ProfileDescriptor
*/
@POST
@GenerateLink(rel = LINK_REL_UPDATE_CURRENT_USER_PROFILE)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public ProfileDescriptor updateCurrent(@Description("attributes to update") Map<String, String> updates)
throws NotFoundException, ServerException, ConflictException {
if (updates == null || updates.isEmpty()) {
throw new ConflictException("Attributes to update required");
}
final User user = userDao.getById(currentUser().getUserId());
final Profile profile = profileDao.getById(user.getId());
profile.getAttributes().putAll(updates);
profileDao.update(profile);
logEventUserUpdateProfile(user, profile.getAttributes());
return toDescriptor(profile);
}
/**
* Updates attributes of certain profile.
*
* @param profileId
* profile identifier
* @param updates
* attributes to update
* @return descriptor of updated profile
* @throws NotFoundException
* when profile with given identifier doesn't exist
* @throws ServerException
* when some error occurred while retrieving/updating profile
* @see ProfileDescriptor
* @see #getById(String)
*/
@POST
@Path("/{id}")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public ProfileDescriptor update(@PathParam("id") String profileId,
Map<String, String> updates) throws NotFoundException, ServerException, ConflictException {
if (updates == null || updates.isEmpty()) {
throw new ConflictException("Attributes to update required");
}
final Profile profile = profileDao.getById(profileId);
profile.getAttributes().putAll(updates);
profileDao.update(profile);
final User user = userDao.getById(profile.getUserId());
logEventUserUpdateProfile(user, profile.getAttributes());
return toDescriptor(profile);
}
/**
* Searches for profile with given identifier and {@link ProfileDescriptor} if found.
*
* @param profileId
* profile identifier
* @return descriptor of found profile
* @throws NotFoundException
* when profile with given identifier doesn't exist
* @throws ServerException
* when some error occurred while retrieving user or profile
* @see ProfileDescriptor
* @see #getById(String)
*/
@ApiOperation(value = "Get profile of a specific user",
notes = "Get profile of a specific user",
response = ProfileDescriptor.class)
@ApiResponses(value = {
@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 500, message = "Internal Server Error")})
@GET
@Path("/{id}")
@Produces(APPLICATION_JSON)
public ProfileDescriptor getById(@ApiParam(value = " ID")
@PathParam("id")
String profileId) throws NotFoundException, ServerException {
final Profile profile = profileDao.getById(profileId);
final User user = userDao.getById(profile.getUserId());
profile.getAttributes().put("email", user.getEmail());
return toDescriptor(profile);
}
/**
* <p>Updates preferences of current user profile.</p>
*
* @param update
* update preferences
* @return descriptor of updated profile
* @throws ServerException
* when some error occurred while retrieving/updating profile
* @throws ConflictException
* when update is {@code null} or <i>empty</i>
* @see ProfileDescriptor
* @see #updateCurrent(Map)
*/
@POST
@Path("/prefs")
@GenerateLink(rel = LINK_REL_UPDATE_PREFERENCES)
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
public Map<String, String> updatePreferences(@Required Map<String, String> update) throws NotFoundException,
ServerException,
ConflictException {
if (update == null || update.isEmpty()) {
throw new ConflictException("Preferences to update required");
}
String userId = currentUser().getUserId();
// Keep the lock in a variable so it isn't garbage collected while in use
Lock lock = preferencesUpdateLocksByUser.get(userId);
lock.lock();
try {
final Map<String, String> preferences = preferenceDao.getPreferences(userId);
preferences.putAll(update);
preferenceDao.setPreferences(currentUser().getUserId(), preferences);
return preferences;
} finally {
lock.unlock();
}
}
/**
* Removes attributes with given names from current user profile.
* If names are {@code null} - all attributes will be removed
*
* @param attrNames
* attributes names to remove
* @throws ConflictException
* when given list of attributes names is {@code null}
* @throws ServerException
* when some error occurred while retrieving/updating profile
*/
@ApiOperation(value = "Remove attributes of a current user",
notes = "Remove attributes of a current user",
position = 6)
@ApiResponses(value = {
@ApiResponse(code = 204, message = "OK"),
@ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 409, message = "Attributes names required"),
@ApiResponse(code = 500, message = "Internal Server Error")})
@DELETE
@Path("/attributes")
@GenerateLink(rel = LINK_REL_REMOVE_ATTRIBUTES)
@Consumes(APPLICATION_JSON)
public void removeAttributes(@ApiParam(value = "Attributes", required = true)
@Required
@Description("Attributes names to remove")
List<String> attrNames) throws NotFoundException, ServerException, ConflictException {
final Profile currentProfile = profileDao.getById(currentUser().getUserId());
if (attrNames == null) {
currentProfile.getAttributes().clear();
} else {
for (String attributeName : attrNames) {
currentProfile.getAttributes().remove(attributeName);
}
}
profileDao.update(currentProfile);
}
/**
* Removes preferences with given name from current user profile.
* If names are {@code null} - all preferences will be removed
*
* @param names
* preferences names to remove
* @throws ServerException
* when some error occurred while retrieving/updating profile
* @see #removeAttributes(List)
*/
@ApiOperation(value = "Remove profile references of a current user",
notes = "Remove profile references of a current user",
position = 7)
@ApiResponses(value = {
@ApiResponse(code = 204, message = "OK"),
@ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 409, message = "Preferences names required"),
@ApiResponse(code = 500, message = "Internal Server Error")})
@DELETE
@Path("/prefs")
@GenerateLink(rel = LINK_REL_REMOVE_PREFERENCES)
@Consumes(APPLICATION_JSON)
public void removePreferences(@ApiParam(value = "Preferences to remove", required = true)
@Required
List<String> names) throws ServerException, NotFoundException {
String userId = currentUser().getUserId();
if (names == null) {
preferenceDao.remove(userId);
} else {
// Keep the lock in a variable so it isn't garbage collected while in use
Lock lock = preferencesUpdateLocksByUser.get(userId);
lock.lock();
try {
final Map<String, String> preferences = preferenceDao.getPreferences(userId);
for (String name : names) {
preferences.remove(name);
}
preferenceDao.setPreferences(userId, preferences);
} finally {
lock.unlock();
}
}
}
/**
* Converts {@link Profile} to {@link ProfileDescriptor}
*/
/* package-private used in tests*/ProfileDescriptor toDescriptor(Profile profile) {
final UriBuilder uriBuilder = getServiceContext().getServiceUriBuilder();
final List<Link> links = new LinkedList<>();
links.add(LinksHelper.createLink(HttpMethod.GET,
uriBuilder.clone()
.path(getClass(), "getCurrent")
.build()
.toString(),
null,
APPLICATION_JSON,
LINK_REL_GET_CURRENT_USER_PROFILE));
links.add(LinksHelper.createLink(HttpMethod.GET,
uriBuilder.clone()
.path(getClass(), "getById")
.build(profile.getId())
.toString(),
null,
APPLICATION_JSON,
LINK_REL_GET_USER_PROFILE_BY_ID));
links.add(LinksHelper.createLink(HttpMethod.POST,
uriBuilder.clone()
.path(getClass(), "updateCurrent")
.build()
.toString(),
APPLICATION_JSON,
APPLICATION_JSON,
LINK_REL_UPDATE_CURRENT_USER_PROFILE));
links.add(LinksHelper.createLink(HttpMethod.POST,
uriBuilder.clone()
.path(getClass(), "updatePreferences")
.build()
.toString(),
APPLICATION_JSON,
APPLICATION_JSON,
LINK_REL_UPDATE_PREFERENCES));
links.add(LinksHelper.createLink(HttpMethod.GET,
uriBuilder.clone()
.path(getClass(), "getById")
.build(profile.getId())
.toString(),
null,
APPLICATION_JSON,
LINK_REL_GET_USER_PROFILE_BY_ID));
links.add(LinksHelper.createLink(HttpMethod.POST,
uriBuilder.clone()
.path(getClass(), "update")
.build(profile.getId())
.toString(),
APPLICATION_JSON,
APPLICATION_JSON,
LINK_REL_UPDATE_USER_PROFILE_BY_ID));
return DtoFactory.newDto(ProfileDescriptor.class)
.withId(profile.getId())
.withUserId(profile.getUserId())
.withAttributes(profile.getAttributes())
.withLinks(links);
}
private Subject currentUser() {
return EnvironmentContext.getCurrent().getSubject();
}
private void logEventUserUpdateProfile(User user, Map<String, String> attributes) {
final Set<String> emails = new HashSet<>(user.getAliases());
emails.add(user.getEmail());
LOG.info("EVENT#user-update-profile# USER#{}# FIRSTNAME#{}# LASTNAME#{}# COMPANY#{}# PHONE#{}# JOBTITLE#{}# EMAILS#{}# USER-ID#{}#",
user.getEmail(),
nullToEmpty(attributes.get("firstName")),
nullToEmpty(attributes.get("lastName")),
nullToEmpty(attributes.get("employer")),
nullToEmpty(attributes.get("phone")),
nullToEmpty(attributes.get("jobtitle")),
user.getAliases(),
user.getId());
}
}

View File

@ -20,15 +20,14 @@ import com.google.common.collect.ImmutableMap;
import org.eclipse.che.api.core.BadRequestException;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.ForbiddenException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.UnauthorizedException;
import org.eclipse.che.api.core.model.user.User;
import org.eclipse.che.api.core.rest.Service;
import org.eclipse.che.api.core.rest.annotations.GenerateLink;
import org.eclipse.che.api.core.rest.annotations.Required;
import org.eclipse.che.api.user.server.dao.User;
import org.eclipse.che.api.user.shared.dto.UserDescriptor;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
import org.eclipse.che.api.user.shared.dto.UserDto;
import org.eclipse.che.commons.env.EnvironmentContext;
import javax.inject.Inject;
@ -46,301 +45,162 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import java.util.Map;
import static com.google.common.base.Strings.isNullOrEmpty;
import static javax.ws.rs.core.MediaType.APPLICATION_FORM_URLENCODED;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static javax.ws.rs.core.Response.Status.CREATED;
import static javax.ws.rs.core.Response.status;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_CREATE_USER;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_GET_CURRENT_USER;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_GET_USER_BY_EMAIL;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_GET_USER_BY_ID;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_REMOVE_USER_BY_ID;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_UPDATE_PASSWORD;
import static org.eclipse.che.api.user.server.DtoConverter.toDescriptor;
import static org.eclipse.che.api.user.server.LinksInjector.injectLinks;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_CURRENT_USER;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_CURRENT_USER_PASSWORD;
import static org.eclipse.che.api.user.server.Constants.LINK_REL_USER;
import static org.eclipse.che.api.user.server.DtoConverter.asDto;
/**
* Provides REST API for user management
* User REST API.
*
* @author Eugene Voevodin
* @author Yevhenii Voevodin
* @author Anton Korneta
*/
@Api(value = "/user", description = "User manager")
@Path("/user")
@Api(value = "/user", description = "User REST API")
public class UserService extends Service {
public static final String USER_SELF_CREATION_ALLOWED = "user.self.creation.allowed";
private final UserManager userManager;
private final TokenValidator tokenValidator;
private final UserNameValidator userNameValidator;
private final UserLinksInjector linksInjector;
private final UserValidator userValidator;
private final boolean userSelfCreationAllowed;
@Inject
public UserService(UserManager userManager,
TokenValidator tokenValidator,
UserNameValidator userNameValidator,
UserValidator userNameValidator,
UserLinksInjector linksInjector,
@Named(USER_SELF_CREATION_ALLOWED) boolean userSelfCreationAllowed) {
this.userManager = userManager;
this.linksInjector = linksInjector;
this.tokenValidator = tokenValidator;
this.userNameValidator = userNameValidator;
this.userValidator = userNameValidator;
this.userSelfCreationAllowed = userSelfCreationAllowed;
}
/**
* Creates new user and profile.
*
* <p>User will be created from {@code token} parameter or from {@code userDescriptor}
* when {@code token} is null
*
* @param token
* authentication token
* @param isTemporary
* if it is {@code true} creates temporary user
* @return entity of created user
* @throws ForbiddenException
* when the user is not the system admin, or self creation is disabled
* @throws BadRequestException
* when {@code userDescriptor} is invalid
* @throws UnauthorizedException
* when token is null
* @throws ConflictException
* when token is not valid
* @throws ServerException
* when some error occurred while persisting user or user profile
* @see UserDescriptor
* @see #getCurrent()
* @see #updatePassword(String)
* @see #getById(String)
* @see #getByAlias(String)
* @see #remove(String)
*/
@POST
@Path("/create")
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@GenerateLink(rel = LINK_REL_CREATE_USER)
@ApiOperation(value = "Create a new user",
notes = "Create a new user in the system. There are two ways to create a user: " +
"through a regular registration workflow when auth token is sent to user's mailbox" +
"and directly with predefined name and password. ",
response = UserDescriptor.class)
@ApiResponses({@ApiResponse(code = 201, message = "Created"),
@GenerateLink(rel = LINK_REL_USER)
@ApiOperation(value = "Create a new user", response = UserDto.class)
@ApiResponses({@ApiResponse(code = 201, message = "User successfully created, response contains created entity"),
@ApiResponse(code = 400, message = "Missed required parameters, parameters are not valid"),
@ApiResponse(code = 401, message = "Missed token parameter"),
@ApiResponse(code = 403, message = "Invalid or missing request parameters"),
@ApiResponse(code = 409, message = "Invalid token"),
@ApiResponse(code = 500, message = "Internal Server Error")})
public Response create(@ApiParam(value = "New user")
UserDescriptor userDescriptor,
@ApiParam(value = "Authentication token")
@ApiResponse(code = 500, message = "Couldn't create user due to internal server error")})
public Response create(@ApiParam("New user")
UserDto userDto,
@ApiParam("Authentication token")
@QueryParam("token")
String token,
@ApiParam(value = "User type")
@ApiParam("User type")
@QueryParam("temporary")
@DefaultValue("false")
Boolean isTemporary) throws ForbiddenException,
BadRequestException,
Boolean isTemporary) throws BadRequestException,
UnauthorizedException,
ConflictException,
ServerException,
NotFoundException {
final User user = isNullOrEmpty(token) ? fromEntity(userDescriptor) : fromToken(token);
if (!userNameValidator.isValidUserName(user.getName())) {
throw new BadRequestException("Username must contain only letters and digits");
}
userManager.create(user, isTemporary);
return status(CREATED).entity(injectLinks(toDescriptor(user), getServiceContext())).build();
ServerException {
final User newUser = token == null ? userDto : tokenValidator.validateToken(token);
userValidator.checkUser(newUser);
return Response.status(CREATED)
.entity(linksInjector.injectLinks(asDto(userManager.create(newUser, isTemporary)), getServiceContext()))
.build();
}
/**
* Returns {@link UserDescriptor} of current user.
*
* @return entity of current user.
* @throws NotFoundException
* when current user not found
* @throws ServerException
* when some error occurred while retrieving current user
*/
@GET
@GenerateLink(rel = LINK_REL_GET_CURRENT_USER)
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Get current user",
notes = "Get user currently logged in the system",
response = UserDescriptor.class,
position = 2)
@ApiResponses({@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 500, message = "Internal Server Error")})
public UserDescriptor getCurrent() throws NotFoundException, ServerException {
final User user = userManager.getById(currentUserId());
return injectLinks(toDescriptor(user), getServiceContext());
@GenerateLink(rel = LINK_REL_CURRENT_USER)
@ApiOperation("Get logged in user")
@ApiResponses({@ApiResponse(code = 200, message = "The response contains currently logged in user entity"),
@ApiResponse(code = 500, message = "Couldn't get user due to internal server error")})
public UserDto getCurrent() throws NotFoundException, ServerException {
final User user = userManager.getById(userId());
return linksInjector.injectLinks(asDto(user), getServiceContext());
}
/**
* Updates current user password.
*
* @param password
* new user password
* @throws NotFoundException
* when current user not found
* @throws BadRequestException
* when given password is invalid
* @throws ServerException
* when some error occurred while updating profile
* @see UserDescriptor
*/
@POST
@Path("/password")
@GenerateLink(rel = LINK_REL_UPDATE_PASSWORD)
@Consumes(APPLICATION_FORM_URLENCODED)
@ApiOperation(value = "Update password",
notes = "Update current password")
@ApiResponses({@ApiResponse(code = 204, message = "OK"),
@ApiResponse(code = 400, message = "Invalid password"),
@ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 500, message = "Internal Server Error")})
@GenerateLink(rel = LINK_REL_CURRENT_USER_PASSWORD)
@ApiOperation(value = "Update password of logged in user",
notes = "Password must contain at least 8 characters, " +
"passport must contain letters and digits")
@ApiResponses({@ApiResponse(code = 204, message = "Password successfully updated"),
@ApiResponse(code = 400, message = "Incoming password is invalid value." +
"Valid password must contain at least 8 character " +
"which are letters and digits"),
@ApiResponse(code = 500, message = "Couldn't update password due to internal server error")})
public void updatePassword(@ApiParam(value = "New password", required = true)
@FormParam("password")
String password) throws NotFoundException,
BadRequestException,
ServerException,
ConflictException {
userValidator.checkPassword(password);
checkPassword(password);
final User user = userManager.getById(currentUserId());
final UserImpl user = new UserImpl(userManager.getById(userId()));
user.setPassword(password);
userManager.update(user);
}
/**
* Returns status <b>200</b> and {@link UserDescriptor} built from user with given {@code id}
* or status <b>404</b> when user with given {@code id} was not found.
*
* @param id
* identifier to search user
* @return entity of found user
* @throws NotFoundException
* when user with given identifier doesn't exist
* @throws ServerException
* when some error occurred while retrieving user
* @see UserDescriptor
* @see #getByAlias(String)
*/
@GET
@Path("/{id}")
@GenerateLink(rel = LINK_REL_GET_USER_BY_ID)
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Get user by ID",
notes = "Get user by its ID in the system",
response = UserDescriptor.class)
@ApiResponses({@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 500, message = "Internal Server Error")})
public UserDescriptor getById(@ApiParam(value = "User ID") @PathParam("id") String id) throws NotFoundException,
ServerException {
@GenerateLink(rel = LINK_REL_USER)
@ApiOperation("Get user by identifier")
@ApiResponses({@ApiResponse(code = 200, message = "The response contains requested user entity"),
@ApiResponse(code = 404, message = "User with requested identifier not found"),
@ApiResponse(code = 500, message = "Impossible to get user due to internal server error")})
public UserDto getById(@ApiParam("User identifier")
@PathParam("id")
String id) throws NotFoundException, ServerException {
final User user = userManager.getById(id);
return injectLinks(toDescriptor(user), getServiceContext());
return linksInjector.injectLinks(asDto(user), getServiceContext());
}
/**
* Returns status <b>200</b> and {@link UserDescriptor} built from user with given {@code alias}
* or status <b>404</b> when user with given {@code alias} was not found.
*
* @param alias
* alias to search user
* @return entity of found user
* @throws NotFoundException
* when user with given alias doesn't exist
* @throws ServerException
* when some error occurred while retrieving user
* @throws BadRequestException
* when alias parameter is missing
* @see UserDescriptor
* @see #getById(String)
* @see #remove(String)
*/
@GET
@Path("/find")
@GenerateLink(rel = LINK_REL_GET_USER_BY_EMAIL)
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Get user by alias",
notes = "Get user by alias",
response = UserDescriptor.class)
@ApiResponses({@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 400, message = "Missed alias parameter"),
@ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 500, message = "Internal Server Error")})
public UserDescriptor getByAlias(@ApiParam(value = "User alias", required = true)
@QueryParam("alias")
@Required String alias) throws NotFoundException,
ServerException,
BadRequestException {
if (alias == null) {
throw new BadRequestException("Missed parameter alias");
@GenerateLink(rel = LINK_REL_USER)
@ApiOperation("Get user by email or name")
@ApiResponses({@ApiResponse(code = 200, message = "The response contains requested user entity"),
@ApiResponse(code = 404, message = "User with requested email/name not found"),
@ApiResponse(code = 500, message = "Impossible to get user due to internal server error")})
public UserDto find(@ApiParam("User email, if it is set then name shouldn't be")
@QueryParam("email")
String email,
@ApiParam("User name, if is is set then email shouldn't be")
@QueryParam("name")
String name) throws NotFoundException,
ServerException,
BadRequestException {
if (email == null && name == null) {
throw new BadRequestException("Missed user's email or name");
}
final User user = userManager.getByAlias(alias);
return injectLinks(toDescriptor(user), getServiceContext());
if (email != null && name != null) {
throw new BadRequestException("Expected either user's email or name, while both values received");
}
final User user = name == null ? userManager.getByEmail(email) : userManager.getByName(name);
return linksInjector.injectLinks(asDto(user), getServiceContext());
}
/**
* Removes user with given identifier.
*
* @param id
* identifier to remove user
* @throws NotFoundException
* when user with given identifier doesn't exist
* @throws ServerException
* when some error occurred while removing user
* @throws ConflictException
* when some error occurred while removing user
*/
@DELETE
@Path("/{id}")
@GenerateLink(rel = LINK_REL_REMOVE_USER_BY_ID)
@ApiOperation(value = "Delete user",
notes = "Delete a user from the system")
@ApiResponses({@ApiResponse(code = 204, message = "Deleted"),
@ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 409, message = "Impossible to remove user"),
@ApiResponse(code = 500, message = "Internal Server Error")})
public void remove(@ApiParam(value = "User ID") @PathParam("id") String id) throws NotFoundException,
ServerException,
ConflictException {
@GenerateLink(rel = LINK_REL_USER)
@ApiOperation("Delete user")
@ApiResponses({@ApiResponse(code = 204, message = "User successfully removed"),
@ApiResponse(code = 409, message = "Couldn't remove user due to conflict(e.g. it has related entities)"),
@ApiResponse(code = 500, message = "Couldn't remove user due to internal server error")})
public void remove(@ApiParam("User identifier")
@PathParam("id")
String id) throws ServerException, ConflictException {
userManager.remove(id);
}
/**
* Get user by name.
*
* @param name
* user name
* @return found user
* @throws NotFoundException
* when user with given name doesn't exist
* @throws ServerException
* when some error occurred while retrieving user
*/
@GET
@Path("/name/{name}")
@GenerateLink(rel = "get user by name")
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Get user by name",
notes = "Get user by its name in the system")
@ApiResponses({@ApiResponse(code = 200, message = "OK"),
@ApiResponse(code = 404, message = "Not Found"),
@ApiResponse(code = 500, message = "Internal Server Error")})
public UserDescriptor getByName(@ApiParam(value = "User email")
@PathParam("name")
String name) throws NotFoundException, ServerException {
final User user = userManager.getByName(name);
return injectLinks(toDescriptor(user), getServiceContext());
}
/**
* Get setting of user service
*/
@GET
@Path("/settings")
@Produces(APPLICATION_JSON)
@ -348,64 +208,7 @@ public class UserService extends Service {
return ImmutableMap.of(USER_SELF_CREATION_ALLOWED, Boolean.toString(userSelfCreationAllowed));
}
private User fromEntity(UserDescriptor userDescriptor) throws BadRequestException {
if (userDescriptor == null) {
throw new BadRequestException("User Descriptor required");
}
if (isNullOrEmpty(userDescriptor.getName())) {
throw new BadRequestException("User name required");
}
if (isNullOrEmpty(userDescriptor.getEmail())) {
throw new BadRequestException("User email required");
}
final User user = new User().withName(userDescriptor.getName())
.withEmail(userDescriptor.getEmail());
if (userDescriptor.getPassword() != null) {
checkPassword(userDescriptor.getPassword());
user.setPassword(userDescriptor.getPassword());
}
return user;
}
private User fromToken(String token) throws UnauthorizedException, ConflictException {
return tokenValidator.validateToken(token);
}
/**
* Checks user password conforms some rules:
* <ul>
* <li> Not null
* <li> Must be at least 8 character length
* <li> Must contain at least one letter and one digit
* </ul>
*
* @param password
* user's password
* @throws BadRequestException
* when password violates any rule
*/
private void checkPassword(String password) throws BadRequestException {
if (password == null) {
throw new BadRequestException("Password required");
}
if (password.length() < 8) {
throw new BadRequestException("Password should contain at least 8 characters");
}
int numOfLetters = 0;
int numOfDigits = 0;
for (char passwordChar : password.toCharArray()) {
if (Character.isDigit(passwordChar)) {
numOfDigits++;
} else if (Character.isLetter(passwordChar)) {
numOfLetters++;
}
}
if (numOfDigits == 0 || numOfLetters == 0) {
throw new BadRequestException("Password should contain letters and digits");
}
}
private String currentUserId() {
private static String userId() {
return EnvironmentContext.getCurrent().getSubject().getUserId();
}
}

View File

@ -10,8 +10,10 @@
*******************************************************************************/
package org.eclipse.che.api.user.server;
import org.eclipse.che.api.core.BadRequestException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.user.User;
import org.eclipse.che.commons.lang.NameGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -19,13 +21,17 @@ import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import java.util.regex.Pattern;
import static com.google.common.base.Strings.isNullOrEmpty;
// TODO extract normalization code from the validator as it is not related to the validation at all
/**
* Utils for username validation and normalization.
*
* @author Mihail Kuznyetsov
* @author Yevhenii Voevodin
*/
public class UserNameValidator {
private static final Logger LOG = LoggerFactory.getLogger(UserNameValidator.class);
public class UserValidator {
private static final Logger LOG = LoggerFactory.getLogger(UserValidator.class);
private static final Pattern ILLEGAL_USERNAME_CHARACTERS = Pattern.compile("[^a-zA-Z0-9]");
private static final Pattern VALID_USERNAME = Pattern.compile("^[a-zA-Z0-9]*");
@ -33,19 +39,74 @@ public class UserNameValidator {
private final UserManager userManager;
@Inject
public UserNameValidator (UserManager userManager) {
public UserValidator(UserManager userManager) {
this.userManager = userManager;
}
/**
* Checks whether given user is valid.
*
* @param user
* user to check
* @throws BadRequestException
* when user is not valid
*/
public void checkUser(User user) throws BadRequestException {
if (user == null) {
throw new BadRequestException("User required");
}
if (isNullOrEmpty(user.getName())) {
throw new BadRequestException("User name required");
}
if (!isValidName(user.getName())) {
throw new BadRequestException("Username must contain only letters and digits");
}
if (isNullOrEmpty(user.getEmail())) {
throw new BadRequestException("User email required");
}
if (user.getPassword() != null) {
checkPassword(user.getPassword());
}
}
/**
* Checks whether password is ok.
*
* @param password
* password to check
* @throws BadRequestException
* when password is not valid
*/
public void checkPassword(String password) throws BadRequestException {
if (password == null) {
throw new BadRequestException("Password required");
}
if (password.length() < 8) {
throw new BadRequestException("Password should contain at least 8 characters");
}
int numOfLetters = 0;
int numOfDigits = 0;
for (char passwordChar : password.toCharArray()) {
if (Character.isDigit(passwordChar)) {
numOfDigits++;
} else if (Character.isLetter(passwordChar)) {
numOfLetters++;
}
}
if (numOfDigits == 0 || numOfLetters == 0) {
throw new BadRequestException("Password should contain letters and digits");
}
}
/**
* Validate name, if it doesn't contain illegal characters
*
* @param name
* username
* username
* @return true if valid name, false otherwise
*/
public boolean isValidUserName(String name) {
return VALID_USERNAME.matcher(name).matches();
public boolean isValidName(String name) {
return name != null && VALID_USERNAME.matcher(name).matches();
}
/**
@ -54,7 +115,7 @@ public class UserNameValidator {
* Also ensures username is unique, if not, adds digits to it's end.
*
* @param name
* username
* username
* @return username without illegal characters
*/
public String normalizeUserName(String name) throws ServerException {
@ -67,7 +128,7 @@ public class UserNameValidator {
candidate = normalized.isEmpty() ? NameGenerator.generate("username", 4) : normalized + String.valueOf(i++);
}
} catch (ServerException e) {
LOG.warn("Error occured during username normalization", e);
LOG.warn("Error occurred during username normalization", e);
throw e;
}
return candidate;
@ -78,8 +139,6 @@ public class UserNameValidator {
userManager.getByName(username);
} catch (NotFoundException e) {
return false;
} catch (ServerException e) {
throw e;
}
return true;
}

View File

@ -1,120 +0,0 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server.dao;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.UnauthorizedException;
/**
* DAO interface offers means to perform CRUD operations with {@link User} data. The implementation is not
* required to be responsible for persistent layer data dto integrity. It simply transfers data from one layer to another, so if
* you're going to call any of implemented methods it is considered that all needed verifications are already done. <p>
* <strong>Note:</strong> This particularly does not mean that method call will not make any inconsistency, but this
* mean that such kind of inconsistencies are expected by design and may be treated further. </p>
*/
public interface UserDao {
/**
* Authenticate user.
*
* @param alias
* user name or alias
* @param password
* password
* @return user id when authentication success
* @throws UnauthorizedException
* when authentication failed or no such user exists
* @throws ServerException
* when any other error occurs
*
*/
String authenticate(String alias, String password) throws UnauthorizedException, ServerException;
/**
* Adds user to persistent layer.
*
* @param user
* - POJO representation of user entity
* @throws ConflictException
* when given user cannot be created
* @throws ServerException
* when any other error occurs
*/
void create(User user) throws ConflictException, ServerException;
/**
* Updates already present in persistent layer user.
*
* @param user
* POJO representation of user entity
* @throws NotFoundException
* when user is not found
* @throws ConflictException
* when given user cannot be updated
* @throws ServerException
* when any other error occurs
*
*/
void update(User user) throws NotFoundException, ServerException, ConflictException;
/**
* Removes user from persistent layer by his identifier.
*
* @param id
* user identifier
* @throws ConflictException
* when given user cannot be deleted
* @throws ServerException
* when any other error occurs
*/
void remove(String id) throws NotFoundException, ServerException, ConflictException;
/**
* Gets user from persistent layer by any of his aliases
*
* @param alias
* user name or alias
* @return user POJO
* @throws NotFoundException
* when user doesn't exist
* @throws ServerException
* when any other error occurs
*/
User getByAlias(String alias) throws NotFoundException, ServerException;
/**
* Gets user from persistent layer by his identifier
*
* @param id
* user identifier
* @return user POJO
* @throws NotFoundException
* when user doesn't exist
* @throws ServerException
* when any other error occurs
*/
User getById(String id) throws NotFoundException, ServerException;
/**
* Gets user from persistent layer by his username
*
* @param userName
* user name
* @return user POJO
* @throws NotFoundException
* when user doesn't exist
* @throws ServerException
* when any other error occurs
*/
User getByName(String userName) throws NotFoundException, ServerException;
}

View File

@ -1,60 +0,0 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server.dao;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
/**
* DAO interface offers means to perform CRUD operations with {@link Profile} data.
*
* @author Eugene Voevodin
* @author Max Shaposhnik
*/
public interface UserProfileDao {
/**
* Adds profile to persistent layer.
*
* @param profile
* profile to setPreferences
*/
void create(Profile profile) throws ConflictException, ServerException;
/**
* Updates already present in persistent layer profile.
*
* @param profile
* profile to update
*/
void update(Profile profile) throws NotFoundException, ServerException;
/**
* Removes profile from persistent layer.
*
* @param id
* profile identifier
*/
void remove(String id) throws NotFoundException, ServerException;
/**
* Gets profile from persistent layer.
*
* @param id
* profile identifier
* @return profile with given {@code id}
* @throws org.eclipse.che.api.core.NotFoundException
* when profile doesn't exist
*/
Profile getById(String id) throws NotFoundException, ServerException;
}

View File

@ -8,57 +8,48 @@
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server.dao;
package org.eclipse.che.api.user.server.model.impl;
import org.eclipse.che.api.core.model.user.Profile;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* @author Eugene Voevodin
* Data object for the {@link Profile}.
*
* @author Yevhenii Voevodin
*/
public class Profile {
public class ProfileImpl implements Profile {
private String id;
private String userId;
private Map<String, String> attributes;
public Profile() {}
public Profile(String id) {
public ProfileImpl(String id) {
this.id = id;
this.userId = id;
}
public String getId() {
public ProfileImpl(String id, Map<String, String> attributes) {
this.id = id;
if (attributes != null) {
this.attributes = new HashMap<>(attributes);
}
}
public ProfileImpl(Profile profile) {
this(profile.getUserId(), profile.getAttributes());
}
@Override
public String getUserId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Profile withId(String id) {
this.id = id;
return this;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Profile withUserId(String userId) {
this.userId = userId;
return this;
}
@Override
public Map<String, String> getAttributes() {
if (attributes == null) {
attributes = new HashMap<>();
this.attributes = new HashMap<>();
}
return attributes;
}
@ -67,31 +58,31 @@ public class Profile {
this.attributes = attributes;
}
public Profile withAttributes(Map<String, String> attributes) {
this.attributes = attributes;
return this;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Profile)) {
if (!(obj instanceof ProfileImpl)) {
return false;
}
final Profile other = (Profile)obj;
return Objects.equals(id, other.id) &&
Objects.equals(userId, other.userId) &&
Objects.equals(getAttributes(), other.getAttributes());
final ProfileImpl that = (ProfileImpl)obj;
return Objects.equals(id, that.id) && getAttributes().equals(that.getAttributes());
}
@Override
public int hashCode() {
int hash = 7;
hash = 31 * hash + Objects.hashCode(id);
hash = 31 * hash + Objects.hashCode(userId);
hash = 31 * hash + Objects.hashCode(attributes);
hash = 31 * hash + getAttributes().hashCode();
return hash;
}
@Override
public String toString() {
return "ProfileImpl{" +
"id='" + id + '\'' +
", attributes=" + attributes +
'}';
}
}

View File

@ -8,16 +8,21 @@
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server.dao;
package org.eclipse.che.api.user.server.model.impl;
import org.eclipse.che.api.core.model.user.User;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
/**
* @author Eugene Voevodin
* Data object for the {@link User}.
*
* @author Yevhenii Voevodin
*/
public class User {
public class UserImpl implements User {
private String id;
private String email;
@ -25,19 +30,69 @@ public class User {
private String password;
private List<String> aliases;
public UserImpl(String id) {
this.id = id;
}
public UserImpl(String id, String email, String name) {
this.id = id;
this.email = email;
this.name = name;
}
public UserImpl(String id,
String email,
String name,
String password,
Collection<String> aliases) {
this(id, email, name);
this.password = password;
if (aliases != null) {
this.aliases = new ArrayList<>(aliases);
}
}
public UserImpl(User user) {
this(user.getId(),
user.getEmail(),
user.getName(),
user.getPassword(),
user.getAliases());
}
@Override
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
@Override
public String getEmail() {
return email;
}
public User withId(String id) {
this.id = id;
return this;
public void setEmail(String email) {
this.email = email;
}
@Override
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public List<String> getAliases() {
if (aliases == null) {
aliases = new ArrayList<>();
@ -49,64 +104,20 @@ public class User {
this.aliases = aliases;
}
public User withAliases(List<String> aliases) {
this.aliases = aliases;
return this;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public User withEmail(String email) {
this.email = email;
return this;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public User withPassword(String password) {
this.password = password;
return this;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User withName(String name) {
this.name = name;
return this;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof User)) {
if (!(obj instanceof UserImpl)) {
return false;
}
final User other = (User)obj;
return Objects.equals(id, other.id) &&
Objects.equals(email, other.email) &&
Objects.equals(password, other.password) &&
Objects.equals(name, other.name) &&
getAliases().equals(other.getAliases());
final UserImpl that = (UserImpl)obj;
return Objects.equals(id, that.id)
&& Objects.equals(email, that.email)
&& Objects.equals(name, that.name)
&& Objects.equals(password, that.password)
&& getAliases().equals(that.getAliases());
}
@Override
@ -114,9 +125,20 @@ public class User {
int hash = 7;
hash = 31 * hash + Objects.hashCode(id);
hash = 31 * hash + Objects.hashCode(email);
hash = 31 * hash + Objects.hashCode(password);
hash = 31 * hash + Objects.hashCode(name);
hash = 31 * hash + Objects.hashCode(password);
hash = 31 * hash + getAliases().hashCode();
return hash;
}
@Override
public String toString() {
return "UserImpl{" +
"id='" + id + '\'' +
", email='" + email + '\'' +
", name='" + name + '\'' +
", password='" + password + '\'' +
", aliases=" + aliases +
'}';
}
}

View File

@ -8,9 +8,8 @@
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server.dao;
package org.eclipse.che.api.user.server.spi;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import java.util.Map;
@ -31,12 +30,10 @@ public interface PreferenceDao {
* new preferences, if preferences are empty - removes user preferences
* @throws NullPointerException
* when preferences or userId is null
* @throws NotFoundException
* when user with given identifier doesn't exist
* @throws ServerException
* when any other error occurs
*/
void setPreferences(String userId, Map<String, String> preferences) throws ServerException, NotFoundException;
void setPreferences(String userId, Map<String, String> preferences) throws ServerException;
/**
* Gets user preferences.
@ -45,7 +42,7 @@ public interface PreferenceDao {
* <pre>{@code
* Map<String, String> prefs = dao.getPreferences("user123");
* prefs.put("key", "secret");
* dao.setPreferences("user123", prefs);
* spi.setPreferences("user123", prefs);
* }</pre>
*
* @param userId
@ -63,7 +60,7 @@ public interface PreferenceDao {
*
* <p>Note that this method must always return upgradable map, thus it may be used as:
* <pre>{@code
* Map<String, String> prefs = dao.getPreferences("user123", ".*key.*");
* Map<String, String> prefs = spi.getPreferences("user123", ".*key.*");
* prefs.put("new-key", "secret");
* prefs.setPreferences("user123", prefs);
* }</pre>

View File

@ -0,0 +1,85 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server.spi;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.user.Profile;
import org.eclipse.che.api.core.model.user.User;
import org.eclipse.che.api.user.server.model.impl.ProfileImpl;
/**
* Data access object contract for {@link Profile}.
*
* @author Yevhenii Voevodin
*/
public interface ProfileDao {
/**
* Creates user profile.
*
* @param profile
* new profile
* @throws NullPointerException
* when {@code profile} is null
* @throws ServerException
* when any error occurs
* @throws ConflictException
* when profile for user {@code profile.getUserId()} already exists
*/
void create(ProfileImpl profile) throws ServerException, ConflictException;
/**
* Updates profile by replacing an existing entity with a new one.
*
* @param profile
* profile update
* @throws NullPointerException
* when {@code profile} is null
* @throws NotFoundException
* when profile with such id doesn't exist
* @throws ServerException
* when any other error occurs
*/
void update(ProfileImpl profile) throws NotFoundException, ServerException;
/**
* Removes profile.
*
* @param id
* profile identifier
* @throws NullPointerException
* when {@code id} is null
* @throws ServerException
* when any other error occurs
*/
void remove(String id) throws ServerException;
/**
* Finds profile by its id.
*
* <p>Due to {@link Profile#getEmail()} and {@link Profile#getUserId()} definition
* returned profile must contain profile owner's {@link User#getEmail() email}
* and {@link User#getId()} identifier.
*
* @param id
* profile identifier
* @return profile with given {@code id}
* @throws NullPointerException
* when {@code id} is null
* @throws NotFoundException
* when profile with such {@code id} doesn't exist
* @throws ServerException
* when any other error occurs
*/
ProfileImpl getById(String id) throws NotFoundException, ServerException;
}

View File

@ -0,0 +1,166 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server.spi;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.UnauthorizedException;
import org.eclipse.che.api.user.server.model.impl.UserImpl;
/**
* Defines data access object contract for {@link UserImpl}.
*
* <p>The implementation is not required to be responsible for persistent layer
* data dto integrity. It simply transfers data from one layer to another,
* so if you're going to call any of implemented methods it is considered
* that all needed verifications are already done.
*
* <p><strong>Note:</strong> This particularly does not mean that
* method call will not make any inconsistency, but this mean that
* such kind of inconsistencies are expected by design and may be treated further.
*
* @author Yevhenii Voevodin
*/
public interface UserDao {
/**
* // TODO remove this method from spi
* Authenticates user.
*
* @param emailOrAliasOrName
* one of the user identifiers such as email/name/alias
* @param password
* password
* @return user identifier
* @throws NullPointerException
* when either {@code emailOrAliasOrName} or {@code password} is null
* @throws UnauthorizedException
* when user with such {@code aliasOrName} and {@code password} doesn't exist
* @throws ServerException
* when any other error occurs
*/
String authenticate(String emailOrAliasOrName, String password) throws UnauthorizedException, ServerException;
/**
* Creates a new user.
*
* @param user
* user to create
* @throws NullPointerException
* when {@code user} is null
* @throws ConflictException
* when user with such id/alias/email/name already exists
* @throws ServerException
* when any other error occurs
*/
void create(UserImpl user) throws ConflictException, ServerException;
/**
* Updates user by replacing an existing entity with a new one.
*
* @param user
* user to update
* @throws NullPointerException
* when {@code user} is null
* @throws NotFoundException
* when user with id {@code user.getId()} doesn't exist
* @throws ConflictException
* when any of the id/alias/email/name updated with a value
* which is not unique
* @throws ServerException
* when any other error occurs
*/
void update(UserImpl user) throws NotFoundException, ServerException, ConflictException;
/**
* Removes user.
*
* <p>It is up to implementation to do cascade removing of dependent data or
* to forbid removing at all.
*
* <p>Note that this method doesn't throw any exception when
* user doesn't exist.
*
* @param id
* user identifier
* @throws NullPointerException
* when {@code id} is null
* @throws ConflictException
* when given user cannot be deleted
* @throws ServerException
* when any other error occurs
*/
void remove(String id) throws ServerException, ConflictException;
/**
* Finds user by his alias.
*
* <p>This method doesn't work for user's email or name.
* If it is necessary to get user by name use {@link #getByName(String)} method instead.
*
* @param alias
* user name or alias
* @return user instance, never null
* @throws NullPointerException
* when {@code alias} is null
* @throws NotFoundException
* when user with given {@code alias} doesn't exist
* @throws ServerException
* when any other error occurs
*/
UserImpl getByAlias(String alias) throws NotFoundException, ServerException;
/**
* Finds user by his identifier.
*
* @param id
* user identifier
* @return user instance, never null
* @throws NullPointerException
* when {@code id} is null
* @throws NotFoundException
* when user with given {@code id} doesn't exist
* @throws ServerException
* when any other error occurs
*/
UserImpl getById(String id) throws NotFoundException, ServerException;
/**
* Finds user by his name.
*
* @param name
* user name
* @return user instance, never null
* @throws NullPointerException
* when {@code name} is null
* @throws NotFoundException
* when user with such {@code name} doesn't exist
* @throws ServerException
* when any other error occurs
*/
UserImpl getByName(String name) throws NotFoundException, ServerException;
/**
* Finds user by his email.
*
* @param email
* user email
* @return user instance, never null
* @throws NullPointerException
* when {@code email} is null
* @throws NotFoundException
* when user with such {@code email} doesn't exist
* @throws ServerException
* when any other error occurs
*/
UserImpl getByEmail(String email) throws NotFoundException, ServerException;
}

View File

@ -0,0 +1,152 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server;
import com.google.common.collect.ImmutableMap;
import org.eclipse.che.api.user.server.spi.PreferenceDao;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static java.util.Arrays.asList;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
/**
* Tests for {@link PreferenceManager}.
*
* @author Yevhenii Voevodin.
*/
@Listeners(MockitoTestNGListener.class)
public class PreferenceManagerTest {
@Mock
private PreferenceDao preferenceDao;
@InjectMocks
private PreferenceManager preferenceManager;
@Captor
private ArgumentCaptor<Map<String, String>> preferencesCaptor;
@Test
public void shouldUseMergeStrategyForPreferencesUpdate() throws Exception {
// Preparing preferences
final Map<String, String> existingPreferences = new HashMap<>();
existingPreferences.put("pKey1", "pValue1");
existingPreferences.put("pKey2", "pValue2");
existingPreferences.put("pKey3", "pValue3");
existingPreferences.put("pKey4", "pValue4");
when(preferenceDao.getPreferences(any())).thenReturn(existingPreferences);
// Updating preferences
final Map<String, String> newPreferences = new HashMap<>();
newPreferences.put("pKey5", "pValue5");
newPreferences.put("pKey1", "new-value");
preferenceManager.update("user123", newPreferences);
// Checking
verify(preferenceDao).setPreferences(anyString(), preferencesCaptor.capture());
assertEquals(preferencesCaptor.getValue(), ImmutableMap.of("pKey1", "new-value",
"pKey2", "pValue2",
"pKey3", "pValue3",
"pKey4", "pValue4",
"pKey5", "pValue5"));
}
@Test
public void shouldRemoveSpecifiedPreferences() throws Exception {
// Preparing preferences
final Map<String, String> existingPreferences = new HashMap<>();
existingPreferences.put("pKey1", "pValue1");
existingPreferences.put("pKey2", "pValue2");
existingPreferences.put("pKey3", "pValue3");
existingPreferences.put("pKey4", "pValue4");
when(preferenceDao.getPreferences(any())).thenReturn(existingPreferences);
// Removing
preferenceManager.remove("user123", asList("pKey1", "pKey5", "odd-pref-name"));
// Checking
verify(preferenceDao).setPreferences(anyString(), preferencesCaptor.capture());
assertEquals(preferencesCaptor.getValue(), ImmutableMap.of("pKey2", "pValue2",
"pKey3", "pValue3",
"pKey4", "pValue4"));
}
@Test
public void shouldGetPreferencesByUser() throws Exception {
final Map<String, String> preferences = ImmutableMap.of("name", "value");
when(preferenceDao.getPreferences("user123")).thenReturn(preferences);
assertEquals(preferenceManager.find("user123"), preferences);
}
@Test
public void shouldGetPreferencesByUserAndFilter() throws Exception {
final Map<String, String> preferences = ImmutableMap.of("name", "value");
when(preferenceDao.getPreferences("user123", "name.*")).thenReturn(preferences);
assertEquals(preferenceManager.find("user123", "name.*"), preferences);
}
@Test(expectedExceptions = NullPointerException.class)
public void getPreferencesShouldThrowNpeWhenUserIdIsNull() throws Exception {
preferenceManager.find(null);
}
@Test(expectedExceptions = NullPointerException.class)
public void getPreferencesByUserAndFilterShouldThrowNpeWhenUserIdIsNull() throws Exception {
preferenceManager.find(null, "name.*");
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeWhenRemovingPreferencesAndUserIdIsNull() throws Exception {
preferenceManager.remove(null);
}
@Test
public void shouldRemoveUserPreferences() throws Exception {
preferenceManager.remove("user123");
verify(preferenceDao).remove("user123");
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeWhenSavePreferencesWithNullUser() throws Exception {
preferenceManager.save(null, Collections.emptyMap());
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeWhenSavePreferencesWithNullPreferences() throws Exception {
preferenceManager.save("user123", null);
}
@Test
public void shouldSavePreferences() throws Exception {
preferenceManager.save("user123", Collections.emptyMap());
verify(preferenceDao).setPreferences("user123", Collections.emptyMap());
}
}

View File

@ -0,0 +1,169 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server;
import com.google.common.collect.ImmutableMap;
import com.jayway.restassured.response.Response;
import org.eclipse.che.api.core.rest.ApiExceptionMapper;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.commons.subject.Subject;
import org.eclipse.che.commons.subject.SubjectImpl;
import org.everrest.assured.EverrestJetty;
import org.everrest.core.Filter;
import org.everrest.core.GenericContainerRequest;
import org.everrest.core.RequestFilter;
import org.mockito.Answers;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import java.util.Map;
import static com.jayway.restassured.RestAssured.given;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.everrest.assured.JettyHttpServer.ADMIN_USER_NAME;
import static org.everrest.assured.JettyHttpServer.ADMIN_USER_PASSWORD;
import static org.everrest.assured.JettyHttpServer.SECURE_PATH;
import static org.mockito.Mockito.verify;
import static org.testng.Assert.assertEquals;
/**
* Tests for {@link PreferencesService}.
*
* @author Yevhenii Voevodin
*/
@Listeners({EverrestJetty.class, MockitoTestNGListener.class})
public class PreferencesServiceTest {
@SuppressWarnings("unused")
private static final ApiExceptionMapper MAPPER = new ApiExceptionMapper();
@SuppressWarnings("unused")
private static final EnvironmentFilter FILTER = new EnvironmentFilter();
private static final Subject SUBJECT = new SubjectImpl("user", "user123", "token", false);
@Mock(answer = Answers.RETURNS_MOCKS)
private PreferenceManager preferenceManager;
@InjectMocks
private PreferencesService preferencesService;
@Test
public void shouldFindPreferences() throws Exception {
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.when()
.get(SECURE_PATH + "/preferences");
assertEquals(response.getStatusCode(), 200);
verify(preferenceManager).find(SUBJECT.getUserId());
}
@Test
public void shouldFindPreferencesAndFilter() throws Exception {
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.when()
.get(SECURE_PATH + "/preferences?filter=.*github.*");
assertEquals(response.getStatusCode(), 200);
verify(preferenceManager).find(SUBJECT.getUserId(), ".*github.*");
}
@Test
public void shouldSavePreferences() throws Exception {
final Map<String, String> preferences = ImmutableMap.of("pref1", "value1",
"pref2", "value2",
"pref3", "value3");
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType("application/json")
.body(preferences)
.when()
.post(SECURE_PATH + "/preferences");
assertEquals(response.getStatusCode(), 204);
verify(preferenceManager).save(SUBJECT.getUserId(), preferences);
}
@Test
public void shouldNotSavePreferencesWhenNothingSent() throws Exception {
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType("application/json")
.when()
.post(SECURE_PATH + "/preferences");
assertEquals(response.getStatusCode(), 400);
}
@Test
public void shouldUpdatePreferences() throws Exception {
final Map<String, String> preferences = ImmutableMap.of("pref1", "value1",
"pref2", "value2",
"pref3", "value3");
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType("application/json")
.body(preferences)
.when()
.put(SECURE_PATH + "/preferences");
assertEquals(response.getStatusCode(), 200);
verify(preferenceManager).update(SUBJECT.getUserId(), preferences);
}
@Test
public void shouldNotUpdatePreferencesWhenNothingSent() throws Exception {
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType("application/json")
.when()
.put(SECURE_PATH + "/preferences");
assertEquals(response.getStatusCode(), 400);
}
@Test
public void shouldRemoveSpecifiedPreferences() throws Exception {
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType("application/json")
.body(asList("pref1", "pref2"))
.when()
.delete(SECURE_PATH + "/preferences");
assertEquals(response.getStatusCode(), 204);
verify(preferenceManager).remove(SUBJECT.getUserId(), asList("pref1", "pref2"));
}
@Test
public void shouldRemoveAllPreferencesIfNothingSent() throws Exception {
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.contentType("application/json")
.when()
.delete(SECURE_PATH + "/preferences");
assertEquals(response.getStatusCode(), 204);
verify(preferenceManager).remove(SUBJECT.getUserId());
}
@Filter
public static class EnvironmentFilter implements RequestFilter {
public void doFilter(GenericContainerRequest request) {
EnvironmentContext.getCurrent().setSubject(SUBJECT);
}
}
}

View File

@ -0,0 +1,79 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server;
import com.google.common.collect.Sets;
import org.eclipse.che.api.core.rest.ServiceContext;
import org.eclipse.che.api.user.shared.dto.ProfileDto;
import org.eclipse.che.commons.lang.Pair;
import org.eclipse.che.dto.server.DtoFactory;
import org.everrest.core.impl.uri.UriBuilderImpl;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import static java.util.Arrays.asList;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
/**
* Tests for {@link ProfileLinksInjector}.
*
* @author Yevhenii Voevodin
*/
@Listeners(MockitoTestNGListener.class)
public class ProfileLinksInjectorTest {
@Mock
private ServiceContext serviceContext;
@InjectMocks
private ProfileLinksInjector linksInjector;
@BeforeMethod
public void setUpContext() {
final UriBuilderImpl uriBuilder = new UriBuilderImpl();
uriBuilder.uri("http://localhost:8080");
when(serviceContext.getServiceUriBuilder()).thenReturn(uriBuilder);
when(serviceContext.getBaseUriBuilder()).thenReturn(uriBuilder);
}
@Test
public void shouldInjectProfileLinks() throws Exception {
final ProfileDto profileDto = DtoFactory.newDto(ProfileDto.class)
.withUserId("user123")
.withEmail("user@codenvy.com");
linksInjector.injectLinks(profileDto, serviceContext);
// [rel, method] pairs links
final Set<Pair<String, String>> links = profileDto.getLinks()
.stream()
.map(link -> Pair.of(link.getMethod(), link.getRel()))
.collect(Collectors.toSet());
final Set<Pair<String, String>> expectedLinks
= new HashSet<>(asList(Pair.of("GET", Constants.LINK_REL_SELF),
Pair.of("GET", Constants.LINK_REL_CURRENT_PROFILE),
Pair.of("PUT", Constants.LINK_REL_PROFILE_ATTRIBUTES),
Pair.of("PUT", Constants.LINK_REL_CURRENT_PROFILE_ATTRIBUTES),
Pair.of("DELETE", Constants.LINK_REL_CURRENT_PROFILE_ATTRIBUTES)));
assertEquals(links, expectedLinks, "Difference " + Sets.symmetricDifference(links, expectedLinks) + "\n");
}
}

View File

@ -0,0 +1,96 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server;
import org.eclipse.che.api.user.server.model.impl.ProfileImpl;
import org.eclipse.che.api.user.server.spi.ProfileDao;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
/**
* Tests for {@link ProfileManager}.
*
* @author Yevhenii Voevodin
*/
@Listeners(MockitoTestNGListener.class)
public class ProfileManagerTest {
@Mock
private ProfileDao profileDao;
@InjectMocks
private ProfileManager profileManager;
@Test
public void shouldGetProfileById() throws Exception {
final ProfileImpl profile = new ProfileImpl("user123");
when(profileDao.getById(profile.getUserId())).thenReturn(profile);
assertEquals(profile, profileManager.getById(profile.getUserId()));
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeWhenGettingProfileByNullId() throws Exception {
profileManager.getById(null);
}
@Test
public void shouldCreateProfile() throws Exception {
final ProfileImpl profile = new ProfileImpl("user123");
profileManager.create(profile);
final ArgumentCaptor<ProfileImpl> captor = ArgumentCaptor.forClass(ProfileImpl.class);
verify(profileDao).create(captor.capture());
assertEquals(captor.getValue(), profile);
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeWhenCreatingNullProfile() throws Exception {
profileManager.create(null);
}
@Test
public void shouldUpdateProfile() throws Exception {
final ProfileImpl profile = new ProfileImpl("user123");
profileManager.update(profile);
final ArgumentCaptor<ProfileImpl> captor = ArgumentCaptor.forClass(ProfileImpl.class);
verify(profileDao).update(captor.capture());
assertEquals(captor.getValue(), profile);
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeWhenUpdatingNull() throws Exception {
profileManager.update(null);
}
@Test
public void shouldRemoveProfile() throws Exception {
profileManager.remove("user123");
verify(profileDao).remove("user123");
}
@Test(expectedExceptions = NullPointerException.class)
public void shouldThrowNpeWhenRemovingNull() throws Exception {
profileManager.remove(null);
}
}

View File

@ -0,0 +1,219 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server;
import com.google.common.collect.ImmutableMap;
import com.jayway.restassured.response.Response;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.core.model.user.Profile;
import org.eclipse.che.api.core.rest.ApiExceptionMapper;
import org.eclipse.che.api.user.server.model.impl.ProfileImpl;
import org.eclipse.che.api.user.shared.dto.ProfileDto;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.commons.subject.Subject;
import org.eclipse.che.commons.subject.SubjectImpl;
import org.eclipse.che.dto.server.DtoFactory;
import org.everrest.assured.EverrestJetty;
import org.everrest.core.Filter;
import org.everrest.core.GenericContainerRequest;
import org.everrest.core.RequestFilter;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import static com.jayway.restassured.RestAssured.given;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.everrest.assured.JettyHttpServer.ADMIN_USER_NAME;
import static org.everrest.assured.JettyHttpServer.ADMIN_USER_PASSWORD;
import static org.everrest.assured.JettyHttpServer.SECURE_PATH;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
/**
* Tests for {@link ProfileService}.
*
* @author Yevhenii Voevodin
*/
@Listeners({EverrestJetty.class, MockitoTestNGListener.class})
public class ProfileServiceTest {
@SuppressWarnings("unused")
private static final ApiExceptionMapper MAPPER = new ApiExceptionMapper();
@SuppressWarnings("unused")
private static final EnvironmentFilter FILTER = new EnvironmentFilter();
private static final Subject SUBJECT = new SubjectImpl("user", "user123", "token", false);
@Mock(answer = Answers.RETURNS_MOCKS)
private ProfileManager profileManager;
@Mock
private ProfileLinksInjector linksInjector;
@Mock(answer = Answers.RETURNS_MOCKS)
private UserManager userManager;
@Captor
private ArgumentCaptor<Profile> profileCaptor;
@InjectMocks
private ProfileService profileService;
@BeforeMethod
public void setUp() throws NotFoundException, ServerException {
when(linksInjector.injectLinks(any(), any())).thenAnswer(inv -> inv.getArguments()[0]);
when(profileManager.getById(SUBJECT.getUserId())).thenReturn(new ProfileImpl(SUBJECT.getUserId()));
}
@Test
public void shouldGetCurrentProfile() throws Exception {
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.when()
.get(SECURE_PATH + "/profile");
assertEquals(response.getStatusCode(), 200);
final ProfileDto profileDto = unwrapDto(response, ProfileDto.class);
assertEquals(profileDto.getUserId(), SUBJECT.getUserId());
}
@Test
public void shouldGetProfileById() throws Exception {
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.when()
.get(SECURE_PATH + "/profile/" + SUBJECT.getUserId());
assertEquals(response.getStatusCode(), 200);
final ProfileDto profileDto = unwrapDto(response, ProfileDto.class);
assertEquals(profileDto.getUserId(), SUBJECT.getUserId());
}
@Test
public void shouldBeAbleToUpdateCurrentProfileAttributes() throws Exception {
final ImmutableMap<String, String> attributes = ImmutableMap.of("attr1", "value1",
"attr2", "value2",
"attr3", "value3");
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.when()
.contentType("application/json")
.body(attributes)
.put(SECURE_PATH + "/profile/attributes");
assertEquals(response.getStatusCode(), 200);
verify(profileManager).update(profileCaptor.capture());
final Profile profile = profileCaptor.getValue();
assertEquals(profile.getAttributes(), attributes);
}
@Test
public void shouldNotUpdateCurrentProfileAttributesIfNothingSent() throws Exception {
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.when()
.contentType("application/json")
.put(SECURE_PATH + "/profile/attributes");
assertEquals(response.getStatusCode(), 400);
}
@Test
public void shouldBeAbleToUpdateAttributesOfSpecifiedProfile() throws Exception {
final ImmutableMap<String, String> attributes = ImmutableMap.of("attr1", "value1",
"attr2", "value2",
"attr3", "value3");
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.when()
.contentType("application/json")
.body(attributes)
.put(SECURE_PATH + "/profile/" + SUBJECT.getUserId() + "/attributes/");
assertEquals(response.getStatusCode(), 200);
verify(profileManager).update(profileCaptor.capture());
final Profile profile = profileCaptor.getValue();
assertEquals(profile.getAttributes(), attributes);
}
@Test
public void shouldNotUpdateSpecifiedProfileAttributesIfNothingSent() throws Exception {
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.when()
.contentType("application/json")
.put(SECURE_PATH + "/profile/" + SUBJECT.getUserId() + "/attributes/");
assertEquals(response.getStatusCode(), 400);
}
@Test
public void shouldBeAbleToRemoveSpecifiedAttributes() throws Exception {
when(profileManager.getById(SUBJECT.getUserId()))
.thenReturn(new ProfileImpl(SUBJECT.getUserId(),
ImmutableMap.of("attr1", "value1",
"attr2", "value2",
"attr3", "value3")));
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.when()
.contentType("application/json")
.body(asList("attr1", "attr3"))
.delete(SECURE_PATH + "/profile/attributes");
assertEquals(response.getStatusCode(), 204);
verify(profileManager).update(profileCaptor.capture());
final Profile profile = profileCaptor.getValue();
assertEquals(profile.getAttributes(), ImmutableMap.of("attr2", "value2"));
}
@Test
public void shouldRemoveAllAttributeIfNoSpecified() throws Exception {
when(profileManager.getById(SUBJECT.getUserId()))
.thenReturn(new ProfileImpl(SUBJECT.getUserId(),
ImmutableMap.of("attr1", "value1",
"attr2", "value2",
"attr3", "value3")));
final Response response = given().auth()
.basic(ADMIN_USER_NAME, ADMIN_USER_PASSWORD)
.when()
.contentType("application/json")
.delete(SECURE_PATH + "/profile/attributes");
assertEquals(response.getStatusCode(), 204);
verify(profileManager).update(profileCaptor.capture());
final Profile profile = profileCaptor.getValue();
assertTrue(profile.getAttributes().isEmpty());
}
@Filter
public static class EnvironmentFilter implements RequestFilter {
public void doFilter(GenericContainerRequest request) {
EnvironmentContext.getCurrent().setSubject(SUBJECT);
}
}
private static <T> T unwrapDto(Response response, Class<T> dtoClass) {
return DtoFactory.getInstance().createDtoFromJson(response.body().print(), dtoClass);
}
}

View File

@ -0,0 +1,81 @@
/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.api.user.server;
import com.google.common.collect.Sets;
import org.eclipse.che.api.core.rest.ServiceContext;
import org.eclipse.che.api.user.shared.dto.UserDto;
import org.eclipse.che.commons.lang.Pair;
import org.eclipse.che.dto.server.DtoFactory;
import org.everrest.core.impl.uri.UriBuilderImpl;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import static java.util.Arrays.asList;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
/**
* Tests for {@link UserLinksInjector}.
*
* @author Yevhenii Voevodin
*/
@Listeners(MockitoTestNGListener.class)
public class UserLinksInjectorTest {
@Mock
private ServiceContext serviceContext;
@InjectMocks
private UserLinksInjector linksInjector;
@BeforeMethod
public void setUpContext() {
final UriBuilderImpl uriBuilder = new UriBuilderImpl();
uriBuilder.uri("http://localhost:8080");
when(serviceContext.getServiceUriBuilder()).thenReturn(uriBuilder);
when(serviceContext.getBaseUriBuilder()).thenReturn(uriBuilder);
}
@Test
public void shouldInjectLinks() throws Exception {
final UserDto userDto = DtoFactory.newDto(UserDto.class)
.withId("user123")
.withEmail("user@codenvy.com")
.withName("user");
linksInjector.injectLinks(userDto, serviceContext);
// [rel, method] pairs links
final Set<Pair<String, String>> links = userDto.getLinks()
.stream()
.map(link -> Pair.of(link.getMethod(), link.getRel()))
.collect(Collectors.toSet());
final Set<Pair<String, String>> expectedLinks
= new HashSet<>(asList(Pair.of("GET", Constants.LINK_REL_SELF),
Pair.of("GET", Constants.LINK_REL_CURRENT_USER),
Pair.of("GET", Constants.LINK_REL_PROFILE),
Pair.of("GET", Constants.LINK_REL_CURRENT_USER_SETTINGS),
Pair.of("GET", Constants.LINK_REL_PREFERENCES),
Pair.of("POST", Constants.LINK_REL_CURRENT_USER_PASSWORD)));
assertEquals(links, expectedLinks, "Difference " + Sets.symmetricDifference(links, expectedLinks) + "\n");
}
}

Some files were not shown because too many files have changed in this diff Show More