mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: chat auto-archive owner digest notifications (#24643)
Depends on #24642 Adds per-owner digest notifications onto the chat auto-archive subsystem. Each tick's archived rows are grouped by owner, the top 25 titles per owner are rendered into a new `Chats Auto-Archived` notification template, and any remainder surfaces as `and N more`. Each digest is per-tick, so users with large amounts of purgeable data may get multiple notifications in sequence (one per user per tick). The template body branches on `retention_days`: when retention is disabled (`retention_days=0`), users are told archived chats are kept indefinitely rather than falsely claiming imminent deletion. ### Changes - migration `000XXX_chat_auto_archive_notification_template` adds new notification template - `dbpurge`: threads `notifications.Enqueuer` through `New`; and enqueues notification message. - `cli/server.go`: passes `options.NotificationsEnqueuer` into `dbpurge.New`. - `coderd/notifications/events.go`: new `TemplateChatAutoArchiveDigest` UUID. - `coderd/inboxnotifications.go`: inbox registration. - Docs: adds a `Notifications` section to `chat-auto-archive.md`. > 🤖
This commit is contained in:
@@ -62,3 +62,8 @@ var (
|
||||
TemplateTaskPaused = uuid.MustParse("2a74f3d3-ab09-4123-a4a5-ca238f4f65a1")
|
||||
TemplateTaskResumed = uuid.MustParse("843ee9c3-a8fb-4846-afa9-977bec578649")
|
||||
)
|
||||
|
||||
// Chat-related events.
|
||||
var (
|
||||
TemplateChatAutoArchiveDigest = uuid.MustParse("764031be-4863-4220-867b-6ce1a1b7a5f5")
|
||||
)
|
||||
|
||||
@@ -1332,6 +1332,89 @@ func TestNotificationTemplates_Golden(t *testing.T) {
|
||||
Data: map[string]any{},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Default branch: multiple visible chats, retention enabled,
|
||||
// no overflow. Body phrasing is number-neutral so this also
|
||||
// covers the n>1 grammar shape without a dedicated branch in
|
||||
// the template.
|
||||
name: "TemplateChatAutoArchiveDigest",
|
||||
id: notifications.TemplateChatAutoArchiveDigest,
|
||||
payload: types.MessagePayload{
|
||||
UserName: "Bobby",
|
||||
UserEmail: "bobby@coder.com",
|
||||
UserUsername: "bobby",
|
||||
Labels: map[string]string{},
|
||||
Data: map[string]any{
|
||||
"auto_archive_days": "90",
|
||||
"retention_days": "30",
|
||||
"archived_chats": []map[string]any{
|
||||
{"title": "Onboarding kickoff", "last_activity_humanized": "3 months ago"},
|
||||
{"title": "Quarterly planning draft", "last_activity_humanized": "4 months ago"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Pins the n=1 rendering so future edits to the body cannot
|
||||
// reintroduce a count-conditional that breaks the singular
|
||||
// case. The list-introduction sentence and retention sentence
|
||||
// both use plural-form pronouns ("them", "they") that read
|
||||
// naturally for a single item.
|
||||
name: "TemplateChatAutoArchiveDigestSingular",
|
||||
id: notifications.TemplateChatAutoArchiveDigest,
|
||||
payload: types.MessagePayload{
|
||||
UserName: "Bobby",
|
||||
UserEmail: "bobby@coder.com",
|
||||
UserUsername: "bobby",
|
||||
Labels: map[string]string{},
|
||||
Data: map[string]any{
|
||||
"auto_archive_days": "90",
|
||||
"retention_days": "30",
|
||||
"archived_chats": []map[string]any{
|
||||
{"title": "Onboarding kickoff", "last_activity_humanized": "3 months ago"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Covers the retention_days="0" indefinite-retention branch.
|
||||
name: "TemplateChatAutoArchiveDigestRetentionZero",
|
||||
id: notifications.TemplateChatAutoArchiveDigest,
|
||||
payload: types.MessagePayload{
|
||||
UserName: "Bobby",
|
||||
UserEmail: "bobby@coder.com",
|
||||
UserUsername: "bobby",
|
||||
Labels: map[string]string{},
|
||||
Data: map[string]any{
|
||||
"auto_archive_days": "90",
|
||||
"retention_days": "0",
|
||||
"archived_chats": []map[string]any{
|
||||
{"title": "Onboarding kickoff", "last_activity_humanized": "3 months ago"},
|
||||
{"title": "Quarterly planning draft", "last_activity_humanized": "4 months ago"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
// Covers the additional_archived_count overflow sentence.
|
||||
name: "TemplateChatAutoArchiveDigestOverflow",
|
||||
id: notifications.TemplateChatAutoArchiveDigest,
|
||||
payload: types.MessagePayload{
|
||||
UserName: "Bobby",
|
||||
UserEmail: "bobby@coder.com",
|
||||
UserUsername: "bobby",
|
||||
Labels: map[string]string{},
|
||||
Data: map[string]any{
|
||||
"auto_archive_days": "90",
|
||||
"retention_days": "30",
|
||||
"archived_chats": []map[string]any{
|
||||
{"title": "Onboarding kickoff", "last_activity_humanized": "3 months ago"},
|
||||
{"title": "Quarterly planning draft", "last_activity_humanized": "4 months ago"},
|
||||
},
|
||||
"additional_archived_count": "6",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// We must have a test case for every notification_template. This is enforced below:
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
// Package notificationsmock contains a mocked implementation of the
|
||||
// notifications.Enqueuer interface for use in tests.
|
||||
package notificationsmock
|
||||
|
||||
//go:generate mockgen -destination ./notificationsmock.go -package notificationsmock github.com/coder/coder/v2/coderd/notifications Enqueuer
|
||||
@@ -0,0 +1,82 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/coder/coder/v2/coderd/notifications (interfaces: Enqueuer)
|
||||
//
|
||||
// Generated by this command:
|
||||
//
|
||||
// mockgen -destination ./notificationsmock.go -package notificationsmock github.com/coder/coder/v2/coderd/notifications Enqueuer
|
||||
//
|
||||
|
||||
// Package notificationsmock is a generated GoMock package.
|
||||
package notificationsmock
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
uuid "github.com/google/uuid"
|
||||
gomock "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
// MockEnqueuer is a mock of Enqueuer interface.
|
||||
type MockEnqueuer struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockEnqueuerMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockEnqueuerMockRecorder is the mock recorder for MockEnqueuer.
|
||||
type MockEnqueuerMockRecorder struct {
|
||||
mock *MockEnqueuer
|
||||
}
|
||||
|
||||
// NewMockEnqueuer creates a new mock instance.
|
||||
func NewMockEnqueuer(ctrl *gomock.Controller) *MockEnqueuer {
|
||||
mock := &MockEnqueuer{ctrl: ctrl}
|
||||
mock.recorder = &MockEnqueuerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockEnqueuer) EXPECT() *MockEnqueuerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Enqueue mocks base method.
|
||||
func (m *MockEnqueuer) Enqueue(ctx context.Context, userID, templateID uuid.UUID, labels map[string]string, createdBy string, targets ...uuid.UUID) ([]uuid.UUID, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{ctx, userID, templateID, labels, createdBy}
|
||||
for _, a := range targets {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "Enqueue", varargs...)
|
||||
ret0, _ := ret[0].([]uuid.UUID)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Enqueue indicates an expected call of Enqueue.
|
||||
func (mr *MockEnqueuerMockRecorder) Enqueue(ctx, userID, templateID, labels, createdBy any, targets ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{ctx, userID, templateID, labels, createdBy}, targets...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Enqueue", reflect.TypeOf((*MockEnqueuer)(nil).Enqueue), varargs...)
|
||||
}
|
||||
|
||||
// EnqueueWithData mocks base method.
|
||||
func (m *MockEnqueuer) EnqueueWithData(ctx context.Context, userID, templateID uuid.UUID, labels map[string]string, data map[string]any, createdBy string, targets ...uuid.UUID) ([]uuid.UUID, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{ctx, userID, templateID, labels, data, createdBy}
|
||||
for _, a := range targets {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "EnqueueWithData", varargs...)
|
||||
ret0, _ := ret[0].([]uuid.UUID)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EnqueueWithData indicates an expected call of EnqueueWithData.
|
||||
func (mr *MockEnqueuerMockRecorder) EnqueueWithData(ctx, userID, templateID, labels, data, createdBy any, targets ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{ctx, userID, templateID, labels, data, createdBy}, targets...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnqueueWithData", reflect.TypeOf((*MockEnqueuer)(nil).EnqueueWithData), varargs...)
|
||||
}
|
||||
Vendored
+92
@@ -0,0 +1,92 @@
|
||||
From: system@coder.com
|
||||
To: bobby@coder.com
|
||||
Subject: Chats auto-archived after 90 days of inactivity
|
||||
Message-Id: 02ee4935-73be-4fa1-a290-ff9999026b13@blush-whale-48
|
||||
Date: Fri, 11 Oct 2024 09:03:06 +0000
|
||||
Content-Type: multipart/alternative; boundary=bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
|
||||
MIME-Version: 1.0
|
||||
|
||||
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
|
||||
Hi Bobby,
|
||||
|
||||
The following chats were automatically archived:
|
||||
|
||||
"Onboarding kickoff" (last active 3 months ago)
|
||||
"Quarterly planning draft" (last active 4 months ago)
|
||||
|
||||
You can restore any of them from the Agents page within 30 days, after whic=
|
||||
h they will be permanently deleted.
|
||||
|
||||
|
||||
View chats: http://test.com/agents?archived=3Darchived
|
||||
|
||||
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
|
||||
<!doctype html>
|
||||
<html lang=3D"en">
|
||||
<head>
|
||||
<meta charset=3D"UTF-8" />
|
||||
<meta name=3D"viewport" content=3D"width=3Ddevice-width, initial-scale=
|
||||
=3D1.0" />
|
||||
<title>Chats auto-archived after 90 days of inactivity</title>
|
||||
</head>
|
||||
<body style=3D"margin: 0; padding: 0; font-family: -apple-system, system-=
|
||||
ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarel=
|
||||
l', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; color: #020617=
|
||||
; background: #f8fafc;">
|
||||
<div style=3D"max-width: 600px; margin: 20px auto; padding: 60px; borde=
|
||||
r: 1px solid #e2e8f0; border-radius: 8px; background-color: #fff; text-alig=
|
||||
n: left; font-size: 14px; line-height: 1.5;">
|
||||
<div style=3D"text-align: center;">
|
||||
<img src=3D"https://coder.com/coder-logo-horizontal.png" alt=3D"Cod=
|
||||
er Logo" style=3D"height: 40px;" />
|
||||
</div>
|
||||
<h1 style=3D"text-align: center; font-size: 24px; font-weight: 400; m=
|
||||
argin: 8px 0 32px; line-height: 1.5;">
|
||||
Chats auto-archived after 90 days of inactivity
|
||||
</h1>
|
||||
<div style=3D"line-height: 1.5;">
|
||||
<p>Hi Bobby,</p>
|
||||
<p>The following chats were automatically archived:</p>
|
||||
|
||||
<ul>
|
||||
<li>“Onboarding kickoff” (last active 3 months ago)<br>
|
||||
</li>
|
||||
<li>“Quarterly planning draft” (last active 4 months ago)<br>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>You can restore any of them from the Agents page within 30 days, after w=
|
||||
hich they will be permanently deleted.</p>
|
||||
</div>
|
||||
<div style=3D"text-align: center; margin-top: 32px;">
|
||||
=20
|
||||
<a href=3D"http://test.com/agents?archived=3Darchived" style=3D"dis=
|
||||
play: inline-block; padding: 13px 24px; background-color: #020617; color: #=
|
||||
f8fafc; text-decoration: none; border-radius: 8px; margin: 0 4px;">
|
||||
View chats
|
||||
</a>
|
||||
=20
|
||||
</div>
|
||||
<div style=3D"border-top: 1px solid #e2e8f0; color: #475569; font-siz=
|
||||
e: 12px; margin-top: 64px; padding-top: 24px; line-height: 1.6;">
|
||||
<p>© 2024 Coder. All rights reserved - <a =
|
||||
href=3D"http://test.com" style=3D"color: #2563eb; text-decoration: none;">h=
|
||||
ttp://test.com</a></p>
|
||||
<p><a href=3D"http://test.com/settings/notifications" style=3D"colo=
|
||||
r: #2563eb; text-decoration: none;">Click here to manage your notification =
|
||||
settings</a></p>
|
||||
<p><a href=3D"http://test.com/settings/notifications?disabled=3D764=
|
||||
031be-4863-4220-867b-6ce1a1b7a5f5" style=3D"color: #2563eb; text-decoration=
|
||||
: none;">Stop receiving emails like this</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4--
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
From: system@coder.com
|
||||
To: bobby@coder.com
|
||||
Subject: Chats auto-archived after 90 days of inactivity
|
||||
Message-Id: 02ee4935-73be-4fa1-a290-ff9999026b13@blush-whale-48
|
||||
Date: Fri, 11 Oct 2024 09:03:06 +0000
|
||||
Content-Type: multipart/alternative; boundary=bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
|
||||
MIME-Version: 1.0
|
||||
|
||||
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
|
||||
Hi Bobby,
|
||||
|
||||
The following chats were automatically archived:
|
||||
|
||||
"Onboarding kickoff" (last active 3 months ago)
|
||||
"Quarterly planning draft" (last active 4 months ago)
|
||||
|
||||
...and 6 more.
|
||||
|
||||
You can restore any of them from the Agents page within 30 days, after whic=
|
||||
h they will be permanently deleted.
|
||||
|
||||
|
||||
View chats: http://test.com/agents?archived=3Darchived
|
||||
|
||||
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
|
||||
<!doctype html>
|
||||
<html lang=3D"en">
|
||||
<head>
|
||||
<meta charset=3D"UTF-8" />
|
||||
<meta name=3D"viewport" content=3D"width=3Ddevice-width, initial-scale=
|
||||
=3D1.0" />
|
||||
<title>Chats auto-archived after 90 days of inactivity</title>
|
||||
</head>
|
||||
<body style=3D"margin: 0; padding: 0; font-family: -apple-system, system-=
|
||||
ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarel=
|
||||
l', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; color: #020617=
|
||||
; background: #f8fafc;">
|
||||
<div style=3D"max-width: 600px; margin: 20px auto; padding: 60px; borde=
|
||||
r: 1px solid #e2e8f0; border-radius: 8px; background-color: #fff; text-alig=
|
||||
n: left; font-size: 14px; line-height: 1.5;">
|
||||
<div style=3D"text-align: center;">
|
||||
<img src=3D"https://coder.com/coder-logo-horizontal.png" alt=3D"Cod=
|
||||
er Logo" style=3D"height: 40px;" />
|
||||
</div>
|
||||
<h1 style=3D"text-align: center; font-size: 24px; font-weight: 400; m=
|
||||
argin: 8px 0 32px; line-height: 1.5;">
|
||||
Chats auto-archived after 90 days of inactivity
|
||||
</h1>
|
||||
<div style=3D"line-height: 1.5;">
|
||||
<p>Hi Bobby,</p>
|
||||
<p>The following chats were automatically archived:</p>
|
||||
|
||||
<ul>
|
||||
<li>“Onboarding kickoff” (last active 3 months ago)<br>
|
||||
</li>
|
||||
<li>“Quarterly planning draft” (last active 4 months ago)<br>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>…and 6 more.</p>
|
||||
|
||||
<p>You can restore any of them from the Agents page within 30 days, after w=
|
||||
hich they will be permanently deleted.</p>
|
||||
</div>
|
||||
<div style=3D"text-align: center; margin-top: 32px;">
|
||||
=20
|
||||
<a href=3D"http://test.com/agents?archived=3Darchived" style=3D"dis=
|
||||
play: inline-block; padding: 13px 24px; background-color: #020617; color: #=
|
||||
f8fafc; text-decoration: none; border-radius: 8px; margin: 0 4px;">
|
||||
View chats
|
||||
</a>
|
||||
=20
|
||||
</div>
|
||||
<div style=3D"border-top: 1px solid #e2e8f0; color: #475569; font-siz=
|
||||
e: 12px; margin-top: 64px; padding-top: 24px; line-height: 1.6;">
|
||||
<p>© 2024 Coder. All rights reserved - <a =
|
||||
href=3D"http://test.com" style=3D"color: #2563eb; text-decoration: none;">h=
|
||||
ttp://test.com</a></p>
|
||||
<p><a href=3D"http://test.com/settings/notifications" style=3D"colo=
|
||||
r: #2563eb; text-decoration: none;">Click here to manage your notification =
|
||||
settings</a></p>
|
||||
<p><a href=3D"http://test.com/settings/notifications?disabled=3D764=
|
||||
031be-4863-4220-867b-6ce1a1b7a5f5" style=3D"color: #2563eb; text-decoration=
|
||||
: none;">Stop receiving emails like this</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4--
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
From: system@coder.com
|
||||
To: bobby@coder.com
|
||||
Subject: Chats auto-archived after 90 days of inactivity
|
||||
Message-Id: 02ee4935-73be-4fa1-a290-ff9999026b13@blush-whale-48
|
||||
Date: Fri, 11 Oct 2024 09:03:06 +0000
|
||||
Content-Type: multipart/alternative; boundary=bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
|
||||
MIME-Version: 1.0
|
||||
|
||||
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
|
||||
Hi Bobby,
|
||||
|
||||
The following chats were automatically archived:
|
||||
|
||||
"Onboarding kickoff" (last active 3 months ago)
|
||||
"Quarterly planning draft" (last active 4 months ago)
|
||||
|
||||
You can restore any of them from the Agents page; archived chats are kept i=
|
||||
ndefinitely.
|
||||
|
||||
|
||||
View chats: http://test.com/agents?archived=3Darchived
|
||||
|
||||
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
|
||||
<!doctype html>
|
||||
<html lang=3D"en">
|
||||
<head>
|
||||
<meta charset=3D"UTF-8" />
|
||||
<meta name=3D"viewport" content=3D"width=3Ddevice-width, initial-scale=
|
||||
=3D1.0" />
|
||||
<title>Chats auto-archived after 90 days of inactivity</title>
|
||||
</head>
|
||||
<body style=3D"margin: 0; padding: 0; font-family: -apple-system, system-=
|
||||
ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarel=
|
||||
l', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; color: #020617=
|
||||
; background: #f8fafc;">
|
||||
<div style=3D"max-width: 600px; margin: 20px auto; padding: 60px; borde=
|
||||
r: 1px solid #e2e8f0; border-radius: 8px; background-color: #fff; text-alig=
|
||||
n: left; font-size: 14px; line-height: 1.5;">
|
||||
<div style=3D"text-align: center;">
|
||||
<img src=3D"https://coder.com/coder-logo-horizontal.png" alt=3D"Cod=
|
||||
er Logo" style=3D"height: 40px;" />
|
||||
</div>
|
||||
<h1 style=3D"text-align: center; font-size: 24px; font-weight: 400; m=
|
||||
argin: 8px 0 32px; line-height: 1.5;">
|
||||
Chats auto-archived after 90 days of inactivity
|
||||
</h1>
|
||||
<div style=3D"line-height: 1.5;">
|
||||
<p>Hi Bobby,</p>
|
||||
<p>The following chats were automatically archived:</p>
|
||||
|
||||
<ul>
|
||||
<li>“Onboarding kickoff” (last active 3 months ago)<br>
|
||||
</li>
|
||||
<li>“Quarterly planning draft” (last active 4 months ago)<br>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>You can restore any of them from the Agents page; archived chats are kep=
|
||||
t indefinitely.</p>
|
||||
</div>
|
||||
<div style=3D"text-align: center; margin-top: 32px;">
|
||||
=20
|
||||
<a href=3D"http://test.com/agents?archived=3Darchived" style=3D"dis=
|
||||
play: inline-block; padding: 13px 24px; background-color: #020617; color: #=
|
||||
f8fafc; text-decoration: none; border-radius: 8px; margin: 0 4px;">
|
||||
View chats
|
||||
</a>
|
||||
=20
|
||||
</div>
|
||||
<div style=3D"border-top: 1px solid #e2e8f0; color: #475569; font-siz=
|
||||
e: 12px; margin-top: 64px; padding-top: 24px; line-height: 1.6;">
|
||||
<p>© 2024 Coder. All rights reserved - <a =
|
||||
href=3D"http://test.com" style=3D"color: #2563eb; text-decoration: none;">h=
|
||||
ttp://test.com</a></p>
|
||||
<p><a href=3D"http://test.com/settings/notifications" style=3D"colo=
|
||||
r: #2563eb; text-decoration: none;">Click here to manage your notification =
|
||||
settings</a></p>
|
||||
<p><a href=3D"http://test.com/settings/notifications?disabled=3D764=
|
||||
031be-4863-4220-867b-6ce1a1b7a5f5" style=3D"color: #2563eb; text-decoration=
|
||||
: none;">Stop receiving emails like this</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4--
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
From: system@coder.com
|
||||
To: bobby@coder.com
|
||||
Subject: Chats auto-archived after 90 days of inactivity
|
||||
Message-Id: 02ee4935-73be-4fa1-a290-ff9999026b13@blush-whale-48
|
||||
Date: Fri, 11 Oct 2024 09:03:06 +0000
|
||||
Content-Type: multipart/alternative; boundary=bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
|
||||
MIME-Version: 1.0
|
||||
|
||||
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
|
||||
Hi Bobby,
|
||||
|
||||
The following chats were automatically archived:
|
||||
|
||||
"Onboarding kickoff" (last active 3 months ago)
|
||||
|
||||
You can restore any of them from the Agents page within 30 days, after whic=
|
||||
h they will be permanently deleted.
|
||||
|
||||
|
||||
View chats: http://test.com/agents?archived=3Darchived
|
||||
|
||||
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
|
||||
<!doctype html>
|
||||
<html lang=3D"en">
|
||||
<head>
|
||||
<meta charset=3D"UTF-8" />
|
||||
<meta name=3D"viewport" content=3D"width=3Ddevice-width, initial-scale=
|
||||
=3D1.0" />
|
||||
<title>Chats auto-archived after 90 days of inactivity</title>
|
||||
</head>
|
||||
<body style=3D"margin: 0; padding: 0; font-family: -apple-system, system-=
|
||||
ui, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarel=
|
||||
l', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; color: #020617=
|
||||
; background: #f8fafc;">
|
||||
<div style=3D"max-width: 600px; margin: 20px auto; padding: 60px; borde=
|
||||
r: 1px solid #e2e8f0; border-radius: 8px; background-color: #fff; text-alig=
|
||||
n: left; font-size: 14px; line-height: 1.5;">
|
||||
<div style=3D"text-align: center;">
|
||||
<img src=3D"https://coder.com/coder-logo-horizontal.png" alt=3D"Cod=
|
||||
er Logo" style=3D"height: 40px;" />
|
||||
</div>
|
||||
<h1 style=3D"text-align: center; font-size: 24px; font-weight: 400; m=
|
||||
argin: 8px 0 32px; line-height: 1.5;">
|
||||
Chats auto-archived after 90 days of inactivity
|
||||
</h1>
|
||||
<div style=3D"line-height: 1.5;">
|
||||
<p>Hi Bobby,</p>
|
||||
<p>The following chats were automatically archived:</p>
|
||||
|
||||
<ul>
|
||||
<li>“Onboarding kickoff” (last active 3 months ago)<br>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<p>You can restore any of them from the Agents page within 30 days, after w=
|
||||
hich they will be permanently deleted.</p>
|
||||
</div>
|
||||
<div style=3D"text-align: center; margin-top: 32px;">
|
||||
=20
|
||||
<a href=3D"http://test.com/agents?archived=3Darchived" style=3D"dis=
|
||||
play: inline-block; padding: 13px 24px; background-color: #020617; color: #=
|
||||
f8fafc; text-decoration: none; border-radius: 8px; margin: 0 4px;">
|
||||
View chats
|
||||
</a>
|
||||
=20
|
||||
</div>
|
||||
<div style=3D"border-top: 1px solid #e2e8f0; color: #475569; font-siz=
|
||||
e: 12px; margin-top: 64px; padding-top: 24px; line-height: 1.6;">
|
||||
<p>© 2024 Coder. All rights reserved - <a =
|
||||
href=3D"http://test.com" style=3D"color: #2563eb; text-decoration: none;">h=
|
||||
ttp://test.com</a></p>
|
||||
<p><a href=3D"http://test.com/settings/notifications" style=3D"colo=
|
||||
r: #2563eb; text-decoration: none;">Click here to manage your notification =
|
||||
settings</a></p>
|
||||
<p><a href=3D"http://test.com/settings/notifications?disabled=3D764=
|
||||
031be-4863-4220-867b-6ce1a1b7a5f5" style=3D"color: #2563eb; text-decoration=
|
||||
: none;">Stop receiving emails like this</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
--bbe61b741255b6098bb6b3c1f41b885773df633cb18d2a3002b68e4bc9c4--
|
||||
Vendored
+39
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"_version": "1.1",
|
||||
"msg_id": "00000000-0000-0000-0000-000000000000",
|
||||
"payload": {
|
||||
"_version": "1.2",
|
||||
"notification_name": "Chats Auto-Archived",
|
||||
"notification_template_id": "00000000-0000-0000-0000-000000000000",
|
||||
"user_id": "00000000-0000-0000-0000-000000000000",
|
||||
"user_email": "bobby@coder.com",
|
||||
"user_name": "Bobby",
|
||||
"user_username": "bobby",
|
||||
"actions": [
|
||||
{
|
||||
"label": "View chats",
|
||||
"url": "http://test.com/agents?archived=archived"
|
||||
}
|
||||
],
|
||||
"labels": {},
|
||||
"data": {
|
||||
"archived_chats": [
|
||||
{
|
||||
"last_activity_humanized": "3 months ago",
|
||||
"title": "Onboarding kickoff"
|
||||
},
|
||||
{
|
||||
"last_activity_humanized": "4 months ago",
|
||||
"title": "Quarterly planning draft"
|
||||
}
|
||||
],
|
||||
"auto_archive_days": "90",
|
||||
"retention_days": "30"
|
||||
},
|
||||
"targets": null
|
||||
},
|
||||
"title": "Chats auto-archived after 90 days of inactivity",
|
||||
"title_markdown": "Chats auto-archived after 90 days of inactivity",
|
||||
"body": "The following chats were automatically archived:\n\n\"Onboarding kickoff\" (last active 3 months ago)\n\"Quarterly planning draft\" (last active 4 months ago)\n\nYou can restore any of them from the Agents page within 30 days, after which they will be permanently deleted.",
|
||||
"body_markdown": "The following chats were automatically archived:\n\n* \"Onboarding kickoff\" (last active 3 months ago)\n* \"Quarterly planning draft\" (last active 4 months ago)\n\nYou can restore any of them from the Agents page within 30 days, after which they will be permanently deleted."
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"_version": "1.1",
|
||||
"msg_id": "00000000-0000-0000-0000-000000000000",
|
||||
"payload": {
|
||||
"_version": "1.2",
|
||||
"notification_name": "Chats Auto-Archived",
|
||||
"notification_template_id": "00000000-0000-0000-0000-000000000000",
|
||||
"user_id": "00000000-0000-0000-0000-000000000000",
|
||||
"user_email": "bobby@coder.com",
|
||||
"user_name": "Bobby",
|
||||
"user_username": "bobby",
|
||||
"actions": [
|
||||
{
|
||||
"label": "View chats",
|
||||
"url": "http://test.com/agents?archived=archived"
|
||||
}
|
||||
],
|
||||
"labels": {},
|
||||
"data": {
|
||||
"additional_archived_count": "6",
|
||||
"archived_chats": [
|
||||
{
|
||||
"last_activity_humanized": "3 months ago",
|
||||
"title": "Onboarding kickoff"
|
||||
},
|
||||
{
|
||||
"last_activity_humanized": "4 months ago",
|
||||
"title": "Quarterly planning draft"
|
||||
}
|
||||
],
|
||||
"auto_archive_days": "90",
|
||||
"retention_days": "30"
|
||||
},
|
||||
"targets": null
|
||||
},
|
||||
"title": "Chats auto-archived after 90 days of inactivity",
|
||||
"title_markdown": "Chats auto-archived after 90 days of inactivity",
|
||||
"body": "The following chats were automatically archived:\n\n\"Onboarding kickoff\" (last active 3 months ago)\n\"Quarterly planning draft\" (last active 4 months ago)\n\n...and 6 more.\n\nYou can restore any of them from the Agents page within 30 days, after which they will be permanently deleted.",
|
||||
"body_markdown": "The following chats were automatically archived:\n\n* \"Onboarding kickoff\" (last active 3 months ago)\n* \"Quarterly planning draft\" (last active 4 months ago)\n\n...and 6 more.\n\n\nYou can restore any of them from the Agents page within 30 days, after which they will be permanently deleted."
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"_version": "1.1",
|
||||
"msg_id": "00000000-0000-0000-0000-000000000000",
|
||||
"payload": {
|
||||
"_version": "1.2",
|
||||
"notification_name": "Chats Auto-Archived",
|
||||
"notification_template_id": "00000000-0000-0000-0000-000000000000",
|
||||
"user_id": "00000000-0000-0000-0000-000000000000",
|
||||
"user_email": "bobby@coder.com",
|
||||
"user_name": "Bobby",
|
||||
"user_username": "bobby",
|
||||
"actions": [
|
||||
{
|
||||
"label": "View chats",
|
||||
"url": "http://test.com/agents?archived=archived"
|
||||
}
|
||||
],
|
||||
"labels": {},
|
||||
"data": {
|
||||
"archived_chats": [
|
||||
{
|
||||
"last_activity_humanized": "3 months ago",
|
||||
"title": "Onboarding kickoff"
|
||||
},
|
||||
{
|
||||
"last_activity_humanized": "4 months ago",
|
||||
"title": "Quarterly planning draft"
|
||||
}
|
||||
],
|
||||
"auto_archive_days": "90",
|
||||
"retention_days": "0"
|
||||
},
|
||||
"targets": null
|
||||
},
|
||||
"title": "Chats auto-archived after 90 days of inactivity",
|
||||
"title_markdown": "Chats auto-archived after 90 days of inactivity",
|
||||
"body": "The following chats were automatically archived:\n\n\"Onboarding kickoff\" (last active 3 months ago)\n\"Quarterly planning draft\" (last active 4 months ago)\n\nYou can restore any of them from the Agents page; archived chats are kept indefinitely.",
|
||||
"body_markdown": "The following chats were automatically archived:\n\n* \"Onboarding kickoff\" (last active 3 months ago)\n* \"Quarterly planning draft\" (last active 4 months ago)\n\nYou can restore any of them from the Agents page; archived chats are kept indefinitely."
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"_version": "1.1",
|
||||
"msg_id": "00000000-0000-0000-0000-000000000000",
|
||||
"payload": {
|
||||
"_version": "1.2",
|
||||
"notification_name": "Chats Auto-Archived",
|
||||
"notification_template_id": "00000000-0000-0000-0000-000000000000",
|
||||
"user_id": "00000000-0000-0000-0000-000000000000",
|
||||
"user_email": "bobby@coder.com",
|
||||
"user_name": "Bobby",
|
||||
"user_username": "bobby",
|
||||
"actions": [
|
||||
{
|
||||
"label": "View chats",
|
||||
"url": "http://test.com/agents?archived=archived"
|
||||
}
|
||||
],
|
||||
"labels": {},
|
||||
"data": {
|
||||
"archived_chats": [
|
||||
{
|
||||
"last_activity_humanized": "3 months ago",
|
||||
"title": "Onboarding kickoff"
|
||||
}
|
||||
],
|
||||
"auto_archive_days": "90",
|
||||
"retention_days": "30"
|
||||
},
|
||||
"targets": null
|
||||
},
|
||||
"title": "Chats auto-archived after 90 days of inactivity",
|
||||
"title_markdown": "Chats auto-archived after 90 days of inactivity",
|
||||
"body": "The following chats were automatically archived:\n\n\"Onboarding kickoff\" (last active 3 months ago)\n\nYou can restore any of them from the Agents page within 30 days, after which they will be permanently deleted.",
|
||||
"body_markdown": "The following chats were automatically archived:\n\n* \"Onboarding kickoff\" (last active 3 months ago)\n\nYou can restore any of them from the Agents page within 30 days, after which they will be permanently deleted."
|
||||
}
|
||||
Reference in New Issue
Block a user