feat(activity logs and admin middleware): add admin middleware to check for admin privilege

This commit is contained in:
Sarab Singh
2020-12-19 20:55:48 +01:00
committed by MrTimscampi
parent f432d6687d
commit 781d9f20d6
3 changed files with 224 additions and 41 deletions
+95
View File
@@ -196,4 +196,99 @@
"youMayAlsoLike": "You may also like",
"unableGetServerConfiguration": "Unable to get server configuration",
"unableGetPublicUsers": "Unable to get users"
"activityLogs": "Activity Logs",
"actors": "Actors",
"albums": "Albums",
"alphabetically": "Alphabetically",
"artist": "Artist",
"artists": "Artists",
"badRequest": "Bad request. Try again",
"biography": "Biography",
"browserNotSupported": "Your browser is not supported for playing this file.",
"byArtist": "By",
"changeServer": "Change server",
"changeUser": "Change user",
"collections": "Collections",
"connect": "Connect",
"continueListening": "Continue listening",
"continueWatching": "Continue watching",
"darkModeToggle": "Toggle dark mode",
"disc": "Disc {discNumber}",
"dislikes": "Dislikes",
"endDate": "End date",
"endsAt": "Ends at {time}",
"episodeNumber": "Episode {episodeNumber}",
"failedToRefreshItems": "Failed to refresh items",
"favorite": "Favorite",
"features": "Features",
"filter": "Filter",
"filtersNotFound": "Unable to load filters",
"genres": "Genres",
"home": "Home",
"incorrectUsernameOrPassword": "Incorrect username or password",
"itemNotFound": "Item not found",
"latestLibrary": "Latest {libraryName}",
"libraries": "Libraries",
"libraryEmpty": "This library is empty",
"libraryNotFound": "Library not found",
"liked": "Liked",
"likes": "Likes",
"login": "Login",
"loginAs": "Login as {name}",
"logout": "Logout",
"manualLogin": "Manual login",
"more": "More",
"moreLikeArtist": "More like {artist}",
"moreLikeThis": "More like this",
"movies": "Movies",
"name": "Name",
"networks": "Networks",
"nextUp": "Next up",
"noNetworkConnection": "No network connection",
"numberTracks": "{number} tracks",
"noResultsFound": "There is nothing here",
"parentalRatings": "Parental Ratings",
"password": "Password",
"play": "Play",
"played": "Played",
"present": "Present",
"rating": "Rating",
"releaseDate": "Release date",
"resumable": "Resumable",
"selectServer": "Select server",
"selectUser": "Select a user",
"series": "Series",
"serverAddress": "Server address",
"serverAddressMustBeUrl": "Server address must be a valid address",
"serverAddressRequired": "Server address is required",
"serverNotFound": "Server not found",
"serverVersionTooLow": "Server version needs to be 10.7.0 or higher",
"settings": "Settings",
"shows": "Shows",
"shuffleAll": "Shuffle all",
"signIn": "Sign in",
"sortByType": "By {type}",
"specialFeatures": "Special Features",
"status": "Status",
"studios": "Studios",
"subtitles": "Subtitles",
"themeSong": "Theme Song",
"themeVideo": "Theme Video",
"trailer": "Trailer",
"unableGetRelated": "Unable to get related items",
"unexpectedError": "Unexpected error",
"unhandledException": "Unhandled exception",
"unliked": "Unliked",
"unplayed": "Unplayed",
"upNext": "Up next",
"username": "Username",
"usernameRequired": "Username is required",
"validation": {
"mustBeUrl": "This field must be a valid URL",
"required": "This field is required"
},
"videoTypes": "Video Types",
"viewDetails": "View details",
"years": "Years",
"youMayAlsoLike": "You may also like"
}
+14
View File
@@ -0,0 +1,14 @@
import { Context } from '@nuxt/types';
/**
* Middleware providing a redirect to the home page in case the
* User is not Admin and tries to access the admin page.
*
* @param {Context} context Nuxt application context
* @returns {void}
*/
export default function (context: Context): void {
if (!context.$auth.user.Policy.IsAdministrator) {
return context.redirect('/');
}
}
+115 -41
View File
@@ -2,16 +2,37 @@
<v-container>
<v-row>
<v-col cols="12" :offset-md="1" md="5" class="pt-0 pb-4">
<!-- Administrator settings -->
<v-list
v-if="$auth.user.Policy.IsAdministrator"
two-line
class="mb-4"
disabled
>
<v-list two-line class="mb-2">
<v-list-item-group>
<v-list-item
v-for="file in logFiles"
:key="file.Name"
:href="getLogFileLink(file.Name)"
target="_blank"
>
<v-list-item-avatar>
<v-icon>mdi-file</v-icon>
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title v-text="file.Name" />
<v-list-item-subtitle
v-text="getFormattedLogDate(file.DateModified)"
/>
</v-list-item-content>
<v-list-item-action>
<v-icon>mdi-chevron-right</v-icon>
</v-list-item-action>
</v-list-item>
</v-list-item-group>
</v-list>
</v-col>
<v-col cols="12" md="5" class="pt-0 pb-4">
<v-list two-line class="mb-2" disabled>
<v-list-item-group>
<v-list-item v-for="activity in activityList" :key="activity.Id">
<v-list-item-avatar>
<v-list-item-avatar
:color="getColorFromSeverity(activity.Severity)"
>
<v-icon>mdi-shield-account-outline</v-icon>
</v-list-item-avatar>
<v-list-item-content>
@@ -19,27 +40,10 @@
<v-list-item-subtitle v-text="activity.ShortOverview" />
</v-list-item-content>
<v-list-item-action>
<v-list-item-subtitle v-text="activity.Date" />
</v-list-item-action>
</v-list-item>
</v-list-item-group>
</v-list>
<!-- Mobile links -->
<v-list v-if="$vuetify.breakpoint.mobile">
<v-list-item-group>
<v-list-item
v-for="linkItem in linkItems"
:key="linkItem.name"
:href="linkItem.link"
>
<v-list-item-avatar>
<v-icon v-text="linkItem.icon" />
</v-list-item-avatar>
<v-list-item-content>
<v-list-item-title v-text="linkItem.name" />
</v-list-item-content>
<v-list-item-action>
<v-icon>mdi-chevron-right</v-icon>
<v-list-item-subtitle
class="text-capitalize-first-letter"
v-text="getFormattedActivityDate(activity.Date)"
/>
</v-list-item-action>
</v-list-item>
</v-list-item-group>
@@ -50,32 +54,102 @@
</template>
<script lang="ts">
import { isEmpty } from 'lodash';
import Vue from 'vue';
import { mapActions } from 'vuex';
import { SystemInfo } from '~/api';
import colors from 'vuetify/lib/util/colors';
import { ActivityLogEntry, LogFile, LogLevel } from '~/api';
import htmlHelper from '~/mixins/htmlHelper';
export default Vue.extend({
mixins: [htmlHelper],
middleware: 'adminMiddleware',
data() {
return {
activityList: {} as SystemInfo
activityList: [] as ActivityLogEntry[],
logFiles: [] as LogFile[]
};
},
head() {
return {
title: this.$store.state.page.title
};
},
async beforeMount() {
this.setAppBarOpacity({ opaqueAppBar: true });
this.setPageTitle({ title: this.$t('settings') });
if (this.$auth.user.Policy.IsAdministrator) {
this.activityList = (await this.$api.system.getActivityLogs()).data.Items;
}
this.setPageTitle({ title: this.$t('activityLogs') });
const minDate = new Date();
minDate.setTime(minDate.getTime() - 7 * 24 * 60 * 60 * 1000);
this.activityList =
(await this.$api.activityLog.getLogEntries({ minDate })).data.Items || [];
this.logFiles = (await this.$api.system.getServerLogs()).data;
},
methods: {
...mapActions('page', ['setPageTitle', 'setAppBarOpacity']),
isEmpty(object: any): boolean {
return isEmpty(object);
...mapActions('page', ['setPageTitle']),
getColorFromSeverity(severity: LogLevel): string {
switch (severity) {
case LogLevel.Trace:
return (
this.$vuetify.theme.currentTheme.success?.toString() ||
colors.green.base
);
case LogLevel.Debug:
return (
this.$vuetify.theme.currentTheme.accent?.toString() ||
colors.blue.accent1
);
case LogLevel.Information:
return (
this.$vuetify.theme.currentTheme.info?.toString() ||
colors.blue.base
);
case LogLevel.Warning:
return (
this.$vuetify.theme.currentTheme.warning?.toString() ||
colors.amber.base
);
case LogLevel.Error:
return (
this.$vuetify.theme.currentTheme.error?.toString() ||
colors.red.accent2
);
case LogLevel.Critical:
return (
this.$vuetify.theme.currentTheme.secondary?.toString() ||
colors.grey.darken3
);
default:
return (
this.$vuetify.theme.currentTheme.primary?.toString() ||
colors.blue.darken2
);
}
},
getFormattedActivityDate(date: Date): string {
const today = this.$dateFns.endOfToday();
const day = this.$dateFns.formatRelative(
this.$dateFns.parseJSON(date),
today
);
return day;
},
getFormattedLogDate(date: Date): string {
const day = this.$dateFns.format(date, 'Ppp');
return day;
},
getLogFileLink(name: string): string {
return (
this.$axios.defaults.baseURL +
'/System/Logs/Log?name=' +
name +
'&api_key=' +
this.$store.state.user.accessToken
);
}
}
});
</script>
<style>
.text-capitalize-first-letter::first-letter {
text-transform: uppercase;
}
</style>