feat: Portal, Email Inbound, Discuss + module improvements

- Portal: /my/* routes, signup, password reset, portal user support
- Email Inbound: IMAP polling (go-imap/v2), thread matching
- Discuss: mail.channel, long-polling bus, DM, unread count
- Cron: ir.cron runner (goroutine scheduler)
- Bank Import, CSV/Excel Import
- Automation (ir.actions.server)
- Fetchmail service
- HR Payroll model
- Various fixes across account, sale, stock, purchase, crm, hr, project

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marc
2026-04-12 18:41:57 +02:00
parent 2c7c1e6c88
commit 66383adf06
87 changed files with 14696 additions and 654 deletions

View File

@@ -70,8 +70,9 @@ func ApplyRecordRules(env *Environment, m *Model, domain Domain) Domain {
ORDER BY r.id`,
m.Name(), env.UID())
if err != nil {
log.Printf("orm: ir.rule query failed for %s: %v — denying access", m.Name(), err)
sp.Rollback(env.ctx)
return domain
return append(domain, Leaf("id", "=", -1)) // Deny all — no records match id=-1
}
type ruleRow struct {
@@ -207,7 +208,8 @@ func CheckRecordRuleAccess(env *Environment, m *Model, ids []int64, perm string)
var count int64
err := env.tx.QueryRow(env.ctx, query, args...).Scan(&count)
if err != nil {
return nil // Fail open on error
log.Printf("orm: record rule check failed for %s: %v", m.Name(), err)
return fmt.Errorf("orm: access denied on %s (record rule check failed)", m.Name())
}
if count < int64(len(ids)) {