Introduce application tokens
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
138
js/src/views/Settings/AppsView.vue
Normal file
138
js/src/views/Settings/AppsView.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<div v-if="loggedUser">
|
||||
<breadcrumbs-nav
|
||||
:links="[
|
||||
{
|
||||
name: RouteName.AUTHORIZED_APPS,
|
||||
text: t('Apps'),
|
||||
},
|
||||
{
|
||||
name: RouteName.ACCOUNT_SETTINGS_GENERAL,
|
||||
text: t('General'),
|
||||
},
|
||||
]"
|
||||
/>
|
||||
<section>
|
||||
<h2>{{ t("Apps") }}</h2>
|
||||
<p>
|
||||
{{
|
||||
t(
|
||||
"These apps can access your account through the API. If you see here apps that you don't recognize, that don't work as expected or that you don't use anymore, you can revoke their access."
|
||||
)
|
||||
}}
|
||||
</p>
|
||||
<div
|
||||
class="flex justify-between items-center rounded-lg bg-white shadow-xl my-6"
|
||||
v-for="authAuthorizedApplication in authAuthorizedApplications"
|
||||
:key="authAuthorizedApplication.id"
|
||||
>
|
||||
<div class="p-4">
|
||||
<p class="text-3xl font-bold">
|
||||
{{ authAuthorizedApplication.application.name }}
|
||||
</p>
|
||||
<a
|
||||
v-if="authAuthorizedApplication.application.website"
|
||||
target="_blank"
|
||||
:href="authAuthorizedApplication.application.website"
|
||||
>{{
|
||||
urlToHostname(authAuthorizedApplication.application.website)
|
||||
}}</a
|
||||
>
|
||||
<p>
|
||||
<span v-if="authAuthorizedApplication.lastUsedAt">{{
|
||||
t("Last used on {last_used_date}", {
|
||||
last_used_date: formatDateString(
|
||||
authAuthorizedApplication.lastUsedAt
|
||||
),
|
||||
})
|
||||
}}</span>
|
||||
<span v-else>{{ t("Never used") }}</span> ⋅
|
||||
{{
|
||||
t("Authorized on {authorization_date}", {
|
||||
authorization_date: formatDateString(
|
||||
authAuthorizedApplication.insertedAt
|
||||
),
|
||||
})
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="p-4">
|
||||
<o-button
|
||||
@click="() => revoke({ appTokenId: authAuthorizedApplication.id })"
|
||||
variant="danger"
|
||||
>{{ t("Revoke") }}</o-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useLoggedUser } from "@/composition/apollo/user";
|
||||
import {
|
||||
AUTH_AUTHORIZED_APPLICATIONS,
|
||||
REVOKED_AUTHORIZED_APPLICATION,
|
||||
} from "@/graphql/application";
|
||||
import { useMutation, useQuery } from "@vue/apollo-composable";
|
||||
import { useHead } from "@vueuse/head";
|
||||
import { computed } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import RouteName from "../../router/name";
|
||||
import { IUser } from "@/types/current-user.model";
|
||||
import { formatDateString } from "@/filters/datetime";
|
||||
|
||||
const { t } = useI18n({ useScope: "global" });
|
||||
|
||||
const { loggedUser } = useLoggedUser();
|
||||
|
||||
const { result: authAuthorizedApplicationsResult } = useQuery<{
|
||||
loggedUser: Pick<IUser, "authAuthorizedApplications">;
|
||||
}>(AUTH_AUTHORIZED_APPLICATIONS);
|
||||
|
||||
const authAuthorizedApplications = computed(
|
||||
() =>
|
||||
authAuthorizedApplicationsResult.value?.loggedUser
|
||||
?.authAuthorizedApplications
|
||||
);
|
||||
|
||||
const urlToHostname = (url: string | undefined): string | null => {
|
||||
if (!url) return null;
|
||||
try {
|
||||
return new URL(url).hostname;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const { mutate: revoke, onDone: onRevokedApplication } = useMutation<
|
||||
{ revokeApplicationToken: { id: string } },
|
||||
{ appTokenId: string }
|
||||
>(REVOKED_AUTHORIZED_APPLICATION, {
|
||||
update: (cache, { data: returnedData }) => {
|
||||
const data = cache.readQuery<{
|
||||
loggedUser: Pick<IUser, "authAuthorizedApplications">;
|
||||
}>({ query: AUTH_AUTHORIZED_APPLICATIONS });
|
||||
if (!data) return;
|
||||
if (!returnedData) return;
|
||||
const authorizedApplications =
|
||||
data.loggedUser.authAuthorizedApplications.filter(
|
||||
(app) => app.id !== returnedData.revokeApplicationToken.id
|
||||
);
|
||||
cache.writeQuery({
|
||||
query: AUTH_AUTHORIZED_APPLICATIONS,
|
||||
data: {
|
||||
...data,
|
||||
loggedUser: {
|
||||
...data.loggedUser,
|
||||
authAuthorizedApplications: authorizedApplications,
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
useHead({
|
||||
title: computed(() => t("Apps")),
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user