// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. package sqlstore import ( "database/sql" "fmt" sq "github.com/mattermost/squirrel" "github.com/pkg/errors" "github.com/mattermost/mattermost/server/public/model" "github.com/mattermost/mattermost/server/v8/channels/store" ) type SqlCommandStore struct { *SqlStore commandColumns []string commandsQuery sq.SelectBuilder } func newSqlCommandStore(sqlStore *SqlStore) store.CommandStore { s := &SqlCommandStore{SqlStore: sqlStore} s.commandColumns = []string{ "Id", "Token", "CreateAt", "UpdateAt", "DeleteAt", "CreatorId", "TeamId", s.toReserveCase("trigger"), "Method", "Username", "IconURL", "AutoComplete", "AutoCompleteDesc", "AutoCompleteHint", "DisplayName", "Description", "URL", "PluginId", } s.commandsQuery = s.getQueryBuilder(). Select(s.commandColumns...). From("Commands") return s } func (s SqlCommandStore) Save(command *model.Command) (*model.Command, error) { if command.Id != "" { return nil, store.NewErrInvalidInput("Command", "CommandId", command.Id) } command.PreSave() if err := command.IsValid(); err != nil { return nil, err } insertQuery := s.getQueryBuilder(). Insert("Commands"). Columns(s.commandColumns...). Values( command.Id, command.Token, command.CreateAt, command.UpdateAt, command.DeleteAt, command.CreatorId, command.TeamId, command.Trigger, command.Method, command.Username, command.IconURL, command.AutoComplete, command.AutoCompleteDesc, command.AutoCompleteHint, command.DisplayName, command.Description, command.URL, command.PluginId, ) if _, err := s.GetMaster().ExecBuilder(insertQuery); err != nil { return nil, errors.Wrapf(err, "insert: command_id=%s", command.Id) } return command, nil } func (s SqlCommandStore) Get(id string) (*model.Command, error) { var command model.Command query, args, err := s.commandsQuery. Where(sq.Eq{"Id": id, "DeleteAt": 0}).ToSql() if err != nil { return nil, errors.Wrapf(err, "commands_tosql") } if err = s.GetReplica().Get(&command, query, args...); err == sql.ErrNoRows { return nil, store.NewErrNotFound("Command", id) } else if err != nil { return nil, errors.Wrapf(err, "selectone: command_id=%s", id) } return &command, nil } func (s SqlCommandStore) GetByTeam(teamId string) ([]*model.Command, error) { commands := []*model.Command{} sql, args, err := s.commandsQuery. Where(sq.Eq{"TeamId": teamId, "DeleteAt": 0}).ToSql() if err != nil { return nil, errors.Wrapf(err, "commands_tosql") } if err := s.GetReplica().Select(&commands, sql, args...); err != nil { return nil, errors.Wrapf(err, "select: team_id=%s", teamId) } return commands, nil } func (s SqlCommandStore) GetByTrigger(teamId string, trigger string) (*model.Command, error) { var command model.Command query, args, err := s.commandsQuery. Where(sq.Eq{"TeamId": teamId, "DeleteAt": 0, "\"trigger\"": trigger}).ToSql() if err != nil { return nil, errors.Wrapf(err, "commands_tosql") } if err := s.GetReplica().Get(&command, query, args...); err == sql.ErrNoRows { errorId := "teamId=" + teamId + ", trigger=" + trigger return nil, store.NewErrNotFound("Command", errorId) } else if err != nil { return nil, errors.Wrapf(err, "selectone: team_id=%s, trigger=%s", teamId, trigger) } return &command, nil } func (s SqlCommandStore) Delete(commandId string, time int64) error { sql, args, err := s.getQueryBuilder(). Update("Commands"). SetMap(sq.Eq{"DeleteAt": time, "UpdateAt": time}). Where(sq.Eq{"Id": commandId}).ToSql() if err != nil { return errors.Wrapf(err, "commands_tosql") } _, err = s.GetMaster().Exec(sql, args...) if err != nil { errors.Wrapf(err, "delete: command_id=%s", commandId) } return nil } func (s SqlCommandStore) PermanentDeleteByTeam(teamId string) error { sql, args, err := s.getQueryBuilder(). Delete("Commands"). Where(sq.Eq{"TeamId": teamId}).ToSql() if err != nil { return errors.Wrapf(err, "commands_tosql") } _, err = s.GetMaster().Exec(sql, args...) if err != nil { return errors.Wrapf(err, "delete: team_id=%s", teamId) } return nil } func (s SqlCommandStore) PermanentDeleteByUser(userId string) error { sql, args, err := s.getQueryBuilder(). Delete("Commands"). Where(sq.Eq{"CreatorId": userId}).ToSql() if err != nil { return errors.Wrapf(err, "commands_tosql") } _, err = s.GetMaster().Exec(sql, args...) if err != nil { return errors.Wrapf(err, "delete: user_id=%s", userId) } return nil } func (s SqlCommandStore) Update(cmd *model.Command) (*model.Command, error) { cmd.UpdateAt = model.GetMillis() if err := cmd.IsValid(); err != nil { return nil, err } query := s.getQueryBuilder(). Update("Commands"). Set("Token", cmd.Token). Set("CreateAt", cmd.CreateAt). Set("UpdateAt", cmd.UpdateAt). Set("CreatorId", cmd.CreatorId). Set("TeamId", cmd.TeamId). Set("Method", cmd.Method). Set("Username", cmd.Username). Set("IconURL", cmd.IconURL). Set("AutoComplete", cmd.AutoComplete). Set("AutoCompleteDesc", cmd.AutoCompleteDesc). Set("AutoCompleteHint", cmd.AutoCompleteHint). Set("DisplayName", cmd.DisplayName). Set("Description", cmd.Description). Set("URL", cmd.URL). Set("PluginId", cmd.PluginId). Where(sq.Eq{"Id": cmd.Id}) // Trigger is a keyword query = query.Set(s.toReserveCase("trigger"), cmd.Trigger) queryString, args, err := query.ToSql() if err != nil { return nil, errors.Wrap(err, "commands_tosql") } res, err := s.GetMaster().Exec(queryString, args...) if err != nil { return nil, errors.Wrap(err, "failed to update commands") } count, err := res.RowsAffected() if err != nil { return nil, errors.Wrap(err, "error while getting rows_affected") } if count > 1 { return nil, fmt.Errorf("unexpected count while updating commands: count=%d, Id=%s", count, cmd.Id) } return cmd, nil } func (s SqlCommandStore) AnalyticsCommandCount(teamId string) (int64, error) { query := s.getQueryBuilder(). Select("COUNT(*)"). From("Commands"). Where(sq.Eq{"DeleteAt": 0}) if teamId != "" { query = query.Where(sq.Eq{"TeamId": teamId}) } sql, args, err := query.ToSql() if err != nil { return 0, errors.Wrapf(err, "commands_tosql") } var c int64 err = s.GetReplica().Get(&c, sql, args...) if err != nil { return 0, errors.Wrapf(err, "unable to count the commands: team_id=%s", teamId) } return c, nil }