Skip to content

Commit 28b3a16

Browse files
committed
progress with a Serch on JS
1 parent 3ad3b58 commit 28b3a16

21 files changed

+527
-85
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package eu.solven.kumite.account;
2+
3+
import java.util.Collections;
4+
import java.util.List;
5+
import java.util.Optional;
6+
import java.util.UUID;
7+
8+
import org.springframework.web.reactive.function.server.ServerRequest;
9+
import org.springframework.web.reactive.function.server.ServerResponse;
10+
11+
import eu.solven.kumite.app.webflux.api.KumiteHandlerHelper;
12+
import lombok.AllArgsConstructor;
13+
import reactor.core.publisher.Mono;
14+
15+
@AllArgsConstructor
16+
public class AccountSearchHandler {
17+
final KumiteUsersRegistry usersRegistry;
18+
19+
public Mono<ServerResponse> searchAccounts(ServerRequest request) {
20+
// We shall later enabling searching by school/company/country
21+
UUID accountId = KumiteHandlerHelper.uuid(request, "account_id");
22+
23+
Optional<KumiteUser> optUser = usersRegistry.optUser(accountId);
24+
25+
List<KumiteUser> match = optUser.map(u -> Collections.singletonList(u)).orElse(Collections.emptyList());
26+
27+
return KumiteHandlerHelper.okAsJson(match);
28+
}
29+
}

contest-core/src/main/java/eu/solven/kumite/account/KumiteUsersRegistry.java

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package eu.solven.kumite.account;
22

3+
import java.util.Optional;
34
import java.util.UUID;
45

56
import eu.solven.kumite.player.KumitePlayer;
@@ -16,11 +17,12 @@ public final class KumiteUsersRegistry {
1617
// This maps to the latest/main one
1718
final IKumiteUserRawRawRepository userRawRawRepository;
1819

19-
public KumiteUser getUser(UUID accountId) {
20-
KumiteUserRawRaw rawUser = userRawRawRepository.getUser(accountId)
21-
.orElseThrow(() -> new IllegalArgumentException("No accountId=" + accountId));
20+
public Optional<KumiteUser> optUser(UUID accountId) {
21+
return userRawRawRepository.getUser(accountId).map(this::getUser);
22+
}
2223

23-
return getUser(rawUser);
24+
public KumiteUser getUser(UUID accountId) {
25+
return optUser(accountId).orElseThrow(() -> new IllegalArgumentException("No accountId=" + accountId));
2426
}
2527

2628
public KumiteUser getUser(KumiteUserRawRaw rawUser) {

contest-core/src/main/java/eu/solven/kumite/app/webflux/api/KumiteHandlerHelper.java

+6
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,10 @@ public static Mono<ServerResponse> okAsJson(Object body) {
5656
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(body));
5757
}
5858

59+
// public static Mono<ServerResponse> resourceGone(Map<String, ?> body) {
60+
// return ServerResponse.status(HttpStatus.NOT_FOUND)
61+
// .contentType(MediaType.APPLICATION_JSON)
62+
// .body(BodyInserters.fromValue(body));
63+
// }
64+
5965
}

contest-core/src/main/java/eu/solven/kumite/player/IAccountPlayersRegistry.java

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package eu.solven.kumite.player;
22

3+
import java.util.Optional;
34
import java.util.UUID;
45

56
/**
@@ -12,6 +13,14 @@ public interface IAccountPlayersRegistry {
1213

1314
void registerPlayer(KumitePlayer player);
1415

16+
/**
17+
* This is useful for search
18+
*
19+
* @param playerId
20+
* @return
21+
*/
22+
Optional<UUID> optAccountId(UUID playerId);
23+
1524
UUID getAccountId(UUID playerId);
1625

1726
IHasPlayers makeDynamicHasPlayers(UUID accountId);

contest-core/src/main/java/eu/solven/kumite/player/PlayersSearchHandler.java

+17-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package eu.solven.kumite.player;
22

3+
import java.util.Collections;
34
import java.util.List;
45
import java.util.Optional;
56
import java.util.UUID;
@@ -39,12 +40,22 @@ public Mono<ServerResponse> listPlayers(ServerRequest request) {
3940
players = accountPlayersRegistry.makeDynamicHasPlayers(search.getAccountId().get()).getPlayers();
4041
} else if (optPlayerId.isPresent()) {
4142
UUID playerId = search.getPlayerId().get();
42-
UUID accountId = accountPlayersRegistry.getAccountId(playerId);
43-
players = accountPlayersRegistry.makeDynamicHasPlayers(accountId)
44-
.getPlayers()
45-
.stream()
46-
.filter(p -> p.getPlayerId().equals(playerId))
47-
.collect(Collectors.toList());
43+
Optional<UUID> optAccountIdFromPlayer = accountPlayersRegistry.optAccountId(playerId);
44+
45+
if (optAccountIdFromPlayer.isEmpty()) {
46+
players = Collections.emptyList();
47+
} else {
48+
UUID accountIdFromPlayer = optAccountIdFromPlayer.get();
49+
if (search.getAccountId().isPresent() && !search.getAccountId().get().equals(accountIdFromPlayer)) {
50+
players = Collections.emptyList();
51+
} else {
52+
players = accountPlayersRegistry.makeDynamicHasPlayers(accountIdFromPlayer)
53+
.getPlayers()
54+
.stream()
55+
.filter(p -> p.getPlayerId().equals(playerId))
56+
.collect(Collectors.toList());
57+
}
58+
}
4859
} else {
4960
throw new IllegalArgumentException("Need at least one filtering clause");
5061
}

contest-core/src/main/java/eu/solven/kumite/player/persistence/BijectiveAccountPlayersRegistry.java

+6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.Arrays;
44
import java.util.Collections;
55
import java.util.List;
6+
import java.util.Optional;
67
import java.util.UUID;
78

89
import eu.solven.kumite.account.fake_player.FakePlayer;
@@ -99,4 +100,9 @@ public static UUID playerIdGivenAccountId(UUID accountId) {
99100
public static UUID accountIdGivenPlayerId(UUID playerId) {
100101
return playerIdGivenAccountId(playerId);
101102
}
103+
104+
@Override
105+
public Optional<UUID> optAccountId(UUID playerId) {
106+
return Optional.of(getAccountId(playerId));
107+
}
102108
}

contest-core/src/main/java/eu/solven/kumite/player/persistence/InMemoryAccountPlayersRegistry.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package eu.solven.kumite.player.persistence;
22

33
import java.util.Map;
4+
import java.util.Optional;
45
import java.util.Set;
56
import java.util.UUID;
67
import java.util.concurrent.ConcurrentHashMap;
@@ -46,13 +47,14 @@ public void registerPlayer(KumitePlayer player) {
4647
}
4748
}
4849

