Redirect to profile creation when user has no identities
Also load persons by ID instead of preferred_username Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
@@ -13,19 +13,14 @@ import NavBar from '@/components/NavBar.vue';
|
||||
import { Component, Vue } from 'vue-property-decorator';
|
||||
import {
|
||||
AUTH_ACCESS_TOKEN,
|
||||
AUTH_USER_ACTOR_ID,
|
||||
AUTH_USER_EMAIL,
|
||||
AUTH_USER_ID,
|
||||
AUTH_USER_ROLE,
|
||||
} from '@/constants';
|
||||
import { CURRENT_USER_CLIENT, UPDATE_CURRENT_USER_CLIENT } from '@/graphql/user';
|
||||
import { ICurrentUser } from '@/types/current-user.model';
|
||||
import Footer from '@/components/Footer.vue';
|
||||
import Logo from '@/components/Logo.vue';
|
||||
import { CURRENT_ACTOR_CLIENT, IDENTITIES, UPDATE_CURRENT_ACTOR_CLIENT } from '@/graphql/actor';
|
||||
import { IPerson } from '@/types/actor';
|
||||
import { changeIdentity, initializeCurrentActor, saveActorData } from '@/utils/auth';
|
||||
|
||||
import { initializeCurrentActor } from '@/utils/auth';
|
||||
@Component({
|
||||
apollo: {
|
||||
currentUser: {
|
||||
|
||||
@@ -119,6 +119,15 @@ export default class NavBar extends Vue {
|
||||
});
|
||||
if (data) {
|
||||
this.identities = data.identities.map(identity => new Person(identity));
|
||||
|
||||
// If we don't have any identities, the user has validated their account,
|
||||
// is logging for the first time but didn't create an identity somehow
|
||||
if (this.identities.length === 0) {
|
||||
await this.$router.push({
|
||||
name: RouteName.REGISTER_PROFILE,
|
||||
params: { email: this.currentUser.email, userAlreadyActivated: 'true' },
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
export const FETCH_PERSON = gql`
|
||||
query($name:String!) {
|
||||
person(preferredUsername: $name) {
|
||||
query($username: String!) {
|
||||
fetchPerson(preferredUsername: $username) {
|
||||
id,
|
||||
url,
|
||||
name,
|
||||
@@ -29,6 +29,35 @@ query($name:String!) {
|
||||
}
|
||||
`;
|
||||
|
||||
export const GET_PERSON = gql`
|
||||
query($actorId: ID!) {
|
||||
person(id: $actorId) {
|
||||
id,
|
||||
url,
|
||||
name,
|
||||
domain,
|
||||
summary,
|
||||
preferredUsername,
|
||||
suspended,
|
||||
avatar {
|
||||
name,
|
||||
url
|
||||
},
|
||||
banner {
|
||||
url
|
||||
},
|
||||
feedTokens {
|
||||
token
|
||||
},
|
||||
organizedEvents {
|
||||
uuid,
|
||||
title,
|
||||
beginsOn
|
||||
},
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const LOGGED_PERSON = gql`
|
||||
query {
|
||||
loggedPerson {
|
||||
@@ -172,9 +201,9 @@ mutation CreatePerson($preferredUsername: String!, $name: String!, $summary: Str
|
||||
`;
|
||||
|
||||
export const UPDATE_PERSON = gql`
|
||||
mutation UpdatePerson($preferredUsername: String!, $name: String, $summary: String, $avatar: PictureInput) {
|
||||
mutation UpdatePerson($id: ID!, $name: String, $summary: String, $avatar: PictureInput) {
|
||||
updatePerson(
|
||||
preferredUsername: $preferredUsername,
|
||||
id: $id,
|
||||
name: $name,
|
||||
summary: $summary,
|
||||
avatar: $avatar
|
||||
@@ -191,8 +220,8 @@ export const UPDATE_PERSON = gql`
|
||||
`;
|
||||
|
||||
export const DELETE_PERSON = gql`
|
||||
mutation DeletePerson($preferredUsername: String!) {
|
||||
deletePerson(preferredUsername: $preferredUsername) {
|
||||
mutation DeletePerson($id: ID!) {
|
||||
deletePerson(id: $id) {
|
||||
preferredUsername,
|
||||
}
|
||||
}
|
||||
@@ -209,6 +238,7 @@ mutation ($preferredUsername: String!, $name: String!, $summary: String!, $email
|
||||
summary: $summary,
|
||||
email: $email
|
||||
) {
|
||||
id,
|
||||
preferredUsername,
|
||||
name,
|
||||
summary,
|
||||
|
||||
@@ -221,6 +221,8 @@ export const CREATE_EVENT = gql`
|
||||
id,
|
||||
uuid,
|
||||
title,
|
||||
url,
|
||||
local,
|
||||
description,
|
||||
beginsOn,
|
||||
endsOn,
|
||||
@@ -239,14 +241,25 @@ export const CREATE_EVENT = gql`
|
||||
physicalAddress {
|
||||
${physicalAddressQuery}
|
||||
},
|
||||
organizerActor {
|
||||
avatar {
|
||||
url
|
||||
},
|
||||
preferredUsername,
|
||||
domain,
|
||||
name,
|
||||
url,
|
||||
id,
|
||||
},
|
||||
participantStats {
|
||||
approved,
|
||||
unapproved
|
||||
},
|
||||
tags {
|
||||
${tagsQuery}
|
||||
},
|
||||
options {
|
||||
${optionsQuery}
|
||||
},
|
||||
organizerActor {
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -397,8 +410,8 @@ export const PARTICIPANTS = gql`
|
||||
`;
|
||||
|
||||
export const EVENT_PERSON_PARTICIPATION = gql`
|
||||
query($name: String!, $eventId: ID!) {
|
||||
person(preferredUsername: $name) {
|
||||
query($actorId: ID!, $eventId: ID!) {
|
||||
person(id: $actorId) {
|
||||
id,
|
||||
participations(eventId: $eventId) {
|
||||
id,
|
||||
|
||||
@@ -104,7 +104,7 @@ import { CREATE_FEED_TOKEN_ACTOR } from '@/graphql/feed_tokens';
|
||||
query: FETCH_PERSON,
|
||||
variables() {
|
||||
return {
|
||||
name: this.$route.params.name,
|
||||
username: this.$route.params.name,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
@@ -69,10 +69,12 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { Component, Prop, Vue } from 'vue-property-decorator';
|
||||
import { IPerson } from '@/types/actor';
|
||||
import { REGISTER_PERSON } from '@/graphql/actor';
|
||||
import { IPerson, Person } from '@/types/actor';
|
||||
import { IDENTITIES, REGISTER_PERSON } from '@/graphql/actor';
|
||||
import { MOBILIZON_INSTANCE_HOST } from '@/api/_entrypoint';
|
||||
import { RouteName } from '@/router';
|
||||
import { changeIdentity } from '@/utils/auth';
|
||||
import { ICurrentUser } from '@/types/current-user.model';
|
||||
|
||||
@Component
|
||||
export default class Register extends Vue {
|
||||
@@ -81,19 +83,7 @@ export default class Register extends Vue {
|
||||
|
||||
host?: string = MOBILIZON_INSTANCE_HOST;
|
||||
|
||||
person: IPerson = {
|
||||
preferredUsername: '',
|
||||
name: '',
|
||||
summary: '',
|
||||
url: '',
|
||||
suspended: false,
|
||||
avatar: null,
|
||||
banner: null,
|
||||
domain: null,
|
||||
feedTokens: [],
|
||||
goingToEvents: [],
|
||||
participations: [],
|
||||
};
|
||||
person: IPerson = new Person();
|
||||
errors: object = {};
|
||||
validationSent: boolean = false;
|
||||
sendingValidation: boolean = false;
|
||||
@@ -102,14 +92,26 @@ export default class Register extends Vue {
|
||||
try {
|
||||
this.sendingValidation = true;
|
||||
this.errors = {};
|
||||
await this.$apollo.mutate({
|
||||
const { data } = await this.$apollo.mutate<{ registerPerson: IPerson }>({
|
||||
mutation: REGISTER_PERSON,
|
||||
variables: Object.assign({ email: this.email }, this.person),
|
||||
});
|
||||
this.validationSent = true;
|
||||
update: (store, { data }) => {
|
||||
const identitiesData = store.readQuery<{ identities: IPerson[] }>({ query: IDENTITIES });
|
||||
|
||||
if (this.userAlreadyActivated) {
|
||||
this.$router.push({ name: RouteName.HOME });
|
||||
if (identitiesData && data) {
|
||||
identitiesData.identities.push(data.registerPerson);
|
||||
store.writeQuery({ query: IDENTITIES, data: identitiesData });
|
||||
}
|
||||
},
|
||||
});
|
||||
if (data) {
|
||||
this.validationSent = true;
|
||||
|
||||
if (this.userAlreadyActivated) {
|
||||
await changeIdentity(this.$apollo.provider.defaultClient, data.registerPerson);
|
||||
|
||||
await this.$router.push({ name: RouteName.HOME });
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
this.errors = error.graphQLErrors.reduce((acc, error) => {
|
||||
|
||||
@@ -95,7 +95,7 @@ import { MOBILIZON_INSTANCE_HOST } from '@/api/_entrypoint';
|
||||
import { Dialog } from 'buefy/dist/components/dialog';
|
||||
import { RouteName } from '@/router';
|
||||
import { buildFileFromIPicture, buildFileVariable } from '@/utils/image';
|
||||
import { changeIdentity, saveActorData } from '@/utils/auth';
|
||||
import { changeIdentity } from '@/utils/auth';
|
||||
|
||||
@Component({
|
||||
components: {
|
||||
@@ -165,7 +165,9 @@ export default class EditIdentity extends Vue {
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: DELETE_PERSON,
|
||||
variables: this.identity,
|
||||
variables: {
|
||||
id: this.identity.id,
|
||||
},
|
||||
update: (store) => {
|
||||
const data = store.readQuery<{ identities: IPerson[] }>({ query: IDENTITIES });
|
||||
|
||||
@@ -278,11 +280,11 @@ export default class EditIdentity extends Vue {
|
||||
const result = await this.$apollo.query({
|
||||
query: FETCH_PERSON,
|
||||
variables: {
|
||||
name: this.identityName,
|
||||
username: this.identityName,
|
||||
},
|
||||
});
|
||||
|
||||
return new Person(result.data.person);
|
||||
return new Person(result.data.fetchPerson);
|
||||
}
|
||||
|
||||
private handleError(err: any) {
|
||||
|
||||
@@ -232,7 +232,7 @@ import {ParticipantRole} from "@/types/event.model";
|
||||
</style>
|
||||
|
||||
<script lang="ts">
|
||||
import { CREATE_EVENT, EDIT_EVENT, FETCH_EVENT } from '@/graphql/event';
|
||||
import { CREATE_EVENT, EDIT_EVENT, EVENT_PERSON_PARTICIPATION, FETCH_EVENT } from '@/graphql/event';
|
||||
import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
|
||||
import {
|
||||
CommentModeration,
|
||||
@@ -243,7 +243,7 @@ import {
|
||||
IEvent, ParticipantRole,
|
||||
} from '@/types/event.model';
|
||||
import { CURRENT_ACTOR_CLIENT, IDENTITIES, LOGGED_USER_DRAFTS, LOGGED_USER_PARTICIPATIONS } from '@/graphql/actor';
|
||||
import { Person } from '@/types/actor';
|
||||
import { IPerson, Person } from '@/types/actor';
|
||||
import PictureUpload from '@/components/PictureUpload.vue';
|
||||
import Editor from '@/components/Editor.vue';
|
||||
import DateTimePicker from '@/components/Event/DateTimePicker.vue';
|
||||
@@ -365,45 +365,10 @@ export default class EditEvent extends Vue {
|
||||
const { data } = await this.$apollo.mutate({
|
||||
mutation: CREATE_EVENT,
|
||||
variables: this.buildVariables(),
|
||||
update: (store, { data: { createEvent } }) => {
|
||||
if (createEvent.draft) {
|
||||
const data = store.readQuery<{ loggedUser: ICurrentUser }>({ query: LOGGED_USER_DRAFTS, variables: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
} });
|
||||
|
||||
if (data) {
|
||||
data.loggedUser.drafts.push(createEvent);
|
||||
store.writeQuery({ query: LOGGED_USER_DRAFTS, variables: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
}, data });
|
||||
}
|
||||
} else {
|
||||
const data = store.readQuery<{ loggedUser: ICurrentUser }>({ query: LOGGED_USER_PARTICIPATIONS, variables: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
afterDateTime: (new Date()).toISOString(),
|
||||
} });
|
||||
|
||||
if (data) {
|
||||
data.loggedUser.participations.push({
|
||||
role: ParticipantRole.CREATOR,
|
||||
actor: createEvent.organizerActor,
|
||||
event: createEvent,
|
||||
});
|
||||
store.writeQuery({ query: LOGGED_USER_PARTICIPATIONS, variables: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
afterDateTime: (new Date()).toISOString(),
|
||||
}, data });
|
||||
}
|
||||
}
|
||||
},
|
||||
update: (store, { data: { createEvent } }) => this.postCreateOrUpdate(store, createEvent),
|
||||
refetchQueries: ({ data: { createEvent } }) => this.postRefetchQueries(createEvent),
|
||||
});
|
||||
|
||||
console.log('Event created', data);
|
||||
|
||||
await this.$router.push({
|
||||
name: 'Event',
|
||||
params: { uuid: data.createEvent.uuid },
|
||||
@@ -418,50 +383,8 @@ export default class EditEvent extends Vue {
|
||||
await this.$apollo.mutate({
|
||||
mutation: EDIT_EVENT,
|
||||
variables: this.buildVariables(),
|
||||
update: (store, { data: { updateEvent } }) => {
|
||||
if (updateEvent.draft) {
|
||||
const data = store.readQuery<{ loggedUser: ICurrentUser }>({ query: LOGGED_USER_DRAFTS, variables: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
} });
|
||||
|
||||
if (data) {
|
||||
data.loggedUser.drafts.push(updateEvent);
|
||||
store.writeQuery({ query: LOGGED_USER_DRAFTS, data });
|
||||
}
|
||||
} else {
|
||||
let participationData: { loggedUser: ICurrentUser}|null = null;
|
||||
try {
|
||||
participationData = store.readQuery<{ loggedUser: ICurrentUser }>({
|
||||
query: LOGGED_USER_PARTICIPATIONS, variables: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
afterDateTime: (new Date()).toISOString(),
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
// no worries, it seems we can't update participation cache because it's not linked to an ID
|
||||
}
|
||||
|
||||
if (participationData) {
|
||||
participationData.loggedUser.participations.push({
|
||||
role: ParticipantRole.CREATOR,
|
||||
actor: updateEvent.organizerActor,
|
||||
event: updateEvent,
|
||||
});
|
||||
store.writeQuery({ query: LOGGED_USER_PARTICIPATIONS, variables: {
|
||||
page: 1,
|
||||
limit: 10,
|
||||
afterDateTime: (new Date()).toISOString(),
|
||||
}, data: participationData });
|
||||
}
|
||||
const resultEvent: IEvent = Object.assign({}, updateEvent);
|
||||
resultEvent.organizerActor = this.event.organizerActor;
|
||||
resultEvent.relatedEvents = [];
|
||||
|
||||
store.writeQuery({ query: FETCH_EVENT, variables: { uuid: updateEvent.uuid }, data: { event: resultEvent } });
|
||||
}
|
||||
},
|
||||
update: (store, { data: { updateEvent } }) => this.postCreateOrUpdate(store, updateEvent),
|
||||
refetchQueries: ({ data: { updateEvent } }) => this.postRefetchQueries(updateEvent),
|
||||
});
|
||||
|
||||
await this.$router.push({
|
||||
@@ -473,6 +396,61 @@ export default class EditEvent extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put in cache the updated or created event.
|
||||
* If the event is not a draft anymore, also put in cache the participation
|
||||
*/
|
||||
private postCreateOrUpdate(store, updateEvent) {
|
||||
const resultEvent: IEvent = Object.assign({}, updateEvent);
|
||||
const organizerActor: IPerson = this.event.organizerActor as Person;
|
||||
resultEvent.organizerActor = organizerActor;
|
||||
resultEvent.relatedEvents = [];
|
||||
|
||||
store.writeQuery({ query: FETCH_EVENT, variables: { uuid: updateEvent.uuid }, data: { event: resultEvent } });
|
||||
if (!updateEvent.draft) {
|
||||
store.writeQuery({
|
||||
query: EVENT_PERSON_PARTICIPATION,
|
||||
variables: { eventId: updateEvent.id, name: organizerActor.preferredUsername },
|
||||
data: {
|
||||
person: {
|
||||
__typename: 'Person',
|
||||
id: organizerActor.id,
|
||||
participations: [{
|
||||
__typename: 'Participant',
|
||||
id: 'unknown',
|
||||
role: ParticipantRole.CREATOR,
|
||||
actor: {
|
||||
__typename: 'Actor',
|
||||
id: organizerActor.id,
|
||||
},
|
||||
event: {
|
||||
__typename: 'Event',
|
||||
id: updateEvent.id,
|
||||
},
|
||||
}],
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh drafts or participation cache depending if the event is still draft or not
|
||||
*/
|
||||
private postRefetchQueries(updateEvent) {
|
||||
if (updateEvent.draft) {
|
||||
return [{
|
||||
query: LOGGED_USER_DRAFTS,
|
||||
}];
|
||||
}
|
||||
return [{
|
||||
query: LOGGED_USER_PARTICIPATIONS,
|
||||
variables: {
|
||||
afterDateTime: new Date(),
|
||||
},
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* Build variables for Event GraphQL creation query
|
||||
*/
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<p class="tags" v-if="event.category || event.tags.length > 0">
|
||||
<b-tag type="is-warning" size="is-medium" v-if="event.draft">{{ $t('Draft') }}</b-tag>
|
||||
<!-- <span class="tag" v-if="event.category">{{ event.category }}</span>-->
|
||||
<b-tag type="is-success" v-if="event.tags" v-for="tag in event.tags">{{ tag.title }}</b-tag>
|
||||
<b-tag type="is-success" v-if="event.tags" v-for="tag in event.tags" :key="tag.title">{{ tag.title }}</b-tag>
|
||||
<span v-if="event.tags > 0">⋅</span>
|
||||
<span class="visibility" v-if="!event.draft">
|
||||
<b-tag type="is-info" v-if="event.visibility === EventVisibility.PUBLIC">{{ $t('Public event') }}</b-tag>
|
||||
@@ -256,13 +256,16 @@ import { RouteName } from '@/router';
|
||||
variables() {
|
||||
return {
|
||||
eventId: this.event.id,
|
||||
name: this.currentActor.preferredUsername,
|
||||
actorId: this.currentActor.id,
|
||||
};
|
||||
},
|
||||
update: (data) => {
|
||||
if (data && data.person) return data.person.participations;
|
||||
return [];
|
||||
},
|
||||
skip() {
|
||||
return !this.event.id || !this.currentActor.id;
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -135,7 +135,7 @@ export default class Register extends Vue {
|
||||
|
||||
this.validationSent = true;
|
||||
|
||||
this.$router.push({
|
||||
await this.$router.push({
|
||||
name: RouteName.REGISTER_PROFILE,
|
||||
params: { email: this.credentials.email },
|
||||
});
|
||||
|
||||
@@ -48,9 +48,12 @@ export default class Validate extends Vue {
|
||||
const user = data.validateUser.user;
|
||||
console.log(user);
|
||||
if (user.defaultActor) {
|
||||
this.$router.push({ name: RouteName.HOME });
|
||||
await this.$router.push({ name: RouteName.HOME });
|
||||
} else { // If the user didn't register any profile yet, let's create one for them
|
||||
this.$router.push({ name: RouteName.REGISTER_PROFILE, params: { email: user.email, userAlreadyActivated: 'true' } });
|
||||
await this.$router.push({
|
||||
name: RouteName.REGISTER_PROFILE,
|
||||
params: { email: user.email, userAlreadyActivated: 'true' },
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
|
||||
Reference in New Issue
Block a user