Skip to content

Commit

Permalink
fixed assignees
Browse files Browse the repository at this point in the history
  • Loading branch information
keshon committed Sep 18, 2021
1 parent 37afb94 commit e167788
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 74 deletions.
58 changes: 54 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,55 @@
# Kitsu automatic notifications to Discord webhook
Supports customizable template.
# Kitsu (CGWire) automatic notifications to Discord
This app automatically sends task status notifications from Kitsu tracker to Discord using a simple schedule. Discord messages can be customized via simple template engine (check /tpl dir).

# Bugs
Assignees - if 1 person he doesn't appear in template (> 1 works fine)
## Quick run
Download the latest version (only Windows for now), fill in conf.toml and run it.

### Configuration (conf.toml)
#### Basic
| Variables | Description |
| - | - |
| ignoreMessagesDaysOld | Don't parse tasks from Kitsu older that this value (days). |
| threads | Increase value to speed up proccesing parsed data - little to no benefit for now |
| debug | Print Kitsu response data to shell |
| log | Print additional information to shell |
#### Kitsu
| Variables | Description |
| - | - |
| hostname | Kitsu hostname like https://example.com/ - trailing slash is required. |
| email | Kitsu account email - account must have `Studio manager` privileges. |
| password | Account password. |
| skipComments | Comments create overhead - skip them if you don't need them. |
| requestInterval | How often (in minutes) to request data from kitsu and publish it to Discord. |
#### Discord
| Variables | Description |
| - | - |
| embedsPerRequests | How many messages (embeds) are in one post in the chat. 10 maximum |
| RequestsPerMinute | How many posts (with messages) per minute can be made. 50 maximum |
| webhookURL | Discord webhook URL address |

### Templating (tpl dir)
The Discord message can be changed using the template files found in the `\tpl` directory.
Each file corresponds to a different element in the Discord embedding structure, and each file has access to the following variables:
| Variables | Description |
| - | - |
| `{{.ProjectName}}` | Production name. |
| `{{.ParentName}}` | Task parent name: can be scenes name or asset type name. |
| `{{.TaskName}}` | Task name |
| `{{.TaskType}}` | Task type |
| `{{.CurrentStatus}}` | Current task type status (got from Kitsu) |
| `{{.PreviousStatus}}` | Previous tast type status (got from local database) |
| `{{.CommentContent}}` | Comment message |
| `{{.CommentAuthor}}` | Comment author |
| `{{.EntityType}}` | Entity type name |

## Compilation
Compilation is straight forward:
```bash
go build -ldflags "-s -w" -o app.exe src/main.go
```
## Docker
To deploy app via Docker:
1. docker-compose and Traefik is installed
2. Go to `deploy` dir
3. Update `.evn` if needed.
4. `bash run.sh` - exec supplied shell script that will download latest sources, build Docker image and run it via docker-compose.
4 changes: 2 additions & 2 deletions empty.conf.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Сonfiguration file

ignoreMessagesDaysOld = 5 # set to 0 to message everything
threads = 12 # small speedup in main loop
debug = false # show kitsu json response
log = true
Expand All @@ -8,11 +9,10 @@ log = true
hostname = "https://example.com/" # trailing slash is mandatory
email = "[email protected]"
password = "123"
skipComments = false # comments creates some overhead for Kitsu database - use with caution
skipComments = true # comments create some overhead for Kitsu database - use with caution
requestInterval = 10 # minutes

[discord]
embedsPerRequests = 10 # ten is maximum
RequestsPerMinute = 50 # fifty is maximum
ignoreMessagesDaysOld = 1
webhookURL = "https://discord.com/api/webhooks/123/123456789"
6 changes: 6 additions & 0 deletions release-build.bat
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,9 @@ go build -ldflags "-s -w" -o .\release\app.exe src/main.go
COPY README.md .\release
COPY LICENSE .\release
COPY empty.conf.toml .\release\conf.toml

