mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-07-09 03:04:54 -04:00
Merge pull request #3100 from Kuchenpirat/feat-frontend-access-controll
feat: frontend access controll
This commit is contained in:
commit
a7775ea7ef
@ -1,8 +1,8 @@
|
|||||||
interface AuthRedirectParams {
|
interface AdminRedirectParams {
|
||||||
$auth: any
|
$auth: any
|
||||||
redirect: (path: string) => void
|
redirect: (path: string) => void
|
||||||
}
|
}
|
||||||
export default function ({ $auth, redirect }: AuthRedirectParams) {
|
export default function ({ $auth, redirect }: AdminRedirectParams) {
|
||||||
// If the user is not an admin redirect to the home page
|
// If the user is not an admin redirect to the home page
|
||||||
if (!$auth.user.admin) {
|
if (!$auth.user.admin) {
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
|
11
frontend/middleware/advanced-only.ts
Normal file
11
frontend/middleware/advanced-only.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
interface AdvancedOnlyRedirectParams {
|
||||||
|
$auth: any
|
||||||
|
redirect: (path: string) => void
|
||||||
|
}
|
||||||
|
export default function ({ $auth, redirect }: AdvancedOnlyRedirectParams) {
|
||||||
|
// If the user is not allowed to access advanced features redirect to the home page
|
||||||
|
if (!$auth.user.advanced) {
|
||||||
|
console.warn("User is not allowed to access advanced features");
|
||||||
|
return redirect("/")
|
||||||
|
}
|
||||||
|
}
|
12
frontend/middleware/can-manage-only.ts
Normal file
12
frontend/middleware/can-manage-only.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
interface CanManageRedirectParams {
|
||||||
|
$auth: any
|
||||||
|
redirect: (path: string) => void
|
||||||
|
}
|
||||||
|
export default function ({ $auth, redirect }: CanManageRedirectParams) {
|
||||||
|
// If the user is not allowed to manage group settings redirect to the home page
|
||||||
|
console.log($auth.user)
|
||||||
|
if (!$auth.user.canManage) {
|
||||||
|
console.warn("User is not allowed to manage group settings");
|
||||||
|
return redirect("/")
|
||||||
|
}
|
||||||
|
}
|
11
frontend/middleware/can-organize-only.ts
Normal file
11
frontend/middleware/can-organize-only.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
interface CanOrganizeRedirectParams {
|
||||||
|
$auth: any
|
||||||
|
redirect: (path: string) => void
|
||||||
|
}
|
||||||
|
export default function ({ $auth, redirect }: CanOrganizeRedirectParams) {
|
||||||
|
// If the user is not allowed to organize redirect to the home page
|
||||||
|
if (!$auth.user.canOrganize) {
|
||||||
|
console.warn("User is not allowed to organize data");
|
||||||
|
return redirect("/")
|
||||||
|
}
|
||||||
|
}
|
12
frontend/middleware/group-only.ts
Normal file
12
frontend/middleware/group-only.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
interface GroupOnlyRedirectParams {
|
||||||
|
$auth: any
|
||||||
|
route: any
|
||||||
|
redirect: (path: string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ({ $auth, route, redirect }: GroupOnlyRedirectParams) {
|
||||||
|
// this can only be used for routes that have a groupSlug parameter (e.g. /g/:groupSlug/...)
|
||||||
|
if (route.params.groupSlug !== $auth.user.groupSlug) {
|
||||||
|
redirect("/")
|
||||||
|
}
|
||||||
|
}
|
@ -98,31 +98,23 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, reactive, ref, useRouter } from "@nuxtjs/composition-api";
|
|
||||||
|
import { defineComponent, reactive, ref } from "@nuxtjs/composition-api";
|
||||||
import draggable from "vuedraggable";
|
import draggable from "vuedraggable";
|
||||||
import { useCookbooks } from "@/composables/use-group-cookbooks";
|
import { useCookbooks } from "@/composables/use-group-cookbooks";
|
||||||
import { useLoggedInState } from "~/composables/use-logged-in-state";
|
|
||||||
import CookbookEditor from "~/components/Domain/Cookbook/CookbookEditor.vue";
|
import CookbookEditor from "~/components/Domain/Cookbook/CookbookEditor.vue";
|
||||||
import { ReadCookBook } from "~/lib/api/types/cookbook";
|
import { ReadCookBook } from "~/lib/api/types/cookbook";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { CookbookEditor, draggable },
|
components: { CookbookEditor, draggable },
|
||||||
|
middleware: ["auth", "group-only"],
|
||||||
setup() {
|
setup() {
|
||||||
const { isOwnGroup, loggedIn } = useLoggedInState();
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
if (!(loggedIn.value && isOwnGroup.value)) {
|
|
||||||
router.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
const dialogStates = reactive({
|
const dialogStates = reactive({
|
||||||
create: false,
|
create: false,
|
||||||
delete: false,
|
delete: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { cookbooks, actions } = useCookbooks();
|
const { cookbooks, actions } = useCookbooks();
|
||||||
|
|
||||||
|
|
||||||
// create
|
// create
|
||||||
const createTarget = ref<ReadCookBook | null>(null);
|
const createTarget = ref<ReadCookBook | null>(null);
|
||||||
async function createCookbook() {
|
async function createCookbook() {
|
||||||
@ -146,7 +138,6 @@ export default defineComponent({
|
|||||||
dialogStates.delete = false;
|
dialogStates.delete = false;
|
||||||
deleteTarget.value = null;
|
deleteTarget.value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cookbooks,
|
cookbooks,
|
||||||
actions,
|
actions,
|
||||||
|
@ -133,6 +133,7 @@ export default defineComponent({
|
|||||||
RecipeIngredientEditor,
|
RecipeIngredientEditor,
|
||||||
draggable
|
draggable
|
||||||
},
|
},
|
||||||
|
middleware: ["auth", "group-only"],
|
||||||
setup() {
|
setup() {
|
||||||
const { $auth } = useContext();
|
const { $auth } = useContext();
|
||||||
const panels = ref<number[]>([]);
|
const panels = ref<number[]>([]);
|
||||||
|
@ -33,6 +33,7 @@ import AdvancedOnly from "~/components/global/AdvancedOnly.vue";
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { AdvancedOnly },
|
components: { AdvancedOnly },
|
||||||
|
middleware: ["auth", "group-only"],
|
||||||
setup() {
|
setup() {
|
||||||
const { $auth, $globals, i18n } = useContext();
|
const { $auth, $globals, i18n } = useContext();
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ export default defineComponent({
|
|||||||
components: {
|
components: {
|
||||||
RecipeOrganizerPage,
|
RecipeOrganizerPage,
|
||||||
},
|
},
|
||||||
|
middleware: ["auth", "group-only"],
|
||||||
setup() {
|
setup() {
|
||||||
const { items, actions } = useCategoryStore();
|
const { items, actions } = useCategoryStore();
|
||||||
|
|
||||||
|
@ -22,6 +22,7 @@ export default defineComponent({
|
|||||||
components: {
|
components: {
|
||||||
RecipeOrganizerPage,
|
RecipeOrganizerPage,
|
||||||
},
|
},
|
||||||
|
middleware: ["auth", "group-only"],
|
||||||
setup() {
|
setup() {
|
||||||
const { items, actions } = useTagStore();
|
const { items, actions } = useTagStore();
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ import RecipeTimeline from "~/components/Domain/Recipe/RecipeTimeline.vue";
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { RecipeTimeline },
|
components: { RecipeTimeline },
|
||||||
|
middleware: ["auth", "group-only"],
|
||||||
setup() {
|
setup() {
|
||||||
const api = useUserApi();
|
const api = useUserApi();
|
||||||
const ready = ref<boolean>(false);
|
const ready = ref<boolean>(false);
|
||||||
|
@ -22,6 +22,7 @@ export default defineComponent({
|
|||||||
components: {
|
components: {
|
||||||
RecipeOrganizerPage,
|
RecipeOrganizerPage,
|
||||||
},
|
},
|
||||||
|
middleware: ["auth", "group-only"],
|
||||||
setup() {
|
setup() {
|
||||||
const toolStore = useToolStore();
|
const toolStore = useToolStore();
|
||||||
const dialog = ref(false);
|
const dialog = ref(false);
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
import { computed, defineComponent, useContext, useRoute } from "@nuxtjs/composition-api";
|
import { computed, defineComponent, useContext, useRoute } from "@nuxtjs/composition-api";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
middleware: ["auth", "can-organize-only"],
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -227,7 +227,6 @@ import { useFoodStore, useLabelStore } from "~/composables/store";
|
|||||||
import { VForm } from "~/types/vuetify";
|
import { VForm } from "~/types/vuetify";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
|
||||||
components: { MultiPurposeLabel, RecipeDataAliasManagerDialog },
|
components: { MultiPurposeLabel, RecipeDataAliasManagerDialog },
|
||||||
setup() {
|
setup() {
|
||||||
const userApi = useUserApi();
|
const userApi = useUserApi();
|
||||||
|
@ -65,6 +65,7 @@ import { useGroupSelf } from "~/composables/use-groups";
|
|||||||
import { ReadGroupPreferences } from "~/lib/api/types/group";
|
import { ReadGroupPreferences } from "~/lib/api/types/group";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
middleware: ["auth", "can-manage-only"],
|
||||||
setup() {
|
setup() {
|
||||||
const { group, actions: groupActions } = useGroupSelf();
|
const { group, actions: groupActions } = useGroupSelf();
|
||||||
|
|
||||||
|
@ -46,6 +46,7 @@ import { isSameDay, addDays, parseISO } from "date-fns";
|
|||||||
import { useMealplans } from "~/composables/use-group-mealplan";
|
import { useMealplans } from "~/composables/use-group-mealplan";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
middleware: ["auth"],
|
||||||
setup() {
|
setup() {
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -98,6 +98,7 @@ export default defineComponent({
|
|||||||
GroupMealPlanRuleForm,
|
GroupMealPlanRuleForm,
|
||||||
RecipeChips,
|
RecipeChips,
|
||||||
},
|
},
|
||||||
|
middleware: ["auth"],
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
@ -78,6 +78,7 @@ export default defineComponent({
|
|||||||
components: {
|
components: {
|
||||||
UserAvatar,
|
UserAvatar,
|
||||||
},
|
},
|
||||||
|
middleware: ["auth"],
|
||||||
setup() {
|
setup() {
|
||||||
const api = useUserApi();
|
const api = useUserApi();
|
||||||
|
|
||||||
|
@ -85,6 +85,7 @@ const MIGRATIONS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
middleware: ["auth", "advanced-only"],
|
||||||
setup() {
|
setup() {
|
||||||
const { $globals, i18n } = useContext();
|
const { $globals, i18n } = useContext();
|
||||||
|
|
||||||
|
@ -124,6 +124,7 @@ interface OptionSection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
middleware: ["auth", "advanced-only"],
|
||||||
setup() {
|
setup() {
|
||||||
const api = useUserApi();
|
const api = useUserApi();
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ import { useUserApi } from "~/composables/api";
|
|||||||
import { ReportOut } from "~/lib/api/types/reports";
|
import { ReportOut } from "~/lib/api/types/reports";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
middleware: "auth",
|
||||||
setup() {
|
setup() {
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const id = route.value.params.id;
|
const id = route.value.params.id;
|
||||||
|
@ -50,6 +50,7 @@ import GroupWebhookEditor from "~/components/Domain/Group/GroupWebhookEditor.vue
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { GroupWebhookEditor },
|
components: { GroupWebhookEditor },
|
||||||
|
middleware: ["auth", "advanced-only"],
|
||||||
setup() {
|
setup() {
|
||||||
const { actions, webhooks } = useGroupWebhooks();
|
const { actions, webhooks } = useGroupWebhooks();
|
||||||
|
|
||||||
|
@ -235,6 +235,7 @@ export default defineComponent({
|
|||||||
RecipeList,
|
RecipeList,
|
||||||
ShoppingListItemEditor,
|
ShoppingListItemEditor,
|
||||||
},
|
},
|
||||||
|
middleware: "auth",
|
||||||
setup() {
|
setup() {
|
||||||
const { $auth, i18n } = useContext();
|
const { $auth, i18n } = useContext();
|
||||||
const preferences = useShoppingListPreferences();
|
const preferences = useShoppingListPreferences();
|
||||||
|
@ -44,6 +44,7 @@ import { useUserApi } from "~/composables/api";
|
|||||||
import { useAsyncKey } from "~/composables/use-utils";
|
import { useAsyncKey } from "~/composables/use-utils";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
middleware: "auth",
|
||||||
setup() {
|
setup() {
|
||||||
const { $auth } = useContext();
|
const { $auth } = useContext();
|
||||||
const userApi = useUserApi();
|
const userApi = useUserApi();
|
||||||
|
@ -14,6 +14,7 @@ import { useAsyncKey } from "~/composables/use-utils";
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { RecipeCardSection },
|
components: { RecipeCardSection },
|
||||||
|
middleware: "auth",
|
||||||
setup() {
|
setup() {
|
||||||
const api = useUserApi();
|
const api = useUserApi();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
@ -69,6 +69,7 @@ import { useUserApi } from "~/composables/api";
|
|||||||
import { VForm } from "~/types/vuetify";
|
import { VForm } from "~/types/vuetify";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
middleware: ["auth", "advanced-only"],
|
||||||
setup() {
|
setup() {
|
||||||
const nuxtContext = useContext();
|
const nuxtContext = useContext();
|
||||||
|
|
||||||
|
@ -135,6 +135,7 @@ export default defineComponent({
|
|||||||
UserAvatar,
|
UserAvatar,
|
||||||
UserPasswordStrength,
|
UserPasswordStrength,
|
||||||
},
|
},
|
||||||
|
middleware: "auth",
|
||||||
setup() {
|
setup() {
|
||||||
const { $auth } = useContext();
|
const { $auth } = useContext();
|
||||||
const user = computed(() => $auth.user as unknown as UserOut);
|
const user = computed(() => $auth.user as unknown as UserOut);
|
||||||
|
@ -113,7 +113,7 @@
|
|||||||
<p>{{ $t('profile.group-description') }}</p>
|
<p>{{ $t('profile.group-description') }}</p>
|
||||||
</div>
|
</div>
|
||||||
<v-row tag="section">
|
<v-row tag="section">
|
||||||
<v-col cols="12" sm="12" md="6">
|
<v-col v-if="$auth.user.canManage" cols="12" sm="12" md="6">
|
||||||
<UserProfileLinkCard
|
<UserProfileLinkCard
|
||||||
:link="{ text: $tc('profile.group-settings'), to: `/group` }"
|
:link="{ text: $tc('profile.group-settings'), to: `/group` }"
|
||||||
:image="require('~/static/svgs/manage-group-settings.svg')"
|
:image="require('~/static/svgs/manage-group-settings.svg')"
|
||||||
@ -162,17 +162,16 @@
|
|||||||
</UserProfileLinkCard>
|
</UserProfileLinkCard>
|
||||||
</v-col>
|
</v-col>
|
||||||
</AdvancedOnly>
|
</AdvancedOnly>
|
||||||
<AdvancedOnly>
|
<!-- $auth.user.canOrganize should not be null because of the auth middleware -->
|
||||||
<v-col cols="12" sm="12" md="6">
|
<v-col v-if="$auth.user.canOrganize" cols="12" sm="12" md="6">
|
||||||
<UserProfileLinkCard
|
<UserProfileLinkCard
|
||||||
:link="{ text: $tc('profile.manage-data'), to: `/group/data/foods` }"
|
:link="{ text: $tc('profile.manage-data'), to: `/group/data/foods` }"
|
||||||
:image="require('~/static/svgs/manage-recipes.svg')"
|
:image="require('~/static/svgs/manage-recipes.svg')"
|
||||||
>
|
>
|
||||||
<template #title> {{ $t('profile.manage-data') }} </template>
|
<template #title> {{ $t('profile.manage-data') }} </template>
|
||||||
{{ $t('profile.manage-data-description') }}
|
{{ $t('profile.manage-data-description') }}
|
||||||
</UserProfileLinkCard>
|
</UserProfileLinkCard>
|
||||||
</v-col>
|
</v-col>
|
||||||
</AdvancedOnly>
|
|
||||||
<AdvancedOnly>
|
<AdvancedOnly>
|
||||||
<v-col cols="12" sm="12" md="6">
|
<v-col cols="12" sm="12" md="6">
|
||||||
<UserProfileLinkCard
|
<UserProfileLinkCard
|
||||||
@ -208,6 +207,7 @@ export default defineComponent({
|
|||||||
UserAvatar,
|
UserAvatar,
|
||||||
StatsCards,
|
StatsCards,
|
||||||
},
|
},
|
||||||
|
middleware: "auth",
|
||||||
scrollToTop: true,
|
scrollToTop: true,
|
||||||
setup() {
|
setup() {
|
||||||
const { $auth, i18n } = useContext();
|
const { $auth, i18n } = useContext();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user