is there any way to edit scope key in AAD login in backstage.? - backstage

I have a backstage instance in which i am using AAD login in which backstage is passing some scope like "user.read offline_access etc" value, i want to add few more keys like "Clendar.ReadWrite". is there any way to do that in backstage.
I am trying to pass ./default values in scope key. I have searched a lot for possible solutions but couldn't get any of it

If I didn't get it wrong, do you want to transform the values ​​created for the User entity?
This documentation may help, if applicable.
The following provides an example of each kind of transformer
import * as MicrosoftGraph from '#microsoft/microsoft-graph-types';
import {
defaultGroupTransformer,
defaultUserTransformer,
defaultOrganizationTransformer,
} from '#backstage/plugin-catalog-backend-module-msgraph';
import { GroupEntity, UserEntity } from '#backstage/catalog-model';
// This group transformer completely replaces the built in logic with custom logic.
export async function myGroupTransformer(
group: MicrosoftGraph.Group,
groupPhoto?: string,
): Promise<GroupEntity | undefined> {
return {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Group',
metadata: {
name: group.id!,
annotations: {},
},
spec: {
type: 'aad',
children: [],
},
};
}
// This user transformer makes use of the built in logic, but also sets the description field
export async function myUserTransformer(
graphUser: MicrosoftGraph.User,
userPhoto?: string,
): Promise<UserEntity | undefined> {
const backstageUser = await defaultUserTransformer(graphUser, userPhoto);
if (backstageUser) {
backstageUser.metadata.description = 'Loaded from Azure Active Directory';
}
return backstageUser;
}
// Example organization transformer that removes the organization group completely
export async function myOrganizationTransformer(
graphOrganization: MicrosoftGraph.Organization,
): Promise<GroupEntity | undefined> {
return undefined;
}

Related

Access context from Apollo GraphQL mutation field directive

I have an input type like this:
input PetGiraffe {
name: String #addUserLastName
}
Inside the directive, I need access to the request's context, so that I can add the user's last name to the giraffe's name. Here's the relevant part of what I've got so far:
const addUserLastNameDirective = {
typeDefs: gql`directive #addUserLastName on INPUT_FIELD_DEFINITION`,
transformer: (schema: GraphQLSchema, directiveName = 'addUserLastName') => {
return mapSchema(schema, {
[MapperKind.INPUT_OBJECT_FIELD]: (fieldConfig, fieldName, typeName, schema) => {
const directive = getDirective(schema, fieldConfig, directiveName)?.[0];
if (directive) {
// Need context in here because the user is in the context.
}
},
});
},
};
For queries, I understand you can override the fieldConfig.resolve method and get access to the context that way. But if I try that with this mutation, it throws: field has a resolve property, but Input Types cannot define resolvers.
The closest I could find was this from the graphql-tools docs, but that doesn't solve my problem of accessing the context.

How to use sequelize-typescript for querying relative objects through custom Apollo GraphQL resolver?

