Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
8b04ad5
add mail service
PiquelChips Nov 23, 2025
8885f1b
Merge branch 'main' into mail
PiquelChips Nov 23, 2025
6d7d9b6
add DB schema and queries for mail stuff
PiquelChips Nov 23, 2025
0df2a82
add env vars for email stuff
PiquelChips Nov 23, 2025
ae8c876
add email policy
PiquelChips Nov 23, 2025
b0406ca
move docs instance out of models
PiquelChips Nov 23, 2025
855f26e
remove models package
PiquelChips Nov 23, 2025
84e1516
start implementing email stuff
PiquelChips Nov 23, 2025
512a5ea
add a comment with all email handlers needed
PiquelChips Nov 23, 2025
f4e6d26
add some basic handlers
PiquelChips Nov 23, 2025
07ddf54
update DB schema for sharing mail accounts
PiquelChips Nov 24, 2025
39c2bd8
Merge branch 'main' into mail
PiquelChips Nov 24, 2025
c0f1c0a
comment out email stuff
PiquelChips Nov 24, 2025
43f540c
setup function and handlers for account management
PiquelChips Nov 24, 2025
d5673b3
remove comments
PiquelChips Nov 24, 2025
f056b8d
remove commented stuff
PiquelChips Nov 24, 2025
3e0a064
Merge branch 'mail' into email/emails
PiquelChips Nov 24, 2025
63d4e58
fix database queries & schema (add mail_share table)
PiquelChips Nov 27, 2025
8b200ba
add options middleware
PiquelChips Nov 27, 2025
7b5800c
add passing context to mail service
PiquelChips Nov 27, 2025
b60111b
remove offset & limit for listing mail accounts
PiquelChips Nov 27, 2025
9dcc64d
add list accounts func
PiquelChips Nov 27, 2025
0c3244d
add constants to describe resource names to avoid typos
PiquelChips Nov 27, 2025
f327849
fix weird condition in policy
PiquelChips Nov 27, 2025
e161b07
fix policy for mail accounts
PiquelChips Nov 27, 2025
988c079
Merge branch 'mail' into email/emails
PiquelChips Nov 27, 2025
aada104
Merge branch 'main' into email/emails
PiquelChips Nov 29, 2025
6048715
Merge branch 'main' into email/emails
PiquelChips Nov 29, 2025
b10ad0f
fix build errors
PiquelChips Nov 29, 2025
c6ee8cd
Merge branch 'main' into email/emails
PiquelChips Nov 29, 2025
7da23e9
Merge branch 'main' into email/emails
PiquelChips Jan 25, 2026
11cb018
fix dependencies
PiquelChips Jan 25, 2026
cbb0f03
Merge branch 'main' into email/emails
PiquelChips Jan 27, 2026
02e9ec1
Merge branch 'main' into email/emails
PiquelChips Feb 9, 2026
1fa0cef
setup basic model for email handling
PiquelChips Feb 9, 2026
8d3c00c
implemented folder management
PiquelChips Feb 9, 2026
467c4dc
add email utilities
PiquelChips Feb 9, 2026
1129d74
setup email handling methods
PiquelChips Feb 9, 2026
fc62067
remove comments
PiquelChips Feb 9, 2026
b348951
make sure to use limit and offset when getting emails from folder
PiquelChips Feb 9, 2026
a1c98bc
add handlers for new API
PiquelChips Feb 9, 2026
8b5dc03
add limit & offset to route
PiquelChips Feb 9, 2026
ecbc87f
add max limit to (public) config
PiquelChips Feb 9, 2026
504c928
update sending email with new params
PiquelChips Feb 10, 2026
295b280
update policy
PiquelChips Feb 10, 2026
b6ede04
start some implementation
PiquelChips Feb 10, 2026
a1164ce
Merge branch 'main' into email/emails
PiquelChips Feb 10, 2026
7c6db3f
fix merge error
PiquelChips Feb 10, 2026
353e34b
fix: make sure to select folder before opening or deleting email
PiquelChips Feb 10, 2026
189e31d
implement email handlers
PiquelChips Feb 10, 2026
3b4f6f6
fix listing of emails
PiquelChips Feb 10, 2026
2555aa7
make sure to select folder
PiquelChips Feb 10, 2026
da130cf
make sure the limit is at least one
PiquelChips Feb 12, 2026
c9439aa
fix issue with mail selection
PiquelChips Feb 12, 2026
7cfd343
fix emails being read
PiquelChips Feb 12, 2026
daacf64
make sure to return the body in getemail
PiquelChips Feb 12, 2026
d26aa03
Merge branch 'main' into email/emails
PiquelChips Feb 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
620 changes: 616 additions & 4 deletions api/email.go

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ type EnvsConfig struct {
type PublicConfig struct {
Policy *PolicyConfiguration `json:"policy"`
UsernameBlacklist []string `json:"username_blacklist"`
MaxLimit uint32 `json:"max_limit"` // the maximum limit for pagination
}

func GetPublicConfig() PublicConfig {
return PublicConfig{Policy, UsernameBlacklist}
return PublicConfig{Policy, UsernameBlacklist, MaxLimit}
}

var Envs EnvsConfig
Expand All @@ -47,6 +48,8 @@ var UserContextKey = "user"
var UsernameBlacklist []string
var Policy *PolicyConfiguration

const MaxLimit = 200

func LoadConfig() {
godotenv.Load()
log.Printf("[Config] Loading configuration...")
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/google/go-github/v74 v74.0.0
github.com/jackc/pgx/v5 v5.8.0
github.com/joho/godotenv v1.5.1
github.com/wneessen/go-mail v0.7.2
golang.org/x/oauth2 v0.34.0
)

Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/wneessen/go-mail v0.7.2 h1:xxPnhZ6IZLSgxShebmZ6DPKh1b6OJcoHfzy7UjOkzS8=
github.com/wneessen/go-mail v0.7.2/go.mod h1:+TkW6QP3EVkgTEqHtVmnAE/1MRhmzb8Y9/W3pweuS+k=
github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0=
github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
Expand Down
62 changes: 36 additions & 26 deletions services/auth/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@ const (
// admin stuff
ActionUpdateAdmin = "update_admin"

// users
ActionViewEmail = "view_email"

// sessions
ActionViewUserSessions = "view_user_sessions"
ActionDeleteUserSessions = "delete_user_sessions"

// email
ActionViewEmail = "view_email"
ActionListEmailAccounts = "list_email_accounts"
ActionSendEmail = "send_email"
)

func own(request *config.AuthRequest) error {
Expand All @@ -50,6 +53,30 @@ func makeOwn(action string) *config.Permission {
}
}

// will check if you own of if the email account is shared with you
func makeOwnEmail(action string) *config.Permission {
return &config.Permission{
Action: action,
Conditions: config.Conditions{
func(request *config.AuthRequest) error {
if request.Ressource.GetOwner() == request.User.ID {
return nil
}

info, ok := request.Ressource.(*email.AccountInfo)
if !ok {
return newRequestMalformedError(request)
}

if slices.Contains(info.Shares, request.User.Username) {
return nil
}
return errors.ErrorNotFound
},
},
}
}

var policy = config.PolicyConfiguration{
Presets: map[string]*config.Permission{},
Roles: map[string]*config.Role{
Expand All @@ -70,13 +97,14 @@ var policy = config.PolicyConfiguration{
{Action: ActionUpdateAdmin},
{Action: ActionViewUserSessions},
{Action: ActionDeleteUserSessions},
{Action: ActionListEmailAccounts},
},
repository.ResourceMailAccount: {
{Action: ActionView},
{Action: ActionUpdate},
{Action: ActionDelete},
{Action: ActionListEmailAccounts},
{Action: ActionShare},
{Action: ActionSendEmail},
},
},
Parents: []string{RoleDefault, RoleDeveloper},
Expand All @@ -85,33 +113,15 @@ var policy = config.PolicyConfiguration{
Name: "Developer",
Color: "blue",
Permissions: map[string][]*config.Permission{
repository.ResourceMailAccount: {
{
Action: ActionView,
Conditions: config.Conditions{
func(request *config.AuthRequest) error {
if request.Ressource.GetOwner() == request.User.ID {
return nil
}

info, ok := request.Ressource.(*email.AccountInfo)
if !ok {
return newRequestMalformedError(request)
}

if slices.Contains(info.Shares, request.User.Username) {
return nil
}
return errors.ErrorNotFound
},
},
},
makeOwn(ActionDelete),
},
repository.ResourceUser: {
makeOwn(ActionShare),
makeOwn(ActionListEmailAccounts),
},
repository.ResourceMailAccount: {
makeOwnEmail(ActionView),
makeOwnEmail(ActionSendEmail),
makeOwn(ActionShare),
makeOwn(ActionDelete),
},
},
Parents: []string{RoleDefault},
},
Expand Down
23 changes: 5 additions & 18 deletions services/email/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,10 @@ import (
"github.com/piquel-fr/api/database/repository"
)

type Mailbox struct {
Name string `json:"name"`
NumMessages int `json:"num_messages"`
NumUnread int `json:"num_unread"`
}

type AccountInfo struct {
*repository.MailAccount
Mailboxes []Mailbox `json:"mailboxes"`
Shares []string `json:"shares"`
Folders []Folder `json:"mailboxes"`
Shares []string `json:"shares"`
}

func (s *realEmailService) GetAccountByEmail(ctx context.Context, email string) (*repository.MailAccount, error) {
Expand Down Expand Up @@ -59,16 +53,9 @@ func (s *realEmailService) GetAccountInfo(ctx context.Context, account *reposito
account.Username = ""
account.Password = ""

// get mailboxes
listCmd := client.List("", "*", nil)
defer listCmd.Close()

for mailbox := listCmd.Next(); mailbox != nil; mailbox = listCmd.Next() {
accountInfo.Mailboxes = append(accountInfo.Mailboxes, Mailbox{
Name: mailbox.Mailbox,
NumMessages: int(*mailbox.Status.NumMessages),
NumUnread: int(*mailbox.Status.NumUnseen),
})
accountInfo.Folders, err = s.ListFolders(account)
if err != nil {
return AccountInfo{}, err
}

// get shares
Expand Down
Loading