TopicsLimit
This commit is contained in:
parent
2267d27c9b
commit
e650f813c5
7 changed files with 43 additions and 14 deletions
|
@ -39,7 +39,7 @@ func (s *Server) handleAccountCreate(w http.ResponseWriter, r *http.Request, v *
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleAccountGet(w http.ResponseWriter, r *http.Request, v *visitor) error {
|
func (s *Server) handleAccountGet(w http.ResponseWriter, _ *http.Request, v *visitor) error {
|
||||||
stats, err := v.Info()
|
stats, err := v.Info()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -50,6 +50,8 @@ func (s *Server) handleAccountGet(w http.ResponseWriter, r *http.Request, v *vis
|
||||||
MessagesRemaining: stats.MessagesRemaining,
|
MessagesRemaining: stats.MessagesRemaining,
|
||||||
Emails: stats.Emails,
|
Emails: stats.Emails,
|
||||||
EmailsRemaining: stats.EmailsRemaining,
|
EmailsRemaining: stats.EmailsRemaining,
|
||||||
|
Topics: stats.Topics,
|
||||||
|
TopicsRemaining: stats.TopicsRemaining,
|
||||||
AttachmentTotalSize: stats.AttachmentTotalSize,
|
AttachmentTotalSize: stats.AttachmentTotalSize,
|
||||||
AttachmentTotalSizeRemaining: stats.AttachmentTotalSizeRemaining,
|
AttachmentTotalSizeRemaining: stats.AttachmentTotalSizeRemaining,
|
||||||
},
|
},
|
||||||
|
@ -57,6 +59,7 @@ func (s *Server) handleAccountGet(w http.ResponseWriter, r *http.Request, v *vis
|
||||||
Basis: stats.Basis,
|
Basis: stats.Basis,
|
||||||
Messages: stats.MessagesLimit,
|
Messages: stats.MessagesLimit,
|
||||||
Emails: stats.EmailsLimit,
|
Emails: stats.EmailsLimit,
|
||||||
|
Topics: stats.TopicsLimit,
|
||||||
AttachmentTotalSize: stats.AttachmentTotalSizeLimit,
|
AttachmentTotalSize: stats.AttachmentTotalSizeLimit,
|
||||||
AttachmentFileSize: stats.AttachmentFileSizeLimit,
|
AttachmentFileSize: stats.AttachmentFileSizeLimit,
|
||||||
},
|
},
|
||||||
|
@ -119,7 +122,7 @@ func (s *Server) handleAccountGet(w http.ResponseWriter, r *http.Request, v *vis
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleAccountDelete(w http.ResponseWriter, r *http.Request, v *visitor) error {
|
func (s *Server) handleAccountDelete(w http.ResponseWriter, _ *http.Request, v *visitor) error {
|
||||||
if err := s.userManager.RemoveUser(v.user.Name); err != nil {
|
if err := s.userManager.RemoveUser(v.user.Name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -141,7 +144,7 @@ func (s *Server) handleAccountPasswordChange(w http.ResponseWriter, r *http.Requ
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleAccountTokenIssue(w http.ResponseWriter, r *http.Request, v *visitor) error {
|
func (s *Server) handleAccountTokenIssue(w http.ResponseWriter, _ *http.Request, v *visitor) error {
|
||||||
// TODO rate limit
|
// TODO rate limit
|
||||||
token, err := s.userManager.CreateToken(v.user)
|
token, err := s.userManager.CreateToken(v.user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -159,7 +162,7 @@ func (s *Server) handleAccountTokenIssue(w http.ResponseWriter, r *http.Request,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleAccountTokenExtend(w http.ResponseWriter, r *http.Request, v *visitor) error {
|
func (s *Server) handleAccountTokenExtend(w http.ResponseWriter, _ *http.Request, v *visitor) error {
|
||||||
// TODO rate limit
|
// TODO rate limit
|
||||||
if v.user == nil {
|
if v.user == nil {
|
||||||
return errHTTPUnauthorized
|
return errHTTPUnauthorized
|
||||||
|
@ -182,7 +185,7 @@ func (s *Server) handleAccountTokenExtend(w http.ResponseWriter, r *http.Request
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleAccountTokenDelete(w http.ResponseWriter, r *http.Request, v *visitor) error {
|
func (s *Server) handleAccountTokenDelete(w http.ResponseWriter, _ *http.Request, v *visitor) error {
|
||||||
// TODO rate limit
|
// TODO rate limit
|
||||||
if v.user.Token == "" {
|
if v.user.Token == "" {
|
||||||
return errHTTPBadRequestNoTokenProvided
|
return errHTTPBadRequestNoTokenProvided
|
||||||
|
|
|
@ -243,6 +243,7 @@ type apiAccountLimits struct {
|
||||||
Basis string `json:"basis"` // "ip", "role" or "plan"
|
Basis string `json:"basis"` // "ip", "role" or "plan"
|
||||||
Messages int64 `json:"messages"`
|
Messages int64 `json:"messages"`
|
||||||
Emails int64 `json:"emails"`
|
Emails int64 `json:"emails"`
|
||||||
|
Topics int64 `json:"topics"`
|
||||||
AttachmentTotalSize int64 `json:"attachment_total_size"`
|
AttachmentTotalSize int64 `json:"attachment_total_size"`
|
||||||
AttachmentFileSize int64 `json:"attachment_file_size"`
|
AttachmentFileSize int64 `json:"attachment_file_size"`
|
||||||
}
|
}
|
||||||
|
@ -252,6 +253,8 @@ type apiAccountStats struct {
|
||||||
MessagesRemaining int64 `json:"messages_remaining"`
|
MessagesRemaining int64 `json:"messages_remaining"`
|
||||||
Emails int64 `json:"emails"`
|
Emails int64 `json:"emails"`
|
||||||
EmailsRemaining int64 `json:"emails_remaining"`
|
EmailsRemaining int64 `json:"emails_remaining"`
|
||||||
|
Topics int64 `json:"topics"`
|
||||||
|
TopicsRemaining int64 `json:"topics_remaining"`
|
||||||
AttachmentTotalSize int64 `json:"attachment_total_size"`
|
AttachmentTotalSize int64 `json:"attachment_total_size"`
|
||||||
AttachmentTotalSizeRemaining int64 `json:"attachment_total_size_remaining"`
|
AttachmentTotalSizeRemaining int64 `json:"attachment_total_size_remaining"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,9 @@ type visitorInfo struct {
|
||||||
Emails int64
|
Emails int64
|
||||||
EmailsLimit int64
|
EmailsLimit int64
|
||||||
EmailsRemaining int64
|
EmailsRemaining int64
|
||||||
|
Topics int64
|
||||||
|
TopicsLimit int64
|
||||||
|
TopicsRemaining int64
|
||||||
AttachmentTotalSize int64
|
AttachmentTotalSize int64
|
||||||
AttachmentTotalSizeLimit int64
|
AttachmentTotalSizeLimit int64
|
||||||
AttachmentTotalSizeRemaining int64
|
AttachmentTotalSizeRemaining int64
|
||||||
|
@ -173,20 +176,19 @@ func (v *visitor) Info() (*visitorInfo, error) {
|
||||||
info := &visitorInfo{}
|
info := &visitorInfo{}
|
||||||
if v.user != nil && v.user.Role == user.RoleAdmin {
|
if v.user != nil && v.user.Role == user.RoleAdmin {
|
||||||
info.Basis = "role"
|
info.Basis = "role"
|
||||||
info.MessagesLimit = 0
|
// All limits are zero!
|
||||||
info.EmailsLimit = 0
|
|
||||||
info.AttachmentTotalSizeLimit = 0
|
|
||||||
info.AttachmentFileSizeLimit = 0
|
|
||||||
} else if v.user != nil && v.user.Plan != nil {
|
} else if v.user != nil && v.user.Plan != nil {
|
||||||
info.Basis = "plan"
|
info.Basis = "plan"
|
||||||
info.MessagesLimit = v.user.Plan.MessagesLimit
|
info.MessagesLimit = v.user.Plan.MessagesLimit
|
||||||
info.EmailsLimit = v.user.Plan.EmailsLimit
|
info.EmailsLimit = v.user.Plan.EmailsLimit
|
||||||
|
info.TopicsLimit = v.user.Plan.TopicsLimit
|
||||||
info.AttachmentTotalSizeLimit = v.user.Plan.AttachmentTotalSizeLimit
|
info.AttachmentTotalSizeLimit = v.user.Plan.AttachmentTotalSizeLimit
|
||||||
info.AttachmentFileSizeLimit = v.user.Plan.AttachmentFileSizeLimit
|
info.AttachmentFileSizeLimit = v.user.Plan.AttachmentFileSizeLimit
|
||||||
} else {
|
} else {
|
||||||
info.Basis = "ip"
|
info.Basis = "ip"
|
||||||
info.MessagesLimit = replenishDurationToDailyLimit(v.config.VisitorRequestLimitReplenish)
|
info.MessagesLimit = replenishDurationToDailyLimit(v.config.VisitorRequestLimitReplenish)
|
||||||
info.EmailsLimit = replenishDurationToDailyLimit(v.config.VisitorEmailLimitReplenish)
|
info.EmailsLimit = replenishDurationToDailyLimit(v.config.VisitorEmailLimitReplenish)
|
||||||
|
info.TopicsLimit = 0 // FIXME
|
||||||
info.AttachmentTotalSizeLimit = v.config.VisitorAttachmentTotalSizeLimit
|
info.AttachmentTotalSizeLimit = v.config.VisitorAttachmentTotalSizeLimit
|
||||||
info.AttachmentFileSizeLimit = v.config.AttachmentFileSizeLimit
|
info.AttachmentFileSizeLimit = v.config.AttachmentFileSizeLimit
|
||||||
}
|
}
|
||||||
|
@ -200,10 +202,20 @@ func (v *visitor) Info() (*visitorInfo, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
var topics int64
|
||||||
|
if v.user != nil {
|
||||||
|
for _, grant := range v.user.Grants {
|
||||||
|
if grant.Owner {
|
||||||
|
topics++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
info.Messages = messages
|
info.Messages = messages
|
||||||
info.MessagesRemaining = zeroIfNegative(info.MessagesLimit - info.Messages)
|
info.MessagesRemaining = zeroIfNegative(info.MessagesLimit - info.Messages)
|
||||||
info.Emails = emails
|
info.Emails = emails
|
||||||
info.EmailsRemaining = zeroIfNegative(info.EmailsLimit - info.Emails)
|
info.EmailsRemaining = zeroIfNegative(info.EmailsLimit - info.Emails)
|
||||||
|
info.Topics = topics
|
||||||
|
info.TopicsRemaining = zeroIfNegative(info.TopicsLimit - info.Topics)
|
||||||
info.AttachmentTotalSize = attachmentsBytesUsed
|
info.AttachmentTotalSize = attachmentsBytesUsed
|
||||||
info.AttachmentTotalSizeRemaining = zeroIfNegative(info.AttachmentTotalSizeLimit - info.AttachmentTotalSize)
|
info.AttachmentTotalSizeRemaining = zeroIfNegative(info.AttachmentTotalSizeLimit - info.AttachmentTotalSize)
|
||||||
return info, nil
|
return info, nil
|
||||||
|
|
|
@ -35,6 +35,7 @@ const (
|
||||||
code TEXT NOT NULL,
|
code TEXT NOT NULL,
|
||||||
messages_limit INT NOT NULL,
|
messages_limit INT NOT NULL,
|
||||||
emails_limit INT NOT NULL,
|
emails_limit INT NOT NULL,
|
||||||
|
topics_limit INT NOT NULL,
|
||||||
attachment_file_size_limit INT NOT NULL,
|
attachment_file_size_limit INT NOT NULL,
|
||||||
attachment_total_size_limit INT NOT NULL,
|
attachment_total_size_limit INT NOT NULL,
|
||||||
PRIMARY KEY (id)
|
PRIMARY KEY (id)
|
||||||
|
@ -75,13 +76,13 @@ const (
|
||||||
`
|
`
|
||||||
createTablesQueries = `BEGIN; ` + createTablesQueriesNoTx + ` COMMIT;`
|
createTablesQueries = `BEGIN; ` + createTablesQueriesNoTx + ` COMMIT;`
|
||||||
selectUserByNameQuery = `
|
selectUserByNameQuery = `
|
||||||
SELECT u.user, u.pass, u.role, u.messages, u.emails, u.settings, p.code, p.messages_limit, p.emails_limit, p.attachment_file_size_limit, p.attachment_total_size_limit
|
SELECT u.user, u.pass, u.role, u.messages, u.emails, u.settings, p.code, p.messages_limit, p.emails_limit, p.topics_limit, p.attachment_file_size_limit, p.attachment_total_size_limit
|
||||||
FROM user u
|
FROM user u
|
||||||
LEFT JOIN plan p on p.id = u.plan_id
|
LEFT JOIN plan p on p.id = u.plan_id
|
||||||
WHERE user = ?
|
WHERE user = ?
|
||||||
`
|
`
|
||||||
selectUserByTokenQuery = `
|
selectUserByTokenQuery = `
|
||||||
SELECT u.user, u.pass, u.role, u.messages, u.emails, u.settings, p.code, p.messages_limit, p.emails_limit, p.attachment_file_size_limit, p.attachment_total_size_limit
|
SELECT u.user, u.pass, u.role, u.messages, u.emails, u.settings, p.code, p.messages_limit, p.emails_limit, p.topics_limit, p.attachment_file_size_limit, p.attachment_total_size_limit
|
||||||
FROM user u
|
FROM user u
|
||||||
JOIN user_token t on u.id = t.user_id
|
JOIN user_token t on u.id = t.user_id
|
||||||
LEFT JOIN plan p on p.id = u.plan_id
|
LEFT JOIN plan p on p.id = u.plan_id
|
||||||
|
@ -469,11 +470,11 @@ func (a *Manager) readUser(rows *sql.Rows) (*User, error) {
|
||||||
var username, hash, role string
|
var username, hash, role string
|
||||||
var settings, planCode sql.NullString
|
var settings, planCode sql.NullString
|
||||||
var messages, emails int64
|
var messages, emails int64
|
||||||
var messagesLimit, emailsLimit, attachmentFileSizeLimit, attachmentTotalSizeLimit sql.NullInt64
|
var messagesLimit, emailsLimit, topicsLimit, attachmentFileSizeLimit, attachmentTotalSizeLimit sql.NullInt64
|
||||||
if !rows.Next() {
|
if !rows.Next() {
|
||||||
return nil, ErrNotFound
|
return nil, ErrNotFound
|
||||||
}
|
}
|
||||||
if err := rows.Scan(&username, &hash, &role, &messages, &emails, &settings, &planCode, &messagesLimit, &emailsLimit, &attachmentFileSizeLimit, &attachmentTotalSizeLimit); err != nil {
|
if err := rows.Scan(&username, &hash, &role, &messages, &emails, &settings, &planCode, &messagesLimit, &emailsLimit, &topicsLimit, &attachmentFileSizeLimit, &attachmentTotalSizeLimit); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if err := rows.Err(); err != nil {
|
} else if err := rows.Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -504,6 +505,7 @@ func (a *Manager) readUser(rows *sql.Rows) (*User, error) {
|
||||||
Upgradable: true, // FIXME
|
Upgradable: true, // FIXME
|
||||||
MessagesLimit: messagesLimit.Int64,
|
MessagesLimit: messagesLimit.Int64,
|
||||||
EmailsLimit: emailsLimit.Int64,
|
EmailsLimit: emailsLimit.Int64,
|
||||||
|
TopicsLimit: topicsLimit.Int64,
|
||||||
AttachmentFileSizeLimit: attachmentFileSizeLimit.Int64,
|
AttachmentFileSizeLimit: attachmentFileSizeLimit.Int64,
|
||||||
AttachmentTotalSizeLimit: attachmentTotalSizeLimit.Int64,
|
AttachmentTotalSizeLimit: attachmentTotalSizeLimit.Int64,
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ type Plan struct {
|
||||||
Upgradable bool `json:"upgradable"`
|
Upgradable bool `json:"upgradable"`
|
||||||
MessagesLimit int64 `json:"messages_limit"`
|
MessagesLimit int64 `json:"messages_limit"`
|
||||||
EmailsLimit int64 `json:"emails_limit"`
|
EmailsLimit int64 `json:"emails_limit"`
|
||||||
|
TopicsLimit int64 `json:"topics_limit"`
|
||||||
AttachmentFileSizeLimit int64 `json:"attachment_file_size_limit"`
|
AttachmentFileSizeLimit int64 `json:"attachment_file_size_limit"`
|
||||||
AttachmentTotalSizeLimit int64 `json:"attachment_total_size_limit"`
|
AttachmentTotalSizeLimit int64 `json:"attachment_total_size_limit"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,6 +183,7 @@
|
||||||
"account_usage_plan_code_business_plus": "Business Plus",
|
"account_usage_plan_code_business_plus": "Business Plus",
|
||||||
"account_usage_messages_title": "Published messages",
|
"account_usage_messages_title": "Published messages",
|
||||||
"account_usage_emails_title": "Emails sent",
|
"account_usage_emails_title": "Emails sent",
|
||||||
|
"account_usage_topics_title": "Topics reserved",
|
||||||
"account_usage_attachment_storage_title": "Attachment storage",
|
"account_usage_attachment_storage_title": "Attachment storage",
|
||||||
"account_usage_attachment_storage_subtitle": "{{filesize}} per file",
|
"account_usage_attachment_storage_subtitle": "{{filesize}} per file",
|
||||||
"account_usage_basis_ip_description": "Usage stats and limits for this account are based on your IP address, so they may be shared with other users.",
|
"account_usage_basis_ip_description": "Usage stats and limits for this account are based on your IP address, so they may be shared with other users.",
|
||||||
|
|
|
@ -168,7 +168,7 @@ const Stats = () => {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
const planCode = account.plan.code ?? "none";
|
const planCode = account.plan.code ?? "none";
|
||||||
const normalize = (value, max) => (value / max * 100);
|
const normalize = (value, max) => Math.min(value / max * 100, 100);
|
||||||
return (
|
return (
|
||||||
<Card sx={{p: 3}} aria-label={t("account_usage_title")}>
|
<Card sx={{p: 3}} aria-label={t("account_usage_title")}>
|
||||||
<Typography variant="h5" sx={{marginBottom: 2}}>
|
<Typography variant="h5" sx={{marginBottom: 2}}>
|
||||||
|
@ -182,6 +182,13 @@ const Stats = () => {
|
||||||
: t(`account_usage_plan_code_${planCode}`)}
|
: t(`account_usage_plan_code_${planCode}`)}
|
||||||
</div>
|
</div>
|
||||||
</Pref>
|
</Pref>
|
||||||
|
<Pref title={t("account_usage_topics_title")}>
|
||||||
|
<div>
|
||||||
|
<Typography variant="body2" sx={{float: "left"}}>{account.stats.topics}</Typography>
|
||||||
|
<Typography variant="body2" sx={{float: "right"}}>{account.limits.topics > 0 ? t("account_usage_of_limit", { limit: account.limits.topics }) : t("account_usage_unlimited")}</Typography>
|
||||||
|
</div>
|
||||||
|
<LinearProgress variant="determinate" value={account.limits.topics > 0 ? normalize(account.stats.topics, account.limits.topics) : 100} />
|
||||||
|
</Pref>
|
||||||
<Pref title={t("account_usage_messages_title")}>
|
<Pref title={t("account_usage_messages_title")}>
|
||||||
<div>
|
<div>
|
||||||
<Typography variant="body2" sx={{float: "left"}}>{account.stats.messages}</Typography>
|
<Typography variant="body2" sx={{float: "left"}}>{account.stats.messages}</Typography>
|
||||||
|
|
Loading…
Reference in a new issue