Introduce authorizations with Rajska

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2023-03-17 18:10:59 +01:00
parent b6875f6a4b
commit 8984bd7636
95 changed files with 4560 additions and 1505 deletions

View File

@@ -234,6 +234,7 @@ import { convertToUsername } from "@/utils/username";
import { Dialog } from "@/plugins/dialog";
import { Notifier } from "@/plugins/notifier";
import { AbsintheGraphQLErrors } from "@/types/errors.model";
import { ICurrentUser } from "@/types/current-user.model";
const { t } = useI18n({ useScope: "global" });
const router = useRouter();
@@ -348,7 +349,7 @@ const {
onError: deletePersonError,
} = useMutation(DELETE_PERSON, () => ({
update: (store: ApolloCache<InMemoryCache>) => {
const data = store.readQuery<{ identities: IPerson[] }>({
const data = store.readQuery<{ loggedUser: Pick<ICurrentUser, 'actors'> }>({
query: IDENTITIES,
});
@@ -356,7 +357,10 @@ const {
store.writeQuery({
query: IDENTITIES,
data: {
identities: data.identities.filter((i) => i.id !== identity.value.id),
loggedUser: {
...data.loggedUser,
actors: data.loggedUser.actors.filter((i) => i.id !== identity.value.id)
}
},
});
}
@@ -379,10 +383,10 @@ deletePersonDone(async () => {
*/
const client = resolveClient();
const data = client.readQuery<{
identities: IPerson[];
loggedUser: Pick<ICurrentUser, 'actors'>
}>({ query: IDENTITIES });
if (data) {
await maybeUpdateCurrentActorCache(data.identities[0]);
await maybeUpdateCurrentActorCache(data.loggedUser.actors[0]);
}
await redirectIfNoIdentitySelected();
@@ -408,7 +412,7 @@ const {
store: ApolloCache<InMemoryCache>,
{ data: updateData }: FetchResult
) => {
const data = store.readQuery<{ identities: IPerson[] }>({
const data = store.readQuery<{ loggedUser: Pick<ICurrentUser, 'actors'> }>({
query: IDENTITIES,
});
@@ -452,7 +456,7 @@ const {
store: ApolloCache<InMemoryCache>,
{ data: updateData }: FetchResult
) => {
const data = store.readQuery<{ identities: IPerson[] }>({
const data = store.readQuery<{ loggedUser: Pick<ICurrentUser, 'actors'> }>({
query: IDENTITIES,
});
@@ -460,10 +464,13 @@ const {
store.writeQuery({
query: IDENTITIES,
data: {
identities: [
...data.identities,
loggedUser: {
...data.loggedUser,
actors: [
...data.loggedUser.actors,
{ ...updateData?.createPerson, type: ActorType.PERSON },
],
]
}
},
});
}

View File

@@ -18,27 +18,47 @@
<section class="timeline">
<o-field>
<o-radio v-model="activityType" :native-value="undefined">
<o-radio class="pr-4" v-model="activityType" :native-value="undefined">
<TimelineText />
{{ t("All activities") }}</o-radio
>
<o-radio v-model="activityType" :native-value="ActivityType.MEMBER">
<o-radio
class="pr-4"
v-model="activityType"
:native-value="ActivityType.MEMBER"
>
<o-icon icon="account-multiple-plus"></o-icon>
{{ t("Members") }}</o-radio
>
<o-radio v-model="activityType" :native-value="ActivityType.GROUP">
<o-radio
class="pr-4"
v-model="activityType"
:native-value="ActivityType.GROUP"
>
<o-icon icon="cog"></o-icon>
{{ t("Settings") }}</o-radio
>
<o-radio v-model="activityType" :native-value="ActivityType.EVENT">
<o-radio
class="pr-4"
v-model="activityType"
:native-value="ActivityType.EVENT"
>
<o-icon icon="calendar"></o-icon>
{{ t("Events") }}</o-radio
>
<o-radio v-model="activityType" :native-value="ActivityType.POST">
<o-radio
class="pr-4"
v-model="activityType"
:native-value="ActivityType.POST"
>
<o-icon icon="bullhorn"></o-icon>
{{ t("Posts") }}</o-radio
>
<o-radio v-model="activityType" :native-value="ActivityType.DISCUSSION">
<o-radio
class="pr-4"
v-model="activityType"
:native-value="ActivityType.DISCUSSION"
>
<o-icon icon="chat"></o-icon>
{{ t("Discussions") }}</o-radio
>
@@ -48,11 +68,16 @@
>
</o-field>
<o-field>
<o-radio v-model="activityAuthor" :native-value="undefined">
<o-radio
class="pr-4"
v-model="activityAuthor"
:native-value="undefined"
>
<TimelineText />
{{ t("All activities") }}</o-radio
>
<o-radio
class="pr-4"
v-model="activityAuthor"
:native-value="ActivityAuthorFilter.SELF"
>
@@ -60,6 +85,7 @@
{{ t("From yourself") }}</o-radio
>
<o-radio
class="pr-4"
v-model="activityAuthor"
:native-value="ActivityAuthorFilter.BY"
>
@@ -89,7 +115,7 @@
<h2 v-else>
{{ formatDateString(date) }}
</h2>
<ul>
<ul class="before:opacity-10">
<li v-for="activityItem in activityItems" :key="activityItem.id">
<skeleton-activity-item v-if="activityItem.type === 'skeleton'" />
<component
@@ -202,6 +228,7 @@ const page = ref(1);
const {
result: groupTimelineResult,
fetchMore: fetchMoreActivities,
onError: onGroupTLError,
loading,
} = useQuery<{ group: IGroup }>(GROUP_TIMELINE, () => ({
preferredUsername: props.preferredUsername,
@@ -211,6 +238,8 @@ const {
author: activityAuthor.value,
}));
onGroupTLError((err) => console.error(err));
const group = computed(() => groupTimelineResult.value?.group);
useHead({

View File

@@ -36,8 +36,8 @@
/>
<div v-show="authApplicationError">
<div
class="rounded-lg bg-mbz-danger shadow-xl my-6 p-4 flex items-center gap-2"
v-if="authApplicationGraphError?.status_code === 404"
class="rounded-lg text-white bg-mbz-danger shadow-xl my-6 p-4 flex items-center gap-2"
v-if="authApplicationGraphError?.message === 'not_found'"
>
<AlertCircle :size="42" />
<div>
@@ -72,9 +72,6 @@
<p class="text-4xl">{{ resultCode }}</p>
</div>
</div>
<o-button variant="text" tag="router-link" :to="{ name: RouteName.HOME }">{{
t("Back to homepage")
}}</o-button>
</div>
</template>
@@ -83,8 +80,8 @@ import { useRouteQuery } from "vue-use-route-query";
import { useHead } from "@vueuse/head";
import { computed, ref } from "vue";
import { useI18n } from "vue-i18n";
import { useMutation, useQuery } from "@vue/apollo-composable";
import { AUTH_APPLICATION, AUTORIZE_APPLICATION } from "@/graphql/application";
import { useQuery } from "@vue/apollo-composable";
import { AUTH_APPLICATION } from "@/graphql/application";
import { IApplication } from "@/types/application.model";
import AlertCircle from "vue-material-design-icons/AlertCircle.vue";
import type { AbsintheGraphQLError } from "@/types/errors.model";
@@ -98,7 +95,6 @@ const redirectURI = useRouteQuery("redirect_uri", null);
const state = useRouteQuery("state", null);
const scope = useRouteQuery("scope", null);
const OUT_OF_BAND_REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";
const resultCode = ref<string | null>(null);
const {
@@ -123,44 +119,6 @@ const authApplicationGraphError = computed(
() => authApplicationError.value?.graphQLErrors[0] as AbsintheGraphQLError
);
const { mutate: authorizeMutation, onDone: onAuthorizeMutationDone } =
useMutation<
{ authorizeApplication: { code: string; state: string } },
{
applicationClientId: string;
redirectURI: string;
state?: string | null;
scope?: string | null;
}
>(AUTORIZE_APPLICATION);
const authorize = () => {
authorizeMutation({
applicationClientId: clientId.value as string,
redirectURI: redirectURI.value as string,
state: state.value,
scope: scope.value,
});
};
onAuthorizeMutationDone(({ data }) => {
const code = data?.authorizeApplication?.code;
const returnedState = data?.authorizeApplication?.state ?? "";
if (!code) return;
if (redirectURI.value !== OUT_OF_BAND_REDIRECT_URI) {
const params = new URLSearchParams(
Object.entries({ code, state: returnedState })
);
window.location.assign(
new URL(`${redirectURI.value}?${params.toString()}`)
);
return;
}
resultCode.value = code;
});
useHead({
title: computed(() => t("Authorize application")),
});

View File

@@ -136,10 +136,8 @@ const { mutate: revoke, onDone: onRevokedApplication } = useMutation<
const notifier = inject<Notifier>("notifier");
onRevokedApplication(() => {
notifier?.success(
t("Application was revoked")
);
})
notifier?.success(t("Application was revoked"));
});
useHead({
title: computed(() => t("Apps")),