-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(bot): add initial migration, schemas and business logic
- Loading branch information
Showing
14 changed files
with
167 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
import type { Context } from 'grammy' | ||
import type { LoggingFlavor } from './plugins/logging' | ||
import type { TranslationsFlavor } from './plugins/translations' | ||
import type { DomainFlavor } from './plugins/domain' | ||
|
||
export type Ctx = | ||
& Context | ||
& LoggingFlavor | ||
& DomainFlavor | ||
& TranslationsFlavor |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import type { InstallFn } from '.' | ||
import type { User } from '~/domain/schemas/user' | ||
import type { Domain } from '~/domain' | ||
|
||
export type DomainOptions = { | ||
domain: Domain | ||
} | ||
|
||
export type DomainFlavor = { | ||
domain: Domain | ||
user?: User | ||
} | ||
|
||
export const install: InstallFn<DomainFlavor, DomainOptions> = (bot, { domain }) => { | ||
bot.use(async (ctx, next) => { | ||
ctx.domain = domain | ||
if (ctx.from) { | ||
ctx.user = await domain.upsertUser({ | ||
telegramId: ctx.from.id, | ||
username: ctx.from.username, | ||
firstName: ctx.from.first_name, | ||
lastName: ctx.from.last_name, | ||
notificationPreferences: { classes: [] }, | ||
}) | ||
} | ||
return next() | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { User } from './schemas/user' | ||
import type { Logger } from '~/lib/logging' | ||
import { type Database, Prisma } from '~/services/database' | ||
import type { Sport } from '~/services/sport' | ||
|
||
export class Domain { | ||
private logger: Logger | ||
private db: Database | ||
private sport: Sport | ||
|
||
constructor(options: { | ||
logger: Logger | ||
db: Database | ||
sport: Sport | ||
}) { | ||
this.logger = options.logger | ||
this.db = options.db | ||
this.sport = options.sport | ||
} | ||
|
||
public async upsertUser({ | ||
telegramId, | ||
...data | ||
}: Omit<Partial<User> & Pick<User, 'telegramId' | 'firstName' | 'notificationPreferences'>, 'createdAt'>): Promise<User> { | ||
const user = await this.db.user.upsert({ | ||
where: { telegramId }, | ||
create: { telegramId, ...data }, | ||
update: { ...data }, | ||
}) | ||
return User.parse(user) | ||
} | ||
|
||
public async updateUser({ | ||
telegramId, | ||
...patch | ||
}: Partial<User> & Pick<User, 'telegramId'>): Promise<User> { | ||
const user = await this.db.user.update({ | ||
where: { telegramId }, | ||
data: patch, | ||
}) | ||
return User.parse(user) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import { z } from 'zod' | ||
|
||
export const Language = z.string().regex(/^[a-z]{2}$/) | ||
export type Language = z.infer<typeof Language> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './notifications' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { z } from 'zod' | ||
|
||
export const ClassesNotificationPreferenceSpecificTime = z.object({ | ||
type: z.literal('specific-time'), | ||
daysBefore: z.number().int(), | ||
time: z.object({ | ||
hours: z.number().int(), | ||
minutes: z.number().int(), | ||
}), | ||
}) | ||
export type ClassesNotificationPreferenceSpecificTime = z.infer<typeof ClassesNotificationPreferenceSpecificTime> | ||
|
||
export const ClassesNotificationPreferenceRelative = z.object({ | ||
type: z.literal('relative'), | ||
minutesBefore: z.number().int(), | ||
}) | ||
export type ClassesNotificationPreferenceRelative = z.infer<typeof ClassesNotificationPreferenceRelative> | ||
|
||
export const ClassesNotificationPreference = z.union([ | ||
ClassesNotificationPreferenceSpecificTime, | ||
ClassesNotificationPreferenceRelative, | ||
]) | ||
export type ClassesNotificationPreference = z.infer<typeof ClassesNotificationPreference> | ||
|
||
export const NotificationPreferences = z.object({ | ||
classes: z.array(ClassesNotificationPreference), | ||
}) | ||
export type NotificationPreferences = z.infer<typeof NotificationPreferences> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { z } from 'zod' | ||
import { Language } from './common' | ||
import { NotificationPreferences } from './notifications' | ||
|
||
export const User = z.object({ | ||
telegramId: z.coerce.number().int(), | ||
createdAt: z.date(), | ||
username: z.string().nullable(), | ||
firstName: z.string(), | ||
lastName: z.string().nullable(), | ||
language: Language.nullable(), | ||
notificationPreferences: NotificationPreferences, | ||
}) | ||
export type User = z.infer<typeof User> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
backend/src/services/database/migrations/20240310111305_add_user_model/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
-- CreateTable | ||
CREATE TABLE "User" ( | ||
"telegramId" BIGINT NOT NULL, | ||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
"username" TEXT, | ||
"firstName" TEXT NOT NULL, | ||
"lastName" TEXT, | ||
"language" TEXT, | ||
"notificationPreferences" JSONB NOT NULL, | ||
|
||
CONSTRAINT "User_pkey" PRIMARY KEY ("telegramId") | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Please do not edit this file manually | ||
# It should be added in your version-control system (i.e. Git) | ||
provider = "postgresql" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export class Sport { | ||
|
||
} |