Skip to content

Commit b484ce4

Browse files
committed
Polish Logout
1 parent 7ad7313 commit b484ce4

File tree

54 files changed

+267
-281
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+267
-281
lines changed

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export default {
2727
},
2828
template: /* HTML */ `
2929
<RouterLink :to="{path:'/html/me'}">
30-
<i class="bi bi-person"></i>accountId: {{ accountId }} <span v-if="account.accountId === accountId">You</span>
30+
<i class="bi bi-person"></i>accountId: {{ accountId }}<span v-if="account.accountId === accountId"> (You)</span>
3131
</RouterLink>
3232
`,
3333
};

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

+4-3
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ export default {
3333
method: {},
3434
setup(props) {
3535
const store = useKumiteStore();
36-
37-
const contestName = ref("A nice name for a contest");
36+
37+
38+
const contestName = ref('');
3839
const createdContest = ref({});
3940

4041
const submitContestForm = function () {
@@ -94,7 +95,7 @@ export default {
9495
9596
<form>
9697
<div class="mb-3">
97-
<label for="contestName" class="form-label">Email address</label>
98+
<label for="contestName" class="form-label">Contest name</label>
9899
<input type="text" class="form-control" id="contestName" v-model="contestName" aria-describedby="emailHelp" />
99100
<div id="emailHelp" class="form-text">Pick a name so your friends can find your contest.</div>
100101
</div>

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,14 @@ export default {
4040
<span v-if="withDescription">
4141
<h1>
4242
<RouterLink :to="{path:'/html/games/' + game.gameId}"><i class="bi bi-puzzle"></i> {{game.title}}</RouterLink>
43-
<RouterLink :to="{path:'/html/games'}"><i class="bi bi-arrow-90deg-left"></i></RouterLink>
43+
<!--RouterLink :to="{path:'/html/games'}"><i class="bi bi-arrow-90deg-left"></i></RouterLink-->
4444
</h1>
4545
Game-Description: {{game.shortDescription}}
4646
</span>
4747
<span v-else>
4848
<h5>
4949
<RouterLink :to="{path:'/html/games/' + game.gameId}"><i class="bi bi-puzzle"></i> {{game.title}}</RouterLink>
50-
<RouterLink :to="{path:'/html/games'}"><i class="bi bi-arrow-90deg-left"></i></RouterLink>
50+
<!--RouterLink :to="{path:'/html/games'}"><i class="bi bi-arrow-90deg-left"></i></RouterLink-->
5151
</h5>
5252
</span>
5353
</span>

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

+16-13
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import { mapState } from "pinia";
22
import { useKumiteStore } from "./store.js";
33

4+
import Logout from "./login-logout.js";
5+
46
export default {
7+
components: {
8+
Logout,
9+
},
510
computed: {
6-
...mapState(useKumiteStore, ["needsToLogin", "account", "tokens", "nbAccountFetching", "playingPlayerId"]),
11+
...mapState(useKumiteStore, ["needsToLogin", "isLoggedIn", "account", "tokens", "nbAccountFetching", "playingPlayerId"]),
712
},
813
setup() {
914
const store = useKumiteStore();
@@ -40,31 +45,29 @@ export default {
4045
<div class="collapse navbar-collapse" id="navbarSupportedContent">
4146
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
4247
<li class="nav-item">
43-
<RouterLink class="nav-link active" aria-current="page" to="/">Home</RouterLink>
44-
</li>
45-
<li class="nav-item">
46-
<RouterLink class="nav-link" to="/html/games">Games</RouterLink>
48+
<RouterLink class="nav-link" to="/html/games"><i class="bi bi-puzzle"/>Games</RouterLink>
4749
</li>
4850
<li class="nav-item">
49-
<RouterLink class="nav-link" to="/html/contests">Contests</RouterLink>
51+
<RouterLink class="nav-link" to="/html/contests"><i class="bi bi-trophy"/>Contests</RouterLink>
5052
</li>
5153
<li class="nav-item">
52-
<RouterLink class="nav-link" to="/html/about">About</RouterLink>
54+
<RouterLink class="nav-link" to="/html/about"><i class="bi bi-info-lg"/>About</RouterLink>
5355
</li>
5456
55-
<li class="nav-item" v-if="account.raw">
56-
<RouterLink class="nav-link" to="/html/me">Account Settings</RouterLink>
57+
<li class="nav-item" v-if="isLoggedIn">
58+
<RouterLink class="nav-link" to="/html/me"><i class="bi bi-person"/>Account Settings</RouterLink>
5759
</li>
5860
</ul>
59-
<span v-if="account.raw">
60-
Current user: {{account.raw.name}}<img
61+
<span v-if="isLoggedIn">
62+
{{account.raw.name}}<img
6163
:src="account.raw.picture"
6264
class="img-thumbnail"
6365
alt="You're looking nice"
64-
width="128"
65-
height="128"
66+
width="64"
67+
height="64"
6668
v-if="account.raw.picture"
6769
/>
70+
<Logout />
6871
</span>
6972
</div>
7073
</div>

js/src/main/resources/static/ui/js/login-checker.js

+4-75
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ import { useKumiteStore } from "./store.js";
66
import { useRouter } from "vue-router";
77

88
import LoginOptions from "./login-providers.js";
9+
import Logout from "./login-logout.js";
910

1011
export default {
11-
// https://vuejs.org/guide/components/registration#local-registration
1212
components: {
1313
LoginOptions,
14+
Logout,
1415
},
1516
props: {
1617
logout: {
@@ -28,80 +29,10 @@ export default {
2829
},
2930
setup(props) {
3031
const store = useKumiteStore();
31-
const router = useRouter();
3232

3333
store.loadUser();
3434

35-
const csrfToken = ref({});
36-
const fetchCsrfToken = async function () {
37-
try {
38-
const response = await fetch(`/api/login/v1/csrf`);
39-
if (!response.ok) {
40-
throw new Error("Rejected request for logout");
41-
}
42-
43-
const json = await response.json();
44-
const csrfHeader = json.header;
45-
console.log("csrf header", csrfHeader);
46-
47-
const freshCrsfToken = response.headers.get(csrfHeader);
48-
if (!freshCrsfToken) {
49-
throw new Error("Invalid csrfToken");
50-
}
51-
console.debug("csrf", freshCrsfToken);
52-
53-
csrfToken.value = { header: csrfHeader, token: freshCrsfToken };
54-
} catch (e) {
55-
console.error("Issue on Network: ", e);
56-
}
57-
};
58-
59-
const doLogout = function () {
60-
console.info("Logout");
61-
async function fetchFromUrl(url) {
62-
// https://www.baeldung.com/spring-security-csrf
63-
// If we relied on Cookie, `.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())` we could get the csrfToken with:
64-
// const csrfToken = document.cookie.replace(/(?:(?:^|.*;\s*)XSRF-TOKEN\s*\=\s*([^;]*).*$)|^.*$/, '$1');
65-
66-
// https://stackoverflow.com/questions/60265617/how-do-you-include-a-csrf-token-in-a-vue-js-application-with-a-spring-boot-backe
67-
const headers = { [csrfToken.value.header]: csrfToken.value.token };
68-
69-
try {
70-
const response = await fetch(url, {
71-
method: "POST",
72-
headers: headers,
73-
74-
// https://stackoverflow.com/questions/39735496/redirect-after-a-fetch-post-call
75-
// https://github.com/whatwg/fetch/issues/601#issuecomment-502667208
76-
redirect: "follow",
77-
});
78-
if (!response.ok) {
79-
throw new Error("Rejected request for logout");
80-
}
81-
82-
const json = await response.json();
83-
84-
// We we can not intercept 3XX to extract the Location header, we introduced an API providing the Location as body of a 2XX.
85-
const logoutHtmlRoute = json["Location"];
86-
87-
console.info("Redirect to logout route", logoutHtmlRoute);
88-
89-
router.push(logoutHtmlRoute);
90-
91-
// We force reloading the page to take in account the removed SESSION
92-
// There should be a cleaner way to do it, without full-reload
93-
router.go(0);
94-
} catch (e) {
95-
console.error("Issue on Network: ", e);
96-
}
97-
}
98-
99-
fetchCsrfToken().then(() => {
100-
fetchFromUrl(`/logout`);
101-
});
102-
};
103-
104-
return { doLogout };
35+
return { };
10536
},
10637
template: /* HTML */ `
10738
<div v-if="needsToLogin">
@@ -111,9 +42,7 @@ export default {
11142
</div>
11243
</div>
11344
<div v-else>
114-
Welcome {{user.raw.name}}.
115-
116-
<button class="btn btn-danger" @click="doLogout">Logout</button>
45+
Welcome {{user.raw.name}}. <Logout />
11746
</div>
11847
`,
11948
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { ref, watch } from "vue";
2+
3+
import { mapState } from "pinia";
4+
import { useKumiteStore } from "./store.js";
5+
6+
import { useRouter } from "vue-router";
7+
8+
import LoginOptions from "./login-providers.js";
9+
10+
export default {
11+
// https://vuejs.org/guide/components/registration#local-registration
12+
components: {
13+
LoginOptions,
14+
},
15+
props: {
16+
logout: {
17+
type: String,
18+
required: false,
19+
},
20+
},
21+
computed: {
22+
...mapState(useKumiteStore, ["nbAccountFetching", "account", "needsToLogin"]),
23+
...mapState(useKumiteStore, {
24+
user(store) {
25+
return store.account;
26+
},
27+
}),
28+
},
29+
setup(props) {
30+
const store = useKumiteStore();
31+
const router = useRouter();
32+
33+
store.loadUser();
34+
35+
const csrfToken = ref({});
36+
const fetchCsrfToken = async function () {
37+
try {
38+
const response = await fetch(`/api/login/v1/csrf`);
39+
if (!response.ok) {
40+
throw new Error("Rejected request for logout");
41+
}
42+
43+
const json = await response.json();
44+
const csrfHeader = json.header;
45+
console.log("csrf header", csrfHeader);
46+
47+
const freshCrsfToken = response.headers.get(csrfHeader);
48+
if (!freshCrsfToken) {
49+
throw new Error("Invalid csrfToken");
50+
}
51+
console.debug("csrf", freshCrsfToken);
52+
53+
csrfToken.value = { header: csrfHeader, token: freshCrsfToken };
54+
} catch (e) {
55+
console.error("Issue on Network: ", e);
56+
}
57+
};
58+
59+
const doLogout = function () {
60+
console.info("Logout");
61+
async function fetchFromUrl(url) {
62+
// https://www.baeldung.com/spring-security-csrf
63+
// If we relied on Cookie, `.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())` we could get the csrfToken with:
64+
// const csrfToken = document.cookie.replace(/(?:(?:^|.*;\s*)XSRF-TOKEN\s*\=\s*([^;]*).*$)|^.*$/, '$1');
65+
66+
// https://stackoverflow.com/questions/60265617/how-do-you-include-a-csrf-token-in-a-vue-js-application-with-a-spring-boot-backe
67+
const headers = { [csrfToken.value.header]: csrfToken.value.token };
68+
69+
try {
70+
const response = await fetch(url, {
71+
method: "POST",
72+
headers: headers,
73+
74+
// https://stackoverflow.com/questions/39735496/redirect-after-a-fetch-post-call
75+
// https://github.com/whatwg/fetch/issues/601#issuecomment-502667208
76+
redirect: "follow",
77+
});
78+
if (!response.ok) {
79+
throw new Error("Rejected request for logout");
80+
}
81+
82+
const json = await response.json();
83+
84+
// We we can not intercept 3XX to extract the Location header, we introduced an API providing the Location as body of a 2XX.
85+
const logoutHtmlRoute = json["Location"];
86+
87+
console.info("Redirect to logout route", logoutHtmlRoute);
88+
89+
router.push(logoutHtmlRoute);
90+
91+
// We force reloading the page to take in account the removed SESSION
92+
// There should be a cleaner way to do it, without full-reload
93+
router.go(0);
94+
} catch (e) {
95+
console.error("Issue on Network: ", e);
96+
}
97+
}
98+
99+
fetchCsrfToken().then(() => {
100+
fetchFromUrl(`/logout`);
101+
});
102+
};
103+
104+
return { doLogout };
105+
},
106+
template: /* HTML */ `
107+
<span v-if="!needsToLogin">
108+
<button class="btn btn-danger" @click="doLogout">Logout</button>
109+
</span>
110+
`,
111+
};

player/src/main/resources/application.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
spring:
2+
application.name: kumite-player
23
main:
34
banner-mode: "off"
4-
application.name: kumite-player
55
# https://stackoverflow.com/questions/26105061/spring-boot-without-the-web-server
66
main.web-application-type: NONE
77
profiles:

server/src/main/java/eu/solven/kumite/account/login/KumiteUsersRegistry.java server/src/main/java/eu/solven/kumite/account/KumiteUsersRegistry.java

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
1-
package eu.solven.kumite.account.login;
1+
package eu.solven.kumite.account;
22

33
import java.util.UUID;
44

5-
import eu.solven.kumite.account.KumiteUser;
6-
import eu.solven.kumite.account.KumiteUserRaw;
7-
import eu.solven.kumite.account.KumiteUserRawRaw;
85
import eu.solven.kumite.player.KumitePlayer;
96
import eu.solven.kumite.user.IKumiteUserRawRawRepository;
107
import eu.solven.kumite.user.IKumiteUserRepository;

server/src/main/java/eu/solven/kumite/app/InjectDefaultGamesConfig.java

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import eu.solven.kumite.game.opposition.tictactoe.TicTacToe;
2121
import eu.solven.kumite.game.optimization.lag.Lag;
2222
import eu.solven.kumite.game.optimization.tsp.TravellingSalesmanProblem;
23+
import eu.solven.kumite.tools.CloseableBean;
2324
import lombok.extern.slf4j.Slf4j;
2425

2526
@Configuration

server/src/main/java/eu/solven/kumite/app/KumiteContestServerApplication.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
55
import org.springframework.context.annotation.Import;
66

7-
import eu.solven.kumite.account.login.KumiteSecurity;
8-
import eu.solven.kumite.app.properties.GitPropertySourceConfig;
97
import eu.solven.kumite.app.webflux.KumiteWebFluxConfiguration;
8+
import eu.solven.kumite.security.KumiteSecurity;
9+
import eu.solven.kumite.tools.GitPropertySourceConfig;
1010

1111
@SpringBootApplication(scanBasePackages = "none")
1212
@Import({

server/src/main/java/eu/solven/kumite/app/KumiteServerComponentsConfiguration.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,21 @@
77
import org.springframework.context.annotation.Configuration;
88
import org.springframework.context.annotation.Import;
99

10-
import eu.solven.kumite.account.login.KumiteUsersRegistry;
10+
import eu.solven.kumite.account.KumiteUsersRegistry;
1111
import eu.solven.kumite.app.persistence.InMemoryKumiteConfiguration;
1212
import eu.solven.kumite.app.persistence.RedisKumiteConfiguration;
1313
import eu.solven.kumite.board.BoardHandler;
14+
import eu.solven.kumite.board.BoardLifecycleManager;
1415
import eu.solven.kumite.board.BoardsRegistry;
1516
import eu.solven.kumite.contest.ContestsRegistry;
1617
import eu.solven.kumite.game.GamesRegistry;
1718
import eu.solven.kumite.leaderboard.LeaderboardRegistry;
18-
import eu.solven.kumite.lifecycle.BoardLifecycleManager;
19-
import eu.solven.kumite.lifecycle.ContestLifecycleManager;
2019
import eu.solven.kumite.player.ContestPlayersFromBoard;
2120
import eu.solven.kumite.player.ContestPlayersRegistry;
2221
import eu.solven.kumite.player.PlayerMovesHandler;
2322
import eu.solven.kumite.player.PlayersSearchHandler;
2423
import eu.solven.kumite.redis.KumiteRedisConfiguration;
24+
import eu.solven.kumite.tools.KumiteRandomConfiguration;
2525
import eu.solven.kumite.webhook.WebhooksRegistry;
2626

2727
@Configuration
@@ -41,8 +41,6 @@
4141
BoardHandler.class,
4242
PlayerMovesHandler.class,
4343

44-
ContestLifecycleManager.class,
45-
4644
InjectDefaultGamesConfig.class,
4745

4846
ContestPlayersFromBoard.class,

0 commit comments

Comments
 (0)