1// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
2// See LICENSE.txt for license information.
3
4package sqlstore
5
6import (
7	"database/sql"
8
9	sq "github.com/Masterminds/squirrel"
10	"github.com/pkg/errors"
11
12	"github.com/mattermost/mattermost-server/v6/model"
13	"github.com/mattermost/mattermost-server/v6/store"
14)
15
16type SqlCommandStore struct {
17	*SqlStore
18
19	commandsQuery sq.SelectBuilder
20}
21
22func newSqlCommandStore(sqlStore *SqlStore) store.CommandStore {
23	s := &SqlCommandStore{SqlStore: sqlStore}
24
25	s.commandsQuery = s.getQueryBuilder().
26		Select("*").
27		From("Commands")
28	for _, db := range sqlStore.GetAllConns() {
29		tableo := db.AddTableWithName(model.Command{}, "Commands").SetKeys(false, "Id")
30		tableo.ColMap("Id").SetMaxSize(26)
31		tableo.ColMap("Token").SetMaxSize(26)
32		tableo.ColMap("CreatorId").SetMaxSize(26)
33		tableo.ColMap("TeamId").SetMaxSize(26)
34		tableo.ColMap("Trigger").SetMaxSize(128)
35		tableo.ColMap("URL").SetMaxSize(1024)
36		tableo.ColMap("Method").SetMaxSize(1)
37		tableo.ColMap("Username").SetMaxSize(64)
38		tableo.ColMap("IconURL").SetMaxSize(1024)
39		tableo.ColMap("AutoCompleteDesc").SetMaxSize(1024)
40		tableo.ColMap("AutoCompleteHint").SetMaxSize(1024)
41		tableo.ColMap("DisplayName").SetMaxSize(64)
42		tableo.ColMap("Description").SetMaxSize(128)
43		tableo.ColMap("PluginId").SetMaxSize(190)
44	}
45
46	return s
47}
48
49func (s SqlCommandStore) createIndexesIfNotExists() {
50	s.CreateIndexIfNotExists("idx_command_team_id", "Commands", "TeamId")
51	s.CreateIndexIfNotExists("idx_command_update_at", "Commands", "UpdateAt")
52	s.CreateIndexIfNotExists("idx_command_create_at", "Commands", "CreateAt")
53	s.CreateIndexIfNotExists("idx_command_delete_at", "Commands", "DeleteAt")
54}
55
56func (s SqlCommandStore) Save(command *model.Command) (*model.Command, error) {
57	if command.Id != "" {
58		return nil, store.NewErrInvalidInput("Command", "CommandId", command.Id)
59	}
60
61	command.PreSave()
62	if err := command.IsValid(); err != nil {
63		return nil, err
64	}
65
66	if err := s.GetMaster().Insert(command); err != nil {
67		return nil, errors.Wrapf(err, "insert: command_id=%s", command.Id)
68	}
69
70	return command, nil
71}
72
73func (s SqlCommandStore) Get(id string) (*model.Command, error) {
74	var command model.Command
75
76	query, args, err := s.commandsQuery.
77		Where(sq.Eq{"Id": id, "DeleteAt": 0}).ToSql()
78	if err != nil {
79		return nil, errors.Wrapf(err, "commands_tosql")
80	}
81	if err = s.GetReplica().SelectOne(&command, query, args...); err == sql.ErrNoRows {
82		return nil, store.NewErrNotFound("Command", id)
83	} else if err != nil {
84		return nil, errors.Wrapf(err, "selectone: command_id=%s", id)
85	}
86
87	return &command, nil
88}
89
90func (s SqlCommandStore) GetByTeam(teamId string) ([]*model.Command, error) {
91	var commands []*model.Command
92
93	sql, args, err := s.commandsQuery.
94		Where(sq.Eq{"TeamId": teamId, "DeleteAt": 0}).ToSql()
95	if err != nil {
96		return nil, errors.Wrapf(err, "commands_tosql")
97	}
98	if _, err := s.GetReplica().Select(&commands, sql, args...); err != nil {
99		return nil, errors.Wrapf(err, "select: team_id=%s", teamId)
100	}
101
102	return commands, nil
103}
104
105func (s SqlCommandStore) GetByTrigger(teamId string, trigger string) (*model.Command, error) {
106	var command model.Command
107	var triggerStr string
108	if s.DriverName() == "mysql" {
109		triggerStr = "`Trigger`"
110	} else {
111		triggerStr = "\"trigger\""
112	}
113
114	query, args, err := s.commandsQuery.
115		Where(sq.Eq{"TeamId": teamId, "DeleteAt": 0, triggerStr: trigger}).ToSql()
116	if err != nil {
117		return nil, errors.Wrapf(err, "commands_tosql")
118	}
119
120	if err := s.GetReplica().SelectOne(&command, query, args...); err == sql.ErrNoRows {
121		errorId := "teamId=" + teamId + ", trigger=" + trigger
122		return nil, store.NewErrNotFound("Command", errorId)
123	} else if err != nil {
124		return nil, errors.Wrapf(err, "selectone: team_id=%s, trigger=%s", teamId, trigger)
125	}
126
127	return &command, nil
128}
129
130func (s SqlCommandStore) Delete(commandId string, time int64) error {
131	sql, args, err := s.getQueryBuilder().
132		Update("Commands").
133		SetMap(sq.Eq{"DeleteAt": time, "UpdateAt": time}).
134		Where(sq.Eq{"Id": commandId}).ToSql()
135	if err != nil {
136		return errors.Wrapf(err, "commands_tosql")
137	}
138
139	_, err = s.GetMaster().Exec(sql, args...)
140	if err != nil {
141		errors.Wrapf(err, "delete: command_id=%s", commandId)
142	}
143
144	return nil
145}
146
147func (s SqlCommandStore) PermanentDeleteByTeam(teamId string) error {
148	sql, args, err := s.getQueryBuilder().
149		Delete("Commands").
150		Where(sq.Eq{"TeamId": teamId}).ToSql()
151	if err != nil {
152		return errors.Wrapf(err, "commands_tosql")
153	}
154	_, err = s.GetMaster().Exec(sql, args...)
155	if err != nil {
156		return errors.Wrapf(err, "delete: team_id=%s", teamId)
157	}
158	return nil
159}
160
161func (s SqlCommandStore) PermanentDeleteByUser(userId string) error {
162	sql, args, err := s.getQueryBuilder().
163		Delete("Commands").
164		Where(sq.Eq{"CreatorId": userId}).ToSql()
165	if err != nil {
166		return errors.Wrapf(err, "commands_tosql")
167	}
168	_, err = s.GetMaster().Exec(sql, args...)
169	if err != nil {
170		return errors.Wrapf(err, "delete: user_id=%s", userId)
171	}
172
173	return nil
174}
175
176func (s SqlCommandStore) Update(cmd *model.Command) (*model.Command, error) {
177	cmd.UpdateAt = model.GetMillis()
178
179	if err := cmd.IsValid(); err != nil {
180		return nil, err
181	}
182
183	if _, err := s.GetMaster().Update(cmd); err != nil {
184		return nil, errors.Wrapf(err, "update: command_id=%s", cmd.Id)
185	}
186
187	return cmd, nil
188}
189
190func (s SqlCommandStore) AnalyticsCommandCount(teamId string) (int64, error) {
191	query := s.getQueryBuilder().
192		Select("COUNT(*)").
193		From("Commands").
194		Where(sq.Eq{"DeleteAt": 0})
195
196	if teamId != "" {
197		query = query.Where(sq.Eq{"TeamId": teamId})
198	}
199
200	sql, args, err := query.ToSql()
201	if err != nil {
202		return 0, errors.Wrapf(err, "commands_tosql")
203	}
204
205	c, err := s.GetReplica().SelectInt(sql, args...)
206	if err != nil {
207		return 0, errors.Wrapf(err, "unable to count the commands: team_id=%s", teamId)
208	}
209	return c, nil
210}
211