Add a landing login page and a logout option.
BasicAuth without an explicit landing page or a logout option has sometimes been confusing to users. This commit adds a static landing page on / with a login link and a logout option in the admin that "logs out" BasicAuth session by posting invalid credentials to the server to obtain a 401.
This commit is contained in:
parent
9d2bc9c41d
commit
98ed4fb384
19 changed files with 73 additions and 21 deletions
|
@ -51,8 +51,8 @@ func initHTTPHandlers(e *echo.Echo, app *App) {
|
|||
|
||||
// Admin JS app views.
|
||||
// /admin/static/* file server is registered in initHTTPServer().
|
||||
g.GET("/", func(c echo.Context) error {
|
||||
return c.Redirect(http.StatusPermanentRedirect, path.Join(adminRoot, ""))
|
||||
e.GET("/", func(c echo.Context) error {
|
||||
return c.Render(http.StatusOK, "home", publicTpl{Title: "listmonk"})
|
||||
})
|
||||
g.GET(path.Join(adminRoot, ""), handleAdminPage)
|
||||
g.GET(path.Join(adminRoot, "/*"), handleAdminPage)
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
</div>
|
||||
</template>
|
||||
<template slot="end">
|
||||
<b-navbar-item tag="div"></b-navbar-item>
|
||||
<b-navbar-item tag="div">
|
||||
<a href="#" @click.prevent="doLogout">{{ $t('users.logout') }}</a>
|
||||
</b-navbar-item>
|
||||
</template>
|
||||
</b-navbar>
|
||||
|
||||
|
@ -134,6 +136,7 @@
|
|||
<script>
|
||||
import Vue from 'vue';
|
||||
import { mapState } from 'vuex';
|
||||
import { uris } from './constants';
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'App',
|
||||
|
@ -164,6 +167,21 @@ export default Vue.extend({
|
|||
toggleGroup(group, state) {
|
||||
this.activeGroup = state ? { [group]: true } : {};
|
||||
},
|
||||
|
||||
doLogout() {
|
||||
const http = new XMLHttpRequest();
|
||||
|
||||
const u = uris.root.substr(-1) === '/' ? uris.root : `${uris.root}/`;
|
||||
http.open('get', `${u}api/logout`, false, 'logout_non_user', 'logout_non_user');
|
||||
http.onload = () => {
|
||||
document.location.href = uris.root;
|
||||
};
|
||||
http.onerror = () => {
|
||||
document.location.href = uris.root;
|
||||
};
|
||||
http.send();
|
||||
},
|
||||
|
||||
reloadApp() {
|
||||
this.$api.reloadApp().then(() => {
|
||||
this.$utils.toast('Reloading app ...');
|
||||
|
|
|
@ -6,7 +6,7 @@ import store from '../store';
|
|||
import { models } from '../constants';
|
||||
|
||||
const http = axios.create({
|
||||
baseURL: process.env.VUE_APP_API_URL || '/',
|
||||
baseURL: process.env.VUE_APP_ROOT_URL || '/',
|
||||
withCredentials: false,
|
||||
responseType: 'json',
|
||||
|
||||
|
@ -276,3 +276,7 @@ export const getLogs = async () => http.get('/api/logs',
|
|||
|
||||
export const getLang = async (lang) => http.get(`/api/lang/${lang}`,
|
||||
{ loading: models.lang, preserveCase: true });
|
||||
|
||||
export const logout = async () => http.get('/api/logout', {
|
||||
auth: { username: 'wrong', password: 'wrong' },
|
||||
});
|
||||
|
|
|
@ -939,10 +939,6 @@ section.analytics {
|
|||
}
|
||||
}
|
||||
|
||||
.navbar-burger {
|
||||
display: none;
|
||||
}
|
||||
|
||||
td .tags {
|
||||
.tag:not(:last-child) {
|
||||
margin-right: 0;
|
||||
|
|
|
@ -13,6 +13,7 @@ export const models = Object.freeze({
|
|||
});
|
||||
|
||||
// Ad-hoc URIs that are used outside of vuex requests.
|
||||
const rootURL = process.env.VUE_APP_ROOT_URL || '/';
|
||||
const baseURL = process.env.BASE_URL.replace(/\/$/, '');
|
||||
|
||||
export const uris = Object.freeze({
|
||||
|
@ -20,6 +21,8 @@ export const uris = Object.freeze({
|
|||
previewTemplate: '/api/templates/:id/preview',
|
||||
previewRawTemplate: '/api/templates/preview',
|
||||
exportSubscribers: '/api/subscribers/export',
|
||||
base: `${baseURL}/static`,
|
||||
root: rootURL,
|
||||
static: `${baseURL}/static`,
|
||||
});
|
||||
|
||||
|
|
|
@ -482,5 +482,7 @@
|
|||
"templates.newTemplate": "Nová šablona",
|
||||
"templates.placeholderHelp": "Zástupný symbol {placeholder} by se měl v šabloně objevit právě jednou.",
|
||||
"templates.preview": "Náhled",
|
||||
"templates.rawHTML": "Kód HTML"
|
||||
"templates.rawHTML": "Kód HTML",
|
||||
"users.login": "Login",
|
||||
"users.logout": "Logout"
|
||||
}
|
||||
|
|
|
@ -482,5 +482,7 @@
|
|||
"templates.newTemplate": "Neue Vorlage",
|
||||
"templates.placeholderHelp": "Der Platzhalter \"{placeholder}\" darf nur einmal im Template vorkommen.",
|
||||
"templates.preview": "Vorschau",
|
||||
"templates.rawHTML": "HTML"
|
||||
"templates.rawHTML": "HTML",
|
||||
"users.login": "Login",
|
||||
"users.logout": "Logout"
|
||||
}
|
||||
|
|
|
@ -482,5 +482,7 @@
|
|||
"templates.newTemplate": "New template",
|
||||
"templates.placeholderHelp": "The placeholder {placeholder} should appear exactly once in the template.",
|
||||
"templates.preview": "Preview",
|
||||
"templates.rawHTML": "Raw HTML"
|
||||
"templates.rawHTML": "Raw HTML",
|
||||
"users.login": "Login",
|
||||
"users.logout": "Logout"
|
||||
}
|
||||
|
|
|
@ -482,5 +482,7 @@
|
|||
"templates.newTemplate": "Nueva plantilla",
|
||||
"templates.placeholderHelp": "El marcador {placeholder} debe aparecer exactamente una vez en la plantilla.",
|
||||
"templates.preview": "Vista pewliminar",
|
||||
"templates.rawHTML": "HTML crudo"
|
||||
"templates.rawHTML": "HTML crudo",
|
||||
"users.login": "Login",
|
||||
"users.logout": "Logout"
|
||||
}
|
||||
|
|
|
@ -482,5 +482,7 @@
|
|||
"templates.newTemplate": "Nouveau modèle",
|
||||
"templates.placeholderHelp": "L'espace réservé {placeholder} doit apparaître exactement une fois dans le modèle.",
|
||||
"templates.preview": "Aperçu",
|
||||
"templates.rawHTML": "HTML brut"
|
||||
"templates.rawHTML": "HTML brut",
|
||||
"users.login": "Login",
|
||||
"users.logout": "Logout"
|
||||
}
|
||||
|
|
|
@ -482,5 +482,7 @@
|
|||
"templates.newTemplate": "Nuovo modello",
|
||||
"templates.placeholderHelp": "Il segnaposto {placeholder} deve apparire esattamente una volta nel modello.",
|
||||
"templates.preview": "Anteprima",
|
||||
"templates.rawHTML": "HTML semplice"
|
||||
"templates.rawHTML": "HTML semplice",
|
||||
"users.login": "Login",
|
||||
"users.logout": "Logout"
|
||||
}
|
||||
|
|
|
@ -482,5 +482,7 @@
|
|||
"templates.newTemplate": "പുതിയ ടെംപ്ലേറ്റ്",
|
||||
"templates.placeholderHelp": "{placeholder} എന്ന പ്ലെയ്സ്ഹോൾഡർ ടെംപ്ലേറ്റിൽ ഒരിക്കലെങ്കിലും വരണം.",
|
||||
"templates.preview": "പ്രിവ്യൂ",
|
||||
"templates.rawHTML": "എച്. ടീ. എം. എൽ"
|
||||
"templates.rawHTML": "എച്. ടീ. എം. എൽ",
|
||||
"users.login": "Login",
|
||||
"users.logout": "Logout"
|
||||
}
|
||||
|
|
|
@ -482,5 +482,7 @@
|
|||
"templates.newTemplate": "Nowy szablon",
|
||||
"templates.placeholderHelp": "Symbol zastępczy {placeholder} powinien występować dokładnie raz w szablonie.",
|
||||
"templates.preview": "Podgląd",
|
||||
"templates.rawHTML": "Surowy HTML"
|
||||
"templates.rawHTML": "Surowy HTML",
|
||||
"users.login": "Login",
|
||||
"users.logout": "Logout"
|
||||
}
|
||||
|
|
|
@ -482,5 +482,7 @@
|
|||
"templates.newTemplate": "Novo modelo",
|
||||
"templates.placeholderHelp": "O palavra reservada {placeholder} deve aparecer exatamente uma vez no modelo.",
|
||||
"templates.preview": "Pré-visualizar",
|
||||
"templates.rawHTML": "Código HTML"
|
||||
"templates.rawHTML": "Código HTML",
|
||||
"users.login": "Login",
|
||||
"users.logout": "Logout"
|
||||
}
|
||||
|
|
|
@ -482,5 +482,7 @@
|
|||
"templates.newTemplate": "Novo template",
|
||||
"templates.placeholderHelp": "O placeholder {placeholder} deve aparecer exatamente uma vez no template.",
|
||||
"templates.preview": "Pré-visualização",
|
||||
"templates.rawHTML": "HTML Simples"
|
||||
"templates.rawHTML": "HTML Simples",
|
||||
"users.login": "Login",
|
||||
"users.logout": "Logout"
|
||||
}
|
||||
|
|
|
@ -482,5 +482,7 @@
|
|||
"templates.newTemplate": "Template nou",
|
||||
"templates.placeholderHelp": "Substituentul {placeholder} ar trebui să apară exact o dată în șablon.",
|
||||
"templates.preview": "Previzualizare",
|
||||
"templates.rawHTML": "HTML brut"
|
||||
"templates.rawHTML": "HTML brut",
|
||||
"users.login": "Login",
|
||||
"users.logout": "Logout"
|
||||
}
|
||||
|
|
|
@ -482,5 +482,7 @@
|
|||
"templates.newTemplate": "Новый шаблон",
|
||||
"templates.placeholderHelp": "Заполнитель {placeholder} должен присутствовать в шаблоне в одном экземпляре.",
|
||||
"templates.preview": "Предпросмотр",
|
||||
"templates.rawHTML": "Необработанный HTML"
|
||||
"templates.rawHTML": "Необработанный HTML",
|
||||
"users.login": "Login",
|
||||
"users.logout": "Logout"
|
||||
}
|
||||
|
|
|
@ -482,5 +482,7 @@
|
|||
"templates.newTemplate": "Yeni taslak",
|
||||
"templates.placeholderHelp": "Yer tutucu {placeholder} taslak içinde sadece bir kere olmalıdır.",
|
||||
"templates.preview": "Önizleme",
|
||||
"templates.rawHTML": "Ham HTML"
|
||||
"templates.rawHTML": "Ham HTML",
|
||||
"users.login": "Login",
|
||||
"users.logout": "Logout"
|
||||
}
|
||||
|
|
|
@ -46,6 +46,9 @@ input[type="text"], input[type="email"], select {
|
|||
border-color: #0055d4;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
.button {
|
||||
background: #0055d4;
|
||||
padding: 15px 30px;
|
||||
|
@ -57,9 +60,11 @@ input[type="text"], input[type="email"], select {
|
|||
display: inline-block;
|
||||
min-width: 150px;
|
||||
font-size: 1.1em;
|
||||
text-align: center;
|
||||
}
|
||||
.button:hover {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
}
|
||||
.button.button-outline {
|
||||
background: #fff;
|
||||
|
|
Loading…
Reference in a new issue