feat: streak

This commit is contained in:
Nevo David 2026-01-28 14:53:45 +07:00
parent aa17498a52
commit c3cdee5c21
7 changed files with 86 additions and 4 deletions

View file

@ -25,4 +25,9 @@ export class EmailActivity {
async getUserOrgs(id: string) {
return this._organizationService.getTeam(id);
}
@ActivityMethod()
async setStreak(organizationId: string, type: 'start' | 'end') {
return this._organizationService.setStreak(organizationId, type);
}
}

View file

@ -83,7 +83,11 @@ export class PostActivity {
@ActivityMethod()
async getPostsList(orgId: string, postId: string) {
const getPosts = await this._postService.getPostsRecursively(postId, true, orgId);
const getPosts = await this._postService.getPostsRecursively(
postId,
true,
orgId
);
if (!getPosts || getPosts.length === 0 || getPosts[0].parentPostId) {
return [];
}
@ -155,7 +159,7 @@ export class PostActivity {
posts
);
return getIntegration.post(
const postNow = await getIntegration.post(
integration.internalId,
integration.token,
await Promise.all(
@ -179,6 +183,23 @@ export class PostActivity {
),
integration
);
await this._temporalService.client
.getRawClient()
.workflow.start('streakWorkflow', {
args: [{ organizationId: integration.organizationId }],
workflowId: `streak_${integration.organizationId}`,
taskQueue: 'main',
workflowIdConflictPolicy: 'TERMINATE_EXISTING',
typedSearchAttributes: new TypedSearchAttributes([
{
key: organizationId,
value: integration.organizationId,
},
]),
});
return postNow;
}
@ActivityMethod()

View file

@ -4,3 +4,4 @@ export * from './digest.email.workflow';
export * from './missing.post.workflow';
export * from './send.email.workflow';
export * from './refresh.token.workflow';
export * from './streak.workflow';

View file

@ -0,0 +1,28 @@
import { proxyActivities, sleep } from '@temporalio/workflow';
import { EmailActivity } from '@gitroom/orchestrator/activities/email.activity';
const { sendEmailAsync, getUserOrgs, setStreak } = proxyActivities<EmailActivity>({
startToCloseTimeout: '10 minute',
taskQueue: 'main',
cancellationType: 'ABANDON',
});
export async function streakWorkflow({
organizationId,
}: {
organizationId: string;
}) {
await setStreak(organizationId, 'start');
await sleep(79200000);
const userOrgs = await getUserOrgs(organizationId);
for (const user of userOrgs.users) {
await sendEmailAsync(
user.user.email,
'Streak Reminder',
'<p>You are about to lose your streak in two hours! schedule a post now to keep it!</p>',
'bottom'
);
}
await sleep(7200000);
await setStreak(organizationId, 'end');
}

View file

@ -260,6 +260,25 @@ export class OrganizationRepository {
});
}
async setStreak(organizationId: string, type: 'start' | 'end') {
try {
await this._organization.model.organization.update({
where: {
id: organizationId,
...(type === 'start'
? {
streakSince: null,
}
: {}),
},
data: {
...(type === 'end' ? { streakSince: null } : {}),
...(type === 'start' ? { streakSince: new Date() } : {}),
},
});
} catch (err) {}
}
async getTeam(orgId: string) {
return this._organization.model.organization.findUnique({
where: {

View file

@ -65,6 +65,10 @@ export class OrganizationService {
return this._organizationRepository.getTeam(orgId);
}
async setStreak(organizationId: string, type: 'start' | 'end') {
return this._organizationRepository.setStreak(organizationId, type);
}
getOrgByCustomerId(customerId: string) {
return this._organizationRepository.getOrgByCustomerId(customerId);
}

View file

@ -14,6 +14,7 @@ model Organization {
description String?
apiKey String?
paymentId String?
streakSince DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
allowTrial Boolean @default(false)
@ -30,8 +31,8 @@ model Organization {
buyerOrganization MessagesGroup[]
notifications Notifications[]
plugs Plugs[]
post Post[] @relation("organization")
submittedPost Post[] @relation("submittedForOrg")
post Post[] @relation("organization")
submittedPost Post[] @relation("submittedForOrg")
sets Sets[]
signatures Signatures[]
subscription Subscription?
@ -40,6 +41,9 @@ model Organization {
usedCodes UsedCodes[]
users UserOrganization[]
webhooks Webhooks[]
@@index([streakSince])
@@index([paymentId])
}
model Tags {