Can't get registered user.id in AdonisJS when setting relationships in controller - adonis.js

My code:
users migration
public async up() {
this.schema.createTable(this.tableName, (table) => {
table.increments('id').primary()
table.string('password', 180).nullable()
table.timestamp('created_at', {useTz: true}).notNullable()
table.timestamp('updated_at', {useTz: true}).notNullable()
}
words migration
public async up() {
this.schema.createTable(this.tableName, (table) => {
table.increments('id')
table.timestamp('created_at', {useTz: true})
table.timestamp('updated_at', {useTz: true})
table.integer('user_id').unsigned().references('users.id').onDelete('CASCADE')
})
}
Models/User
#hasMany(() => Word)
public words: HasMany<typeof Word>
Models/Word
#column()
public userId: number
#belongsTo(() => User)
public author: BelongsTo<typeof User>
WordsController
public async store({request, auth}: HttpContextContract) {
const user = auth.user!.id
const data = await request.validate(WordValidator)
const word = await user?.related('words').create(data)
return word
}
When I type auth.user!.id as it is in upper example, it returns this:
"Cannot read properties of undefined (reading 'id')"
I'm registered, it even normally shows my id on other requests (but only get requests).
What can I do, to get registered user id, and set it as userId in word table or what am I doing wrong?
Thanks

Related

"errors":[{"rule":"required","field":"username","message":"required validation failed"}

i am trying to validate my user resister form in adonis js by using
import {schema, rules} from '#ioc:Adonis/Core/Validator';
after register I am getting error of
{"errors":[{"rule":"required","field":"username","message":"required validation failed"},{"rule":"required","field":"username","message":"required validation failed"},{"rule":"required","field":"password","message":"required validation failed"},{"rule":"required","field":"phone","message":"required validation failed"}]}
validation code is
import { HttpContextContract } from '#ioc:Adonis/Core/HttpContext';
import {schema, rules} from '#ioc:Adonis/Core/Validator';
import user from 'App/Models/User';
export default class LoginController{
public async loginShow({view}:HttpContextContract){
return view.render('backend/login');
}
public async register({request,response,auth}:HttpContextContract){
const userSchema = schema.create({
username: schema.string({trim:true},[rules.required(), rules.unique({table:'users', column:'username', caseInsensitive: true})]),
email: schema.string({trim:true},[rules.email(), rules.required(), rules.unique({table:'users', column:'email', caseInsensitive: true})]),
password: schema.string({},[rules.minLength(6), rules.maxLength(20)]),
phone: schema.string({},[rules.unique({table:'users', column:'phone'})])
})
const data = await request.validate({schema: userSchema})
const User = await user.create(data)
await auth.login(User)
return response.redirect('/')
}
public async registerShow({view}:HttpContextContract){
return view.render('backend/register');
}
public async login({request,response,auth}:HttpContextContract){
const {uid, password} = request.only(['uid','password'])
try{
await auth.attempt(uid,password)
} catch (error){
console.log('form','your email or password is incorrect')
return response.redirect().back()
}
return response.redirect('/')
}
}
migration table is given below:
import BaseSchema from '#ioc:Adonis/Lucid/Schema'
export default class Users extends BaseSchema {
protected tableName = 'users'
public async up () {
this.schema.createTable(this.tableName, (table) => {
table.increments('id')
table.string('name',50).nullable()
table.string('username',50).unique().notNullable()
table.string('email',100).unique().notNullable()
table.string('phone',18).unique().nullable()
table.string('password',50).notNullable()
table.string('country',30).nullable()
table.string('city',40).nullable()
table.string('address_1',40).nullable()
table.string('address_2',40).nullable()
table.string('token',40).nullable()
table.dateTime('token_expiry')
table.boolean('is_active').defaultTo(false)
table.timestamps(true,true)
})
}
public async down () {
this.schema.dropTable(this.tableName)
}
}

How to configure retry for MassTransit sagas

I'm having a concurrency issue with MassTransit sagas.
I'm currently working on a POC with this flow:
One thread produces 100 event that are published to MassTransit in a sequence.
When the saga is instantiated it publishes another event to MassTransit.
The new event is picked up by a Consumer that perform some business logic and publishes one of two resulting event to MassTransit.
The resulting events from step 3. triggers a state change in the saga
I sometimes get exceptions like this Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException: The database operation was expected to affect 1 row(s), but actually affected 0 row(s); data may have been modified or deleted since entities were loaded. in step 4, and the state change is not persisted.
Here is the business logic code:
public interface IInitialSagaEvent : CorrelatedBy<Guid> { }
public interface IExternalCheckRequest : CorrelatedBy<Guid> { }
public interface IExternalCheckOk : CorrelatedBy<Guid> { }
public interface IExternalCheckNotOk : CorrelatedBy<Guid> { }
public class MySaga : SagaStateMachineInstance
{
public Guid CorrelationId { get; set; }
public string CurrentState { get; set; }
public byte[] RowVersion { get; set; }
}
public class MyStateMachine : MassTransitStateMachine<MySaga>
{
public MyStateMachine()
{
InstanceState(instance => instance.CurrentState);
Initially(
When(InitialSagaEvent)
.ThenAsync(context => context.GetPayload<ConsumeContext>().Publish<IExternalCheckRequest>(new { context.Instance.CorrelationId }))
.TransitionTo(AwaitingExternalCheck)
);
During(AwaitingExternalCheck,
Ignore(InitialSagaEvent),
When(ExternalCheckOk)
.TransitionTo(CheckedOk),
When(ExternalCheckNotOk)
.TransitionTo(CheckedNotOk)
);
During(CheckedOk,
When(InitialSagaEvent)
.ThenAsync(context => context.GetPayload<ConsumeContext>().Publish<IExternalCheckRequest>(new { context.Instance.CorrelationId }))
.TransitionTo(AwaitingExternalCheck)
);
During(CheckedNotOk,
When(InitialSagaEvent)
.ThenAsync(context => context.GetPayload<ConsumeContext>().Publish<IExternalCheckRequest>(new { context.Instance.CorrelationId }))
.TransitionTo(AwaitingExternalCheck)
);
}
public Event<IInitialSagaEvent> InitialSagaEvent { get; private set; }
public Event<IExternalCheckOk> ExternalCheckOk { get; private set; }
public Event<IExternalCheckNotOk> ExternalCheckNotOk { get; private set; }
public State AwaitingExternalCheck { get; private set; }
public State CheckedOk { get; private set; }
public State CheckedNotOk { get; private set; }
}
public class ExternalCheckRequestConsumer : IConsumer<IExternalCheckRequest>
{
private readonly IExternalChecker externalChecker;
public ExternalCheckRequestConsumer(IExternalChecker externalChecker)
{
this.externalChecker = externalChecker;
}
public async Task Consume(ConsumeContext<IExternalCheckRequest> context)
{
var ok = await externalChecker.PerformCheck(context.Message, context.CancellationToken);
if (ok)
{
await context.Publish<IExternalCheckOk>(new { context.Message.CorrelationId }, context.CancellationToken);
}
else
{
await context.Publish<IExternalCheckNotOk>(new { context.Message.CorrelationId }, context.CancellationToken);
}
}
}
public interface IExternalChecker
{
Task<bool> PerformCheck(IExternalCheckRequest request, CancellationToken cancellationToken);
}
public class Publisher
{
private readonly IPublishEndpoint publishEndpoint;
public Publisher(IPublishEndpoint publishEndpoint)
{
this.publishEndpoint = publishEndpoint;
}
public async Task Publish(Guid correlationId, CancellationToken cancellationToken)
{
await publishEndpoint.Publish<IInitialSagaEvent>(new { CorrelationId = correlationId }, cancellationToken);
}
}
Here it the configuration code
public class MySagaDbContext : SagaDbContext
{
public MySagaDbContext(DbContextOptions<MySagaDbContext> options) : base(options) { }
protected override IEnumerable<ISagaClassMap> Configurations
{
get
{
yield return new MySagaClassMap();
}
}
}
public class MySagaClassMap : SagaClassMap<MySaga>
{
protected override void Configure(EntityTypeBuilder<MySaga> entity, ModelBuilder model)
{
entity.Property(x => x.CurrentState).HasMaxLength(128);
entity.Property(x => x.RowVersion).IsRowVersion();
}
}
public class ExternalCheckRequestConsumerDefinition : ConsumerDefinition<ExternalCheckRequestConsumer>
{
protected override void ConfigureConsumer(IReceiveEndpointConfigurator endpointConfigurator, IConsumerConfigurator<ExternalCheckRequestConsumer> consumerConfigurator) =>
endpointConfigurator.UseRetry(r =>
{
r.Handle<DbUpdateConcurrencyException>();
// This is the SQLServer error code for duplicate key
r.Handle<DbUpdateException>(y => y.InnerException is SqlException e && e.Number == 2627);
r.Interval(5, TimeSpan.FromMilliseconds(100));
});
}
public class Program
{
public static async Task Main(string[] args)
{
var services = new ServiceCollection();
services.AddDbContext<DbContext, MySagaDbContext>((provider, builder)
=> builder.UseSqlServer(connectionString, m =>
{
m.MigrationsAssembly(typeof(MySagaDbContext).Assembly.GetName().Name);
m.MigrationsHistoryTable($"__EFMigrationsHistory_Sagas");
}));
services.AddMassTransit(configureMassTransit =>
{
configureMassTransit.AddConsumer<ExternalCheckRequestConsumer, ExternalCheckRequestConsumerDefinition>();
configureMassTransit.AddSagaStateMachine<MyStateMachine, MySaga>()
.EntityFrameworkRepository(r =>
{
r.ConcurrencyMode = ConcurrencyMode.Optimistic;
r.ExistingDbContext<MySagaDbContext>();
});
configureMassTransit.SetEndpointNameFormatter(new DefaultEndpointNameFormatter(true));
configureMassTransit.UsingActiveMq((context, config) =>
{
config.Host("artemis", 61616, configureHost =>
{
configureHost.Username("admin");
configureHost.Password("admin");
});
config.UseInMemoryOutbox(); // ref https://masstransit-project.com/articles/outbox.html#the-in-memory-outbox
config.EnableArtemisCompatibility();
config.ConfigureEndpoints(context);
});
});
var serviceProvider = services.BuildServiceProvider();
var busControl = serviceProvider.GetRequiredService<IBusControl>();
await busControl.StartAsync();
await RunPoc(serviceProvider);
}
private static async Task RunPoc(IServiceProvider serviceProvider)
{
await Task.CompletedTask;
}
static string connectionString = string.Empty;
}
My guess is that I need to get in a UseRetry at the correct point, so I've tried to configure the AddSagaStateMachine with UseRetry like this:
configureMassTransit.AddSagaStateMachine<MyStateMachine, MySaga>(
configure =>
{
configure.UseRetry(r =>
{
r.Handle<DbUpdateConcurrencyException>();
// This is the SQLServer error code for duplicate key
r.Handle<DbUpdateException>(y => y.InnerException is SqlException e && e.Number == 2627);
r.Interval(5, TimeSpan.FromMilliseconds(100));
});
})
.EntityFrameworkRepository(r =>
{
r.ConcurrencyMode = ConcurrencyMode.Optimistic;
r.ExistingDbContext<MySagaDbContext>();
});
But with this UseRetry in AddSagaStateMachine nothing works, I just get loads of exception like this:
fail: MassTransit.ReceiveTransport[0]
R - FAULT activemq://artemis:61616/XXXX
System.ArgumentException: THe message could not be retrieved: IInitialSagaEvent(Parameter 'context')
at MassTransit.Saga.Pipeline.Pipes.SagaMergePipe`2.Send(SagaConsumeContext`1 context)
at GreenPipes.Filters.RetryFilter`1.GreenPipes.IFilter<TContext>.Send(TContext context, IPipe`1 next)
at GreenPipes.Filters.RetryFilter`1.GreenPipes.IFilter<TContext>.Send(TContext context, IPipe`1 next)
at MassTransit.Saga.SendSagaPipe`2.Send(SagaRepositoryContext`2 context)
at MassTransit.Saga.SendSagaPipe`2.Send(SagaRepositoryContext`2 context)
at MassTransit.EntityFrameworkCoreIntegration.Saga.Context.EntityFrameworkSagaRepositoryContextFactory`1.<> c__DisplayClass5_0`1.<< Send > b__1 > d.MoveNext()
-- - End of stack trace from previous location ---
at MassTransit.EntityFrameworkCoreIntegration.Saga.Context.EntityFrameworkSagaRepositoryContextFactory`1.<> c__DisplayClass8_0.<< WithinTransaction > g__Create | 0 > d.MoveNext()
-- - End of stack trace from previous location ---
at MassTransit.EntityFrameworkCoreIntegration.Saga.Context.EntityFrameworkSagaRepositoryContextFactory`1.WithinTransaction[T](DbContext context, CancellationToken cancellationToken, Func`1 callback)
at MassTransit.EntityFrameworkCoreIntegration.Saga.Context.EntityFrameworkSagaRepositoryContextFactory`1.WithinTransaction[T](DbContext context, CancellationToken cancellationToken, Func`1 callback)
at MassTransit.EntityFrameworkCoreIntegration.Saga.Context.EntityFrameworkSagaRepositoryContextFactory`1.WithinTransaction[T](DbContext context, CancellationToken cancellationToken, Func`1 callback)
at MassTransit.EntityFrameworkCoreIntegration.Saga.Context.EntityFrameworkSagaRepositoryContextFactory`1.Send[T](ConsumeContext`1 context, IPipe`1 next)
at MassTransit.EntityFrameworkCoreIntegration.Saga.Context.EntityFrameworkSagaRepositoryContextFactory`1.Send[T](ConsumeContext`1 context, IPipe`1 next)
at MassTransit.ExtensionsDependencyInjectionIntegration.ScopeProviders.DependencyInjectionSagaRepositoryContextFactory`1.<> c__DisplayClass6_0`1.<< Send > g__CreateScope | 0 > d.MoveNext()
-- - End of stack trace from previous location ---
at MassTransit.ExtensionsDependencyInjectionIntegration.ScopeProviders.DependencyInjectionSagaRepositoryContextFactory`1.<> c__DisplayClass6_0`1.<< Send > g__CreateScope | 0 > d.MoveNext()
-- - End of stack trace from previous location ---
at MassTransit.Saga.Pipeline.Filters.CorrelatedSagaFilter`2.GreenPipes.IFilter<MassTransit.ConsumeContext<TMessage>>.Send(ConsumeContext`1 context, IPipe`1 next)
I'm using .Net 6 and have tried MassTransit v 7.3.1 and v 8.0.0-develop.391, but both has the same behavior.
I've tried defining the messages as interfaces and publishing them both as anonymous classes and as actual implementations, and also tried to define the messages as classes, but with no luck.
My hope it that there is just some small configuration detail I'm missing, but I'm out of ideas, so any help is deeply appreciated.
The proper configuration in your SagaDefinition is shown below. Note the use of UseMessageRetry, instead of UseRetry.
public class ExternalCheckRequestConsumerDefinition :
ConsumerDefinition<ExternalCheckRequestConsumer>
{
protected override void ConfigureConsumer(IReceiveEndpointConfigurator endpointConfigurator,
IConsumerConfigurator<ExternalCheckRequestConsumer> consumerConfigurator) =>
endpointConfigurator.UseMessageRetry(r =>
{
r.Handle<DbUpdateConcurrencyException>();
// This is the SQLServer error code for duplicate key
r.Handle<DbUpdateException>(y => y.InnerException is SqlException e && e.Number == 2627);
r.Interval(5, TimeSpan.FromMilliseconds(100));
});
}
UPDATE
The above Consumer definition isn't used by the saga. You'd need to create a Saga definition, and specify it when adding the saga, for the retry to apply to the saga. Which would do the same as configuring it inline when adding the saga:
.AddSagaStateMachine<MyStateMachine, MySaga, MySagaDefinition>(
Also, in your state machine, replace the overly noisy:
.ThenAsync(context => context.GetPayload<ConsumeContext>().Publish<IExternalCheckRequest>(new { context.Instance.CorrelationId }))
With:
.PublishAsync(context => context.Init<IExternalCheckRequest>(new { context.Instance.CorrelationId }))
Here is the .AddSagaStateMachine I used, ref Chris Pattersons solution in the other answer.
configureMassTransit.AddSagaStateMachine<MyStateMachine, MySaga>(
configure =>
{
configure.UseMessageRetry(r =>
{
r.Handle<DbUpdateConcurrencyException>();
// This is the SQLServer error code for duplicate key
r.Handle<DbUpdateException>(y => y.InnerException is SqlException e && e.Number == 2627);
r.Interval(5, TimeSpan.FromMilliseconds(100));
});
})
.EntityFrameworkRepository(r =>
{
r.ConcurrencyMode = ConcurrencyMode.Optimistic;
r.ExistingDbContext<MySagaDbContext>();
});

Unable to setup AWS-amplify MFA - issue with the Auth.confirmSignIn function

I'm having a problem with my adding MFA to my site which manages authentication with AWS Amplify.
I've followed the example here and created the code below to handle both users who have MFA enabled, and those that don't.
const Signin = props => {
const { classes, onStateChange, history } = props;
const [inputs, setInputs] = useState({
username: '',
password: '',
});
const [currentStep, setCurrentStep] = useState(1)
const [userObject, setUserObject] = useState({})
const [authCode, setauthCode] = useState({code: ''})
const onSignIn = async (e) => {
const username = inputs.username.toLowerCase()
await Auth.signIn({
username, // Required, the username
password: inputs.password, // Optional, the password
}).then(user => {
if (user.preferredMFA === 'SOFTWARE_TOKEN_MFA'){
setUserObject(user)
setCurrentStep(2)}
else{
onStateChange('signedIn', {})
history.push('/dashboard');
}
})
.catch(err => {
showAlert(err.message)
if (err.code === 'PasswordResetRequiredException') {
onStateChange('forgotPassword')
history.push('/forgotpassword');
}
})
}
const MfaSignIn = async (e) => {
const user=userObject
await Auth.confirmSignIn(
user,
authCode.code,
user.preferredMFA
).then(user => {
onStateChange('signedIn', {})
history.push('/dashboard');
})
.catch(err => {
showAlert(err.message)
if (err.code === 'PasswordResetRequiredException') {
onStateChange('forgotPassword')
history.push('/forgotpassword');
}
})
If MFA is not enabled the login page will call the onSignIn function then log them in. If MFA is enabled the user object returned from the signin function will return the value "SOFTWARE_TOKEN_MFA" for the preferredMFA key, and a second page will load which allows the user to enter their MFA code, which is handled by the MfaSignIn function.
No MFA works fine, however when attempting to use the MfaSignIn function as is I get "Missing required parameter Session"
the Session key of the user object returned by onSignIn has a value of null, and there's no mention of it needing to be added from the docs. Ive tried adjusting this function to
const MfaSignIn = async (e) => {
e.preventDefault(authCode.code);
const session= Auth.currentSession().then(data=> {return data})
const token = await session.then(data=>{return data.getAccessToken()})
const user=userObject
user.Session=token.jwtToken
await Auth.confirmSignIn(
user,
authCode.code,
user.preferredMFA
).then(user => {
onStateChange('signedIn', {})
history.push('/dashboard');
})
.catch(err => {
showAlert(err.message)
if (err.code === 'PasswordResetRequiredException') {
onStateChange('forgotPassword')
history.push('/upgrade');
}
})
}
Where I call the Auth.currentSession method and add the data from there to the Session value in the user object. Adding the whole object returns the error-
"Start of structure or map found where not expected."
- seems to need a string not a map object
I've tried adding each of the three JWT token strings that are found in the currentSession object, along with the result of the getAccessToken as in the example above. All return the error
"Invalid session provided"
I'm at a loss at what I need to give the Auth.confirmSignIn to let the user sign in- I appear to be doing everything correctly as per the docs.
Any ideas?

Adonis.js - Seeding Users and Profiles throwing DB error (Postgres)

I am trying to write a seed file for users and profiles with a one to one relationship and currently getting an "error: relation 'user_profiles' does not exist". From digging around, it seems like Adonis will assume this as a pivot table in the case of a many to many relationship. What I (think or intend to) have is a one to one relationship between users and profiles. Thanks in advance! Newbie to SQL and Adonis. As a side note, the user persists to the db, but there is no corresponding profile.
// My User Schema
class UserSchema extends Schema {
up () {
this.create('users', (table) => {
table.increments('id')
table.string('username', 80).notNullable().unique()
table.string('email', 254).notNullable().unique()
table.string('password', 60).notNullable()
// table.integer('profile_id').unsigned().references('id').inTable('userprofiles')
table.timestamps()
})
}
down () {
this.drop('users')
}
}
// My Profile Schema
class UserprofileSchema extends Schema {
up () {
this.create('userprofiles', (table) => {
table.increments()
table.string('first_name')
table.string('last_name')
// table.integer('user_id')
// .unsigned().references('id').inTable('users')
table.integer('user_id')
.unsigned()
.index('user_id')
table.foreign('user_id')
.references('users.id')
table.timestamps()
})
}
down () {
this.drop('userprofiles')
}
}
My User model includes the following relationship definition:
profile () {
return this.hasOne('App/Models/UserProfile')
}
// Seed script
class UserSeeder {
async run () {
try {
const user = await Factory.model('App/Models/User').create()
const userProfile = await Factory.model('App/Models/UserProfile').make()
userProfile.user_id = user.id
await user.profile().save(userProfile)
} catch (e) {
console.log('Error From Seeder: ', e);
}
}
}
Error code '42P01' and can post whole body if needed. Thanks!
On your Model userProfile, set table name as follows.
class User extends Model {
static get table () {
return 'userprofiles'
}
}

Facebook Workplace Account Management API Not Returning Photos

I am having an issue with the Account Management API for Facebook Workplace. All I am trying to do is build a quick and easy employee directory, that grabs all of our active users and spits out their name, title, dept, and photos. The problem is, the data coming back does not seem to match the Facebook Core Schema as seen in the link above. Some of the schema data comes back, but never photos, no matter what I seem to try.
private function getEmployees()
{
$done = false;
$current_index = 1;
$current_page = 1;
$results = [];
while(!$done) {
$res = $this->client->request(
'GET',
'https://www.facebook.com/company/XXXXXXXXX/scim/Users?count=100&startIndex=' . $current_index,
[
'headers' => ['Accept' => 'application/json',
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $this->token
]
]
);
$decoded = json_decode($res->getBody());
$total = $decoded->totalResults;
$perPage = $decoded->itemsPerPage;
if (isset($decoded->Resources)) {
$results = array_merge($results, $decoded->Resources);
if (($current_page * $perPage) >= $total) {
$done = true;
} else {
$current_page++;
$current_index += $perPage;
}
} else {
$done = true;
}
}
return $results;
}
Which gives back:
object(stdClass)[392]
public 'schemas' =>
array (size=3)
0 => string 'urn:scim:schemas:core:1.0' (length=25)
1 => string 'urn:scim:schemas:extension:enterprise:1.0' (length=41)
2 => string 'urn:scim:schemas:extension:facebook:starttermdates:1.0' (length=54)
public 'id' => int 10001156699923
public 'userName' => string 'np#lt.com' (length=21)
public 'name' =>
object(stdClass)[393]
public 'formatted' => string 'Nick P' (length=11)
public 'title' => string 'Lead PHP Engineer' (length=17)
public 'active' => boolean true
public 'phoneNumbers' =>
array (size=1)
0 =>
object(stdClass)[394]
public 'primary' => boolean true
public 'type' => string 'work' (length=4)
public 'value' => string '+1631123456' (length=12)
public 'addresses' =>
array (size=1)
0 =>
object(stdClass)[395]
public 'type' => string 'attributes' (length=10)
public 'formatted' => string 'Manhattan' (length=9)
public 'primary' => boolean true
public 'urn:scim:schemas:extension:enterprise:1.0' =>
object(stdClass)[396]
public 'department' => string 'IT' (length=2)
public 'manager' =>
object(stdClass)[397]
public 'managerId' => int 100011017901494
public 'urn:scim:schemas:extension:facebook:starttermdates:1.0' =>
object(stdClass)[398]
public 'startDate' => int 0
public 'termDate' => int 0
So as you can see, it returns other fields that are part of the 'core' schema, but is missing the 'photos' array and others. I thought this might have been because a user didnt have any photos, but almost all have profile pictures, and many have more. I tried getting their user information specifically but encountered the same result, no photos.
Anybody ever try something similar? Any help much appreciated, this has been a bit of a road block for us.
Thanks
To get profile information, don't use SCIM but graph API
https://graph.facebook.com/community/members will list all members
and https://graph.facebook.com/[email] for one of your member will get all infos.
After that you have to set the params you want to get with the fields param.
In our implementation we get the whole data from this request
https://graph.facebook.com/XXXX/members?fields=email,picture.type(large),link,title,first_name,last_name,department,updated_time,managers{email}&limit=500