| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- // Copyright 2019 Yunion
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package models
- import (
- "context"
- "fmt"
- "strings"
- "time"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/regutils"
- "yunion.io/x/sqlchemy"
- api "yunion.io/x/onecloud/pkg/apis/notify"
- "yunion.io/x/onecloud/pkg/cloudcommon/consts"
- "yunion.io/x/onecloud/pkg/cloudcommon/db"
- "yunion.io/x/onecloud/pkg/httperrors"
- "yunion.io/x/onecloud/pkg/mcclient"
- "yunion.io/x/onecloud/pkg/util/stringutils2"
- )
- const (
- maxEmailDestCount = 256
- )
- type SEmailQueueManager struct {
- db.SLogBaseManager
- }
- type SEmailQueue struct {
- db.SLogBase
- RecvAt time.Time `nullable:"false" created_at:"true" index:"true" get:"user" list:"user" json:"recv_at"`
- Dest string `width:"256" charset:"ascii" nullable:"false" list:"user" create:"admin_required"`
- Subject string `width:"256" charset:"utf8" nullable:"false" list:"user" create:"admin_required"`
- DestCc string `width:"256" charset:"ascii" nullable:"false" list:"user" create:"admin_optional"`
- DestBcc string `width:"256" charset:"ascii" nullable:"false" list:"user" create:"admin_optional"`
- SessionId string `width:"256" charset:"utf8" nullable:"false" list:"user" create:"admin_optional"`
- Content jsonutils.JSONObject `length:"long" charset:"utf8" nullable:"false" list:"user" create:"admin_required"`
- MoreDetails jsonutils.JSONObject `length:"long" charset:"utf8" nullable:"true" list:"user" create:"admin_optional"`
- ProjectId string `width:"128" charset:"ascii" list:"user" create:"admin_optional" index:"true"`
- Project string `width:"128" charset:"utf8" list:"user" create:"admin_optional"`
- ProjectDomainId string `name:"project_domain_id" default:"default" width:"128" charset:"ascii" list:"user" create:"admin_optional"`
- ProjectDomain string `name:"project_domain" default:"Default" width:"128" charset:"utf8" list:"user" create:"admin_optional"`
- UserId string `width:"128" charset:"ascii" list:"user" create:"admin_required"`
- User string `width:"128" charset:"utf8" list:"user" create:"admin_required"`
- DomainId string `width:"128" charset:"ascii" list:"user" create:"admin_optional"`
- Domain string `width:"128" charset:"utf8" list:"user" create:"admin_optional"`
- Roles string `width:"64" charset:"utf8" list:"user" create:"admin_optional"`
- }
- var EmailQueueManager *SEmailQueueManager
- func InitEmailQueue() {
- EmailQueueManager = &SEmailQueueManager{
- SLogBaseManager: db.NewLogBaseManager(SEmailQueue{}, "emailqueue_tbl", "emailqueue", "emailqueues", "recv_at", consts.OpsLogWithClickhouse),
- }
- EmailQueueManager.SetVirtualObject(EmailQueueManager)
- }
- func (e *SEmailQueue) GetRecordTime() time.Time {
- return e.RecvAt
- }
- func (manager *SEmailQueueManager) ValidateCreateData(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- ownerId mcclient.IIdentityProvider,
- query jsonutils.JSONObject,
- input api.EmailQueueCreateInput,
- ) (api.EmailQueueCreateInput, error) {
- // check permission
- if db.IsAdminAllowCreate(userCred, manager).Result.IsDeny() {
- return input, errors.Wrap(httperrors.ErrForbidden, "only admin can send email")
- }
- // validate data
- if len(input.To) == 0 {
- return input, errors.Wrap(httperrors.ErrInputParameter, "empty receiver")
- }
- invalidTos := make([]string, 0)
- for _, tos := range [][]string{
- input.To,
- input.Cc,
- input.Bcc,
- } {
- for _, to := range tos {
- if !regutils.MatchEmail(to) {
- invalidTos = append(invalidTos, to)
- }
- }
- }
- if len(invalidTos) > 0 {
- return input, errors.Wrapf(httperrors.ErrInputParameter, "invalid email %s", strings.Join(invalidTos, ","))
- }
- input.Dest = strings.Join(input.To, ",")
- input.DestCc = strings.Join(input.Cc, ",")
- input.DestBcc = strings.Join(input.Bcc, ",")
- if len(input.Dest) > maxEmailDestCount {
- return input, errors.Wrap(httperrors.ErrInputParameter, "too many tos")
- }
- if len(input.DestCc) > maxEmailDestCount {
- return input, errors.Wrap(httperrors.ErrInputParameter, "too many ccs")
- }
- if len(input.DestBcc) > maxEmailDestCount {
- return input, errors.Wrap(httperrors.ErrInputParameter, "too many bccs")
- }
- msg := api.SEmailMessage{
- Body: input.Body,
- Attachments: input.Attachments,
- }
- input.Content = jsonutils.Marshal(msg)
- input.Project = userCred.GetProjectName()
- input.ProjectId = userCred.GetProjectId()
- input.ProjectDomain = userCred.GetProjectDomain()
- input.ProjectDomainId = userCred.GetProjectDomainId()
- input.User = userCred.GetUserName()
- input.UserId = userCred.GetUserId()
- input.Domain = userCred.GetDomainName()
- input.DomainId = userCred.GetDomainId()
- input.Roles = strings.Join(userCred.GetRoles(), ",")
- return input, nil
- }
- func (eq *SEmailQueue) PostCreate(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- ownerId mcclient.IIdentityProvider,
- query jsonutils.JSONObject,
- data jsonutils.JSONObject,
- ) {
- eq.SLogBase.PostCreate(ctx, userCred, ownerId, query, data)
- eq.setStatus(ctx, api.EmailQueued, nil)
- eq.doSendAsync()
- }
- func (eq *SEmailQueue) doSendAsync() {
- Worker.Run(eq, nil, nil)
- }
- func (eq *SEmailQueue) Dump() string {
- return fmt.Sprintf("send email %s", eq.Subject)
- }
- func (eq *SEmailQueue) Run() {
- log.Debugf("send email")
- eq.doSend(context.TODO())
- }
- func (eq *SEmailQueue) doSend(ctx context.Context) {
- msg, err := eq.getMessage()
- if err != nil {
- eq.setStatus(ctx, api.EmailFail, err)
- return
- }
- eq.setStatus(ctx, api.EmailSending, nil)
- driver := GetDriver(api.EMAIL)
- err = driver.Send(ctx, api.SendParams{
- EmailMsg: *msg,
- })
- if err != nil {
- eq.setStatus(ctx, api.EmailFail, err)
- return
- }
- eq.setStatus(ctx, api.EmailSuccess, nil)
- }
- func (eq *SEmailQueue) getMessage() (*api.SEmailMessage, error) {
- msg := api.SEmailMessage{}
- err := eq.Content.Unmarshal(&msg)
- if err != nil {
- return nil, errors.Wrap(err, "Unmarshal")
- }
- msg.To = strings.Split(eq.Dest, ",")
- msg.Cc = strings.Split(eq.DestCc, ",")
- msg.Bcc = strings.Split(eq.DestBcc, ",")
- msg.Subject = eq.Subject
- return &msg, nil
- }
- func (eq *SEmailQueue) setStatus(ctx context.Context, status string, results error) {
- eqs := SEmailQueueStatus{
- Id: eq.Id,
- Status: status,
- }
- if results != nil {
- eqs.Results = results.Error()
- }
- if status == api.EmailSuccess || status == api.EmailFail {
- eqs.SentAt = time.Now()
- }
- EmailQueueStatusManager.TableSpec().InsertOrUpdate(ctx, &eqs)
- }
- // 宿主机/物理机列表
- func (manager *SEmailQueueManager) ListItemFilter(
- ctx context.Context,
- q *sqlchemy.SQuery,
- userCred mcclient.TokenCredential,
- query api.EmailQueueListInput,
- ) (*sqlchemy.SQuery, error) {
- var err error
- q, err = manager.SLogBaseManager.ListItemFilter(ctx, q, userCred, query.LogBaseListInput)
- if err != nil {
- return q, errors.Wrap(err, "SLogBaseManager.ListItemFilter")
- }
- if len(query.To) > 0 {
- cond := make([]sqlchemy.ICondition, 0)
- for _, to := range query.To {
- cond = append(cond, sqlchemy.Contains(q.Field("dest"), to))
- }
- q = q.Filter(sqlchemy.OR(cond...))
- }
- if len(query.Subject) > 0 {
- q = q.Contains("subject", query.Subject)
- }
- if len(query.SessionId) > 0 {
- q = q.In("session_id", query.SessionId)
- }
- return q, nil
- }
- func (eq *SEmailQueue) PerformSend(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- input api.EmailQueueSendInput,
- ) (jsonutils.JSONObject, error) {
- eq.setStatus(ctx, api.EmailQueued, nil)
- if input.Sync {
- log.Debugf("send email synchronously")
- eq.doSend(ctx)
- } else {
- log.Debugf("send email Asynchronously")
- eq.doSendAsync()
- }
- return nil, nil
- }
- func (manager *SEmailQueueManager) FetchCustomizeColumns(
- ctx context.Context,
- userCred mcclient.TokenCredential,
- query jsonutils.JSONObject,
- objs []interface{},
- fields stringutils2.SSortedStrings,
- isList bool,
- ) []api.EmailQueueDetails {
- rows := make([]api.EmailQueueDetails, len(objs))
- baseRows := manager.SModelBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
- emailIds := make([]int64, len(objs))
- for i := range rows {
- rows[i] = api.EmailQueueDetails{
- ModelBaseDetails: baseRows[i],
- }
- eq := objs[i].(*SEmailQueue)
- emailIds[i] = eq.Id
- }
- rets, err := EmailQueueStatusManager.fetchEmailQueueStatus(emailIds)
- if err != nil {
- log.Errorf("EmailQueueStatusManager.fetchEmailQueueStatus fail %s", err)
- return rows
- }
- for i := range rows {
- eq := objs[i].(*SEmailQueue)
- if eqs, ok := rets[eq.Id]; ok {
- rows[i].Status = eqs.Status
- rows[i].SentAt = eqs.SentAt
- rows[i].Results = eqs.Results
- }
- }
- return rows
- }
|