Commit Graph

136 Commits

Author SHA1 Message Date
78d8df6a68 Add workspace favorites behind feature flag (#6904)
- make member nullable on favorites
- add potential relation with view entity
- add a new type of favorite list in front : workspace favorite
- build a new component for retrieving workspace favorite to display +
refacto the existing one

Bonus:
- removing activities seed since this is deprecated
2024-09-05 16:41:06 +02:00
7e03419c16 Serverless function improvements (#6769)
- add layer for lambda execution
- add layer for local execution
- add package resolve for the monaco editor
- add route to get installed package for serverless functions
- add layer versioning
2024-09-02 15:25:20 +02:00
96d659cf56 Make custom objects soft deletable by default (#6768)
Fixes #6766
2024-08-31 18:02:41 +02:00
cd06ae20e8 chore(*): remove unused code (#6781)
The code removed in the PR was flagged as unused by the JetBrains
inspector.

I did a QA on the dev environment but other checks are highly
recommended.

There is one commit by scope to make the review easier.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-08-29 18:16:50 +02:00
7a9a43b85c Add composite Emails field and forbid creation of Email field type (#6689)
### Description

1. 
   - We are introducing new field type(Emails)


   - We are Forbiding creation of Email field


   - We Added support for filtering and sorting on Emails field


- We are using the same display mode as used on the Links field type
(chips), check the Domain field of the Company object


   - We are also using the same logic of the link when editing the field

   \
   How To Test\
   Follow the below steps for testing locally:\
   1. Checkout to TWENTY-6261\
2. Reset database using "npx nx database:reset twenty-server" command\
   3. Run both the backend and frontend app\
4. Go to Settings/Data model and choose one of the standard objects like
people\
   5. Click on Add Field button and choose Emails as the field type

   \
   ### Refs

   #6261\
   \
   ### Demo

    \

<https://www.loom.com/share/22979acac8134ed390fef93cc56fe07c?sid=adafba94-840d-4f01-872c-dc9ec256d987>

Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com>
2024-08-29 11:42:24 +02:00
c87ccfa3c7 refactor graphql query runner connection mapper (#6771) 2024-08-28 19:02:45 +02:00
9f69383aa2 Add function execution throttler (#6742)
Add throttler service to limit the number of function execution
2024-08-27 18:56:47 +02:00
f6fd92adcb [POC] add graphql query runner (#6747)
## Context
The goal is to replace pg_graphql with our own ORM wrapper (TwentyORM).
This PR tries to add some parsing logic to convert graphql requests to
send to the ORM to replace pg_graphql implementation.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-08-27 17:06:39 +02:00
d61d5857f8 View becomes blank after deleting select (#6703)
This PR was created by [GitStart](https://gitstart.com/) to address the
requirements from this ticket:
[TWNTY-6027](https://clients.gitstart.com/twenty/5449/tickets/TWNTY-6027).
This ticket was imported from:
[TWNTY-6027](https://github.com/twentyhq/twenty/issues/6027)

 --- 

### Description

- Delete corresponding view simultaneously once select field is
deactivated instead of deleted because the bug happens on the
deactivation (one step before deleting), confirmation:
<https://discord.com/channels/1130383047699738754/1268662542172028971/1270367244509249651>
- Is still possible to create Kanban views with deactivated Select
fields, but this is not related to the PR.
- The changes on the frontend are for refreshing the data after the view
deletion

### Refs

#6027

### Demo


<https://www.loom.com/share/4f705344e3054cd5b3d5eadd398d2c9c?sid=8db3d8b9-4dce-4e31-8359-0e31cbc0e2e7>

Fixes #6027

---------

Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2024-08-27 11:10:32 +02:00
873a4c1bd1 Fix serverless save when name empty (#6720)
- fix serverless function error on save when name empty
- remove useless unique constraint on serverless function names
2024-08-23 17:34:31 +02:00
ee6180a76f [Fix] Prevent fields name conflicts with composite subfields names (#6713)
At field creation we are checking the availability of the name by
comparing it to the other fields' names' on the object; but for
composite fields the fields' names' as indicated in the repository do
not exactly match the column names' on the tables (e.g "createdBy" field
is actually represented by columns createdByName, createdBySource etc.).

In this PR we prevent the conflict with the standard composite fields'
names.
There is still room for errors with the custom composite fields: for
example a custom composite field "address" of type address on a custom
object "listing" will introduce the columns addressAddressStreet1,
addressAddressStreet2 etc. while we won't prevent the user from later
creating a custom field named "addressAddressStreet1".
For now I decided not to tackle this as this seem extremely edgy + would
impact performance on creation of all fields while never actually useful
(I think).
2024-08-23 13:24:10 +02:00
6f9aa1e870 6654 serverless functions add a deploy button disable deploy when autosave (#6715)
- improvements on serverless function behavior (autosave performances,
deploy on execution only)
- add versioning to serverless functions
- add a publish endpoint to create a new version of a serverless
function
  - add deploy and reset to lastVersion button in the settings section:
<img width="736" alt="image"
src="https://github.com/user-attachments/assets/2001f8d2-07a4-4f79-84dd-ec74b6f301d3">
2024-08-23 12:06:03 +02:00
663acd56e4 Trigger workflow run manually (#6696)
Fix https://github.com/twentyhq/twenty/issues/6669

- create a commun function `startWorkflowRun` that both create the run
object and the job for executing the workflow
- use it in both the `workflowEventJob` and the `runWorkflowVersion`
endpoint

Bonus:
- use filtering for exceptions instead of a util. It avoids doing a try
catch in all endpoint
2024-08-21 17:41:26 +02:00
aa4ae53fb4 [Fix] field does not appear directly after creation (#6708) 2024-08-21 12:08:57 +02:00
6caa78008f If an object is disabled, then the relationships to that object should be disabled (#6690)
This PR was created by [GitStart](https://gitstart.com/) to address the
requirements from this ticket:
[TWNTY-5370](https://clients.gitstart.com/twenty/5449/tickets/TWNTY-5370).
This ticket was imported from:
[TWNTY-5370](https://github.com/twentyhq/twenty/issues/5370)

 --- 


### Description

- We updated the logic in
packages/twenty-server/src/engine/metadata-modules/object-metadata/object-metadata.service.ts
  
  Test cases:
1. Ensure that when an object is disabled, all related relationships are
also disabled.
         a. Example disable the people object
b. Check the company object and verify that the people field has been
disabled too
c. Check the opportunity object and check that the point of contact
field has been disabled too
2. Verify that when a previously disabled object is restored, the
relationships are also restored.
3. Ensure that previously disabled relationships remain disabled when
the object is disabled and later restored.
4. Verify that relationships of a disabled object are not visible in the
UI.
5. Ensure that relationships to a disabled object are marked as inactive
in the data models screen

 ### Refs

#5370

  
### Demo
  

<https://www.loom.com/share/2b0a91f463ca4e02a6963f9a8796a0d9?sid=1e9c4fb8-8fb9-4c6c-b43a-c50f3776e1d3>

Fixes #5370

---------

Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com>
Co-authored-by: Marie Stoppa <marie.stoppa@essec.edu>
2024-08-21 11:19:21 +02:00
08e07ac2d5 Update graphql-yoga patch in yarn.lock 2024-08-21 00:39:55 +02:00
17a1760afd Improve performance twenty orm (#6691)
## Context

As we grow, the messaging scripts are experiencing performance issues
forcing us to temporarily disable them on the cloud.
While investigating the performance, I have noticed that generating the
entity schema (for twentyORM) in the repository is taking ~500ms locally
on my Mac M2 so likely more on pods. Caching the entitySchema then!

I'm also clarifying naming around schemaVersion and cacheVersions ==>
both are renamed workspaceMetadataVersion and migrated to the workspace
table (the workspaceCacheVersion table is dropped).
2024-08-20 19:42:02 +02:00
db54469c8a feat: soft delete (#6576)
Implement soft delete on standards and custom objects.
This is a temporary solution, when we drop `pg_graphql` we should rely
on the `softDelete` functions of TypeORM.

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2024-08-16 21:20:02 +02:00
9e7714e627 Add workflow run entity (#6622)
- create a workflow run every time a workflow is triggered in
not_started status. This status will be helpful later for once workflows
will be scheduled
- update run status once workflow starts running
- complete status once the workflow finished running
- add a failed status if an error occurs
2024-08-14 18:27:32 +02:00
d5350e11a3 Remove some dead code (#6611)
We could remove a lot more than this, this is just a start.

There are various tools to help with this, knip is a good one
2024-08-11 20:43:18 +02:00
4157a67bf8 Fix permissions for serverless functions (#6555)
Fixes #6525

(@martmull fyi it was not related to AWS but linked to the fact that we
recently enforced passing a token to access files)
2024-08-06 15:31:22 +02:00
2b311b5f7b Update standard fields (#6532)
In this PR:
- adding Favorites to Tasks and Notes
- fixing inconsistencies between custom object creation and sync of
standard fields of custom objects
- fixing workspaceCacheVersion not used to invalidate existing
datasource
2024-08-04 23:22:41 +02:00
e787215e15 Add createdBy field on custom object creation (#6529)
In this PR, I'm:
- adding createdBy field (type ACTOR) on custom objects when created
- moving `name` and `position` default column to the set of columns
automatically creation on object creation
- fixing a bug on mutations (update / create), if the targetted object
has a 'data' custom field, it was conflicting with the payload ==> I
feel we need to refactor this part of the code but we can keep this for
a bit later as we plan to move out of pg_graphql

<img width="1198" alt="image"
src="https://github.com/user-attachments/assets/891c4a97-bab1-415c-8551-dabd5996a794">
2024-08-04 13:12:24 +02:00
6e0c1b4c73 Fallback to default value when migrating value from enum (#6517)
When migrating the option values of a select type, if the field is non
nullable (for now, only available for opportunity's "stage" standard
field), we fallback to the (potentially updated) default value instead
of nullifying the value to avoid getting a database error.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-08-03 17:53:01 +02:00
6432ad39b9 feat: add new ACTOR field type and createdBy standard fields (#6324)
This pull request introduces a new `FieldMetadataType` called `ACTOR`.
The primary objective of this new type is to add an extra column to the
following objects: `person`, `company`, `opportunity`, `note`, `task`,
and all custom objects.

This composite type contains three properties:

- `source`
    ```typescript
    export enum FieldActorSource {
      EMAIL = 'EMAIL',
      CALENDAR = 'CALENDAR',
      API = 'API',
      IMPORT = 'IMPORT',
      MANUAL = 'MANUAL',
    }
    ```
- `workspaceMemberId`
- This property can be `undefined` in some cases and refers to the
member who created the record.
- `name`
- Serves as a fallback if the `workspaceMember` is deleted and is used
for other source types like `API`.

### Functionality

The pre-hook system has been updated to allow real-time argument
updates. When a record is created, a pre-hook can now compute and update
the arguments accordingly. This enhancement enables the `createdBy`
field to be populated with the correct values based on the
`authContext`.

The `authContext` now includes:
- An optional User entity
- An optional ApiKey entity
- The workspace entity

This provides access to the necessary data for the `createdBy` field.

In the GraphQL API, only the `source` can be specified in the
`createdBy` input. This allows the front-end to specify the source when
creating records from a CSV file.

### Front-End Handling

On the front-end, `orderBy` and `filter` are only applied to the name
property of the `ACTOR` composite type. Currently, we are unable to
apply these operations to the workspace member relation. This means that
if a workspace member changes their first name or last name, there may
be a mismatch because the name will differ from the new one. The name
displayed on the screen is based on the workspace member entity when
available.

### Missing Components

Currently, this PR does not include a `createdBy` value for the `MAIL`
and `CALENDAR` sources. These records are created in a job, and at
present, we only have access to the workspaceId within the job. To
address this, we should use a function similar to
`loadServiceWithContext`, which was recently removed from `TwentyORM`.
This function would allow us to pass the `authContext` to the jobs
without disrupting existing jobs.
Another PR will be created to handle these cases.

### Related Issues

Fixes issue #5155.

### Additional Notes

This PR doesn't include the migrations of the current records and views.
Everything works properly when the database is reset but this part is
still missing for now. We'll add that in another PR.

- There is a minor issue: front-end tests are broken since this commit:
[80c0fc7ff1).

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
2024-08-03 15:43:31 +02:00
277c51d58e Add note and task target relation creation for customs (#6515)
As title

Urgent bug to fix, I will take the time to refacto this code next week

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2024-08-02 18:04:32 +02:00
80c0fc7ff1 Activity as standard object (#6219)
In this PR I layout the first steps to migrate Activity to a traditional
Standard objects

Since this is a big transition, I'd rather split it into several
deployments / PRs

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/012e2bbf-9d1b-4723-aaf6-269ef588b050">

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
Co-authored-by: bosiraphael <71827178+bosiraphael@users.noreply.github.com>
Co-authored-by: Weiko <corentin@twenty.com>
Co-authored-by: Faisal-imtiyaz123 <142205282+Faisal-imtiyaz123@users.noreply.github.com>
Co-authored-by: Prateek Jain <prateekj1171998@gmail.com>
2024-07-31 15:36:11 +02:00
6b4c79ff0d Add workflow runner (#6458)
- add workflow runner module
- add an endpoint to trigger a workflow via api
- improve error handling for serverless functions

## Testing
- create 2 serverless functions
- create a workflow
- create this workflow Version
```
{
  "type": "MANUAL",
  "input": {"b": "bb"},
  "nextAction": {
    "name": "step_1",
    "displayName": "Code",
    "type": "CODE",
    "valid": true,
    "settings": {
      "serverlessFunctionId": "Serverless function 1 Id",
      "errorHandlingOptions": {
        "retryOnFailure": {
          "value": false
        },
        "continueOnFailure": {
          "value": false
        }
      }
    },
    "nextAction": {
      "name": "step_1",
      "displayName": "Code",
      "type": "CODE",
      "valid": true,
      "settings": {
        "serverlessFunctionId": "Serverless function 1 Id",
        "errorHandlingOptions": {
          "retryOnFailure": {
            "value": false
          },
          "continueOnFailure": {
            "value": false
          }
        }
      },
      "nextAction": {
        "name": "step_1",
        "displayName": "Code",
        "type": "CODE",
        "valid": true,
        "settings": {
          "serverlessFunctionId": "Serverless function 2 Id",
          "errorHandlingOptions": {
            "retryOnFailure": {
              "value": false
            },
            "continueOnFailure": {
              "value": false
            }
          }
        }
      }
    }
  }
}

`
``
- call 
```
mutation Trigger {
  triggerWorkflow(workflowVersionId: "WORKFLOW_VERSION_ID") {
    result
  }
}
```
- try when errors are injected in serverless function
2024-07-31 12:48:33 +02:00
b85ae7e1ac Fix googleApisSetRequestExtraParams (#6455) 2024-07-30 16:08:59 +02:00
fb0fd99a38 Fix error handling in serverless service (#6442)
- narrowing error handling in aws sdk usage
- updating dto to authorize null descriptions
2024-07-29 18:51:57 +02:00
00fea17920 Serverless function UI (#6388)
https://www.figma.com/design/xt8O9mFeLl46C5InWwoMrN/Twenty?node-id=36235-120877

Did not do the file manager part. A Function is defined using one unique
file at the moment

Feature protected by featureFlag `IS_FUNCTION_SETTINGS_ENABLED`

## Demo


https://github.com/user-attachments/assets/0acb8291-47b4-4521-a6fa-a88b9198609b
2024-07-29 13:03:09 +02:00
368f142f3a Delete cache version on reset db (#6426)
As title
2024-07-27 11:54:03 +02:00
4cb83e050f Put workfows behind a feature flag (#6417)
We have recently merged
[#workflow](https://github.com/twentyhq/twenty/pull/6412) but we should
put the workflow standard object behind a feature flag for now

---------

Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
2024-07-25 20:33:31 +02:00
8d33264a7d Migrate fields of deprecated type LINK to type LINKS (#6332)
Closes #5909.

Adding a command to migrate fields of type Link to fields of type Links,
including their data.
2024-07-23 09:57:30 +02:00
a374922902 Cannot delete label identifier associated field (#6340)
## Context
An object should always have a labelIdentifier (would be its primary key
at least). If the associated field is deleted by a user, it will break
the app. Ideally we should handle that on the DB level but we don't have
a FK for this column yet.
In the meantime I'm adding the validation check in the backend, note
that this is already handle on the FE side since the "archive/delete"
buttons don't appear for such fields so you need to reassign it to
another field first which is the desired behaviour.
2024-07-19 15:57:40 +02:00
67e2d5c73a Add label identifier to object decorator (#6227)
## Context
LabelIdentifier and ImageIdentifier are metadata info attached to
objectMetadata that are used to display a record in a more readable way.
Those columns point to existing fields that are part of the object.
For example, for a relation picker of a person, we will show a record
using the "name" labelIdentifier and the "avatarUrl" imageIdentifier.
<img width="215" alt="Screenshot 2024-07-11 at 18 45 51"
src="https://github.com/twentyhq/twenty/assets/1834158/488f8294-0d7c-4209-b763-2499716ef29d">

Currently, the FE has a specific logic for company and people objects
and we have a way to update this value via the API for custom objects,
but the code is not flexible enough to change other standard objects.

This PR updates the WorkspaceEntity API so we can now provide the
labelIdentifier and imageIdentifier in the WorkspaceEntity decorator.

Example:
```typescript
@WorkspaceEntity({
  standardId: STANDARD_OBJECT_IDS.activity,
  namePlural: 'activities',
  labelSingular: 'Activity',
  labelPlural: 'Activities',
  description: 'An activity',
  icon: 'IconCheckbox',
  labelIdentifierStandardId: ACTIVITY_STANDARD_FIELD_IDS.title,
})
@WorkspaceIsSystem()
export class ActivityWorkspaceEntity extends BaseWorkspaceEntity {
  @WorkspaceField({
    standardId: ACTIVITY_STANDARD_FIELD_IDS.title,
    type: FieldMetadataType.TEXT,
    label: 'Title',
    description: 'Activity title',
    icon: 'IconNotes',
  })
  title: string;
...
```
2024-07-19 14:24:04 +02:00
a4e82d643a Support custom composite field deletion (#6320)
as per title
Fixes #6033 and closes #4841
2024-07-18 15:28:32 +02:00
47ddc7be83 6181 workflows create a custom code executor (#6235)
Closes #6181

## Testing
- download Altair graphql dev tool https://altairgraphql.dev/#download
- create a file locally `test.ts` containing:
```
export const handler = async (event: object, context: object) => {
  return { test: 'toto', data: event['data'] };
}
```
- play those requests in Altair:
mutation UpsertFunction($file: Upload!) {
  upsertFunction(name: "toto", file: $file)
}

mutation ExecFunction {
  executeFunction(name:"toto", payload: {data: "titi"})
}
- it will run the local driver, add those env variable to test with
lambda driver
```
CUSTOM_CODE_ENGINE_DRIVER_TYPE=lambda
LAMBDA_REGION=eu-west-2
LAMBDA_ROLE=<ASK_ME>
```
2024-07-17 17:53:01 +02:00
34cbba5fd8 Add interceptors for auto-resolvers (#6270)
Services exceptions are not catch when the endpoint comes from an
auto-resolver.
We want to remove auto-resolver but it requires to implement pagination
by ourselves.

As a quick fix, here are interceptors that will trigger the exception
handler.
I had a hard time making it generic so I finally added one interceptor
for each since this is not supposed to stay
2024-07-16 10:49:18 +02:00
364caf0fdf fix: remove usage of probability field (#5877)
- fixes #5735

---------

Co-authored-by: Marie Stoppa <marie.stoppa@essec.edu>
2024-07-16 10:24:35 +02:00
aed0bf41ce Forbid default value nullification for non-nullable field (#6258)
as per title 


https://github.com/user-attachments/assets/ce07d437-eeeb-488c-8dfa-3fc07316f485
2024-07-15 14:22:15 +02:00
1dff5bf957 Fix custom errors thrown as 500 (#6238)
We call convertExceptionToGraphQLError in the exception handler for http
exceptions but we don't take into account those that already are
graphqlErrors and because of that the logic of convertExceptionToGraphql
is to fallback to a 500.
Now if the exception is a BaseGraphqlError (custom graphql error we
throw in the code), we throw them directly.

BEFORE
<img width="957" alt="Screenshot 2024-07-12 at 15 33 03"
src="https://github.com/user-attachments/assets/22ddae13-4996-4ad3-8f86-dd17c2922ca8">


AFTER
<img width="923" alt="Screenshot 2024-07-12 at 15 32 01"
src="https://github.com/user-attachments/assets/d3d6db93-6d28-495c-a4b4-ba4e47d45abd">

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-07-12 17:56:21 +02:00
a44249287f Forbid creation of link field type (#6237)
This is the first step of Link field type deprecation
(https://github.com/twentyhq/twenty/issues/5909).
Forbid creation of link field type in product and api. Update to this
type is not a concern as we do not allow the update of field type.
2024-07-12 15:28:17 +02:00
6af1bcd55c [Flexible Schema] Create indexes for join columns (#6165)
## Context
We want to add an index on our foreign keys since PG does not do it for
us. An index can sometimes be expensive and not always meaningful
depending on different usages but in our case we decided to apply an
index for every foreign keys.

```typescript
  @WorkspaceIndex()
  @WorkspaceJoinColumn('author')
  authorId: string;
```
This syntax is valid but since we want to apply it to every join column
I've decided to update the code of WorkspaceJoinColumn so it properly
registers a new index at the same time which is less error-prone.

Note: We had a bug on index name generation since postgres index names
are unique per schema and not table, the object metadata id (hashed) has
been added to the formula that generates the name of the index

## Test
Sync metadata. We have 45 join columns as of today per workspace, we
should see 45 rows inside IndexMetadata table
2024-07-09 14:51:24 +02:00
6cd154aac6 Forbid names above 63 characters to comply with pg identifier limit (#6095)
Fixes #6032.

Pg has a char limit on identifiers (= table, columns, enum names) of 63
bytes.
Let's limit the metadata names that will be converted to identifiers
(objects names, fields names, relation names, enum values) to 63 chars.
For the sake of simplicity in the FE we will limit the input length of
labels.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-07-04 15:32:42 +02:00
4c642a0bb8 Text-to-SQL proof of concept (#5788)
Added:
- An "Ask AI" command to the command menu.
- A simple GraphQL resolver that converts the user's question into a
relevant SQL query using an LLM, runs the query, and returns the result.

<img width="428" alt="Screenshot 2024-06-09 at 20 53 09"
src="https://github.com/twentyhq/twenty/assets/171685816/57127f37-d4a6-498d-b253-733ffa0d209f">

No security concerns have been addressed, this is only a
proof-of-concept and not intended to be enabled in production.

All changes are behind a feature flag called `IS_ASK_AI_ENABLED`.

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2024-07-04 08:57:26 +02:00
4183e5460d Use return await to catch exceptions (#6109)
So the exceptions are handled properly and filtered in sentry
2024-07-03 11:14:28 +02:00
bb627a91e2 Use invalid field input error for invalid object metadata input (#6083)
As title
2024-07-01 16:33:48 +02:00
a15884ea0a Add exceptions for metadata modules (#6070)
Class exception for each metadata module + handler to map on graphql
error

TODO left :
- find a way to call handler on auto-resolvers nestjs query (probably
interceptors)
- discuss what should be done for pre-hooks errors
- discuss what should be done for Unauthorized exception
2024-07-01 13:49:17 +02:00
f8c057deea Fix sign up broken because of missing workspace schema (#6013)
Allow workspace datasource factory to return null if the workspace
schema has not been created yet
2024-06-25 10:59:07 +02:00