How to use sequelize-typescript for querying relative objects through custom Apollo GraphQL type? I have the following query without typescript:
User and Event GraphQL types:
type User {
id: Int
login: String
email: String
role: Roles
url_identity: String
}
type Event {
id: Int
event_name: String
user: User
}
User model
import {HasOne, Model, Table} from "sequelize-typescript";
import Event from "./event.model";
#Table({
timestamps: false,
modelName: 'User',
})
export default class User extends Model {
#HasOne(() => Event)
event: Event
}
Resolver:
static resolver() {
return {
Event: {
user: event => event.$get('user')
}
}
Typescript can't see event.$get('user')
The answer is to add mappers to your graphql-codegen config.
You can also pass interface for context (third parameter):
schema: ./src/graphql/types/**/*.graphql
generates:
./src/graphql/resolvers-types.ts:
config:
useIndexSignature: true
contextType: ./schema#IApolloServerContext
mappers:
Event: ../database/models/event.model#EventModel
User: ../database/models/user.model#UserModel
plugins:
- typescript
- typescript-resolvers
More info here: https://graphql-code-generator.com/docs/plugins/typescript-resolvers#use-your-model-types-mappers

Limit Graphql results that belongs to owner in Strapi

I am using a simple Strapi policy like below to limit the REST result that belongs to the owner only, which documented in the following link.
https://github.com/strapi/strapi/issues/624
module.exports = async (ctx, next) => {
const { id, role } = ctx.state.user;
if(role !== 'administrator'){
ctx.query.owner = id;
}
await next();
};
Now I want to do the same for Graphql results, but it doesn't seems to work with the same code because "ctx.query" is undefined. I have tried looking at the all the request API but none of them seems to be work for Graphql query. The URL ended like 'http://localhost:1337/graphql', and 'ctx.request.query' is an empty [].
https://strapi.io/documentation/3.0.0-beta.x/guides/requests.html#api-reference
Here what I did to solve that problem:
Override the GraphQl Schema in api/activity/config/schema.graphql
module.exports = {
definition: ``,
query: `
notifications(sort: String, limit: Int, start: Int, where: JSON): [Activity]
`,
type: {},
resolver: {
Query: {
notifications: {
description: 'Return the auth user notifications',
policies: ['plugins.users-permissions.permissions'],
resolver: 'Activity.findNotifications'
},
},
},
};
Create a new function resolver in api/activity/controllers/Activity.js
module.exports = {
findNotifications(ctx) {
ctx.query = { ...ctx.query, owner: ctx.state.user.id }
if (ctx.query._q) {
return strapi.services.activity.search(ctx.query);
}
return strapi.services.activity.find(ctx.query);
},
}
In the controller you got the query and add the owner id filter.
Hope it helps.
Why are you looking at REST docs while searching for graphQL problem? There is no url query parsing at all.
Owner role (permissions) can be checked using policies - it's described here.
The following sections contain examples of misc permission/customization - resolvers have a context parameter. User data should (did't checked) be available at context.state.user.

How to create generics with the schema language?

Using facebook's reference library, I found a way to hack generic types like this:
type PagedResource<Query, Item> = (pagedQuery: PagedQuery<Query>) => PagedResponse<Item>
​
interface PagedQuery<Query> {
query: Query;
take: number;
skip: number;
}
​
interface PagedResponse<Item> {
items: Array<Item>;
total: number;
}
function pagedResource({type, resolve, args}) {
return {
type: pagedType(type),
args: Object.assign(args, {
page: { type: new GraphQLNonNull(pageQueryType()) }
}),
resolve
};
function pageQueryType() {
return new GraphQLInputObjectType({
name: 'PageQuery',
fields: {
skip: { type: new GraphQLNonNull(GraphQLInt) },
take: { type: new GraphQLNonNull(GraphQLInt) }
}
});
}
function pagedType(type) {
return new GraphQLObjectType({
name: 'Paged' + type.toString(),
fields: {
items: { type: new GraphQLNonNull(new GraphQLList(type)) },
total: { type: new GraphQLNonNull(GraphQLInt) }
}
});
}
}
But I like how with Apollo Server I can declaratively create the schema. So question is, how do you guys go about creating generic-like types with the schema language?
You can create an interface or union to achieve a similar result. I think this article does a good job explaining how to implement interfaces and unions correctly. Your schema would look something like this:
type Query {
pagedQuery(page: PageInput!): PagedResult
}
input PageInput {
skip: Int!
take: Int!
}
type PagedResult {
items: [Pageable!]!
total: Int
}
# Regular type definitions for Bar, Foo, Baz types...
union Pageable = Bar | Foo | Baz
You also need to define a resolveType method for the union. With graphql-tools, this is done through the resolvers:
const resolvers = {
Query: { ... },
Pageable {
__resolveType: (obj) => {
// resolve logic here, needs to return a string specifying type
// i.e. if (obj.__typename == 'Foo') return 'Foo'
}
}
}
__resolveType takes the business object being resolved as its first argument (typically your raw DB result that you give GraphQL to resolve). You need to apply some logic here to figure out of all the different Pageable types, which one we're handling. With most ORMs, you can just add some kind of typename field to the model instance you're working with and just have resolveType return that.
Edit: As you pointed out, the downside to this approach is that the returned type in items is no longer transparent to the client -- the client would have to know what type is being returned and specify the fields for items within an inline fragment like ... on Foo. Of course, your clients will still have to have some idea about what type is being returned, otherwise they won't know what fields to request.
I imagine creating generics the way you want is impossible when generating a schema declaratively. To get your schema to work the same way it currently does, you would have to bite the bullet and define PagedFoo when you define Foo, define PagedBar when you define Bar and so on.
The only other alternative I can think of is to combine the two approaches. Create your "base" schema programatically. You would only need to define the paginated queries under the Root Query using your pagedResource function. You can then use printSchema from graphql/utilities to convert it to a String that can be concatenated with the rest of your type definitions. Within your type definitions, you can use the extend keyword to build on any of the types already declared in the base schema, like this:
extend Query {
nonPaginatedQuery: Result
}
If you go this route, you can skip passing a resolve function to pagedResource, or defining any resolvers on your programatically-defined types, and just utilize the resolvers object you normally pass to buildExecutableSchema.

Apollo GraphQL: Multiple Queries in One Component?

I have a component that needs to query two entirely separate tables. What do the schema, query and resolver need to look like in this case? I've googled but haven't found examples yet. Thanks in advance for any info.
UPDATE:
On Slack I see there may be a way to use compose for this purpose, e.g.:
export default compose(
graphql(query1,
....),
graphql(query2,
....),
graphql(query3,
....),
withApollo
)(PrintListEditPage)
Is there a way to have multiple declarations like this:
const withMutations = graphql(updateName, {
props({ mutate }) {
return {
updatePrintListName({ printListId, name }) {
return mutate({
variables: { printListId, name },
});
},
};
},
});
...that come before the call to export default compose?
The graphql function takes an optional second argument that allows you to alias the passed down property name. If you have multiple mutations you can use the name property to rename mutate as needed:
import { graphql, compose } from 'react-apollo'
export default compose(
graphql(mutation1, { name: 'createSomething' }),
graphql(mutation2, { name: 'deleteSomething' }),
)(Component)
For more details see the complete API.

Resources