Skip to content

Commit

Permalink
Copy over presence module from Hybridilusmu
Browse files Browse the repository at this point in the history
  • Loading branch information
joonashak committed Sep 11, 2024
1 parent 6ee6191 commit e68200e
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 1 deletion.
11 changes: 10 additions & 1 deletion app/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,19 @@ import { BoltModule } from "./bolt/bolt.module";
import { ConfigModule } from "./common/config/config.module";
import { DatabaseModule } from "./database/database.module";
import { OfficeModule } from "./entities/office/office.module";
import { PresenceModule } from "./entities/presence/presence.module";
import { UserSettingsModule } from "./entities/user-settings/user-settings.module";
import { UserModule } from "./entities/user/user.module";

@Module({
imports: [ConfigModule, DatabaseModule, BoltModule, OfficeModule, UserSettingsModule, UserModule],
imports: [
ConfigModule,
DatabaseModule,
BoltModule,
OfficeModule,
UserSettingsModule,
UserModule,
PresenceModule,
],
})
export class AppModule {}
8 changes: 8 additions & 0 deletions app/src/entities/presence/dto/presence.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { OmitType, PickType } from "@nestjs/swagger";
import { Presence } from "../presence.model";

export class UpsertPresenceDto extends OmitType(Presence, ["office"]) {}

export class SetOfficeDto extends PickType(Presence, ["userId", "date"]) {
officeId: number;
}
61 changes: 61 additions & 0 deletions app/src/entities/presence/presence.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Controller, InternalServerErrorException } from "@nestjs/common";
import dayjs from "dayjs";
import BoltAction from "../../bolt/decorators/bolt-action.decorator";
import BoltActions from "../../bolt/enums/bolt-actions.enum";
import { BoltActionArgs } from "../../bolt/types/bolt-action-types";
import { PresenceType } from "./presence.model";
import { PresenceService } from "./presence.service";

@Controller()
export class PresenceController {
constructor(private presenceService: PresenceService) {}

@BoltAction(BoltActions.SET_OFFICE_PRESENCE)
async setOfficePresence({ ack, body, payload }: BoltActionArgs) {
await ack();
const date = dayjs(payload["value"]).toDate();
await this.presenceService.upsert({
userId: body.user.id,
type: PresenceType.AT_OFFICE,
date,
});
}

@BoltAction(BoltActions.SET_REMOTE_PRESENCE)
async setRemotePresence({ ack, body, payload }: BoltActionArgs) {
await ack();
const date = dayjs(payload["value"]).toDate();
await this.presenceService.upsert({
userId: body.user.id,
type: PresenceType.REMOTE,
date,
});
}

@BoltAction(BoltActions.SELECT_OFFICE_FOR_DATE)
async selectOfficeForDate({ ack, body, payload }: BoltActionArgs) {
await ack();
const { value, date } = JSON.parse(payload["selected_option"].value);
await this.presenceService.setOffice({
userId: body.user.id,
date: dayjs(date).toDate(),
officeId: value,
});
}

// TODO: Should this be moved?
@BoltAction(BoltActions.DAY_LIST_ITEM_OVERFLOW)
async dayListItemOverflow({ ack, body, payload }: BoltActionArgs) {
await ack();
const { type, date } = JSON.parse(payload["selected_option"].value);

if (type !== "remove_presence") {
throw new InternalServerErrorException("Not implemented.");
}

await this.presenceService.remove({
userId: body.user.id,
date: dayjs(date).toDate(),
});
}
}
24 changes: 24 additions & 0 deletions app/src/entities/presence/presence.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Column, Entity, ManyToOne, PrimaryColumn, Repository } from "typeorm";
import { Office } from "../office/office.model";

export enum PresenceType {
AT_OFFICE = "at_office",
REMOTE = "remote",
}

@Entity()
export class Presence {
@PrimaryColumn()
userId: string;

@PrimaryColumn({ type: "date" })
date: Date;

@Column({ type: "enum", enum: PresenceType, nullable: true })
type: PresenceType | null;

@ManyToOne(() => Office, { nullable: true })
office: Office;
}

export type PresenceRepository = Repository<Presence>;
14 changes: 14 additions & 0 deletions app/src/entities/presence/presence.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { OfficeModule } from "../office/office.module";
import { PresenceController } from "./presence.controller";
import { Presence } from "./presence.model";
import { PresenceService } from "./presence.service";

@Module({
imports: [TypeOrmModule.forFeature([Presence]), OfficeModule],
providers: [PresenceService],
controllers: [PresenceController],
exports: [TypeOrmModule],
})
export class PresenceModule {}
47 changes: 47 additions & 0 deletions app/src/entities/presence/presence.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { DataSource } from "typeorm";
import { SetOfficeDto, UpsertPresenceDto } from "./dto/presence.dto";
import { Presence, PresenceRepository } from "./presence.model";

@Injectable()
export class PresenceService {
constructor(
@InjectRepository(Presence) private presenceRepository: PresenceRepository,
private dataSource: DataSource,
) {}

async remove(presence: Pick<Presence, "userId" | "date">) {
return this.presenceRepository.delete(presence);
}

async upsert(presence: Partial<UpsertPresenceDto>) {
// Select only existing cols for the upsert operation to avoid overriding
// existing data with defaults/nulls.
const primaryKeys = ["userId", "date"];
const updatableCols = Object.keys(presence).filter((key) => !primaryKeys.includes(key));

if (updatableCols.length === 0) {
return;
}

return this.dataSource
.createQueryBuilder()
.insert()
.into(Presence)
.values(presence)
.orUpdate(updatableCols, primaryKeys)
.execute();
}

async setOffice({ userId, date, officeId }: SetOfficeDto) {
await this.upsert({ userId, date });

return this.presenceRepository.update(
{ userId, date },
{
office: { id: officeId },
},
);
}
}

0 comments on commit e68200e

Please sign in to comment.