refactor: Remove unused code and update models and functions for notification channels and settings

This commit is contained in:
Marvin Zhang
2024-07-23 12:22:59 +08:00
parent c893b5452e
commit 9ffdd3f1cd
14 changed files with 169 additions and 832 deletions

View File

@@ -2,6 +2,7 @@ package notification
import (
"errors"
"github.com/apex/log"
"github.com/crawlab-team/crawlab/core/models/models/v2"
"github.com/crawlab-team/crawlab/trace"
"github.com/imroc/req"
@@ -15,6 +16,10 @@ type ResBody struct {
func SendIMNotification(s *models.NotificationSettingV2, ch *models.NotificationChannelV2, content string) error {
// TODO: compatibility with different IM providers
switch ch.Provider {
case ChannelIMProviderLark:
return sendImLark(ch, content)
}
// request header
header := req.Header{
@@ -63,3 +68,49 @@ func SendIMNotification(s *models.NotificationSettingV2, ch *models.Notification
return nil
}
func getIMRequestHeader() req.Header {
return req.Header{
"Content-Type": "application/json; charset=utf-8",
}
}
func performIMRequest(webhookUrl string, data req.Param) error {
// perform request
res, err := req.Post(webhookUrl, getIMRequestHeader(), req.BodyJSON(&data))
if err != nil {
log.Errorf("IM request error: %v", err)
return err
}
// parse response
var resBody ResBody
if err := res.ToJSON(&resBody); err != nil {
log.Errorf("Parsing IM response error: %v", err)
return err
}
// validate response code
if resBody.ErrCode != 0 {
log.Errorf("IM response error: %v", resBody.ErrMsg)
return errors.New(resBody.ErrMsg)
}
return nil
}
func sendImLark(ch *models.NotificationChannelV2, content string) error {
// request header
data := req.Param{
"msg_type": "interactive",
"card": req.Param{
"elements": []req.Param{
{
"tag": "markdown",
"content": content,
},
},
},
}
return performIMRequest(ch.WebhookUrl, data)
}

View File

@@ -9,7 +9,6 @@ import (
"gopkg.in/gomail.v2"
"net/mail"
"regexp"
"runtime/debug"
"strings"
)
@@ -44,8 +43,8 @@ func SendMail(s *models.NotificationSettingV2, ch *models.NotificationChannelV2,
// send the email
if err := send(smtpConfig, options, content, text); err != nil {
log.Errorf(err.Error())
debug.PrintStack()
log.Errorf("failed to send email: %v", err)
trace.PrintError(err)
return err
}

View File

@@ -1,8 +0,0 @@
package notification
import "github.com/matcornic/hermes/v2"
type MailTheme interface {
hermes.Theme
GetStyle() string
}

View File

@@ -1,287 +0,0 @@
package notification
// MailThemeFlat is a theme
type MailThemeFlat struct{}
// Name returns the name of the flat theme
func (dt *MailThemeFlat) Name() string {
return "flat"
}
// HTMLTemplate returns a Golang template that will generate an HTML email.
func (dt *MailThemeFlat) HTMLTemplate() string {
return `
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body dir="{{.Hermes.TextDirection}}">
<table class="email-wrapper" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td class="content">
<table class="email-content" width="100%" cellpadding="0" cellspacing="0">
<!-- Logo -->
<tr>
<td class="email-masthead">
<a class="email-masthead_name" href="{{.Hermes.Product.Link}}" target="_blank">
{{ if .Hermes.Product.Logo }}
<img src="{{.Hermes.Product.Logo | url }}" class="email-logo" style="height: 48px"/>
<span style="font-size:36px;font-weight:600;margin-left:12px;color:#409eff">{{ .Hermes.Product.Name}} </span>
{{ else }}
{{ .Hermes.Product.Name }}
{{ end }}
</a>
</td>
</tr>
<!-- Email Body -->
<tr>
<td class="email-body" width="100%">
<table class="email-body_inner" align="center" width="570" cellpadding="0" cellspacing="0">
<!-- Body content -->
<tr>
<td class="content-cell">
{{ if (ne .Email.Body.FreeMarkdown "") }}
{{ .Email.Body.FreeMarkdown.ToHTML }}
{{ else }}
{{ with .Email.Body.Dictionary }}
{{ if gt (len .) 0 }}
<dl class="body-dictionary">
{{ range $entry := . }}
<dt>{{ $entry.Key }}:</dt>
<dd>{{ $entry.Value }}</dd>
{{ end }}
</dl>
{{ end }}
{{ end }}
<!-- Table -->
{{ with .Email.Body.Table }}
{{ $data := .Data }}
{{ $columns := .Columns }}
{{ if gt (len $data) 0 }}
<table class="data-wrapper" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td colspan="2">
<table class="data-table" width="100%" cellpadding="0" cellspacing="0">
<tr>
{{ $col := index $data 0 }}
{{ range $entry := $col }}
<th
{{ with $columns }}
{{ $width := index .CustomWidth $entry.Key }}
{{ with $width }}
width="{{ . }}"
{{ end }}
{{ $align := index .CustomAlignment $entry.Key }}
{{ with $align }}
style="text-align:{{ . }}"
{{ end }}
{{ end }}
>
<p>{{ $entry.Key }}</p>
</th>
{{ end }}
</tr>
{{ range $row := $data }}
<tr>
{{ range $cell := $row }}
<td
{{ with $columns }}
{{ $align := index .CustomAlignment $cell.Key }}
{{ with $align }}
style="text-align:{{ . }}"
{{ end }}
{{ end }}
>
{{ $cell.Value }}
</td>
{{ end }}
</tr>
{{ end }}
</table>
</td>
</tr>
</table>
{{ end }}
{{ end }}
<!-- Action -->
{{ with .Email.Body.Actions }}
{{ if gt (len .) 0 }}
{{ range $action := . }}
<p>{{ $action.Instructions }}</p>
<table class="body-action" align="center" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td align="center">
<div>
<a href="{{ $action.Button.Link }}" class="button" style="background-color: {{ $action.Button.Color }}; color: {{ $action.Button.TextColor }}" target="_blank">
{{ $action.Button.Text }}
</a>
</div>
</td>
</tr>
</table>
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ with .Email.Body.Outros }}
{{ if gt (len .) 0 }}
{{ range $line := . }}
<p>{{ $line }}</p>
{{ end }}
{{ end }}
{{ end }}
<p>
{{.Email.Body.Signature}}
</p>
{{ if (eq .Email.Body.FreeMarkdown "") }}
{{ with .Email.Body.Actions }}
<table class="body-sub">
<tbody>
{{ range $action := . }}
<tr>
<td>
<p class="sub">{{$.Hermes.Product.TroubleText | replace "{ACTION}" $action.Button.Text}}</p>
<p class="sub"><a href="{{ $action.Button.Link }}">{{ $action.Button.Link }}</a></p>
</td>
</tr>
{{ end }}
</tbody>
</table>
{{ end }}
{{ end }}
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table class="email-footer" align="center" width="570" cellpadding="0" cellspacing="0">
<tr>
<td class="content-cell">
<p class="sub center">
{{.Hermes.Product.Copyright}}
</p>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
`
}
// PlainTextTemplate returns a Golang template that will generate an plain text email.
func (dt *MailThemeFlat) PlainTextTemplate() string {
return `{{ with .Email.Body.Intros }}
{{ range $line := . }}
<p>{{ $line }}</p>
{{ end }}
{{ end }}
{{ if (ne .Email.Body.FreeMarkdown "") }}
{{ .Email.Body.FreeMarkdown.ToHTML }}
{{ else }}
{{ with .Email.Body.Dictionary }}
<ul>
{{ range $entry := . }}
<li>{{ $entry.Key }}: {{ $entry.Value }}</li>
{{ end }}
</ul>
{{ end }}
{{ with .Email.Body.Table }}
{{ $data := .Data }}
{{ $columns := .Columns }}
{{ if gt (len $data) 0 }}
<table class="data-table" width="100%" cellpadding="0" cellspacing="0">
<tr>
{{ $col := index $data 0 }}
{{ range $entry := $col }}
<th>{{ $entry.Key }} </th>
{{ end }}
</tr>
{{ range $row := $data }}
<tr>
{{ range $cell := $row }}
<td>
{{ $cell.Value }}
</td>
{{ end }}
</tr>
{{ end }}
</table>
{{ end }}
{{ end }}
{{ with .Email.Body.Actions }}
{{ range $action := . }}
<p>{{ $action.Instructions }} {{ $action.Button.Link }}</p>
{{ end }}
{{ end }}
{{ end }}
{{ with .Email.Body.Outros }}
{{ range $line := . }}
<p>{{ $line }}<p>
{{ end }}
{{ end }}
<p>{{.Email.Body.Signature}},<br>{{.Hermes.Product.Name}} - {{.Hermes.Product.Link}}</p>
<p>{{.Hermes.Product.Copyright}}</p>
`
}
func (dt *MailThemeFlat) GetStyle() string {
return `
<style>
.content-cell table {
width: 100%;
border-collapse: collapse;
}
.content-cell table,
.content-cell th,
.content-cell td {
border: 1px solid #EDEFF2;
}
.content-cell th,
.content-cell td {
padding: 10px;
font-size: 14px;
line-height: 18px;
}
.content-cell th {
background: #409eff;
color: white;
}
.content-cell td {
color: #606266;
}
.content-cell p {
color: #606266;
}
.content-cell a {
color: #409eff;
}
.email-masthead .email-masthead_name {
display: flex;
justify-content: center;
align-items: center;
text-decoration: none;
color: #409eff;
margin-bottom: 20px;
}
</style>
`
}

View File

@@ -1,8 +0,0 @@
package notification
import "go.mongodb.org/mongo-driver/bson/primitive"
type SendPayload struct {
TaskId primitive.ObjectID `json:"task_id"`
Data string `json:"data"`
}

View File

@@ -11,6 +11,7 @@ import (
"regexp"
"strings"
"sync"
"time"
)
type ServiceV2 struct {
@@ -91,14 +92,108 @@ func (svc *ServiceV2) getTaskContent(template string, variables []entity.Notific
content = strings.ReplaceAll(content, v.GetKey(), vd.Task.Id.Hex())
case "status":
content = strings.ReplaceAll(content, v.GetKey(), vd.Task.Status)
case "priority":
content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%d", vd.Task.Priority))
case "mode":
content = strings.ReplaceAll(content, v.GetKey(), vd.Task.Mode)
case "cmd":
content = strings.ReplaceAll(content, v.GetKey(), vd.Task.Cmd)
case "param":
content = strings.ReplaceAll(content, v.GetKey(), vd.Task.Param)
case "error":
content = strings.ReplaceAll(content, v.GetKey(), vd.Task.Error)
case "pid":
content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%d", vd.Task.Pid))
case "type":
content = strings.ReplaceAll(content, v.GetKey(), vd.Task.Type)
case "mode":
content = strings.ReplaceAll(content, v.GetKey(), vd.Task.Mode)
case "priority":
content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%d", vd.Task.Priority))
case "created_at":
content = strings.ReplaceAll(content, v.GetKey(), vd.Task.CreatedAt.Format(time.DateTime))
case "updated_at":
content = strings.ReplaceAll(content, v.GetKey(), vd.Task.UpdatedAt.Format(time.DateTime))
}
case "spider":
switch v.Name {
case "id":
content = strings.ReplaceAll(content, v.GetKey(), vd.Spider.Id.Hex())
case "name":
content = strings.ReplaceAll(content, v.GetKey(), vd.Spider.Name)
case "type":
content = strings.ReplaceAll(content, v.GetKey(), vd.Spider.Type)
case "description":
content = strings.ReplaceAll(content, v.GetKey(), vd.Spider.Description)
case "mode":
content = strings.ReplaceAll(content, v.GetKey(), vd.Spider.Mode)
case "cmd":
content = strings.ReplaceAll(content, v.GetKey(), vd.Spider.Cmd)
case "param":
content = strings.ReplaceAll(content, v.GetKey(), vd.Spider.Param)
case "priority":
content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%d", vd.Spider.Priority))
case "created_at":
content = strings.ReplaceAll(content, v.GetKey(), vd.Spider.CreatedAt.Format(time.DateTime))
case "updated_at":
content = strings.ReplaceAll(content, v.GetKey(), vd.Spider.UpdatedAt.Format(time.DateTime))
}
case "node":
switch v.Name {
case "id":
content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Id.Hex())
case "key":
content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Key)
case "name":
content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Name)
case "ip":
content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Ip)
case "port":
content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Port)
case "hostname":
content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Hostname)
case "description":
content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Description)
case "status":
content = strings.ReplaceAll(content, v.GetKey(), vd.Node.Status)
case "enabled":
content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%t", vd.Node.Enabled))
case "active":
content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%t", vd.Node.Active))
case "active_at":
content = strings.ReplaceAll(content, v.GetKey(), vd.Node.ActiveAt.Format("2006-01-02 15:04:05"))
case "available_runners":
content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%d", vd.Node.AvailableRunners))
case "max_runners":
content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%d", vd.Node.MaxRunners))
case "created_at":
content = strings.ReplaceAll(content, v.GetKey(), vd.Node.CreatedAt.Format(time.DateTime))
case "updated_at":
content = strings.ReplaceAll(content, v.GetKey(), vd.Node.UpdatedAt.Format(time.DateTime))
}
case "schedule":
switch v.Name {
case "id":
content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.Id.Hex())
case "name":
content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.Name)
case "description":
content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.Description)
case "cron":
content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.Cron)
case "cmd":
content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.Cmd)
case "param":
content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.Param)
case "mode":
content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.Mode)
case "priority":
content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%d", vd.Schedule.Priority))
case "enabled":
content = strings.ReplaceAll(content, v.GetKey(), fmt.Sprintf("%t", vd.Schedule.Enabled))
case "created_at":
content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.CreatedAt.Format(time.DateTime))
case "updated_at":
content = strings.ReplaceAll(content, v.GetKey(), vd.Schedule.UpdatedAt.Format(time.DateTime))
}
}
}
@@ -153,6 +248,10 @@ func (svc *ServiceV2) parseTemplateVariables(template string) (variables []entit
return variables
}
func (svc *ServiceV2) getUserById(id primitive.ObjectID) {
}
func newNotificationServiceV2() *ServiceV2 {
return &ServiceV2{}
}