diff --git a/backend/src/apis/gms/model/GmsEnums.ts b/backend/src/apis/gms/model/GmsEnums.ts deleted file mode 100644 index 1342327d1..000000000 --- a/backend/src/apis/gms/model/GmsEnums.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { registerEnumType } from 'type-graphql' - -export enum GmsPublishNameType { - GMS_PUBLISH_NAME_ALIAS_OR_INITALS = 0, - GMS_PUBLISH_NAME_INITIALS = 1, - GMS_PUBLISH_NAME_FIRST = 2, - GMS_PUBLISH_NAME_FIRST_INITIAL = 3, - GMS_PUBLISH_NAME_FULL = 4, -} - -registerEnumType(GmsPublishNameType, { - name: 'GmsPublishNameType', // this one is mandatory - description: 'Type of name publishing', // this one is optional -}) - -export enum GmsPublishPhoneType { - GMS_PUBLISH_PHONE_NOTHING = 0, - GMS_PUBLISH_PHONE_COUNTRY = 1, - GMS_PUBLISH_PHONE_FULL = 2, -} - -registerEnumType(GmsPublishPhoneType, { - name: 'GmsPublishPhoneType', // this one is mandatory - description: 'Type of Phone publishing', // this one is optional -}) - -export enum GmsLocationType { - GMS_LOCATION_TYPE_EXACT = 0, - GMS_LOCATION_TYPE_APPROXIMATE = 1, - GMS_LOCATION_TYPE_RANDOM = 2, -} - -registerEnumType(GmsLocationType, { - name: 'GmsLocationType', // this one is mandatory - description: 'Type of location treatment in GMS', // this one is optional -}) diff --git a/backend/src/apis/gms/model/GmsUser.ts b/backend/src/apis/gms/model/GmsUser.ts index 2fad3bd1e..7f7db7660 100644 --- a/backend/src/apis/gms/model/GmsUser.ts +++ b/backend/src/apis/gms/model/GmsUser.ts @@ -1,6 +1,8 @@ import { User as dbUser } from '@entity/User' -import { GmsLocationType, GmsPublishNameType, GmsPublishPhoneType } from './GmsEnums' +import { GmsPublishLocationType } from '@/graphql/enum/GmsPublishLocationType' +import { GmsPublishNameType } from '@/graphql/enum/GmsPublishNameType' +import { GmsPublishPhoneType } from '@/graphql/enum/GmsPublishPhoneType' export class GmsUser { constructor(user: dbUser) { @@ -12,7 +14,7 @@ export class GmsUser { this.firstName = this.getGmsFirstName(user) this.lastName = this.getGmsLastName(user) this.alias = this.getGmsAlias(user) - this.type = GmsLocationType.GMS_LOCATION_TYPE_RANDOM + this.type = GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM this.location = null } diff --git a/backend/src/graphql/arg/UpdateUserInfosArgs.ts b/backend/src/graphql/arg/UpdateUserInfosArgs.ts index 6b2ab1032..ab1263eee 100644 --- a/backend/src/graphql/arg/UpdateUserInfosArgs.ts +++ b/backend/src/graphql/arg/UpdateUserInfosArgs.ts @@ -1,6 +1,8 @@ -import { IsBoolean, IsInt, IsString } from 'class-validator' +import { IsBoolean, IsInt, IsObject, IsString } from 'class-validator' import { ArgsType, Field, Int } from 'type-graphql' +import { Location } from '@model/Location' + @ArgsType() export class UpdateUserInfosArgs { @Field({ nullable: true }) @@ -38,4 +40,20 @@ export class UpdateUserInfosArgs { @Field({ nullable: true }) @IsBoolean() hideAmountGDT?: boolean + + @Field({ nullable: false }) + @IsBoolean() + gmsAllowed: boolean + + @Field(() => Int, { nullable: false }) + @IsInt() + gmsPublishName: number + + @Field(() => Location, { nullable: true }) + @IsObject() + gmsLocation?: Location | null + + @Field(() => Int, { nullable: false }) + @IsInt() + gmsPublishLocation: number } diff --git a/backend/src/graphql/enum/GmsPublishLocationType.ts b/backend/src/graphql/enum/GmsPublishLocationType.ts new file mode 100644 index 000000000..afb9c246d --- /dev/null +++ b/backend/src/graphql/enum/GmsPublishLocationType.ts @@ -0,0 +1,12 @@ +import { registerEnumType } from 'type-graphql' + +export enum GmsPublishLocationType { + GMS_LOCATION_TYPE_EXACT = 0, + GMS_LOCATION_TYPE_APPROXIMATE = 1, + GMS_LOCATION_TYPE_RANDOM = 2, +} + +registerEnumType(GmsPublishLocationType, { + name: 'GmsPublishLocationType', // this one is mandatory + description: 'Type of location treatment in GMS', // this one is optional +}) diff --git a/backend/src/graphql/enum/GmsPublishNameType.ts b/backend/src/graphql/enum/GmsPublishNameType.ts new file mode 100644 index 000000000..08aaaf8ef --- /dev/null +++ b/backend/src/graphql/enum/GmsPublishNameType.ts @@ -0,0 +1,14 @@ +import { registerEnumType } from 'type-graphql' + +export enum GmsPublishNameType { + GMS_PUBLISH_NAME_ALIAS_OR_INITALS = 0, + GMS_PUBLISH_NAME_INITIALS = 1, + GMS_PUBLISH_NAME_FIRST = 2, + GMS_PUBLISH_NAME_FIRST_INITIAL = 3, + GMS_PUBLISH_NAME_FULL = 4, +} + +registerEnumType(GmsPublishNameType, { + name: 'GmsPublishNameType', // this one is mandatory + description: 'Type of name publishing', // this one is optional +}) diff --git a/backend/src/graphql/enum/GmsPublishPhoneType.ts b/backend/src/graphql/enum/GmsPublishPhoneType.ts new file mode 100644 index 000000000..a9821d8ff --- /dev/null +++ b/backend/src/graphql/enum/GmsPublishPhoneType.ts @@ -0,0 +1,12 @@ +import { registerEnumType } from 'type-graphql' + +export enum GmsPublishPhoneType { + GMS_PUBLISH_PHONE_NOTHING = 0, + GMS_PUBLISH_PHONE_COUNTRY = 1, + GMS_PUBLISH_PHONE_FULL = 2, +} + +registerEnumType(GmsPublishPhoneType, { + name: 'GmsPublishPhoneType', // this one is mandatory + description: 'Type of Phone publishing', // this one is optional +}) diff --git a/backend/src/graphql/model/Location.ts b/backend/src/graphql/model/Location.ts new file mode 100644 index 000000000..281ee9ff4 --- /dev/null +++ b/backend/src/graphql/model/Location.ts @@ -0,0 +1,31 @@ +import { Point } from '@dbTools/typeorm' +import { ArgsType, Field, InputType, Int } from 'type-graphql' + +@InputType() +@ArgsType() +// @ObjectType() +export class Location { + constructor(lon: number, lat: number) { + this.longitude = lon + this.latitude = lat + } + + @Field(() => Int) + longitude: number + + @Field(() => Int) + latitude: number + + // point is no Field and not part of the graphql type + private point: Point + + public getPoint(): Point { + const pointStr = '{ "type": "Point", "coordinates": [' + .concat(this.longitude.toString()) + .concat(', ') + .concat(this.latitude.toString()) + .concat('] }') + this.point = JSON.parse(pointStr) as Point + return this.point + } +} diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index a4892496b..7a81b7017 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -16,6 +16,8 @@ import { ApolloServerTestClient } from 'apollo-server-testing' import { GraphQLError } from 'graphql' import { v4 as uuidv4, validate as validateUUID, version as versionUUID } from 'uuid' +import { GmsPublishLocationType } from '@enum/GmsPublishLocationType' +import { GmsPublishNameType } from '@enum/GmsPublishNameType' import { OptInType } from '@enum/OptInType' import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' import { RoleNames } from '@enum/RoleNames' @@ -1165,7 +1167,16 @@ describe('UserResolver', () => { it('throws an error', async () => { jest.clearAllMocks() resetToken() - await expect(mutate({ mutation: updateUserInfos })).resolves.toEqual( + await expect( + mutate({ + mutation: updateUserInfos, + variables: { + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, + }, + }), + ).resolves.toEqual( expect.objectContaining({ errors: [new GraphQLError('401 Unauthorized')], }), @@ -1190,7 +1201,16 @@ describe('UserResolver', () => { }) it('returns true', async () => { - await expect(mutate({ mutation: updateUserInfos })).resolves.toEqual( + await expect( + mutate({ + mutation: updateUserInfos, + variables: { + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, + }, + }), + ).resolves.toEqual( expect.objectContaining({ data: { updateUserInfos: true, @@ -1207,6 +1227,9 @@ describe('UserResolver', () => { firstName: 'Benjamin', lastName: 'Blümchen', locale: 'en', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }, }) await expect(User.find()).resolves.toEqual([ @@ -1244,6 +1267,9 @@ describe('UserResolver', () => { mutation: updateUserInfos, variables: { alias: 'bibi_Bloxberg', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }, }) await expect(User.find()).resolves.toEqual([ @@ -1263,6 +1289,9 @@ describe('UserResolver', () => { mutation: updateUserInfos, variables: { locale: 'not-valid', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }, }), ).resolves.toEqual( @@ -1287,6 +1316,9 @@ describe('UserResolver', () => { variables: { password: 'wrong password', passwordNew: 'Aa12345_', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }, }), ).resolves.toEqual( @@ -1310,6 +1342,9 @@ describe('UserResolver', () => { variables: { password: 'Aa12345_', passwordNew: 'Aa12345', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }, }), ).resolves.toEqual( @@ -1338,6 +1373,9 @@ describe('UserResolver', () => { variables: { password: 'Aa12345_', passwordNew: 'Bb12345_', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }, }), ).resolves.toEqual( @@ -2585,6 +2623,9 @@ describe('UserResolver', () => { mutation: updateUserInfos, variables: { alias: 'bibi', + gmsAllowed: true, + gmsPublishName: GmsPublishNameType.GMS_PUBLISH_NAME_ALIAS_OR_INITALS, + gmsPublishLocation: GmsPublishLocationType.GMS_LOCATION_TYPE_RANDOM, }, }) }) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 45053bda4..fa00a4d57 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -547,10 +547,16 @@ export class UserResolver { passwordNew, hideAmountGDD, hideAmountGDT, + gmsAllowed, + gmsPublishName, + gmsLocation, + gmsPublishLocation, }: UpdateUserInfosArgs, @Ctx() context: Context, ): Promise { - logger.info(`updateUserInfos(${firstName}, ${lastName}, ${language}, ***, ***)...`) + logger.info( + `updateUserInfos(${firstName}, ${lastName}, ${language}, ***, ***, ${gmsAllowed}, ${gmsPublishName}, ${gmsLocation}, ${gmsPublishLocation})...`, + ) const user = getUser(context) if (firstName) { @@ -599,6 +605,13 @@ export class UserResolver { user.hideAmountGDT = hideAmountGDT } + user.gmsAllowed = gmsAllowed + user.gmsPublishName = gmsPublishName + if (gmsLocation) { + user.location = gmsLocation.getPoint() + } + user.gmsPublishLocation = gmsPublishLocation + const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() await queryRunner.startTransaction('REPEATABLE READ') diff --git a/backend/src/graphql/scalar/Geometry.ts b/backend/src/graphql/scalar/Geometry.ts new file mode 100644 index 000000000..c2cd48fdb --- /dev/null +++ b/backend/src/graphql/scalar/Geometry.ts @@ -0,0 +1,33 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +import { Geometry as DbGeometry } from '@dbTools/typeorm' +import { GraphQLScalarType, Kind } from 'graphql' + +import { Location } from '@model/Location' + +export const GeometryScalar = new GraphQLScalarType({ + name: 'Geometry', + description: + 'The `Geometry` scalar type to represent longitude and latitude values of a geo location', + + serialize(value: DbGeometry): Location { + // Check type of value + if (value.type !== 'Point') { + throw new Error(`GeometryScalar can only serialize Geometry type 'Point' values`) + } + + return new Location(value.coordinates[0], value.coordinates[1]) + }, + + parseValue(value): DbGeometry { + const geometry: DbGeometry = JSON.parse(value) as DbGeometry + return geometry + }, + + parseLiteral(ast) { + if (ast.kind !== Kind.STRING) { + throw new TypeError(`${String(ast)} is not a valid Geometry value.`) + } + + return JSON.parse(ast.value) as DbGeometry + }, +}) diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index 554cc4def..a658c84d7 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -34,6 +34,10 @@ export const updateUserInfos = gql` $locale: String $hideAmountGDD: Boolean $hideAmountGDT: Boolean + $gmsAllowed: Boolean! + $gmsPublishName: Int! + $gmsLocation: Location + $gmsPublishLocation: Int! ) { updateUserInfos( firstName: $firstName @@ -44,6 +48,10 @@ export const updateUserInfos = gql` language: $locale hideAmountGDD: $hideAmountGDD hideAmountGDT: $hideAmountGDT + gmsAllowed: $gmsAllowed + gmsPublishName: $gmsPublishName + gmsLocation: $gmsLocation + gmsPublishLocation: $gmsPublishLocation ) } `