50+
@Override
51+
public Optional<UUID> optAccountId(UUID playerId) {
52+
return Optional.ofNullable(playerIdToAccountId.get(playerId));
53+
}
54+
4955
@Override
5056
public UUID getAccountId(UUID playerId) {
51-
UUID accountId = playerIdToAccountId.get(playerId);
52-
if (accountId == null) {
53-
throw new IllegalArgumentException("Unknown playerId: " + playerId);
54-
}
55-
return accountId;
57+
return optAccountId(playerId).orElseThrow(() -> new IllegalArgumentException("Unknown playerId: " + playerId));
5658
}
5759

5860
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package eu.solven.kumite.account;
2+
3+
import java.util.Optional;
4+
import java.util.UUID;
5+
6+
import org.assertj.core.api.Assertions;
7+
import org.junit.jupiter.api.Test;
8+
import org.junit.jupiter.api.extension.ExtendWith;
9+
import org.mockito.Mockito;
10+
import org.springframework.beans.factory.annotation.Autowired;
11+
import org.springframework.test.context.ActiveProfiles;
12+
import org.springframework.test.context.ContextConfiguration;
13+
import org.springframework.test.context.junit.jupiter.SpringExtension;
14+
import org.springframework.web.reactive.function.server.ServerRequest;
15+
import org.springframework.web.reactive.function.server.ServerResponse;
16+
17+
import eu.solven.kumite.account.fake_player.RandomPlayer;
18+
import eu.solven.kumite.app.IKumiteSpringProfiles;
19+
import eu.solven.kumite.app.KumiteServerComponentsConfiguration;
20+
21+
@ExtendWith(SpringExtension.class)
22+
@ContextConfiguration(classes = {
23+
24+
KumiteServerComponentsConfiguration.class,
25+
26+
AccountSearchHandler.class,
27+
28+
})
29+
@ActiveProfiles({ IKumiteSpringProfiles.P_INMEMORY })
30+
public class TestKumiteAccountsHandler {
31+
@Autowired
32+
AccountSearchHandler accountsSearchHandler;
33+
34+
@Test
35+
public void testNoFilter() {
36+
ServerRequest request = Mockito.mock(ServerRequest.class);
37+
38+
Assertions.assertThatThrownBy(() -> accountsSearchHandler.searchAccounts(request).block())
39+
.isInstanceOf(IllegalArgumentException.class);
40+
}
41+
42+
@Test
43+
public void testUnknownAccount() {
44+
ServerRequest request = Mockito.mock(ServerRequest.class);
45+
Mockito.when(request.queryParam("account_id")).thenReturn(Optional.of(UUID.randomUUID().toString()));
46+
47+
// TODO Check the output is empty
48+
ServerResponse serverResponse = accountsSearchHandler.searchAccounts(request).block();
49+
}
50+
51+
@Test
52+
public void testRandomPlayer() {
53+
ServerRequest request = Mockito.mock(ServerRequest.class);
54+
Mockito.when(request.queryParam("account_id")).thenReturn(Optional.of(RandomPlayer.ACCOUNT_ID.toString()));
55+
56+
// TODO Check the output is empty
57+
accountsSearchHandler.searchAccounts(request).block();
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package eu.solven.kumite.player;
2+
3+
import java.util.Optional;
4+
import java.util.UUID;
5+
6+
import org.assertj.core.api.Assertions;
7+
import org.junit.jupiter.api.Test;
8+
import org.junit.jupiter.api.extension.ExtendWith;
9+
import org.mockito.Mockito;
10+
import org.springframework.beans.factory.annotation.Autowired;
11+
import org.springframework.test.context.ActiveProfiles;
12+
import org.springframework.test.context.ContextConfiguration;
13+
import org.springframework.test.context.junit.jupiter.SpringExtension;
14+
import org.springframework.web.reactive.function.server.ServerRequest;
15+
16+
import eu.solven.kumite.account.fake_player.RandomPlayer;
17+
import eu.solven.kumite.app.IKumiteSpringProfiles;
18+
import eu.solven.kumite.app.KumiteServerComponentsConfiguration;
19+
20+
@ExtendWith(SpringExtension.class)
21+
@ContextConfiguration(classes = {
22+
23+
KumiteServerComponentsConfiguration.class,
24+
25+
PlayersSearchHandler.class,
26+
27+
})
28+
@ActiveProfiles({ IKumiteSpringProfiles.P_INMEMORY })
29+
public class TestKumitePlayerHandler {
30+
@Autowired
31+
PlayersSearchHandler playersSearchHandler;
32+
33+
@Test
34+
public void testNoFilter() {
35+
ServerRequest request = Mockito.mock(ServerRequest.class);
36+
37+
Assertions.assertThatThrownBy(() -> playersSearchHandler.listPlayers(request).block())
38+
.isInstanceOf(IllegalArgumentException.class);
39+
}
40+
41+
@Test
42+
public void testUnknownPlayer() {
43+
ServerRequest request = Mockito.mock(ServerRequest.class);
44+
Mockito.when(request.queryParam("player_id")).thenReturn(Optional.of(UUID.randomUUID().toString()));
45+
46+
// TODO Check the output is empty
47+
playersSearchHandler.listPlayers(request).block();
48+
}
49+
50+
@Test
51+
public void testRandomPlayer() {
52+
ServerRequest request = Mockito.mock(ServerRequest.class);
53+
Mockito.when(request.queryParam("player_id")).thenReturn(Optional.of(RandomPlayer.PLAYERID_1.toString()));
54+
55+
// TODO Check the output is empty
56+
playersSearchHandler.listPlayers(request).block();
57+
}
58+
}

js/src/main/resources/static/index.html

+8
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
import KumiteContest from "./ui/js/kumite-contest.js";
5454
import KumiteBoardOverview from "./ui/js/kumite-board-overview.js";
5555
import KumiteBoardPlay from "./ui/js/kumite-board-play.js";
56+
import KumiteSearch from "./ui/js/kumite-search.js";
5657
import Login from "./ui/js/login.js";
5758
import LoginBasic from "./ui/js/login-basic.js";
5859
import AboutView from "./ui/js/about.js";
@@ -122,6 +123,13 @@
122123
// https://stackoverflow.com/questions/44783787/bind-query-to-props-with-vue-router
123124
// props: route => Object.assign({}, route.query, route.params)
124125
},
126+
{
127+
path: "/html/search/:someId?",
128+
name: "search",
129+
component: KumiteSearch,
130+
props: true,
131+
},
132+
125133
{ path: "/html/about", component: AboutView },
126134
];
127135

