diff --git a/cmd/main.go b/cmd/main.go index f4f3198..fdd202c 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -8,212 +8,94 @@ import ( "os/signal" "syscall" - "ticket-pimp/bot/handler" - "ticket-pimp/internal/controller" "ticket-pimp/internal/domain" "ticket-pimp/internal/services" - discordbot "ticket-pimp/discord-bot" - configDB "ticket-pimp/internal/storage/db/config" + "ticket-pimp/discord" + "ticket-pimp/telegram" + ticketDB "ticket-pimp/internal/storage/db/tickets" "github.com/jackc/pgx/v5" - "github.com/joho/godotenv" - "github.com/mr-linch/go-tg" - "github.com/mr-linch/go-tg/tgb" ) func main() { log.Print("started") - config := env("develop.env") - // run(config) - test(config) + config := domain.InitConfig("develop.env") + run(config) + // test(config) } -func test(conf domain.Config) { - ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill, syscall.SIGTERM) - defer cancel() - conn, err := pgx.Connect( - ctx, - fmt.Sprintf( - "postgresql://%s:%s@%s:%s/%s", - conf.DB.User, - conf.DB.Pass, - conf.DB.Host, - conf.DB.Port, - conf.DB.Name, - )) - if err != nil { - log.Fatalf("DB connection failed: %v", err) - } +// func test(conf domain.Config) { +// ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill, syscall.SIGTERM) +// defer cancel() - q := configDB.New(conn) - // appconfig, err := q.GetConfig(ctx) +// conn, err := pgxpool.New(ctx, fmt.Sprintf( +// "postgresql://%s:%s@%s:%s/%s", +// conf.DB.User, +// conf.DB.Pass, +// conf.DB.Host, +// conf.DB.Port, +// conf.DB.Name, +// )) - // appconfigNew, err := q.SetNewConfig(ctx) +// if err != nil { +// log.Fatalf("DB connection failed: %v", err) +// } - // _ = appconfig - // _ = appconfigNew +// q := configDB.New(conn) - appController := controller.NewAppConfig(q) - ticketConfig, err := appController.NewKey(ctx) - _ = ticketConfig +// appController := controller.NewAppConfig(q) +// ticketConfig, err := appController.NewKey(ctx) +// _ = ticketConfig -} +// } func run(conf domain.Config) { ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill, syscall.SIGTERM) defer cancel() + // -- DB connection init -- START conn, err := pgx.Connect( ctx, fmt.Sprintf( "postgresql://%s:%s@%s:%s/%s", - conf.DB.User, - conf.DB.Pass, - conf.DB.Host, - conf.DB.Port, - conf.DB.Name, + conf.DB.User, conf.DB.Pass, conf.DB.Host, conf.DB.Port, conf.DB.Name, )) if err != nil { log.Fatalf("DB connection failed: %v", err) } defer conn.Close(ctx) + // -- DB connection init -- END - opts := TelegramOptions{ - ticketsRepo: ticketDB.New(conn), - gitService: services.NewGit(conf.Git), - cloudService: services.NewCloud(conf.Cloud), - coda: services.NewCodaClient(conf.Coda), - appConfig: &conf, - } + ticketsRepo := ticketDB.New(conn) + gitService := services.NewGit(conf.Git) + cloudService := services.NewCloud(conf.Cloud) + codeService := services.NewCodaClient(conf.Coda) go func() { - if err := runDiscrodBot(conf); err != nil { + opts := discord.DiscordOptions{ + TicketsRepo: ticketsRepo, + GitService: gitService, + CloudService: cloudService, + Coda: codeService, + AppConfig: &conf, + } + if err := discord.Run(conf, opts); err != nil { log.Fatalf("discord bot cannot be runned: %v", err) } - }() - if err := runTgBot(ctx, opts); err != nil { + opts := telegram.TelegramOptions{ + TicketsRepo: ticketsRepo, + GitService: gitService, + CloudService: cloudService, + Coda: codeService, + AppConfig: &conf, + } + + if err := telegram.Run(ctx, opts); err != nil { log.Fatalf("telegram bot cannot be runned: %v", err) defer os.Exit(1) } } - -// env -// env function reads provided file and setup envirmental variables; -func env(envFilePath string) domain.Config { - err := godotenv.Load(envFilePath) - if err != nil { - log.Fatal("Error while loading env file") - } - - return domain.Config{ - Git: domain.GitConfig{ - BaseUrl: os.Getenv("GIT_BASE_URL"), - Token: os.Getenv("GIT_TOKEN"), - User: os.Getenv("GIT_USER"), - }, - Cloud: domain.CloudConfig{ - BaseUrl: os.Getenv("CLOUD_BASE_URL"), - User: os.Getenv("CLOUD_USER"), - Pass: os.Getenv("CLOUD_PASS"), - RootDir: os.Getenv("ROOTDIR"), - }, - Coda: domain.CodaConfig{ - Farm: os.Getenv("CODA_TOKEN1"), - Develop: os.Getenv("CODA_TOKEN2"), - }, - DB: domain.DBConfig{ - Host: os.Getenv("DB_HOST"), - Port: os.Getenv("DB_PORT"), - Name: os.Getenv("DB_NAME"), - User: os.Getenv("DB_USER"), - Pass: os.Getenv("DB_PASS"), - SslMode: os.Getenv("SSLMODE"), - }, - Telegram: domain.TelegramConfig{ - Token: os.Getenv("TG_API"), - }, - Discord: domain.DiscordConfig{ - Token: os.Getenv("DISCORD_TOKEN"), - }, - } -} - -func runDiscrodBot(conf domain.Config) error { - token := conf.Discord.Token - - dbot, err := discordbot.NewDiscordBot(token) - if err != nil { - return err - } - - createRepoHandler := discordbot.CreateRepoHandler(3) - - dbot.Session.AddHandler(createRepoHandler.Handler) - - if err := dbot.Session.Open(); err != nil { - return fmt.Errorf("cannot open the session: %v", err) - } - - log.Println("Adding commands...") - cmd, err := dbot.Session.ApplicationCommandCreate(dbot.Session.State.User.ID, "", &createRepoHandler.Command) - if err != nil { - log.Panicf("Cannot create '%v' command: %v", createRepoHandler.Command.Name, err) - } - - defer dbot.Session.Close() - stop := make(chan os.Signal, 1) - signal.Notify(stop, os.Interrupt) - <-stop - log.Println("Graceful shutdown") - - log.Println("Removing commands...") - err = dbot.Session.ApplicationCommandDelete(dbot.Session.State.User.ID, "", cmd.ID) - if err != nil { - log.Panicf("Cannot delete '%v' command: %v", cmd.Name, err) - } - - return nil -} - -type TelegramOptions struct { - ticketsRepo *ticketDB.Queries - gitService *services.Git - cloudService *services.Cloud - coda *services.Coda - appConfig *domain.Config -} - -// runTgBot ... -// ..function creates new Telegram BOT instance -// ..throw env variables through bot's handlers -// ..setup tg bot router; -// and finally returns tgb.Poller -func runTgBot(ctx context.Context, opts TelegramOptions) error { - - log.Print("Start telegram bot init..") - client := tg.New(opts.appConfig.Telegram.Token) - - h := handler.NewHandler( - opts.gitService, - opts.cloudService, - opts.coda, - opts.ticketsRepo, - ) - - router := tgb.NewRouter(). - Message(h.Init, tgb.Command("init")). - Message(h.PingHandler, tgb.Command("ping")). - Message(h.DevelopmentTaskHandler, tgb.TextHasPrefix("/new")). - Message(h.NewRepoHandler, tgb.TextHasPrefix("/repo")). - Message(h.NewFolderHandler, tgb.TextHasPrefix("/folder")). - Message(h.FarmTaskHandler, tgb.TextHasPrefix("/task")) - - return tgb.NewPoller( - router, - client, - ).Run(ctx) -} diff --git a/discord/discord.go b/discord/discord.go new file mode 100644 index 0000000..0cfcac3 --- /dev/null +++ b/discord/discord.go @@ -0,0 +1,78 @@ +package discord + +import ( + "fmt" + "log" + "os" + "os/signal" + "ticket-pimp/discord/handler" + "ticket-pimp/internal/domain" + "ticket-pimp/internal/services" + + tickets "ticket-pimp/internal/storage/db/tickets" + + "github.com/bwmarrin/discordgo" +) + +func initBotWith(token string) (*discordgo.Session, error) { + discord, err := discordgo.New("Bot " + token) + if err != nil { + return nil, err + } + return discord, nil +} + +type DiscordOptions struct { + TicketsRepo *tickets.Queries + GitService *services.Git + CloudService *services.Cloud + Coda *services.Coda + AppConfig *domain.Config +} + +func Run(conf domain.Config, opts DiscordOptions) error { + token := conf.Discord.Token + + session, err := initBotWith(token) + if err != nil { + return err + } + + router := handler.InitRouter(opts.GitService) + + for _, h := range router.Routes { + session.AddHandler(h.Handler) + } + + if err := session.Open(); err != nil { + return fmt.Errorf("cannot open the session: %v", err) + } + + log.Println("Adding commands...") + var cmds []*discordgo.ApplicationCommand + for _, h := range router.Routes { + cmd, err := session.ApplicationCommandCreate(session.State.User.ID, "", &h.Command) + if err != nil { + log.Panicf("Cannot create '%v' command: %v", h.Command.Name, err) + } + cmds = append(cmds, cmd) + } + + log.Println("Following commands added:") + log.Println(cmds) + defer session.Close() + stop := make(chan os.Signal, 1) + signal.Notify(stop, os.Interrupt) + <-stop + log.Println("Graceful shutdown") + + log.Println("Removing commands...") + for _, h := range cmds { + err = session.ApplicationCommandDelete(session.State.User.ID, "", h.ID) + if err != nil { + log.Panicf("Cannot delete '%v' command: %v", h.Name, err) + } + } + + return nil +} diff --git a/discord-bot/discord-bot.go b/discord/handler/handler.go similarity index 64% rename from discord-bot/discord-bot.go rename to discord/handler/handler.go index d82598e..95cf243 100644 --- a/discord-bot/discord-bot.go +++ b/discord/handler/handler.go @@ -1,32 +1,46 @@ -package discordbot +package handler import ( "fmt" + "log" + "ticket-pimp/internal/domain" + "ticket-pimp/internal/services" "github.com/bwmarrin/discordgo" ) -type DiscordBot struct { - Session *discordgo.Session +type router struct { + Routes []route + + git services.IGit } -func NewDiscordBot(token string) (*DiscordBot, error) { - discord, err := discordgo.New("Bot " + token) - if err != nil { - return nil, err - } - return &DiscordBot{ - Session: discord, - }, nil +// Подключение роутов к Discord боту +func InitRouter(gitService services.IGit) *router { + var r router + r.Routes = append( + r.Routes, + r.CreateRepoHandler(3), + // r.CreateTicketHandler(3), + ) + + r.git = gitService + + return &r } -type CommandHandler struct { +type route struct { Command discordgo.ApplicationCommand Handler func(s *discordgo.Session, i *discordgo.InteractionCreate) } -func CreateRepoHandler(repoNameMinLength int) CommandHandler { - return CommandHandler{ +func (h *router) CreateRepoHandler(repoNameMinLength int) route { + const ( + projectRepo = "project_repo" + buildRepo = "build_repo" + ) + + return route{ Command: discordgo.ApplicationCommand{ Name: "repo", Description: "Command for repository creation", @@ -39,11 +53,11 @@ func CreateRepoHandler(repoNameMinLength int) CommandHandler { Choices: []*discordgo.ApplicationCommandOptionChoice{ { Name: "Unity project repo", - Value: "project_repo", + Value: projectRepo, }, { Name: "XCode build repo", - Value: "build_repo", + Value: buildRepo, }, }, }, @@ -66,41 +80,44 @@ func CreateRepoHandler(repoNameMinLength int) CommandHandler { optionMap[opt.Name] = opt } - // This example stores the provided arguments in an []interface{} - // which will be used to format the bot's response - margs := make([]interface{}, 0, len(options)) - msgformat := "You learned how to use command options! " + - "Take a look at the value(s) you entered:\n" + var str string = "" - if option, ok := optionMap["repo_type"]; ok { - // Option values must be type asserted from interface{}. - // Discordgo provides utility functions to make this simple. - margs = append(margs, option.StringValue()) - msgformat += "> string-option: %s\n" - } if option, ok := optionMap["repo_name"]; ok { - // Option values must be type asserted from interface{}. - // Discordgo provides utility functions to make this simple. - margs = append(margs, option.StringValue()) - msgformat += "> string-option: %s\n" + str = option.StringValue() + if option, ok := optionMap["repo_type"]; ok { + switch option.Value { + case projectRepo: + + case buildRepo: + str += "-build" + } + } } - s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + var g *domain.Git + var result string + + g, err := h.git.CreateRepo(str) + if err != nil { + result = fmt.Sprintf("error while repo creation: %v", err) + } else { + result = "🚀 " + g.HtmlUrl + " was created" + } + + discerr := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ // Ignore type for now, they will be discussed in "responses" Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ - Content: fmt.Sprintf( - msgformat, - margs..., - ), + Content: result, }, }) + log.Println(discerr) }, } } -func CreateTicketHandler(repoNameMinLength int) CommandHandler { - return CommandHandler{ +func (h *router) CreateTicketHandler(repoNameMinLength int) route { + return route{ Command: discordgo.ApplicationCommand{ Name: "new", Description: "Create new development ticket", @@ -130,13 +147,7 @@ func CreateTicketHandler(repoNameMinLength int) CommandHandler { msgformat := "You learned how to use command options! " + "Take a look at the value(s) you entered:\n" - if option, ok := optionMap["repo_type"]; ok { - // Option values must be type asserted from interface{}. - // Discordgo provides utility functions to make this simple. - margs = append(margs, option.StringValue()) - msgformat += "> string-option: %s\n" - } - if option, ok := optionMap["repo_name"]; ok { + if option, ok := optionMap["project_name"]; ok { // Option values must be type asserted from interface{}. // Discordgo provides utility functions to make this simple. margs = append(margs, option.StringValue()) diff --git a/docker/gitbucket/Dockerfile b/docker/gitbucket/Dockerfile deleted file mode 100644 index f7587fb..0000000 --- a/docker/gitbucket/Dockerfile +++ /dev/null @@ -1,28 +0,0 @@ -FROM adoptopenjdk/openjdk11-openj9 - -ARG GITBUCKET_HOME - -# create home -RUN mkdir -p $GITBUCKET_HOME - -# mark volumes -VOLUME $GITBUCKET_HOME/repositories -VOLUME $GITBUCKET_HOME/data -VOLUME $GITBUCKET_HOME/gist -VOLUME $GITBUCKET_HOME/plugins - -# Port for web page and Port for SSH access to git repository (Optional) -EXPOSE 8080 8443 29418 - -COPY server-WIN-DOMAIN-CA.cer / -COPY SSLPoke.java / - -# ADD https://github.com/gitbucket/gitbucket/releases/download/4.38.4/gitbucket.war $GITBUCKET_HOME/gitbucket.war -COPY gitbucket.war $GITBUCKET_HOME - -RUN keytool -importcert -file /server-WIN-DOMAIN-CA.cer -alias "server-WIN-DOMAIN-CA" -cacerts -storepass changeit -noprompt - -# set environment -WORKDIR $GITBUCKET_HOME - -CMD ["sh", "-c", "java $JAVA_OPTS -jar $GITBUCKET_HOME/gitbucket.war"] \ No newline at end of file diff --git a/docker/gitbucket/SSLPoke.java b/docker/gitbucket/SSLPoke.java deleted file mode 100644 index b46dcce..0000000 --- a/docker/gitbucket/SSLPoke.java +++ /dev/null @@ -1,40 +0,0 @@ -import javax.net.ssl.SSLParameters; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.SSLSocketFactory; -import java.io.*; - -/** Establish a SSL connection to a host and port, writes a byte and - * prints the response. See - * http://confluence.atlassian.com/display/JIRA/Connecting+to+SSL+services - */ -public class SSLPoke { - public static void main(String[] args) { - if (args.length != 2) { - System.out.println("Usage: "+SSLPoke.class.getName()+" "); - System.exit(1); - } - try { - SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); - SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket(args[0], Integer.parseInt(args[1])); - - SSLParameters sslparams = new SSLParameters(); - sslparams.setEndpointIdentificationAlgorithm("HTTPS"); - sslsocket.setSSLParameters(sslparams); - - InputStream in = sslsocket.getInputStream(); - OutputStream out = sslsocket.getOutputStream(); - - // Write a test byte to get a reaction :) - out.write(1); - - while (in.available() > 0) { - System.out.print(in.read()); - } - System.out.println("Successfully connected"); - - } catch (Exception exception) { - exception.printStackTrace(); - System.exit(1); - } - } -} \ No newline at end of file diff --git a/docker/gitbucket/docker-compose.yml b/docker/gitbucket/docker-compose.yml deleted file mode 100644 index 48fdcbf..0000000 --- a/docker/gitbucket/docker-compose.yml +++ /dev/null @@ -1,68 +0,0 @@ -version: "3" - -volumes: - mysql: - driver: local - -services: - gitbucket: - build: - context: . - dockerfile: Dockerfile - args: - GITBUCKET_HOME: /mnt/gitbucket - container_name: gitbucket_server - restart: always - ports: - - ${HTTP_PORT}:8080 - - ${HTTPS_PORT}:8443 - # Optional for SSH: - - ${SSH_PORT}:29418 - depends_on: - mariadb: - condition: service_healthy - environment: - - JAVA_OPTS=-Dcom.sun.net.ssl.checkRevocation=false -Dcom.sun.security.enableAIAcaIssuers=true -Docsp.enable=fase -Dtrust_all_cert=true -Djdk.tls.client.protocols=TLSv1.2 -Dcom.sun.net.ssl.enableECC=false - - GITBUCKET_HOME=/mnt/gitbucket - - GITBUCKET_CONNECTORS=http - - GITBUCKET_HOST=0.0.0.0 - - GITBUCKET_PORT=8080 - - GITBUCKET_SECUREPORT=8443 - - GITBUCKET_REDIRECTHTTPS=false - - GITBUCKET_PREFIX=/ - - GITBUCKET_MAXFILESIZE=4294967296 - - GITBUCKET_UPLOADTIMEOUT=120000 - - GITBUCKET_JETTYIDLETIMEOUT=600000 - - GITBUCKET_DB_URL=jdbc:mariadb://mariadb/gitbucket?useUnicode=true&characterEncoding=utf8 - - GITBUCKET_DB_USER=gitbucket - - GITBUCKET_DB_PASSWORD=gitbucket - healthcheck: - test: ["CMD", "/usr/bin/healthcheck"] - interval: 30s - timeout: 10s - retries: 5 - volumes: - - ../disks/disk1/gitbucket_data/repositories/:/mnt/gitbucket/repositories/ - - ../disks/disk1/gitbucket_data/data/:/mnt/gitbucket/data/ - - ../disks/disk1/gitbucket_data/gist/:/mnt/gitbucket/gist/ - - ../disks/disk1/gitbucket_data/plugins/:/mnt/gitbucket/plugins/ - - mariadb: - image: mariadb:10.6 - container_name: gitbucket_mariadb - restart: always - ports: - - ${DB_PORT}:3306 - environment: - - MYSQL_ROOT_PASSWORD=gitbucket - - MYSQL_USER=gitbucket - - MYSQL_PASSWORD=gitbucket - - MYSQL_DATABASE=gitbucket - command: ["--max-allowed-packet=128M", "--innodb-log-file-size=64M"] - healthcheck: - test: ["CMD", "mysqladmin", "ping", "-u", "root", "--password=gitbucket"] - interval: 10s - timeout: 5s - retries: 5 - volumes: - - mysql:/var/lib/mysql \ No newline at end of file diff --git a/docker/gitbucket/gitbucket.war b/docker/gitbucket/gitbucket.war deleted file mode 100644 index c63e40a..0000000 Binary files a/docker/gitbucket/gitbucket.war and /dev/null differ diff --git a/docker/gitbucket/server-WIN-DOMAIN-CA.cer b/docker/gitbucket/server-WIN-DOMAIN-CA.cer deleted file mode 100644 index 906db20..0000000 --- a/docker/gitbucket/server-WIN-DOMAIN-CA.cer +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDuTCCAqGgAwIBAgIQcZXcA798CYtB1LtewpzPijANBgkqhkiG9w0BAQsFADBu -MRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxHjAcBgoJkiaJk/IsZAEZFg5tYXJsZXJp -bm9ncm91cDEWMBQGCgmSJomT8ixkARkWBnNlcnZlcjEdMBsGA1UEAxMUc2VydmVy -LVdJTi1ET01BSU4tQ0EwIBcNMjIwODE1MTI1NTM3WhgPMjEyMjA4MTUxMzA1Mzda -MG4xFTATBgoJkiaJk/IsZAEZFgVsb2NhbDEeMBwGCgmSJomT8ixkARkWDm1hcmxl -cmlub2dyb3VwMRYwFAYKCZImiZPyLGQBGRYGc2VydmVyMR0wGwYDVQQDExRzZXJ2 -ZXItV0lOLURPTUFJTi1DQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AMBJwWymu7Csp+y8EMiPNo5drsQE58+enNCk13OIemQON5LZwY++BnvIrHvnaCof -Cdb9U2QyWV+Iehv/lNXcBkT6dJCTxUVmn6rXMmwNnBJmGuy0D6APIEPVBO3S7+/R -E4az8ikpVezbqAw/LiSyVMEQFaAEK8RlleBScLw9gpXmcWKljCrO/z+2wO1EGI3z -a1+qFLynQLeyusRj6rvo0U4RTyXdKaA++Ojhx3DV1NopHoSJ7CqXR728ubWK0fvY -0JGMg2ijS1cle7yC96+9ZSjdtktI/9M+8SG/tbpXcpW1bzGM0wCWOos1hLehks7V -c1pBEuVGSKSdtyF/FK2C7YUCAwEAAaNRME8wCwYDVR0PBAQDAgGGMA8GA1UdEwEB -/wQFMAMBAf8wHQYDVR0OBBYEFL+/yzfaRM/Rcrc9oYEzZf3STypqMBAGCSsGAQQB -gjcVAQQDAgEAMA0GCSqGSIb3DQEBCwUAA4IBAQA7j2n9ZeKDwbmWCM2P1F9+6EZ8 -+RZ+PEdxqs3aDo6S0Ckr/iopHA9PoexKGVEQN6bzaYxb0XTEbpJ89oI299weJF+W -63zID/lpEzsaSlTWpuj8KBudVoKsJmwJK2akQ2T3MmSiz7drtFOyh5wl9vhoi2cv -H3xhpqOYgh6iRwfwXMLo2YyS4vG6UZtq1GnU/drwVb1gHCoMdz7sFIdxlaw85Ub+ -dlicykBNu60dbvM/iI0qSG25PerjEoOWZAglrPWpsQ0Zy+ChV0lWSp6FIYHjT3Rj -3TUo18LwIUKyorRErOTO4vgYHpqaA/RkAfl0C3cUujMw9eAp1fyd9FH0UcDo ------END CERTIFICATE----- diff --git a/docker/owncloud/docker-compose.yml b/docker/owncloud/docker-compose.yml deleted file mode 100644 index 4218d74..0000000 --- a/docker/owncloud/docker-compose.yml +++ /dev/null @@ -1,72 +0,0 @@ -version: "3" - -volumes: - mysql: - driver: local - redis: - driver: local - -services: - owncloud: - image: owncloud/server:${OWNCLOUD_VERSION} - container_name: owncloud_server - restart: always - ports: - - ${HTTP_PORT}:8080 - depends_on: - - mariadb - - redis - environment: - - OWNCLOUD_DOMAIN=${OWNCLOUD_DOMAIN} - - OWNCLOUD_TRUSTED_DOMAINS=${OWNCLOUD_TRUSTED_DOMAINS} - - OWNCLOUD_DB_TYPE=mysql - - OWNCLOUD_DB_NAME=owncloud - - OWNCLOUD_DB_USERNAME=owncloud - - OWNCLOUD_DB_PASSWORD=owncloud - - OWNCLOUD_DB_HOST=mariadb - - OWNCLOUD_ADMIN_USERNAME=${ADMIN_USERNAME} - - OWNCLOUD_ADMIN_PASSWORD=${ADMIN_PASSWORD} - - OWNCLOUD_MYSQL_UTF8MB4=true - - OWNCLOUD_REDIS_ENABLED=true - - OWNCLOUD_REDIS_HOST=redis - healthcheck: - test: ["CMD", "/usr/bin/healthcheck"] - interval: 30s - timeout: 10s - retries: 5 - volumes: - - ../disks/disk1/owncloud_data/:/mnt/data - - ../disks/:/mnt/disks - - mariadb: - image: mariadb:10.6 # minimum required ownCloud version is 10.9 - container_name: owncloud_mariadb - restart: always - ports: - - ${DB_PORT}:3306 - environment: - - MYSQL_ROOT_PASSWORD=owncloud - - MYSQL_USER=owncloud - - MYSQL_PASSWORD=owncloud - - MYSQL_DATABASE=owncloud - command: ["--max-allowed-packet=128M", "--innodb-log-file-size=64M"] - healthcheck: - test: ["CMD", "mysqladmin", "ping", "-u", "root", "--password=owncloud"] - interval: 10s - timeout: 5s - retries: 5 - volumes: - - mysql:/var/lib/mysql - - redis: - image: redis:6 - container_name: owncloud_redis - restart: always - command: ["--databases", "1"] - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 10s - timeout: 5s - retries: 5 - volumes: - - redis:/data diff --git a/go.mod b/go.mod index ec33b16..6b32eba 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.20 require ( github.com/bwmarrin/discordgo v0.27.1 github.com/imroc/req/v3 v3.35.2 - github.com/jackc/pgx v3.6.2+incompatible github.com/jackc/pgx/v5 v5.4.3 github.com/joho/godotenv v1.5.1 github.com/mr-linch/go-tg v0.9.1 @@ -20,9 +19,8 @@ require ( github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/lib/pq v1.10.9 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/onsi/ginkgo/v2 v2.10.0 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qtls-go1-19 v0.3.2 // indirect github.com/quic-go/qtls-go1-20 v0.2.2 // indirect @@ -33,6 +31,7 @@ require ( golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/net v0.11.0 // indirect + golang.org/x/sync v0.2.0 // indirect golang.org/x/sys v0.9.0 // indirect golang.org/x/text v0.10.0 // indirect golang.org/x/tools v0.9.3 // indirect diff --git a/go.sum b/go.sum index 7ce9bea..a42806f 100644 --- a/go.sum +++ b/go.sum @@ -27,21 +27,17 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o= -github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= github.com/jackc/pgx/v5 v5.4.3 h1:cxFyXhxlvAifxnkKKdlxv8XqUf59tDlYjnV5YYfsJJY= github.com/jackc/pgx/v5 v5.4.3/go.mod h1:Ig06C2Vu0t5qXC60W8sqIthScaEnFvojjj9dSljmHRA= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= -github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mr-linch/go-tg v0.9.1 h1:4KNe7zwFG6svgM9w6pIcH3R7QWa6hIK8tCisQiFRCpU= github.com/mr-linch/go-tg v0.9.1/go.mod h1:276w69YW4pEo3ZYta+LQe4v/ut2w2h1ksP4ziBWkK98= github.com/onsi/ginkgo/v2 v2.10.0 h1:sfUl4qgLdvkChZrWCYndY2EAu9BRIw1YphNAzy1VNWs= github.com/onsi/ginkgo/v2 v2.10.0/go.mod h1:UDQOh5wbQUlMnkLfVaIUMtQ1Vus92oM+P2JX1aulgcE= github.com/onsi/gomega v1.27.7 h1:fVih9JD6ogIiHUN6ePK7HJidyEDpWGVB5mzM7cWNXoU= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= @@ -54,7 +50,6 @@ github.com/quic-go/quic-go v0.35.1 h1:b0kzj6b/cQAf05cT0CkQubHM31wiA+xH3IBkxP62po github.com/quic-go/quic-go v0.35.1/go.mod h1:+4CVgVppm0FNjpG3UcX8Joi/frKOH7/ciD5yGcwOO1g= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -81,6 +76,8 @@ golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -108,4 +105,3 @@ google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/bot/controller/controller.go b/internal/controller/controller.go similarity index 100% rename from bot/controller/controller.go rename to internal/controller/controller.go diff --git a/internal/domain/config.go b/internal/domain/config.go index 8ee777d..26411f1 100644 --- a/internal/domain/config.go +++ b/internal/domain/config.go @@ -1,5 +1,12 @@ package domain +import ( + "log" + "os" + + "github.com/joho/godotenv" +) + type Config struct { Git GitConfig Cloud CloudConfig @@ -48,3 +55,44 @@ type ApplicationConfig struct { Key string ID int } + +// InitConfig +// InitConfig function reads provided file and setup envirmental variables; +func InitConfig(envFilePath string) Config { + err := godotenv.Load(envFilePath) + if err != nil { + log.Fatal("Error while loading env file") + } + + return Config{ + Git: GitConfig{ + BaseUrl: os.Getenv("GIT_BASE_URL"), + Token: os.Getenv("GIT_TOKEN"), + User: os.Getenv("GIT_USER"), + }, + Cloud: CloudConfig{ + BaseUrl: os.Getenv("CLOUD_BASE_URL"), + User: os.Getenv("CLOUD_USER"), + Pass: os.Getenv("CLOUD_PASS"), + RootDir: os.Getenv("ROOTDIR"), + }, + Coda: CodaConfig{ + Farm: os.Getenv("CODA_TOKEN1"), + Develop: os.Getenv("CODA_TOKEN2"), + }, + DB: DBConfig{ + Host: os.Getenv("DB_HOST"), + Port: os.Getenv("DB_PORT"), + Name: os.Getenv("DB_NAME"), + User: os.Getenv("DB_USER"), + Pass: os.Getenv("DB_PASS"), + SslMode: os.Getenv("SSLMODE"), + }, + Telegram: TelegramConfig{ + Token: os.Getenv("TG_API"), + }, + Discord: DiscordConfig{ + Token: os.Getenv("DISCORD_TOKEN"), + }, + } +} diff --git a/internal/services/git.go b/internal/services/git.go index 6aea8c4..01388d6 100644 --- a/internal/services/git.go +++ b/internal/services/git.go @@ -49,19 +49,15 @@ func (gb *Git) CreateRepo(name string) (*domain.Git, error) { return repo, nil } -type request struct { +type gitCreateRequest struct { Name string `json:"name"` Private bool `json:"private"` } -type permissionRequest struct { - Perm string `json:"permission"` -} - func (gb *Git) newRepo(name string) (*domain.Git, error) { name = helpers.GitNaming(name) - payload := request{ + payload := gitCreateRequest{ Name: name, Private: true, } @@ -81,13 +77,16 @@ func (gb *Git) newRepo(name string) (*domain.Git, error) { return &git, nil } +type gitSetPermissionRequest struct { + Perm string `json:"permission"` +} + func (gb *Git) defaultGroupAsCollaborator(git *domain.Git) (*domain.Git, error) { - payload := permissionRequest{ + payload := gitSetPermissionRequest{ Perm: "push", } - ///orgs/manurlerino/teams/devs/repos/manurlerino/x respURL := "/orgs/mobilerino/teams/devs/repos/mobilerino/" + git.Name resp, _ := gb.R(). diff --git a/bot/handler/application.go b/telegram/handler/handle_application.go similarity index 100% rename from bot/handler/application.go rename to telegram/handler/handle_application.go diff --git a/bot/handler/farmtask.go b/telegram/handler/handle_farmtask.go similarity index 100% rename from bot/handler/farmtask.go rename to telegram/handler/handle_farmtask.go diff --git a/bot/handler/folder.go b/telegram/handler/handle_folder.go similarity index 100% rename from bot/handler/folder.go rename to telegram/handler/handle_folder.go diff --git a/bot/handler/git.go b/telegram/handler/handle_git.go similarity index 84% rename from bot/handler/git.go rename to telegram/handler/handle_git.go index 8627da7..52e0a76 100644 --- a/bot/handler/git.go +++ b/telegram/handler/handle_git.go @@ -19,12 +19,12 @@ type git struct { ssh string } -func newGit(domain *domain.Git) *git { +func newGit(g *domain.Git) *git { return &git{ - name: domain.Name, - url: domain.HtmlUrl, - git: domain.CloneUrl, - ssh: fmt.Sprintf("ssh://%s/%s.git", domain.SshUrl, domain.FullName), + name: g.Name, + url: g.HtmlUrl, + git: g.CloneUrl, + ssh: fmt.Sprintf("ssh://%s/%s.git", g.SshUrl, g.FullName), } } diff --git a/bot/handler/init.go b/telegram/handler/handle_init.go similarity index 100% rename from bot/handler/init.go rename to telegram/handler/handle_init.go diff --git a/bot/handler/handler.go b/telegram/handler/handler.go similarity index 78% rename from bot/handler/handler.go rename to telegram/handler/handler.go index 7e9ce31..ab26e26 100644 --- a/bot/handler/handler.go +++ b/telegram/handler/handler.go @@ -1,9 +1,9 @@ package handler import ( - "ticket-pimp/bot/controller" + "ticket-pimp/internal/controller" "ticket-pimp/internal/services" - db "ticket-pimp/internal/storage/db/tickets" + tickets "ticket-pimp/internal/storage/db/tickets" ) type Handler struct { @@ -13,14 +13,14 @@ type Handler struct { coda services.ICoda key string id string - db *db.Queries + db *tickets.Queries } func NewHandler( git services.IGit, cloud services.ICloud, coda services.ICoda, - db *db.Queries, + db *tickets.Queries, ) *Handler { return &Handler{ diff --git a/bot/handler/handler_test.go b/telegram/handler/handler_test.go similarity index 100% rename from bot/handler/handler_test.go rename to telegram/handler/handler_test.go diff --git a/telegram/telegram.go b/telegram/telegram.go new file mode 100644 index 0000000..140acf8 --- /dev/null +++ b/telegram/telegram.go @@ -0,0 +1,53 @@ +package telegram + +import ( + "context" + "log" + "ticket-pimp/internal/domain" + "ticket-pimp/internal/services" + "ticket-pimp/telegram/handler" + + "github.com/mr-linch/go-tg" + "github.com/mr-linch/go-tg/tgb" + + tickets "ticket-pimp/internal/storage/db/tickets" +) + +type TelegramOptions struct { + TicketsRepo *tickets.Queries + GitService *services.Git + CloudService *services.Cloud + Coda *services.Coda + AppConfig *domain.Config +} + +// runTgBot ... +// ..function creates new Telegram BOT instance +// ..throw env variables through bot's handlers +// ..setup tg bot router; +// and finally returns tgb.Poller +func Run(ctx context.Context, opts TelegramOptions) error { + + log.Print("Start telegram bot init..") + client := tg.New(opts.AppConfig.Telegram.Token) + + h := handler.NewHandler( + opts.GitService, + opts.CloudService, + opts.Coda, + opts.TicketsRepo, + ) + + router := tgb.NewRouter(). + Message(h.Init, tgb.Command("init")). + Message(h.PingHandler, tgb.Command("ping")). + Message(h.DevelopmentTaskHandler, tgb.TextHasPrefix("/new")). + Message(h.NewRepoHandler, tgb.TextHasPrefix("/repo")). + Message(h.NewFolderHandler, tgb.TextHasPrefix("/folder")). + Message(h.FarmTaskHandler, tgb.TextHasPrefix("/task")) + + return tgb.NewPoller( + router, + client, + ).Run(ctx) +}