neo4j graphql #auth only read if relationship property is x - neo4j

Inside #auth allow or where field, I would like to access the role of the user on PART_OF_TEAM to determine whether or not they should read/edit the posts.
As an example: a user connected to a team with the edge property "VIEWER" should only be able to read the posts inside the team, not edit them.
I am using neo4j graphql javascript plugin and I have these type definitions:
type Post #auth(
rules: [
{
operations: [READ]
allowUnauthenticated: true
allow: {
OR:[
{ visibility: PUBLIC },
{ users: { id: "$jwt.id"} }, # users reference the Post users field
{ inTeam: {users: {id: "$jwt.id"}}},
]
},
},
])
{
id: ID! #id
name: String!
"See Enum ANCHOR Visibility: PRIVATE or PUBLIC"
visibility: Visibility!
description: String
color: String!
inTeam: [Team!]! #relationship(type: "IN_TEAM", direction: OUT)
}
type User {
"generate unique id"
id: ID! #id
username: String
email: String!
password: String!
inTeams: [Team!]!
#relationship(
type: "PART_OF_TEAM"
properties: "PartOfTeam"
direction: OUT
)
}
type Team {
id: ID! #id
name: String!
users: [User!]!
#relationship(
type: "PART_OF_TEAM"
properties: "PartOfTeam"
direction: IN
)
}
interface PartOfTeam #relationshipProperties {
role: Role!
}
I already tried to search for an answer but only found this other question which was not answered:
neo4j #auth related to edge property

Related

How can I display multiple ResponseDTOs' schemas in Swagger/NestJS?

I have this route which can return one of these two different DTOs:
#Get()
#ApiQuery({ name: 'legacy', description: "'Y' to get houses legacy" })
async findAllHouses(
#Query('legacy') legacy: string,
): Promise<HousesDto[] | HousesLegacyDto[]> {
...
}
I want to display both of these ResponseDTOs in swagger.
I've tried this decorator:
#ApiOkResponse({
schema: { oneOf: refs(HousesDto, HousesLegacyDto) },
})
// OR
#ApiOkResponse({
schema: {
oneOf: [
{ $ref: getSchemaPath(HousesDto) },
{ $ref: getSchemaPath(HousesLegacyDto) },
],
},
})
with #ApiExtraModels() on top of DTO classes and #ApiProperty() on each properties.
But I still get empty objects in Swagger and I suppose it would not have even taken array types in consideration.
How can I display both of these schemas properly?
Seems to me like a lot of very obscure solutions have been posted here and there, so I will try to clarify what needs to be done.
You have two DTOs:
export class SomeStatusDto {
#ApiProperty({
description: 'Id',
example: 1,
})
#IsNumber()
id: number;
#ApiProperty({
description: 'Status',
example: 'in_progress',
})
#IsString()
status: string;
}
export class ErrorStatusDto {
#ApiProperty({
description: 'Id',
example: 1,
})
#IsNumber()
id: number;
#ApiProperty({
description: 'Error',
example: 'Some error string',
})
#IsString()
error: string;
}
Then you have your controller:
#UseGuards(AccountTypesGuard)
#ApiOperation({ summary: 'Get status of...' })
#Get('status')
#ApiExtraModels(SomeStatusDto, ErrorStatusDto)
#ApiOkResponse({
schema: { anyOf: refs(SomeStatusDto, ErrorStatusDto) },
})
async getPullStatus(
#Request() req,
#Param('id', ParseIntPipe) someId: number,
): Promise<SomeStatusDto | ErrorStatusDto> {
// check if someId belongs to user
const idBelongsToUser = await this.myService.validateSomeId(
req.user.id,
someId,
);
if (!idBelongsToUser) {
throw new ForbiddenException(
`SomeId does not belong to user (someId=${someId}, userId=${req.user.id})`,
);
}
const key = `status-${someId}`;
const response = await this.redisService.getByKey(key);
return response ? response : {};
}
Note the solution below. You need to reference the DTOs as #ApiExtraModels() and then you can add them as anyOf: refs(...) in your schema.
#ApiExtraModels(SomeStatusDto, ErrorStatusDto)
#ApiOkResponse({
schema: { anyOf: refs(SomeStatusDto, ErrorStatusDto) },
})
Hope this helps somebody :)
so I encountered a similar issue and this is how you could get the output shown in the image above.
Using the #ApiResponse decorator you could set the two responses using the examples property, try the code sample below
#ApiResponse({
status: 200,
description: 'Successful response',
content: {
'application/json': {
examples: {
HousesDto: { value: HousesDto },
HousesLegacyDto: { value: HousesLegacyDto },
},
},
},
})

