Merge branch 'master' of ssh://git.paulbsd.com:2222/paulbsd/vmail
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Paul 2021-04-07 11:37:12 +02:00
commit d2a83c54ed
22 changed files with 261 additions and 103 deletions

12
go.sum
View File

@ -1,22 +1,16 @@
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU=
github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
@ -55,7 +49,6 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykE
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
@ -67,7 +60,6 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@ -85,7 +77,6 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -100,7 +91,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 h1:F5Gozwx4I1xtr/sr/8CFbb57iKi3297KFs0QDbGN60A=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@ -110,9 +100,7 @@ golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384 h1:TFlARGu6Czu1z7q93HTxcP1P+/ZFC/IKythI5RzrnRg=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=

View File

@ -1,7 +1,8 @@
package api
// Admin defines the admin struct
// Admin defines the admin struct for api
type Admin struct {
ID int `json:"id"`
Username string `json:"username"`
Created string `json:"created"`
Modified string `json:"modified"`

View File

@ -1,7 +1,8 @@
package api
// Alias defines the admin struct
// Alias defines the alias struct for api
type Alias struct {
ID int `json:"id"`
Address string `json:"address"`
Goto string `json:"goto"`
Domain string `json:"domain"`

View File

@ -1,6 +1,6 @@
package api
// Log defines the admin struct
// Log defines the log struct for api
type Log struct {
ID int `json:"id"`
Timestamp string `json:"timestamp"`

View File

@ -1,7 +1,8 @@
package api
// Mailbox defines the admin struct
// Mailbox defines the mailbox struct for api
type Mailbox struct {
ID int `json:"id"`
Username string `json:"username"`
Password string `json:"password"`
Name string `json:"name"`

View File

@ -9,6 +9,7 @@ import (
"git.paulbsd.com/paulbsd/vmail/src/models"
_ "github.com/lib/pq"
"xorm.io/xorm"
"xorm.io/xorm/dialects"
"xorm.io/xorm/names"
)
@ -20,11 +21,9 @@ func Initialize(ctx *context.Context, config *config.Config) (err error) {
}
config.Db.SetMapper(names.GonicMapper{})
config.Db.SetQuotePolicy(2)
config.Db.SetQuotePolicy(dialects.QuotePolicyReserved)
if config.Debug {
config.Db.ShowSQL(true)
}
config.Db.ShowSQL(config.Debug)
err = models.NewEngine(ctx, config)

View File

@ -2,26 +2,35 @@ package models
import (
"context"
"fmt"
"time"
"git.paulbsd.com/paulbsd/vmail/src/api"
"git.paulbsd.com/paulbsd/vmail/src/config"
"github.com/labstack/echo/v4"
)
// GetAdmins return list of apiadmins
func GetAdmins(ctx *context.Context, config *config.Config) (apiadmins []*api.Admin, err error) {
var admins []Admin
err = config.Db.Find(&admins)
err = config.Db.OrderBy(keyname).Find(&admins)
for _, adm := range admins {
apiadmins = append(apiadmins, adm.APIFormat())
}
return
}
// GetAdminModel ...
func GetAdminModel(ctx *context.Context, config *config.Config) (apiadmin *api.Admin, err error) {
var admin Admin
apiadmin = admin.APIFormat()
return
}
// GetAdmin ...
func GetAdmin(ctx *context.Context, config *config.Config, id interface{}) (apiadmin *api.Admin, err error) {
var admin Admin
has, err := config.Db.Where("username = ?", id).Get(&admin)
has, err := config.Db.Where(fmt.Sprintf("%s = ?", keyname), id).Get(&admin)
if !has || err != nil {
return
}
@ -29,12 +38,59 @@ func GetAdmin(ctx *context.Context, config *config.Config, id interface{}) (apia
return
}
// CreateAdmin ...
func CreateAdmin(ctx *context.Context, config *config.Config) (num int64, err error) {
var admin Admin
num, err = config.Db.Insert(&admin)
if err != nil {
return
}
return
}
// UpdateAdmin ...
func UpdateAdmin(ctx *context.Context, config *config.Config, c echo.Context) (num int64, err error) {
var admin Admin
var apiadmin = new(api.Admin)
if err = c.Bind(apiadmin); err != nil {
fmt.Println(err)
return
}
admin.APIParse(*apiadmin)
num, err = config.Db.ID(admin.ID).AllCols().Update(&admin)
return
}
// DeleteAdmin ...
func DeleteAdmin(ctx *context.Context, config *config.Config, id interface{}) (num int64, err error) {
var alias Alias
num, err = config.Db.Where(fmt.Sprintf("%s = ?", keyname), id).Delete(&alias)
if num > 0 || err != nil {
return
}
return
}
// APIParse returns a JSON formatted object of Admin
func (alias *Admin) APIParse(apiadmin api.Admin) (err error) {
*alias = Admin{
ID: apiadmin.ID,
Username: apiadmin.Username,
Active: apiadmin.Active,
Superadmin: apiadmin.Superadmin,
Phone: apiadmin.Phone,
EmailOther: apiadmin.EmailOther,
}
return
}
// APIFormat returns a JSON formatted object of Admin
func (admin *Admin) APIFormat() *api.Admin {
if admin == nil {
return nil
}
return &api.Admin{
ID: admin.ID,
Username: admin.Username,
Created: admin.Created.Format(timetostring),
Modified: admin.Modified.Format(timetostring),
@ -47,10 +103,11 @@ func (admin *Admin) APIFormat() *api.Admin {
// Admin defines the admin struct
type Admin struct {
Username string `xorm:"not null pk unique VARCHAR(255)"`
ID int `xorm:"not null pk unique serial"`
Username string `xorm:"not null unique VARCHAR(255)"`
Password string `xorm:"not null default '' VARCHAR(255)"`
Created time.Time `xorm:"default now() TIMESTAMPZ"`
Modified time.Time `xorm:"default now() TIMESTAMPZ"`
Created time.Time `xorm:"default now() TIMESTAMPZ created"`
Modified time.Time `xorm:"default now() TIMESTAMPZ modified"`
Active bool `xorm:"not null default true BOOL"`
Superadmin bool `xorm:"not null default false BOOL"`
Phone string `xorm:"not null default '' VARCHAR(30)"`

View File

@ -3,28 +3,39 @@ package models
import (
"context"
"fmt"
"strconv"
"time"
"git.paulbsd.com/paulbsd/vmail/src/api"
"git.paulbsd.com/paulbsd/vmail/src/config"
"github.com/labstack/echo/v4"
)
const key = "address"
// GetAliases ...
func GetAliases(ctx *context.Context, config *config.Config) (apialiases []*api.Alias, err error) {
// GetAliases get aliases from vmail
func GetAliases(ctx *context.Context, config *config.Config, limit string) (apialiases []*api.Alias, err error) {
var aliases []Alias
err = config.Db.Find(&aliases)
l, _ := strconv.Atoi(limit)
if l == 0 {
l = defaultlimit
}
err = config.Db.Limit(l, 0).OrderBy(keyname).Find(&aliases)
for _, al := range aliases {
apialiases = append(apialiases, al.APIFormat())
}
return
}
// GetAlias ...
// GetAliasModel get alias model from vmail
func GetAliasModel(ctx *context.Context, config *config.Config) (apialias *api.Alias, err error) {
var alias Alias
apialias = alias.APIFormat()
return
}
// GetAlias get alias from vmail
func GetAlias(ctx *context.Context, config *config.Config, id interface{}) (apialias *api.Alias, err error) {
var alias Alias
has, err := config.Db.Where(fmt.Sprintf("%s = ?", key), id).Get(&alias)
has, err := config.Db.Where(fmt.Sprintf("%s = ?", keyname), id).Get(&alias)
if !has || err != nil {
return
}
@ -32,7 +43,7 @@ func GetAlias(ctx *context.Context, config *config.Config, id interface{}) (apia
return
}
// CreateAlias ...
// CreateAlias creates alias on vmail
func CreateAlias(ctx *context.Context, config *config.Config) (num int64, err error) {
var alias Alias
num, err = config.Db.Insert(&alias)
@ -42,48 +53,66 @@ func CreateAlias(ctx *context.Context, config *config.Config) (num int64, err er
return
}
// UpdateAlias ...
func UpdateAlias(ctx *context.Context, config *config.Config, id interface{}) (apialias *api.Alias, err error) {
// UpdateAlias updates alias on vmail
func UpdateAlias(ctx *context.Context, config *config.Config, id string, c echo.Context) (apialias *api.Alias, err error) {
var alias Alias
has, err := config.Db.Where(fmt.Sprintf("%s = ?", key), id).Get(&alias)
if !has || err != nil {
apialias = new(api.Alias)
if err = c.Bind(apialias); err != nil {
return
}
apialias = alias.APIFormat()
alias.APIParse(*apialias)
num, err := config.Db.ID(id).AllCols().Update(&alias)
if num < 1 {
err = fmt.Errorf("%s", "No record updated")
}
return
}
// DeleteAlias ...
// DeleteAlias deletes alias on vmail
func DeleteAlias(ctx *context.Context, config *config.Config, id interface{}) (num int64, err error) {
var alias Alias
num, err = config.Db.Where(fmt.Sprintf("%s = ?", key), id).Delete(&alias)
num, err = config.Db.Where(fmt.Sprintf("%s = ?", keyname), id).Delete(&alias)
if num > 0 || err != nil {
return
}
return
}
// APIFormat returns a JSON formatted object of Admin
// APIParse returns a JSON formatted object of Alias
func (alias *Alias) APIParse(apialias api.Alias) (err error) {
*alias = Alias{
ID: apialias.ID,
Address: apialias.Address,
Goto: apialias.Goto,
Domain: apialias.Domain,
Active: apialias.Active,
}
return
}
// APIFormat returns a JSON formatted object of Alias
func (alias *Alias) APIFormat() *api.Alias {
if alias == nil {
return nil
}
return &api.Alias{
ID: alias.ID,
Address: alias.Address,
Goto: alias.Goto,
Domain: alias.Domain,
Created: alias.Created.Format(timetostring),
Modified: alias.Modified.Format(timetostring),
Created: alias.Created.In(timezone).Format(timetostring),
Modified: alias.Modified.In(timezone).Format(timetostring),
Active: alias.Active,
}
}
// Alias defines the admin struct
type Alias struct {
Address string `xorm:"not null pk index(alias_address_active) unique VARCHAR(255)"`
ID int `xorm:"not null pk unique serial"`
Address string `xorm:"not null index(alias_address_active) unique VARCHAR(255)"`
Goto string `xorm:"not null TEXT"`
Domain string `xorm:"not null index VARCHAR(255)"`
Created time.Time `xorm:"default now() TIMESTAMPZ"`
Modified time.Time `xorm:"default now() TIMESTAMPZ"`
Created time.Time `xorm:"default now() TIMESTAMPZ created"`
Modified time.Time `xorm:"default now() TIMESTAMPZ updated"`
Active bool `xorm:"default false index(alias_address_active) BOOL"`
}

View File

@ -4,9 +4,10 @@ import "time"
// AliasDomain defines domain aliases
type AliasDomain struct {
ID int `xorm:"not null pk unique serial"`
AliasDomain string `xorm:"not null index(alias_domain_active) VARCHAR(255)"`
TargetDomain string `xorm:"not null VARCHAR(255)"`
Created time.Time `xorm:"default now() TIMESTAMPZ"`
Modified time.Time `xorm:"default now() TIMESTAMPZ"`
Created time.Time `xorm:"default now() TIMESTAMPZ created"`
Modified time.Time `xorm:"default now() TIMESTAMPZ modified"`
Active bool `xorm:"not null default true index(alias_domain_active) BOOL"`
}

View File

@ -2,7 +2,7 @@ package models
// Config defines config table
type Config struct {
ID int `xorm:"not null pk autoincr INTEGER"`
ID int `xorm:"not null pk serial"`
Name string `xorm:"not null unique VARCHAR(20)"`
Value string `xorm:"not null VARCHAR(20)"`
}

View File

@ -4,7 +4,8 @@ import "time"
// Domain defines domain table
type Domain struct {
Domain string `xorm:"not null pk index(domain_domain_active) unique VARCHAR(255)"`
ID int `xorm:"not null pk unique serial"`
Domain string `xorm:"not null index(domain_domain_active) unique VARCHAR(255)"`
Description string `xorm:"not null default '' VARCHAR(255)"`
Aliases int `xorm:"not null default 0 INTEGER"`
Mailboxes int `xorm:"not null default 0 INTEGER"`
@ -12,8 +13,8 @@ type Domain struct {
Quota int64 `xorm:"not null default 0 BIGINT"`
Transport string `xorm:"default 'NULL' VARCHAR(255)"`
Backupmx bool `xorm:"not null default false BOOL"`
Created time.Time `xorm:"default now() TIMESTAMPZ"`
Modified time.Time `xorm:"default now() TIMESTAMPZ"`
Created time.Time `xorm:"default now() TIMESTAMPZ created"`
Modified time.Time `xorm:"default now() TIMESTAMPZ modified"`
Active bool `xorm:"not null default true index(domain_domain_active) BOOL"`
PasswordExpiry int `xorm:"default 0 INTEGER"`
}

View File

@ -4,8 +4,9 @@ import "time"
// DomainAdmins defines admin users of domains
type DomainAdmins struct {
ID int `xorm:"not null pk unique serial"`
Username string `xorm:"not null VARCHAR(255)"`
Domain string `xorm:"not null VARCHAR(255)"`
Created time.Time `xorm:"default now() TIMESTAMPZ"`
Created time.Time `xorm:"default now() TIMESTAMPZ created"`
Active bool `xorm:"not null default true BOOL"`
}

View File

@ -25,6 +25,6 @@ type Fetchmail struct {
Sslfingerprint string `xorm:"default '' VARCHAR(255)"`
Domain string `xorm:"default '' VARCHAR(255)"`
Active bool `xorm:"not null default false BOOL"`
Created time.Time `xorm:"default '2000-01-01 00:00:00+01' TIMESTAMPZ"`
Modified time.Time `xorm:"default now() TIMESTAMPZ"`
Created time.Time `xorm:"default '2000-01-01 00:00:00+01' TIMESTAMPZ created"`
Modified time.Time `xorm:"default now() TIMESTAMPZ modified"`
}

View File

@ -24,18 +24,18 @@ func (log *Log) APIFormat() *api.Log {
return nil
}
return &api.Log{
ID: log.ID,
Timestamp: log.Timestamp.Format(timetostring),
Username: log.Username,
Domain: log.Domain,
Action: log.Action,
Data: log.Data,
ID: log.ID,
}
}
// Log ...
type Log struct {
ID int `xorm:"not null pk autoincr INTEGER"`
ID int `xorm:"not null pk autoincr SERIAL"`
Timestamp time.Time `xorm:"default now() index(log_domain_timestamp_idx) TIMESTAMPZ"`
Username string `xorm:"not null default '' VARCHAR(255)"`
Domain string `xorm:"not null default '' index(log_domain_timestamp_idx) VARCHAR(255)"`

View File

@ -2,10 +2,12 @@ package models
import (
"context"
"fmt"
"time"
"git.paulbsd.com/paulbsd/vmail/src/api"
"git.paulbsd.com/paulbsd/vmail/src/config"
"github.com/labstack/echo/v4"
)
// GetMailboxes ...
@ -21,7 +23,7 @@ func GetMailboxes(ctx *context.Context, config *config.Config) (apimailboxes []*
// GetMailbox ...
func GetMailbox(ctx *context.Context, config *config.Config, id interface{}) (apimailbox *api.Mailbox, err error) {
var mailbox Mailbox
has, err := config.Db.Where("username = ?", id).Get(&mailbox)
has, err := config.Db.Where(fmt.Sprintf("%s = ?", keyname), id).Get(&mailbox)
if !has || err != nil {
return
}
@ -29,12 +31,54 @@ func GetMailbox(ctx *context.Context, config *config.Config, id interface{}) (ap
return
}
// APIFormat returns a JSON formatted object of Admin
// CreateMailbox ...
func CreateMailbox(ctx *context.Context, config *config.Config) (num int64, err error) {
var mailbox Mailbox
num, err = config.Db.Insert(&mailbox)
if err != nil {
return
}
return
}
// UpdateMailbox ...
func UpdateMailbox(ctx *context.Context, config *config.Config, c echo.Context) (num int64, err error) {
var mailbox Mailbox
var apimailbox = new(api.Mailbox)
if err = c.Bind(apimailbox); err != nil {
fmt.Println(err)
return
}
mailbox.APIParse(*apimailbox)
num, err = config.Db.ID(mailbox.ID).AllCols().Update(&mailbox)
return
}
// APIParse returns a JSON formatted object of Mailbox
func (alias *Mailbox) APIParse(apimailbox api.Mailbox) (err error) {
*alias = Mailbox{
ID: apimailbox.ID,
Username: apimailbox.Username,
Password: apimailbox.Password,
Name: apimailbox.Name,
Maildir: apimailbox.Maildir,
//Quota: apimailbox.Quota,
Active: apimailbox.Active,
Domain: apimailbox.Domain,
LocalPart: apimailbox.LocalPart,
Phone: apimailbox.Phone,
EmailOther: apimailbox.EmailOther,
}
return
}
// APIFormat returns a JSON formatted object of Mailbox
func (mailbox *Mailbox) APIFormat() *api.Mailbox {
if mailbox == nil {
return nil
}
return &api.Mailbox{
ID: mailbox.ID,
Username: mailbox.Username,
Password: "****",
Name: mailbox.Name,
@ -52,14 +96,15 @@ func (mailbox *Mailbox) APIFormat() *api.Mailbox {
// Mailbox ...
type Mailbox struct {
Username string `xorm:"not null pk unique index(mailbox_username_active) VARCHAR(255)"`
ID int `xorm:"not null pk serial"`
Username string `xorm:"not null index VARCHAR(255)"`
Password string `xorm:"not null default '' VARCHAR(255)"`
Name string `xorm:"not null default '' VARCHAR(255)"`
Maildir string `xorm:"not null default '' VARCHAR(255)"`
Quota int64 `xorm:"not null default 0 BIGINT"`
Created time.Time `xorm:"default now() TIMESTAMPZ"`
Modified time.Time `xorm:"default now() TIMESTAMPZ"`
Active bool `xorm:"default false index(mailbox_username_active) BOOL"`
Created time.Time `xorm:"default now() TIMESTAMPZ created"`
Modified time.Time `xorm:"default now() TIMESTAMPZ modified"`
Active bool `xorm:"default false index BOOL"`
Domain string `xorm:"index VARCHAR(255)"`
LocalPart string `xorm:"not null VARCHAR(255)"`
Phone string `xorm:"not null default '' VARCHAR(30)"`

View File

@ -2,7 +2,8 @@ package models
// Quota defines the Quota table
type Quota struct {
Username string `xorm:"not null pk VARCHAR(255)"`
Path string `xorm:"not null pk VARCHAR(100)"`
ID int `xorm:"not null pk unique serial"`
Username string `xorm:"not null unique VARCHAR(255)"`
Path string `xorm:"not null VARCHAR(100)"`
Current int64 `xorm:"BIGINT"`
}

View File

@ -2,7 +2,8 @@ package models
// Quota2 defines the Quota2 table
type Quota2 struct {
Username string `xorm:"not null pk VARCHAR(100)"`
ID int `xorm:"not null pk unique serial"`
Username string `xorm:"not null unique VARCHAR(100)"`
Bytes int64 `xorm:"not null default 0 BIGINT"`
Messages int `xorm:"not null default 0 INTEGER"`
}

View File

@ -2,11 +2,17 @@ package models
import (
"fmt"
"time"
"git.paulbsd.com/paulbsd/vmail/utils/units"
)
const timetostring = "02/01/2006 15:04"
var timezone, _ = time.LoadLocation("Europe/Paris")
// For template: Mon Jan 2 15:04:05 MST 2006
const timetostring string = "02/01/2006 15:04:05"
const keyname string = "id"
const defaultlimit = 10
func quotaFormat(in int64) (out string) {
var converted units.Base2Bytes

View File

@ -4,13 +4,14 @@ import "time"
// Vacation defines the vacation table
type Vacation struct {
Email string `xorm:"not null pk index(vacation_email_active) VARCHAR(255)"`
ID int `xorm:"not null pk unique serial"`
Email string `xorm:"not null index(vacation_email_active) VARCHAR(255)"`
Subject string `xorm:"not null VARCHAR(255)"`
Body string `xorm:"not null default '' TEXT"`
Created time.Time `xorm:"default now() TIMESTAMPZ"`
Active bool `xorm:"not null default true index(vacation_email_active) BOOL"`
Domain string `xorm:"VARCHAR(255)"`
Modified time.Time `xorm:"default now() TIMESTAMPZ"`
Created time.Time `xorm:"default now() TIMESTAMPZ created"`
Modified time.Time `xorm:"default now() TIMESTAMPZ modified"`
Activefrom time.Time `xorm:"default '2000-01-01 00:00:00+01' TIMESTAMPZ"`
Activeuntil time.Time `xorm:"default '2038-01-18 00:00:00+01' TIMESTAMPZ"`
IntervalTime int `xorm:"not null default 0 INTEGER"`

View File

@ -4,6 +4,7 @@ import "time"
//VacationNotification defines the VacationNotification table
type VacationNotification struct {
ID int `xorm:"not null pk unique serial"`
OnVacation string `xorm:"not null VARCHAR(255)"`
Notified string `xorm:"not null pk VARCHAR(255)"`
NotifiedAt time.Time `xorm:"not null default now() TIMESTAMPZ"`

View File

@ -23,65 +23,81 @@ func RegisterRoutes(e *echo.Echo, ctx *context.Context, cfg *config.Config) {
// Admins
e.GET("/api/admin", func(c echo.Context) (err error) {
admins, err := models.GetAdmins(ctx, cfg)
return c.JSON(http.StatusOK, admins)
ret, err := models.GetAdmins(ctx, cfg)
return JSONResult(c, err, ret)
})
e.GET("/api/admin/model", func(c echo.Context) (err error) {
ret, err := models.GetAdminModel(ctx, cfg)
return JSONResult(c, err, ret)
})
e.GET("/api/admin/:id", func(c echo.Context) (err error) {
admins, err := models.GetAdmins(ctx, cfg)
return c.JSON(http.StatusOK, admins)
ret, err := models.GetAdmin(ctx, cfg, c.Param("id"))
return JSONResult(c, err, ret)
})
e.POST("/api/admin", func(c echo.Context) (err error) {
ret, err := models.CreateAdmin(ctx, cfg)
return JSONResult(c, err, ret)
})
e.PUT("/api/admin/:id", func(c echo.Context) (err error) {
ret, err := models.UpdateAdmin(ctx, cfg, c)
return JSONResult(c, err, ret)
})
e.DELETE("/api/admin/:id", func(c echo.Context) (err error) {
admins, err := models.GetAdmins(ctx, cfg)
return c.JSON(http.StatusOK, admins)
ret, err := models.DeleteAdmin(ctx, cfg, c.Param("id"))
return JSONResult(c, err, ret)
})
// Aliases
e.GET("/api/alias", func(c echo.Context) (err error) {
aliases, err := models.GetAliases(ctx, cfg)
return c.JSON(http.StatusOK, aliases)
ret, err := models.GetAliases(ctx, cfg, c.QueryParam("limit"))
return JSONResult(c, err, ret)
})
e.GET("/api/alias/model", func(c echo.Context) (err error) {
ret, err := models.GetAliasModel(ctx, cfg)
return JSONResult(c, err, ret)
})
e.GET("/api/alias/:id", func(c echo.Context) (err error) {
alias, err := models.GetAlias(ctx, cfg, c.Param("id"))
return JSONResult(c, err, alias)
ret, err := models.GetAlias(ctx, cfg, c.Param("id"))
return JSONResult(c, err, ret)
})
e.POST("/api/alias", func(c echo.Context) (err error) {
_, err = models.CreateAlias(ctx, cfg)
return c.JSON(http.StatusOK, nil)
ret, err := models.CreateAlias(ctx, cfg)
return JSONResult(c, err, ret)
})
e.PUT("/api/alias/:id", func(c echo.Context) (err error) {
aliases, err := models.UpdateAlias(ctx, cfg, c.Param("id"))
return c.JSON(http.StatusOK, aliases)
ret, err := models.UpdateAlias(ctx, cfg, c.Param("id"), c)
return JSONResult(c, err, ret)
})
e.DELETE("/api/alias/:id", func(c echo.Context) (err error) {
aliases, err := models.DeleteAlias(ctx, cfg, c.Param("id"))
return c.JSON(http.StatusOK, aliases)
ret, err := models.DeleteAlias(ctx, cfg, c.Param("id"))
return JSONResult(c, err, ret)
})
// Mailboxes
e.GET("/api/mailbox", func(c echo.Context) (err error) {
mailboxes, err := models.GetMailboxes(ctx, cfg)
return c.JSON(http.StatusOK, mailboxes)
ret, err := models.GetMailboxes(ctx, cfg)
return JSONResult(c, err, ret)
})
e.GET("/api/mailbox/:id", func(c echo.Context) (err error) {
mailbox, err := models.GetMailbox(ctx, cfg, c.Param("id"))
return c.JSON(http.StatusOK, mailbox)
ret, err := models.GetMailbox(ctx, cfg, c.Param("id"))
return JSONResult(c, err, ret)
})
e.POST("/api/mailbox", func(c echo.Context) (err error) {
ret, err := models.CreateMailbox(ctx, cfg)
return JSONResult(c, err, ret)
})
e.PUT("/api/mailbox/:id", func(c echo.Context) (err error) {
ret, err := models.UpdateMailbox(ctx, cfg, c)
return JSONResult(c, err, ret)
})
e.DELETE("/api/mailbox/:id", func(c echo.Context) (err error) {
mailbox, err := models.GetMailbox(ctx, cfg, c.Param("id"))
return c.JSON(http.StatusOK, mailbox)
ret, err := models.GetMailbox(ctx, cfg, c.Param("id"))
return JSONResult(c, err, ret)
})
// Logs
e.GET("/api/log", func(c echo.Context) (err error) {
logs, err := models.GetLogs(ctx, cfg)
return c.JSON(http.StatusOK, logs)
ret, err := models.GetLogs(ctx, cfg)
return JSONResult(c, err, ret)
})
}
// JSONResult ...
func JSONResult(c echo.Context, inputerr error, data interface{}) (err error) {
if inputerr != nil {
return c.JSON(http.StatusInternalServerError, nil)
}
return c.JSON(http.StatusOK, data)
}

View File

@ -17,7 +17,7 @@ func RunServer(ctx *context.Context, cfg *config.Config) (err error) {
e.HideBanner = true
e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
AllowOrigins: []string{"http://localhost:8081"},
AllowOrigins: []string{"http://localhost:8080"},
AllowMethods: []string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete},
}))
@ -26,3 +26,11 @@ func RunServer(ctx *context.Context, cfg *config.Config) (err error) {
e.Logger.Fatal(e.Start(fmt.Sprintf(":%d", cfg.Port)))
return
}
// JSONResult handles returns and error management on backend api
func JSONResult(c echo.Context, inputerr error, data interface{}) (err error) {
if inputerr != nil {
return c.JSON(http.StatusInternalServerError, inputerr)
}
return c.JSON(http.StatusOK, data)
}