generated from VLADIMIR/template
clear
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
//go:generate mockgen -source=interface.go -destination=mocks/mock.go -package=mocks
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"evening_detective/internal/models"
|
||||
)
|
||||
|
||||
type IDBService interface {
|
||||
Close()
|
||||
|
||||
GetTeams(ctx context.Context) ([]*models.Team, error)
|
||||
GetTeam(ctx context.Context, teamId any, password any) (*models.Team, error)
|
||||
AddTeams(ctx context.Context, teams []*models.Team) ([]*models.Team, error)
|
||||
DeleteAllTeams(ctx context.Context) error
|
||||
|
||||
GetActions(ctx context.Context, teamId int64) ([]*models.Action, error)
|
||||
AddActions(ctx context.Context, teamId int64, actions []*models.Action) error
|
||||
|
||||
GetApplications(ctx context.Context, teamId int64) ([]*models.Application, error)
|
||||
GetApplicationsByState(ctx context.Context, teamId int64, state string) ([]*models.Application, error)
|
||||
AddApplications(ctx context.Context, teamId int64, applications []*models.Application) error
|
||||
|
||||
GiveApplications(ctx context.Context, teamId int64, applications []*models.Application) error
|
||||
|
||||
GetGame(ctx context.Context) (*models.Game, error)
|
||||
UpdateGameState(ctx context.Context, state string) error
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: interface.go
|
||||
|
||||
// Package mocks is a generated GoMock package.
|
||||
package mocks
|
||||
|
||||
import (
|
||||
context "context"
|
||||
models "evening_detective/internal/models"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockIDBService is a mock of IDBService interface.
|
||||
type MockIDBService struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockIDBServiceMockRecorder
|
||||
}
|
||||
|
||||
// MockIDBServiceMockRecorder is the mock recorder for MockIDBService.
|
||||
type MockIDBServiceMockRecorder struct {
|
||||
mock *MockIDBService
|
||||
}
|
||||
|
||||
// NewMockIDBService creates a new mock instance.
|
||||
func NewMockIDBService(ctrl *gomock.Controller) *MockIDBService {
|
||||
mock := &MockIDBService{ctrl: ctrl}
|
||||
mock.recorder = &MockIDBServiceMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockIDBService) EXPECT() *MockIDBServiceMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// AddActions mocks base method.
|
||||
func (m *MockIDBService) AddActions(ctx context.Context, teamId int64, actions []*models.Action) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AddActions", ctx, teamId, actions)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AddActions indicates an expected call of AddActions.
|
||||
func (mr *MockIDBServiceMockRecorder) AddActions(ctx, teamId, actions interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddActions", reflect.TypeOf((*MockIDBService)(nil).AddActions), ctx, teamId, actions)
|
||||
}
|
||||
|
||||
// AddApplications mocks base method.
|
||||
func (m *MockIDBService) AddApplications(ctx context.Context, teamId int64, applications []*models.Application) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AddApplications", ctx, teamId, applications)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AddApplications indicates an expected call of AddApplications.
|
||||
func (mr *MockIDBServiceMockRecorder) AddApplications(ctx, teamId, applications interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddApplications", reflect.TypeOf((*MockIDBService)(nil).AddApplications), ctx, teamId, applications)
|
||||
}
|
||||
|
||||
// AddTeams mocks base method.
|
||||
func (m *MockIDBService) AddTeams(ctx context.Context, teams []*models.Team) ([]*models.Team, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AddTeams", ctx, teams)
|
||||
ret0, _ := ret[0].([]*models.Team)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// AddTeams indicates an expected call of AddTeams.
|
||||
func (mr *MockIDBServiceMockRecorder) AddTeams(ctx, teams interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddTeams", reflect.TypeOf((*MockIDBService)(nil).AddTeams), ctx, teams)
|
||||
}
|
||||
|
||||
// Close mocks base method.
|
||||
func (m *MockIDBService) Close() {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "Close")
|
||||
}
|
||||
|
||||
// Close indicates an expected call of Close.
|
||||
func (mr *MockIDBServiceMockRecorder) Close() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockIDBService)(nil).Close))
|
||||
}
|
||||
|
||||
// DeleteAllTeams mocks base method.
|
||||
func (m *MockIDBService) DeleteAllTeams(ctx context.Context) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteAllTeams", ctx)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DeleteAllTeams indicates an expected call of DeleteAllTeams.
|
||||
func (mr *MockIDBServiceMockRecorder) DeleteAllTeams(ctx interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAllTeams", reflect.TypeOf((*MockIDBService)(nil).DeleteAllTeams), ctx)
|
||||
}
|
||||
|
||||
// GetActions mocks base method.
|
||||
func (m *MockIDBService) GetActions(ctx context.Context, teamId int64) ([]*models.Action, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetActions", ctx, teamId)
|
||||
ret0, _ := ret[0].([]*models.Action)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetActions indicates an expected call of GetActions.
|
||||
func (mr *MockIDBServiceMockRecorder) GetActions(ctx, teamId interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActions", reflect.TypeOf((*MockIDBService)(nil).GetActions), ctx, teamId)
|
||||
}
|
||||
|
||||
// GetApplications mocks base method.
|
||||
func (m *MockIDBService) GetApplications(ctx context.Context, teamId int64) ([]*models.Application, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetApplications", ctx, teamId)
|
||||
ret0, _ := ret[0].([]*models.Application)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetApplications indicates an expected call of GetApplications.
|
||||
func (mr *MockIDBServiceMockRecorder) GetApplications(ctx, teamId interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplications", reflect.TypeOf((*MockIDBService)(nil).GetApplications), ctx, teamId)
|
||||
}
|
||||
|
||||
// GetApplicationsByState mocks base method.
|
||||
func (m *MockIDBService) GetApplicationsByState(ctx context.Context, teamId int64, state string) ([]*models.Application, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetApplicationsByState", ctx, teamId, state)
|
||||
ret0, _ := ret[0].([]*models.Application)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetApplicationsByState indicates an expected call of GetApplicationsByState.
|
||||
func (mr *MockIDBServiceMockRecorder) GetApplicationsByState(ctx, teamId, state interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetApplicationsByState", reflect.TypeOf((*MockIDBService)(nil).GetApplicationsByState), ctx, teamId, state)
|
||||
}
|
||||
|
||||
// GetGame mocks base method.
|
||||
func (m *MockIDBService) GetGame(ctx context.Context) (*models.Game, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetGame", ctx)
|
||||
ret0, _ := ret[0].(*models.Game)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetGame indicates an expected call of GetGame.
|
||||
func (mr *MockIDBServiceMockRecorder) GetGame(ctx interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGame", reflect.TypeOf((*MockIDBService)(nil).GetGame), ctx)
|
||||
}
|
||||
|
||||
// GetTeam mocks base method.
|
||||
func (m *MockIDBService) GetTeam(ctx context.Context, teamId, password any) (*models.Team, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetTeam", ctx, teamId, password)
|
||||
ret0, _ := ret[0].(*models.Team)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetTeam indicates an expected call of GetTeam.
|
||||
func (mr *MockIDBServiceMockRecorder) GetTeam(ctx, teamId, password interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTeam", reflect.TypeOf((*MockIDBService)(nil).GetTeam), ctx, teamId, password)
|
||||
}
|
||||
|
||||
// GetTeams mocks base method.
|
||||
func (m *MockIDBService) GetTeams(ctx context.Context) ([]*models.Team, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetTeams", ctx)
|
||||
ret0, _ := ret[0].([]*models.Team)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetTeams indicates an expected call of GetTeams.
|
||||
func (mr *MockIDBServiceMockRecorder) GetTeams(ctx interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTeams", reflect.TypeOf((*MockIDBService)(nil).GetTeams), ctx)
|
||||
}
|
||||
|
||||
// GiveApplications mocks base method.
|
||||
func (m *MockIDBService) GiveApplications(ctx context.Context, teamId int64, applications []*models.Application) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GiveApplications", ctx, teamId, applications)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GiveApplications indicates an expected call of GiveApplications.
|
||||
func (mr *MockIDBServiceMockRecorder) GiveApplications(ctx, teamId, applications interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GiveApplications", reflect.TypeOf((*MockIDBService)(nil).GiveApplications), ctx, teamId, applications)
|
||||
}
|
||||
|
||||
// UpdateGameState mocks base method.
|
||||
func (m *MockIDBService) UpdateGameState(ctx context.Context, state string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateGameState", ctx, state)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UpdateGameState indicates an expected call of UpdateGameState.
|
||||
func (mr *MockIDBServiceMockRecorder) UpdateGameState(ctx, state interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateGameState", reflect.TypeOf((*MockIDBService)(nil).UpdateGameState), ctx, state)
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"evening_detective/internal/models"
|
||||
"log"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
type service struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewDBService(filepath string) (IDBService, error) {
|
||||
db, err := sql.Open("sqlite3", filepath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Printf("load db from: %s", filepath)
|
||||
_, err = db.Exec("CREATE TABLE IF NOT EXISTS teams (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL CHECK(length(trim(name)) > 0), password TEXT);")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = db.Exec("CREATE TABLE IF NOT EXISTS actions (id INTEGER PRIMARY KEY AUTOINCREMENT, place TEXT, teamId INTEGER, FOREIGN KEY (teamId) REFERENCES teams(id) ON DELETE CASCADE);")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = db.Exec("CREATE TABLE IF NOT EXISTS applications (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, teamId INTEGER, state TEXT, FOREIGN KEY (teamId) REFERENCES teams(id) ON DELETE CASCADE);")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = db.Exec("CREATE TABLE IF NOT EXISTS games (id INTEGER PRIMARY KEY AUTOINCREMENT, state TEXT, startAt TEXT, endAt TEXT);")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &service{db: db}, nil
|
||||
}
|
||||
|
||||
func (s *service) Close() {
|
||||
s.db.Close()
|
||||
}
|
||||
|
||||
func (s *service) GetTeams(ctx context.Context) ([]*models.Team, error) {
|
||||
rows, err := s.db.Query("select id, name, password from teams")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
teams := []*models.Team{}
|
||||
|
||||
for rows.Next() {
|
||||
item := &models.Team{}
|
||||
err := rows.Scan(&item.ID, &item.Name, &item.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
teams = append(teams, item)
|
||||
}
|
||||
return teams, nil
|
||||
}
|
||||
|
||||
func (s *service) GetTeam(ctx context.Context, teamId any, password any) (*models.Team, error) {
|
||||
rows, err := s.db.Query("select id, name from teams where LOWER(name) = LOWER($1) and password = $2", teamId, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
teams := []*models.Team{}
|
||||
|
||||
for rows.Next() {
|
||||
item := &models.Team{}
|
||||
err := rows.Scan(&item.ID, &item.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
teams = append(teams, item)
|
||||
}
|
||||
if len(teams) != 1 {
|
||||
return nil, errors.New("bad result")
|
||||
}
|
||||
return teams[0], nil
|
||||
}
|
||||
|
||||
func (s *service) AddTeams(ctx context.Context, teams []*models.Team) ([]*models.Team, error) {
|
||||
for _, team := range teams {
|
||||
result, err := s.db.Exec("insert into teams (name, password) values ($1, $2)", team.Name, team.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
team.ID, err = result.LastInsertId()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return teams, nil
|
||||
}
|
||||
|
||||
func (s *service) DeleteAllTeams(ctx context.Context) error {
|
||||
_, err := s.db.Exec("delete from teams where 1")
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *service) GetActions(ctx context.Context, teamId int64) ([]*models.Action, error) {
|
||||
rows, err := s.db.Query("select id, place from actions where teamId = $1", teamId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
actions := []*models.Action{}
|
||||
|
||||
for rows.Next() {
|
||||
item := &models.Action{}
|
||||
err := rows.Scan(&item.ID, &item.Place)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
actions = append(actions, item)
|
||||
}
|
||||
return actions, nil
|
||||
}
|
||||
|
||||
func (s *service) AddActions(ctx context.Context, teamId int64, actions []*models.Action) error {
|
||||
for _, action := range actions {
|
||||
_, err := s.db.Exec("insert into actions (place, teamId) values ($1, $2)", action.Place, teamId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) GetApplications(ctx context.Context, teamId int64) ([]*models.Application, error) {
|
||||
rows, err := s.db.Query("select id, name from applications where teamId = $1", teamId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
applications := []*models.Application{}
|
||||
|
||||
for rows.Next() {
|
||||
item := &models.Application{}
|
||||
err := rows.Scan(&item.ID, &item.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
applications = append(applications, item)
|
||||
}
|
||||
return applications, nil
|
||||
}
|
||||
|
||||
func (s *service) GetApplicationsByState(ctx context.Context, teamId int64, state string) ([]*models.Application, error) {
|
||||
rows, err := s.db.Query("select id, name from applications where teamId = $1 and state = $2", teamId, state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
applications := []*models.Application{}
|
||||
|
||||
for rows.Next() {
|
||||
item := &models.Application{}
|
||||
err := rows.Scan(&item.ID, &item.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
applications = append(applications, item)
|
||||
}
|
||||
return applications, nil
|
||||
}
|
||||
|
||||
func (s *service) AddApplications(ctx context.Context, teamId int64, applications []*models.Application) error {
|
||||
for _, application := range applications {
|
||||
_, err := s.db.Exec("insert into applications (name, teamId, state) values ($1, $2, $3)", application.Name, teamId, application.State)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) GiveApplications(ctx context.Context, teamId int64, applications []*models.Application) error {
|
||||
for _, application := range applications {
|
||||
_, err := s.db.Exec("update applications set state = \"gave\" where teamId = $1 and id = $2", teamId, application.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *service) GetGame(ctx context.Context) (*models.Game, error) {
|
||||
rows, err := s.db.Query("select state, startAt, endAt from games limit 1")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
game := &models.Game{}
|
||||
if rows.Next() {
|
||||
err := rows.Scan(&game.State, &game.StartTime, &game.EndTime)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return game, nil
|
||||
}
|
||||
|
||||
state := "NEW"
|
||||
_, err = s.db.Exec("insert into games (state, startAt, endAt) values ($1, '', '')", state)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
game.State = state
|
||||
return game, nil
|
||||
}
|
||||
|
||||
func (s *service) UpdateGameState(ctx context.Context, state string) error {
|
||||
game, err := s.GetGame(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch state {
|
||||
case "RUN":
|
||||
if game.StartTime == "" {
|
||||
_, err := s.db.Exec("update games set state = $1, startAt = datetime('now', 'localtime')", state)
|
||||
return err
|
||||
}
|
||||
_, err := s.db.Exec("update games set state = $1", state)
|
||||
return err
|
||||
case "STOP":
|
||||
_, err := s.db.Exec("update games set state = $1, endAt = datetime('now', 'localtime')", state)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package link
|
||||
|
||||
type ILinkService interface {
|
||||
GetTeamClientLink(host string, name string, password string) string
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package link
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
type service struct{}
|
||||
|
||||
func NewLinkService() ILinkService {
|
||||
return &service{}
|
||||
}
|
||||
|
||||
func (s *service) GetTeamClientLink(host string, name string, password string) string {
|
||||
return fmt.Sprintf("%s?name=%s&password=%s", host, url.PathEscape(name), password)
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,7 @@
|
||||
package pdf
|
||||
|
||||
import "evening_detective/internal/models"
|
||||
|
||||
type IPDFGenerator interface {
|
||||
CreateTeamsPDF(teams []*models.Team) ([]byte, error)
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package pdf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"evening_detective/internal/models"
|
||||
"strings"
|
||||
|
||||
"github.com/signintech/gopdf"
|
||||
"github.com/skip2/go-qrcode"
|
||||
)
|
||||
|
||||
//go:embed JetBrainsMono-Medium.ttf
|
||||
var f embed.FS
|
||||
|
||||
type service struct{}
|
||||
|
||||
func NewPDFGenerator() IPDFGenerator {
|
||||
return &service{}
|
||||
}
|
||||
|
||||
func (s *service) CreateTeamsPDF(teams []*models.Team) ([]byte, error) {
|
||||
pdf := &gopdf.GoPdf{}
|
||||
pdf.Start(gopdf.Config{PageSize: *gopdf.PageSizeA4}) // W: 595, H: 842
|
||||
file, err := f.Open("JetBrainsMono-Medium.ttf")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := pdf.AddTTFFontByReader("main", file); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := pdf.SetFont("main", "", 10); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
countOnPage := 9
|
||||
padding := 17.
|
||||
xDelta := 187.
|
||||
yDelta := 260.
|
||||
for i, team := range teams {
|
||||
if i%countOnPage == 0 {
|
||||
pdf.AddPage()
|
||||
pdf.SetPage(1 + i/countOnPage)
|
||||
}
|
||||
y := (padding + 15) + yDelta*float64(i%countOnPage/3)
|
||||
x := padding + xDelta*float64(i%3)
|
||||
|
||||
if err := printTextCenter(pdf, "Подключите Wi-Fi", xDelta-6, x+3, y); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := printTextCenter(pdf, "Имя: evening_detective", xDelta-6, x+3, 15+y); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := printTextCenter(pdf, "Пароль: 12345678", xDelta-6, x+3, 30+y); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := printQR(pdf, team.Link, x+21, 65+y); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := printTextCenter(pdf, "Войдите в приложение по qr", xDelta-6, x+3, 55+y); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := printTextCenter(pdf, team.Name, xDelta-6, x+3, 55+y+150); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
buffer := &bytes.Buffer{}
|
||||
_, err = pdf.WriteTo(buffer)
|
||||
return buffer.Bytes(), err
|
||||
}
|
||||
|
||||
func printQR(pdf *gopdf.GoPdf, url string, x, y float64) error {
|
||||
png, err := qrcode.Encode(url, qrcode.Medium, 256)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imgHolder, err := gopdf.ImageHolderByBytes(png)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = pdf.ImageByHolder(imgHolder, x, y, &gopdf.Rect{W: 145, H: 145})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func printTextCenter(pdf *gopdf.GoPdf, text string, pageWidth, x, y float64) error {
|
||||
lines := splitTextByWords(pdf, text, pageWidth)
|
||||
for i, line := range lines {
|
||||
lineWidth, err := pdf.MeasureTextWidth(line)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
xLine := x + (pageWidth-lineWidth)/2
|
||||
yLine := y + 15*float64(i)
|
||||
pdf.SetXY(xLine, yLine)
|
||||
|
||||
pdf.Cell(nil, line)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func splitTextByWords(pdf *gopdf.GoPdf, text string, maxWidth float64) []string {
|
||||
words := strings.Fields(text)
|
||||
var lines []string
|
||||
var currentLine string
|
||||
|
||||
for _, word := range words {
|
||||
testLine := currentLine
|
||||
if testLine != "" {
|
||||
testLine += " " + word
|
||||
} else {
|
||||
testLine = word
|
||||
}
|
||||
|
||||
width, _ := pdf.MeasureTextWidth(testLine)
|
||||
|
||||
if width <= maxWidth {
|
||||
currentLine = testLine
|
||||
} else {
|
||||
if currentLine != "" {
|
||||
lines = append(lines, currentLine)
|
||||
}
|
||||
currentLine = word
|
||||
}
|
||||
}
|
||||
|
||||
if currentLine != "" {
|
||||
lines = append(lines, currentLine)
|
||||
}
|
||||
|
||||
return lines
|
||||
}
|
||||
@@ -5,10 +5,10 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"evening_detective/internal/models"
|
||||
"evening_detective/internal/modules/db"
|
||||
"evening_detective/internal/modules/link"
|
||||
"evening_detective/internal/modules/password"
|
||||
"evening_detective/internal/modules/pdf"
|
||||
"evening_detective/internal/services/db"
|
||||
"evening_detective/internal/services/link"
|
||||
"evening_detective/internal/services/pdf"
|
||||
"evening_detective/internal/services/story_service"
|
||||
"evening_detective/proto"
|
||||
"fmt"
|
||||
|
||||
Reference in New Issue
Block a user