Auto-generated Mutation Does Not Create Relationship

I want to test auto-generated CRUD mutations created by calling makeAugmentedSchema from 'neo4j-graphql-js'. There is no problem with creating nodes but creating relationship does not work for me. Please advise on what I am doing wrong here.
Schema:
type Bio{
id: ID!
description: String
}
type Person{
id: ID!
name: String
dob: Date
gender: String
bioRelation: [Bio] #relation(name: "HAS_BIO", direction: "OUT")
}
Mutation:
I am following the Interface Mutations guidance https://grandstack.io/docs/graphql-interface-union-types to create mutation.
mutation {
p: CreatePerson(
name: "Anton",
gender: "Male") {
name
gender
id
}
b: CreateBio(
description: "I am a developer") {
description
id
}
r: AddPersonBioRelation(
from: {id: "p"},
to:{id: "b"}
){
from{
name
}
to{
description
}
}
}
It create Person and Bio nodes but no any relationship gets created between the two:
{
"data": {
"p": {
"name": "Anton",
"gender": "Male",
"id": "586b63fd-f9a5-4274-890f-26ba567c065c"
},
"b": {
"description": "I am a developer",
"id": "a46b4c22-d23b-4630-ac84-9d6248bdda89"
},
"r": null
}
}
This is how AddPersonBioRelation looks like:
Thank you.
I am new to GRANDstack, and I have also been struggling with these types of issues myself. I have typically broken this out separate mutations (in javascript) and used the return value for each as values for the next mutation. for example:
await createIncident({
variables: {
brief: values.brief,
date,
description: values.description,
recordable: values.recordable,
title: values.title
}
}).then((res) => {
addIncidentUser({
variables: {
from: user.id,
to: res.data.CreateIncident.id
}
});
});
the problem that i see in the example you've provided is that you are specifying a string value for from and to as "p" and "b" respectively and NOT the p.id and b.id return values from the parent mutations.
it's fine of me to point that out but what i can't for the LIFE of me figure out is how to properly reference p.id and b.id in the mutation itself. in other words you are trying to send
from: { id: "586b63fd-f9a5-4274-890f-26ba567c065c"}
to: { id: "a46b4c22-d23b-4630-ac84-9d6248bdda89" }
but in reality you are sending
from: { id: "p"}
to: { id: "b" }
which aren't actually references in neo4j so it fails.
if we can figure out how to properly reference p.id and b.id we should get this working.
Thank you, #dryhurst. It appears that there is no way to reference id of newly created nodes, but I found a solution by introducing temp id property. Please see the discussion of this matter and final solution on:
https://community.neo4j.com/t/auto-generated-mutation-does-not-create-relationship/21412/16.

Loopback POST array of entry?

I want to insert 10 entries with one query against 10 queries.
I read that it's possible to do it by sending an array like this :
But I get this error:
Do I need to set something? I don't know what to do at all.
Repo with a sample : https://github.com/mathias22osterhagen22/loopback-array-post-sample
Edit:
people-model.ts:
import {Entity, model, property} from '#loopback/repository';
#model()
export class People extends Entity {
#property({
type: 'number',
id: true,
generated: true,
})
id?: number;
#property({
type: 'string',
required: true,
})
name: string;
constructor(data?: Partial<People>) {
super(data);
}
}
export interface PeopleRelations {
// describe navigational properties here
}
export type PeopleWithRelations = People & PeopleRelations;
The problem with your code was :
"name": "ValidationError", "message": "The People instance is not
valid. Details: 0 is not defined in the model (value: undefined);
1 is not defined in the model (value: undefined); name can't be
blank (value: undefined).",
Here in above as in your #requestBody schema, you are applying to insert a single object property, where as in your body are sending the array of [people] object.
As you can see in your people.model.ts you have declared property name to be required, so system finds for the property "name", which obviously not available in the given array of object as primary node.
As you are passing index array, so its obvious error that you don't have any property named 0 or 1, so it throws error.
The below is the code hat you should apply to get insert the multiple, items of the type.
#post('/peoples', {
responses: {
'200': {
description: 'People model instance',
content: {
'application/json': {
schema: getModelSchemaRef(People)
}
},
},
},
})
async create(
#requestBody({
content: {
'application/json': {
schema: {
type: 'array',
items: getModelSchemaRef(People, {
title: 'NewPeople',
exclude: ['id'],
}),
}
},
},
})
people: [Omit<People, 'id'>]
): Promise<{}> {
people.forEach(item => this.peopleRepository.create(item))
return people;
}
You can also use this below
Promise<People[]> {
return await this.peopleRepository.createAll(people)
}
You can pass the array of your people model by modifying the request body.If you need more help you can leave comment.
I think you have a clear solution now. "Happy Loopbacking :)"

