Skip to content

Commit

Permalink
Release dev to master (#345)
Browse files Browse the repository at this point in the history
## RecNet auto-release action
This is an auto-generated PR by recnet-release-action 🤖
Please make sure to test your changes in staging before merging. 
## Related Issues
- #341
- #335
- #301
- #260
- #261
- #342
## Related PRs
- #346
- #344
- #343
## Staging links
recnet-web:
[https://vercel.live/link/recnet-git-dev-recnet-542617e7.vercel.app](https://vercel.live/link/recnet-git-dev-recnet-542617e7.vercel.app)
recnet-api:
[https://dev-api.recnet.io/api](https://dev-api.recnet.io/api)
  • Loading branch information
swh00tw authored Oct 29, 2024
2 parents 923ce3c + c4daef1 commit 399f7cb
Show file tree
Hide file tree
Showing 49 changed files with 1,090 additions and 1,030 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/recnet-api-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ name: recnet-api-ci
on:
push:
paths:
- 'apps/recnet-api/package.json'
- "apps/recnet-api/package.json"

jobs:
version_bump:
runs-on: ubuntu-latest
permissions: write-all
if: github.event_name == 'push' &&
github.ref == 'refs/heads/master'
github.ref == 'refs/heads/master'
steps:
- name: Checkout code
uses: actions/checkout@v2
Expand Down
3 changes: 3 additions & 0 deletions apps/recnet-api/.env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ export PRISMA_DATABASE_URL="postgresql://postgres:admin@localhost:5432/postgres?
# SMTP
export SMTP_USER="lil.recnet@gmail.com"
export SMTP_PASS="ask for password"

# SLACK
export SLACK_TOKEN="ask for token"
5 changes: 5 additions & 0 deletions apps/recnet-api/.eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
{
"files": ["*.js", "*.jsx"],
"rules": {}
},
{
"files": ["*.json"],
"parser": "jsonc-eslint-parser",
"rules": {}
}
]
}
2 changes: 1 addition & 1 deletion apps/recnet-api/package.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"name": "recnet-api",
"version": "1.7.2"
"version": "1.8.0"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-- DropForeignKey
ALTER TABLE "Subscription" DROP CONSTRAINT "Subscription_userId_fkey";

-- AlterTable
ALTER TABLE "User" DROP COLUMN "slackEmail";

-- DropTable
DROP TABLE "Subscription";

-- DropEnum
DROP TYPE "Channel";

-- DropEnum
DROP TYPE "SubscriptionType";

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-- CreateEnum
CREATE TYPE "Channel" AS ENUM ('EMAIL', 'SLACK');

-- CreateEnum
CREATE TYPE "SubscriptionType" AS ENUM ('WEEKLY_DIGEST');

-- AlterTable
ALTER TABLE "User" ADD COLUMN "slackEmail" VARCHAR(128);

-- CreateTable
CREATE TABLE "Subscription" (
"id" SERIAL NOT NULL,
"userId" VARCHAR(64) NOT NULL,
"type" "SubscriptionType" NOT NULL,
"channel" "Channel" NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT "Subscription_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE UNIQUE INDEX "Subscription_userId_type_channel_key" ON "Subscription"("userId", "type", "channel");

-- AddForeignKey
ALTER TABLE "Subscription" ADD CONSTRAINT "Subscription_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
25 changes: 25 additions & 0 deletions apps/recnet-api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ enum ReactionType {
// Add other reactions here as needed
}

enum Channel {
EMAIL
SLACK
// Add other channels here as needed
}

enum SubscriptionType {
WEEKLY_DIGEST
// Add other subscription types here as needed
}

model User {
id String @id @default(uuid()) @db.VarChar(64) // Primary key, UUID type
provider Provider // Enum type
Expand All @@ -65,6 +76,7 @@ model User {
lastLoginAt DateTime
role Role @default(USER) // Enum type
isActivated Boolean @default(true)
slackEmail String? @db.VarChar(128)
createdAt DateTime @default(now())
updatedAt DateTime @default(now()) @updatedAt
Expand All @@ -75,6 +87,7 @@ model User {
inviteCodeUsed InviteCode? @relation("InviteCodeUsedBy")
announcements Announcement[]
recReactions RecReaction[]
subscriptions Subscription[]
@@unique([provider, providerId])
}
Expand Down Expand Up @@ -170,6 +183,18 @@ model RecReaction {
@@unique([userId, recId, reaction])
}

model Subscription {
id Int @id @default(autoincrement())
userId String @db.VarChar(64)
type SubscriptionType
channel Channel
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id])
@@unique([userId, type, channel])
}

model WeeklyDigestCronLog {
id Int @id @default(autoincrement())
cutoff DateTime
Expand Down
2 changes: 2 additions & 0 deletions apps/recnet-api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { HealthModule } from "./modules/health/health.module";
import { InviteCodeModule } from "./modules/invite-code/invite-code.module";
import { RecModule } from "./modules/rec/rec.module";
import { StatModule } from "./modules/stat/stat.module";
import { SubscriptionModule } from "./modules/subscription/subscription.module";
import { UserModule } from "./modules/user/user.module";
import { LoggerMiddleware } from "./utils/middlewares/logger.middleware";

Expand All @@ -30,6 +31,7 @@ import { LoggerMiddleware } from "./utils/middlewares/logger.middleware";
StatModule,
EmailModule,
AnnouncementModule,
SubscriptionModule,
],
controllers: [],
providers: [],
Expand Down
4 changes: 4 additions & 0 deletions apps/recnet-api/src/config/common.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@ export const NodemailerConfig = registerAs("nodemailer", () => ({
user: parsedEnv.SMTP_USER,
pass: parsedEnv.SMTP_PASS,
}));

export const SlackConfig = registerAs("slack", () => ({
token: parsedEnv.SLACK_TOKEN,
}));
2 changes: 2 additions & 0 deletions apps/recnet-api/src/config/env.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ export const EnvSchema = z.object({
SMTP_SECURE: z.string().optional().default("true"),
SMTP_USER: z.string(),
SMTP_PASS: z.string(),
// slack config
SLACK_TOKEN: z.string().optional(),
});

export const parseEnv = (env: Record<string, string | undefined>) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export const user = Prisma.validator<Prisma.UserDefaultArgs>()({
},
},
email: true,
slackEmail: true,
role: true,
isActivated: true,
following: {
Expand Down
29 changes: 5 additions & 24 deletions apps/recnet-api/src/modules/announcement/announcement.service.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
import { HttpStatus, Inject, Injectable } from "@nestjs/common";

import AnnouncementRepository from "@recnet-api/database/repository/announcement.repository";
import {
AnnouncementFilterBy,
Announcement as DbAnnouncement,
} from "@recnet-api/database/repository/announcement.repository.type";
import { AnnouncementFilterBy } from "@recnet-api/database/repository/announcement.repository.type";
import { getOffset } from "@recnet-api/utils";
import { RecnetError } from "@recnet-api/utils/error/recnet.error";
import { ErrorCode } from "@recnet-api/utils/error/recnet.error.const";

import { GetAnnouncementsResponse } from "./announcement.response";
import { transformAnnouncement } from "./announcement.transform";
import { CreateAnnouncementDto } from "./dto/create.announcement.dto";
import { UpdateAnnouncementDto } from "./dto/update.announcement.dto";
import { Announcement } from "./entities/announcement.entity";

import { transformUserPreview } from "../user/user.transformer";

@Injectable()
export class AnnouncementService {
constructor(
Expand All @@ -39,7 +35,7 @@ export class AnnouncementService {
return {
hasNext: dbAnnouncements.length + getOffset(page, pageSize) < totalCount,
totalCount,
announcements: dbAnnouncements.map(this.transformAnnouncement),
announcements: dbAnnouncements.map(transformAnnouncement),
};
}

Expand All @@ -59,7 +55,7 @@ export class AnnouncementService {
const dbAnnouncement = await this.announcementRepository.createAnnouncement(
createAnnouncementInput
);
return this.transformAnnouncement(dbAnnouncement);
return transformAnnouncement(dbAnnouncement);
}

public async updateAnnouncement(
Expand Down Expand Up @@ -99,21 +95,6 @@ export class AnnouncementService {
id,
updateAnnouncementInput
);
return this.transformAnnouncement(updatedDbAnnouncement);
}

private transformAnnouncement(dbAnnouncement: DbAnnouncement): Announcement {
const { createdBy } = dbAnnouncement;
const createdByUserPreview = transformUserPreview(createdBy);
return {
id: dbAnnouncement.id,
title: dbAnnouncement.title,
content: dbAnnouncement.content,
startAt: dbAnnouncement.startAt,
endAt: dbAnnouncement.endAt,
isActivated: dbAnnouncement.isActivated,
allowClose: dbAnnouncement.allowClose,
createdBy: createdByUserPreview,
};
return transformAnnouncement(updatedDbAnnouncement);
}
}
21 changes: 21 additions & 0 deletions apps/recnet-api/src/modules/announcement/announcement.transform.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Announcement as DbAnnouncement } from "@recnet-api/database/repository/announcement.repository.type";
import { transformUserPreview } from "@recnet-api/modules/user/user.transformer";

import { Announcement } from "./entities/announcement.entity";

export const transformAnnouncement = (
dbAnnouncement: DbAnnouncement
): Announcement => {
const { createdBy } = dbAnnouncement;
const createdByUserPreview = transformUserPreview(createdBy);
return {
id: dbAnnouncement.id,
title: dbAnnouncement.title,
content: dbAnnouncement.content,
startAt: dbAnnouncement.startAt,
endAt: dbAnnouncement.endAt,
isActivated: dbAnnouncement.isActivated,
allowClose: dbAnnouncement.allowClose,
createdBy: createdByUserPreview,
};
};
32 changes: 30 additions & 2 deletions apps/recnet-api/src/modules/email/email.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import { render } from "@react-email/render";
import groupBy from "lodash.groupby";

import { AppConfig, NodemailerConfig } from "@recnet-api/config/common.config";
import AnnouncementRepository from "@recnet-api/database/repository/announcement.repository";
import InviteCodeRepository from "@recnet-api/database/repository/invite-code.repository";
import RecRepository from "@recnet-api/database/repository/rec.repository";
import { RecFilterBy } from "@recnet-api/database/repository/rec.repository.type";
import UserRepository from "@recnet-api/database/repository/user.repository";
import { User as DbUser } from "@recnet-api/database/repository/user.repository.type";
import WeeklyDigestCronLogRepository from "@recnet-api/database/repository/weekly-digest-cron-log.repository";
import { transformAnnouncement } from "@recnet-api/modules/announcement/announcement.transform";
import { Rec } from "@recnet-api/modules/rec/entities/rec.entity";
import { transformRec } from "@recnet-api/modules/rec/rec.transformer";
import { sleep } from "@recnet-api/utils";
Expand Down Expand Up @@ -40,7 +43,11 @@ export class EmailService {
@Inject(RecRepository)
private readonly recRepository: RecRepository,
@Inject(WeeklyDigestCronLogRepository)
private readonly weeklyDigestCronLogRepository: WeeklyDigestCronLogRepository
private readonly weeklyDigestCronLogRepository: WeeklyDigestCronLogRepository,
@Inject(InviteCodeRepository)
private readonly inviteCodeRepository: InviteCodeRepository,
@Inject(AnnouncementRepository)
private readonly announcementRepository: AnnouncementRepository
) {}

@Cron(WEEKLY_DIGEST_CRON, { utcOffset: 0 })
Expand Down Expand Up @@ -134,13 +141,34 @@ export class EmailService {
const words = titleLowercase.split(" ").filter((w) => w.length > 0);
return words.join("");
});
const numUnusedInviteCodes =
await this.inviteCodeRepository.countInviteCodes({
used: false,
ownerId: user.id,
});
const currentActivatedAnnouncements =
await this.announcementRepository.findAnnouncements(1, 1, {
activatedOnly: true,
currentOnly: true,
});
const latestAnnouncement =
currentActivatedAnnouncements.length > 0
? transformAnnouncement(currentActivatedAnnouncements[0])
: undefined;

// send email
const mailOptions = {
from: this.nodemailerConfig.user,
to: user.email,
subject: WeeklyDigestSubject(cutoff, this.appConfig.nodeEnv),
html: render(WeeklyDigest({ recsGroupByTitle })),
html: render(
WeeklyDigest({
env: this.appConfig.nodeEnv,
recsGroupByTitle,
numUnusedInviteCodes,
latestAnnouncement,
})
),
};

let result;
Expand Down
Loading

0 comments on commit 399f7cb

Please sign in to comment.