mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 01:46:07 +00:00
implement coordinates for community
This commit is contained in:
parent
ab393f3428
commit
b3fab60970
@ -113,7 +113,7 @@
|
||||
{{ $t('contributionLink.clear') }}
|
||||
</b-button>
|
||||
<b-button @click.prevent="$emit('closeContributionForm')">
|
||||
{{ $t('contributionLink.close') }}
|
||||
{{ $t('close') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</b-form>
|
||||
|
||||
@ -25,12 +25,24 @@
|
||||
{{ $t('federation.publicKey') }} {{ item.publicKey }}
|
||||
</b-list-group-item>
|
||||
<b-list-group-item v-if="!item.foreign">
|
||||
{{ $t('federation.gmsApiKey') }}
|
||||
<editable-label
|
||||
:value="gmsApiKey"
|
||||
<editable-group
|
||||
:allowEdit="$store.state.moderator.roles.includes('ADMIN')"
|
||||
@save="handleSaveGsmApiKey"
|
||||
/>
|
||||
@save="handleUpdateHomeCommunity"
|
||||
@reset="resetHomeCommunityEditable"
|
||||
>
|
||||
<template #view>
|
||||
<label>{{ $t('federation.gmsApiKey') }} {{ item.gmsApiKey }}</label>
|
||||
<b-form-group>
|
||||
{{ $t('federation.coordinates') }} {{ item.location.coordinates[1] }} {{
|
||||
item.location.coordinates[0]
|
||||
}}
|
||||
</b-form-group>
|
||||
</template>
|
||||
<template #edit>
|
||||
<g-m-s-api-key v-model="gmsApiKey" />
|
||||
<coordinates v-model="location" />
|
||||
</template>
|
||||
</editable-group>
|
||||
</b-list-group-item>
|
||||
<b-list-group-item>
|
||||
<b-list-group>
|
||||
@ -59,17 +71,21 @@
|
||||
<script>
|
||||
import { formatDistanceToNow } from 'date-fns'
|
||||
import { de, enUS as en, fr, es, nl } from 'date-fns/locale'
|
||||
import EditableLabel from '@/components/input/EditableLabel'
|
||||
import EditableGroup from '@/components/input/EditableGroup'
|
||||
import FederationVisualizeItem from './FederationVisualizeItem.vue'
|
||||
import { updateHomeCommunity } from '../../graphql/updateHomeCommunity'
|
||||
import Coordinates from '../input/Coordinates.vue'
|
||||
import GMSApiKey from './GMSApiKey.vue'
|
||||
|
||||
const locales = { en, de, es, fr, nl }
|
||||
|
||||
export default {
|
||||
name: 'CommunityVisualizeItem',
|
||||
components: {
|
||||
EditableLabel,
|
||||
Coordinates,
|
||||
EditableGroup,
|
||||
FederationVisualizeItem,
|
||||
GMSApiKey,
|
||||
},
|
||||
props: {
|
||||
item: { type: Object },
|
||||
@ -80,10 +96,14 @@ export default {
|
||||
locale: this.$i18n.locale,
|
||||
details: false,
|
||||
gmsApiKey: '',
|
||||
location: () => ({
|
||||
type: 'Point',
|
||||
coordinates: [],
|
||||
}),
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.gmsApiKey = this.item.gmsApiKey
|
||||
this.resetHomeCommunityEditable()
|
||||
},
|
||||
computed: {
|
||||
verified() {
|
||||
@ -138,14 +158,14 @@ export default {
|
||||
toggleDetails() {
|
||||
this.details = !this.details
|
||||
},
|
||||
handleSaveGsmApiKey(gmsApiKey) {
|
||||
this.gmsApiKey = gmsApiKey
|
||||
handleUpdateHomeCommunity() {
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: updateHomeCommunity,
|
||||
variables: {
|
||||
uuid: this.item.uuid,
|
||||
gmsApiKey: gmsApiKey,
|
||||
gmsApiKey: this.gmsApiKey,
|
||||
location: this.location,
|
||||
},
|
||||
})
|
||||
.then(() => {
|
||||
@ -155,6 +175,10 @@ export default {
|
||||
this.toastError(error.message)
|
||||
})
|
||||
},
|
||||
resetHomeCommunityEditable() {
|
||||
this.gmsApiKey = this.item.gmsApiKey
|
||||
this.location = this.item.location
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
33
admin/src/components/Federation/GMSApiKey.vue
Normal file
33
admin/src/components/Federation/GMSApiKey.vue
Normal file
@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<b-form-group :label="$t('federation.gmsApiKey')" label-for="home-community-api-key">
|
||||
<b-form-input id="home-community-api-key" v-model="inputValue" @input="updateValue" />
|
||||
</b-form-group>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
// Code written from chatGPT 3.5
|
||||
name: 'GMSApiKey',
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
inputValue: this.value,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateValue(value) {
|
||||
this.inputValue = value
|
||||
if (this.$parent.valueChanged) {
|
||||
this.$parent.valueChanged()
|
||||
}
|
||||
this.$emit('input', this.inputValue)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
90
admin/src/components/input/Coordinates.vue
Normal file
90
admin/src/components/input/Coordinates.vue
Normal file
@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<div>
|
||||
<b-form-group
|
||||
:label="$t('geo-coordinates.label')"
|
||||
:invalid-feedback="$t('geo-coordinates.both-or-none')"
|
||||
:state="isValid"
|
||||
>
|
||||
<b-form-group
|
||||
:label="$t('latitude')"
|
||||
label-for="home-community-latitude"
|
||||
:description="$t('geo-coordinates.latitude.describe')"
|
||||
>
|
||||
<b-form-input
|
||||
v-model="inputValue.coordinates[1]"
|
||||
id="home-community-latitude"
|
||||
type="text"
|
||||
@input="splitCoordinates"
|
||||
/>
|
||||
</b-form-group>
|
||||
<b-form-group :label="$t('longitude')" label-for="home-community-longitude">
|
||||
<b-form-input
|
||||
v-model="inputValue.coordinates[0]"
|
||||
id="home-community-longitude"
|
||||
type="text"
|
||||
@input="valueUpdated"
|
||||
/>
|
||||
</b-form-group>
|
||||
</b-form-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
value: Object,
|
||||
default: () => ({
|
||||
type: 'Point',
|
||||
coordinates: [],
|
||||
}),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
inputValue: this.value,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
console.log("created value: %o, inputValue: %o", this.value, this.inputValue)
|
||||
},
|
||||
computed: {
|
||||
isValid() {
|
||||
return this.inputValue.coordinates.length === 0 || this.inputValue.coordinates.length === 2
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
splitCoordinates(value) {
|
||||
// format from google maps 'longitude, latitude'
|
||||
const parts = value.split(',').map((part) => part.trim())
|
||||
|
||||
if (parts.length === 2) {
|
||||
const [lat, lon] = parts
|
||||
// format in geojson Point: coordinates[longitude, latitude]
|
||||
if (!isNaN(parseFloat(lon) && !isNaN(parseFloat(lat)))) {
|
||||
this.inputValue.coordinates[0] = parseFloat(lon)
|
||||
this.inputValue.coordinates[1] = parseFloat(lat)
|
||||
}
|
||||
}
|
||||
this.valueUpdated()
|
||||
},
|
||||
valueUpdated() {
|
||||
// make sure all coordinates are numbers
|
||||
this.inputValue.coordinates = this.inputValue.coordinates
|
||||
.map((coord) => parseFloat(coord))
|
||||
// Remove null and NaN values
|
||||
.filter((coord) => coord !== null && !isNaN(coord))
|
||||
|
||||
if (this.isValid) {
|
||||
if (this.$parent.valueChanged) {
|
||||
this.$parent.valueChanged()
|
||||
}
|
||||
} else {
|
||||
if (this.$parent.invalidValues) {
|
||||
this.$parent.invalidValues();
|
||||
}
|
||||
}
|
||||
|
||||
this.$emit('input', this.inputValue)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
61
admin/src/components/input/EditableGroup.vue
Normal file
61
admin/src/components/input/EditableGroup.vue
Normal file
@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<div>
|
||||
<slot v-if="!isEditing" v-bind:isEditing="isEditing" name="view"></slot>
|
||||
<slot v-else v-bind:isEditing="isEditing" name="edit" @input="valueChanged"></slot>
|
||||
<b-form-group v-if="allowEdit && !isEditing">
|
||||
<b-button @click="enableEdit" :variant="variant">
|
||||
<b-icon icon="pencil-fill">{{ $t('edit') }}</b-icon>
|
||||
</b-button>
|
||||
</b-form-group>
|
||||
<b-form-group v-else-if="allowEdit && isEditing">
|
||||
<b-button @click="save" :variant="variant" :disabled="!isValueChanged">
|
||||
{{ $t('save') }}
|
||||
</b-button>
|
||||
<b-button @click="close" variant="secondary">
|
||||
{{ $t('close') }}
|
||||
</b-button>
|
||||
</b-form-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'EditableGroup',
|
||||
props: {
|
||||
allowEdit: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isEditing: false,
|
||||
isValueChanged: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
variant() {
|
||||
return this.isEditing ? 'success' : 'prime'
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
enableEdit() {
|
||||
this.isEditing = true
|
||||
},
|
||||
valueChanged() {
|
||||
this.isValueChanged = true
|
||||
},
|
||||
invalidValues() {
|
||||
this.isValueChanged = false
|
||||
},
|
||||
save() {
|
||||
this.$emit('save')
|
||||
this.isEditing = false
|
||||
},
|
||||
close() {
|
||||
this.$emit('reset')
|
||||
this.isEditing = false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@ -11,6 +11,7 @@ export const allCommunities = gql`
|
||||
name
|
||||
description
|
||||
gmsApiKey
|
||||
location
|
||||
creationDate
|
||||
createdAt
|
||||
updatedAt
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const updateHomeCommunity = gql`
|
||||
mutation ($uuid: String!, $gmsApiKey: String!) {
|
||||
updateHomeCommunity(uuid: $uuid, gmsApiKey: $gmsApiKey) {
|
||||
mutation ($uuid: String!, $gmsApiKey: String!, $location: Point!) {
|
||||
updateHomeCommunity(uuid: $uuid, gmsApiKey: $gmsApiKey, location: $location) {
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
{
|
||||
"GDD": "GDD",
|
||||
"all_emails": "Alle Nutzer",
|
||||
"edit": "bearbeiten",
|
||||
"back": "zurück",
|
||||
"change_user_role": "Nutzerrolle ändern",
|
||||
"chat": "Chat",
|
||||
"close": "Schließen",
|
||||
"contributionLink": {
|
||||
"amount": "Betrag",
|
||||
"changeSaved": "Änderungen gespeichert",
|
||||
"clear": "Löschen",
|
||||
"close": "Schließen",
|
||||
"contributionLinks": "Beitragslinks",
|
||||
"create": "Anlegen",
|
||||
"cycle": "Zyklus",
|
||||
@ -76,6 +77,7 @@
|
||||
"apiVersion": "API Version",
|
||||
"authenticatedAt": "Verifiziert am:",
|
||||
"communityUuid": "Community UUID:",
|
||||
"coordinates": "Koordinaten:",
|
||||
"createdAt": "Erstellt am",
|
||||
"gmsApiKey": "GMS API Key:",
|
||||
"toast_gmsApiKeyUpdated": "Der GMS Api Key wurde erfolgreich aktualisiert!",
|
||||
@ -100,6 +102,13 @@
|
||||
"form": {
|
||||
"cancel": "Abbrechen"
|
||||
},
|
||||
"geo-coordinates": {
|
||||
"both-or-none": "Bitte beide oder keine eingeben!",
|
||||
"label": "Geo-Koordinaten",
|
||||
"latitude": {
|
||||
"describe": "Teilt Koordinaten im Format 'Längengrad, Breitengrad' automatisch in separate Eingabefelder auf. Fügen sie hier einfach z.B. ihre Koordinaten von Google Maps, zum Beispiel: 49.28187664243721, 9.740672183943639, ein."
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
"help": "Hilfe",
|
||||
"transactionlist": {
|
||||
@ -113,6 +122,8 @@
|
||||
"hide_resubmission": "Wiedervorlage verbergen",
|
||||
"hide_resubmission_tooltip": "Verbirgt alle Schöpfungen für die ein Moderator ein Erinnerungsdatum festgelegt hat.",
|
||||
"lastname": "Nachname",
|
||||
"latitude": "Breitengrad:",
|
||||
"longitude": "Längengrad:",
|
||||
"math": {
|
||||
"equals": "=",
|
||||
"pipe": "|",
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
{
|
||||
"GDD": "GDD",
|
||||
"all_emails": "All users",
|
||||
"edit": "edit",
|
||||
"back": "back",
|
||||
"change_user_role": "Change user role",
|
||||
"chat": "Chat",
|
||||
"close": "Close",
|
||||
"contributionLink": {
|
||||
"amount": "Amount",
|
||||
"changeSaved": "Changes saved",
|
||||
"clear": "Clear",
|
||||
"close": "Close",
|
||||
"contributionLinks": "Contribution Links",
|
||||
"create": "Create",
|
||||
"cycle": "Cycle",
|
||||
@ -76,6 +77,7 @@
|
||||
"apiVersion": "API Version",
|
||||
"authenticatedAt": "verified at:",
|
||||
"communityUuid": "Community UUID:",
|
||||
"coordinates": "Coordinates:",
|
||||
"createdAt": "Created At ",
|
||||
"gmsApiKey": "GMS API Key:",
|
||||
"toast_gmsApiKeyUpdated": "The GMS Api Key has been successfully updated!",
|
||||
@ -100,6 +102,13 @@
|
||||
"form": {
|
||||
"cancel": "Cancel"
|
||||
},
|
||||
"geo-coordinates": {
|
||||
"both-or-none": "Please enter both or none!",
|
||||
"label": "geo-coordinates",
|
||||
"latitude": {
|
||||
"describe": "Automatically splits coordinates in the format 'longitude, latitude' into separate input fields. Simply enter your coordinates from Google Maps here, for example: 49.28187664243721, 9.740672183943639."
|
||||
}
|
||||
},
|
||||
"help": {
|
||||
"help": "Help",
|
||||
"transactionlist": {
|
||||
@ -113,6 +122,8 @@
|
||||
"hide_resubmission": "Hide resubmission",
|
||||
"hide_resubmission_tooltip": "Hides all creations for which a moderator has set a reminder date.",
|
||||
"lastname": "Lastname",
|
||||
"latitude": "Breitengrad:",
|
||||
"longitude": "Längengrad:",
|
||||
"math": {
|
||||
"equals": "=",
|
||||
"pipe": "|",
|
||||
|
||||
@ -33,9 +33,11 @@
|
||||
"email-templates": "^10.0.1",
|
||||
"express": "^4.17.1",
|
||||
"express-slow-down": "^2.0.1",
|
||||
"geojson": "^0.5.0",
|
||||
"gradido-database": "file:../database",
|
||||
"graphql": "^15.5.1",
|
||||
"graphql-request": "5.0.0",
|
||||
"graphql-type-json": "0.3.2",
|
||||
"helmet": "^5.1.1",
|
||||
"i18n": "^0.15.1",
|
||||
"jose": "^4.14.4",
|
||||
@ -56,6 +58,7 @@
|
||||
"@types/email-templates": "^10.0.1",
|
||||
"@types/express": "^4.17.12",
|
||||
"@types/faker": "^5.5.9",
|
||||
"@types/geojson": "^7946.0.13",
|
||||
"@types/i18n": "^0.13.4",
|
||||
"@types/jest": "^27.0.2",
|
||||
"@types/lodash.clonedeep": "^4.5.6",
|
||||
|
||||
@ -12,7 +12,7 @@ Decimal.set({
|
||||
})
|
||||
|
||||
const constants = {
|
||||
DB_VERSION: '0084-introduce_humhub_registration',
|
||||
DB_VERSION: '0085-add_community_location',
|
||||
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
|
||||
LOG4JS_CONFIG: 'log4js-config.json',
|
||||
// default log level on production should be info
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
import { IsString, IsUUID } from 'class-validator'
|
||||
import { ArgsType, Field, InputType } from 'type-graphql'
|
||||
|
||||
import { Point } from '@/graphql/model/Point'
|
||||
import { isValidPoint } from '@/graphql/validator/Point'
|
||||
|
||||
@ArgsType()
|
||||
@InputType()
|
||||
export class EditCommunityInput {
|
||||
@ -11,4 +14,8 @@ export class EditCommunityInput {
|
||||
@Field(() => String)
|
||||
@IsString()
|
||||
gmsApiKey: string
|
||||
|
||||
@Field(() => Point)
|
||||
@isValidPoint()
|
||||
location: Point
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCom
|
||||
import { ObjectType, Field } from 'type-graphql'
|
||||
|
||||
import { FederatedCommunity } from './FederatedCommunity'
|
||||
import { Point } from './Point'
|
||||
|
||||
@ObjectType()
|
||||
export class AdminCommunityView {
|
||||
@ -36,6 +37,7 @@ export class AdminCommunityView {
|
||||
this.uuid = dbCom.communityUuid
|
||||
this.authenticatedAt = dbCom.authenticatedAt
|
||||
this.gmsApiKey = dbCom.gmsApiKey
|
||||
this.location = dbCom.location ? dbCom.location as Point : new Point()
|
||||
}
|
||||
|
||||
@Field(() => Boolean)
|
||||
@ -62,6 +64,9 @@ export class AdminCommunityView {
|
||||
@Field(() => String, { nullable: true })
|
||||
gmsApiKey: string | null
|
||||
|
||||
@Field(() => Point)
|
||||
location: Point
|
||||
|
||||
@Field(() => Date, { nullable: true })
|
||||
creationDate: Date | null
|
||||
|
||||
|
||||
10
backend/src/graphql/model/Point.ts
Normal file
10
backend/src/graphql/model/Point.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Position, Point as geojsonPoint } from 'geojson'
|
||||
|
||||
export class Point implements geojsonPoint {
|
||||
constructor() {
|
||||
this.coordinates = []
|
||||
this.type = 'Point'
|
||||
}
|
||||
type: 'Point'
|
||||
coordinates: Position
|
||||
}
|
||||
@ -78,7 +78,9 @@ export class CommunityResolver {
|
||||
|
||||
@Authorized([RIGHTS.COMMUNITY_UPDATE])
|
||||
@Mutation(() => Community)
|
||||
async updateHomeCommunity(@Args() { uuid, gmsApiKey }: EditCommunityInput): Promise<Community> {
|
||||
async updateHomeCommunity(
|
||||
@Args() { uuid, gmsApiKey, location }: EditCommunityInput,
|
||||
): Promise<Community> {
|
||||
const homeCom = await getCommunityByUuid(uuid)
|
||||
if (!homeCom) {
|
||||
throw new LogError('HomeCommunity with uuid not found: ', uuid)
|
||||
@ -86,8 +88,9 @@ export class CommunityResolver {
|
||||
if (homeCom.foreign) {
|
||||
throw new LogError('Error: Only the HomeCommunity could be modified!')
|
||||
}
|
||||
if (homeCom.gmsApiKey !== gmsApiKey) {
|
||||
if (homeCom.gmsApiKey !== gmsApiKey || homeCom.location !== location) {
|
||||
homeCom.gmsApiKey = gmsApiKey
|
||||
homeCom.location = location
|
||||
await DbCommunity.save(homeCom)
|
||||
}
|
||||
return new Community(homeCom)
|
||||
|
||||
@ -1,23 +1,25 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
import { Point as DbPoint } from '@dbTools/typeorm'
|
||||
import { GraphQLScalarType, Kind } from 'graphql'
|
||||
import { Point } from '@/graphql/model/Point'
|
||||
|
||||
export const PointScalar = new GraphQLScalarType({
|
||||
name: 'Point',
|
||||
description:
|
||||
'The `Point` scalar type to represent longitude and latitude values of a geo location',
|
||||
|
||||
serialize(value: DbPoint) {
|
||||
serialize(value: Point) {
|
||||
// Check type of value
|
||||
if (value.type !== 'Point') {
|
||||
throw new Error(`PointScalar can only serialize Geometry type 'Point' values`)
|
||||
throw new Error(`PointScalar can only serialize Geometry type 'Point' values`, )
|
||||
}
|
||||
return value
|
||||
},
|
||||
|
||||
parseValue(value): DbPoint {
|
||||
const point = JSON.parse(value) as DbPoint
|
||||
return point
|
||||
parseValue(value): Point {
|
||||
if (value.type !== 'Point') {
|
||||
throw new Error(`PointScalar can only deserialize Geometry type 'Point' values`, )
|
||||
}
|
||||
return value as Point
|
||||
},
|
||||
|
||||
parseLiteral(ast) {
|
||||
@ -25,7 +27,7 @@ export const PointScalar = new GraphQLScalarType({
|
||||
throw new TypeError(`${String(ast)} is not a valid Geometry value.`)
|
||||
}
|
||||
|
||||
const point = JSON.parse(ast.value) as DbPoint
|
||||
const point = JSON.parse(ast.value) as Point
|
||||
return point
|
||||
},
|
||||
})
|
||||
|
||||
@ -7,8 +7,10 @@ import { buildSchema } from 'type-graphql'
|
||||
import { Location } from '@model/Location'
|
||||
|
||||
import { isAuthorized } from './directive/isAuthorized'
|
||||
import { Point } from './model/Point'
|
||||
import { DecimalScalar } from './scalar/Decimal'
|
||||
import { LocationScalar } from './scalar/Location'
|
||||
import { PointScalar } from './scalar/Point'
|
||||
|
||||
export const schema = async (): Promise<GraphQLSchema> => {
|
||||
return buildSchema({
|
||||
@ -17,6 +19,7 @@ export const schema = async (): Promise<GraphQLSchema> => {
|
||||
scalarsMap: [
|
||||
{ type: Decimal, scalar: DecimalScalar },
|
||||
{ type: Location, scalar: LocationScalar },
|
||||
{ type: Point, scalar: PointScalar },
|
||||
],
|
||||
validate: {
|
||||
validationError: { target: false },
|
||||
|
||||
29
backend/src/graphql/validator/Point.ts
Normal file
29
backend/src/graphql/validator/Point.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { registerDecorator, ValidationOptions, ValidationArguments } from 'class-validator'
|
||||
import { Point } from '@/graphql/model/Point'
|
||||
|
||||
export function isValidPoint(validationOptions?: ValidationOptions) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
return function (object: Object, propertyName: string) {
|
||||
registerDecorator({
|
||||
name: 'isValidPoint',
|
||||
target: object.constructor,
|
||||
propertyName,
|
||||
options: validationOptions,
|
||||
validator: {
|
||||
validate(value: Point) {
|
||||
if (value.type === 'Point') {
|
||||
if (value.coordinates.length === 2) {
|
||||
return value.coordinates.every((coord) => typeof coord === 'number')
|
||||
} else if(value.coordinates.length === 0) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
},
|
||||
defaultMessage(args: ValidationArguments) {
|
||||
return `${propertyName} must be a valid Point in geoJSON Format, ${args.property}`
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -994,6 +994,11 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/geojson@^7946.0.13":
|
||||
version "7946.0.14"
|
||||
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-7946.0.14.tgz#319b63ad6df705ee2a65a73ef042c8271e696613"
|
||||
integrity sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==
|
||||
|
||||
"@types/glob@^7.1.3":
|
||||
version "7.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.4.tgz#ea59e21d2ee5c517914cb4bc8e4153b99e566672"
|
||||
@ -3696,7 +3701,7 @@ graceful-fs@^4.1.6, graceful-fs@^4.2.0:
|
||||
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
|
||||
|
||||
"gradido-database@file:../database":
|
||||
version "2.2.1"
|
||||
version "2.3.1"
|
||||
dependencies:
|
||||
"@types/uuid" "^8.3.4"
|
||||
cross-env "^7.0.3"
|
||||
@ -3774,6 +3779,11 @@ graphql-tools@^4.0.8:
|
||||
iterall "^1.1.3"
|
||||
uuid "^3.1.0"
|
||||
|
||||
graphql-type-json@0.3.2:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/graphql-type-json/-/graphql-type-json-0.3.2.tgz#f53a851dbfe07bd1c8157d24150064baab41e115"
|
||||
integrity sha512-J+vjof74oMlCWXSvt0DOf2APEdZOCdubEvGDUAlqH//VBYcOYsGgRW7Xzorr44LvkjiuvecWc8fChxuZZbChtg==
|
||||
|
||||
graphql@^15.5.1:
|
||||
version "15.6.1"
|
||||
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.6.1.tgz#9125bdf057553525da251e19e96dab3d3855ddfc"
|
||||
|
||||
89
database/entity/0085-add_community_location/Community.ts
Normal file
89
database/entity/0085-add_community_location/Community.ts
Normal file
@ -0,0 +1,89 @@
|
||||
import {
|
||||
BaseEntity,
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
OneToMany,
|
||||
JoinColumn,
|
||||
Geometry,
|
||||
} from 'typeorm'
|
||||
import { FederatedCommunity } from '../FederatedCommunity'
|
||||
import { GeometryTransformer } from '../../src/typeorm/GeometryTransformer'
|
||||
import { User } from '../User'
|
||||
|
||||
@Entity('communities')
|
||||
export class Community extends BaseEntity {
|
||||
@PrimaryGeneratedColumn('increment', { unsigned: true })
|
||||
id: number
|
||||
|
||||
@Column({ name: 'foreign', type: 'bool', nullable: false, default: true })
|
||||
foreign: boolean
|
||||
|
||||
@Column({ name: 'url', length: 255, nullable: false })
|
||||
url: string
|
||||
|
||||
@Column({ name: 'public_key', type: 'binary', length: 32, nullable: false })
|
||||
publicKey: Buffer
|
||||
|
||||
@Column({ name: 'private_key', type: 'binary', length: 64, nullable: true })
|
||||
privateKey: Buffer | null
|
||||
|
||||
@Column({
|
||||
name: 'community_uuid',
|
||||
type: 'char',
|
||||
length: 36,
|
||||
nullable: true,
|
||||
collation: 'utf8mb4_unicode_ci',
|
||||
})
|
||||
communityUuid: string | null
|
||||
|
||||
@Column({ name: 'authenticated_at', type: 'datetime', nullable: true })
|
||||
authenticatedAt: Date | null
|
||||
|
||||
@Column({ name: 'name', type: 'varchar', length: 40, nullable: true })
|
||||
name: string | null
|
||||
|
||||
@Column({ name: 'description', type: 'varchar', length: 255, nullable: true })
|
||||
description: string | null
|
||||
|
||||
@CreateDateColumn({ name: 'creation_date', type: 'datetime', nullable: true })
|
||||
creationDate: Date | null
|
||||
|
||||
@Column({ name: 'gms_api_key', type: 'varchar', length: 512, nullable: true, default: null })
|
||||
gmsApiKey: string | null
|
||||
|
||||
@Column({
|
||||
name: 'location',
|
||||
type: 'geometry',
|
||||
default: null,
|
||||
nullable: true,
|
||||
transformer: GeometryTransformer,
|
||||
})
|
||||
location: Geometry | null
|
||||
|
||||
@CreateDateColumn({
|
||||
name: 'created_at',
|
||||
type: 'datetime',
|
||||
default: () => 'CURRENT_TIMESTAMP(3)',
|
||||
nullable: false,
|
||||
})
|
||||
createdAt: Date
|
||||
|
||||
@UpdateDateColumn({
|
||||
name: 'updated_at',
|
||||
type: 'datetime',
|
||||
onUpdate: 'CURRENT_TIMESTAMP(3)',
|
||||
nullable: true,
|
||||
})
|
||||
updatedAt: Date | null
|
||||
|
||||
@OneToMany(() => User, (user) => user.community)
|
||||
@JoinColumn({ name: 'community_uuid', referencedColumnName: 'communityUuid' })
|
||||
users: User[]
|
||||
|
||||
@OneToMany(() => FederatedCommunity, (federatedCommunity) => federatedCommunity.community)
|
||||
@JoinColumn({ name: 'public_key', referencedColumnName: 'publicKey' })
|
||||
federatedCommunities?: FederatedCommunity[]
|
||||
}
|
||||
@ -1 +1 @@
|
||||
export { Community } from './0083-join_community_federated_communities/Community'
|
||||
export { Community } from './0085-add_community_location/Community'
|
||||
|
||||
13
database/migrations/0085-add_community_location.ts
Normal file
13
database/migrations/0085-add_community_location.ts
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
await queryFn(
|
||||
'ALTER TABLE `communities` ADD COLUMN IF NOT EXISTS `location` geometry DEFAULT NULL NULL AFTER `gms_api_key`;',
|
||||
)
|
||||
}
|
||||
|
||||
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
await queryFn('ALTER TABLE `communities` DROP COLUMN IF EXISTS `location`;')
|
||||
}
|
||||
@ -4,7 +4,7 @@ import dotenv from 'dotenv'
|
||||
dotenv.config()
|
||||
|
||||
const constants = {
|
||||
DB_VERSION: '0084-introduce_humhub_registration',
|
||||
DB_VERSION: '0085-add_community_location',
|
||||
LOG4JS_CONFIG: 'log4js-config.json',
|
||||
// default log level on production should be info
|
||||
LOG_LEVEL: process.env.LOG_LEVEL ?? 'info',
|
||||
|
||||
@ -2260,6 +2260,11 @@ gensync@^1.0.0-beta.2:
|
||||
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
||||
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
|
||||
|
||||
geojson@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/geojson/-/geojson-0.5.0.tgz#3cd6c96399be65b56ee55596116fe9191ce701c0"
|
||||
integrity sha512-/Bx5lEn+qRF4TfQ5aLu6NH+UKtvIv7Lhc487y/c8BdludrCTpiWf9wyI0RTyqg49MFefIAvFDuEi5Dfd/zgNxQ==
|
||||
|
||||
get-caller-file@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
|
||||
@ -2389,18 +2394,20 @@ graceful-fs@^4.2.4:
|
||||
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
||||
|
||||
"gradido-database@file:../database":
|
||||
version "1.22.3"
|
||||
version "2.2.1"
|
||||
dependencies:
|
||||
"@types/uuid" "^8.3.4"
|
||||
cross-env "^7.0.3"
|
||||
crypto "^1.0.1"
|
||||
decimal.js-light "^2.5.1"
|
||||
dotenv "^10.0.0"
|
||||
geojson "^0.5.0"
|
||||
mysql2 "^2.3.0"
|
||||
reflect-metadata "^0.1.13"
|
||||
ts-mysql-migrate "^1.0.2"
|
||||
typeorm "^0.3.16"
|
||||
uuid "^8.3.2"
|
||||
wkx "^0.5.0"
|
||||
|
||||
grapheme-splitter@^1.0.4:
|
||||
version "1.0.4"
|
||||
@ -4888,6 +4895,13 @@ which@^2.0.1:
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
wkx@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/wkx/-/wkx-0.5.0.tgz#c6c37019acf40e517cc6b94657a25a3d4aa33e8c"
|
||||
integrity sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
word-wrap@^1.2.3, word-wrap@~1.2.3:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
await queryFn(`
|
||||
ALTER TABLE \`transactions\`
|
||||
RENAME COLUMN \`paring_transaction_id\` TO \`pairing_transaction_id\`,
|
||||
RENAME COLUMN \`paring_transaction_id\` TO \`pairing_transaction_id\`
|
||||
;
|
||||
`)
|
||||
}
|
||||
@ -9,7 +9,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
|
||||
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
|
||||
await queryFn(`
|
||||
ALTER TABLE \`transactions\`
|
||||
RENAME COLUMN \`pairing_transaction_id\` TO \`paring_transaction_id\`,
|
||||
RENAME COLUMN \`pairing_transaction_id\` TO \`paring_transaction_id\`
|
||||
;
|
||||
`)
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ Decimal.set({
|
||||
})
|
||||
|
||||
const constants = {
|
||||
DB_VERSION: '0084-introduce_humhub_registration',
|
||||
DB_VERSION: '0085-add_community_location',
|
||||
DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0
|
||||
LOG4JS_CONFIG: 'log4js-config.json',
|
||||
// default log level on production should be info
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user