#1448 Create AuthMePlayer to get player data from API with (#2000)

* #1448 Create AuthMePlayer to get player data from API with

* #1448 Add tests for new API method & AuthMePlayer

* #1448 Create AuthMePlayer to get player data from API with
- Use Optional for all values that may be null

* #1448 Add comment that AuthMePlayer data does not update itself
This commit is contained in:
ljacqu 2020-02-12 20:06:42 +01:00 committed by GitHub
parent 214f0b5587
commit f7911edd60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 291 additions and 33 deletions

View File

@ -21,6 +21,7 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
/**
* The current API of AuthMe.
@ -133,20 +134,17 @@ public class AuthMeApi {
}
/**
* Get the registration ip address of a player.
* Returns the AuthMe info of the given player's name, or empty optional if the player doesn't exist.
*
* @param playerName The name of the player to process
* @return The registration ip address of the player
* @param playerName The player name to look up
* @return AuthMe player info, or empty optional if the player doesn't exist
*/
public String getRegistrationIp(String playerName) {
public Optional<AuthMePlayer> getPlayerInfo(String playerName) {
PlayerAuth auth = playerCache.getAuth(playerName);
if (auth == null) {
auth = dataSource.getAuth(playerName);
}
if (auth != null) {
return auth.getRegistrationIp();
}
return null;
return AuthMePlayerImpl.fromPlayerAuth(auth);
}
/**
@ -180,7 +178,6 @@ public class AuthMeApi {
* Get the last (AuthMe) login date of a player.
*
* @param playerName The name of the player to process
*
* @return The date of the last login, or null if the player doesn't exist or has never logged in
* @deprecated Use Java 8's Instant method {@link #getLastLoginTime(String)}
*/
@ -213,29 +210,6 @@ public class AuthMeApi {
return null;
}
/**
* Get the registration (AuthMe) timestamp of a player.
*
* @param playerName The name of the player to process
*
* @return The timestamp of when the player was registered, or null if the player doesn't exist or is not registered
*/
public Instant getRegistrationTime(String playerName) {
Long registrationDate = getRegistrationMillis(playerName);
return registrationDate == null ? null : Instant.ofEpochMilli(registrationDate);
}
private Long getRegistrationMillis(String playerName) {
PlayerAuth auth = playerCache.getAuth(playerName);
if (auth == null) {
auth = dataSource.getAuth(playerName);
}
if (auth != null) {
return auth.getRegistrationDate();
}
return null;
}
/**
* Return whether the player is registered.
*

View File

@ -0,0 +1,65 @@
package fr.xephi.authme.api.v3;
import java.time.Instant;
import java.util.Optional;
import java.util.UUID;
/**
* Read-only player info exposed in the AuthMe API. The data in this object is copied from the
* database and not updated afterwards. As such, it may become outdated if the player data changes
* in AuthMe.
*
* @see AuthMeApi#getPlayerInfo
*/
public interface AuthMePlayer {
/**
* @return the case-sensitive name of the player, e.g. "thePlayer3030" - never null
*/
String getName();
/**
* Returns the UUID of the player as given by the server (may be offline UUID or not).
* The UUID is not present if AuthMe is configured not to store the UUID or if the data is not
* present (e.g. older record).
*
* @return player uuid, or empty optional if not available
*/
Optional<UUID> getUuid();
/**
* Returns the email address associated with this player, or an empty optional if not available.
*
* @return player's email or empty optional
*/
Optional<String> getEmail();
/**
* @return the registration date of the player's account - never null
*/
Instant getRegistrationDate();
/**
* Returns the IP address with which the player's account was registered. Returns an empty optional
* for older accounts, or if the account was registered by someone else (e.g. by an admin).
*
* @return the ip address used during the registration of the account, or empty optional
*/
Optional<String> getRegistrationIpAddress();
/**
* Returns the last login date of the player. An empty optional is returned if the player never logged in.
*
* @return date the player last logged in successfully, or empty optional if not applicable
*/
Optional<Instant> getLastLoginDate();
/**
* Returns the IP address the player last logged in with successfully. Returns an empty optional if the
* player never logged in.
*
* @return ip address the player last logged in with successfully, or empty optional if not applicable
*/
Optional<String> getLastLoginIpAddress();
}

View File

@ -0,0 +1,93 @@
package fr.xephi.authme.api.v3;
import fr.xephi.authme.data.auth.PlayerAuth;
import java.time.Instant;
import java.util.Optional;
import java.util.UUID;
/**
* Implementation of {@link AuthMePlayer}. This implementation is not part of the API and
* may have breaking changes in subsequent releases.
*/
class AuthMePlayerImpl implements AuthMePlayer {
private String name;
private UUID uuid;
private String email;
private Instant registrationDate;
private String registrationIpAddress;
private Instant lastLoginDate;
private String lastLoginIpAddress;
AuthMePlayerImpl() {
}
/**
* Maps the given player auth to an AuthMePlayer instance. Returns an empty optional if
* the player auth is null.
*
* @param playerAuth the player auth or null
* @return the mapped player auth, or empty optional if the argument was null
*/
static Optional<AuthMePlayer> fromPlayerAuth(PlayerAuth playerAuth) {
if (playerAuth == null) {
return Optional.empty();
}
AuthMePlayerImpl authMeUser = new AuthMePlayerImpl();
authMeUser.name = playerAuth.getRealName();
authMeUser.uuid = playerAuth.getUuid();
authMeUser.email = nullIfDefault(playerAuth.getEmail(), PlayerAuth.DB_EMAIL_DEFAULT);
Long lastLoginMillis = nullIfDefault(playerAuth.getLastLogin(), PlayerAuth.DB_LAST_LOGIN_DEFAULT);
authMeUser.registrationDate = toInstant(playerAuth.getRegistrationDate());
authMeUser.registrationIpAddress = playerAuth.getRegistrationIp();
authMeUser.lastLoginDate = toInstant(lastLoginMillis);
authMeUser.lastLoginIpAddress = nullIfDefault(playerAuth.getLastIp(), PlayerAuth.DB_LAST_IP_DEFAULT);
return Optional.of(authMeUser);
}
@Override
public String getName() {
return name;
}
public Optional<UUID> getUuid() {
return Optional.ofNullable(uuid);
}
@Override
public Optional<String> getEmail() {
return Optional.ofNullable(email);
}
@Override
public Instant getRegistrationDate() {
return registrationDate;
}
@Override
public Optional<String> getRegistrationIpAddress() {
return Optional.ofNullable(registrationIpAddress);
}
@Override
public Optional<Instant> getLastLoginDate() {
return Optional.ofNullable( lastLoginDate);
}
@Override
public Optional<String> getLastLoginIpAddress() {
return Optional.ofNullable(lastLoginIpAddress);
}
private static Instant toInstant(Long epochMillis) {
return epochMillis == null ? null : Instant.ofEpochMilli(epochMillis);
}
private static <T> T nullIfDefault(T value, T defaultValue) {
return defaultValue.equals(value) ? null : value;
}
}

View File

@ -28,15 +28,16 @@ import java.time.Instant;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import static fr.xephi.authme.IsEqualByReflectionMatcher.hasEqualValuesOnAllFields;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
@ -512,6 +513,36 @@ public class AuthMeApiTest {
assertThat(countryName, equalTo("Syldavia"));
}
@Test
public void shouldReturnAuthMePlayerInfo() {
// given
PlayerAuth auth = PlayerAuth.builder()
.name("bobb")
.realName("Bobb")
.registrationDate(1433166082000L)
.build();
given(dataSource.getAuth("bobb")).willReturn(auth);
// when
Optional<AuthMePlayer> result = api.getPlayerInfo("bobb");
// then
AuthMePlayer playerInfo = result.get();
assertThat(playerInfo.getName(), equalTo("Bobb"));
assertThat(playerInfo.getRegistrationDate(), equalTo(Instant.ofEpochMilli(1433166082000L)));
}
@Test
public void shouldReturnNullForNonExistentAuth() {
// given / when
Optional<AuthMePlayer> result = api.getPlayerInfo("doesNotExist");
// then
assertThat(result.isPresent(), equalTo(false));
verify(playerCache).getAuth("doesNotExist");
verify(dataSource).getAuth("doesNotExist");
}
private static Player mockPlayerWithName(String name) {
Player player = mock(Player.class);
given(player.getName()).willReturn(name);

View File

@ -0,0 +1,95 @@
package fr.xephi.authme.api.v3;
import fr.xephi.authme.data.auth.PlayerAuth;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Test;
import java.time.Instant;
import java.util.Optional;
import java.util.UUID;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
/**
* Test for {@link AuthMePlayerImpl}.
*/
public class AuthMePlayerImplTest {
@Test
public void shouldMapNullWithoutError() {
// given / when / then
assertThat(AuthMePlayerImpl.fromPlayerAuth(null), emptyOptional());
}
@Test
public void shouldMapFromPlayerAuth() {
// given
PlayerAuth auth = PlayerAuth.builder()
.name("victor")
.realName("Victor")
.email("vic@example.com")
.registrationDate(1480075661000L)
.registrationIp("124.125.126.127")
.lastLogin(1542675632000L)
.lastIp("62.63.64.65")
.uuid(UUID.fromString("deadbeef-2417-4653-9026-feedbabeface"))
.build();
// when
Optional<AuthMePlayer> result = AuthMePlayerImpl.fromPlayerAuth(auth);
// then
AuthMePlayer playerInfo = result.get();
assertThat(playerInfo.getName(), equalTo("Victor"));
assertThat(playerInfo.getUuid().get(), equalTo(auth.getUuid()));
assertThat(playerInfo.getEmail().get(), equalTo(auth.getEmail()));
assertThat(playerInfo.getRegistrationDate(), equalTo(Instant.ofEpochMilli(auth.getRegistrationDate())));
assertThat(playerInfo.getRegistrationIpAddress().get(), equalTo(auth.getRegistrationIp()));
assertThat(playerInfo.getLastLoginDate().get(), equalTo(Instant.ofEpochMilli(auth.getLastLogin())));
assertThat(playerInfo.getLastLoginIpAddress().get(), equalTo(auth.getLastIp()));
}
@Test
public void shouldHandleNullAndDefaultValues() {
// given
PlayerAuth auth = PlayerAuth.builder()
.name("victor")
.realName("Victor")
.email("your@email.com") // DB default
.registrationDate(1480075661000L)
.lastLogin(0L) // DB default
.lastIp("127.0.0.1") // DB default
.build();
// when
Optional<AuthMePlayer> result = AuthMePlayerImpl.fromPlayerAuth(auth);
// then
AuthMePlayer playerInfo = result.get();
assertThat(playerInfo.getName(), equalTo("Victor"));
assertThat(playerInfo.getUuid(), emptyOptional());
assertThat(playerInfo.getEmail(), emptyOptional());
assertThat(playerInfo.getRegistrationDate(), equalTo(Instant.ofEpochMilli(auth.getRegistrationDate())));
assertThat(playerInfo.getRegistrationIpAddress(), emptyOptional());
assertThat(playerInfo.getLastLoginDate(), emptyOptional());
assertThat(playerInfo.getLastLoginIpAddress(), emptyOptional());
}
private static <T> Matcher<Optional<T>> emptyOptional() {
return new TypeSafeMatcher<Optional<T>>() {
@Override
public void describeTo(Description description) {
description.appendText("an empty optional");
}
@Override
protected boolean matchesSafely(Optional<T> item) {
return !item.isPresent();
}
};
}
}