jz.bm.chat.max_upload_bytes is now handed to golem15.chat as the total size of one message's attachments, so the server enforces the limit the bootstrap advertises.
141 lines
4.7 KiB
Go
141 lines
4.7 KiB
Go
package bm
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"errors"
|
|
|
|
chatclasses "git.golem15.com/golem15/sm-chat-plugin/classes"
|
|
chatcontracts "git.golem15.com/golem15/sm-chat-plugin/contracts"
|
|
chanclasses "git.golem15.com/golem15/sm-chatchannels-plugin/classes"
|
|
"git.golem15.com/golem15/summercms/modules/backpack"
|
|
"git.golem15.com/golem15/summercms/modules/lagoon"
|
|
"git.golem15.com/jakub/sm-bm-plugin/classes"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// The chat config keys and their fallbacks (config/config.yaml).
|
|
const (
|
|
configChatGroup = "jz.bm.chat.group"
|
|
configChatModeratorGroup = "jz.bm.chat.moderator_group"
|
|
configChatMaxUpload = "jz.bm.chat.max_upload_bytes"
|
|
configChatMaxEmbeds = "jz.bm.chat.max_embeds"
|
|
|
|
defaultChatGroup = "studenci"
|
|
defaultChatModeratorGroup = "moderatorzy"
|
|
defaultChatMaxUpload = 62914560
|
|
defaultChatMaxEmbeds = 3
|
|
)
|
|
|
|
// registerChat makes jz.bm the host of the BM chat: it registers the bm
|
|
// context alias on golem15.chat's registry and installs the channel access
|
|
// policy. Without golem15.chat it does nothing, so jz.bm keeps working (and
|
|
// its tests keep activating) without the chat plugins; jz.bm does not
|
|
// Require them.
|
|
func (p *Plugin) registerChat(app *backpack.App) error {
|
|
if app == nil || !app.HasPlugin("golem15.chat") {
|
|
return nil
|
|
}
|
|
reg, ok := app.Lookup[*chatcontracts.Registry]()
|
|
if !ok || reg == nil {
|
|
return errors.New("jz.bm: golem15.chat must be listed before jz.bm in summer.yaml")
|
|
}
|
|
if err := reg.Add(p.ID(), chatcontracts.Registration{Alias: classes.ChatContextType, Loader: p.loadChatContext}); err != nil {
|
|
return err
|
|
}
|
|
if err := p.installChatLimits(app); err != nil {
|
|
return err
|
|
}
|
|
return p.installChatAccess(app)
|
|
}
|
|
|
|
// installChatLimits makes golem15.chat enforce jz.bm.chat.max_upload_bytes
|
|
// as the total size of one message's attachments, the value the bootstrap
|
|
// advertises to the student app. golem15.chat publishes its service from
|
|
// its own database hook, which runs before this one.
|
|
func (p *Plugin) installChatLimits(app *backpack.App) error {
|
|
return lagoon.OnDatabase(app, func(_ *sql.DB, _ *gorm.DB) error {
|
|
svc, ok := app.Lookup[*chatclasses.Service]()
|
|
if !ok || svc == nil {
|
|
return errors.New("jz.bm: golem15.chat must be listed before jz.bm in summer.yaml")
|
|
}
|
|
svc.SetMaxMessageBytes(int64(p.chatMaxUploadBytes()))
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// loadChatContext is the loader of the bm alias. The only context is id 1;
|
|
// any other id is unknown, which golem15.chat answers with its not-a-member
|
|
// error.
|
|
func (p *Plugin) loadChatContext(ctx context.Context, db *gorm.DB, id uint) (chatcontracts.Context, error) {
|
|
return classes.ChatContextLoader(p.chatGroup, p.chatModeratorGroup)(ctx, db, id)
|
|
}
|
|
|
|
// installChatAccess installs BM's access policy on golem15.chatchannels'
|
|
// channel service. The service is published from chatchannels' own
|
|
// database hook, which runs before this one because chatchannels boots
|
|
// first; under a database-less boot (tests, route:list) neither runs.
|
|
func (p *Plugin) installChatAccess(app *backpack.App) error {
|
|
if app == nil || !app.HasPlugin("golem15.chatchannels") {
|
|
return nil
|
|
}
|
|
return lagoon.OnDatabase(app, func(_ *sql.DB, _ *gorm.DB) error {
|
|
svc, ok := app.Lookup[*chanclasses.ChannelService]()
|
|
if !ok || svc == nil {
|
|
return errors.New("jz.bm: golem15.chatchannels must be listed before jz.bm in summer.yaml")
|
|
}
|
|
svc.SetAccessResolver(classes.NewChatAccess(p.database, p.chatGroup(), nil))
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// database returns the published application database, or nil.
|
|
func (p *Plugin) database() *gorm.DB {
|
|
if p.app == nil {
|
|
return nil
|
|
}
|
|
db, _ := p.app.Lookup[*gorm.DB]()
|
|
return db
|
|
}
|
|
|
|
// chatGroup is the code of the user group whose members are in the chat.
|
|
func (p *Plugin) chatGroup() string {
|
|
return p.configString(configChatGroup, defaultChatGroup)
|
|
}
|
|
|
|
// chatModeratorGroup is the code of the user group whose members moderate
|
|
// the chat's channels.
|
|
func (p *Plugin) chatModeratorGroup() string {
|
|
return p.configString(configChatModeratorGroup, defaultChatModeratorGroup)
|
|
}
|
|
|
|
// chatMaxUploadBytes is the total attachment size of one message.
|
|
func (p *Plugin) chatMaxUploadBytes() int {
|
|
return p.configInt(configChatMaxUpload, defaultChatMaxUpload)
|
|
}
|
|
|
|
// chatMaxEmbeds is the number of entity embeds one message may carry.
|
|
func (p *Plugin) chatMaxEmbeds() int {
|
|
return p.configInt(configChatMaxEmbeds, defaultChatMaxEmbeds)
|
|
}
|
|
|
|
func (p *Plugin) configString(key, fallback string) string {
|
|
if p.app == nil || p.app.Config == nil {
|
|
return fallback
|
|
}
|
|
if v := p.app.Config.String(key); v != "" {
|
|
return v
|
|
}
|
|
return fallback
|
|
}
|
|
|
|
func (p *Plugin) configInt(key string, fallback int) int {
|
|
if p.app == nil || p.app.Config == nil {
|
|
return fallback
|
|
}
|
|
if v := p.app.Config.Int(key); v > 0 {
|
|
return v
|
|
}
|
|
return fallback
|
|
}
|