js/src/main/resources/static/ui/js/kumite-contest-delete.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export default {
2828
setup(props) {
2929
const store = useKumiteStore();
3030

31-
store.loadContestIfMissing(props.gameId, props.contestId);
31+
store.loadContestIfMissing(props.contestId, props.gameId);
3232

3333
return {};
3434
},

js/src/main/resources/static/ui/js/kumite-contest-header.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export default {
5858

5959
const nextInterval = setInterval(() => {
6060
console.log("Intervalled shortPollContestDynamic");
61-
store.loadContest(props.gameId, props.contestId);
61+
store.loadContest(props.contestId, props.gameId);
6262
}, intervalPeriodMs);
6363
shortPollContestDynamicInterval.value = nextInterval;
6464

@@ -73,7 +73,7 @@ export default {
7373
clearShortPollContestDynamic();
7474
});
7575

76-
store.loadContestIfMissing(props.gameId, props.contestId);
76+
store.loadContestIfMissing(props.contestId, props.gameId);
7777

7878
return {};
7979
},

js/src/main/resources/static/ui/js/kumite-contest.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export default {
4646
setup(props) {
4747
const store = useKumiteStore();
4848

49-
store.loadContestIfMissing(props.gameId, props.contestId);
49+
store.loadContestIfMissing(props.contestId, props.gameId);
5050

5151
return {};
5252
},

js/src/main/resources/static/ui/js/kumite-contests.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import { mapState } from "pinia";
22
import { useKumiteStore } from "./store.js";
3+
4+
import LoginRef from "./login-ref.js";
35
import KumiteContest from "./kumite-contest.js";
46

57
export default {
68
// https://vuejs.org/guide/components/registration#local-registration
79
components: {
10+
LoginRef,
811
KumiteContest,
912
},
1013
// https://vuejs.org/guide/components/props.html
@@ -56,8 +59,8 @@ export default {
5659
},
5760

5861
template: /* HTML */ `
59-
<div v-if="!isLoggedIn">You need to login</div>
60-
<div v-if="Object.values(contests).length == 0 && nbContestFetching > 0">Loading contests</div>
62+
<div v-if="!isLoggedIn"><LoginRef /></div>
63+
<div v-else-if="Object.values(contests).length == 0 && nbContestFetching > 0">Loading contests</div>
6164
<div v-else class="container">
6265
<div class="row border" v-for="contest in contests">
6366
<KumiteContest

js/src/main/resources/static/ui/js/kumite-navbar.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,12 @@ export default {
4343
<li class="nav-item">
4444
<RouterLink class="nav-link" to="/html/about"><i class="bi bi-info-lg" />About</RouterLink>
4545
</li>
46-
4746
<li class="nav-item" v-if="isLoggedIn">
4847
<RouterLink class="nav-link" to="/html/me"><i class="bi bi-person" />Account Settings</RouterLink>
4948
</li>
49+
<li class="nav-item">
50+
<RouterLink class="nav-link" to="/html/search"><i class="bi bi-search" />Search</RouterLink>
51+
</li>
5052
</ul>
5153
<span v-if="isLoggedIn">
5254
{{account.raw.name}}<img

js/src/main/resources/static/ui/js/kumite-player-ref.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,9 @@ export default {
2929

3030
return {};
3131
},
32-
template: /* HTML */ ` <RouterLink :to="{path:'/html/players/' + playerId}"> <i class="bi bi-android"></i>playerId: {{ playerId }} </RouterLink> `,
32+
template: /* HTML */ `
33+
<RouterLink :to="{path:'/html/players/' + playerId}">
34+
<i class="bi bi-android"></i>playerId: {{ playerId }} <span v-if="account.accountId === player.accountId"> (You)</span></RouterLink
35+
>
36+
`,
3337
};

0 commit comments

Comments
 (0)