Skip to content

Commit

Permalink
Merge pull request #51 from aura-nw/dev
Browse files Browse the repository at this point in the history
fix create chapter
  • Loading branch information
ThienLK1 authored Aug 27, 2024
2 parents 8607d6d + 995a5f1 commit 12ac71b
Show file tree
Hide file tree
Showing 24 changed files with 406 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
table:
name: telegram_users
schema: public
object_relationships:
- name: authorizer_user
using:
foreign_key_constraint_on: user_id
1 change: 1 addition & 0 deletions hasura/metadata/databases/punkga-pg/tables/tables.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
- "!include public_system_key.yaml"
- "!include public_tag_languages.yaml"
- "!include public_tags.yaml"
- "!include public_telegram_users.yaml"
- "!include public_user_campaign.yaml"
- "!include public_user_campaign_reward.yaml"
- "!include public_user_level.yaml"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DROP TABLE "public"."telegram_users";
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
CREATE TABLE "public"."telegram_users" ("id" serial NOT NULL, "telegram_id" text NOT NULL, "username" text NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") );
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
RETURNS TRIGGER AS $$
DECLARE
_new record;
BEGIN
_new := NEW;
_new."updated_at" = NOW();
RETURN _new;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER "set_public_telegram_users_updated_at"
BEFORE UPDATE ON "public"."telegram_users"
FOR EACH ROW
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
COMMENT ON TRIGGER "set_public_telegram_users_updated_at" ON "public"."telegram_users"
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."telegram_users" add column "user_id" bpchar
-- null;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
alter table "public"."telegram_users" add column "user_id" bpchar
null;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
alter table "public"."telegram_users" drop constraint "telegram_users_user_id_fkey";
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
alter table "public"."telegram_users"
add constraint "telegram_users_user_id_fkey"
foreign key ("user_id")
references "public"."authorizer_users"
("id") on update set null on delete set null;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
alter table "public"."telegram_users" drop constraint "telegram_users_telegram_id_key";
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
alter table "public"."telegram_users" add constraint "telegram_users_telegram_id_key" unique ("telegram_id");
2 changes: 2 additions & 0 deletions src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { ChainModule } from './modules/chain/chain.module';
import { ChainGateWayModule } from './chain-gateway/chain-gateway.module';
import { ArtworkModule } from './modules/artwork/artwork.module';
import { AlbumModule } from './modules/album/album.module';
import { TelegramModule } from './modules/telegram/telegram.module';

@Module({
imports: [
Expand Down Expand Up @@ -75,6 +76,7 @@ import { AlbumModule } from './modules/album/album.module';
ChainGateWayModule,
ArtworkModule,
AlbumModule,
TelegramModule,
],
controllers: [],
providers: [
Expand Down
121 changes: 117 additions & 4 deletions src/auth/auth.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,102 @@ import {
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
// import { jwtConstants } from './constants';
import { createHmac } from 'crypto';
import { Request } from 'express';
import { readFile } from 'fs/promises';
import * as path from 'path';
import { ITelegramUser } from './interfaces/telegram-user.interface';
import { GraphqlService } from '../modules/graphql/graphql.service';
import { Role } from './role.enum';

@Injectable()
export class AuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
constructor(
private jwtService: JwtService,
private configService: ConfigService,
private graphqlSvc: GraphqlService
) {}

async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = this.extractTokenFromHeader(request);
const token = this.extractBrearerTokenFromHeader(request);
if (token) {
return this.bearerAuth(request);
}

return this.telegramAuth(request);
}

private async telegramAuth(request: Request) {
const telegramInitData = this.extractTelegramInitData(request);
if (!telegramInitData) {
throw new UnauthorizedException();
}

const user: ITelegramUser = this.verifyTelegramWebAppData(telegramInitData);
// insert user

if (!user) {
throw new UnauthorizedException();
}

const insertResult = await this.insertTelegramUser({
object: {
telegram_id: user.id.toString(),
username: user.username,
},
});
if (insertResult.errors)
throw new UnauthorizedException(JSON.stringify(insertResult));

request['user'] = {
userId: insertResult.data.insert_telegram_users_one.authorizer_user?.id,
roles: [Role.TelegramUser],
telegramUserId: insertResult.data.insert_telegram_users_one.id,
};

return true;
}

private verifyTelegramWebAppData(telegramInitData: string) {
const TELEGRAM_BOT_TOKEN =
this.configService.get<string>('telgram.bot_token');
// / The data is a query string, which is composed of a series of field-value pairs.
const encoded = decodeURIComponent(telegramInitData);

// HMAC-SHA-256 signature of the bot's token with the constant string WebAppData used as a key.
const secret = createHmac('sha256', 'WebAppData').update(
TELEGRAM_BOT_TOKEN
);

// Data-check-string is a chain of all received fields'.
const arr = encoded.split('&');
const hashIndex = arr.findIndex((str) => str.startsWith('hash='));
const hash = arr.splice(hashIndex)[0].split('=')[1];
// sorted alphabetically
arr.sort((a, b) => a.localeCompare(b));
// in the format key=<value> with a line feed character ('\n', 0x0A) used as separator
// e.g., 'auth_date=<auth_date>\nquery_id=<query_id>\nuser=<user>
const dataCheckString = arr.join('\n');

// The hexadecimal representation of the HMAC-SHA-256 signature of the data-check-string with the secret key
const _hash = createHmac('sha256', secret.digest())
.update(dataCheckString)
.digest('hex');

// if hash are equal the data may be used on your server.
// Complex data types are represented as JSON-serialized objects.
if (_hash !== hash) throw new UnauthorizedException();

const userIndex = arr.findIndex((str) => str.startsWith('user='));
const user = JSON.parse(arr.splice(userIndex)[0].split('=')[1]);
return user;
}

private async bearerAuth(request: Request): Promise<boolean> {
const token = this.extractBrearerTokenFromHeader(request);
if (!token) {
throw new UnauthorizedException();
}
Expand All @@ -43,8 +126,38 @@ export class AuthGuard implements CanActivate {
return true;
}

private extractTokenFromHeader(request: Request): string | undefined {
private extractBrearerTokenFromHeader(request: Request): string | undefined {
const [type, token] = request.headers.authorization?.split(' ') ?? [];
return type === 'Bearer' ? token : undefined;
}

private extractTelegramInitData(request: Request): string | undefined {
return request.headers.authorization;
}

private insertTelegramUser(variables: any) {
const headers = {
'x-hasura-admin-secret': this.configService.get<string>(
'graphql.adminSecret'
),
};

return this.graphqlSvc.query(
this.configService.get<string>('graphql.endpoint'),
'',
`mutation insert_telegram_users_one($object: telegram_users_insert_input = {}) {
insert_telegram_users_one(object: $object, on_conflict: {constraint: telegram_users_telegram_id_key, update_columns: updated_at}) {
id
authorizer_user {
id
email
nickname
}
}
}`,
'insert_telegram_users_one',
variables,
headers
);
}
}
1 change: 1 addition & 0 deletions src/auth/dto/user.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export class UserDto {
userId: string;
roles: string[];
token: string;
telegramUserId?: string;
}
4 changes: 4 additions & 0 deletions src/auth/interfaces/telegram-user.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface ITelegramUser {
id: string;
username: string;
}
1 change: 1 addition & 0 deletions src/auth/role.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export enum Role {
User = 'user',
Creator = 'creator',
Admin = 'admin',
TelegramUser = 'telegram_user',
}
4 changes: 3 additions & 1 deletion src/modules/album/album.graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export class AlbumGraphql {
name
show
disable
thumbnail_url
created_at
artworks_aggregate(where: {creator_id: {_eq: $creator_id}}) {
aggregate {
Expand All @@ -36,14 +37,15 @@ export class AlbumGraphql {
name
show
disable
thumbnail_url
created_at
artworks_aggregate {
aggregate {
count
}
}
}
}
}
`,
'list_album',
variables,
Expand Down
7 changes: 5 additions & 2 deletions src/modules/album/album.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ export class AlbumService {
},
});

if (result.errors) return result;

const albumId = result.data.insert_albums_one.id;

let thumbnail_url = '';
Expand Down Expand Up @@ -88,6 +90,7 @@ export class AlbumService {
if (thumbnail_url !== '') {
const updateResult = await this.albumGraphql.update({
id: albumId,
creator_id: creatorId,
data: {
thumbnail_url,
},
Expand Down Expand Up @@ -124,8 +127,8 @@ export class AlbumService {
const { limit, offset } = query;
return this.albumGraphql.getListAlbum({
creator_id: creatorId,
limit,
offset,
limit: Number(limit),
offset: Number(offset),
});
}

Expand Down
41 changes: 24 additions & 17 deletions src/modules/chapter/chapter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,18 @@ export class ChapterService {
return updateResult;
}
}
const collectionIdListStr = collection_ids.toString().split(',');
let collectionIdList = Array.from(collectionIdListStr, Number);
const updateResult = await this.addChapterCollection(
chapterId,
collectionIdList
);
if (updateResult.errors && updateResult.errors.length > 0) {
return updateResult;
if (collection_ids) {
const collectionIdListStr = collection_ids.toString().split(',');
let collectionIdList = Array.from(collectionIdListStr, Number);
if (collectionIdList.length > 0) {
const updateResult = await this.addChapterCollection(
chapterId,
collectionIdList
);
if (updateResult.errors && updateResult.errors.length > 0) {
return updateResult;
}
}
}
return result.data;
} catch (errors) {
Expand Down Expand Up @@ -252,15 +256,18 @@ export class ChapterService {
UpdateChapterImage,
JSON.parse(data.chapter_images)
);

const collectionIdListStr = collection_ids.toString().split(',');
let collectionIdList = Array.from(collectionIdListStr, Number);
const updateResult = await this.addChapterCollection(
chapter_id,
collectionIdList
);
if (updateResult.errors && updateResult.errors.length > 0) {
return updateResult;
if (collection_ids) {
const collectionIdListStr = collection_ids.toString().split(',');
let collectionIdList = Array.from(collectionIdListStr, Number);
if (collectionIdList.length > 0) {
const updateResult = await this.addChapterCollection(
chapter_id,
collectionIdList
);
if (updateResult.errors && updateResult.errors.length > 0) {
return updateResult;
}
}
}
// upload chapter languages
const uploadChapterResult =
Expand Down
3 changes: 2 additions & 1 deletion src/modules/graphql/graphql.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Module } from '@nestjs/common';
import { Global, Module } from '@nestjs/common';
import { GraphqlService } from './graphql.service';

@Global()
@Module({
providers: [GraphqlService],
exports: [GraphqlService],
Expand Down
9 changes: 9 additions & 0 deletions src/modules/telegram/dto/link-user.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { ApiProperty } from '@nestjs/swagger';

export class LinkUserDto {
@ApiProperty()
email: string;

@ApiProperty()
password: string;
}
Loading

0 comments on commit 12ac71b

Please sign in to comment.