formatting to our pj layout
This commit is contained in:
parent
8f56724bac
commit
da9c292adf
259
app/app.go
259
app/app.go
@ -1,259 +0,0 @@
|
|||||||
package app
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/go-redis/redis/v8"
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"github.com/skeris/appInit"
|
|
||||||
"github.com/themakers/hlog"
|
|
||||||
"go.uber.org/zap"
|
|
||||||
"go.uber.org/zap/zapcore"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/penahub_common/log_mw"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/penahub_common/privilege"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/healthchecks"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/middleware"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/brokers"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/clients/auth"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/clients/telegram"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/initialize"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/models"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/server"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/service"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/tools"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/workers"
|
|
||||||
"penahub.gitlab.yandexcloud.net/external/trashlog/wrappers/zaptrashlog"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type App struct {
|
|
||||||
logger *zap.Logger
|
|
||||||
err chan error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a App) GetLogger() *zap.Logger {
|
|
||||||
return a.logger
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a App) GetErr() chan error {
|
|
||||||
return a.err
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
errInvalidOptions = errors.New("invalid options")
|
|
||||||
)
|
|
||||||
|
|
||||||
var zapOptions = []zap.Option{
|
|
||||||
zap.AddCaller(),
|
|
||||||
zap.AddCallerSkip(2),
|
|
||||||
zap.AddStacktrace(zap.ErrorLevel),
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ appInit.CommonApp = (*App)(nil)
|
|
||||||
|
|
||||||
type Options struct {
|
|
||||||
LoggerProdMode bool `env:"IS_PROD_LOG" default:"false"`
|
|
||||||
IsProd bool `env:"IS_PROD" default:"false"`
|
|
||||||
NumberPort string `env:"PORT" default:"1488"`
|
|
||||||
CrtFile string `env:"CRT" default:"server.crt"`
|
|
||||||
KeyFile string `env:"KEY" default:"server.key"`
|
|
||||||
PostgresCredentials string `env:"PG_CRED" default:"host=localhost port=35432 user=squiz password=Redalert2 dbname=squiz sslmode=disable"`
|
|
||||||
HubAdminUrl string `env:"HUB_ADMIN_URL" default:"http://localhost:8001/"`
|
|
||||||
ServiceName string `env:"SERVICE_NAME" default:"squiz"`
|
|
||||||
AuthServiceURL string `env:"AUTH_URL" default:"http://localhost:8000/"`
|
|
||||||
GrpcHost string `env:"GRPC_HOST" default:"localhost"`
|
|
||||||
GrpcPort string `env:"GRPC_PORT" default:"9000"`
|
|
||||||
KafkaBrokers string `env:"KAFKA_BROKERS" default:"localhost:9092"`
|
|
||||||
KafkaTopic string `env:"KAFKA_TOPIC" default:"test-topic"`
|
|
||||||
KafkaGroup string `env:"KAFKA_GROUP" default:"mailnotifier"`
|
|
||||||
TrashLogHost string `env:"TRASH_LOG_HOST" default:"localhost:7113"`
|
|
||||||
ModuleLogger string `env:"MODULE_LOGGER" default:"core-local"`
|
|
||||||
ClickHouseCred string `env:"CLICK_HOUSE_CRED" default:"tcp://10.8.0.15:9000/default?sslmode=disable"`
|
|
||||||
RedisHost string `env:"REDIS_HOST" default:"localhost:6379"`
|
|
||||||
RedisPassword string `env:"REDIS_PASSWORD" default:"admin"`
|
|
||||||
RedisDB uint64 `env:"REDIS_DB" default:"2"`
|
|
||||||
S3Prefix string `env:"S3_PREFIX"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(ctx context.Context, opts interface{}, ver appInit.Version) (appInit.CommonApp, error) {
|
|
||||||
var (
|
|
||||||
err, workerErr error
|
|
||||||
zapLogger *zap.Logger
|
|
||||||
errChan = make(chan error)
|
|
||||||
options Options
|
|
||||||
ok bool
|
|
||||||
)
|
|
||||||
|
|
||||||
if options, ok = opts.(Options); !ok {
|
|
||||||
return App{}, errInvalidOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.LoggerProdMode {
|
|
||||||
zapLogger, err = zap.NewProduction(zapOptions...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
zapLogger, err = zap.NewDevelopment(zapOptions...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
zapLogger = zapLogger.With(
|
|
||||||
zap.String("SvcCommit", ver.Commit),
|
|
||||||
zap.String("SvcVersion", ver.Release),
|
|
||||||
zap.String("SvcBuildTime", ver.BuildTime),
|
|
||||||
)
|
|
||||||
|
|
||||||
clickHouseLogger, err := zaptrashlog.NewCore(ctx, zap.InfoLevel, options.TrashLogHost, ver.Release, ver.Commit, time.Now().Unix())
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
loggerForHlog := zapLogger.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core {
|
|
||||||
return zapcore.NewTee(core, clickHouseLogger)
|
|
||||||
}))
|
|
||||||
|
|
||||||
loggerHlog := hlog.New(loggerForHlog).Module(options.ModuleLogger)
|
|
||||||
loggerHlog.With(models.AllFields{})
|
|
||||||
loggerHlog.Emit(InfoSvcStarted{})
|
|
||||||
|
|
||||||
authClient := auth.NewAuthClient(options.AuthServiceURL)
|
|
||||||
|
|
||||||
pgdal, err := dal.New(ctx, options.PostgresCredentials, nil)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("NEW", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
chDal, err := dal.NewClickHouseDAL(ctx, options.ClickHouseCred)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("failed init clickhouse", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
kafkaClient, err := initialize.KafkaInit(ctx, initialize.KafkaDeps{
|
|
||||||
KafkaGroup: options.KafkaGroup,
|
|
||||||
KafkaBrokers: options.KafkaBrokers,
|
|
||||||
KafkaTopic: options.KafkaTopic,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
producer := brokers.NewProducer(brokers.ProducerDeps{
|
|
||||||
KafkaClient: kafkaClient,
|
|
||||||
Logger: zapLogger,
|
|
||||||
})
|
|
||||||
|
|
||||||
redisClient := redis.NewClient(&redis.Options{
|
|
||||||
Addr: options.RedisHost,
|
|
||||||
Password: options.RedisPassword,
|
|
||||||
DB: int(options.RedisDB),
|
|
||||||
})
|
|
||||||
err = redisClient.Ping(ctx).Err()
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("error ping to redis db %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
clientData := privilege.Client{
|
|
||||||
URL: options.HubAdminUrl,
|
|
||||||
ServiceName: options.ServiceName,
|
|
||||||
Privileges: model.Privileges,
|
|
||||||
}
|
|
||||||
fiberClient := &fiber.Client{}
|
|
||||||
privilegeController := privilege.NewPrivilege(clientData, fiberClient)
|
|
||||||
go tools.PublishPrivilege(privilegeController, 10, 5*time.Minute)
|
|
||||||
|
|
||||||
tgClient, err := telegram.NewTelegramClient(ctx, pgdal)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed init tg clietns: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
tgWC := workers.NewTgListenerWC(workers.Deps{
|
|
||||||
BotID: int64(6712573453), // todo убрать
|
|
||||||
Redis: redisClient,
|
|
||||||
Dal: pgdal,
|
|
||||||
TgClient: tgClient,
|
|
||||||
})
|
|
||||||
|
|
||||||
go tgWC.Start(ctx)
|
|
||||||
|
|
||||||
// todo подумать над реализацией всего а то пока мне кажется что немного каша получается такой предикт что через некоторое время
|
|
||||||
// сложно будет разобраться что есть где
|
|
||||||
grpcControllers := initialize.InitRpcControllers(pgdal)
|
|
||||||
grpc, err := server.NewGRPC(zapLogger)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println("error:", err)
|
|
||||||
panic("err init grpc server")
|
|
||||||
}
|
|
||||||
grpc.Register(grpcControllers)
|
|
||||||
go grpc.Run(server.DepsGrpcRun{
|
|
||||||
Host: options.GrpcHost,
|
|
||||||
Port: options.GrpcPort,
|
|
||||||
})
|
|
||||||
|
|
||||||
app := fiber.New()
|
|
||||||
app.Use(middleware.JWTAuth())
|
|
||||||
app.Use(log_mw.ContextLogger(loggerHlog))
|
|
||||||
app.Get("/liveness", healthchecks.Liveness)
|
|
||||||
app.Get("/readiness", healthchecks.Readiness(&workerErr)) //todo parametrized readiness. should discuss ready reason
|
|
||||||
|
|
||||||
svc := service.New(service.Deps{
|
|
||||||
Dal: pgdal,
|
|
||||||
AuthClient: authClient,
|
|
||||||
Producer: producer,
|
|
||||||
ServiceName: options.ServiceName,
|
|
||||||
ChDAL: chDal,
|
|
||||||
TelegramClient: tgClient,
|
|
||||||
RedisClient: redisClient,
|
|
||||||
S3Prefix: options.S3Prefix,
|
|
||||||
})
|
|
||||||
|
|
||||||
svc.Register(app)
|
|
||||||
|
|
||||||
loggerHlog.Emit(InfoSvcReady{})
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
defer func() {
|
|
||||||
if pgdal != nil {
|
|
||||||
pgdal.Close()
|
|
||||||
}
|
|
||||||
if chDal != nil {
|
|
||||||
if derr := chDal.Close(ctx); derr != nil {
|
|
||||||
fmt.Printf("error closing clickhouse: %v", derr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
err := grpc.Stop(ctx)
|
|
||||||
err = app.Shutdown()
|
|
||||||
loggerHlog.Emit(InfoSvcShutdown{Signal: err.Error()})
|
|
||||||
}()
|
|
||||||
|
|
||||||
if options.IsProd {
|
|
||||||
if err := app.ListenTLS(fmt.Sprintf(":%s", options.NumberPort), options.CrtFile, options.KeyFile); err != nil {
|
|
||||||
loggerHlog.Emit(ErrorCanNotServe{
|
|
||||||
Err: err,
|
|
||||||
})
|
|
||||||
errChan <- err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := app.Listen(fmt.Sprintf(":%s", options.NumberPort)); err != nil {
|
|
||||||
loggerHlog.Emit(ErrorCanNotServe{
|
|
||||||
Err: err,
|
|
||||||
})
|
|
||||||
errChan <- err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
errChan <- nil
|
|
||||||
}()
|
|
||||||
// todo implement helper func for service app type. such as server preparing, logger preparing, healthchecks and etc.
|
|
||||||
return &App{
|
|
||||||
logger: zapLogger,
|
|
||||||
err: errChan,
|
|
||||||
}, err
|
|
||||||
}
|
|
41
cmd/main.go
Normal file
41
cmd/main.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/app"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/initialize"
|
||||||
|
"syscall"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
commit string = os.Getenv("COMMIT")
|
||||||
|
buildTime string = os.Getenv("BUILD_TIME")
|
||||||
|
version string = os.Getenv("VERSION")
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
logger, err := zap.NewProduction()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Failed to initialize logger: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
config, err := initialize.LoadConfig()
|
||||||
|
if err != nil {
|
||||||
|
logger.Fatal("Failed to load config", zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
if err = app.Run(ctx, *config, logger, app.Build{
|
||||||
|
Commit: commit,
|
||||||
|
Version: version,
|
||||||
|
}); err != nil {
|
||||||
|
logger.Fatal("App exited with error", zap.Error(err))
|
||||||
|
}
|
||||||
|
}
|
3
go.mod
3
go.mod
@ -20,7 +20,7 @@ require (
|
|||||||
google.golang.org/grpc v1.64.0
|
google.golang.org/grpc v1.64.0
|
||||||
google.golang.org/protobuf v1.34.2
|
google.golang.org/protobuf v1.34.2
|
||||||
penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240607202348-efe5f2bf3e8c
|
penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240607202348-efe5f2bf3e8c
|
||||||
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240711133242-0b8534fae5b2
|
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20241025130405-8ab347d96f1f
|
||||||
penahub.gitlab.yandexcloud.net/backend/quiz/worker.git v0.0.0-20240421230341-0e086fcbb990
|
penahub.gitlab.yandexcloud.net/backend/quiz/worker.git v0.0.0-20240421230341-0e086fcbb990
|
||||||
penahub.gitlab.yandexcloud.net/backend/tdlib v0.0.0-20240701075856-1731684c936f
|
penahub.gitlab.yandexcloud.net/backend/tdlib v0.0.0-20240701075856-1731684c936f
|
||||||
penahub.gitlab.yandexcloud.net/external/trashlog v0.1.6-0.20240827173635-78ce9878c387
|
penahub.gitlab.yandexcloud.net/external/trashlog v0.1.6-0.20240827173635-78ce9878c387
|
||||||
@ -29,6 +29,7 @@ require (
|
|||||||
require (
|
require (
|
||||||
github.com/ClickHouse/clickhouse-go v1.5.4 // indirect
|
github.com/ClickHouse/clickhouse-go v1.5.4 // indirect
|
||||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||||
|
github.com/caarlos0/env/v8 v8.0.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 // indirect
|
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
6
go.sum
6
go.sum
@ -7,6 +7,8 @@ github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer5
|
|||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
|
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
|
||||||
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
|
||||||
|
github.com/caarlos0/env/v8 v8.0.0 h1:POhxHhSpuxrLMIdvTGARuZqR4Jjm8AYmoi/JKlcScs0=
|
||||||
|
github.com/caarlos0/env/v8 v8.0.0/go.mod h1:7K4wMY9bH0esiXSSHlfHLX5xKGQMnkH5Fk4TDSSSzfo=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
@ -140,6 +142,7 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/tealeg/xlsx v1.0.5/go.mod h1:btRS8dz54TDnvKNosuAqxrM1QgN1udgk9O34bDCnORM=
|
||||||
github.com/themakers/bdd v0.0.0-20210316111417-6b1dfe326f33 h1:N9f/Q+2Ssa+yDcbfaoLTYvXmdeyUUxsJKdPUVsjSmiA=
|
github.com/themakers/bdd v0.0.0-20210316111417-6b1dfe326f33 h1:N9f/Q+2Ssa+yDcbfaoLTYvXmdeyUUxsJKdPUVsjSmiA=
|
||||||
github.com/themakers/bdd v0.0.0-20210316111417-6b1dfe326f33/go.mod h1:rpcH99JknBh8seZmlOlUg51gasZH6QH34oXNsIwYT6E=
|
github.com/themakers/bdd v0.0.0-20210316111417-6b1dfe326f33/go.mod h1:rpcH99JknBh8seZmlOlUg51gasZH6QH34oXNsIwYT6E=
|
||||||
github.com/themakers/hlog v0.0.0-20191205140925-235e0e4baddf h1:TJJm6KcBssmbWzplF5lzixXl1RBAi/ViPs1GaSOkhwo=
|
github.com/themakers/hlog v0.0.0-20191205140925-235e0e4baddf h1:TJJm6KcBssmbWzplF5lzixXl1RBAi/ViPs1GaSOkhwo=
|
||||||
@ -260,6 +263,7 @@ google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6h
|
|||||||
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
@ -284,6 +288,8 @@ penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240607202348-efe5
|
|||||||
penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240607202348-efe5f2bf3e8c/go.mod h1:+bPxq2wfW5S1gd+83vZYmHm33AE7nEBfznWS8AM1TKE=
|
penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240607202348-efe5f2bf3e8c/go.mod h1:+bPxq2wfW5S1gd+83vZYmHm33AE7nEBfznWS8AM1TKE=
|
||||||
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240711133242-0b8534fae5b2 h1:0t6pQHJvA3jMeBB3FPUmA+hw8rWlksTah8KJEtf2KD8=
|
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240711133242-0b8534fae5b2 h1:0t6pQHJvA3jMeBB3FPUmA+hw8rWlksTah8KJEtf2KD8=
|
||||||
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240711133242-0b8534fae5b2/go.mod h1:uOuosXduBzd2WbLH6TDZO7ME7ZextulA662oZ6OsoB0=
|
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20240711133242-0b8534fae5b2/go.mod h1:uOuosXduBzd2WbLH6TDZO7ME7ZextulA662oZ6OsoB0=
|
||||||
|
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20241025130405-8ab347d96f1f h1:HMXxbIkNmFeQTFI/MlsDBIRUTu8MTbn3i2PVcpQbXEI=
|
||||||
|
penahub.gitlab.yandexcloud.net/backend/quiz/common.git v0.0.0-20241025130405-8ab347d96f1f/go.mod h1:uOuosXduBzd2WbLH6TDZO7ME7ZextulA662oZ6OsoB0=
|
||||||
penahub.gitlab.yandexcloud.net/backend/quiz/worker.git v0.0.0-20240421230341-0e086fcbb990 h1:jiO8GWO+3sCnDAV8/NAV8tQIUwae/I6/xiDilW7zf0o=
|
penahub.gitlab.yandexcloud.net/backend/quiz/worker.git v0.0.0-20240421230341-0e086fcbb990 h1:jiO8GWO+3sCnDAV8/NAV8tQIUwae/I6/xiDilW7zf0o=
|
||||||
penahub.gitlab.yandexcloud.net/backend/quiz/worker.git v0.0.0-20240421230341-0e086fcbb990/go.mod h1:zswBuTwmEsFHBVRu1nkG3/Fwylk5Vcm8OUm9iWxccSE=
|
penahub.gitlab.yandexcloud.net/backend/quiz/worker.git v0.0.0-20240421230341-0e086fcbb990/go.mod h1:zswBuTwmEsFHBVRu1nkG3/Fwylk5Vcm8OUm9iWxccSE=
|
||||||
penahub.gitlab.yandexcloud.net/backend/tdlib v0.0.0-20240701075856-1731684c936f h1:Qli89wgu0T7nG4VECXZOZ40fjE/hVVfxF3hTaSYS008=
|
penahub.gitlab.yandexcloud.net/backend/tdlib v0.0.0-20240701075856-1731684c936f h1:Qli89wgu0T7nG4VECXZOZ40fjE/hVVfxF3hTaSYS008=
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
package initialize
|
|
||||||
|
|
||||||
import (
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/rpc_service"
|
|
||||||
)
|
|
||||||
|
|
||||||
type RpcRegister struct {
|
|
||||||
MailNotify *rpc_service.MailNotify
|
|
||||||
}
|
|
||||||
|
|
||||||
func InitRpcControllers(dal *dal.DAL) *RpcRegister {
|
|
||||||
return &RpcRegister{
|
|
||||||
MailNotify: rpc_service.NewMailNotify(dal),
|
|
||||||
}
|
|
||||||
}
|
|
187
internal/app/app.go
Normal file
187
internal/app/app.go
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/themakers/hlog"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/penahub_common/privilege"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/brokers"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/initialize"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/models"
|
||||||
|
server "penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/server/grpc"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/server/http"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/tools"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/workers"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/pkg/closer"
|
||||||
|
"penahub.gitlab.yandexcloud.net/external/trashlog/wrappers/zaptrashlog"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Build struct {
|
||||||
|
Commit string
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
|
||||||
|
var zapOptions = []zap.Option{
|
||||||
|
zap.AddCaller(),
|
||||||
|
zap.AddCallerSkip(2),
|
||||||
|
zap.AddStacktrace(zap.ErrorLevel),
|
||||||
|
}
|
||||||
|
|
||||||
|
func Run(ctx context.Context, cfg initialize.Config, logger *zap.Logger, build Build) error {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
zapLogger *zap.Logger
|
||||||
|
)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
logger.Error("Recovered from a panic", zap.Any("error", r))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
if cfg.LoggerProdMode {
|
||||||
|
zapLogger, err = zap.NewProduction(zapOptions...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
zapLogger, err = zap.NewDevelopment(zapOptions...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zapLogger = zapLogger.With(
|
||||||
|
zap.String("SvcCommit", build.Commit),
|
||||||
|
zap.String("SvcVersion", build.Version),
|
||||||
|
zap.String("SvcBuildTime", time.Now().String()),
|
||||||
|
)
|
||||||
|
|
||||||
|
clickHouseLogger, err := zaptrashlog.NewCore(ctx, zap.InfoLevel, cfg.TrashLogHost, build.Version, build.Commit, time.Now().Unix())
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
loggerForHlog := zapLogger.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core {
|
||||||
|
return zapcore.NewTee(core, clickHouseLogger)
|
||||||
|
}))
|
||||||
|
|
||||||
|
loggerHlog := hlog.New(loggerForHlog).Module(cfg.ModuleLogger)
|
||||||
|
loggerHlog.With(models.AllFields{})
|
||||||
|
loggerHlog.Emit(InfoSvcStarted{})
|
||||||
|
|
||||||
|
shutdownGroup := closer.NewCloserGroup()
|
||||||
|
|
||||||
|
dalS, err := initialize.NewDALs(ctx, cfg)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Error initializing dals", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
kafkaClient, err := initialize.KafkaInit(ctx, initialize.KafkaDeps{
|
||||||
|
KafkaGroup: cfg.KafkaGroup,
|
||||||
|
KafkaBrokers: cfg.KafkaBrokers,
|
||||||
|
KafkaTopic: cfg.KafkaTopic,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Error initializing kafka", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
producer := brokers.NewProducer(brokers.ProducerDeps{
|
||||||
|
KafkaClient: kafkaClient,
|
||||||
|
Logger: zapLogger,
|
||||||
|
})
|
||||||
|
|
||||||
|
redisClient, err := initialize.Redis(ctx, cfg)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Error initializing redis", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
go tools.PublishPrivilege(privilege.NewPrivilege(privilege.Client{
|
||||||
|
URL: cfg.HubAdminUrl,
|
||||||
|
ServiceName: cfg.ServiceName,
|
||||||
|
Privileges: model.Privileges,
|
||||||
|
}, &fiber.Client{}), 10, 5*time.Minute)
|
||||||
|
|
||||||
|
clients, err := initialize.NewClients(ctx, cfg, dalS.PgDAL)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Error initializing clients", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tgWC := workers.NewTgListenerWC(workers.Deps{
|
||||||
|
BotID: int64(6712573453), // todo убрать
|
||||||
|
Redis: redisClient,
|
||||||
|
Dal: dalS.PgDAL,
|
||||||
|
TgClient: clients.TgClient,
|
||||||
|
})
|
||||||
|
|
||||||
|
go tgWC.Start(ctx)
|
||||||
|
|
||||||
|
controllers := initialize.NewControllers(initialize.ControllerDeps{
|
||||||
|
Clients: clients,
|
||||||
|
DALs: dalS,
|
||||||
|
Config: cfg,
|
||||||
|
Producer: producer,
|
||||||
|
RedisClient: redisClient,
|
||||||
|
})
|
||||||
|
|
||||||
|
grpc, err := server.NewGRPC(zapLogger)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("Error initializing grpc", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
grpc.Register(controllers.GRpcControllers)
|
||||||
|
|
||||||
|
srv := http.NewServer(http.ServerConfig{
|
||||||
|
Logger: logger,
|
||||||
|
Controllers: []http.Controller{controllers.HttpControllers.Account, controllers.HttpControllers.Telegram, controllers.HttpControllers.Result,
|
||||||
|
controllers.HttpControllers.Question, controllers.HttpControllers.Quiz, controllers.HttpControllers.Statistic},
|
||||||
|
Hlogger: loggerHlog,
|
||||||
|
})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
if err := srv.Start(cfg.HttpHost + ":" + cfg.NumberPort); err != nil {
|
||||||
|
logger.Error("HTTP server startup error", zap.Error(err))
|
||||||
|
cancel()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go grpc.Run(server.DepsGrpcRun{
|
||||||
|
Host: cfg.GrpcHost,
|
||||||
|
Port: cfg.GrpcPort,
|
||||||
|
})
|
||||||
|
|
||||||
|
srv.ListRoutes()
|
||||||
|
|
||||||
|
shutdownGroup.Add(closer.CloserFunc(srv.Shutdown))
|
||||||
|
shutdownGroup.Add(closer.CloserFunc(grpc.Stop))
|
||||||
|
shutdownGroup.Add(closer.CloserFunc(dalS.PgDAL.Close))
|
||||||
|
shutdownGroup.Add(closer.CloserFunc(dalS.ChDAL.Close))
|
||||||
|
|
||||||
|
<-ctx.Done()
|
||||||
|
|
||||||
|
timeoutCtx, timeoutCancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer timeoutCancel()
|
||||||
|
if err := shutdownGroup.Call(timeoutCtx); err != nil {
|
||||||
|
if errors.Is(err, context.DeadlineExceeded) {
|
||||||
|
logger.Error("Shutdown timed out", zap.Error(err))
|
||||||
|
} else {
|
||||||
|
logger.Error("Failed to shutdown services gracefully", zap.Error(err))
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Application has stopped")
|
||||||
|
return nil
|
||||||
|
}
|
@ -1,21 +1,50 @@
|
|||||||
package service
|
package account
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/penahub_common/log_mw"
|
"penahub.gitlab.yandexcloud.net/backend/penahub_common/log_mw"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/middleware"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/middleware"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/pj_errors"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/pj_errors"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/brokers"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/brokers"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/models"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/clients/auth"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/models"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Deps struct {
|
||||||
|
Dal *dal.DAL
|
||||||
|
AuthClient *auth.AuthClient
|
||||||
|
Producer *brokers.Producer
|
||||||
|
ServiceName string
|
||||||
|
RedisClient *redis.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type Account struct {
|
||||||
|
dal *dal.DAL
|
||||||
|
authClient *auth.AuthClient
|
||||||
|
producer *brokers.Producer
|
||||||
|
serviceName string
|
||||||
|
redisClient *redis.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAccountController(deps Deps) *Account {
|
||||||
|
return &Account{
|
||||||
|
dal: deps.Dal,
|
||||||
|
authClient: deps.AuthClient,
|
||||||
|
producer: deps.Producer,
|
||||||
|
serviceName: deps.ServiceName,
|
||||||
|
redisClient: deps.RedisClient,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type CreateAccountReq struct {
|
type CreateAccountReq struct {
|
||||||
UserID string `json:"userId"`
|
UserID string `json:"userId"`
|
||||||
}
|
}
|
||||||
@ -51,13 +80,13 @@ type GetAccountsResp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getCurrentAccount обработчик для получения текущего аккаунта
|
// getCurrentAccount обработчик для получения текущего аккаунта
|
||||||
func (s *Service) getCurrentAccount(ctx *fiber.Ctx) error {
|
func (r *Account) GetCurrentAccount(ctx *fiber.Ctx) error {
|
||||||
accountID, ok := middleware.GetAccountId(ctx)
|
accountID, ok := middleware.GetAccountId(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err := s.dal.AccountRepo.GetAccountByID(ctx.Context(), accountID)
|
account, err := r.dal.AccountRepo.GetAccountByID(ctx.Context(), accountID)
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -71,14 +100,14 @@ func (s *Service) getCurrentAccount(ctx *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createAccount обработчик для создания нового аккаунта
|
// createAccount обработчик для создания нового аккаунта
|
||||||
func (s *Service) createAccount(ctx *fiber.Ctx) error {
|
func (r *Account) CreateAccount(ctx *fiber.Ctx) error {
|
||||||
accountID, ok := middleware.GetAccountId(ctx)
|
accountID, ok := middleware.GetAccountId(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
||||||
}
|
}
|
||||||
hlogger := log_mw.ExtractLogger(ctx)
|
hlogger := log_mw.ExtractLogger(ctx)
|
||||||
|
|
||||||
existingAccount, err := s.dal.AccountRepo.GetAccountByID(ctx.Context(), accountID)
|
existingAccount, err := r.dal.AccountRepo.GetAccountByID(ctx.Context(), accountID)
|
||||||
if err != nil && err != sql.ErrNoRows {
|
if err != nil && err != sql.ErrNoRows {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -86,7 +115,7 @@ func (s *Service) createAccount(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusConflict).SendString("user with this ID already exists")
|
return ctx.Status(fiber.StatusConflict).SendString("user with this ID already exists")
|
||||||
}
|
}
|
||||||
|
|
||||||
email, err := s.authClient.GetUserEmail(accountID)
|
email, err := r.authClient.GetUserEmail(accountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -105,11 +134,11 @@ func (s *Service) createAccount(ctx *fiber.Ctx) error {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
createdAcc, err := s.dal.AccountRepo.CreateAccount(ctx.Context(), &newAccount)
|
createdAcc, err := r.dal.AccountRepo.CreateAccount(ctx.Context(), &newAccount)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
_, err = s.dal.AccountRepo.PostLeadTarget(ctx.Context(), model.LeadTarget{
|
_, err = r.dal.AccountRepo.PostLeadTarget(ctx.Context(), model.LeadTarget{
|
||||||
AccountID: accountID,
|
AccountID: accountID,
|
||||||
Target: email,
|
Target: email,
|
||||||
Type: model.LeadTargetEmail,
|
Type: model.LeadTargetEmail,
|
||||||
@ -124,10 +153,10 @@ func (s *Service) createAccount(ctx *fiber.Ctx) error {
|
|||||||
CtxAccountID: createdAcc.ID,
|
CtxAccountID: createdAcc.ID,
|
||||||
})
|
})
|
||||||
|
|
||||||
err = s.producer.ToMailNotify(ctx.Context(), brokers.Message{
|
err = r.producer.ToMailNotify(ctx.Context(), brokers.Message{
|
||||||
AccountID: accountID,
|
AccountID: accountID,
|
||||||
Email: email,
|
Email: email,
|
||||||
ServiceKey: s.serviceName,
|
ServiceKey: r.serviceName,
|
||||||
SendAt: time.Now(),
|
SendAt: time.Now(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -140,18 +169,18 @@ func (s *Service) createAccount(ctx *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// deleteAccount обработчик для удаления текущего аккаунта
|
// deleteAccount обработчик для удаления текущего аккаунта
|
||||||
func (s *Service) deleteAccount(ctx *fiber.Ctx) error {
|
func (r *Account) DeleteAccount(ctx *fiber.Ctx) error {
|
||||||
accountID, ok := middleware.GetAccountId(ctx)
|
accountID, ok := middleware.GetAccountId(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err := s.dal.AccountRepo.GetAccountByID(ctx.Context(), accountID)
|
account, err := r.dal.AccountRepo.GetAccountByID(ctx.Context(), accountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.dal.AccountRepo.DeleteAccount(ctx.Context(), account.ID); err != nil {
|
if err := r.dal.AccountRepo.DeleteAccount(ctx.Context(), account.ID); err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,13 +190,13 @@ func (s *Service) deleteAccount(ctx *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getPrivilegeByUserID обработчик для получения привилегий аккаунта по ID пользователя
|
// getPrivilegeByUserID обработчик для получения привилегий аккаунта по ID пользователя
|
||||||
func (s *Service) getPrivilegeByUserID(ctx *fiber.Ctx) error {
|
func (r *Account) GetPrivilegeByUserID(ctx *fiber.Ctx) error {
|
||||||
var req GetPrivilegeByUserIDReq
|
var req GetPrivilegeByUserIDReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
}
|
}
|
||||||
|
|
||||||
privilege, err := s.dal.AccountRepo.GetPrivilegesByAccountID(ctx.Context(), req.UserID)
|
privilege, err := r.dal.AccountRepo.GetPrivilegesByAccountID(ctx.Context(), req.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -176,13 +205,13 @@ func (s *Service) getPrivilegeByUserID(ctx *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// deleteAccountByUserID обработчик для удаления аккаунта по ID пользователя
|
// deleteAccountByUserID обработчик для удаления аккаунта по ID пользователя
|
||||||
func (s *Service) deleteAccountByUserID(ctx *fiber.Ctx) error {
|
func (r *Account) DeleteAccountByUserID(ctx *fiber.Ctx) error {
|
||||||
var req DeleteAccountByUserIDReq
|
var req DeleteAccountByUserIDReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
}
|
}
|
||||||
|
|
||||||
existingAccount, err := s.dal.AccountRepo.GetAccountByID(ctx.Context(), req.UserID)
|
existingAccount, err := r.dal.AccountRepo.GetAccountByID(ctx.Context(), req.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -191,7 +220,7 @@ func (s *Service) deleteAccountByUserID(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusInternalServerError).SendString("user with this ID not found")
|
return ctx.Status(fiber.StatusInternalServerError).SendString("user with this ID not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.dal.AccountRepo.DeleteAccount(ctx.Context(), existingAccount.ID); err != nil {
|
if err := r.dal.AccountRepo.DeleteAccount(ctx.Context(), existingAccount.ID); err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +230,7 @@ func (s *Service) deleteAccountByUserID(ctx *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// getAccounts обработчик для получения списка аккаунтов с пагинацией
|
// getAccounts обработчик для получения списка аккаунтов с пагинацией
|
||||||
func (s *Service) getAccounts(ctx *fiber.Ctx) error {
|
func (r *Account) GetAccounts(ctx *fiber.Ctx) error {
|
||||||
var req GetAccountsReq
|
var req GetAccountsReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
@ -212,7 +241,7 @@ func (s *Service) getAccounts(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
accounts, totalCount, err := s.dal.AccountRepo.GetAccounts(ctx.Context(), req.Limit, req.Page)
|
accounts, totalCount, err := r.dal.AccountRepo.GetAccounts(ctx.Context(), req.Limit, req.Page)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -225,7 +254,7 @@ func (s *Service) getAccounts(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusOK).JSON(response)
|
return ctx.Status(fiber.StatusOK).JSON(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) ManualDone(ctx *fiber.Ctx) error {
|
func (r *Account) ManualDone(ctx *fiber.Ctx) error {
|
||||||
var req struct {
|
var req struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
}
|
}
|
||||||
@ -237,7 +266,7 @@ func (s *Service) ManualDone(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusBadRequest).SendString("User id is required")
|
return ctx.Status(fiber.StatusBadRequest).SendString("User id is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
err := s.dal.AccountRepo.ManualDone(ctx.Context(), req.Id)
|
err := r.dal.AccountRepo.ManualDone(ctx.Context(), req.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, pj_errors.ErrNotFound) {
|
if errors.Is(err, pj_errors.ErrNotFound) {
|
||||||
return ctx.Status(fiber.StatusNotFound).SendString("user don't have this privilege")
|
return ctx.Status(fiber.StatusNotFound).SendString("user don't have this privilege")
|
||||||
@ -248,7 +277,7 @@ func (s *Service) ManualDone(ctx *fiber.Ctx) error {
|
|||||||
return ctx.SendStatus(fiber.StatusOK)
|
return ctx.SendStatus(fiber.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) PostLeadTarget(ctx *fiber.Ctx) error {
|
func (r *Account) PostLeadTarget(ctx *fiber.Ctx) error {
|
||||||
var req struct {
|
var req struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
QuizID int32 `json:"quizID"`
|
QuizID int32 `json:"quizID"`
|
||||||
@ -276,7 +305,7 @@ func (s *Service) PostLeadTarget(ctx *fiber.Ctx) error {
|
|||||||
|
|
||||||
switch req.Type {
|
switch req.Type {
|
||||||
case "mail":
|
case "mail":
|
||||||
_, err := s.dal.AccountRepo.PostLeadTarget(ctx.Context(), model.LeadTarget{
|
_, err := r.dal.AccountRepo.PostLeadTarget(ctx.Context(), model.LeadTarget{
|
||||||
AccountID: accountID,
|
AccountID: accountID,
|
||||||
Target: req.Target,
|
Target: req.Target,
|
||||||
Type: model.LeadTargetType(req.Type),
|
Type: model.LeadTargetType(req.Type),
|
||||||
@ -287,7 +316,7 @@ func (s *Service) PostLeadTarget(ctx *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
return ctx.SendStatus(fiber.StatusOK)
|
return ctx.SendStatus(fiber.StatusOK)
|
||||||
case "telegram":
|
case "telegram":
|
||||||
targets, err := s.dal.AccountRepo.GetLeadTarget(ctx.Context(), accountID, req.QuizID)
|
targets, err := r.dal.AccountRepo.GetLeadTarget(ctx.Context(), accountID, req.QuizID)
|
||||||
if err != nil && !errors.Is(err, pj_errors.ErrNotFound) {
|
if err != nil && !errors.Is(err, pj_errors.ErrNotFound) {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -311,7 +340,7 @@ func (s *Service) PostLeadTarget(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.redisClient.Set(ctx.Context(), taskKey, taskData, 0).Err(); err != nil {
|
if err := r.redisClient.Set(ctx.Context(), taskKey, taskData, 0).Err(); err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
case "whatsapp":
|
case "whatsapp":
|
||||||
@ -321,21 +350,21 @@ func (s *Service) PostLeadTarget(ctx *fiber.Ctx) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) DeleteLeadTarget(ctx *fiber.Ctx) error {
|
func (r *Account) DeleteLeadTarget(ctx *fiber.Ctx) error {
|
||||||
leadIDStr := ctx.Params("id")
|
leadIDStr := ctx.Params("id")
|
||||||
leadID, err := strconv.ParseInt(leadIDStr, 10, 64)
|
leadID, err := strconv.ParseInt(leadIDStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid lead ID format")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid lead ID format")
|
||||||
}
|
}
|
||||||
|
|
||||||
err = s.dal.AccountRepo.DeleteLeadTarget(ctx.Context(), leadID)
|
err = r.dal.AccountRepo.DeleteLeadTarget(ctx.Context(), leadID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
return ctx.SendStatus(fiber.StatusOK)
|
return ctx.SendStatus(fiber.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetLeadTarget(ctx *fiber.Ctx) error {
|
func (r *Account) GetLeadTarget(ctx *fiber.Ctx) error {
|
||||||
accountID, ok := middleware.GetAccountId(ctx)
|
accountID, ok := middleware.GetAccountId(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
||||||
@ -347,7 +376,7 @@ func (s *Service) GetLeadTarget(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid quiz ID format")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid quiz ID format")
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := s.dal.AccountRepo.GetLeadTarget(ctx.Context(), accountID, int32(quizID))
|
result, err := r.dal.AccountRepo.GetLeadTarget(ctx.Context(), accountID, int32(quizID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, pj_errors.ErrNotFound):
|
case errors.Is(err, pj_errors.ErrNotFound):
|
||||||
@ -360,7 +389,7 @@ func (s *Service) GetLeadTarget(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusOK).JSON(result)
|
return ctx.Status(fiber.StatusOK).JSON(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) UpdateLeadTarget(ctx *fiber.Ctx) error {
|
func (r *Account) UpdateLeadTarget(ctx *fiber.Ctx) error {
|
||||||
var req struct {
|
var req struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Target string `json:"target"`
|
Target string `json:"target"`
|
||||||
@ -374,7 +403,7 @@ func (s *Service) UpdateLeadTarget(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusBadRequest).SendString("ID and Target don't be nil")
|
return ctx.Status(fiber.StatusBadRequest).SendString("ID and Target don't be nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := s.dal.AccountRepo.UpdateLeadTarget(ctx.Context(), model.LeadTarget{
|
result, err := r.dal.AccountRepo.UpdateLeadTarget(ctx.Context(), model.LeadTarget{
|
||||||
ID: req.ID,
|
ID: req.ID,
|
||||||
Target: req.Target,
|
Target: req.Target,
|
||||||
})
|
})
|
21
internal/controllers/http_controllers/account/route.go
Normal file
21
internal/controllers/http_controllers/account/route.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package account
|
||||||
|
|
||||||
|
import "github.com/gofiber/fiber/v2"
|
||||||
|
|
||||||
|
func (r *Account) Register(router fiber.Router) {
|
||||||
|
router.Get("/account/get", r.GetCurrentAccount)
|
||||||
|
router.Post("/account/create", r.CreateAccount)
|
||||||
|
router.Delete("/account/delete", r.DeleteAccount)
|
||||||
|
router.Get("/accounts", r.GetAccounts)
|
||||||
|
router.Get("/privilege/:userId", r.GetPrivilegeByUserID)
|
||||||
|
router.Delete("/account/:userId", r.DeleteAccountByUserID)
|
||||||
|
router.Post("/account/manualdone", r.ManualDone)
|
||||||
|
router.Post("/account/leadtarget", r.PostLeadTarget)
|
||||||
|
router.Delete("/account/leadtarget/:id", r.DeleteLeadTarget)
|
||||||
|
router.Get("/account/leadtarget/:quizID", r.GetLeadTarget)
|
||||||
|
router.Put("/account/leadtarget", r.UpdateLeadTarget)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Account) Name() string {
|
||||||
|
return ""
|
||||||
|
}
|
@ -1,15 +1,28 @@
|
|||||||
package service
|
package question
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/lib/pq"
|
"github.com/lib/pq"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/penahub_common/log_mw"
|
"penahub.gitlab.yandexcloud.net/backend/penahub_common/log_mw"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/middleware"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/middleware"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/models"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/models"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Deps struct {
|
||||||
|
DAL *dal.DAL
|
||||||
|
}
|
||||||
|
|
||||||
|
type Question struct {
|
||||||
|
dal *dal.DAL
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewQuestionController(deps Deps) *Question {
|
||||||
|
return &Question{dal: deps.DAL}
|
||||||
|
}
|
||||||
|
|
||||||
// QuestionCreateReq request structure for creating Question
|
// QuestionCreateReq request structure for creating Question
|
||||||
type QuestionCreateReq struct {
|
type QuestionCreateReq struct {
|
||||||
QuizId uint64 `json:"quiz_id"` // relation to quiz
|
QuizId uint64 `json:"quiz_id"` // relation to quiz
|
||||||
@ -23,7 +36,7 @@ type QuestionCreateReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateQuestion service handler for creating question for quiz
|
// CreateQuestion service handler for creating question for quiz
|
||||||
func (s *Service) CreateQuestion(ctx *fiber.Ctx) error {
|
func (r *Question) CreateQuestion(ctx *fiber.Ctx) error {
|
||||||
accountID, ok := middleware.GetAccountId(ctx)
|
accountID, ok := middleware.GetAccountId(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
||||||
@ -64,7 +77,7 @@ func (s *Service) CreateQuestion(ctx *fiber.Ctx) error {
|
|||||||
Content: req.Content,
|
Content: req.Content,
|
||||||
}
|
}
|
||||||
|
|
||||||
questionID, err := s.dal.QuestionRepo.CreateQuestion(ctx.Context(), &result)
|
questionID, err := r.dal.QuestionRepo.CreateQuestion(ctx.Context(), &result)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if e, ok := err.(*pq.Error); ok {
|
if e, ok := err.(*pq.Error); ok {
|
||||||
if e.Constraint == "quiz_relation" {
|
if e.Constraint == "quiz_relation" {
|
||||||
@ -104,7 +117,7 @@ type GetQuestionListResp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetQuestionList handler for paginated list question
|
// GetQuestionList handler for paginated list question
|
||||||
func (s *Service) GetQuestionList(ctx *fiber.Ctx) error {
|
func (r *Question) GetQuestionList(ctx *fiber.Ctx) error {
|
||||||
var req GetQuestionListReq
|
var req GetQuestionListReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
@ -127,7 +140,7 @@ func (s *Service) GetQuestionList(ctx *fiber.Ctx) error {
|
|||||||
"'test','none','file', 'button','select','checkbox'")
|
"'test','none','file', 'button','select','checkbox'")
|
||||||
}
|
}
|
||||||
|
|
||||||
res, cnt, err := s.dal.QuestionRepo.GetQuestionList(ctx.Context(),
|
res, cnt, err := r.dal.QuestionRepo.GetQuestionList(ctx.Context(),
|
||||||
req.Limit,
|
req.Limit,
|
||||||
req.Page*req.Limit,
|
req.Page*req.Limit,
|
||||||
uint64(req.From),
|
uint64(req.From),
|
||||||
@ -165,7 +178,7 @@ type UpdateResp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateQuestion handler for update question
|
// UpdateQuestion handler for update question
|
||||||
func (s *Service) UpdateQuestion(ctx *fiber.Ctx) error {
|
func (r *Question) UpdateQuestion(ctx *fiber.Ctx) error {
|
||||||
var req UpdateQuestionReq
|
var req UpdateQuestionReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
@ -195,7 +208,7 @@ func (s *Service) UpdateQuestion(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusNotAcceptable).SendString("type must be only test,button,file,checkbox,select, none or empty string")
|
return ctx.Status(fiber.StatusNotAcceptable).SendString("type must be only test,button,file,checkbox,select, none or empty string")
|
||||||
}
|
}
|
||||||
|
|
||||||
question, err := s.dal.QuestionRepo.MoveToHistoryQuestion(ctx.Context(), req.Id)
|
question, err := r.dal.QuestionRepo.MoveToHistoryQuestion(ctx.Context(), req.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -227,7 +240,7 @@ func (s *Service) UpdateQuestion(ctx *fiber.Ctx) error {
|
|||||||
question.Content = req.Content
|
question.Content = req.Content
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.dal.QuestionRepo.UpdateQuestion(ctx.Context(), question); err != nil {
|
if err := r.dal.QuestionRepo.UpdateQuestion(ctx.Context(), question); err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +256,7 @@ type CopyQuestionReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CopyQuestion handler for copy question
|
// CopyQuestion handler for copy question
|
||||||
func (s *Service) CopyQuestion(ctx *fiber.Ctx) error {
|
func (r *Question) CopyQuestion(ctx *fiber.Ctx) error {
|
||||||
var req CopyQuestionReq
|
var req CopyQuestionReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
@ -253,7 +266,7 @@ func (s *Service) CopyQuestion(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusFailedDependency).SendString("no id provided")
|
return ctx.Status(fiber.StatusFailedDependency).SendString("no id provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
question, err := s.dal.QuestionRepo.CopyQuestion(ctx.Context(), req.Id, req.QuizId)
|
question, err := r.dal.QuestionRepo.CopyQuestion(ctx.Context(), req.Id, req.QuizId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -271,8 +284,8 @@ type GetQuestionHistoryReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetQuestionHistory handler for history of quiz
|
// GetQuestionHistory handler for history of quiz
|
||||||
func (s *Service) GetQuestionHistory(ctx *fiber.Ctx) error {
|
func (r *Question) GetQuestionHistory(ctx *fiber.Ctx) error {
|
||||||
var req GetQuizHistoryReq
|
var req GetQuestionHistoryReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
}
|
}
|
||||||
@ -281,7 +294,7 @@ func (s *Service) GetQuestionHistory(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusFailedDependency).SendString("no id provided")
|
return ctx.Status(fiber.StatusFailedDependency).SendString("no id provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
history, err := s.dal.QuestionRepo.QuestionHistory(ctx.Context(), req.Id, req.Limit, req.Page*req.Limit)
|
history, err := r.dal.QuestionRepo.QuestionHistory(ctx.Context(), req.Id, req.Limit, req.Page*req.Limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -289,15 +302,22 @@ func (s *Service) GetQuestionHistory(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusOK).JSON(history)
|
return ctx.Status(fiber.StatusOK).JSON(history)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DeactivateResp struct {
|
||||||
|
Deactivated uint64 `json:"deactivated"`
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteQuestion handler for fake delete question
|
// DeleteQuestion handler for fake delete question
|
||||||
func (s *Service) DeleteQuestion(ctx *fiber.Ctx) error {
|
func (r *Question) DeleteQuestion(ctx *fiber.Ctx) error {
|
||||||
accountID, ok := middleware.GetAccountId(ctx)
|
accountID, ok := middleware.GetAccountId(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
||||||
}
|
}
|
||||||
hlogger := log_mw.ExtractLogger(ctx)
|
hlogger := log_mw.ExtractLogger(ctx)
|
||||||
|
|
||||||
var req DeactivateReq
|
var req struct {
|
||||||
|
Id uint64 `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
}
|
}
|
||||||
@ -306,7 +326,7 @@ func (s *Service) DeleteQuestion(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusFailedDependency).SendString("id for deleting question is required")
|
return ctx.Status(fiber.StatusFailedDependency).SendString("id for deleting question is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
deleted, err := s.dal.QuestionRepo.DeleteQuestion(ctx.Context(), req.Id)
|
deleted, err := r.dal.QuestionRepo.DeleteQuestion(ctx.Context(), req.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
16
internal/controllers/http_controllers/question/route.go
Normal file
16
internal/controllers/http_controllers/question/route.go
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package question
|
||||||
|
|
||||||
|
import "github.com/gofiber/fiber/v2"
|
||||||
|
|
||||||
|
func (r *Question) Register(router fiber.Router) {
|
||||||
|
router.Post("/create", r.CreateQuestion)
|
||||||
|
router.Post("/getList", r.GetQuestionList)
|
||||||
|
router.Patch("/edit", r.UpdateQuestion)
|
||||||
|
router.Post("/copy", r.CopyQuestion)
|
||||||
|
router.Post("/history", r.GetQuestionHistory)
|
||||||
|
router.Delete("/delete", r.DeleteQuestion)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Question) Name() string {
|
||||||
|
return "question"
|
||||||
|
}
|
@ -1,17 +1,30 @@
|
|||||||
package service
|
package quiz
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/penahub_common/log_mw"
|
"penahub.gitlab.yandexcloud.net/backend/penahub_common/log_mw"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/middleware"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/middleware"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/repository/quiz"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/repository/quiz"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/models"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/models"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Deps struct {
|
||||||
|
DAL *dal.DAL
|
||||||
|
}
|
||||||
|
|
||||||
|
type Quiz struct {
|
||||||
|
dal *dal.DAL
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewQuizController(deps Deps) *Quiz {
|
||||||
|
return &Quiz{dal: deps.DAL}
|
||||||
|
}
|
||||||
|
|
||||||
type CreateQuizReq struct {
|
type CreateQuizReq struct {
|
||||||
Fingerprinting bool `json:"fingerprinting"` // true if you need to store device id
|
Fingerprinting bool `json:"fingerprinting"` // true if you need to store device id
|
||||||
Repeatable bool `json:"repeatable"` // make it true for allow more than one quiz checkouting
|
Repeatable bool `json:"repeatable"` // make it true for allow more than one quiz checkouting
|
||||||
@ -36,7 +49,7 @@ type CreateQuizReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateQuiz handler for quiz creating request
|
// CreateQuiz handler for quiz creating request
|
||||||
func (s *Service) CreateQuiz(ctx *fiber.Ctx) error {
|
func (r *Quiz) CreateQuiz(ctx *fiber.Ctx) error {
|
||||||
var req CreateQuizReq
|
var req CreateQuizReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
@ -95,7 +108,7 @@ func (s *Service) CreateQuiz(ctx *fiber.Ctx) error {
|
|||||||
GroupId: req.GroupId,
|
GroupId: req.GroupId,
|
||||||
}
|
}
|
||||||
|
|
||||||
quizID, err := s.dal.QuizRepo.CreateQuiz(ctx.Context(), &record)
|
quizID, err := r.dal.QuizRepo.CreateQuiz(ctx.Context(), &record)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -129,7 +142,7 @@ type GetQuizListResp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetQuizList handler for paginated list quiz
|
// GetQuizList handler for paginated list quiz
|
||||||
func (s *Service) GetQuizList(ctx *fiber.Ctx) error {
|
func (r *Quiz) GetQuizList(ctx *fiber.Ctx) error {
|
||||||
var req GetQuizListReq
|
var req GetQuizListReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
@ -151,7 +164,7 @@ func (s *Service) GetQuizList(ctx *fiber.Ctx) error {
|
|||||||
"'stop','start','draft', 'template','timeout','offlimit'")
|
"'stop','start','draft', 'template','timeout','offlimit'")
|
||||||
}
|
}
|
||||||
|
|
||||||
res, cnt, err := s.dal.QuizRepo.GetQuizList(ctx.Context(),
|
res, cnt, err := r.dal.QuizRepo.GetQuizList(ctx.Context(),
|
||||||
quiz.GetQuizListDeps{
|
quiz.GetQuizListDeps{
|
||||||
Limit: req.Limit,
|
Limit: req.Limit,
|
||||||
Offset: req.Limit * req.Page,
|
Offset: req.Limit * req.Page,
|
||||||
@ -195,7 +208,11 @@ type UpdateQuizReq struct {
|
|||||||
GroupId uint64 `json:"group_id"`
|
GroupId uint64 `json:"group_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) UpdateQuiz(ctx *fiber.Ctx) error {
|
type UpdateResp struct {
|
||||||
|
Updated uint64 `json:"updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Quiz) UpdateQuiz(ctx *fiber.Ctx) error {
|
||||||
var req UpdateQuizReq
|
var req UpdateQuizReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
@ -236,7 +253,7 @@ func (s *Service) UpdateQuiz(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusConflict).SendString("you can pause quiz only if it has deadline for passing")
|
return ctx.Status(fiber.StatusConflict).SendString("you can pause quiz only if it has deadline for passing")
|
||||||
}
|
}
|
||||||
|
|
||||||
quiz, err := s.dal.QuizRepo.MoveToHistoryQuiz(ctx.Context(), req.Id, accountId)
|
quiz, err := r.dal.QuizRepo.MoveToHistoryQuiz(ctx.Context(), req.Id, accountId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -308,7 +325,7 @@ func (s *Service) UpdateQuiz(ctx *fiber.Ctx) error {
|
|||||||
|
|
||||||
quiz.ParentIds = append(quiz.ParentIds, int32(quiz.Id))
|
quiz.ParentIds = append(quiz.ParentIds, int32(quiz.Id))
|
||||||
|
|
||||||
if err := s.dal.QuizRepo.UpdateQuiz(ctx.Context(), accountId, quiz); err != nil {
|
if err := r.dal.QuizRepo.UpdateQuiz(ctx.Context(), accountId, quiz); err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,7 +353,7 @@ type CopyQuizReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CopyQuiz request handler for copy quiz
|
// CopyQuiz request handler for copy quiz
|
||||||
func (s *Service) CopyQuiz(ctx *fiber.Ctx) error {
|
func (r *Quiz) CopyQuiz(ctx *fiber.Ctx) error {
|
||||||
var req CopyQuizReq
|
var req CopyQuizReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
@ -351,7 +368,7 @@ func (s *Service) CopyQuiz(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusFailedDependency).SendString("no id provided")
|
return ctx.Status(fiber.StatusFailedDependency).SendString("no id provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
quiz, err := s.dal.QuizRepo.CopyQuiz(ctx.Context(), accountId, req.Id)
|
quiz, err := r.dal.QuizRepo.CopyQuiz(ctx.Context(), accountId, req.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -369,7 +386,7 @@ type GetQuizHistoryReq struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetQuizHistory handler for history of quiz
|
// GetQuizHistory handler for history of quiz
|
||||||
func (s *Service) GetQuizHistory(ctx *fiber.Ctx) error {
|
func (r *Quiz) GetQuizHistory(ctx *fiber.Ctx) error {
|
||||||
var req GetQuizHistoryReq
|
var req GetQuizHistoryReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
@ -383,7 +400,7 @@ func (s *Service) GetQuizHistory(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusFailedDependency).SendString("no id provided")
|
return ctx.Status(fiber.StatusFailedDependency).SendString("no id provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
history, err := s.dal.QuizRepo.QuizHistory(ctx.Context(), quiz.QuizHistoryDeps{
|
history, err := r.dal.QuizRepo.QuizHistory(ctx.Context(), quiz.QuizHistoryDeps{
|
||||||
Id: req.Id,
|
Id: req.Id,
|
||||||
Limit: req.Limit,
|
Limit: req.Limit,
|
||||||
Offset: req.Page * req.Limit,
|
Offset: req.Page * req.Limit,
|
||||||
@ -406,7 +423,7 @@ type DeactivateResp struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteQuiz handler for fake delete quiz
|
// DeleteQuiz handler for fake delete quiz
|
||||||
func (s *Service) DeleteQuiz(ctx *fiber.Ctx) error {
|
func (r *Quiz) DeleteQuiz(ctx *fiber.Ctx) error {
|
||||||
var req DeactivateReq
|
var req DeactivateReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
@ -422,7 +439,7 @@ func (s *Service) DeleteQuiz(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusFailedDependency).SendString("id for deleting is required")
|
return ctx.Status(fiber.StatusFailedDependency).SendString("id for deleting is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
deleted, err := s.dal.QuizRepo.DeleteQuiz(ctx.Context(), accountId, req.Id)
|
deleted, err := r.dal.QuizRepo.DeleteQuiz(ctx.Context(), accountId, req.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -438,7 +455,7 @@ func (s *Service) DeleteQuiz(ctx *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ArchiveQuiz handler for archiving quiz
|
// ArchiveQuiz handler for archiving quiz
|
||||||
func (s *Service) ArchiveQuiz(ctx *fiber.Ctx) error {
|
func (r *Quiz) ArchiveQuiz(ctx *fiber.Ctx) error {
|
||||||
var req DeactivateReq
|
var req DeactivateReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
@ -453,7 +470,7 @@ func (s *Service) ArchiveQuiz(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusFailedDependency).SendString("id for archive quiz is required")
|
return ctx.Status(fiber.StatusFailedDependency).SendString("id for archive quiz is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
archived, err := s.dal.QuizRepo.DeleteQuiz(ctx.Context(), accountId, req.Id)
|
archived, err := r.dal.QuizRepo.DeleteQuiz(ctx.Context(), accountId, req.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -467,7 +484,7 @@ type QuizMoveReq struct {
|
|||||||
Qid, AccountID string
|
Qid, AccountID string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) QuizMove(ctx *fiber.Ctx) error {
|
func (r *Quiz) QuizMove(ctx *fiber.Ctx) error {
|
||||||
var req QuizMoveReq
|
var req QuizMoveReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
@ -477,7 +494,7 @@ func (s *Service) QuizMove(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request qid and accountID is required")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request qid and accountID is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := s.dal.QuizRepo.QuizMove(ctx.Context(), req.Qid, req.AccountID)
|
resp, err := r.dal.QuizRepo.QuizMove(ctx.Context(), req.Qid, req.AccountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -485,7 +502,7 @@ func (s *Service) QuizMove(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusOK).JSON(resp)
|
return ctx.Status(fiber.StatusOK).JSON(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) TemplateCopy(ctx *fiber.Ctx) error {
|
func (r *Quiz) TemplateCopy(ctx *fiber.Ctx) error {
|
||||||
accountID, ok := middleware.GetAccountId(ctx)
|
accountID, ok := middleware.GetAccountId(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
||||||
@ -504,7 +521,7 @@ func (s *Service) TemplateCopy(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request qid is required")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request qid is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
qizID, err := s.dal.QuizRepo.TemplateCopy(ctx.Context(), accountID, req.Qid)
|
qizID, err := r.dal.QuizRepo.TemplateCopy(ctx.Context(), accountID, req.Qid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("TEMPLERR", err)
|
fmt.Println("TEMPLERR", err)
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
19
internal/controllers/http_controllers/quiz/route.go
Normal file
19
internal/controllers/http_controllers/quiz/route.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package quiz
|
||||||
|
|
||||||
|
import "github.com/gofiber/fiber/v2"
|
||||||
|
|
||||||
|
func (r *Quiz) Register(router fiber.Router) {
|
||||||
|
router.Post("/create", r.CreateQuiz)
|
||||||
|
router.Post("/getList", r.GetQuizList)
|
||||||
|
router.Patch("/edit", r.UpdateQuiz)
|
||||||
|
router.Post("/copy", r.CopyQuiz)
|
||||||
|
router.Post("/history", r.GetQuizHistory)
|
||||||
|
router.Delete("/delete", r.DeleteQuiz)
|
||||||
|
router.Patch("/archive", r.ArchiveQuiz)
|
||||||
|
router.Post("/move", r.QuizMove)
|
||||||
|
router.Post("/template", r.TemplateCopy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Quiz) Name() string {
|
||||||
|
return "quiz"
|
||||||
|
}
|
@ -1,16 +1,34 @@
|
|||||||
package service
|
package result
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/middleware"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/middleware"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/repository/result"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/repository/result"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/tools"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/tools"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Deps struct {
|
||||||
|
DAL *dal.DAL
|
||||||
|
S3Prefix string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Result struct {
|
||||||
|
dal *dal.DAL
|
||||||
|
s3Prefix string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewResultController(deps Deps) *Result {
|
||||||
|
return &Result{
|
||||||
|
dal: deps.DAL,
|
||||||
|
s3Prefix: deps.S3Prefix,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ReqExport struct {
|
type ReqExport struct {
|
||||||
To, From time.Time
|
To, From time.Time
|
||||||
New bool
|
New bool
|
||||||
@ -23,7 +41,7 @@ type ReqExportResponse struct {
|
|||||||
Results []model.AnswerExport `json:"results"`
|
Results []model.AnswerExport `json:"results"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetResultsByQuizID(ctx *fiber.Ctx) error {
|
func (r *Result) GetResultsByQuizID(ctx *fiber.Ctx) error {
|
||||||
payment := true // параметр для определения существования текущих привилегий юзера
|
payment := true // параметр для определения существования текущих привилегий юзера
|
||||||
|
|
||||||
accountID, ok := middleware.GetAccountId(ctx)
|
accountID, ok := middleware.GetAccountId(ctx)
|
||||||
@ -42,7 +60,7 @@ func (s *Service) GetResultsByQuizID(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid quiz ID format")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid quiz ID format")
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err := s.dal.AccountRepo.GetAccountByID(ctx.Context(), accountID)
|
account, err := r.dal.AccountRepo.GetAccountByID(ctx.Context(), accountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -52,7 +70,7 @@ func (s *Service) GetResultsByQuizID(ctx *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
results, totalCount, err := s.dal.ResultRepo.GetQuizResults(ctx.Context(), quizID, result.GetQuizResDeps{
|
results, totalCount, err := r.dal.ResultRepo.GetQuizResults(ctx.Context(), quizID, result.GetQuizResDeps{
|
||||||
To: req.To,
|
To: req.To,
|
||||||
From: req.From,
|
From: req.From,
|
||||||
New: req.New,
|
New: req.New,
|
||||||
@ -71,7 +89,7 @@ func (s *Service) GetResultsByQuizID(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusOK).JSON(resp)
|
return ctx.Status(fiber.StatusOK).JSON(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) DelResultByID(ctx *fiber.Ctx) error {
|
func (r *Result) DelResultByID(ctx *fiber.Ctx) error {
|
||||||
accountID, ok := middleware.GetAccountId(ctx)
|
accountID, ok := middleware.GetAccountId(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ctx.Status(fiber.StatusUnauthorized).SendString("could not get account ID from token")
|
return ctx.Status(fiber.StatusUnauthorized).SendString("could not get account ID from token")
|
||||||
@ -83,7 +101,7 @@ func (s *Service) DelResultByID(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid result ID format")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid result ID format")
|
||||||
}
|
}
|
||||||
|
|
||||||
isOwner, err := s.dal.ResultRepo.CheckResultOwner(ctx.Context(), resultID, accountID)
|
isOwner, err := r.dal.ResultRepo.CheckResultOwner(ctx.Context(), resultID, accountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -92,7 +110,7 @@ func (s *Service) DelResultByID(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusUnauthorized).SendString("not the owner of the result")
|
return ctx.Status(fiber.StatusUnauthorized).SendString("not the owner of the result")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.dal.ResultRepo.SoftDeleteResultByID(ctx.Context(), resultID); err != nil {
|
if err := r.dal.ResultRepo.SoftDeleteResultByID(ctx.Context(), resultID); err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +122,7 @@ type ReqSeen struct {
|
|||||||
Answers []int64
|
Answers []int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) SetStatus(ctx *fiber.Ctx) error {
|
func (r *Result) SetStatus(ctx *fiber.Ctx) error {
|
||||||
var req ReqSeen
|
var req ReqSeen
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
@ -115,7 +133,7 @@ func (s *Service) SetStatus(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusUnauthorized).SendString("could not get account ID from token")
|
return ctx.Status(fiber.StatusUnauthorized).SendString("could not get account ID from token")
|
||||||
}
|
}
|
||||||
|
|
||||||
answers, err := s.dal.ResultRepo.CheckResultsOwner(ctx.Context(), req.Answers, accountID)
|
answers, err := r.dal.ResultRepo.CheckResultsOwner(ctx.Context(), req.Answers, accountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -124,14 +142,14 @@ func (s *Service) SetStatus(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusNotAcceptable).SendString("could not update some answers because you don't have rights")
|
return ctx.Status(fiber.StatusNotAcceptable).SendString("could not update some answers because you don't have rights")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.dal.ResultRepo.UpdateAnswersStatus(ctx.Context(), accountID, answers); err != nil {
|
if err := r.dal.ResultRepo.UpdateAnswersStatus(ctx.Context(), accountID, answers); err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.Status(fiber.StatusOK).JSON(nil)
|
return ctx.Status(fiber.StatusOK).JSON(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) ExportResultsToCSV(ctx *fiber.Ctx) error {
|
func (r *Result) ExportResultsToCSV(ctx *fiber.Ctx) error {
|
||||||
accountID, ok := middleware.GetAccountId(ctx)
|
accountID, ok := middleware.GetAccountId(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
||||||
@ -148,7 +166,7 @@ func (s *Service) ExportResultsToCSV(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusBadRequest).SendString("invalid request body")
|
return ctx.Status(fiber.StatusBadRequest).SendString("invalid request body")
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err := s.dal.AccountRepo.GetAccountByID(ctx.Context(), accountID)
|
account, err := r.dal.AccountRepo.GetAccountByID(ctx.Context(), accountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -159,17 +177,17 @@ func (s *Service) ExportResultsToCSV(ctx *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
quiz, err := s.dal.QuizRepo.GetQuizById(ctx.Context(), accountID, quizID)
|
quiz, err := r.dal.QuizRepo.GetQuizById(ctx.Context(), accountID, quizID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString("failed to get quiz")
|
return ctx.Status(fiber.StatusInternalServerError).SendString("failed to get quiz")
|
||||||
}
|
}
|
||||||
|
|
||||||
questions, err := s.dal.ResultRepo.GetQuestions(ctx.Context(), quizID)
|
questions, err := r.dal.ResultRepo.GetQuestions(ctx.Context(), quizID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString("failed to get questions")
|
return ctx.Status(fiber.StatusInternalServerError).SendString("failed to get questions")
|
||||||
}
|
}
|
||||||
|
|
||||||
answers, err := s.dal.ResultRepo.GetQuizResultsCSV(ctx.Context(), quizID, result.GetQuizResDeps{
|
answers, err := r.dal.ResultRepo.GetQuizResultsCSV(ctx.Context(), quizID, result.GetQuizResDeps{
|
||||||
To: req.To,
|
To: req.To,
|
||||||
From: req.From,
|
From: req.From,
|
||||||
New: req.New,
|
New: req.New,
|
||||||
@ -182,7 +200,7 @@ func (s *Service) ExportResultsToCSV(ctx *fiber.Ctx) error {
|
|||||||
|
|
||||||
buffer := new(bytes.Buffer)
|
buffer := new(bytes.Buffer)
|
||||||
|
|
||||||
if err := tools.WriteDataToExcel(buffer, questions, answers, s.s3Prefix + quiz.Qid + "/"); err != nil {
|
if err := tools.WriteDataToExcel(buffer, questions, answers, r.s3Prefix+quiz.Qid+"/"); err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString("failed to write data to Excel")
|
return ctx.Status(fiber.StatusInternalServerError).SendString("failed to write data to Excel")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +210,7 @@ func (s *Service) ExportResultsToCSV(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Send(buffer.Bytes())
|
return ctx.Send(buffer.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetResultAnswers(ctx *fiber.Ctx) error {
|
func (r *Result) GetResultAnswers(ctx *fiber.Ctx) error {
|
||||||
accountID, ok := middleware.GetAccountId(ctx)
|
accountID, ok := middleware.GetAccountId(ctx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
return ctx.Status(fiber.StatusUnauthorized).SendString("account id is required")
|
||||||
@ -203,7 +221,7 @@ func (s *Service) GetResultAnswers(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusBadRequest).SendString("invalid quiz ID")
|
return ctx.Status(fiber.StatusBadRequest).SendString("invalid quiz ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err := s.dal.AccountRepo.GetAccountByID(ctx.Context(), accountID)
|
account, err := r.dal.AccountRepo.GetAccountByID(ctx.Context(), accountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -214,11 +232,11 @@ func (s *Service) GetResultAnswers(ctx *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
answers, err := s.dal.ResultRepo.GetResultAnswers(ctx.Context(), resultID)
|
answers, err := r.dal.ResultRepo.GetResultAnswers(ctx.Context(), resultID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString("failed to get result answers")
|
return ctx.Status(fiber.StatusInternalServerError).SendString("failed to get result answers")
|
||||||
}
|
}
|
||||||
sortedAnswers, err := s.dal.QuestionRepo.ForSortingResults(ctx.Context(), answers)
|
sortedAnswers, err := r.dal.QuestionRepo.ForSortingResults(ctx.Context(), answers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString("failed sort result answers")
|
return ctx.Status(fiber.StatusInternalServerError).SendString("failed sort result answers")
|
||||||
}
|
}
|
15
internal/controllers/http_controllers/result/route.go
Normal file
15
internal/controllers/http_controllers/result/route.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package result
|
||||||
|
|
||||||
|
import "github.com/gofiber/fiber/v2"
|
||||||
|
|
||||||
|
func (r *Result) Register(router fiber.Router) {
|
||||||
|
router.Post("/results/getResults/:quizId", r.GetResultsByQuizID)
|
||||||
|
router.Delete("/results/delete/:resultId", r.DelResultByID)
|
||||||
|
router.Patch("/result/seen", r.SetStatus)
|
||||||
|
router.Post("/results/:quizID/export", r.ExportResultsToCSV)
|
||||||
|
router.Get("/result/:resultID", r.GetResultAnswers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Result) Name() string {
|
||||||
|
return ""
|
||||||
|
}
|
15
internal/controllers/http_controllers/statistic/route.go
Normal file
15
internal/controllers/http_controllers/statistic/route.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package statistic
|
||||||
|
|
||||||
|
import "github.com/gofiber/fiber/v2"
|
||||||
|
|
||||||
|
func (r *Statistic) Register(router fiber.Router) {
|
||||||
|
router.Post("/statistic/:quizID/devices", r.GetDeviceStatistics)
|
||||||
|
router.Post("/statistic/:quizID/general", r.GetGeneralStatistics)
|
||||||
|
router.Post("/statistic/:quizID/questions", r.GetQuestionsStatistics)
|
||||||
|
router.Post("/statistic", r.AllServiceStatistics)
|
||||||
|
router.Get("/statistics/:quizID/pipelines", r.GetPipelinesStatistics)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Statistic) Name() string {
|
||||||
|
return ""
|
||||||
|
}
|
@ -1,17 +1,35 @@
|
|||||||
package service
|
package statistic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/repository/statistics"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/repository/statistics"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Deps struct {
|
||||||
|
DAL *dal.DAL
|
||||||
|
ChDAL *dal.ClickHouseDAL
|
||||||
|
}
|
||||||
|
|
||||||
|
type Statistic struct {
|
||||||
|
dal *dal.DAL
|
||||||
|
chDAL *dal.ClickHouseDAL
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewStatisticController(deps Deps) *Statistic {
|
||||||
|
return &Statistic{
|
||||||
|
dal: deps.DAL,
|
||||||
|
chDAL: deps.ChDAL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type DeviceStatReq struct {
|
type DeviceStatReq struct {
|
||||||
From uint64 // временные границы выбора статистики
|
From uint64 // временные границы выбора статистики
|
||||||
To uint64
|
To uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetDeviceStatistics(ctx *fiber.Ctx) error {
|
func (r *Statistic) GetDeviceStatistics(ctx *fiber.Ctx) error {
|
||||||
quizIDStr := ctx.Params("quizID")
|
quizIDStr := ctx.Params("quizID")
|
||||||
|
|
||||||
quizID, err := strconv.ParseInt(quizIDStr, 10, 64)
|
quizID, err := strconv.ParseInt(quizIDStr, 10, 64)
|
||||||
@ -24,7 +42,7 @@ func (s *Service) GetDeviceStatistics(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceStats, err := s.dal.StatisticsRepo.GetDeviceStatistics(ctx.Context(), statistics.DeviceStatReq{
|
deviceStats, err := r.dal.StatisticsRepo.GetDeviceStatistics(ctx.Context(), statistics.DeviceStatReq{
|
||||||
QuizId: quizID,
|
QuizId: quizID,
|
||||||
From: req.From,
|
From: req.From,
|
||||||
To: req.To,
|
To: req.To,
|
||||||
@ -40,7 +58,7 @@ type GeneralStatsResp struct {
|
|||||||
Open, Result, AvTime, Conversion map[uint64]uint64
|
Open, Result, AvTime, Conversion map[uint64]uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetGeneralStatistics(ctx *fiber.Ctx) error {
|
func (r *Statistic) GetGeneralStatistics(ctx *fiber.Ctx) error {
|
||||||
quizIDStr := ctx.Params("quizID")
|
quizIDStr := ctx.Params("quizID")
|
||||||
quizID, err := strconv.ParseInt(quizIDStr, 10, 64)
|
quizID, err := strconv.ParseInt(quizIDStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -52,7 +70,7 @@ func (s *Service) GetGeneralStatistics(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
}
|
}
|
||||||
|
|
||||||
generalStats, err := s.dal.StatisticsRepo.GetGeneralStatistics(ctx.Context(), statistics.DeviceStatReq{
|
generalStats, err := r.dal.StatisticsRepo.GetGeneralStatistics(ctx.Context(), statistics.DeviceStatReq{
|
||||||
QuizId: quizID,
|
QuizId: quizID,
|
||||||
From: req.From,
|
From: req.From,
|
||||||
To: req.To,
|
To: req.To,
|
||||||
@ -64,7 +82,7 @@ func (s *Service) GetGeneralStatistics(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusOK).JSON(generalStats)
|
return ctx.Status(fiber.StatusOK).JSON(generalStats)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetQuestionsStatistics(ctx *fiber.Ctx) error {
|
func (r *Statistic) GetQuestionsStatistics(ctx *fiber.Ctx) error {
|
||||||
quizIDStr := ctx.Params("quizID")
|
quizIDStr := ctx.Params("quizID")
|
||||||
quizID, err := strconv.ParseInt(quizIDStr, 0, 64)
|
quizID, err := strconv.ParseInt(quizIDStr, 0, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -76,7 +94,7 @@ func (s *Service) GetQuestionsStatistics(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
}
|
}
|
||||||
|
|
||||||
questionsStats, err := s.dal.StatisticsRepo.GetQuestionsStatistics(ctx.Context(), statistics.DeviceStatReq{
|
questionsStats, err := r.dal.StatisticsRepo.GetQuestionsStatistics(ctx.Context(), statistics.DeviceStatReq{
|
||||||
QuizId: quizID,
|
QuizId: quizID,
|
||||||
From: req.From,
|
From: req.From,
|
||||||
To: req.To,
|
To: req.To,
|
||||||
@ -92,13 +110,13 @@ type StatisticReq struct {
|
|||||||
From, To uint64 // временные границы выбора статистики
|
From, To uint64 // временные границы выбора статистики
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) AllServiceStatistics(ctx *fiber.Ctx) error {
|
func (r *Statistic) AllServiceStatistics(ctx *fiber.Ctx) error {
|
||||||
var req StatisticReq
|
var req StatisticReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
}
|
}
|
||||||
|
|
||||||
allSvcStats, err := s.dal.StatisticsRepo.AllServiceStatistics(ctx.Context(), req.From, req.To)
|
allSvcStats, err := r.dal.StatisticsRepo.AllServiceStatistics(ctx.Context(), req.From, req.To)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -106,7 +124,7 @@ func (s *Service) AllServiceStatistics(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusOK).JSON(allSvcStats)
|
return ctx.Status(fiber.StatusOK).JSON(allSvcStats)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetPipelinesStatistics(ctx *fiber.Ctx) error {
|
func (r *Statistic) GetPipelinesStatistics(ctx *fiber.Ctx) error {
|
||||||
var req StatisticReq
|
var req StatisticReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
@ -118,7 +136,7 @@ func (s *Service) GetPipelinesStatistics(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid quiz ID format")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid quiz ID format")
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := s.chDAL.StatisticClickRepo.GetPipelinesStatistics(ctx.Context(), quizID, req.From, req.To)
|
result, err := r.chDAL.StatisticClickRepo.GetPipelinesStatistics(ctx.Context(), quizID, req.From, req.To)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
14
internal/controllers/http_controllers/telegram/route.go
Normal file
14
internal/controllers/http_controllers/telegram/route.go
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package telegram
|
||||||
|
|
||||||
|
import "github.com/gofiber/fiber/v2"
|
||||||
|
|
||||||
|
func (r *Telegram) Register(router fiber.Router) {
|
||||||
|
router.Get("/pool", r.GetPoolTgAccounts)
|
||||||
|
router.Post("/create", r.AddingTgAccount)
|
||||||
|
router.Delete("/:id", r.DeleteTgAccountByID)
|
||||||
|
router.Post("/setCode", r.SettingTgCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Telegram) Name() string {
|
||||||
|
return "telegram"
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package service
|
package telegram
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@ -6,20 +6,38 @@ import (
|
|||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/rs/xid"
|
"github.com/rs/xid"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/pj_errors"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/pj_errors"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/clients/telegram"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/clients/telegram"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/tdlib/client"
|
"penahub.gitlab.yandexcloud.net/backend/tdlib/client"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Deps struct {
|
||||||
|
DAL *dal.DAL
|
||||||
|
TelegramClient *telegram.TelegramClient
|
||||||
|
}
|
||||||
|
|
||||||
|
type Telegram struct {
|
||||||
|
dal *dal.DAL
|
||||||
|
telegramClient *telegram.TelegramClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTelegramController(deps Deps) *Telegram {
|
||||||
|
return &Telegram{
|
||||||
|
dal: deps.DAL,
|
||||||
|
telegramClient: deps.TelegramClient,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Data string `json:"data"`
|
Data string `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetPoolTgAccounts(ctx *fiber.Ctx) error {
|
func (r *Telegram) GetPoolTgAccounts(ctx *fiber.Ctx) error {
|
||||||
allAccounts, err := s.dal.TgRepo.GetAllTgAccounts(ctx.Context())
|
allAccounts, err := r.dal.TgRepo.GetAllTgAccounts(ctx.Context())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
switch {
|
switch {
|
||||||
case errors.Is(err, pj_errors.ErrNotFound):
|
case errors.Is(err, pj_errors.ErrNotFound):
|
||||||
@ -31,7 +49,7 @@ func (s *Service) GetPoolTgAccounts(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusOK).JSON(allAccounts)
|
return ctx.Status(fiber.StatusOK).JSON(allAccounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) AddingTgAccount(ctx *fiber.Ctx) error {
|
func (r *Telegram) AddingTgAccount(ctx *fiber.Ctx) error {
|
||||||
var req telegram.AuthTgUserReq
|
var req telegram.AuthTgUserReq
|
||||||
if err := ctx.BodyParser(&req); err != nil {
|
if err := ctx.BodyParser(&req); err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid request data")
|
||||||
@ -39,7 +57,7 @@ func (s *Service) AddingTgAccount(ctx *fiber.Ctx) error {
|
|||||||
if req.ApiID == 0 || req.ApiHash == "" || req.Password == "" || req.PhoneNumber == "" {
|
if req.ApiID == 0 || req.ApiHash == "" || req.Password == "" || req.PhoneNumber == "" {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("empty required fields")
|
return ctx.Status(fiber.StatusBadRequest).SendString("empty required fields")
|
||||||
}
|
}
|
||||||
allAccounts, err := s.dal.TgRepo.GetAllTgAccounts(ctx.Context())
|
allAccounts, err := r.dal.TgRepo.GetAllTgAccounts(ctx.Context())
|
||||||
if err != nil && !errors.Is(err, pj_errors.ErrNotFound) {
|
if err != nil && !errors.Is(err, pj_errors.ErrNotFound) {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
||||||
@ -84,7 +102,7 @@ func (s *Service) AddingTgAccount(ctx *fiber.Ctx) error {
|
|||||||
fmt.Println("new client failed", err)
|
fmt.Println("new client failed", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.telegramClient.SaveTgAccount(req.ApiID, req.ApiHash, tdlibClient)
|
r.telegramClient.SaveTgAccount(req.ApiID, req.ApiHash, tdlibClient)
|
||||||
fmt.Println("i am down")
|
fmt.Println("i am down")
|
||||||
}()
|
}()
|
||||||
if goErr != nil {
|
if goErr != nil {
|
||||||
@ -102,7 +120,7 @@ func (s *Service) AddingTgAccount(ctx *fiber.Ctx) error {
|
|||||||
authorizer.PhoneNumber <- req.PhoneNumber
|
authorizer.PhoneNumber <- req.PhoneNumber
|
||||||
case client.TypeAuthorizationStateWaitCode:
|
case client.TypeAuthorizationStateWaitCode:
|
||||||
signature := xid.New()
|
signature := xid.New()
|
||||||
s.telegramClient.AddedToMap(telegram.WaitingClient{
|
r.telegramClient.AddedToMap(telegram.WaitingClient{
|
||||||
PreviousReq: req,
|
PreviousReq: req,
|
||||||
Authorizer: authorizer,
|
Authorizer: authorizer,
|
||||||
}, signature.String())
|
}, signature.String())
|
||||||
@ -114,7 +132,7 @@ func (s *Service) AddingTgAccount(ctx *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) SettingTgCode(ctx *fiber.Ctx) error {
|
func (r *Telegram) SettingTgCode(ctx *fiber.Ctx) error {
|
||||||
var req struct {
|
var req struct {
|
||||||
Code string `json:"code"`
|
Code string `json:"code"`
|
||||||
Signature string `json:"signature"`
|
Signature string `json:"signature"`
|
||||||
@ -127,7 +145,7 @@ func (s *Service) SettingTgCode(ctx *fiber.Ctx) error {
|
|||||||
return ctx.Status(fiber.StatusBadRequest).SendString("empty required fields")
|
return ctx.Status(fiber.StatusBadRequest).SendString("empty required fields")
|
||||||
}
|
}
|
||||||
|
|
||||||
data, ok := s.telegramClient.GetFromMap(req.Signature)
|
data, ok := r.telegramClient.GetFromMap(req.Signature)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid id, don't have data")
|
return ctx.Status(fiber.StatusBadRequest).SendString("Invalid id, don't have data")
|
||||||
}
|
}
|
||||||
@ -140,7 +158,7 @@ func (s *Service) SettingTgCode(ctx *fiber.Ctx) error {
|
|||||||
fmt.Println("currnet state:", state)
|
fmt.Println("currnet state:", state)
|
||||||
switch state.AuthorizationStateType() {
|
switch state.AuthorizationStateType() {
|
||||||
case client.TypeAuthorizationStateReady:
|
case client.TypeAuthorizationStateReady:
|
||||||
id, err := s.dal.TgRepo.CreateTgAccount(ctx.Context(), model.TgAccount{
|
id, err := r.dal.TgRepo.CreateTgAccount(ctx.Context(), model.TgAccount{
|
||||||
ApiID: data.PreviousReq.ApiID,
|
ApiID: data.PreviousReq.ApiID,
|
||||||
ApiHash: data.PreviousReq.ApiHash,
|
ApiHash: data.PreviousReq.ApiHash,
|
||||||
PhoneNumber: data.PreviousReq.PhoneNumber,
|
PhoneNumber: data.PreviousReq.PhoneNumber,
|
||||||
@ -159,12 +177,12 @@ func (s *Service) SettingTgCode(ctx *fiber.Ctx) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) DeleteTgAccountByID(ctx *fiber.Ctx) error {
|
func (r *Telegram) DeleteTgAccountByID(ctx *fiber.Ctx) error {
|
||||||
id, err := strconv.ParseInt(ctx.Params("id"), 10, 64)
|
id, err := strconv.ParseInt(ctx.Params("id"), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusBadRequest).SendString("invalid id format")
|
return ctx.Status(fiber.StatusBadRequest).SendString("invalid id format")
|
||||||
}
|
}
|
||||||
err = s.dal.TgRepo.SoftDeleteTgAccount(ctx.Context(), id)
|
err = r.dal.TgRepo.SoftDeleteTgAccount(ctx.Context(), id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
return ctx.Status(fiber.StatusInternalServerError).SendString(err.Error())
|
||||||
}
|
}
|
@ -1,13 +1,13 @@
|
|||||||
package rpc_service
|
package rpc_controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/proto/notifyer"
|
notifyer2 "penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/proto/notifyer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MailNotify struct {
|
type MailNotify struct {
|
||||||
notifyer.UnimplementedQuizServiceServer
|
notifyer2.UnimplementedQuizServiceServer
|
||||||
dal *dal.DAL
|
dal *dal.DAL
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,23 +17,23 @@ func NewMailNotify(dal *dal.DAL) *MailNotify {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MailNotify) GetQuizzes(ctx context.Context, in *notifyer.GetQuizzesRequest) (*notifyer.GetQuizzesResponse, error) {
|
func (m *MailNotify) GetQuizzes(ctx context.Context, in *notifyer2.GetQuizzesRequest) (*notifyer2.GetQuizzesResponse, error) {
|
||||||
ids, err := m.dal.QuizRepo.GetAllQuizzesID(ctx, in.AccountId)
|
ids, err := m.dal.QuizRepo.GetAllQuizzesID(ctx, in.AccountId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resp := ¬ifyer.GetQuizzesResponse{
|
resp := ¬ifyer2.GetQuizzesResponse{
|
||||||
QuizIds: ids,
|
QuizIds: ids,
|
||||||
}
|
}
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MailNotify) GetStartedQuizzes(ctx context.Context, in *notifyer.GetStartedQuizzesRequest) (*notifyer.GetStartedQuizzesResponse, error) {
|
func (m *MailNotify) GetStartedQuizzes(ctx context.Context, in *notifyer2.GetStartedQuizzesRequest) (*notifyer2.GetStartedQuizzesResponse, error) {
|
||||||
ids, err := m.dal.QuizRepo.GetStartedQuizzesID(ctx, in.AccountId)
|
ids, err := m.dal.QuizRepo.GetStartedQuizzesID(ctx, in.AccountId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resp := ¬ifyer.GetStartedQuizzesResponse{
|
resp := ¬ifyer2.GetStartedQuizzesResponse{
|
||||||
QuizIds: ids,
|
QuizIds: ids,
|
||||||
}
|
}
|
||||||
return resp, nil
|
return resp, nil
|
25
internal/initialize/clients.go
Normal file
25
internal/initialize/clients.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package initialize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/clients/auth"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/clients/telegram"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Clients struct {
|
||||||
|
AuthClient *auth.AuthClient
|
||||||
|
TgClient *telegram.TelegramClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClients(ctx context.Context, cfg Config, pgDAL *dal.DAL) (*Clients, error) {
|
||||||
|
tgClient, err := telegram.NewTelegramClient(ctx, pgDAL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Clients{
|
||||||
|
TgClient: tgClient,
|
||||||
|
AuthClient: auth.NewAuthClient(cfg.AuthServiceURL),
|
||||||
|
}, nil
|
||||||
|
}
|
43
internal/initialize/config.go
Normal file
43
internal/initialize/config.go
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
package initialize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/caarlos0/env/v8"
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
LoggerProdMode bool `env:"IS_PROD_LOG" envDefault:"false"`
|
||||||
|
IsProd bool `env:"IS_PROD" envDefault:"false"`
|
||||||
|
NumberPort string `env:"PORT" envDefault:"1488"`
|
||||||
|
HttpHost string `env:"HTTP_HOST" envDefault:"0.0.0.0"`
|
||||||
|
CrtFile string `env:"CRT" envDefault:"server.crt"`
|
||||||
|
KeyFile string `env:"KEY" envDefault:"server.key"`
|
||||||
|
PostgresCredentials string `env:"PG_CRED" envDefault:"host=localhost port=35432 user=squiz password=Redalert2 dbname=squiz sslmode=disable"`
|
||||||
|
HubAdminUrl string `env:"HUB_ADMIN_URL" envDefault:"http://localhost:8001/"`
|
||||||
|
ServiceName string `env:"SERVICE_NAME" envDefault:"squiz"`
|
||||||
|
AuthServiceURL string `env:"AUTH_URL" envDefault:"http://localhost:8000/"`
|
||||||
|
GrpcHost string `env:"GRPC_HOST" envDefault:"localhost"`
|
||||||
|
GrpcPort string `env:"GRPC_PORT" envDefault:"9000"`
|
||||||
|
KafkaBrokers string `env:"KAFKA_BROKERS" envDefault:"localhost:9092"`
|
||||||
|
KafkaTopic string `env:"KAFKA_TOPIC" envDefault:"test-topic"`
|
||||||
|
KafkaGroup string `env:"KAFKA_GROUP" envDefault:"mailnotifier"`
|
||||||
|
TrashLogHost string `env:"TRASH_LOG_HOST" envDefault:"localhost:7113"`
|
||||||
|
ModuleLogger string `env:"MODULE_LOGGER" envDefault:"core-local"`
|
||||||
|
ClickHouseCred string `env:"CLICK_HOUSE_CRED" envDefault:"tcp://10.8.0.15:9000/default?sslmode=disable"`
|
||||||
|
RedisHost string `env:"REDIS_HOST" envDefault:"localhost:6379"`
|
||||||
|
RedisPassword string `env:"REDIS_PASSWORD" envDefault:"admin"`
|
||||||
|
RedisDB uint64 `env:"REDIS_DB" envDefault:"2"`
|
||||||
|
S3Prefix string `env:"S3_PREFIX"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoadConfig() (*Config, error) {
|
||||||
|
if err := godotenv.Load(); err != nil {
|
||||||
|
log.Print("No .env file found")
|
||||||
|
}
|
||||||
|
var config Config
|
||||||
|
if err := env.Parse(&config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &config, nil
|
||||||
|
}
|
73
internal/initialize/controllers.go
Normal file
73
internal/initialize/controllers.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package initialize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/brokers"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/controllers/http_controllers/account"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/controllers/http_controllers/question"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/controllers/http_controllers/quiz"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/controllers/http_controllers/result"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/controllers/http_controllers/statistic"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/controllers/http_controllers/telegram"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/controllers/rpc_controllers"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ControllerDeps struct {
|
||||||
|
Clients *Clients
|
||||||
|
DALs *DALs
|
||||||
|
Config Config
|
||||||
|
Producer *brokers.Producer
|
||||||
|
RedisClient *redis.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type Controller struct {
|
||||||
|
GRpcControllers GRpcControllers
|
||||||
|
HttpControllers HttpControllers
|
||||||
|
}
|
||||||
|
|
||||||
|
type GRpcControllers struct {
|
||||||
|
MailNotify *rpc_controllers.MailNotify
|
||||||
|
}
|
||||||
|
type HttpControllers struct {
|
||||||
|
Account *account.Account
|
||||||
|
Question *question.Question
|
||||||
|
Quiz *quiz.Quiz
|
||||||
|
Result *result.Result
|
||||||
|
Statistic *statistic.Statistic
|
||||||
|
Telegram *telegram.Telegram
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewControllers(deps ControllerDeps) *Controller {
|
||||||
|
return &Controller{
|
||||||
|
GRpcControllers: GRpcControllers{
|
||||||
|
MailNotify: rpc_controllers.NewMailNotify(deps.DALs.PgDAL),
|
||||||
|
},
|
||||||
|
HttpControllers: HttpControllers{
|
||||||
|
Account: account.NewAccountController(account.Deps{
|
||||||
|
Dal: deps.DALs.PgDAL,
|
||||||
|
AuthClient: deps.Clients.AuthClient,
|
||||||
|
Producer: deps.Producer,
|
||||||
|
ServiceName: deps.Config.ServiceName,
|
||||||
|
RedisClient: deps.RedisClient,
|
||||||
|
}),
|
||||||
|
Question: question.NewQuestionController(question.Deps{
|
||||||
|
DAL: deps.DALs.PgDAL,
|
||||||
|
}),
|
||||||
|
Quiz: quiz.NewQuizController(quiz.Deps{
|
||||||
|
DAL: deps.DALs.PgDAL,
|
||||||
|
}),
|
||||||
|
Result: result.NewResultController(result.Deps{
|
||||||
|
DAL: deps.DALs.PgDAL,
|
||||||
|
S3Prefix: deps.Config.S3Prefix,
|
||||||
|
}),
|
||||||
|
Statistic: statistic.NewStatisticController(statistic.Deps{
|
||||||
|
DAL: deps.DALs.PgDAL,
|
||||||
|
ChDAL: deps.DALs.ChDAL,
|
||||||
|
}),
|
||||||
|
Telegram: telegram.NewTelegramController(telegram.Deps{
|
||||||
|
DAL: deps.DALs.PgDAL,
|
||||||
|
TelegramClient: deps.Clients.TgClient,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
28
internal/initialize/dals.go
Normal file
28
internal/initialize/dals.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package initialize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DALs struct {
|
||||||
|
PgDAL *dal.DAL
|
||||||
|
ChDAL *dal.ClickHouseDAL
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDALs(ctx context.Context, cfg Config) (*DALs, error) {
|
||||||
|
pgDal, err := dal.New(ctx, cfg.PostgresCredentials, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
chDal, err := dal.NewClickHouseDAL(ctx, cfg.ClickHouseCred)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &DALs{
|
||||||
|
PgDAL: pgDal,
|
||||||
|
ChDAL: chDal,
|
||||||
|
}, nil
|
||||||
|
}
|
21
internal/initialize/redis.go
Normal file
21
internal/initialize/redis.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package initialize
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/go-redis/redis/v8"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Redis(ctx context.Context, cfg Config) (*redis.Client, error) {
|
||||||
|
rdb := redis.NewClient(&redis.Options{
|
||||||
|
Addr: cfg.RedisHost,
|
||||||
|
Password: cfg.RedisPassword,
|
||||||
|
DB: int(cfg.RedisDB),
|
||||||
|
})
|
||||||
|
|
||||||
|
status := rdb.Ping(ctx)
|
||||||
|
if err := status.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rdb, nil
|
||||||
|
}
|
@ -9,8 +9,8 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"net"
|
"net"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/initialize"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/initialize"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/proto/notifyer"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/proto/notifyer"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ func (g *GRPC) Stop(_ context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GRPC) Register(reg *initialize.RpcRegister) *GRPC {
|
func (g *GRPC) Register(reg initialize.GRpcControllers) *GRPC {
|
||||||
notifyer.RegisterQuizServiceServer(g.grpc, reg.MailNotify)
|
notifyer.RegisterQuizServiceServer(g.grpc, reg.MailNotify)
|
||||||
// another
|
// another
|
||||||
return g
|
return g
|
73
internal/server/http/http_server.go
Normal file
73
internal/server/http/http_server.go
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
package http
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/themakers/hlog"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/penahub_common/log_mw"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/middleware"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ServerConfig struct {
|
||||||
|
Logger *zap.Logger
|
||||||
|
Controllers []Controller
|
||||||
|
Hlogger hlog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
Logger *zap.Logger
|
||||||
|
Controllers []Controller
|
||||||
|
app *fiber.App
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewServer(config ServerConfig) *Server {
|
||||||
|
app := fiber.New()
|
||||||
|
app.Use(middleware.JWTAuth())
|
||||||
|
app.Use(log_mw.ContextLogger(config.Hlogger))
|
||||||
|
//app.Get("/liveness", healthchecks.Liveness)
|
||||||
|
//app.Get("/readiness", healthchecks.Readiness(&workerErr)) //todo parametrized readiness. should discuss ready reason
|
||||||
|
s := &Server{
|
||||||
|
Logger: config.Logger,
|
||||||
|
Controllers: config.Controllers,
|
||||||
|
app: app,
|
||||||
|
}
|
||||||
|
|
||||||
|
s.registerRoutes()
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Start(addr string) error {
|
||||||
|
if err := s.app.Listen(addr); err != nil {
|
||||||
|
s.Logger.Error("Failed to start server", zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) Shutdown(ctx context.Context) error {
|
||||||
|
return s.app.Shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) registerRoutes() {
|
||||||
|
for _, c := range s.Controllers {
|
||||||
|
router := s.app.Group(c.Name())
|
||||||
|
c.Register(router)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Controller interface {
|
||||||
|
Register(router fiber.Router)
|
||||||
|
Name() string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Server) ListRoutes() {
|
||||||
|
fmt.Println("Registered routes:")
|
||||||
|
for _, stack := range s.app.Stack() {
|
||||||
|
for _, route := range stack {
|
||||||
|
fmt.Printf("%s %s\n", route.Method, route.Path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -187,66 +187,6 @@ func handleImage(file *excelize.File, sheet, cell, content string, count, row in
|
|||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
count := 2
|
|
||||||
for _, q := range questions {
|
|
||||||
if !q.Deleted && q.Type != model.TypeResult {
|
|
||||||
index := binarySearch(response, q.Id)
|
|
||||||
if index != -1 {
|
|
||||||
cell := ToAlphaString(count) + strconv.Itoa(row)
|
|
||||||
tipe := FileSearch(response[index].Content)
|
|
||||||
noAccept := make(map[string]struct{})
|
|
||||||
todoMap := make(map[string]string)
|
|
||||||
if tipe != "Text" && q.Type == model.TypeImages || q.Type == model.TypeVarImages {
|
|
||||||
urle := ExtractImageURL(response[index].Content)
|
|
||||||
urlData := strings.Split(urle, " ")
|
|
||||||
if len(urlData) == 1 {
|
|
||||||
u, err := url.Parse(urle)
|
|
||||||
if err == nil && u.Scheme != "" && u.Host != "" {
|
|
||||||
picture, err := downloadImage(urle)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
}
|
|
||||||
err = file.SetColWidth(sheet, ToAlphaString(count), ToAlphaString(count), 50)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
}
|
|
||||||
err = file.SetRowHeight(sheet, row, 150)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
}
|
|
||||||
if err := file.AddPictureFromBytes(sheet, cell, picture); err != nil {
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
}
|
|
||||||
noAccept[response[index].Content] = struct{}{}
|
|
||||||
} else {
|
|
||||||
todoMap[response[index].Content] = cell
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
todoMap[response[index].Content] = cell
|
|
||||||
}
|
|
||||||
} else if tipe != "Text" && q.Type == model.TypeFile {
|
|
||||||
urle := ExtractImageURL(response[index].Content)
|
|
||||||
display, tooltip := urle, urle
|
|
||||||
if err := file.SetCellValue(sheet, cell, response[index].Content); err != nil {
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
}
|
|
||||||
if err := file.SetCellHyperLink(sheet, cell, urle, "External", excelize.HyperlinkOpts{
|
|
||||||
Display: &display,
|
|
||||||
Tooltip: &tooltip,
|
|
||||||
}); err != nil {
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
}
|
|
||||||
noAccept[response[index].Content] = struct{}{}
|
|
||||||
} else {
|
|
||||||
todoMap[response[index].Content] = cell
|
|
||||||
}
|
|
||||||
for cnt, cel := range todoMap {
|
|
||||||
if _, ok := noAccept[cnt]; !ok {
|
|
||||||
if err := file.SetCellValue(sheet, cel, cnt); err != nil {
|
|
||||||
fmt.Println(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mediaRow := row
|
mediaRow := row
|
||||||
for i, imgContent := range multiImgArr {
|
for i, imgContent := range multiImgArr {
|
||||||
@ -356,7 +296,6 @@ func handleImage(file *excelize.File, sheet, cell, content string, count, row in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleFile(file *excelize.File, sheet, cell, content, s3Prefix string, noAccept map[string]struct{}) {
|
func handleFile(file *excelize.File, sheet, cell, content, s3Prefix string, noAccept map[string]struct{}) {
|
||||||
urle := content
|
urle := content
|
||||||
if urle != "" && !strings.HasPrefix(urle, "https") {
|
if urle != "" && !strings.HasPrefix(urle, "https") {
|
@ -7,7 +7,7 @@ import (
|
|||||||
"github.com/go-redis/redis/v8"
|
"github.com/go-redis/redis/v8"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/model"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/clients/telegram"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/clients/telegram"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
11
main.go
11
main.go
@ -1,11 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/skeris/appInit"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/app"
|
|
||||||
_ "penahub.gitlab.yandexcloud.net/devops/linters/golang.git/pkg/dummy"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
appInit.Initialize(app.New, app.Options{})
|
|
||||||
}
|
|
37
pkg/closer/closer.go
Normal file
37
pkg/closer/closer.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package closer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Closer interface {
|
||||||
|
Close(ctx context.Context) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type CloserFunc func(ctx context.Context) error
|
||||||
|
|
||||||
|
func (cf CloserFunc) Close(ctx context.Context) error {
|
||||||
|
return cf(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
type CloserGroup struct {
|
||||||
|
closers []Closer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCloserGroup() *CloserGroup {
|
||||||
|
return &CloserGroup{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cg *CloserGroup) Add(c Closer) {
|
||||||
|
cg.closers = append(cg.closers, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cg *CloserGroup) Call(ctx context.Context) error {
|
||||||
|
var closeErr error
|
||||||
|
for i := len(cg.closers) - 1; i >= 0; i-- {
|
||||||
|
if err := cg.closers[i].Close(ctx); err != nil && closeErr == nil {
|
||||||
|
closeErr = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return closeErr
|
||||||
|
}
|
@ -1,24 +0,0 @@
|
|||||||
-- Drop indexes
|
|
||||||
DROP INDEX IF EXISTS subquizes;
|
|
||||||
DROP INDEX IF EXISTS birthtime;
|
|
||||||
DROP INDEX IF EXISTS groups;
|
|
||||||
DROP INDEX IF EXISTS timeouted;
|
|
||||||
DROP INDEX IF EXISTS active ON quiz;
|
|
||||||
DROP INDEX IF EXISTS questiontype;
|
|
||||||
DROP INDEX IF EXISTS required;
|
|
||||||
DROP INDEX IF EXISTS relation;
|
|
||||||
DROP INDEX IF EXISTS active ON question;
|
|
||||||
|
|
||||||
-- Drop tables
|
|
||||||
DROP TABLE IF EXISTS privileges;
|
|
||||||
DROP TABLE IF EXISTS answer;
|
|
||||||
DROP TABLE IF EXISTS question;
|
|
||||||
DROP TABLE IF EXISTS quiz;
|
|
||||||
DROP TABLE IF EXISTS account;
|
|
||||||
|
|
||||||
-- Drop types
|
|
||||||
DO $$
|
|
||||||
BEGIN
|
|
||||||
DROP TYPE IF EXISTS question_type;
|
|
||||||
DROP TYPE IF EXISTS quiz_status;
|
|
||||||
END$$;
|
|
@ -1,120 +0,0 @@
|
|||||||
-- Create types
|
|
||||||
DO $$
|
|
||||||
BEGIN
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'question_type') THEN
|
|
||||||
CREATE TYPE question_type AS ENUM (
|
|
||||||
'variant',
|
|
||||||
'images',
|
|
||||||
'varimg',
|
|
||||||
'emoji',
|
|
||||||
'text',
|
|
||||||
'select',
|
|
||||||
'date',
|
|
||||||
'number',
|
|
||||||
'file',
|
|
||||||
'page',
|
|
||||||
'rating'
|
|
||||||
);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'quiz_status') THEN
|
|
||||||
CREATE TYPE quiz_status AS ENUM (
|
|
||||||
'draft',
|
|
||||||
'template',
|
|
||||||
'stop',
|
|
||||||
'start',
|
|
||||||
'timeout',
|
|
||||||
'offlimit'
|
|
||||||
);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
|
||||||
END$$;
|
|
||||||
|
|
||||||
-- Create tables
|
|
||||||
CREATE TABLE IF NOT EXISTS account (
|
|
||||||
id UUID PRIMARY KEY,
|
|
||||||
user_id VARCHAR(24),
|
|
||||||
email VARCHAR(50),
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
deleted BOOLEAN DEFAULT false
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS quiz (
|
|
||||||
id bigserial UNIQUE NOT NULL PRIMARY KEY,
|
|
||||||
qid uuid DEFAULT uuid_generate_v4(),
|
|
||||||
accountid varchar(30) NOT NULL,
|
|
||||||
deleted boolean DEFAULT false,
|
|
||||||
archived boolean DEFAULT false,
|
|
||||||
fingerprinting boolean DEFAULT false,
|
|
||||||
repeatable boolean DEFAULT false,
|
|
||||||
note_prevented boolean DEFAULT false,
|
|
||||||
mail_notifications boolean DEFAULT false,
|
|
||||||
unique_answers boolean DEFAULT false,
|
|
||||||
super boolean DEFAULT false,
|
|
||||||
group_id bigint DEFAULT 0,
|
|
||||||
name varchar(280),
|
|
||||||
description text,
|
|
||||||
config text,
|
|
||||||
status quiz_status DEFAULT 'draft',
|
|
||||||
limit_answers integer DEFAULT 0,
|
|
||||||
due_to integer DEFAULT 0,
|
|
||||||
time_of_passing integer DEFAULT 0,
|
|
||||||
pausable boolean DEFAULT false,
|
|
||||||
version smallint DEFAULT 0,
|
|
||||||
version_comment text DEFAULT '',
|
|
||||||
parent_ids integer[],
|
|
||||||
created_at timestamp DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
updated_at timestamp DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
questions_count integer DEFAULT 0,
|
|
||||||
answers_count integer DEFAULT 0,
|
|
||||||
average_time_passing integer DEFAULT 0
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS question (
|
|
||||||
id bigserial UNIQUE NOT NULL PRIMARY KEY,
|
|
||||||
quiz_id bigint NOT NULL,
|
|
||||||
title varchar(512) NOT NULL,
|
|
||||||
description text,
|
|
||||||
questiontype question_type DEFAULT 'text',
|
|
||||||
required boolean DEFAULT false,
|
|
||||||
deleted boolean DEFAULT false,
|
|
||||||
page smallint DEFAULT 0,
|
|
||||||
content text,
|
|
||||||
version smallint DEFAULT 0,
|
|
||||||
parent_ids integer[],
|
|
||||||
created_at timestamp DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
updated_at timestamp DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
CONSTRAINT quiz_relation FOREIGN KEY(quiz_id) REFERENCES quiz(id)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS answer (
|
|
||||||
id bigserial UNIQUE NOT NULL PRIMARY KEY,
|
|
||||||
content text,
|
|
||||||
quiz_id bigint NOT NULL REFERENCES quiz(id),
|
|
||||||
question_id bigint NOT NULL REFERENCES question(id),
|
|
||||||
fingerprint varchar(1024),
|
|
||||||
session varchar(20),
|
|
||||||
created_at timestamp DEFAULT CURRENT_TIMESTAMP
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS privileges (
|
|
||||||
id SERIAL PRIMARY KEY,
|
|
||||||
privilegeID VARCHAR(50),
|
|
||||||
account_id UUID,
|
|
||||||
privilege_name VARCHAR(255),
|
|
||||||
amount INT,
|
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
FOREIGN KEY (account_id) REFERENCES account (id)
|
|
||||||
);
|
|
||||||
|
|
||||||
-- Create indexes
|
|
||||||
CREATE INDEX IF NOT EXISTS active ON question(deleted) WHERE deleted=false;
|
|
||||||
CREATE INDEX IF NOT EXISTS relation ON question(quiz_id DESC);
|
|
||||||
CREATE INDEX IF NOT EXISTS required ON question(required DESC);
|
|
||||||
CREATE INDEX IF NOT EXISTS questiontype ON question(questiontype);
|
|
||||||
CREATE INDEX IF NOT EXISTS active ON quiz(deleted, archived, status) WHERE deleted = false AND archived = false AND status = 'start';
|
|
||||||
CREATE INDEX IF NOT EXISTS timeouted ON quiz(due_to DESC) WHERE deleted = false AND due_to <> 0 AND status <> 'timeout';
|
|
||||||
CREATE INDEX IF NOT EXISTS groups ON quiz(super) WHERE super = true;
|
|
||||||
CREATE INDEX IF NOT EXISTS birthtime ON quiz(created_at DESC);
|
|
||||||
CREATE INDEX IF NOT EXISTS subquizes ON quiz(group_id DESC) WHERE group_id <> 0;
|
|
@ -1 +0,0 @@
|
|||||||
ALTER TABLE answer DROP COLUMN IF EXISTS result;
|
|
@ -1 +0,0 @@
|
|||||||
ALTER TABLE answer ADD COLUMN result BOOLEAN DEFAULT FALSE;
|
|
@ -1 +0,0 @@
|
|||||||
ALTER TABLE quiz DROP COLUMN IF EXISTS sessions_count;
|
|
@ -1 +0,0 @@
|
|||||||
ALTER TABLE quiz ADD COLUMN sessions_count integer;
|
|
@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE quiz DROP COLUMN IF EXISTS new;
|
|
||||||
ALTER TABLE quiz DROP COLUMN IF EXISTS deleted;
|
|
@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE answer ADD COLUMN new BOOLEAN DEFAULT TRUE;
|
|
||||||
ALTER TABLE answer ADD COLUMN deleted BOOLEAN DEFAULT FALSE;
|
|
@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE answer DROP COLUMN IF EXISTS email;
|
|
||||||
DROP INDEX IF EXISTS answer_email_unique_idx;
|
|
@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE answer ADD COLUMN email VARCHAR(50) NOT NULL DEFAULT '';
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS answer_email_unique_idx ON answer (quiz_id, email) WHERE email <> '';
|
|
@ -1,6 +0,0 @@
|
|||||||
ALTER TABLE answer
|
|
||||||
DROP COLUMN device_type,
|
|
||||||
DROP COLUMN device,
|
|
||||||
DROP COLUMN os,
|
|
||||||
DROP COLUMN browser,
|
|
||||||
DROP COLUMN ip;
|
|
@ -1,6 +0,0 @@
|
|||||||
ALTER TABLE answer
|
|
||||||
ADD COLUMN device_type VARCHAR(50) NOT NULL DEFAULT '',
|
|
||||||
ADD COLUMN device VARCHAR(100) NOT NULL DEFAULT '',
|
|
||||||
ADD COLUMN os VARCHAR(100) NOT NULL DEFAULT '',
|
|
||||||
ADD COLUMN browser VARCHAR(100) NOT NULL DEFAULT '',
|
|
||||||
ADD COLUMN ip VARCHAR(50) NOT NULL DEFAULT '';
|
|
@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE answer
|
|
||||||
DROP COLUMN start;
|
|
@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE answer
|
|
||||||
ADD COLUMN start BOOLEAN NOT NULL DEFAULT FALSE;
|
|
@ -1,4 +0,0 @@
|
|||||||
ALTER TABLE answer
|
|
||||||
ALTER COLUMN device TYPE VARCHAR(100),
|
|
||||||
ALTER COLUMN os TYPE VARCHAR(100),
|
|
||||||
ALTER COLUMN browser TYPE VARCHAR(100);
|
|
@ -1,4 +0,0 @@
|
|||||||
ALTER TABLE answer
|
|
||||||
ALTER COLUMN device TYPE VARCHAR(1024),
|
|
||||||
ALTER COLUMN os TYPE VARCHAR(1024),
|
|
||||||
ALTER COLUMN browser TYPE VARCHAR(1024);
|
|
@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE quiz
|
|
||||||
ALTER COLUMN name TYPE VARCHAR(280);
|
|
@ -1,2 +0,0 @@
|
|||||||
ALTER TABLE quiz
|
|
||||||
ALTER COLUMN name TYPE VARCHAR(1024);
|
|
@ -1,101 +0,0 @@
|
|||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/go-redis/redis/v8"
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/common.git/dal"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/brokers"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/clients/auth"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/clients/telegram"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Service is an entity for http requests handling
|
|
||||||
type Service struct {
|
|
||||||
dal *dal.DAL
|
|
||||||
authClient *auth.AuthClient
|
|
||||||
producer *brokers.Producer
|
|
||||||
serviceName string
|
|
||||||
chDAL *dal.ClickHouseDAL
|
|
||||||
telegramClient *telegram.TelegramClient
|
|
||||||
redisClient *redis.Client
|
|
||||||
s3Prefix string
|
|
||||||
}
|
|
||||||
|
|
||||||
type Deps struct {
|
|
||||||
Dal *dal.DAL
|
|
||||||
AuthClient *auth.AuthClient
|
|
||||||
Producer *brokers.Producer
|
|
||||||
ServiceName string
|
|
||||||
ChDAL *dal.ClickHouseDAL
|
|
||||||
TelegramClient *telegram.TelegramClient
|
|
||||||
RedisClient *redis.Client
|
|
||||||
S3Prefix string
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(deps Deps) *Service {
|
|
||||||
return &Service{
|
|
||||||
dal: deps.Dal,
|
|
||||||
authClient: deps.AuthClient,
|
|
||||||
producer: deps.Producer,
|
|
||||||
serviceName: deps.ServiceName,
|
|
||||||
chDAL: deps.ChDAL,
|
|
||||||
telegramClient: deps.TelegramClient,
|
|
||||||
redisClient: deps.RedisClient,
|
|
||||||
s3Prefix: deps.S3Prefix,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register is a function for add handlers of service to external multiplexer
|
|
||||||
func (s *Service) Register(app *fiber.App) {
|
|
||||||
// quiz manipulating handlers
|
|
||||||
app.Post("/quiz/create", s.CreateQuiz)
|
|
||||||
app.Post("/quiz/getList", s.GetQuizList)
|
|
||||||
app.Patch("/quiz/edit", s.UpdateQuiz)
|
|
||||||
app.Post("/quiz/copy", s.CopyQuiz)
|
|
||||||
app.Post("/quiz/history", s.GetQuizHistory)
|
|
||||||
app.Delete("/quiz/delete", s.DeleteQuiz)
|
|
||||||
app.Patch("/quiz/archive", s.ArchiveQuiz)
|
|
||||||
app.Post("/quiz/move", s.QuizMove)
|
|
||||||
app.Post("/quiz/template", s.TemplateCopy)
|
|
||||||
|
|
||||||
// question manipulating handlers
|
|
||||||
app.Post("/question/create", s.CreateQuestion)
|
|
||||||
app.Post("/question/getList", s.GetQuestionList)
|
|
||||||
app.Patch("/question/edit", s.UpdateQuestion)
|
|
||||||
app.Post("/question/copy", s.CopyQuestion)
|
|
||||||
app.Post("/question/history", s.GetQuestionHistory)
|
|
||||||
app.Delete("/question/delete", s.DeleteQuestion)
|
|
||||||
|
|
||||||
// account handlers
|
|
||||||
app.Get("/account/get", s.getCurrentAccount)
|
|
||||||
app.Post("/account/create", s.createAccount)
|
|
||||||
app.Delete("/account/delete", s.deleteAccount)
|
|
||||||
app.Get("/accounts", s.getAccounts)
|
|
||||||
app.Get("/privilege/:userId", s.getPrivilegeByUserID)
|
|
||||||
app.Delete("/account/:userId", s.deleteAccountByUserID)
|
|
||||||
app.Post("/account/manualdone", s.ManualDone)
|
|
||||||
app.Post("/account/leadtarget", s.PostLeadTarget)
|
|
||||||
app.Delete("/account/leadtarget/:id", s.DeleteLeadTarget)
|
|
||||||
app.Get("/account/leadtarget/:quizID", s.GetLeadTarget)
|
|
||||||
app.Put("/account/leadtarget", s.UpdateLeadTarget)
|
|
||||||
|
|
||||||
// result handlers
|
|
||||||
app.Post("/results/getResults/:quizId", s.GetResultsByQuizID)
|
|
||||||
app.Delete("/results/delete/:resultId", s.DelResultByID)
|
|
||||||
app.Patch("/result/seen", s.SetStatus)
|
|
||||||
app.Post("/results/:quizID/export", s.ExportResultsToCSV)
|
|
||||||
app.Get("/result/:resultID", s.GetResultAnswers)
|
|
||||||
|
|
||||||
// statistics handlers
|
|
||||||
app.Post("/statistic/:quizID/devices", s.GetDeviceStatistics)
|
|
||||||
app.Post("/statistic/:quizID/general", s.GetGeneralStatistics)
|
|
||||||
app.Post("/statistic/:quizID/questions", s.GetQuestionsStatistics)
|
|
||||||
app.Post("/statistic", s.AllServiceStatistics)
|
|
||||||
app.Get("/statistics/:quizID/pipelines", s.GetPipelinesStatistics)
|
|
||||||
|
|
||||||
//telegram handlers
|
|
||||||
app.Get("/telegram/pool", s.GetPoolTgAccounts)
|
|
||||||
app.Post("/telegram/create", s.AddingTgAccount)
|
|
||||||
app.Delete("/telegram/:id", s.DeleteTgAccountByID)
|
|
||||||
app.Post("/telegram/setCode", s.SettingTgCode)
|
|
||||||
}
|
|
@ -5,8 +5,8 @@ import (
|
|||||||
"github.com/pioz/faker"
|
"github.com/pioz/faker"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"log"
|
"log"
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/brokers"
|
|
||||||
"penahub.gitlab.yandexcloud.net/backend/quiz/core/initialize"
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/initialize"
|
||||||
|
"penahub.gitlab.yandexcloud.net/backend/quiz/core/internal/brokers"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user