Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 0 additions & 56 deletions api/v4/source/teams.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1572,62 +1572,6 @@
$ref: "#/components/responses/Unauthorized"
"403":
$ref: "#/components/responses/Forbidden"
"/api/v4/teams/{team_id}/import":
post:
tags:
- teams
summary: Import a Team from other application
description: >
Import a team into a existing team. Import users, channels, posts,
hooks.

##### Permissions

Must have `permission_import_team` permission.
operationId: ImportTeam
parameters:
- name: team_id
in: path
description: Team GUID
required: true
schema:
type: string
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
file:
description: A file to be uploaded in zip format.
type: string
format: binary
filesize:
description: The size of the zip file to be imported.
type: integer
importFrom:
description: String that defines from which application the team was
exported to be imported into Mattermost.
type: string
required:
- file
- filesize
- importFrom
responses:
"200":
description: JSON object containing a base64 encoded text file of the import logs
in its `results` property.
content:
application/json:
schema:
type: object
properties:
results:
type: string
"400":
$ref: "#/components/responses/BadRequest"
"403":
$ref: "#/components/responses/Forbidden"
"/api/v4/teams/invite/{invite_id}":
get:
tags:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -439,10 +439,6 @@ The following tables list the comprehensive audit event types (`event_name` valu
<td>Deleting teams</td>
</tr>
<tr>
<td><code>importTeam</code></td>
<td>Importing team data</td>
</tr>
<tr>
<td><code>invalidateAllEmailInvites</code></td>
<td>Invalidating all email invitations</td>
</tr>
Expand Down Expand Up @@ -1484,10 +1480,6 @@ From Mattermost v11.5.0, audit log entries for posts and content access events i
<td><code>scheduleExport</code></td>
<td>Scheduling export operations</td>
</tr>
<tr>
<td><code>slackImport</code></td>
<td>Slack data import operations</td>
</tr>
</tbody>
</table>

Expand Down
18 changes: 0 additions & 18 deletions docs/main/administration-guide/manage/command-line-tools.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -320,29 +320,11 @@ Import data into Mattermost.

Child Command
- [mattermost import bulk](#mattermost-import-bulk) - Import a Mattermost Bulk Import File. Deprecated in favor of [mmctl import commands](/administration-guide/manage/mmctl-command-line-tool#mmctl-import).
- [mattermost import slack](#mattermost-import-slack) - Import a team from Slack.

### mattermost import bulk

From Mattermost v6.0, this command has been deprecated in favor of [mmctl import commands](/administration-guide/manage/mmctl-command-line-tool#mmctl-import) as the supported way to import data into Mattermost.

### mattermost import slack

See the [mmctl import commands](/administration-guide/manage/mmctl-command-line-tool#mmctl-import) documentation as the preferred way to import Slack data into Mattermost.

Description
Import a team from a Slack export zip file.

Format
. code-block:: sh

mattermost import slack &#123;team&#125; &#123;file&#125;

Example
``` sh
bin/mattermost import slack myteam slack_export.zip
```

------------------------------------------------------------------------------------------------------------------------

## mattermost jobserver
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -387,12 +387,6 @@ Permissions in Mattermost are a property of the server code base and are not cre
<td></td>
</tr>
<tr>
<td>import_team</td>
<td>system</td>
<td>Import teams in Team Settings.</td>
<td></td>
</tr>
<tr>
<td>view_team</td>
<td>team</td>
<td>Read the Team object.</td>
Expand Down Expand Up @@ -802,7 +796,6 @@ The following built-in roles with default permissions are available:
- sysconsole_read_user_management_permissions
- manage_public_channel_members
- sysconsole_write_about
- import_team
- sysconsole_write_user_management_system_roles
- sysconsole_read_reporting
- upload_file
Expand Down Expand Up @@ -1021,7 +1014,6 @@ The following built-in roles with default permissions are available:
- manage_private_channel_members
- convert_public_channel_to_private
- add_reaction
- import_team
- add_bookmark_public_channel
- edit_bookmark_public_channel
- delete_bookmark_public_channel
Expand Down

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion server/.golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,6 @@ linters:
platform/services/sharedchannel/permalink_test.go|\
platform/services/sharedchannel/sync_recv.go|\
platform/services/sharedchannel/sync_send.go|\
platform/services/slackimport/slackimport.go|\
platform/services/telemetry/telemetry.go|\
platform/services/telemetry/telemetry_test.go|\
platform/services/upgrader/upgrader_linux.go|\
Expand Down
99 changes: 2 additions & 97 deletions server/channels/api4/team.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
package api4

import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
Expand All @@ -19,9 +17,8 @@ import (
)

const (
MaxAddMembersBatch = 256
MaximumBulkImportSize = 10 * 1024 * 1024
groupIDsParamPattern = "[^a-zA-Z0-9,]*"
MaxAddMembersBatch = 256
groupIDsParamPattern = "[^a-zA-Z0-9,]*"
)

var groupIDsQueryParamRegex *regexp.Regexp
Expand Down Expand Up @@ -68,7 +65,6 @@ func (api *API) InitTeam() {
api.BaseRoutes.TeamByName.Handle("/exists", api.APISessionRequired(teamExists)).Methods(http.MethodGet)
api.BaseRoutes.TeamMember.Handle("/roles", api.APISessionRequired(updateTeamMemberRoles)).Methods(http.MethodPut)
api.BaseRoutes.TeamMember.Handle("/schemeRoles", api.APISessionRequired(updateTeamMemberSchemeRoles)).Methods(http.MethodPut)
api.BaseRoutes.Team.Handle("/import", api.APISessionRequired(importTeam)).Methods(http.MethodPost)
api.BaseRoutes.Team.Handle("/invite/email", api.APISessionRequired(inviteUsersToTeam)).Methods(http.MethodPost)
api.BaseRoutes.Team.Handle("/invite-guests/email", api.APISessionRequired(inviteGuestsToChannels)).Methods(http.MethodPost)
api.BaseRoutes.Teams.Handle("/invites/email", api.APISessionRequired(invalidateAllEmailInvites)).Methods(http.MethodDelete)
Expand Down Expand Up @@ -1657,97 +1653,6 @@ func teamExists(c *Context, w http.ResponseWriter, r *http.Request) {
}
}

func importTeam(c *Context, w http.ResponseWriter, r *http.Request) {
if c.App.Channels().License().IsCloud() {
c.Err = model.NewAppError("importTeam", "api.restricted_system_admin", nil, "", http.StatusForbidden)
return
}

c.RequireTeamId()
if c.Err != nil {
return
}

if !c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), c.Params.TeamId, model.PermissionImportTeam) {
c.SetPermissionError(model.PermissionImportTeam)
return
}

if err := r.ParseMultipartForm(MaximumBulkImportSize); err != nil {
c.Err = model.NewAppError("importTeam", "api.team.import_team.parse.app_error", nil, "", http.StatusInternalServerError).Wrap(err)
return
}

importFromArray, ok := r.MultipartForm.Value["importFrom"]
if !ok || len(importFromArray) < 1 {
c.Err = model.NewAppError("importTeam", "api.team.import_team.no_import_from.app_error", nil, "", http.StatusBadRequest)
return
}
importFrom := importFromArray[0]

fileSizeStr, ok := r.MultipartForm.Value["filesize"]
if !ok || len(fileSizeStr) < 1 {
c.Err = model.NewAppError("importTeam", "api.team.import_team.unavailable.app_error", nil, "", http.StatusBadRequest)
return
}

fileSize, err := strconv.ParseInt(fileSizeStr[0], 10, 64)
if err != nil {
c.Err = model.NewAppError("importTeam", "api.team.import_team.integer.app_error", nil, "", http.StatusBadRequest)
return
}

fileInfoArray, ok := r.MultipartForm.File["file"]
if !ok {
c.Err = model.NewAppError("importTeam", "api.team.import_team.no_file.app_error", nil, "", http.StatusBadRequest)
return
}

if len(fileInfoArray) <= 0 {
c.Err = model.NewAppError("importTeam", "api.team.import_team.array.app_error", nil, "", http.StatusBadRequest)
return
}

auditRec := c.MakeAuditRecord(model.AuditEventImportTeam, model.AuditStatusFail)
defer c.LogAuditRec(auditRec)
model.AddEventParameterToAuditRec(auditRec, "team_id", c.Params.TeamId)

fileInfo := fileInfoArray[0]

fileData, err := fileInfo.Open()
if err != nil {
c.Err = model.NewAppError("importTeam", "api.team.import_team.open.app_error", nil, "", http.StatusBadRequest).Wrap(err)
return
}
defer fileData.Close()
model.AddEventParameterToAuditRec(auditRec, "filename", fileInfo.Filename)
model.AddEventParameterToAuditRec(auditRec, "filesize", fileSize)
model.AddEventParameterToAuditRec(auditRec, "from", importFrom)

var log *bytes.Buffer
data := map[string]string{}
switch importFrom {
case "slack":
var err *model.AppError
if err, log = c.App.SlackImport(c.AppContext, fileData, fileSize, c.Params.TeamId); err != nil {
c.Err = err
c.Err.StatusCode = http.StatusBadRequest
}
data["results"] = base64.StdEncoding.EncodeToString(log.Bytes())
default:
c.Err = model.NewAppError("importTeam", "api.team.import_team.unknown_import_from.app_error", nil, "", http.StatusBadRequest)
}

if c.Err != nil {
w.WriteHeader(c.Err.StatusCode)
return
}
auditRec.Success()
if _, err := w.Write([]byte(model.MapToJSON(data))); err != nil {
c.Logger.Warn("Error while writing response", mlog.Err(err))
}
}

func inviteUsersToTeam(c *Context, w http.ResponseWriter, r *http.Request) {
graceful := r.URL.Query().Get("graceful") != ""

Expand Down
93 changes: 0 additions & 93 deletions server/channels/api4/team_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ package api4

import (
"context"
"encoding/base64"
"encoding/binary"
"encoding/json"
"fmt"
"net/http"
Expand Down Expand Up @@ -4131,97 +4129,6 @@ func TestTeamExists(t *testing.T) {
})
}

func TestImportTeam(t *testing.T) {
mainHelper.Parallel(t)
th := Setup(t).InitBasic(t)

th.TestForAllClients(t, func(T *testing.T, c *model.Client4) {
data, err := testutils.ReadTestFile("Fake_Team_Import.zip")

require.False(t, err != nil && len(data) == 0, "Error while reading the test file.")
_, resp, err := th.SystemAdminClient.ImportTeam(context.Background(), data, binary.Size(data), "XYZ", "Fake_Team_Import.zip", th.BasicTeam.Id)
require.Error(t, err)
CheckBadRequestStatus(t, resp)

_, resp, err = th.SystemAdminClient.ImportTeam(context.Background(), data, binary.Size(data), "", "Fake_Team_Import.zip", th.BasicTeam.Id)
require.Error(t, err)
CheckBadRequestStatus(t, resp)
}, "Import from unknown and source")

t.Run("ImportTeam", func(t *testing.T) {
var data []byte
var err error
data, err = testutils.ReadTestFile("Fake_Team_Import.zip")

require.False(t, err != nil && len(data) == 0, "Error while reading the test file.")

// Import the channels/users/posts
fileResp, _, err := th.SystemAdminClient.ImportTeam(context.Background(), data, binary.Size(data), "slack", "Fake_Team_Import.zip", th.BasicTeam.Id)
require.NoError(t, err)

fileData, err := base64.StdEncoding.DecodeString(fileResp["results"])
require.NoError(t, err, "failed to decode base64 results data")

fileReturned := string(fileData)
require.Truef(t, strings.Contains(fileReturned, "darth.vader@stardeath.com"), "failed to report the user was imported, fileReturned: %s", fileReturned)

// Checking the imported users
importedUser, _, err := th.SystemAdminClient.GetUserByUsername(context.Background(), "bot_test", "")
require.NoError(t, err)
require.Equal(t, importedUser.Username, "bot_test", "username should match with the imported user")

importedUser, _, err = th.SystemAdminClient.GetUserByUsername(context.Background(), "lordvader", "")
require.NoError(t, err)
require.Equal(t, importedUser.Username, "lordvader", "username should match with the imported user")

// Checking the imported Channels
importedChannel, _, err := th.SystemAdminClient.GetChannelByName(context.Background(), "testchannel", th.BasicTeam.Id, "")
require.NoError(t, err)
require.Equal(t, importedChannel.Name, "testchannel", "names did not match expected: testchannel")

importedChannel, _, err = th.SystemAdminClient.GetChannelByName(context.Background(), "general", th.BasicTeam.Id, "")
require.NoError(t, err)
require.Equal(t, importedChannel.Name, "general", "names did not match expected: general")

posts, _, err := th.SystemAdminClient.GetPostsForChannel(context.Background(), importedChannel.Id, 0, 60, "", false, false)
require.NoError(t, err)
require.Equal(t, posts.Posts[posts.Order[3]].Message, "This is a test post to test the import process", "missing posts in the import process")
})

t.Run("Cloud Forbidden", func(t *testing.T) {
var data []byte
var err error
data, err = testutils.ReadTestFile("Fake_Team_Import.zip")

require.False(t, err != nil && len(data) == 0, "Error while reading the test file.")
th.App.Srv().SetLicense(model.NewTestLicense("cloud"))

// Import the channels/users/posts
_, resp, err := th.SystemAdminClient.ImportTeam(context.Background(), data, binary.Size(data), "slack", "Fake_Team_Import.zip", th.BasicTeam.Id)
require.Error(t, err)
CheckForbiddenStatus(t, resp)
th.App.Srv().SetLicense(nil)
})

t.Run("MissingFile", func(t *testing.T) {
_, resp, err := th.SystemAdminClient.ImportTeam(context.Background(), nil, 4343, "slack", "Fake_Team_Import.zip", th.BasicTeam.Id)
require.Error(t, err)
CheckBadRequestStatus(t, resp)
})

t.Run("WrongPermission", func(t *testing.T) {
var data []byte
var err error
data, err = testutils.ReadTestFile("Fake_Team_Import.zip")
require.False(t, err != nil && len(data) == 0, "Error while reading the test file.")

// Import the channels/users/posts
_, resp, err := th.Client.ImportTeam(context.Background(), data, binary.Size(data), "slack", "Fake_Team_Import.zip", th.BasicTeam.Id)
require.Error(t, err)
CheckForbiddenStatus(t, resp)
})
}

func TestValidateUserPermissionsOnChannels(t *testing.T) {
mainHelper.Parallel(t)
th := Setup(t).InitBasic(t)
Expand Down
1 change: 0 additions & 1 deletion server/channels/app/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@ func TestDoAdvancedPermissionsMigration(t *testing.T) {
"team_admin": {
model.PermissionRemoveUserFromTeam.Id,
model.PermissionManageTeam.Id,
model.PermissionImportTeam.Id,
model.PermissionManageTeamRoles.Id,
model.PermissionManageTeamAccessRules.Id,
model.PermissionManageChannelRoles.Id,
Expand Down
Loading
Loading