github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/plugin_api.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package app
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/json"
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"net/http"
    13  	"net/url"
    14  	"path/filepath"
    15  	"strings"
    16  
    17  	"github.com/mattermost/mattermost-server/v5/mlog"
    18  	"github.com/mattermost/mattermost-server/v5/model"
    19  	"github.com/mattermost/mattermost-server/v5/utils"
    20  )
    21  
    22  type PluginAPI struct {
    23  	id       string
    24  	app      *App
    25  	logger   *mlog.SugarLogger
    26  	manifest *model.Manifest
    27  }
    28  
    29  func NewPluginAPI(a *App, manifest *model.Manifest) *PluginAPI {
    30  	return &PluginAPI{
    31  		id:       manifest.Id,
    32  		manifest: manifest,
    33  		app:      a,
    34  		logger:   a.Log().With(mlog.String("plugin_id", manifest.Id)).Sugar(),
    35  	}
    36  }
    37  
    38  func (api *PluginAPI) LoadPluginConfiguration(dest interface{}) error {
    39  	finalConfig := make(map[string]interface{})
    40  
    41  	// First set final config to defaults
    42  	if api.manifest.SettingsSchema != nil {
    43  		for _, setting := range api.manifest.SettingsSchema.Settings {
    44  			finalConfig[strings.ToLower(setting.Key)] = setting.Default
    45  		}
    46  	}
    47  
    48  	// If we have settings given we override the defaults with them
    49  	for setting, value := range api.app.Config().PluginSettings.Plugins[api.id] {
    50  		finalConfig[strings.ToLower(setting)] = value
    51  	}
    52  
    53  	if pluginSettingsJsonBytes, err := json.Marshal(finalConfig); err != nil {
    54  		api.logger.Error("Error marshaling config for plugin", mlog.Err(err))
    55  		return nil
    56  	} else {
    57  		err := json.Unmarshal(pluginSettingsJsonBytes, dest)
    58  		if err != nil {
    59  			api.logger.Error("Error unmarshaling config for plugin", mlog.Err(err))
    60  		}
    61  		return nil
    62  	}
    63  }
    64  
    65  func (api *PluginAPI) RegisterCommand(command *model.Command) error {
    66  	return api.app.RegisterPluginCommand(api.id, command)
    67  }
    68  
    69  func (api *PluginAPI) UnregisterCommand(teamId, trigger string) error {
    70  	api.app.UnregisterPluginCommand(api.id, teamId, trigger)
    71  	return nil
    72  }
    73  
    74  func (api *PluginAPI) ExecuteSlashCommand(commandArgs *model.CommandArgs) (*model.CommandResponse, error) {
    75  	user, appErr := api.app.GetUser(commandArgs.UserId)
    76  	if appErr != nil {
    77  		return nil, appErr
    78  	}
    79  	commandArgs.T = utils.GetUserTranslations(user.Locale)
    80  	commandArgs.SiteURL = api.app.GetSiteURL()
    81  	response, appErr := api.app.ExecuteCommand(commandArgs)
    82  	if appErr != nil {
    83  		return response, appErr
    84  	}
    85  	return response, nil
    86  }
    87  
    88  func (api *PluginAPI) GetSession(sessionId string) (*model.Session, *model.AppError) {
    89  	session, err := api.app.GetSessionById(sessionId)
    90  
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  
    95  	return session, nil
    96  }
    97  
    98  func (api *PluginAPI) GetConfig() *model.Config {
    99  	return api.app.GetSanitizedConfig()
   100  }
   101  
   102  // GetUnsanitizedConfig gets the configuration for a system admin without removing secrets.
   103  func (api *PluginAPI) GetUnsanitizedConfig() *model.Config {
   104  	return api.app.Config().Clone()
   105  }
   106  
   107  func (api *PluginAPI) SaveConfig(config *model.Config) *model.AppError {
   108  	return api.app.SaveConfig(config, true)
   109  }
   110  
   111  func (api *PluginAPI) GetPluginConfig() map[string]interface{} {
   112  	cfg := api.app.GetSanitizedConfig()
   113  	if pluginConfig, isOk := cfg.PluginSettings.Plugins[api.manifest.Id]; isOk {
   114  		return pluginConfig
   115  	}
   116  	return map[string]interface{}{}
   117  }
   118  
   119  func (api *PluginAPI) SavePluginConfig(pluginConfig map[string]interface{}) *model.AppError {
   120  	cfg := api.app.GetSanitizedConfig()
   121  	cfg.PluginSettings.Plugins[api.manifest.Id] = pluginConfig
   122  	return api.app.SaveConfig(cfg, true)
   123  }
   124  
   125  func (api *PluginAPI) GetBundlePath() (string, error) {
   126  	bundlePath, err := filepath.Abs(filepath.Join(*api.GetConfig().PluginSettings.Directory, api.manifest.Id))
   127  	if err != nil {
   128  		return "", err
   129  	}
   130  
   131  	return bundlePath, err
   132  }
   133  
   134  func (api *PluginAPI) GetLicense() *model.License {
   135  	return api.app.Srv().License()
   136  }
   137  
   138  func (api *PluginAPI) GetServerVersion() string {
   139  	return model.CurrentVersion
   140  }
   141  
   142  func (api *PluginAPI) GetSystemInstallDate() (int64, *model.AppError) {
   143  	return api.app.Srv().getSystemInstallDate()
   144  }
   145  
   146  func (api *PluginAPI) GetDiagnosticId() string {
   147  	return api.app.DiagnosticId()
   148  }
   149  
   150  func (api *PluginAPI) CreateTeam(team *model.Team) (*model.Team, *model.AppError) {
   151  	return api.app.CreateTeam(team)
   152  }
   153  
   154  func (api *PluginAPI) DeleteTeam(teamId string) *model.AppError {
   155  	return api.app.SoftDeleteTeam(teamId)
   156  }
   157  
   158  func (api *PluginAPI) GetTeams() ([]*model.Team, *model.AppError) {
   159  	return api.app.GetAllTeams()
   160  }
   161  
   162  func (api *PluginAPI) GetTeam(teamId string) (*model.Team, *model.AppError) {
   163  	return api.app.GetTeam(teamId)
   164  }
   165  
   166  func (api *PluginAPI) SearchTeams(term string) ([]*model.Team, *model.AppError) {
   167  	teams, _, err := api.app.SearchAllTeams(&model.TeamSearch{Term: term})
   168  	return teams, err
   169  }
   170  
   171  func (api *PluginAPI) GetTeamByName(name string) (*model.Team, *model.AppError) {
   172  	return api.app.GetTeamByName(name)
   173  }
   174  
   175  func (api *PluginAPI) GetTeamsUnreadForUser(userId string) ([]*model.TeamUnread, *model.AppError) {
   176  	return api.app.GetTeamsUnreadForUser("", userId)
   177  }
   178  
   179  func (api *PluginAPI) UpdateTeam(team *model.Team) (*model.Team, *model.AppError) {
   180  	return api.app.UpdateTeam(team)
   181  }
   182  
   183  func (api *PluginAPI) GetTeamsForUser(userId string) ([]*model.Team, *model.AppError) {
   184  	return api.app.GetTeamsForUser(userId)
   185  }
   186  
   187  func (api *PluginAPI) CreateTeamMember(teamId, userId string) (*model.TeamMember, *model.AppError) {
   188  	return api.app.AddTeamMember(teamId, userId)
   189  }
   190  
   191  func (api *PluginAPI) CreateTeamMembers(teamId string, userIds []string, requestorId string) ([]*model.TeamMember, *model.AppError) {
   192  	members, err := api.app.AddTeamMembers(teamId, userIds, requestorId, false)
   193  	if err != nil {
   194  		return nil, err
   195  	}
   196  	return model.TeamMembersWithErrorToTeamMembers(members), nil
   197  }
   198  
   199  func (api *PluginAPI) CreateTeamMembersGracefully(teamId string, userIds []string, requestorId string) ([]*model.TeamMemberWithError, *model.AppError) {
   200  	return api.app.AddTeamMembers(teamId, userIds, requestorId, true)
   201  }
   202  
   203  func (api *PluginAPI) DeleteTeamMember(teamId, userId, requestorId string) *model.AppError {
   204  	return api.app.RemoveUserFromTeam(teamId, userId, requestorId)
   205  }
   206  
   207  func (api *PluginAPI) GetTeamMembers(teamId string, page, perPage int) ([]*model.TeamMember, *model.AppError) {
   208  	return api.app.GetTeamMembers(teamId, page*perPage, perPage, nil)
   209  }
   210  
   211  func (api *PluginAPI) GetTeamMember(teamId, userId string) (*model.TeamMember, *model.AppError) {
   212  	return api.app.GetTeamMember(teamId, userId)
   213  }
   214  
   215  func (api *PluginAPI) GetTeamMembersForUser(userId string, page int, perPage int) ([]*model.TeamMember, *model.AppError) {
   216  	return api.app.GetTeamMembersForUserWithPagination(userId, page, perPage)
   217  }
   218  
   219  func (api *PluginAPI) UpdateTeamMemberRoles(teamId, userId, newRoles string) (*model.TeamMember, *model.AppError) {
   220  	return api.app.UpdateTeamMemberRoles(teamId, userId, newRoles)
   221  }
   222  
   223  func (api *PluginAPI) GetTeamStats(teamId string) (*model.TeamStats, *model.AppError) {
   224  	return api.app.GetTeamStats(teamId, nil)
   225  }
   226  
   227  func (api *PluginAPI) CreateUser(user *model.User) (*model.User, *model.AppError) {
   228  	return api.app.CreateUser(user)
   229  }
   230  
   231  func (api *PluginAPI) DeleteUser(userId string) *model.AppError {
   232  	user, err := api.app.GetUser(userId)
   233  	if err != nil {
   234  		return err
   235  	}
   236  	_, err = api.app.UpdateActive(user, false)
   237  	return err
   238  }
   239  
   240  func (api *PluginAPI) GetUsers(options *model.UserGetOptions) ([]*model.User, *model.AppError) {
   241  	return api.app.GetUsers(options)
   242  }
   243  
   244  func (api *PluginAPI) GetUser(userId string) (*model.User, *model.AppError) {
   245  	return api.app.GetUser(userId)
   246  }
   247  
   248  func (api *PluginAPI) GetUserByEmail(email string) (*model.User, *model.AppError) {
   249  	return api.app.GetUserByEmail(email)
   250  }
   251  
   252  func (api *PluginAPI) GetUserByUsername(name string) (*model.User, *model.AppError) {
   253  	return api.app.GetUserByUsername(name)
   254  }
   255  
   256  func (api *PluginAPI) GetUsersByUsernames(usernames []string) ([]*model.User, *model.AppError) {
   257  	return api.app.GetUsersByUsernames(usernames, true, nil)
   258  }
   259  
   260  func (api *PluginAPI) GetUsersInTeam(teamId string, page int, perPage int) ([]*model.User, *model.AppError) {
   261  	options := &model.UserGetOptions{InTeamId: teamId, Page: page, PerPage: perPage}
   262  	return api.app.GetUsersInTeam(options)
   263  }
   264  
   265  func (api *PluginAPI) GetPreferencesForUser(userId string) ([]model.Preference, *model.AppError) {
   266  	return api.app.GetPreferencesForUser(userId)
   267  }
   268  
   269  func (api *PluginAPI) UpdatePreferencesForUser(userId string, preferences []model.Preference) *model.AppError {
   270  	return api.app.UpdatePreferences(userId, preferences)
   271  }
   272  
   273  func (api *PluginAPI) DeletePreferencesForUser(userId string, preferences []model.Preference) *model.AppError {
   274  	return api.app.DeletePreferences(userId, preferences)
   275  }
   276  
   277  func (api *PluginAPI) UpdateUser(user *model.User) (*model.User, *model.AppError) {
   278  	return api.app.UpdateUser(user, true)
   279  }
   280  
   281  func (api *PluginAPI) UpdateUserActive(userId string, active bool) *model.AppError {
   282  	return api.app.UpdateUserActive(userId, active)
   283  }
   284  
   285  func (api *PluginAPI) GetUserStatus(userId string) (*model.Status, *model.AppError) {
   286  	return api.app.GetStatus(userId)
   287  }
   288  
   289  func (api *PluginAPI) GetUserStatusesByIds(userIds []string) ([]*model.Status, *model.AppError) {
   290  	return api.app.GetUserStatusesByIds(userIds)
   291  }
   292  
   293  func (api *PluginAPI) UpdateUserStatus(userId, status string) (*model.Status, *model.AppError) {
   294  	switch status {
   295  	case model.STATUS_ONLINE:
   296  		api.app.SetStatusOnline(userId, true)
   297  	case model.STATUS_OFFLINE:
   298  		api.app.SetStatusOffline(userId, true)
   299  	case model.STATUS_AWAY:
   300  		api.app.SetStatusAwayIfNeeded(userId, true)
   301  	case model.STATUS_DND:
   302  		api.app.SetStatusDoNotDisturb(userId)
   303  	default:
   304  		return nil, model.NewAppError("UpdateUserStatus", "plugin.api.update_user_status.bad_status", nil, "unrecognized status", http.StatusBadRequest)
   305  	}
   306  
   307  	return api.app.GetStatus(userId)
   308  }
   309  
   310  func (api *PluginAPI) GetUsersInChannel(channelId, sortBy string, page, perPage int) ([]*model.User, *model.AppError) {
   311  	switch sortBy {
   312  	case model.CHANNEL_SORT_BY_USERNAME:
   313  		return api.app.GetUsersInChannel(channelId, page*perPage, perPage)
   314  	case model.CHANNEL_SORT_BY_STATUS:
   315  		return api.app.GetUsersInChannelByStatus(channelId, page*perPage, perPage)
   316  	default:
   317  		return nil, model.NewAppError("GetUsersInChannel", "plugin.api.get_users_in_channel", nil, "invalid sort option", http.StatusBadRequest)
   318  	}
   319  }
   320  
   321  func (api *PluginAPI) GetLDAPUserAttributes(userId string, attributes []string) (map[string]string, *model.AppError) {
   322  	if api.app.Ldap() == nil {
   323  		return nil, model.NewAppError("GetLdapUserAttributes", "ent.ldap.disabled.app_error", nil, "", http.StatusNotImplemented)
   324  	}
   325  
   326  	user, err := api.app.GetUser(userId)
   327  	if err != nil {
   328  		return nil, err
   329  	}
   330  
   331  	if user.AuthData == nil {
   332  		return map[string]string{}, nil
   333  	}
   334  
   335  	// Only bother running the query if the user's auth service is LDAP or it's SAML and sync is enabled.
   336  	if user.AuthService == model.USER_AUTH_SERVICE_LDAP ||
   337  		(user.AuthService == model.USER_AUTH_SERVICE_SAML && *api.app.Config().SamlSettings.EnableSyncWithLdap) {
   338  		return api.app.Ldap().GetUserAttributes(*user.AuthData, attributes)
   339  	}
   340  
   341  	return map[string]string{}, nil
   342  }
   343  
   344  func (api *PluginAPI) CreateChannel(channel *model.Channel) (*model.Channel, *model.AppError) {
   345  	return api.app.CreateChannel(channel, false)
   346  }
   347  
   348  func (api *PluginAPI) DeleteChannel(channelId string) *model.AppError {
   349  	channel, err := api.app.GetChannel(channelId)
   350  	if err != nil {
   351  		return err
   352  	}
   353  	return api.app.DeleteChannel(channel, "")
   354  }
   355  
   356  func (api *PluginAPI) GetPublicChannelsForTeam(teamId string, page, perPage int) ([]*model.Channel, *model.AppError) {
   357  	channels, err := api.app.GetPublicChannelsForTeam(teamId, page*perPage, perPage)
   358  	if err != nil {
   359  		return nil, err
   360  	}
   361  	return *channels, err
   362  }
   363  
   364  func (api *PluginAPI) GetChannel(channelId string) (*model.Channel, *model.AppError) {
   365  	return api.app.GetChannel(channelId)
   366  }
   367  
   368  func (api *PluginAPI) GetChannelByName(teamId, name string, includeDeleted bool) (*model.Channel, *model.AppError) {
   369  	return api.app.GetChannelByName(name, teamId, includeDeleted)
   370  }
   371  
   372  func (api *PluginAPI) GetChannelByNameForTeamName(teamName, channelName string, includeDeleted bool) (*model.Channel, *model.AppError) {
   373  	return api.app.GetChannelByNameForTeamName(channelName, teamName, includeDeleted)
   374  }
   375  
   376  func (api *PluginAPI) GetChannelsForTeamForUser(teamId, userId string, includeDeleted bool) ([]*model.Channel, *model.AppError) {
   377  	channels, err := api.app.GetChannelsForUser(teamId, userId, includeDeleted, 0)
   378  	if err != nil {
   379  		return nil, err
   380  	}
   381  	return *channels, err
   382  }
   383  
   384  func (api *PluginAPI) GetChannelStats(channelId string) (*model.ChannelStats, *model.AppError) {
   385  	memberCount, err := api.app.GetChannelMemberCount(channelId)
   386  	if err != nil {
   387  		return nil, err
   388  	}
   389  	guestCount, err := api.app.GetChannelMemberCount(channelId)
   390  	if err != nil {
   391  		return nil, err
   392  	}
   393  	return &model.ChannelStats{ChannelId: channelId, MemberCount: memberCount, GuestCount: guestCount}, nil
   394  }
   395  
   396  func (api *PluginAPI) GetDirectChannel(userId1, userId2 string) (*model.Channel, *model.AppError) {
   397  	return api.app.GetOrCreateDirectChannel(userId1, userId2)
   398  }
   399  
   400  func (api *PluginAPI) GetGroupChannel(userIds []string) (*model.Channel, *model.AppError) {
   401  	return api.app.CreateGroupChannel(userIds, "")
   402  }
   403  
   404  func (api *PluginAPI) UpdateChannel(channel *model.Channel) (*model.Channel, *model.AppError) {
   405  	return api.app.UpdateChannel(channel)
   406  }
   407  
   408  func (api *PluginAPI) SearchChannels(teamId string, term string) ([]*model.Channel, *model.AppError) {
   409  	channels, err := api.app.SearchChannels(teamId, term)
   410  	if err != nil {
   411  		return nil, err
   412  	}
   413  	return *channels, err
   414  }
   415  
   416  func (api *PluginAPI) SearchUsers(search *model.UserSearch) ([]*model.User, *model.AppError) {
   417  	pluginSearchUsersOptions := &model.UserSearchOptions{
   418  		IsAdmin:       true,
   419  		AllowInactive: search.AllowInactive,
   420  		Limit:         search.Limit,
   421  	}
   422  	return api.app.SearchUsers(search, pluginSearchUsersOptions)
   423  }
   424  
   425  func (api *PluginAPI) SearchPostsInTeam(teamId string, paramsList []*model.SearchParams) ([]*model.Post, *model.AppError) {
   426  	postList, err := api.app.SearchPostsInTeam(teamId, paramsList)
   427  	if err != nil {
   428  		return nil, err
   429  	}
   430  	return postList.ToSlice(), nil
   431  }
   432  
   433  func (api *PluginAPI) SearchPostsInTeamForUser(teamId string, userId string, searchParams model.SearchParameter) (*model.PostSearchResults, *model.AppError) {
   434  	var terms string
   435  	if searchParams.Terms != nil {
   436  		terms = *searchParams.Terms
   437  	}
   438  
   439  	timeZoneOffset := 0
   440  	if searchParams.TimeZoneOffset != nil {
   441  		timeZoneOffset = *searchParams.TimeZoneOffset
   442  	}
   443  
   444  	isOrSearch := false
   445  	if searchParams.IsOrSearch != nil {
   446  		isOrSearch = *searchParams.IsOrSearch
   447  	}
   448  
   449  	page := 0
   450  	if searchParams.Page != nil {
   451  		page = *searchParams.Page
   452  	}
   453  
   454  	perPage := 100
   455  	if searchParams.PerPage != nil {
   456  		perPage = *searchParams.PerPage
   457  	}
   458  
   459  	includeDeletedChannels := false
   460  	if searchParams.IncludeDeletedChannels != nil {
   461  		includeDeletedChannels = *searchParams.IncludeDeletedChannels
   462  	}
   463  
   464  	return api.app.SearchPostsInTeamForUser(terms, userId, teamId, isOrSearch, includeDeletedChannels, timeZoneOffset, page, perPage)
   465  }
   466  
   467  func (api *PluginAPI) AddChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) {
   468  	// For now, don't allow overriding these via the plugin API.
   469  	userRequestorId := ""
   470  	postRootId := ""
   471  
   472  	channel, err := api.GetChannel(channelId)
   473  	if err != nil {
   474  		return nil, err
   475  	}
   476  
   477  	return api.app.AddChannelMember(userId, channel, userRequestorId, postRootId)
   478  }
   479  
   480  func (api *PluginAPI) AddUserToChannel(channelId, userId, asUserId string) (*model.ChannelMember, *model.AppError) {
   481  	postRootId := ""
   482  
   483  	channel, err := api.GetChannel(channelId)
   484  	if err != nil {
   485  		return nil, err
   486  	}
   487  
   488  	return api.app.AddChannelMember(userId, channel, asUserId, postRootId)
   489  }
   490  
   491  func (api *PluginAPI) GetChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) {
   492  	return api.app.GetChannelMember(channelId, userId)
   493  }
   494  
   495  func (api *PluginAPI) GetChannelMembers(channelId string, page, perPage int) (*model.ChannelMembers, *model.AppError) {
   496  	return api.app.GetChannelMembersPage(channelId, page, perPage)
   497  }
   498  
   499  func (api *PluginAPI) GetChannelMembersByIds(channelId string, userIds []string) (*model.ChannelMembers, *model.AppError) {
   500  	return api.app.GetChannelMembersByIds(channelId, userIds)
   501  }
   502  
   503  func (api *PluginAPI) GetChannelMembersForUser(teamId, userId string, page, perPage int) ([]*model.ChannelMember, *model.AppError) {
   504  	return api.app.GetChannelMembersForUserWithPagination(teamId, userId, page, perPage)
   505  }
   506  
   507  func (api *PluginAPI) UpdateChannelMemberRoles(channelId, userId, newRoles string) (*model.ChannelMember, *model.AppError) {
   508  	return api.app.UpdateChannelMemberRoles(channelId, userId, newRoles)
   509  }
   510  
   511  func (api *PluginAPI) UpdateChannelMemberNotifications(channelId, userId string, notifications map[string]string) (*model.ChannelMember, *model.AppError) {
   512  	return api.app.UpdateChannelMemberNotifyProps(notifications, channelId, userId)
   513  }
   514  
   515  func (api *PluginAPI) DeleteChannelMember(channelId, userId string) *model.AppError {
   516  	return api.app.LeaveChannel(channelId, userId)
   517  }
   518  
   519  func (api *PluginAPI) GetGroup(groupId string) (*model.Group, *model.AppError) {
   520  	return api.app.GetGroup(groupId)
   521  }
   522  
   523  func (api *PluginAPI) GetGroupByName(name string) (*model.Group, *model.AppError) {
   524  	return api.app.GetGroupByName(name, model.GroupSearchOpts{})
   525  }
   526  
   527  func (api *PluginAPI) GetGroupsForUser(userId string) ([]*model.Group, *model.AppError) {
   528  	return api.app.GetGroupsByUserId(userId)
   529  }
   530  
   531  func (api *PluginAPI) CreatePost(post *model.Post) (*model.Post, *model.AppError) {
   532  	return api.app.CreatePostMissingChannel(post, true)
   533  }
   534  
   535  func (api *PluginAPI) AddReaction(reaction *model.Reaction) (*model.Reaction, *model.AppError) {
   536  	return api.app.SaveReactionForPost(reaction)
   537  }
   538  
   539  func (api *PluginAPI) RemoveReaction(reaction *model.Reaction) *model.AppError {
   540  	return api.app.DeleteReactionForPost(reaction)
   541  }
   542  
   543  func (api *PluginAPI) GetReactions(postId string) ([]*model.Reaction, *model.AppError) {
   544  	return api.app.GetReactionsForPost(postId)
   545  }
   546  
   547  func (api *PluginAPI) SendEphemeralPost(userId string, post *model.Post) *model.Post {
   548  	return api.app.SendEphemeralPost(userId, post)
   549  }
   550  
   551  func (api *PluginAPI) UpdateEphemeralPost(userId string, post *model.Post) *model.Post {
   552  	return api.app.UpdateEphemeralPost(userId, post)
   553  }
   554  
   555  func (api *PluginAPI) DeleteEphemeralPost(userId, postId string) {
   556  	api.app.DeleteEphemeralPost(userId, postId)
   557  }
   558  
   559  func (api *PluginAPI) DeletePost(postId string) *model.AppError {
   560  	_, err := api.app.DeletePost(postId, api.id)
   561  	return err
   562  }
   563  
   564  func (api *PluginAPI) GetPostThread(postId string) (*model.PostList, *model.AppError) {
   565  	return api.app.GetPostThread(postId, false)
   566  }
   567  
   568  func (api *PluginAPI) GetPost(postId string) (*model.Post, *model.AppError) {
   569  	return api.app.GetSinglePost(postId)
   570  }
   571  
   572  func (api *PluginAPI) GetPostsSince(channelId string, time int64) (*model.PostList, *model.AppError) {
   573  	return api.app.GetPostsSince(model.GetPostsSinceOptions{ChannelId: channelId, Time: time})
   574  }
   575  
   576  func (api *PluginAPI) GetPostsAfter(channelId, postId string, page, perPage int) (*model.PostList, *model.AppError) {
   577  	return api.app.GetPostsAfterPost(model.GetPostsOptions{ChannelId: channelId, PostId: postId, Page: page, PerPage: perPage})
   578  }
   579  
   580  func (api *PluginAPI) GetPostsBefore(channelId, postId string, page, perPage int) (*model.PostList, *model.AppError) {
   581  	return api.app.GetPostsBeforePost(model.GetPostsOptions{ChannelId: channelId, PostId: postId, Page: page, PerPage: perPage})
   582  }
   583  
   584  func (api *PluginAPI) GetPostsForChannel(channelId string, page, perPage int) (*model.PostList, *model.AppError) {
   585  	return api.app.GetPostsPage(model.GetPostsOptions{ChannelId: channelId, Page: page, PerPage: perPage})
   586  }
   587  
   588  func (api *PluginAPI) UpdatePost(post *model.Post) (*model.Post, *model.AppError) {
   589  	return api.app.UpdatePost(post, false)
   590  }
   591  
   592  func (api *PluginAPI) GetProfileImage(userId string) ([]byte, *model.AppError) {
   593  	user, err := api.app.GetUser(userId)
   594  	if err != nil {
   595  		return nil, err
   596  	}
   597  
   598  	data, _, err := api.app.GetProfileImage(user)
   599  	return data, err
   600  }
   601  
   602  func (api *PluginAPI) SetProfileImage(userId string, data []byte) *model.AppError {
   603  	_, err := api.app.GetUser(userId)
   604  	if err != nil {
   605  		return err
   606  	}
   607  
   608  	return api.app.SetProfileImageFromFile(userId, bytes.NewReader(data))
   609  }
   610  
   611  func (api *PluginAPI) GetEmojiList(sortBy string, page, perPage int) ([]*model.Emoji, *model.AppError) {
   612  	return api.app.GetEmojiList(page, perPage, sortBy)
   613  }
   614  
   615  func (api *PluginAPI) GetEmojiByName(name string) (*model.Emoji, *model.AppError) {
   616  	return api.app.GetEmojiByName(name)
   617  }
   618  
   619  func (api *PluginAPI) GetEmoji(emojiId string) (*model.Emoji, *model.AppError) {
   620  	return api.app.GetEmoji(emojiId)
   621  }
   622  
   623  func (api *PluginAPI) CopyFileInfos(userId string, fileIds []string) ([]string, *model.AppError) {
   624  	return api.app.CopyFileInfos(userId, fileIds)
   625  }
   626  
   627  func (api *PluginAPI) GetFileInfo(fileId string) (*model.FileInfo, *model.AppError) {
   628  	return api.app.GetFileInfo(fileId)
   629  }
   630  
   631  func (api *PluginAPI) GetFileInfos(page, perPage int, opt *model.GetFileInfosOptions) ([]*model.FileInfo, *model.AppError) {
   632  	return api.app.GetFileInfos(page, perPage, opt)
   633  }
   634  
   635  func (api *PluginAPI) GetFileLink(fileId string) (string, *model.AppError) {
   636  	if !*api.app.Config().FileSettings.EnablePublicLink {
   637  		return "", model.NewAppError("GetFileLink", "plugin_api.get_file_link.disabled.app_error", nil, "", http.StatusNotImplemented)
   638  	}
   639  
   640  	info, err := api.app.GetFileInfo(fileId)
   641  	if err != nil {
   642  		return "", err
   643  	}
   644  
   645  	if len(info.PostId) == 0 {
   646  		return "", model.NewAppError("GetFileLink", "plugin_api.get_file_link.no_post.app_error", nil, "file_id="+info.Id, http.StatusBadRequest)
   647  	}
   648  
   649  	return api.app.GeneratePublicLink(api.app.GetSiteURL(), info), nil
   650  }
   651  
   652  func (api *PluginAPI) ReadFile(path string) ([]byte, *model.AppError) {
   653  	return api.app.ReadFile(path)
   654  }
   655  
   656  func (api *PluginAPI) GetFile(fileId string) ([]byte, *model.AppError) {
   657  	return api.app.GetFile(fileId)
   658  }
   659  
   660  func (api *PluginAPI) UploadFile(data []byte, channelId string, filename string) (*model.FileInfo, *model.AppError) {
   661  	return api.app.UploadFile(data, channelId, filename)
   662  }
   663  
   664  func (api *PluginAPI) GetEmojiImage(emojiId string) ([]byte, string, *model.AppError) {
   665  	return api.app.GetEmojiImage(emojiId)
   666  }
   667  
   668  func (api *PluginAPI) GetTeamIcon(teamId string) ([]byte, *model.AppError) {
   669  	team, err := api.app.GetTeam(teamId)
   670  	if err != nil {
   671  		return nil, err
   672  	}
   673  
   674  	data, err := api.app.GetTeamIcon(team)
   675  	if err != nil {
   676  		return nil, err
   677  	}
   678  	return data, nil
   679  }
   680  
   681  func (api *PluginAPI) SetTeamIcon(teamId string, data []byte) *model.AppError {
   682  	team, err := api.app.GetTeam(teamId)
   683  	if err != nil {
   684  		return err
   685  	}
   686  
   687  	return api.app.SetTeamIconFromFile(team, bytes.NewReader(data))
   688  }
   689  
   690  func (api *PluginAPI) OpenInteractiveDialog(dialog model.OpenDialogRequest) *model.AppError {
   691  	return api.app.OpenInteractiveDialog(dialog)
   692  }
   693  
   694  func (api *PluginAPI) RemoveTeamIcon(teamId string) *model.AppError {
   695  	_, err := api.app.GetTeam(teamId)
   696  	if err != nil {
   697  		return err
   698  	}
   699  
   700  	err = api.app.RemoveTeamIcon(teamId)
   701  	if err != nil {
   702  		return err
   703  	}
   704  	return nil
   705  }
   706  
   707  // Mail Section
   708  
   709  func (api *PluginAPI) SendMail(to, subject, htmlBody string) *model.AppError {
   710  	if to == "" {
   711  		return model.NewAppError("SendMail", "plugin_api.send_mail.missing_to", nil, "", http.StatusBadRequest)
   712  	}
   713  
   714  	if subject == "" {
   715  		return model.NewAppError("SendMail", "plugin_api.send_mail.missing_subject", nil, "", http.StatusBadRequest)
   716  	}
   717  
   718  	if htmlBody == "" {
   719  		return model.NewAppError("SendMail", "plugin_api.send_mail.missing_htmlbody", nil, "", http.StatusBadRequest)
   720  	}
   721  
   722  	return api.app.Srv().EmailService.sendNotificationMail(to, subject, htmlBody)
   723  }
   724  
   725  // Plugin Section
   726  
   727  func (api *PluginAPI) GetPlugins() ([]*model.Manifest, *model.AppError) {
   728  	plugins, err := api.app.GetPlugins()
   729  	if err != nil {
   730  		return nil, err
   731  	}
   732  	var manifests []*model.Manifest
   733  	for _, manifest := range plugins.Active {
   734  		manifests = append(manifests, &manifest.Manifest)
   735  	}
   736  	for _, manifest := range plugins.Inactive {
   737  		manifests = append(manifests, &manifest.Manifest)
   738  	}
   739  	return manifests, nil
   740  }
   741  
   742  func (api *PluginAPI) EnablePlugin(id string) *model.AppError {
   743  	return api.app.EnablePlugin(id)
   744  }
   745  
   746  func (api *PluginAPI) DisablePlugin(id string) *model.AppError {
   747  	return api.app.DisablePlugin(id)
   748  }
   749  
   750  func (api *PluginAPI) RemovePlugin(id string) *model.AppError {
   751  	return api.app.RemovePlugin(id)
   752  }
   753  
   754  func (api *PluginAPI) GetPluginStatus(id string) (*model.PluginStatus, *model.AppError) {
   755  	return api.app.GetPluginStatus(id)
   756  }
   757  
   758  func (api *PluginAPI) InstallPlugin(file io.Reader, replace bool) (*model.Manifest, *model.AppError) {
   759  	if !*api.app.Config().PluginSettings.Enable || !*api.app.Config().PluginSettings.EnableUploads {
   760  		return nil, model.NewAppError("installPlugin", "app.plugin.upload_disabled.app_error", nil, "", http.StatusNotImplemented)
   761  	}
   762  
   763  	fileBuffer, err := ioutil.ReadAll(file)
   764  	if err != nil {
   765  		return nil, model.NewAppError("InstallPlugin", "api.plugin.upload.file.app_error", nil, "", http.StatusBadRequest)
   766  	}
   767  
   768  	return api.app.InstallPlugin(bytes.NewReader(fileBuffer), replace)
   769  }
   770  
   771  // KV Store Section
   772  
   773  func (api *PluginAPI) KVSetWithOptions(key string, value []byte, options model.PluginKVSetOptions) (bool, *model.AppError) {
   774  	return api.app.SetPluginKeyWithOptions(api.id, key, value, options)
   775  }
   776  
   777  func (api *PluginAPI) KVSet(key string, value []byte) *model.AppError {
   778  	return api.app.SetPluginKey(api.id, key, value)
   779  }
   780  
   781  func (api *PluginAPI) KVCompareAndSet(key string, oldValue, newValue []byte) (bool, *model.AppError) {
   782  	return api.app.CompareAndSetPluginKey(api.id, key, oldValue, newValue)
   783  }
   784  
   785  func (api *PluginAPI) KVCompareAndDelete(key string, oldValue []byte) (bool, *model.AppError) {
   786  	return api.app.CompareAndDeletePluginKey(api.id, key, oldValue)
   787  }
   788  
   789  func (api *PluginAPI) KVSetWithExpiry(key string, value []byte, expireInSeconds int64) *model.AppError {
   790  	return api.app.SetPluginKeyWithExpiry(api.id, key, value, expireInSeconds)
   791  }
   792  
   793  func (api *PluginAPI) KVGet(key string) ([]byte, *model.AppError) {
   794  	return api.app.GetPluginKey(api.id, key)
   795  }
   796  
   797  func (api *PluginAPI) KVDelete(key string) *model.AppError {
   798  	return api.app.DeletePluginKey(api.id, key)
   799  }
   800  
   801  func (api *PluginAPI) KVDeleteAll() *model.AppError {
   802  	return api.app.DeleteAllKeysForPlugin(api.id)
   803  }
   804  
   805  func (api *PluginAPI) KVList(page, perPage int) ([]string, *model.AppError) {
   806  	return api.app.ListPluginKeys(api.id, page, perPage)
   807  }
   808  
   809  func (api *PluginAPI) PublishWebSocketEvent(event string, payload map[string]interface{}, broadcast *model.WebsocketBroadcast) {
   810  	ev := model.NewWebSocketEvent(fmt.Sprintf("custom_%v_%v", api.id, event), "", "", "", nil)
   811  	ev = ev.SetBroadcast(broadcast).SetData(payload)
   812  	api.app.Publish(ev)
   813  }
   814  
   815  func (api *PluginAPI) HasPermissionTo(userId string, permission *model.Permission) bool {
   816  	return api.app.HasPermissionTo(userId, permission)
   817  }
   818  
   819  func (api *PluginAPI) HasPermissionToTeam(userId, teamId string, permission *model.Permission) bool {
   820  	return api.app.HasPermissionToTeam(userId, teamId, permission)
   821  }
   822  
   823  func (api *PluginAPI) HasPermissionToChannel(userId, channelId string, permission *model.Permission) bool {
   824  	return api.app.HasPermissionToChannel(userId, channelId, permission)
   825  }
   826  
   827  func (api *PluginAPI) LogDebug(msg string, keyValuePairs ...interface{}) {
   828  	api.logger.Debug(msg, keyValuePairs...)
   829  }
   830  func (api *PluginAPI) LogInfo(msg string, keyValuePairs ...interface{}) {
   831  	api.logger.Info(msg, keyValuePairs...)
   832  }
   833  func (api *PluginAPI) LogError(msg string, keyValuePairs ...interface{}) {
   834  	api.logger.Error(msg, keyValuePairs...)
   835  }
   836  func (api *PluginAPI) LogWarn(msg string, keyValuePairs ...interface{}) {
   837  	api.logger.Warn(msg, keyValuePairs...)
   838  }
   839  
   840  func (api *PluginAPI) CreateBot(bot *model.Bot) (*model.Bot, *model.AppError) {
   841  	// Bots created by a plugin should use the plugin's ID for the creator field, unless
   842  	// otherwise specified by the plugin.
   843  	if bot.OwnerId == "" {
   844  		bot.OwnerId = api.id
   845  	}
   846  	// Bots cannot be owners of other bots
   847  	if user, err := api.app.GetUser(bot.OwnerId); err == nil {
   848  		if user.IsBot {
   849  			return nil, model.NewAppError("CreateBot", "plugin_api.bot_cant_create_bot", nil, "", http.StatusBadRequest)
   850  		}
   851  	}
   852  
   853  	return api.app.CreateBot(bot)
   854  }
   855  
   856  func (api *PluginAPI) PatchBot(userId string, botPatch *model.BotPatch) (*model.Bot, *model.AppError) {
   857  	return api.app.PatchBot(userId, botPatch)
   858  }
   859  
   860  func (api *PluginAPI) GetBot(userId string, includeDeleted bool) (*model.Bot, *model.AppError) {
   861  	return api.app.GetBot(userId, includeDeleted)
   862  }
   863  
   864  func (api *PluginAPI) GetBots(options *model.BotGetOptions) ([]*model.Bot, *model.AppError) {
   865  	bots, err := api.app.GetBots(options)
   866  
   867  	return []*model.Bot(bots), err
   868  }
   869  
   870  func (api *PluginAPI) UpdateBotActive(userId string, active bool) (*model.Bot, *model.AppError) {
   871  	return api.app.UpdateBotActive(userId, active)
   872  }
   873  
   874  func (api *PluginAPI) PermanentDeleteBot(userId string) *model.AppError {
   875  	return api.app.PermanentDeleteBot(userId)
   876  }
   877  
   878  func (api *PluginAPI) GetBotIconImage(userId string) ([]byte, *model.AppError) {
   879  	if _, err := api.app.GetBot(userId, true); err != nil {
   880  		return nil, err
   881  	}
   882  
   883  	return api.app.GetBotIconImage(userId)
   884  }
   885  
   886  func (api *PluginAPI) SetBotIconImage(userId string, data []byte) *model.AppError {
   887  	if _, err := api.app.GetBot(userId, true); err != nil {
   888  		return err
   889  	}
   890  
   891  	return api.app.SetBotIconImage(userId, bytes.NewReader(data))
   892  }
   893  
   894  func (api *PluginAPI) DeleteBotIconImage(userId string) *model.AppError {
   895  	if _, err := api.app.GetBot(userId, true); err != nil {
   896  		return err
   897  	}
   898  
   899  	return api.app.DeleteBotIconImage(userId)
   900  }
   901  
   902  func (api *PluginAPI) PublishUserTyping(userId, channelId, parentId string) *model.AppError {
   903  	return api.app.PublishUserTyping(userId, channelId, parentId)
   904  }
   905  
   906  func (api *PluginAPI) PluginHTTP(request *http.Request) *http.Response {
   907  	split := strings.SplitN(request.URL.Path, "/", 3)
   908  	if len(split) != 3 {
   909  		return &http.Response{
   910  			StatusCode: http.StatusBadRequest,
   911  			Body:       ioutil.NopCloser(bytes.NewBufferString("Not enough URL. Form of URL should be /<pluginid>/*")),
   912  		}
   913  	}
   914  	destinationPluginId := split[1]
   915  	newURL, err := url.Parse("/" + split[2])
   916  	newURL.RawQuery = request.URL.Query().Encode()
   917  	request.URL = newURL
   918  	if destinationPluginId == "" || err != nil {
   919  		message := "No plugin specified. Form of URL should be /<pluginid>/*"
   920  		if err != nil {
   921  			message = "Form of URL should be /<pluginid>/* Error: " + err.Error()
   922  		}
   923  		return &http.Response{
   924  			StatusCode: http.StatusBadRequest,
   925  			Body:       ioutil.NopCloser(bytes.NewBufferString(message)),
   926  		}
   927  	}
   928  	responseTransfer := &PluginResponseWriter{}
   929  	api.app.ServeInterPluginRequest(responseTransfer, request, api.id, destinationPluginId)
   930  	return responseTransfer.GenerateResponse()
   931  }
   932  
   933  func (api *PluginAPI) CreateCommand(cmd *model.Command) (*model.Command, error) {
   934  	cmd.CreatorId = ""
   935  	cmd.PluginId = api.id
   936  
   937  	cmd, appErr := api.app.createCommand(cmd)
   938  
   939  	if appErr != nil {
   940  		return cmd, appErr
   941  	}
   942  
   943  	return cmd, nil
   944  }
   945  
   946  func (api *PluginAPI) ListCommands(teamID string) ([]*model.Command, error) {
   947  	ret := make([]*model.Command, 0)
   948  
   949  	cmds, err := api.ListPluginCommands(teamID)
   950  	if err != nil {
   951  		return nil, err
   952  	}
   953  	ret = append(ret, cmds...)
   954  
   955  	cmds, err = api.ListBuiltInCommands()
   956  	if err != nil {
   957  		return nil, err
   958  	}
   959  	ret = append(ret, cmds...)
   960  
   961  	cmds, err = api.ListCustomCommands(teamID)
   962  	if err != nil {
   963  		return nil, err
   964  	}
   965  	ret = append(ret, cmds...)
   966  
   967  	return ret, nil
   968  }
   969  
   970  func (api *PluginAPI) ListCustomCommands(teamID string) ([]*model.Command, error) {
   971  	// Plugins are allowed to bypass the a.Config().ServiceSettings.EnableCommands setting.
   972  	return api.app.Srv().Store.Command().GetByTeam(teamID)
   973  }
   974  
   975  func (api *PluginAPI) ListPluginCommands(teamID string) ([]*model.Command, error) {
   976  	commands := make([]*model.Command, 0)
   977  	seen := make(map[string]bool)
   978  
   979  	for _, cmd := range api.app.PluginCommandsForTeam(teamID) {
   980  		if !seen[cmd.Trigger] {
   981  			seen[cmd.Trigger] = true
   982  			commands = append(commands, cmd)
   983  		}
   984  	}
   985  
   986  	return commands, nil
   987  }
   988  
   989  func (api *PluginAPI) ListBuiltInCommands() ([]*model.Command, error) {
   990  	commands := make([]*model.Command, 0)
   991  	seen := make(map[string]bool)
   992  
   993  	for _, value := range commandProviders {
   994  		if cmd := value.GetCommand(api.app, utils.T); cmd != nil {
   995  			cpy := *cmd
   996  			if cpy.AutoComplete && !seen[cpy.Trigger] {
   997  				cpy.Sanitize()
   998  				seen[cpy.Trigger] = true
   999  				commands = append(commands, &cpy)
  1000  			}
  1001  		}
  1002  	}
  1003  
  1004  	return commands, nil
  1005  }
  1006  
  1007  func (api *PluginAPI) GetCommand(commandID string) (*model.Command, error) {
  1008  	return api.app.Srv().Store.Command().Get(commandID)
  1009  }
  1010  
  1011  func (api *PluginAPI) UpdateCommand(commandID string, updatedCmd *model.Command) (*model.Command, error) {
  1012  	oldCmd, err := api.GetCommand(commandID)
  1013  	if err != nil {
  1014  		return nil, err
  1015  	}
  1016  
  1017  	updatedCmd.Trigger = strings.ToLower(updatedCmd.Trigger)
  1018  	updatedCmd.Id = oldCmd.Id
  1019  	updatedCmd.Token = oldCmd.Token
  1020  	updatedCmd.CreateAt = oldCmd.CreateAt
  1021  	updatedCmd.UpdateAt = model.GetMillis()
  1022  	updatedCmd.DeleteAt = oldCmd.DeleteAt
  1023  	updatedCmd.PluginId = api.id
  1024  	if updatedCmd.TeamId == "" {
  1025  		updatedCmd.TeamId = oldCmd.TeamId
  1026  	}
  1027  
  1028  	return api.app.Srv().Store.Command().Update(updatedCmd)
  1029  }
  1030  
  1031  func (api *PluginAPI) DeleteCommand(commandID string) error {
  1032  	err := api.app.Srv().Store.Command().Delete(commandID, model.GetMillis())
  1033  	if err != nil {
  1034  		return err
  1035  	}
  1036  
  1037  	return nil
  1038  }