Skip to content

Commit

Permalink
Add population of the service links table (#536)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sheikah45 authored Jul 23, 2022
1 parent ed99422 commit 86b87fc
Show file tree
Hide file tree
Showing 16 changed files with 284 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
@Configuration
public class MainDbTestContainers {
private static final MariaDBContainer<?> fafDBContainer = new MariaDBContainer<>("mariadb:10.6");
private static final GenericContainer<?> flywayMigrationsContainer = new GenericContainer<>("faforever/faf-db-migrations:v125");
private static final GenericContainer<?> flywayMigrationsContainer = new GenericContainer<>("faforever/faf-db-migrations:v126");
private static final Network sharedNetwork = Network.newNetwork();

@Bean
Expand Down
15 changes: 0 additions & 15 deletions src/inttest/java/com/faforever/api/data/PlayerElideTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@ public void restrictedResultWithoutScope() throws Exception {
.andExpect(jsonPath("$.data[1].attributes", not(hasKey("email"))))
.andExpect(jsonPath("$.data[2].attributes", not(hasKey("email"))))
.andExpect(jsonPath("$.data[3].attributes", not(hasKey("email"))))
.andExpect(jsonPath("$.data[0].attributes", not(hasKey("steamId"))))
.andExpect(jsonPath("$.data[1].attributes", not(hasKey("steamId"))))
.andExpect(jsonPath("$.data[2].attributes", not(hasKey("steamId"))))
.andExpect(jsonPath("$.data[3].attributes", not(hasKey("steamId"))))
.andExpect(jsonPath("$.data[0].attributes", not(hasKey("recentIpAddress"))))
.andExpect(jsonPath("$.data[1].attributes", not(hasKey("recentIpAddress"))))
.andExpect(jsonPath("$.data[2].attributes", not(hasKey("recentIpAddress"))))
Expand All @@ -59,7 +55,6 @@ public void restrictedResultWithoutScope() throws Exception {
// you are allowed to see your own stuff
.andExpect(jsonPath("$.data[4].attributes.email", is("[email protected]")))
.andExpect(jsonPath("$.data[4].attributes.recentIpAddress", is("127.0.0.1")))
.andExpect(jsonPath("$.data[4].attributes", hasKey("steamId")))
.andExpect(jsonPath("$.data[4].attributes", hasKey("lastLogin")))
// you cannot see your uuid
.andExpect(jsonPath("$.data[4].relationships", not(hasKey("uniqueIds"))))
Expand Down Expand Up @@ -97,10 +92,6 @@ public void restrictedResultWithoutRole() throws Exception {
.andExpect(jsonPath("$.data[1].attributes", not(hasKey("email"))))
.andExpect(jsonPath("$.data[2].attributes", not(hasKey("email"))))
.andExpect(jsonPath("$.data[3].attributes", not(hasKey("email"))))
.andExpect(jsonPath("$.data[0].attributes", not(hasKey("steamId"))))
.andExpect(jsonPath("$.data[1].attributes", not(hasKey("steamId"))))
.andExpect(jsonPath("$.data[2].attributes", not(hasKey("steamId"))))
.andExpect(jsonPath("$.data[3].attributes", not(hasKey("steamId"))))
.andExpect(jsonPath("$.data[0].attributes", not(hasKey("recentIpAddress"))))
.andExpect(jsonPath("$.data[1].attributes", not(hasKey("recentIpAddress"))))
.andExpect(jsonPath("$.data[2].attributes", not(hasKey("recentIpAddress"))))
Expand All @@ -116,7 +107,6 @@ public void restrictedResultWithoutRole() throws Exception {
// you are allowed to see your own stuff
.andExpect(jsonPath("$.data[4].attributes.email", is("[email protected]")))
.andExpect(jsonPath("$.data[4].attributes.recentIpAddress", is("127.0.0.1")))
.andExpect(jsonPath("$.data[4].attributes", hasKey("steamId")))
.andExpect(jsonPath("$.data[4].attributes", hasKey("lastLogin")))
.andExpect(jsonPath("$.data[4].relationships", hasKey("reporterOnModerationReports")))
.andExpect(jsonPath("$.data[4].relationships", hasKey("userGroups")))
Expand Down Expand Up @@ -167,11 +157,6 @@ public void canSeePrivateDetailsWithScopeAndRole() throws Exception {
.andExpect(jsonPath("$.data[2].attributes", hasKey("lastLogin")))
.andExpect(jsonPath("$.data[3].attributes", hasKey("lastLogin")))
.andExpect(jsonPath("$.data[4].attributes", hasKey("lastLogin")))
.andExpect(jsonPath("$.data[0].attributes", hasKey("steamId")))
.andExpect(jsonPath("$.data[1].attributes", hasKey("steamId")))
.andExpect(jsonPath("$.data[2].attributes", hasKey("steamId")))
.andExpect(jsonPath("$.data[3].attributes", hasKey("steamId")))
.andExpect(jsonPath("$.data[4].attributes", hasKey("steamId")))
.andExpect(jsonPath("$.data[0].relationships", hasKey("uniqueIds")))
.andExpect(jsonPath("$.data[1].relationships", hasKey("uniqueIds")))
.andExpect(jsonPath("$.data[2].relationships", hasKey("uniqueIds")))
Expand Down
39 changes: 30 additions & 9 deletions src/inttest/java/com/faforever/api/user/UsersControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import com.faforever.api.AbstractIntegrationTest;
import com.faforever.api.data.domain.GroupPermission;
import com.faforever.api.data.domain.LinkedServiceType;
import com.faforever.api.data.domain.User;
import com.faforever.api.email.EmailSender;
import com.faforever.api.error.ErrorCode;
Expand All @@ -24,7 +25,6 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
Expand Down Expand Up @@ -61,6 +61,9 @@ public class UsersControllerTest extends AbstractIntegrationTest {
@Autowired
private UserRepository userRepository;

@Autowired
private AccountLinkRepository accountLinkRepository;

@Test
public void registerWithSuccess() throws Exception {
MultiValueMap<String, String> params = new HttpHeaders();
Expand Down Expand Up @@ -292,9 +295,10 @@ public void buildSteamLinkUrl() throws Exception {

@Test
public void linkToSteam() throws Exception {
assertThat(userRepository.getById(1).getSteamId(), nullValue());

String steamId = "12345";

assertThat(accountLinkRepository.findOneByServiceIdAndServiceType(steamId, LinkedServiceType.STEAM).isEmpty(), is(true));

String callbackUrl = "http://faforever.com";
String token = fafTokenService.createToken(
FafTokenType.LINK_TO_STEAM,
Expand All @@ -312,15 +316,14 @@ public void linkToSteam() throws Exception {
.andExpect(status().isFound())
.andExpect(redirectedUrl(callbackUrl));

assertThat(userRepository.getById(1).getSteamId(), is(steamId));
assertThat(accountLinkRepository.findOneByServiceIdAndServiceType(steamId, LinkedServiceType.STEAM).get().getUser().getId(), is(1));
}

@Test
public void linkToSteamAlreadyLinkedAccount() throws Exception {
String steamId = "1234";
assertThat(userRepository.getById(1).getSteamId(), nullValue());
User userThatOwnsSteamId = userRepository.getById(2);
assertThat(userThatOwnsSteamId.getSteamId(), is(steamId));
User userThatOwnsSteamId = accountLinkRepository.findOneByServiceIdAndServiceType(steamId, LinkedServiceType.STEAM).get().getUser();
assertThat(userThatOwnsSteamId.getId(), is(2));

String callbackUrl = "http://faforever.com";
String token = fafTokenService.createToken(
Expand All @@ -340,7 +343,7 @@ public void linkToSteamAlreadyLinkedAccount() throws Exception {
.andExpect(redirectedUrlPattern(callbackUrl + "?errors=*" + ErrorCode.STEAM_ID_ALREADY_LINKED.getCode() + "*" + userThatOwnsSteamId.getLogin() + "*"));
//We expect and error with code STEAM_ID_ALREADY_LINKED and that the error message contains the user that this steam account was linked to already which is MODERATOR with id 2

assertThat(userRepository.getById(1).getSteamId(), nullValue());
assertThat(accountLinkRepository.existsByUserAndServiceType(userRepository.getReferenceById(1), LinkedServiceType.STEAM), is(false));
}

@Test
Expand Down Expand Up @@ -508,7 +511,7 @@ public void linkToGogWithoutOAuthScopeFails() throws Exception {
}

@Test
public void linkToGogWithoutSuccess() throws Exception {
public void linkToGogSuccess() throws Exception {
MultiValueMap<String, String> params = new HttpHeaders();
params.add("gogUsername", "someUsername");

Expand All @@ -519,5 +522,23 @@ public void linkToGogWithoutSuccess() throws Exception {
.with(getOAuthTokenForUserId(USERID_USER, OAuthScope._WRITE_ACCOUNT_DATA))
.params(params))
.andExpect(status().isOk());

assertThat(accountLinkRepository.existsByUserAndServiceType(userRepository.getReferenceById(1), LinkedServiceType.GOG), is(true));
}

@Test
public void linkToGogAlreadyLinked() throws Exception {
MultiValueMap<String, String> params = new HttpHeaders();
params.add("gogUsername", "username");

when(gogService.buildGogToken(any())).thenReturn("theToken");

mockMvc.perform(
post("/users/linkToGog")
.with(getOAuthTokenForUserId(USERID_USER, OAuthScope._WRITE_ACCOUNT_DATA))
.params(params))
.andExpect(status().isUnprocessableEntity());

assertThat(accountLinkRepository.existsByUserAndServiceType(userRepository.getReferenceById(1), LinkedServiceType.GOG), is(false));
}
}
2 changes: 1 addition & 1 deletion src/inttest/java/com/faforever/api/utils/OAuthHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public OAuthHelper(PlayerRepository playerRepository) {
}

public RequestPostProcessor addBearerTokenForUser(int userId, @NotNull Set<String> scopes) {
Player user = playerRepository.getById(userId);
Player user = playerRepository.getReferenceById(userId);

Set<FafRole> roles = user.getUserGroups().stream()
.flatMap(userGroup -> userGroup.getPermissions().stream())
Expand Down
18 changes: 10 additions & 8 deletions src/inttest/resources/sql/prepDefaultData.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ VALUES ('test', 'test', '{noop}test', 'public', 'http://localhost https://www.ge
'http://localhost',
'read_events read_achievements upload_map upload_mod upload_avatar write_account_data vote read_sensible_userdata');

INSERT INTO login (id, login, email, password, steamid, ip)
VALUES (1, 'USER', '[email protected]', '92b7b421992ef490f3b75898ec0e511f1a5c02422819d89719b20362b023ee4f', NULL,
INSERT INTO login (id, login, email, password, ip)
VALUES (1, 'USER', '[email protected]', '92b7b421992ef490f3b75898ec0e511f1a5c02422819d89719b20362b023ee4f',
'127.0.0.1'),
(2, 'MODERATOR', '[email protected]', '778ac5b81fa251b450f827846378739caee510c31b01cfa9d31822b88bed8441',
1234, '127.0.0.1'),
(3, 'ADMIN', '[email protected]', '835d6dc88b708bc646d6db82c853ef4182fabbd4a8de59c213f2b5ab3ae7d9be', NULL,
'127.0.0.1'),
(4, 'BANNED', '[email protected]', '', NULL, '127.0.0.1'),
(5, 'ACTIVE_USER', '[email protected]', '', null, '127.0.0.1');
(2, 'MODERATOR', '[email protected]', '778ac5b81fa251b450f827846378739caee510c31b01cfa9d31822b88bed8441', '127.0.0.1'),
(3, 'ADMIN', '[email protected]', '835d6dc88b708bc646d6db82c853ef4182fabbd4a8de59c213f2b5ab3ae7d9be', '127.0.0.1'),
(4, 'BANNED', '[email protected]', '', '127.0.0.1'),
(5, 'ACTIVE_USER', '[email protected]', '', '127.0.0.1');

INSERT INTO service_links (id, user_id, service_id, type, public, ownership)
VALUES (UUID(), 2, '1234', 'STEAM', false, true),
(UUID(), 2, 'username', 'GOG', false, true);

INSERT INTO user_group (id, technical_name, name_key, parent_group_id, public)
VALUES (1, 'ADMINISTRATOR', 'administrator', null, true),
Expand Down
1 change: 1 addition & 0 deletions src/inttest/resources/sql/truncateTables.sql
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ DELETE FROM `patchs_table`;
DELETE FROM `player_achievements`;
DELETE FROM `player_events`;
DELETE FROM `reported_user`;
DELETE FROM `service_links`;
DELETE FROM `table_map_comments`;
DELETE FROM `teamkills`;
DELETE FROM `tutorial`;
Expand Down
84 changes: 84 additions & 0 deletions src/main/java/com/faforever/api/data/domain/AccountLink.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.faforever.api.data.domain;

import com.faforever.api.data.checks.IsEntityOwner;
import com.faforever.api.data.checks.Prefab;
import com.faforever.api.security.elide.permission.ReadAccountPrivateDetailsCheck;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.yahoo.elide.annotation.Include;
import com.yahoo.elide.annotation.ReadPermission;
import com.yahoo.elide.annotation.UpdatePermission;
import lombok.Setter;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Transient;

@Entity
@Table(name = "service_links")
@Include(name = "accountLink")
@Setter
@ReadPermission(expression = IsEntityOwner.EXPRESSION + " OR " + ReadAccountPrivateDetailsCheck.EXPRESSION)
public class AccountLink implements OwnableEntity {

private String id;
private User user;
private LinkedServiceType serviceType;
private String serviceId;
private boolean public_;
private boolean ownership;

@Id
@Column(name = "id")
public String getId() {
return id;
}

@Column(name = "type")
@Enumerated(EnumType.STRING)
public LinkedServiceType getServiceType() {
return serviceType;
}

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
public User getUser() {
return user;
}

@Column(name = "service_id")
@UpdatePermission(expression = Prefab.NONE)
public String getServiceId() {
return serviceId;
}

@Column(name = "public")
@ReadPermission(expression = ReadAccountPrivateDetailsCheck.EXPRESSION)
public boolean getPublic() {
return public_;
}

public AccountLink setPublic(boolean public_) {
this.public_ = public_;
return this;
}

@Column(name = "ownership")
@ReadPermission(expression = ReadAccountPrivateDetailsCheck.EXPRESSION)
public boolean getOwnership() {
return ownership;
}

@Override
@Transient
@JsonIgnore
public Login getEntityOwner() {
return user;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.faforever.api.data.domain;

public enum LinkedServiceType {
STEAM, GOG, DISCORD, PATREON;
}
21 changes: 7 additions & 14 deletions src/main/java/com/faforever/api/data/domain/Login.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,9 @@ public abstract class Login extends AbstractEntity<Login> implements OwnableEnti

private String login;
private String email;
private String steamId;
private String gogId;
private String userAgent;
private Set<BanInfo> bans;
private Set<AccountLink> accountLinks;
private Set<UserNote> userNotes;
private Set<UserGroup> userGroups;
private String recentIpAddress;
Expand All @@ -59,18 +58,6 @@ public String getEmail() {
return email;
}

@Column(name = "steamid")
@ReadPermission(expression = IsEntityOwner.EXPRESSION + " OR " + ReadAccountPrivateDetailsCheck.EXPRESSION)
public String getSteamId() {
return steamId;
}

@Column(name = "gog_id")
@ReadPermission(expression = IsEntityOwner.EXPRESSION + " OR " + ReadAccountPrivateDetailsCheck.EXPRESSION)
public String getGogId() {
return gogId;
}

@Column(name = "ip")
@ReadPermission(expression = IsEntityOwner.EXPRESSION + " OR " + ReadAccountPrivateDetailsCheck.EXPRESSION)
public String getRecentIpAddress() {
Expand Down Expand Up @@ -103,6 +90,12 @@ public Set<UserNote> getUserNotes() {
return this.userNotes;
}

@OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
@BatchSize(size = 1000)
public Set<AccountLink> getAccountLinks() {
return this.accountLinks;
}

@Transient
public Set<BanInfo> getActiveBans() {
return getBans().stream().filter(ban -> ban.getBanStatus() == BanStatus.BANNED).collect(Collectors.toSet());
Expand Down
16 changes: 16 additions & 0 deletions src/main/java/com/faforever/api/user/AccountLinkRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.faforever.api.user;

import com.faforever.api.data.domain.AccountLink;
import com.faforever.api.data.domain.LinkedServiceType;
import com.faforever.api.data.domain.Login;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface AccountLinkRepository extends JpaRepository<AccountLink, String> {
Optional<AccountLink> findOneByServiceIdAndServiceType(String serviceId, LinkedServiceType serviceType);

boolean existsByUserAndServiceType(Login login, LinkedServiceType serviceType);
}
4 changes: 0 additions & 4 deletions src/main/java/com/faforever/api/user/UserRepository.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,8 @@ public interface UserRepository extends JpaRepository<User, Integer> {

Optional<User> findOneByEmail(String email);

Optional<User> findOneBySteamId(String steamId);

Optional<User> findOneByLoginOrEmail(String login, String email);

Optional<User> findOneByGogId(String gogId);

boolean existsByEmail(String email);

boolean existsByLogin(String login);
Expand Down
Loading

0 comments on commit 86b87fc

Please sign in to comment.