Skip to content

Commit

Permalink
Polish Logout
Browse files Browse the repository at this point in the history
  • Loading branch information
blacelle committed Sep 22, 2024
1 parent 7ad7313 commit b484ce4
Show file tree
Hide file tree
Showing 54 changed files with 267 additions and 281 deletions.
2 changes: 1 addition & 1 deletion js/src/main/resources/static/ui/js/kumite-account-ref.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default {
},
template: /* HTML */ `
<RouterLink :to="{path:'/html/me'}">
<i class="bi bi-person"></i>accountId: {{ accountId }} <span v-if="account.accountId === accountId">You</span>
<i class="bi bi-person"></i>accountId: {{ accountId }}<span v-if="account.accountId === accountId"> (You)</span>
</RouterLink>
`,
};
7 changes: 4 additions & 3 deletions js/src/main/resources/static/ui/js/kumite-contest-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ export default {
method: {},
setup(props) {
const store = useKumiteStore();

const contestName = ref("A nice name for a contest");


const contestName = ref('');
const createdContest = ref({});

const submitContestForm = function () {
Expand Down Expand Up @@ -94,7 +95,7 @@ export default {
<form>
<div class="mb-3">
<label for="contestName" class="form-label">Email address</label>
<label for="contestName" class="form-label">Contest name</label>
<input type="text" class="form-control" id="contestName" v-model="contestName" aria-describedby="emailHelp" />
<div id="emailHelp" class="form-text">Pick a name so your friends can find your contest.</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions js/src/main/resources/static/ui/js/kumite-game-header.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ export default {
<span v-if="withDescription">
<h1>
<RouterLink :to="{path:'/html/games/' + game.gameId}"><i class="bi bi-puzzle"></i> {{game.title}}</RouterLink>
<RouterLink :to="{path:'/html/games'}"><i class="bi bi-arrow-90deg-left"></i></RouterLink>
<!--RouterLink :to="{path:'/html/games'}"><i class="bi bi-arrow-90deg-left"></i></RouterLink-->
</h1>
Game-Description: {{game.shortDescription}}
</span>
<span v-else>
<h5>
<RouterLink :to="{path:'/html/games/' + game.gameId}"><i class="bi bi-puzzle"></i> {{game.title}}</RouterLink>
<RouterLink :to="{path:'/html/games'}"><i class="bi bi-arrow-90deg-left"></i></RouterLink>
<!--RouterLink :to="{path:'/html/games'}"><i class="bi bi-arrow-90deg-left"></i></RouterLink-->
</h5>
</span>
</span>
Expand Down
29 changes: 16 additions & 13 deletions js/src/main/resources/static/ui/js/kumite-navbar.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { mapState } from "pinia";
import { useKumiteStore } from "./store.js";

import Logout from "./login-logout.js";

export default {
components: {
Logout,
},
computed: {
...mapState(useKumiteStore, ["needsToLogin", "account", "tokens", "nbAccountFetching", "playingPlayerId"]),
...mapState(useKumiteStore, ["needsToLogin", "isLoggedIn", "account", "tokens", "nbAccountFetching", "playingPlayerId"]),
},
setup() {
const store = useKumiteStore();
Expand Down Expand Up @@ -40,31 +45,29 @@ export default {
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<RouterLink class="nav-link active" aria-current="page" to="/">Home</RouterLink>
</li>
<li class="nav-item">
<RouterLink class="nav-link" to="/html/games">Games</RouterLink>
<RouterLink class="nav-link" to="/html/games"><i class="bi bi-puzzle"/>Games</RouterLink>
</li>
<li class="nav-item">
<RouterLink class="nav-link" to="/html/contests">Contests</RouterLink>
<RouterLink class="nav-link" to="/html/contests"><i class="bi bi-trophy"/>Contests</RouterLink>
</li>
<li class="nav-item">
<RouterLink class="nav-link" to="/html/about">About</RouterLink>
<RouterLink class="nav-link" to="/html/about"><i class="bi bi-info-lg"/>About</RouterLink>
</li>
<li class="nav-item" v-if="account.raw">
<RouterLink class="nav-link" to="/html/me">Account Settings</RouterLink>
<li class="nav-item" v-if="isLoggedIn">
<RouterLink class="nav-link" to="/html/me"><i class="bi bi-person"/>Account Settings</RouterLink>
</li>
</ul>
<span v-if="account.raw">
Current user: {{account.raw.name}}<img
<span v-if="isLoggedIn">
{{account.raw.name}}<img
:src="account.raw.picture"
class="img-thumbnail"
alt="You're looking nice"
width="128"
height="128"
width="64"
height="64"
v-if="account.raw.picture"
/>
<Logout />
</span>
</div>
</div>
Expand Down
79 changes: 4 additions & 75 deletions js/src/main/resources/static/ui/js/login-checker.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import { useKumiteStore } from "./store.js";
import { useRouter } from "vue-router";

import LoginOptions from "./login-providers.js";
import Logout from "./login-logout.js";

export default {
// https://vuejs.org/guide/components/registration#local-registration
components: {
LoginOptions,
Logout,
},
props: {
logout: {
Expand All @@ -28,80 +29,10 @@ export default {
},
setup(props) {
const store = useKumiteStore();
const router = useRouter();

store.loadUser();

const csrfToken = ref({});
const fetchCsrfToken = async function () {
try {
const response = await fetch(`/api/login/v1/csrf`);
if (!response.ok) {
throw new Error("Rejected request for logout");
}

const json = await response.json();
const csrfHeader = json.header;
console.log("csrf header", csrfHeader);

const freshCrsfToken = response.headers.get(csrfHeader);
if (!freshCrsfToken) {
throw new Error("Invalid csrfToken");
}
console.debug("csrf", freshCrsfToken);

csrfToken.value = { header: csrfHeader, token: freshCrsfToken };
} catch (e) {
console.error("Issue on Network: ", e);
}
};

const doLogout = function () {
console.info("Logout");
async function fetchFromUrl(url) {
// https://www.baeldung.com/spring-security-csrf
// If we relied on Cookie, `.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())` we could get the csrfToken with:
// const csrfToken = document.cookie.replace(/(?:(?:^|.*;\s*)XSRF-TOKEN\s*\=\s*([^;]*).*$)|^.*$/, '$1');

// https://stackoverflow.com/questions/60265617/how-do-you-include-a-csrf-token-in-a-vue-js-application-with-a-spring-boot-backe
const headers = { [csrfToken.value.header]: csrfToken.value.token };

try {
const response = await fetch(url, {
method: "POST",
headers: headers,

// https://stackoverflow.com/questions/39735496/redirect-after-a-fetch-post-call
// https://github.com/whatwg/fetch/issues/601#issuecomment-502667208
redirect: "follow",
});
if (!response.ok) {
throw new Error("Rejected request for logout");
}

const json = await response.json();

// We we can not intercept 3XX to extract the Location header, we introduced an API providing the Location as body of a 2XX.
const logoutHtmlRoute = json["Location"];

console.info("Redirect to logout route", logoutHtmlRoute);

router.push(logoutHtmlRoute);

// We force reloading the page to take in account the removed SESSION
// There should be a cleaner way to do it, without full-reload
router.go(0);
} catch (e) {
console.error("Issue on Network: ", e);
}
}

fetchCsrfToken().then(() => {
fetchFromUrl(`/logout`);
});
};

return { doLogout };
return { };
},
template: /* HTML */ `
<div v-if="needsToLogin">
Expand All @@ -111,9 +42,7 @@ export default {
</div>
</div>
<div v-else>
Welcome {{user.raw.name}}.
<button class="btn btn-danger" @click="doLogout">Logout</button>
Welcome {{user.raw.name}}. <Logout />
</div>
`,
};
111 changes: 111 additions & 0 deletions js/src/main/resources/static/ui/js/login-logout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { ref, watch } from "vue";

import { mapState } from "pinia";
import { useKumiteStore } from "./store.js";

import { useRouter } from "vue-router";

import LoginOptions from "./login-providers.js";

export default {
// https://vuejs.org/guide/components/registration#local-registration
components: {
LoginOptions,
},
props: {
logout: {
type: String,
required: false,
},
},
computed: {
...mapState(useKumiteStore, ["nbAccountFetching", "account", "needsToLogin"]),
...mapState(useKumiteStore, {
user(store) {
return store.account;
},
}),
},
setup(props) {
const store = useKumiteStore();
const router = useRouter();

store.loadUser();

const csrfToken = ref({});
const fetchCsrfToken = async function () {
try {
const response = await fetch(`/api/login/v1/csrf`);
if (!response.ok) {
throw new Error("Rejected request for logout");
}

const json = await response.json();
const csrfHeader = json.header;
console.log("csrf header", csrfHeader);

const freshCrsfToken = response.headers.get(csrfHeader);
if (!freshCrsfToken) {
throw new Error("Invalid csrfToken");
}
console.debug("csrf", freshCrsfToken);

csrfToken.value = { header: csrfHeader, token: freshCrsfToken };
} catch (e) {
console.error("Issue on Network: ", e);
}
};

const doLogout = function () {
console.info("Logout");
async function fetchFromUrl(url) {
// https://www.baeldung.com/spring-security-csrf
// If we relied on Cookie, `.csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())` we could get the csrfToken with:
// const csrfToken = document.cookie.replace(/(?:(?:^|.*;\s*)XSRF-TOKEN\s*\=\s*([^;]*).*$)|^.*$/, '$1');

// https://stackoverflow.com/questions/60265617/how-do-you-include-a-csrf-token-in-a-vue-js-application-with-a-spring-boot-backe
const headers = { [csrfToken.value.header]: csrfToken.value.token };

try {
const response = await fetch(url, {
method: "POST",
headers: headers,

// https://stackoverflow.com/questions/39735496/redirect-after-a-fetch-post-call
// https://github.com/whatwg/fetch/issues/601#issuecomment-502667208
redirect: "follow",
});
if (!response.ok) {
throw new Error("Rejected request for logout");
}

const json = await response.json();

// We we can not intercept 3XX to extract the Location header, we introduced an API providing the Location as body of a 2XX.
const logoutHtmlRoute = json["Location"];

console.info("Redirect to logout route", logoutHtmlRoute);

router.push(logoutHtmlRoute);

// We force reloading the page to take in account the removed SESSION
// There should be a cleaner way to do it, without full-reload
router.go(0);
} catch (e) {
console.error("Issue on Network: ", e);
}
}

fetchCsrfToken().then(() => {
fetchFromUrl(`/logout`);
});
};

return { doLogout };
},
template: /* HTML */ `
<span v-if="!needsToLogin">
<button class="btn btn-danger" @click="doLogout">Logout</button>
</span>
`,
};
2 changes: 1 addition & 1 deletion player/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
spring:
application.name: kumite-player
main:
banner-mode: "off"
application.name: kumite-player
# https://stackoverflow.com/questions/26105061/spring-boot-without-the-web-server
main.web-application-type: NONE
profiles:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package eu.solven.kumite.account.login;
package eu.solven.kumite.account;

import java.util.UUID;

import eu.solven.kumite.account.KumiteUser;
import eu.solven.kumite.account.KumiteUserRaw;
import eu.solven.kumite.account.KumiteUserRawRaw;
import eu.solven.kumite.player.KumitePlayer;
import eu.solven.kumite.user.IKumiteUserRawRawRepository;
import eu.solven.kumite.user.IKumiteUserRepository;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import eu.solven.kumite.game.opposition.tictactoe.TicTacToe;
import eu.solven.kumite.game.optimization.lag.Lag;
import eu.solven.kumite.game.optimization.tsp.TravellingSalesmanProblem;
import eu.solven.kumite.tools.CloseableBean;
import lombok.extern.slf4j.Slf4j;

@Configuration
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;

import eu.solven.kumite.account.login.KumiteSecurity;
import eu.solven.kumite.app.properties.GitPropertySourceConfig;
import eu.solven.kumite.app.webflux.KumiteWebFluxConfiguration;
import eu.solven.kumite.security.KumiteSecurity;
import eu.solven.kumite.tools.GitPropertySourceConfig;

@SpringBootApplication(scanBasePackages = "none")
@Import({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import eu.solven.kumite.account.login.KumiteUsersRegistry;
import eu.solven.kumite.account.KumiteUsersRegistry;
import eu.solven.kumite.app.persistence.InMemoryKumiteConfiguration;
import eu.solven.kumite.app.persistence.RedisKumiteConfiguration;
import eu.solven.kumite.board.BoardHandler;
import eu.solven.kumite.board.BoardLifecycleManager;
import eu.solven.kumite.board.BoardsRegistry;
import eu.solven.kumite.contest.ContestsRegistry;
import eu.solven.kumite.game.GamesRegistry;
import eu.solven.kumite.leaderboard.LeaderboardRegistry;
import eu.solven.kumite.lifecycle.BoardLifecycleManager;
import eu.solven.kumite.lifecycle.ContestLifecycleManager;
import eu.solven.kumite.player.ContestPlayersFromBoard;
import eu.solven.kumite.player.ContestPlayersRegistry;
import eu.solven.kumite.player.PlayerMovesHandler;
import eu.solven.kumite.player.PlayersSearchHandler;
import eu.solven.kumite.redis.KumiteRedisConfiguration;
import eu.solven.kumite.tools.KumiteRandomConfiguration;
import eu.solven.kumite.webhook.WebhooksRegistry;

@Configuration
Expand All @@ -41,8 +41,6 @@
BoardHandler.class,
PlayerMovesHandler.class,

ContestLifecycleManager.class,

InjectDefaultGamesConfig.class,

ContestPlayersFromBoard.class,
Expand Down
Loading

0 comments on commit b484ce4

Please sign in to comment.