Skip to content

Commit afcfcd7

Browse files
feat: script sender and fix apprise error
1 parent f0b86b9 commit afcfcd7

File tree

10 files changed

+155
-56
lines changed

10 files changed

+155
-56
lines changed

config/config.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ func (p Parser) Parse(raw Raw) (Config, error) {
203203
return Config{}, err
204204
}
205205

206+
scriptDirectory := path.Join(dataDirectory, "scripts")
207+
if err := os.MkdirAll(scriptDirectory, 0755); err != nil {
208+
return Config{}, err
209+
}
210+
206211
smtpMaxMessageSize, err := bytes.Parse(raw.SMTPMaxPayloadSize)
207212
if err != nil {
208213
return Config{}, err
@@ -263,7 +268,7 @@ func (p Parser) Parse(raw Raw) (Config, error) {
263268
}
264269
}
265270

266-
endpointFactory := endpoint.NewFactory(raw.PythonExecutable, appriseScriptPath, endpoint.NewFuncMap(endpoint.CreateFuncMap{
271+
endpointFactory := endpoint.NewFactory(raw.PythonExecutable, appriseScriptPath, scriptDirectory, endpoint.NewFuncMap(endpoint.CreateFuncMap{
267272
URL: raw.HTTPURL,
268273
}))
269274
var endpoints []models.Endpoint

internal/endpoint/endpoint.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,15 @@ func (p payload) Title(ctx context.Context, env models.Envelope) (string, error)
169169
type Factory struct {
170170
pythonExecutable string
171171
appriseScriptPath string
172+
scriptDirectory string
172173
funcMap template.FuncMap
173174
}
174175

175-
func NewFactory(pythonExecutable string, appriseScriptPath string, funcMap template.FuncMap) Factory {
176+
func NewFactory(pythonExecutable string, appriseScriptPath string, scriptDirectory string, funcMap template.FuncMap) Factory {
176177
return Factory{
177178
pythonExecutable: pythonExecutable,
178179
appriseScriptPath: appriseScriptPath,
180+
scriptDirectory: scriptDirectory,
179181
funcMap: funcMap,
180182
}
181183
}

internal/endpoint/schema.go

+27-7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package endpoint
22

33
import (
44
"fmt"
5+
"path"
56

67
"github.com/ItsNotGoodName/smtpbridge/internal/models"
78
"github.com/ItsNotGoodName/smtpbridge/internal/senders"
@@ -18,14 +19,16 @@ var Schema models.EndpointSchema = models.EndpointSchema{
1819
Kind: "telegram",
1920
Fields: []models.EndpointSchemaField{
2021
{
21-
Name: "Token",
22-
Description: "",
2322
Key: "token",
23+
Name: "Token",
24+
Description: "Bot token from BotFather.",
25+
Example: "0123456789:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
2426
},
2527
{
26-
Name: "Chat ID",
27-
Description: "",
2828
Key: "chat_id",
29+
Name: "Chat ID",
30+
Description: "Channel/chat/group ID.",
31+
Example: "1000000000",
2932
},
3033
},
3134
},
@@ -34,9 +37,10 @@ var Schema models.EndpointSchema = models.EndpointSchema{
3437
Kind: "shoutrrr",
3538
Fields: []models.EndpointSchemaField{
3639
{
37-
Name: "URLs",
3840
Key: "urls",
39-
Description: "List of URLs.",
41+
Name: "URLs",
42+
Description: "List of Shoutrrr URLs.",
43+
Example: "telegram://token@telegram?chats=channel-1[,chat-id-1,...]",
4044
Multiline: true,
4145
},
4246
},
@@ -48,11 +52,24 @@ var Schema models.EndpointSchema = models.EndpointSchema{
4852
{
4953
Name: "URLs",
5054
Key: "urls",
51-
Description: "List of URLs.",
55+
Description: "List of Apprise URLs.",
56+
Example: "tgram://bottoken/ChatID",
5257
Multiline: true,
5358
},
5459
},
5560
},
61+
{
62+
Name: "Script",
63+
Kind: "script",
64+
Fields: []models.EndpointSchemaField{
65+
{
66+
Key: "file",
67+
Name: "File",
68+
Description: "Name of script file located in the script directory.",
69+
Example: "my-script.py",
70+
},
71+
},
72+
},
5673
}
5774

5875
var errInvalidSenderKind = fmt.Errorf("invalid sender kind")
@@ -82,6 +99,9 @@ func (s Factory) build(kind string, config models.EndpointConfig) (Sender, error
8299
return senders.NewShoutrrr(router), nil
83100
case "apprise":
84101
return senders.NewApprise(s.pythonExecutable, s.appriseScriptPath, config.StrSlice("urls")), nil
102+
case "script":
103+
scriptPath := path.Join(s.scriptDirectory, config.Str("file"))
104+
return senders.NewScript(scriptPath), nil
85105
default:
86106
return nil, errInvalidSenderKind
87107
}

internal/models/models.go

+1
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ type EndpointSchemaItem struct {
134134
type EndpointSchemaField struct {
135135
Name string
136136
Description string
137+
Example string
137138
Key string
138139
Multiline bool
139140
Optional bool

internal/senders/apprise.go

+6-10
Original file line numberDiff line numberDiff line change
@@ -54,27 +54,23 @@ func (a Apprise) Send(ctx context.Context, env models.Envelope, tr Transformer)
5454
Attachments: []apprisePayloadAttachment{},
5555
}
5656

57+
var err error
58+
5759
// Title
58-
title, err := tr.Title(ctx, env)
60+
payload.Title, err = tr.Title(ctx, env)
5961
if err != nil {
6062
return err
6163
}
62-
if title != "" {
63-
payload.Title = title
64-
}
6564

6665
// Body
67-
body, err := tr.Body(ctx, env)
66+
payload.Body, err = tr.Body(ctx, env)
6867
if err != nil {
6968
return err
7069
}
71-
if body != "" {
72-
payload.Body = body
73-
}
7470

7571
// Apprise's body cannot be empty
76-
if body == "" && title != "" {
77-
payload.Body = title
72+
if payload.Body == "" && payload.Title != "" {
73+
payload.Body = payload.Title
7874
payload.Title = ""
7975
}
8076

internal/senders/apprise_script.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414

1515
attach = apprise.AppriseAttachment(paths=paths)
1616

17-
apobj.notify(
18-
body=data['body'],
19-
title=data['title'],
20-
attach=attach
21-
)
17+
with apprise.LogCapture(level=apprise.logging.INFO) as logs:
18+
if not apobj.notify(body=data['body'], title=data['title'], attach=attach):
19+
print(logs.getvalue(), file=sys.stderr) # type: ignore
20+
sys.exit(1)

internal/senders/script.go

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package senders
2+
3+
import (
4+
"bytes"
5+
"context"
6+
_ "embed"
7+
"encoding/json"
8+
"fmt"
9+
"io"
10+
"os/exec"
11+
12+
"github.com/ItsNotGoodName/smtpbridge/internal/models"
13+
)
14+
15+
type Script struct {
16+
scriptPath string
17+
}
18+
19+
func NewScript(scriptPath string) Script {
20+
return Script{
21+
scriptPath: scriptPath,
22+
}
23+
}
24+
25+
type scriptPayload struct {
26+
Title string `json:"title"`
27+
Body string `json:"body"`
28+
Attachments []scriptPayloadAttachment `json:"attachments"`
29+
}
30+
31+
type scriptPayloadAttachment struct {
32+
Path string `json:"path"`
33+
Name string `json:"name"`
34+
}
35+
36+
func (s Script) Send(ctx context.Context, env models.Envelope, tr Transformer) error {
37+
payload := scriptPayload{
38+
Title: "",
39+
Body: "",
40+
Attachments: []scriptPayloadAttachment{},
41+
}
42+
43+
var err error
44+
45+
// Title
46+
payload.Title, err = tr.Title(ctx, env)
47+
if err != nil {
48+
return err
49+
}
50+
51+
// Body
52+
payload.Body, err = tr.Body(ctx, env)
53+
if err != nil {
54+
return err
55+
}
56+
57+
// Files
58+
files, err := tr.Files(ctx, env)
59+
if err != nil {
60+
return err
61+
}
62+
for i := range files {
63+
path, err := tr.Path(ctx, files[i])
64+
if err != nil {
65+
return err
66+
}
67+
payload.Attachments = append(payload.Attachments, scriptPayloadAttachment{
68+
Path: path,
69+
Name: files[i].Name,
70+
})
71+
}
72+
73+
rd, wt := io.Pipe()
74+
defer rd.Close()
75+
76+
go func() {
77+
json.NewEncoder(wt).Encode(payload)
78+
wt.Close()
79+
}()
80+
81+
cmd := exec.CommandContext(ctx, s.scriptPath)
82+
cmd.Stdin = rd
83+
var errBuf bytes.Buffer
84+
cmd.Stderr = &errBuf
85+
86+
if err := cmd.Run(); err != nil {
87+
stdErr := errBuf.String()
88+
return fmt.Errorf("%w: %s", err, stdErr)
89+
}
90+
91+
return nil
92+
}

web/components/endpoint_form.templ

+4-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/ItsNotGoodName/smtpbridge/web/routes"
77
"github.com/ItsNotGoodName/smtpbridge/web/helpers"
88
"github.com/ItsNotGoodName/smtpbridge/web/icons"
9+
"github.com/ItsNotGoodName/smtpbridge/internal/models"
910
)
1011

1112

@@ -130,11 +131,8 @@ type EndpointFormConfigProps struct {
130131
}
131132

132133
type EndpointFormConfigField struct {
133-
Name string
134-
Description string
135-
Key string
134+
models.EndpointSchemaField
136135
Value string
137-
Multiline bool
138136
}
139137

140138
templ EndpointFormConfig(props EndpointFormConfigProps) {
@@ -151,11 +149,11 @@ templ EndpointFormConfig(props EndpointFormConfigProps) {
151149
</label>
152150
<input type="hidden" name={ "Config." + strconv.Itoa(i) + ".Key" } value={ f.Key } />
153151
if f.Multiline{
154-
<textarea disabled?={ props.Internal } name={ "Config." + strconv.Itoa(i) + ".Value" } placeholder={ f.Name } class="textarea textarea-bordered h-24">
152+
<textarea disabled?={ props.Internal } name={ "Config." + strconv.Itoa(i) + ".Value" } placeholder={ f.Example } class="textarea textarea-bordered h-24">
155153
{ f.Value }
156154
</textarea>
157155
} else {
158-
<input disabled?={ props.Internal } name={ "Config." + strconv.Itoa(i) + ".Value" } placeholder={ f.Name } type="text" class="input input-bordered" value={ f.Value } />
156+
<input disabled?={ props.Internal } name={ "Config." + strconv.Itoa(i) + ".Value" } placeholder={ f.Example } type="text" class="input input-bordered" value={ f.Value } />
159157
}
160158
if f.Description != "" {
161159
<label class="label">

web/components/endpoint_form_templ.go

+5-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web/pages/pages_endpoint.go

+7-19
Original file line numberDiff line numberDiff line change
@@ -59,11 +59,8 @@ func EndpointCreate(ct Controller, app core.App) http.HandlerFunc {
5959
item := helpers.EndpointSchema().Get(form.Kind)
6060
for _, field := range item.Fields {
6161
fields = append(fields, c.EndpointFormConfigField{
62-
Name: field.Name,
63-
Description: field.Description,
64-
Key: field.Key,
65-
Multiline: field.Multiline,
66-
Value: formConfig[field.Key],
62+
EndpointSchemaField: field,
63+
Value: formConfig[field.Key],
6764
})
6865
}
6966

@@ -105,11 +102,8 @@ func EndpointView(ct Controller, app core.App) http.HandlerFunc {
105102
var fields []c.EndpointFormConfigField
106103
for _, field := range item.Fields {
107104
fields = append(fields, c.EndpointFormConfigField{
108-
Name: field.Name,
109-
Description: field.Description,
110-
Key: field.Key,
111-
Multiline: field.Multiline,
112-
Value: endpoint.Config[field.Key],
105+
EndpointSchemaField: field,
106+
Value: endpoint.Config[field.Key],
113107
})
114108
}
115109

@@ -167,11 +161,8 @@ func EndpointUpdate(ct Controller, app core.App) http.HandlerFunc {
167161
var fields []c.EndpointFormConfigField
168162
for _, field := range item.Fields {
169163
fields = append(fields, c.EndpointFormConfigField{
170-
Name: field.Name,
171-
Description: field.Description,
172-
Key: field.Key,
173-
Multiline: field.Multiline,
174-
Value: formConfig[field.Key],
164+
EndpointSchemaField: field,
165+
Value: formConfig[field.Key],
175166
})
176167
}
177168

@@ -224,10 +215,7 @@ func EndpointFormConfigComponent(ct Controller, app core.App) http.HandlerFunc {
224215
var fields []c.EndpointFormConfigField
225216
for _, field := range item.Fields {
226217
fields = append(fields, c.EndpointFormConfigField{
227-
Name: field.Name,
228-
Description: field.Description,
229-
Key: field.Key,
230-
Multiline: field.Multiline,
218+
EndpointSchemaField: field,
231219
})
232220
}
233221

0 commit comments

Comments
 (0)