Is there a way to control loading relations in gorm with mongodb?

I'm building a REST api with grails 3 and mongo. I have encountered a problem when i need to marshal an object graph with a bigger depth.
I have the following domains:
class Category extends Resource {
/* other fields */
Category parent
}
class Product extends Resource {
/* other fields */
List<Category> categories
static hasMany = [categories: Category]
}
I have in the database the following structure(simplified for the sake of understanding):
categories:
{name: 'cat1'}
{name: 'cat2', parent: 'cat3'}
{name: 'cat3', parent: 'cat4'}
{name: 'cat4', parent: 'cat5'}
{name: 'cat5'}
product:
{categories: ['cat1', 'cat2']}
I am extending from RestfullController when creating my controllers. I want to be able to get a product and have the categories with parents in the returned json.
I get the following results:
/product/${id}
{
id: '...',
categories: [{
id: '...',
name: 'cat1'
}, {
id: '...',
name: 'cat2',
parent: { id: '...' }
}]
}
/category/cat2id
{
id: '...',
name: 'cat2',
parent: { id: '...' }
}
/category
[{
id: '...',
name: 'cat1'
},{
id: '...',
name: 'cat5'
},{
id: '...',
name: 'cat4',
parent: {
id: '...',
name: 'cat5'
}
},{
id: '...',
name: 'cat3',
parent: {
id: '...',
name: 'cat4',
parent: {
id: '...',
name: 'cat5'
}
}
},{
id: '...',
name: 'cat2',
parent: {
id: '...',
name: 'cat3',
parent: {
id: '...',
name: 'cat4',
parent: {
id: '...',
name: 'cat5'
}
}
}
}]
Why would Category.list() load the whole category object graph, and Category.get(), Product.get() and Product.list() would not load it? Is there a way to control this behaviour ?
The way Grails works is that it will only render associations that have already been loaded from the database, hence why you get some associations rendered and others not.
There is no built in way to control this behaviour other than writing your own marshaller. See http://grails.github.io/grails-doc/latest/guide/webServices.html#renderers

An example on how to embed forms in Symfony

I am using Symfony 1.3.2 with Propel ORM on Ubuntu 9.10.
I have a user profile table, which has many other tables linked to it (i.e. user_profile.id is a FK in many other tables.
My db schema looks something like this:
user_profile:
_attributes: { phpName: UserProfile }
id: ~
guard_id: { type: integer, foreignTable: sf_guard_user, foreignReference: id, required: true }
address: { type: longvarchar, required: true }
vehicle_type:
_attributes: { phpName: VehicleType }
id: ~
name: { type: varchar(32), required: true }
user_vehicle:
_attributes: { phpName: UserVehicle }
id: ~
user_id: { type: integer, foreignTable: user_profile, foreignReference: id, required: true }
vehicle_type: { type: integer, foreignTable: vehicle_type, foreignReference: id, required: true }
license_plate: { type: varchar(16), required: true }
user_child:
_attributes: { phpName: UserChild }
id: ~
user_id: { type: integer, foreignTable: user_profile, foreignReference: id, required: true }
gender: { type: boolean, required: true }
name: { type: varchar(32), required: true }
I would like to embed the other objects that link to the user profile object, in the user profile form, so that when I am performing CRUD on a user profile form, the related objects (e.g. UserVehicle, UserJob are also CRUD at the same time as the user profile object).
I need a simple snippet that will show how to:
Embed the various related objects (i.e. UserVehicle, UserChild) into the UserProfile form
Create/Update/Delete the various related objects as the operation is being carried (please note, a user can have more than 0-N vehicles or children assigned to them
Have you read the documentation?:
// lib/form/doctrine/ProductForm.class.php
public function configure()
{
$subForm = new sfForm();
for ($i = 0; $i < 2; $i++)
{
$productPhoto = new ProductPhoto();
$productPhoto->Product = $this->getObject();
$form = new ProductPhotoForm($productPhoto);
$subForm->embedForm($i, $form);
}
$this->embedForm('newPhotos', $subForm);
}
For the create/delete/update part, this article might give some help.
I never found the official approach right for my needs. I developed a completely different approach. In the company where I used to work we used in production this new approach, finding it a bit more elastic and simple. The key concept is "don't use Symfony's Form class and you will discover that embedding forms can be a very simple task"
I hope this can help you embedding forms.

Resources