mkdir .\release\tpl
COPY .\tpl\author.tpl .\release\tpl
COPY .\tpl\description.tpl .\release\tpl
COPY .\tpl\footer.tpl .\release\tpl
COPY .\tpl\title.tpl .\release\tpl
2 changes: 1 addition & 1 deletion src/api/discord/discord.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func SendMessageBunch(conf config.Config, data []kitsu.MessagePayload, webHookUR
var placeholders Template

placeholders.ProjectName = elem.Project.Name
placeholders.GroupName = elem.EntityType.Name
placeholders.GroupName = elem.EntityType.Name // not needed
placeholders.ParentName = elem.Parent.Name
placeholders.TaskName = elem.Entity.Name
placeholders.TaskType = elem.TaskType.Name
Expand Down
2 changes: 1 addition & 1 deletion src/api/kitsu/kitsu.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ func GetComment(objectID string) Comments {
}

func GetTasks() Tasks {
path := config.Read().Kitsu.Hostname + "api/data/tasks/?relations=true"
path := config.Read().Kitsu.Hostname + "api/data/tasks?relations=true"
response := Tasks{}
println(os.Getenv("KitsuJWTToken"))
request.Do(os.Getenv("KitsuJWTToken"), http.MethodGet, path, nil, &response.Each)
Expand Down
110 changes: 52 additions & 58 deletions src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,15 @@ func MakeKitsuResponse(conf config.Config) []kitsu.MessagePayload {
}

var comments kitsu.Comments
if conf.Kitsu.SkipComments {
if !conf.Kitsu.SkipComments {
comments = kitsu.GetComments()
if conf.Log {
fmt.Println("Got comments: " + strconv.Itoa(len(comments.Each)))
}
}

start := time.Now()

response := make([]kitsu.MessagePayload, len(tasks.Each))

wg := waitgroup.NewWaitGroup(conf.Threads)
Expand All @@ -79,6 +81,18 @@ func MakeKitsuResponse(conf config.Config) []kitsu.MessagePayload {
go func(i int) {
defer wg.Done()

// Ignore old messages
layout := "2006-01-02T15:04:05"
taskDate, err := time.Parse(layout, tasks.Each[i].UpdatedAt)
if err != nil {
fmt.Println(err)
}
daysCount := int(start.Sub(taskDate).Hours() / 24)

if conf.IgnoreMessagesDaysOld != 0 && daysCount > conf.IgnoreMessagesDaysOld {
return
}

// Store task
response[i].Task.Task = tasks.Each[i]

Expand Down Expand Up @@ -165,33 +179,15 @@ func MakeKitsuResponse(conf config.Config) []kitsu.MessagePayload {
break
}
}

/*
if len(tasks.Each[i].Assignees) > 0 {
response[i].Assignees = make([]kitsu.Person, len(tasks.Each[i].Assignees))
for e := 0; e < len(tasks.Each[i].Assignees); e++ {
if elem.ID == tasks.Each[i].Assignees[e] {
response[i].Assignees[e].FullName = "Test"
response[i].Assignees[e].FirstName = elem.FirstName
response[i].Assignees[e].LastName = elem.LastName
response[i].Assignees[e].Email = elem.Email
}
}
}
*/
}
}

// Store assignee
for _, elem := range persons.Each {
if len(tasks.Each[i].Assignees) > 0 {
response[i].Assignees = make([]kitsu.Person, len(tasks.Each[i].Assignees))
for e := 0; e < len(tasks.Each[i].Assignees); e++ {
if elem.ID == tasks.Each[i].Assignees[e] {
response[i].Assignees[e].FullName = elem.FullName
response[i].Assignees[e].FirstName = elem.FirstName
response[i].Assignees[e].LastName = elem.LastName
response[i].Assignees[e].Email = elem.Email
if len(tasks.Each[i].Assignees) > 0 {
for _, assigneeID := range tasks.Each[i].Assignees {
for _, person := range persons.Each {
if assigneeID == person.ID {
response[i].Assignees = append(response[i].Assignees, person)
}
}
}
Expand All @@ -201,7 +197,24 @@ func MakeKitsuResponse(conf config.Config) []kitsu.MessagePayload {
}
wg.Wait()

return response
if conf.Log {
log.Printf("Done primary loop in %s", time.Since(start))
}
//return response

// Remove empty elems
var out []kitsu.MessagePayload
for _, elem := range response {
if len(elem.Task.Task.ID) > 0 {
out = append(out, elem)
}
}

if conf.Log {
log.Printf("Done secondary loop in %s", time.Since(start))
}

return out
}

/*
Expand Down Expand Up @@ -248,7 +261,7 @@ func DiscordQueue(data []kitsu.MessagePayload, conf config.Config, db *gorm.DB)
}

rl := rate.New(conf.Discord.RequestsPerMinute, time.Minute) // 50 times per minute
begin := time.Now()
start := time.Now()

var payload []kitsu.MessagePayload
for i := 0; i < len(data); i++ {
Expand All @@ -270,31 +283,19 @@ func DiscordQueue(data []kitsu.MessagePayload, conf config.Config, db *gorm.DB)
model.CreateTask(db, data[i].Task.Task.ID, data[i].Task.Task.UpdatedAt, data[i].TaskStatus.TaskStatus.ShortName, data[i].LatestComment.Comment.ID, data[i].LatestComment.Comment.UpdatedAt)
}

// Ignore old messages
layout := "2006-01-02T15:04:05"
taskDate, err := time.Parse(layout, data[i].Task.Task.UpdatedAt)
if err != nil {
fmt.Println(err)
}
daysCount := int(begin.Sub(taskDate).Hours() / 24)
/*
if daysCount > conf.Discord.IgnoreMessagesDaysOld {
// Discord send
if daysCount < conf.Discord.IgnoreMessagesDaysOld {
payload = append(payload, data[i])
} else {
continue
}
*/

// Discord send
if daysCount < conf.Discord.IgnoreMessagesDaysOld {
payload = append(payload, data[i])
} else {
continue
}

}*/
payload = append(payload, data[i])
if i%conf.Discord.EmbedsPerRequests == 1 || len(data)-i < conf.Discord.EmbedsPerRequests {
rl.Wait()

if conf.Log {
fmt.Printf("%d started at %s\n", i, time.Now().Sub(begin))
fmt.Printf("%d started at %s\n", i, time.Since(start))
}
discord.SendMessageBunch(conf, payload, conf.Discord.WebhookURL)

Expand Down Expand Up @@ -323,10 +324,8 @@ func main() {
}
db.AutoMigrate(&model.Task{})

var elapsed time.Duration
if conf.Log {
elapsed = time.Since(start)
log.Printf("Connected to database in %s", elapsed)
log.Printf("Connected to database in %s", time.Since(start))
}

// Create Cron
Expand All @@ -338,8 +337,7 @@ func main() {
token := basicauth.AuthForJWTToken(conf.Kitsu.Hostname+"api/auth/login", conf.Kitsu.Email, conf.Kitsu.Password)
os.Setenv("KitsuJWTToken", token)
if conf.Log {
elapsed = time.Since(start)
log.Printf("Connected to Kitsu in %s", elapsed)
log.Printf("Connected to Kitsu in %s", time.Since(start))
}

c.AddFunc("@every 1h", func() {
Expand All @@ -354,31 +352,27 @@ func main() {
kitsuResponse := MakeKitsuResponse(conf)
if conf.Log {
DumpToFile(kitsuResponse, "kitsu_response")
elapsed = time.Since(start)
log.Printf("Done MakeKitsuResponse in %s", elapsed)
log.Printf("Done MakeKitsuResponse in %s", time.Since(start))
}

// Prepare messages to Discord
DiscordQueue(kitsuResponse, conf, db)
if conf.Log {
elapsed = time.Since(start)
log.Printf("Done DiscordQueue in %s", elapsed)
log.Printf("Done DiscordQueue in %s", time.Since(start))
}

c.AddFunc("@every "+strconv.Itoa(conf.Kitsu.RequestInterval)+"s", func() {
// Request data from Kitsu
kitsuResponse := MakeKitsuResponse(conf)
if conf.Log {
DumpToFile(kitsuResponse, "kitsu_response")
elapsed = time.Since(start)
log.Printf("Done MakeKitsuResponse in %s", elapsed)
log.Printf("Done MakeKitsuResponse in %s", time.Since(start))
}

// Prepare messages to Discord
DiscordQueue(kitsuResponse, conf, db)
if conf.Log {
elapsed = time.Since(start)
log.Printf("Done DiscordQueue in %s", elapsed)
log.Printf("Done DiscordQueue in %s", time.Since(start))
}
})

Expand Down
3 changes: 2 additions & 1 deletion src/utils/basicauth/basicauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ func AuthForJWTToken(url, email, password string) string {
var jwt Response
err = json.Unmarshal(respBody, &jwt)
if err != nil {
log.Fatalln(err)
log.Fatalln("Error! Check your Kitsu credentials in conf.toml")
//log.Fatalln(err)
}

return jwt.Token
Expand Down
14 changes: 7 additions & 7 deletions src/utils/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import (
)

type Config struct {
Threads int
Debug bool
Log bool
IgnoreMessagesDaysOld int
Threads int
Debug bool
Log bool

Kitsu struct {
Hostname string
Expand All @@ -20,10 +21,9 @@ type Config struct {
RequestInterval int
}
Discord struct {
EmbedsPerRequests int
RequestsPerMinute int
IgnoreMessagesDaysOld int
WebhookURL string
EmbedsPerRequests int
RequestsPerMinute int
WebhookURL string
}
}

Expand Down

0 comments on commit e167788

Please sign in to comment.