Skip to content
Snippets Groups Projects
Commit aa9a9865 authored by simon.mellerin's avatar simon.mellerin
Browse files

#12 - Implémenter page rejoindre une communauté

parent 651c5ed8
No related branches found
No related tags found
1 merge request!9Resolve "Implémenter page rejoindre une communauté"
import type { ContextDefinition } from "jsonld" import type { ContextDefinition } from "jsonld"
export type OcCommunity = { export type OcCommunity = {
'@id': string
identifier: string identifier: string
name: string,
title: undefined | { [locale: string]: string } title: undefined | { [locale: string]: string }
description: undefined | { [locale: string]: string } description: undefined | { [locale: string]: string }
logo: undefined | string logo: undefined | string
......
...@@ -57,7 +57,7 @@ const firstColDescription = computed(() => { ...@@ -57,7 +57,7 @@ const firstColDescription = computed(() => {
return translateValue(props.community.description, locale.value, fallbackLocale.value) ?? defaultDescription return translateValue(props.community.description, locale.value, fallbackLocale.value) ?? defaultDescription
}) })
const color = props.community ? props.community.color ?? 'olivine' : 'primary' const color = computed(() => props.community ? props.community.color ?? 'olivine' : 'primary')
</script> </script>
<style scoped> <style scoped>
......
...@@ -17,6 +17,16 @@ export default { ...@@ -17,6 +17,16 @@ export default {
goToCommunity: 'Go to community {label}', goToCommunity: 'Go to community {label}',
}, },
communities: 'Communities', communities: 'Communities',
community: {
askJoin: {
buttonLabel: "Request an access to this community",
error: "An error has occurred. If the problem persists, please contact us (via the envelope icon in the top right-hand corner).",
confirmation: {
1: "Your request has been received and you will be given access to the community within a few days.",
2: "In the meantime, you can use the viewer mode.",
},
},
},
backHome: 'Go back to home page', backHome: 'Go back to home page',
error: { error: {
title: 'Error', title: 'Error',
......
...@@ -18,6 +18,16 @@ export default { ...@@ -18,6 +18,16 @@ export default {
goToCommunity: 'Voir la communauté {label}', goToCommunity: 'Voir la communauté {label}',
}, },
communities: 'Communautés', communities: 'Communautés',
community: {
askJoin: {
buttonLabel: "Demander l’accès à cette communauté",
error: "Une erreur est survenue. Si le problème persiste, contactez-nous (via l'icone enveloppe en haut à droite).",
confirmation: {
1: "Votre demande a été prise en compte, vous recevrez sous quelques jours une autorisation d’accès à la communauté.",
2: "En attendant vous pouvez utiliser le mode visteurs.",
},
},
},
backHome: 'Retourner à la page d\'accueil', backHome: 'Retourner à la page d\'accueil',
error: { error: {
title: 'Erreur', title: 'Erreur',
......
<template>
<OcLayoutBiColumn :is-authenticated="!!accountStore.isAuthenticated" :community="community">
<div class="w-11/12 md:w-10/12 xl:w-7/12">
<img src="/logo.png" class="h-16" />
<p class="font-title font-bold text-5xl uppercase text-primary mb-4">Open Common</p>
<p class="text-lg line mb-8">{{ t('connection.catchphrase') }}</p>
<Message severity="error" class="mb-4" v-if="!!requestError">
{{ t('community.askJoin.error') }}
</Message>
<div class="flex justify-center">
<Button rounded class="mb-8" @click="requestAccess" :disabled="!!requestError || requestDone">{{
t('community.askJoin.buttonLabel') }}</Button>
</div>
<div class="flex justify-center">
<Button rounded severity="secondary" class="">{{ t('connection.continueAsGuest') }}</Button>
</div>
</div>
<Dialog v-model:visible="showConfirmation" modal :style="{ width: '25rem' }">
<div class="flex flex-col items-center justify-center">
<i class="fa-solid fa-circle-check text-6xl text-center text-primary mb-6"></i>
<p class="text-center mb-6">{{ t('community.askJoin.confirmation.1') }}</p>
<p class="text-center mb-6">{{ t('community.askJoin.confirmation.2') }}</p>
<Button :as="OcLink" to="" severity="secondary" rounded>
{{ t('connection.continueAsGuest') }}
</Button>
</div>
</Dialog>
</OcLayoutBiColumn>
</template>
<script setup lang="ts">
import OcLink from '@/components/OcLink.vue';
import OcLayoutBiColumn from '@/layout/OcLayoutBiColumn/OcLayoutBiColumn.vue';
import { insertCommunityAccessRequest } from '@/sparql/communities';
import { useAccountStore } from '@/stores/account';
import { useCommunityStore } from '@/stores/community';
import Button from 'primevue/button';
import Dialog from 'primevue/dialog';
import Message from 'primevue/message';
import { computed, onBeforeMount, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router';
const accountStore = useAccountStore()
const communityStore = useCommunityStore()
const route = useRoute()
const { t } = useI18n()
onBeforeMount(() => communityStore.fetchIfEmpty())
const communityName = route.params.community as string
const community = computed(() => communityStore.getByName(communityName))
const requestError = ref<Error | null>(null)
const showConfirmation = ref(false)
const requestDone = ref(false)
async function requestAccess() {
try {
if (!community.value) {
throw new Error('No community available')
}
if (!accountStore.infos) {
throw new Error('No user infos available')
}
await insertCommunityAccessRequest(community.value['@id'], accountStore.infos.loginID)
requestDone.value = true
showConfirmation.value = true
} catch (e) {
console.log(e)
requestError.value = e as Error
}
}
</script>
import type { OcJsonLdDocument, OcCommunity } from "@/declarations"; import type { OcJsonLdDocument, OcCommunity } from "@/declarations";
import { executeSparqlConstruct } from "./sparql"; import { executeSparqlConstruct, executeSparqlInsert } from "./sparql";
import type { ContextDefinition } from "jsonld";
const communityContext: ContextDefinition = {
"identifier": {
"@id": "http://purl.org/dc/terms/identifier",
"@type": "http://www.w3.org/2000/01/rdf-schema#Literal"
},
"title": {
"@id": "http://purl.org/dc/terms/title",
"@container": "@language"
},
"description": {
"@id": "http://purl.org/dc/terms/description",
"@container": "@language"
},
"name": {
"@id": "http://xmlns.com/foaf/0.1/name",
},
"relation": {
"@id": "http://purl.org/dc/terms/relation",
"@type": "@id"
},
"isSpaceOf": {
"@id": "https://www.irit.fr/opencommon/system/isSpaceOf",
"@type": "@id"
},
"logo": {
"@id": "http://xmlns.com/foaf/0.1/logo",
"@type": "@id"
},
}
export const getCommunityList = async (isAuthenticated: boolean = false): Promise<OcJsonLdDocument<OcCommunity>> => { export const getCommunityList = async (isAuthenticated: boolean = false): Promise<OcJsonLdDocument<OcCommunity>> => {
return executeSparqlConstruct<OcCommunity>( return executeSparqlConstruct<OcCommunity>(
...@@ -11,34 +42,19 @@ export const getCommunityList = async (isAuthenticated: boolean = false): Promis ...@@ -11,34 +42,19 @@ export const getCommunityList = async (isAuthenticated: boolean = false): Promis
} }
`, `,
isAuthenticated, isAuthenticated,
{ communityContext
"identifier": {
"@id": "http://purl.org/dc/terms/identifier",
"@type": "http://www.w3.org/2000/01/rdf-schema#Literal"
},
"title": {
"@id": "http://purl.org/dc/terms/title",
"@container": "@language"
},
"description": {
"@id": "http://purl.org/dc/terms/description",
"@container": "@language"
},
"name": {
"@id": "http://xmlns.com/foaf/0.1/name",
},
"relation": {
"@id": "http://purl.org/dc/terms/relation",
"@type": "@id"
},
"isSpaceOf": {
"@id": "https://www.irit.fr/opencommon/system/isSpaceOf",
"@type": "@id"
},
"logo": {
"@id": "http://xmlns.com/foaf/0.1/logo",
"@type": "@id"
},
}
) )
} }
export function insertCommunityAccessRequest(communityUri: string, userLoginID: string) {
const uuid = crypto.randomUUID()
return executeSparqlInsert(`
INSERT INTO <test:graph:garbage> {
<https://www.irit.fr/opencommon/members/${uuid}> a foaf:Person;
oct:loginID '${userLoginID}';
foaf:name '${userLoginID}';
org:hasMembership _:membership.
_:membership org:organization <${communityUri}>.
}
`)
}
...@@ -64,8 +64,8 @@ export async function executeSparqlInsert( ...@@ -64,8 +64,8 @@ export async function executeSparqlInsert(
{ {
method: 'GET', method: 'GET',
headers: { headers: {
'Content-Type': "application/sparql-results+xml", 'Content-Type': "application/x-www-form-urlencoded",
"Accept": "application/ld+json" "Accept": "application/sparql-results+xml"
}, },
credentials: 'include', credentials: 'include',
} }
......
import type { OcCommunity } from '@/declarations' import type { OcCommunity } from '@/declarations'
import { getCommunityList } from '@/sparql/communities' import { getCommunityByName, getCommunityList } from '@/sparql/communities'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { ref } from 'vue' import { computed, ref } from 'vue'
interface CommunityState { interface CommunityState {
data: OcCommunity[] data: OcCommunity[]
...@@ -16,7 +16,7 @@ export const useCommunityStore = defineStore('community', () => { ...@@ -16,7 +16,7 @@ export const useCommunityStore = defineStore('community', () => {
error: null, error: null,
}) })
const fetchIfEmpty = async (force: boolean = false) => { async function fetchIfEmpty(force: boolean = false) {
if (force || state.value.data.length === 0) { if (force || state.value.data.length === 0) {
state.value.loading = true state.value.loading = true
try { try {
...@@ -29,8 +29,13 @@ export const useCommunityStore = defineStore('community', () => { ...@@ -29,8 +29,13 @@ export const useCommunityStore = defineStore('community', () => {
} }
} }
const getByName = computed(() => {
return (name: string) => state.value.data.find((community) => community.name === name)
})
return { return {
state, state,
fetchIfEmpty fetchIfEmpty,
getByName,
} }
}) })
...@@ -21,6 +21,7 @@ declare module 'vue-router/auto-routes' { ...@@ -21,6 +21,7 @@ declare module 'vue-router/auto-routes' {
'/:lang/': RouteRecordInfo<'/:lang/', '/:lang', Record<never, never>, Record<never, never>>, '/:lang/': RouteRecordInfo<'/:lang/', '/:lang', Record<never, never>, Record<never, never>>,
'/:lang/[...path]': RouteRecordInfo<'/:lang/[...path]', '/:lang/:path(.*)', { path: ParamValue<true> }, { path: ParamValue<false> }>, '/:lang/[...path]': RouteRecordInfo<'/:lang/[...path]', '/:lang/:path(.*)', { path: ParamValue<true> }, { path: ParamValue<false> }>,
'/:lang/community/[community]/': RouteRecordInfo<'/:lang/community/[community]/', '/:lang/community/:community', { community: ParamValue<true> }, { community: ParamValue<false> }>, '/:lang/community/[community]/': RouteRecordInfo<'/:lang/community/[community]/', '/:lang/community/:community', { community: ParamValue<true> }, { community: ParamValue<false> }>,
'/:lang/community/[community]/join': RouteRecordInfo<'/:lang/community/[community]/join', '/:lang/community/:community/join', { community: ParamValue<true> }, { community: ParamValue<false> }>,
'/:lang/connection': RouteRecordInfo<'/:lang/connection', '/:lang/connection', Record<never, never>, Record<never, never>>, '/:lang/connection': RouteRecordInfo<'/:lang/connection', '/:lang/connection', Record<never, never>, Record<never, never>>,
'/:lang/profile': RouteRecordInfo<'/:lang/profile', '/:lang/profile', Record<never, never>, Record<never, never>>, '/:lang/profile': RouteRecordInfo<'/:lang/profile', '/:lang/profile', Record<never, never>, Record<never, never>>,
'/:lang/register': RouteRecordInfo<'/:lang/register', '/:lang/register', Record<never, never>, Record<never, never>>, '/:lang/register': RouteRecordInfo<'/:lang/register', '/:lang/register', Record<never, never>, Record<never, never>>,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment