Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions dbschema/field-region.gel
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ module default {

required fieldZone: FieldZone;
required director: User;

multi projects := .<fieldRegion[is Project];
}
}
1 change: 1 addition & 0 deletions dbschema/field-zone.gel
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ module default {
required director: User;

fieldRegions := .<fieldZone[is FieldRegion];
multi projects := .<fieldZone[is FieldRegion].projects;
}
}
10 changes: 10 additions & 0 deletions dbschema/migrations/00020-m1cjlgl.edgeql

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions src/components/field-region/dto/field-region.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,26 @@ import {
DbUnique,
NameField,
Resource,
type ResourceRelationsShape,
type Secured,
SecuredProperty,
SecuredPropertyList,
SecuredString,
} from '~/common';
import { e } from '~/core/gel';
import { type LinkTo, RegisterResource } from '~/core/resources';
import { IProject } from '../../project/dto';

@RegisterResource({ db: e.FieldRegion })
@ObjectType({
implements: [Resource],
})
export class FieldRegion extends Resource {
static readonly Relations = () =>
({
projects: [IProject],
} satisfies ResourceRelationsShape);

@NameField()
@DbUnique()
readonly name: SecuredString;
Expand Down
25 changes: 25 additions & 0 deletions src/components/field-region/field-region-projects.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Parent, ResolveField, Resolver } from '@nestjs/graphql';
import { ListArg } from '~/common';
import { Loader, type LoaderOf } from '~/core';
import { ProjectListInput, SecuredProjectList } from '../project/dto';
import { ProjectLoader } from '../project/project.loader';
import { FieldRegion } from './dto';
import { FieldRegionService } from './field-region.service';

@Resolver(FieldRegion)
export class FieldRegionProjectsResolver {
constructor(private readonly fieldRegionService: FieldRegionService) {}

@ResolveField(() => SecuredProjectList, {
description: 'The list of projects in this field region',
})
async projects(
@Parent() fieldRegion: FieldRegion,
@ListArg(ProjectListInput) input: ProjectListInput,
@Loader(ProjectLoader) projects: LoaderOf<ProjectLoader>,
): Promise<SecuredProjectList> {
const list = await this.fieldRegionService.listProjects(fieldRegion, input);
projects.primeAll(list.items);
return list;
}
}
4 changes: 4 additions & 0 deletions src/components/field-region/field-region.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { forwardRef, Module } from '@nestjs/common';
import { splitDb } from '~/core';
import { AuthorizationModule } from '../authorization/authorization.module';
import { FieldZoneModule } from '../field-zone/field-zone.module';
import { ProjectModule } from '../project/project.module';
import { UserModule } from '../user/user.module';
import { FieldRegionProjectsResolver } from './field-region-projects.resolver';
import { FieldRegionGelRepository } from './field-region.gel.repository';
import { FieldRegionLoader } from './field-region.loader';
import { FieldRegionRepository } from './field-region.repository';
Expand All @@ -14,10 +16,12 @@ import { RestrictRegionDirectorRemovalHandler } from './handlers/restrict-region
imports: [
forwardRef(() => AuthorizationModule),
FieldZoneModule,
forwardRef(() => ProjectModule),
forwardRef(() => UserModule),
],
providers: [
FieldRegionResolver,
FieldRegionProjectsResolver,
FieldRegionService,
splitDb(FieldRegionRepository, FieldRegionGelRepository),
FieldRegionLoader,
Expand Down
29 changes: 29 additions & 0 deletions src/components/field-region/field-region.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import {
import { HandleIdLookup } from '~/core';
import { IEventBus } from '~/core/events';
import { Privileges } from '../authorization';
import {
IProject,
type ProjectListInput,
type SecuredProjectList,
} from '../project/dto';
import { ProjectService } from '../project/project.service';
import { UserService } from '../user';
import {
type CreateFieldRegion,
Expand All @@ -28,6 +34,7 @@ export class FieldRegionService {
private readonly events: IEventBus,
private readonly users: UserService,
private readonly repo: FieldRegionRepository,
private readonly projectService: ProjectService,
) {}

async create(input: CreateFieldRegion): Promise<FieldRegion> {
Expand Down Expand Up @@ -115,4 +122,26 @@ export class FieldRegionService {
items: results.items.map((dto) => this.secure(dto)),
};
}

async listProjects(
fieldRegion: FieldRegion,
input: ProjectListInput,
): Promise<SecuredProjectList> {
const projectListOutput = await this.projectService.list({
...input,
filter: {
...input.filter,
fieldRegion: {
...(input.filter?.fieldRegion ?? {}),
id: fieldRegion.id,
},
},
});

return {
...projectListOutput,
canRead: true,
canCreate: this.privileges.for(IProject).can('create'),
};
}
}
7 changes: 7 additions & 0 deletions src/components/field-zone/dto/field-zone.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,25 @@ import {
DbUnique,
NameField,
Resource,
type ResourceRelationsShape,
type Secured,
SecuredProperty,
SecuredString,
} from '~/common';
import { e } from '~/core/gel';
import { type LinkTo, RegisterResource } from '~/core/resources';
import { IProject } from '../../project/dto';

@RegisterResource({ db: e.FieldZone })
@ObjectType({
implements: [Resource],
})
export class FieldZone extends Resource {
static readonly Relations = () =>
({
projects: [IProject],
} satisfies ResourceRelationsShape);

@NameField()
@DbUnique()
readonly name: SecuredString;
Expand Down
25 changes: 25 additions & 0 deletions src/components/field-zone/field-zone-projects.resolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Parent, ResolveField, Resolver } from '@nestjs/graphql';
import { ListArg } from '~/common';
import { Loader, type LoaderOf } from '~/core';
import { ProjectListInput, SecuredProjectList } from '../project/dto';
import { ProjectLoader } from '../project/project.loader';
import { FieldZone } from './dto';
import { FieldZoneService } from './field-zone.service';

@Resolver(FieldZone)
export class FieldZoneProjectsResolver {
constructor(private readonly fieldZoneService: FieldZoneService) {}

@ResolveField(() => SecuredProjectList, {
description: 'The list of projects in regions within this field zone',
})
async projects(
@Parent() fieldZone: FieldZone,
@ListArg(ProjectListInput) input: ProjectListInput,
@Loader(ProjectLoader) projects: LoaderOf<ProjectLoader>,
): Promise<SecuredProjectList> {
const list = await this.fieldZoneService.listProjects(fieldZone, input);
projects.primeAll(list.items);
return list;
}
}
4 changes: 4 additions & 0 deletions src/components/field-zone/field-zone.module.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { forwardRef, Module } from '@nestjs/common';
import { splitDb } from '~/core';
import { AuthorizationModule } from '../authorization/authorization.module';
import { ProjectModule } from '../project/project.module';
import { UserModule } from '../user/user.module';
import { FieldZoneProjectsResolver } from './field-zone-projects.resolver';
import { FieldZoneGelRepository } from './field-zone.gel.repository';
import { FieldZoneLoader } from './field-zone.loader';
import { FieldZoneRepository } from './field-zone.repository';
Expand All @@ -12,10 +14,12 @@ import { RestrictZoneDirectorRemovalHandler } from './handlers/restrict-zone-dir
@Module({
imports: [
forwardRef(() => AuthorizationModule),
forwardRef(() => ProjectModule),
forwardRef(() => UserModule),
],
providers: [
FieldZoneResolver,
FieldZoneProjectsResolver,
FieldZoneService,
splitDb(FieldZoneRepository, FieldZoneGelRepository),
FieldZoneLoader,
Expand Down
28 changes: 28 additions & 0 deletions src/components/field-zone/field-zone.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
import { HandleIdLookup } from '~/core';
import { IEventBus } from '~/core/events';
import { Privileges } from '../authorization';
import { type ProjectListInput, type SecuredProjectList } from '../project/dto';
import { ProjectService } from '../project/project.service';
import { UserService } from '../user';
import {
type CreateFieldZone,
Expand All @@ -28,6 +30,7 @@ export class FieldZoneService {
private readonly events: IEventBus,
private readonly users: UserService,
private readonly repo: FieldZoneRepository,
private readonly projectService: ProjectService,
) {}

async create(input: CreateFieldZone): Promise<FieldZone> {
Expand Down Expand Up @@ -115,4 +118,29 @@ export class FieldZoneService {
items: results.items.map((dto) => this.secure(dto)),
};
}

async listProjects(
fieldZone: FieldZone,
input: ProjectListInput,
): Promise<SecuredProjectList> {
const projectListOutput = await this.projectService.list({
...input,
filter: {
...input.filter,
fieldRegion: {
...(input.filter?.fieldRegion ?? {}),
fieldZone: {
...(input.filter?.fieldRegion?.fieldZone ?? {}),
id: fieldZone.id,
},
},
},
});

return {
...projectListOutput,
canRead: true,
canCreate: false, // Field zone doesn't own project creation
};
}
}
2 changes: 1 addition & 1 deletion src/components/location/location.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { DefaultMarketingRegionMigration } from './migrations/default-marketing-
imports: [
forwardRef(() => AuthorizationModule),
forwardRef(() => FundingAccountModule),
FieldRegionModule,
forwardRef(() => FieldRegionModule),
FileModule,
],
providers: [
Expand Down
5 changes: 4 additions & 1 deletion src/components/organization/organization.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import { OrganizationResolver } from './organization.resolver';
import { OrganizationService } from './organization.service';

@Module({
imports: [forwardRef(() => AuthorizationModule), LocationModule],
imports: [
forwardRef(() => AuthorizationModule),
forwardRef(() => LocationModule),
],
providers: [
OrganizationResolver,
OrganizationService,
Expand Down
Empty file.
Empty file.