diff --git a/pom.xml b/pom.xml index 4338272..1003ff6 100644 --- a/pom.xml +++ b/pom.xml @@ -52,6 +52,10 @@ tmortagne Thomas Mortagne + + martindelille + Martin Delille + usersync-api @@ -85,4 +89,21 @@ + + + com.squareup.retrofit2 + retrofit + 2.5.0 + + + com.squareup.retrofit2 + converter-gson + 2.5.0 + + + com.squareup.okhttp3 + logging-interceptor + 3.12.0 + + diff --git a/usersync-api/src/main/java/org/xwiki/contrib/usersync/UserSyncConnector.java b/usersync-api/src/main/java/org/xwiki/contrib/usersync/UserSyncConnector.java index cb1d0b2..8737580 100644 --- a/usersync-api/src/main/java/org/xwiki/contrib/usersync/UserSyncConnector.java +++ b/usersync-api/src/main/java/org/xwiki/contrib/usersync/UserSyncConnector.java @@ -34,16 +34,16 @@ public interface UserSyncConnector /** * @param user the object containing the metadata of the new user */ - void createUser(BaseObject user); + void createUser(BaseObject user) throws UserSyncException; /** * @param previousUser the object containing the previous metadata of the user * @param previousUser the object containing the new metadata of the user */ - void modifyUser(BaseObject previousUser, BaseObject newUser); + void modifyUser(BaseObject previousUser, BaseObject newUser) throws UserSyncException; /** * @param deletedUser the object containing the metadata of the deleted user */ - void deleteUser(BaseObject deletedUser); + void deleteUser(BaseObject deletedUser) throws UserSyncException; } diff --git a/usersync-api/src/main/java/org/xwiki/contrib/usersync/interval/UserSyncListener.java b/usersync-api/src/main/java/org/xwiki/contrib/usersync/interval/UserSyncListener.java index b9d2ecb..8ba9b1c 100644 --- a/usersync-api/src/main/java/org/xwiki/contrib/usersync/interval/UserSyncListener.java +++ b/usersync-api/src/main/java/org/xwiki/contrib/usersync/interval/UserSyncListener.java @@ -27,6 +27,7 @@ import org.xwiki.component.annotation.Component; import org.xwiki.contrib.usersync.UserSyncConnector; +import org.xwiki.contrib.usersync.UserSyncException; import org.xwiki.model.reference.EntityReference; import org.xwiki.observation.AbstractEventListener; import org.xwiki.observation.event.Event; @@ -80,12 +81,16 @@ private void onEvent(UserSyncConnector connector, XObjectEvent event, XWikiDocum BaseObject newUser = document.getXObject(event.getReference()); BaseObject previousUser = document.getOriginalDocument().getXObject(event.getReference()); - if (event instanceof XObjectAddedEvent) { - connector.createUser(newUser); - } else if (event instanceof XObjectDeletedEvent) { - connector.deleteUser(previousUser); - } else { - connector.modifyUser(previousUser, newUser); + try { + if (event instanceof XObjectAddedEvent) { + connector.createUser(newUser); + } else if (event instanceof XObjectDeletedEvent) { + connector.deleteUser(previousUser); + } else { + connector.modifyUser(previousUser, newUser); + } + } catch (UserSyncException exception) { + System.out.println(exception.getMessage()); } } } diff --git a/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/CreateUserBody.java b/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/CreateUserBody.java new file mode 100644 index 0000000..26393ab --- /dev/null +++ b/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/CreateUserBody.java @@ -0,0 +1,23 @@ +package org.xwiki.contrib.usersync.discourse.internal; + +import com.google.gson.annotations.SerializedName; + +public class CreateUserBody { + private String username; + + private String name; + + private String email; + + private String password; + + private Boolean active; + + public CreateUserBody(String _username, String _name, String _email, String _password) { + username = _username; + name = _name; + email = _email; + password = _password; + active = true; + } +} diff --git a/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/CreateUserResponse.java b/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/CreateUserResponse.java new file mode 100644 index 0000000..b6f16aa --- /dev/null +++ b/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/CreateUserResponse.java @@ -0,0 +1,21 @@ +package org.xwiki.contrib.usersync.discourse.internal; + +import org.xwiki.contrib.usersync.discourse.internal.User; + +public class CreateUserResponse { + private Boolean success; + + private String message; + + private Integer user_id; + + public Boolean getSuccess() { + return success; + } + + public String getMessage() { + return message; + } + + public Integer getUserId() { return user_id; } +} diff --git a/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/DeleteUserResponse.java b/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/DeleteUserResponse.java new file mode 100644 index 0000000..0eda85d --- /dev/null +++ b/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/DeleteUserResponse.java @@ -0,0 +1,11 @@ +package org.xwiki.contrib.usersync.discourse.internal; + +import org.xwiki.contrib.usersync.discourse.internal.User; + +public class DeleteUserResponse { + private Boolean deleted; + + public Boolean getDeleted() { + return deleted; + } +} diff --git a/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/DiscourseService.java b/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/DiscourseService.java new file mode 100644 index 0000000..803212b --- /dev/null +++ b/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/DiscourseService.java @@ -0,0 +1,21 @@ +package org.xwiki.contrib.usersync.discourse.internal; + +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.DELETE; +import retrofit2.http.GET; +import retrofit2.http.POST; +import retrofit2.http.Path; +import retrofit2.http.Header; + +public interface DiscourseService { + @GET("users/{username}.json") + Call getUser(@Path("username") String username, @Header("Api-Key") String apiKey, @Header("Api-Username") String apiUsername); + + @POST("users") + Call createUser(@Body CreateUserBody createUserBody, @Header("Api-Key") String apiKey, @Header("Api-Username") String apiUsername); + + @DELETE("/admin/users/{userid}.json") + Call deleteUser(@Path("userid") Integer userId, @Header("Api-Key") String apiKey, @Header("Api-Username") String apiUsername); +} + diff --git a/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/DiscourseUserSyncConnector.java b/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/DiscourseUserSyncConnector.java index 13ff277..7041c10 100644 --- a/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/DiscourseUserSyncConnector.java +++ b/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/DiscourseUserSyncConnector.java @@ -19,57 +19,164 @@ */ package org.xwiki.contrib.usersync.discourse.internal; +import java.io.IOException; + import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import org.xwiki.component.annotation.Component; +import org.xwiki.component.phase.Initializable; +import org.xwiki.component.phase.InitializationException; import org.xwiki.configuration.ConfigurationSource; import org.xwiki.contrib.usersync.UserSyncConnector; +import org.xwiki.contrib.usersync.UserSyncException; import com.xpn.xwiki.objects.BaseObject; +import okhttp3.OkHttpClient; +import okhttp3.logging.HttpLoggingInterceptor; +import retrofit2.Call; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + /** * {@link UserSyncConnector} implementation for Discourse. - * + * * @version $Id$ */ @Component @Singleton @Named("discourse") -public class DiscourseUserSyncConnector implements UserSyncConnector +public class DiscourseUserSyncConnector implements UserSyncConnector, Initializable { private static final String PREFIX_CONFIGURATION = "usersync.discourse."; - - private static final String CONFIGURATION_URL = PREFIX_CONFIGURATION + "url"; + + public static final String CONFIGURATION_URL = PREFIX_CONFIGURATION + "url"; + public static final String CONFIGURATION_API_KEY = PREFIX_CONFIGURATION + "api_key"; + public static final String CONFIGURATION_API_USERNAME = PREFIX_CONFIGURATION + "api_username"; @Inject private ConfigurationSource configuration; + HttpLoggingInterceptor logging; + OkHttpClient.Builder httpClient; + + private Retrofit retrofit; + private DiscourseService service; + String discourseURL; + String discourseApiKey; + String discourseApiUsername; + @Override - public void createUser(BaseObject user) + public void initialize() throws InitializationException { + // Get the URL of the discourse server to synchronize with + discourseURL = this.configuration.getProperty(CONFIGURATION_URL); + discourseApiKey = this.configuration.getProperty(CONFIGURATION_API_KEY); + discourseApiUsername = this.configuration.getProperty(CONFIGURATION_API_USERNAME); + + logging = new HttpLoggingInterceptor(); + logging.setLevel(HttpLoggingInterceptor.Level.BODY); + httpClient = new OkHttpClient.Builder(); + httpClient.addInterceptor(logging); + + retrofit = new Retrofit.Builder() + .baseUrl(discourseURL) + .addConverterFactory(GsonConverterFactory.create()) + .client(httpClient.build()) + .build(); + + service = retrofit.create(DiscourseService.class); + } + + @Override + public void createUser(BaseObject userObject) throws UserSyncException { // Get the user login - String userId = user.getReference().getName(); + String userId = userObject.getStringValue("id"); - // Get the user mail - String mail = user.getStringValue("email"); + // Get the user email + String email = userObject.getStringValue("email"); - // Get the URL of the discourse server to synchronize with - String discourseURL = this.configuration.getProperty(CONFIGURATION_URL); + // Get the user password + String password = userObject.getStringValue("password"); - // TODO + // Get the user name + String name = userObject.getStringValue("name"); + + System.out.printf("creating user: %s / %s / %s / %s\n", userId, email, password, name); + + CreateUserBody createUserBody = new CreateUserBody(userId, name, email, password); + + Call call = service.createUser(createUserBody, discourseApiKey, discourseApiUsername); + + try { + Response response = call.execute(); + if(response.isSuccessful()) { + System.out.println("succeed!"); + CreateUserResponse createUserResponse = response.body(); + if (createUserResponse.getSuccess()) { + System.out.println("Success creating user with id:" + createUserResponse.getUserId()); + userObject.setIntValue("id", createUserResponse.getUserId()); + } else { + throw new UserSyncException(createUserResponse.getMessage()); + } + } else { + System.out.println("Code: " + response.code()); + throw new UserSyncException("Bad response code:" + response.code()); + } + } catch (IOException exception) { + System.out.println(exception.getMessage()); + throw new UserSyncException("Unknown error", exception); + } } @Override - public void modifyUser(BaseObject previousUser, BaseObject newUser) + public void modifyUser(BaseObject previousUser, BaseObject newUser) throws UserSyncException { // TODO } @Override - public void deleteUser(BaseObject deletedUser) + public void deleteUser(BaseObject userObject) throws UserSyncException { - // TODO + // Get the user login + String userName = userObject.getStringValue("id"); + + System.out.printf("deleting user: %s\n", userName); + + Call getUserResponseCall = service.getUser(userName, discourseApiKey, discourseApiUsername); + + + + try { + Response getUserResponse = getUserResponseCall.execute(); + if (getUserResponse.isSuccessful()) { + System.out.printf("user name is " + getUserResponse.body().getUser().getEmail()); + Integer userId = getUserResponse.body().getUser().getId(); + System.out.printf("user id is " + userId); + Call deleteUserResponseCall = service.deleteUser(userId, discourseApiKey, discourseApiUsername); + + Response deleteUserResponse = deleteUserResponseCall.execute(); + if(deleteUserResponse.isSuccessful()) { + System.out.println("succeed!"); + if (deleteUserResponse.body().getDeleted()) { + System.out.println("Success deleting user"); + } else { + throw new UserSyncException("Failed deleting user"); + } + } else { + System.out.println("Code: " + deleteUserResponse.code()); + throw new UserSyncException("Bad response code for deleteUser:" + deleteUserResponse.code()); + } + } else { + System.out.println("Code: " + getUserResponse.code()); + throw new UserSyncException("Bad response code for getUser:" + getUserResponse.code()); + } + } catch (IOException exception) { + System.out.println(exception.getMessage()); + throw new UserSyncException("Unknown error", exception); + } } } diff --git a/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/GetUserResponse.java b/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/GetUserResponse.java new file mode 100644 index 0000000..cfad7ea --- /dev/null +++ b/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/GetUserResponse.java @@ -0,0 +1,11 @@ +package org.xwiki.contrib.usersync.discourse.internal; + +import org.xwiki.contrib.usersync.discourse.internal.User; + +public class GetUserResponse { + private User user; + + public User getUser() { + return user; + } +} diff --git a/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/User.java b/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/User.java new file mode 100644 index 0000000..6cbe3c8 --- /dev/null +++ b/usersync-connectors/usersync-connector-discourse/src/main/java/org/xwiki/contrib/usersync/discourse/internal/User.java @@ -0,0 +1,33 @@ +package org.xwiki.contrib.usersync.discourse.internal; + +import com.google.gson.annotations.SerializedName; + +public class User { + private int id; + + private String username; + + private String name; + + private String email; + + private String password; + + public int getId() { return id; } + + public String getUsername() { + return username; + } + + public String getName() { + return name; + } + + public String getEmail() { + return email; + } + + public String getPassword() { + return password; + } +} diff --git a/usersync-connectors/usersync-connector-discourse/src/test/java/org/xwiki/contrib/usersync/discourse/internal/DiscourseUserSyncConnectorTest.java b/usersync-connectors/usersync-connector-discourse/src/test/java/org/xwiki/contrib/usersync/discourse/internal/DiscourseUserSyncConnectorTest.java index 079eebe..9a0093f 100644 --- a/usersync-connectors/usersync-connector-discourse/src/test/java/org/xwiki/contrib/usersync/discourse/internal/DiscourseUserSyncConnectorTest.java +++ b/usersync-connectors/usersync-connector-discourse/src/test/java/org/xwiki/contrib/usersync/discourse/internal/DiscourseUserSyncConnectorTest.java @@ -19,13 +19,17 @@ */ package org.xwiki.contrib.usersync.discourse.internal; +import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.xwiki.component.manager.ComponentLookupException; +import org.xwiki.configuration.internal.MemoryConfigurationSource; import org.xwiki.contrib.usersync.UserSyncConnector; +import org.xwiki.contrib.usersync.UserSyncException; import org.xwiki.model.reference.DocumentReference; import org.xwiki.model.reference.LocalDocumentReference; +import org.xwiki.test.annotation.AfterComponent; import org.xwiki.test.mockito.MockitoComponentMockingRule; import com.xpn.xwiki.doc.XWikiDocument; @@ -48,6 +52,12 @@ public class DiscourseUserSyncConnectorTest private BaseObject newUser; private BaseObject previousUser; + private MemoryConfigurationSource configuration = oldcore.getConfigurationSource(); + + @AfterComponent + public void afterComponent() throws Exception { + configuration = mocker.registerMemoryConfigurationSource(); + } @Before public void before() @@ -57,7 +67,10 @@ public void before() this.newUser = new BaseObject(); this.newUser.setXClassReference(new LocalDocumentReference("XWiki", "XWikiUsers")); - this.newUser.setStringValue("email", "mail@domain.com"); + this.newUser.setStringValue("id", "SergeGainsbourg"); + this.newUser.setStringValue("email", "martin@phonations.com"); + this.newUser.setStringValue("password", "abcdefgh1234"); + this.newUser.setStringValue("name", "Serge Gainsbourg"); userDocument.addXObject(this.newUser); @@ -67,14 +80,37 @@ public void before() } @Test + public void createUser() throws ComponentLookupException + { + try { + // Call the component + this.mocker.getComponentUnderTest().createUser(this.newUser); + } catch (UserSyncException exception) { + Assert.fail(exception.getMessage()); + } + } + public void modifyUser() throws ComponentLookupException { // Modify the user this.newUser.setStringValue("email", "differentmail@domain.com"); - // Call the component - this.mocker.getComponentUnderTest().modifyUser(this.previousUser, this.newUser); + try { + // Call the component + this.mocker.getComponentUnderTest().modifyUser(this.previousUser, this.newUser); + } catch (UserSyncException exception) { + Assert.fail(exception.getMessage()); + } + } - // TODO + @Test + public void deleteUser() throws ComponentLookupException + { + try { + // Call the component + this.mocker.getComponentUnderTest().deleteUser(this.newUser); + } catch (UserSyncException exception) { + Assert.fail(exception.getMessage()); + } } }