Introduce authorizations with Rajska
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -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 },
|
||||
],
|
||||
]
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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")),
|
||||
});
|
||||
|
||||
@@ -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")),
|
||||
|
||||
Reference in New Issue
Block a user