mirror of
https://github.com/mattermost/mattermost.git
synced 2025-02-25 18:55:24 -06:00
* Posts * Add missing translation * Fix internal store marshaling * [MM-22051] Remove To/From JSON (Channels) (#18116) * Channels * Channel members * ChannelSearch * Channel categories, list, sidebar, stats, view * Fix conversions * [MM-22051] Remove To/From JSON (Users) (#18121) * User related structs * Fix return * Team related structures (#18127) * [MM-22051] Remove To/From JSON (Status, Bot, Reaction, Thread, FileInfo) (#18130) * Status * Bot * Reaction * Thread * FileInfo * Some fixes * Translations update from Weblate (#18143) * Translated using Weblate (German) Currently translated at 100.0% (2309 of 2309 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/de/ * Translated using Weblate (Turkish) Currently translated at 100.0% (2309 of 2309 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/tr/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2309 of 2309 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/hu/ * Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ Update translation files Updated by "Cleanup translation files" hook in Weblate. Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ * Translated using Weblate (German) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/de/ * Translated using Weblate (Turkish) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/tr/ * Translated using Weblate (Hungarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/hu/ * Translated using Weblate (English (Australia)) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/en_AU/ * Translated using Weblate (Bulgarian) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/bg/ * Translated using Weblate (Japanese) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/ja/ * Translated using Weblate (Chinese (Simplified)) Currently translated at 100.0% (2301 of 2301 strings) Translation: mattermost-languages-shipped/mattermost-server Translate-URL: https://translate.mattermost.com/projects/mattermost/mattermost-server_master/zh_Hans/ Co-authored-by: JtheBAB <srast@bioc.uzh.ch> Co-authored-by: Kaya Zeren <kayazeren@gmail.com> Co-authored-by: Tóth Csaba // Online ERP Hungary Kft <csaba.toth@online-erp.hu> Co-authored-by: Matthew Williams <Matthew.Williams@outlook.com.au> Co-authored-by: Nikolai Zahariev <nikolaiz@yahoo.com> Co-authored-by: kaakaa <stooner.hoe@gmail.com> Co-authored-by: aeomin <lin@aeomin.net> Co-authored-by: Weblate (bot) <hosted@weblate.org> Co-authored-by: JtheBAB <srast@bioc.uzh.ch> Co-authored-by: Kaya Zeren <kayazeren@gmail.com> Co-authored-by: Tóth Csaba // Online ERP Hungary Kft <csaba.toth@online-erp.hu> Co-authored-by: Matthew Williams <Matthew.Williams@outlook.com.au> Co-authored-by: Nikolai Zahariev <nikolaiz@yahoo.com> Co-authored-by: kaakaa <stooner.hoe@gmail.com> Co-authored-by: aeomin <lin@aeomin.net> * [MM-22051] Remove To/From JSON methods from model (#18138) * Scheme * Role * Session * Config * Status * Fix logic * Emoji * GuestsInvite * Group * Command * ClusterInfo * License * Job * System * Plugin * Command2 * IncomingWebhook * OutgoingWebhook * Fix tests * Update traslation * Some fixes * Add missing return * Simplify * Make Config.ToJSONFiltered() return []byte * Make Busy.ToJSON() return []byte * Include error in log * Split logic * [MM-22051] Remove To/From JSON (final) (#18150) * SwitchRequest * PluginEventData * Permalink * PushNotification * SuggestCommand * PluginsResponse * WebSocketMessage * RemoteCluster * SharedChannel * PluginStatuses * InitialLoad * ClusterDiscovery * ClusterStats * MfaSecret * GroupSyncable * SAML * WebSocketRequest * TypingRequest * SecurityBulletin * OAuthApp * IntegrationAction * DataRetention * Preference * FileInfoList * Compliance * Preferences * FileInfoSearchResults * TermsOfService * InstallMarketplacePluginRequest * GitLabUser * UploadSessions * Remove unused helpers * Fix tests * [MM-23280] Fix linting for ToJSON/FromJSON (#18153) * SwitchRequest * PluginEventData * Permalink * PushNotification * SuggestCommand * PluginsResponse * WebSocketMessage * RemoteCluster * SharedChannel * PluginStatuses * InitialLoad * ClusterDiscovery * ClusterStats * MfaSecret * GroupSyncable * SAML * WebSocketRequest * TypingRequest * SecurityBulletin * OAuthApp * IntegrationAction * DataRetention * Preference * FileInfoList * Compliance * Preferences * FileInfoSearchResults * TermsOfService * InstallMarketplacePluginRequest * GitLabUser * UploadSessions * Remove unused helpers * Fix tests * Fix linting for ToJSON/FromJSON * Fix conversions Co-authored-by: Weblate (bot) <hosted@weblate.org> Co-authored-by: JtheBAB <srast@bioc.uzh.ch> Co-authored-by: Kaya Zeren <kayazeren@gmail.com> Co-authored-by: Tóth Csaba // Online ERP Hungary Kft <csaba.toth@online-erp.hu> Co-authored-by: Matthew Williams <Matthew.Williams@outlook.com.au> Co-authored-by: Nikolai Zahariev <nikolaiz@yahoo.com> Co-authored-by: kaakaa <stooner.hoe@gmail.com> Co-authored-by: aeomin <lin@aeomin.net> Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
281 lines
7.8 KiB
Go
281 lines
7.8 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package api4
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"time"
|
|
|
|
"github.com/mattermost/mattermost-server/v6/audit"
|
|
"github.com/mattermost/mattermost-server/v6/model"
|
|
"github.com/mattermost/mattermost-server/v6/services/remotecluster"
|
|
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
|
)
|
|
|
|
func (api *API) InitRemoteCluster() {
|
|
api.BaseRoutes.RemoteCluster.Handle("/ping", api.RemoteClusterTokenRequired(remoteClusterPing)).Methods("POST")
|
|
api.BaseRoutes.RemoteCluster.Handle("/msg", api.RemoteClusterTokenRequired(remoteClusterAcceptMessage)).Methods("POST")
|
|
api.BaseRoutes.RemoteCluster.Handle("/confirm_invite", api.RemoteClusterTokenRequired(remoteClusterConfirmInvite)).Methods("POST")
|
|
api.BaseRoutes.RemoteCluster.Handle("/upload/{upload_id:[A-Za-z0-9]+}", api.RemoteClusterTokenRequired(uploadRemoteData)).Methods("POST")
|
|
api.BaseRoutes.RemoteCluster.Handle("/{user_id:[A-Za-z0-9]+}/image", api.RemoteClusterTokenRequired(remoteSetProfileImage)).Methods("POST")
|
|
}
|
|
|
|
func remoteClusterPing(c *Context, w http.ResponseWriter, r *http.Request) {
|
|
// make sure remote cluster service is enabled.
|
|
if _, appErr := c.App.GetRemoteClusterService(); appErr != nil {
|
|
c.Err = appErr
|
|
return
|
|
}
|
|
|
|
var frame model.RemoteClusterFrame
|
|
if jsonErr := json.NewDecoder(r.Body).Decode(&frame); jsonErr != nil {
|
|
c.Err = model.NewAppError("remoteClusterPing", "api.unmarshal_error", nil, jsonErr.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if appErr := frame.IsValid(); appErr != nil {
|
|
c.Err = appErr
|
|
return
|
|
}
|
|
|
|
remoteId := c.GetRemoteID(r)
|
|
if remoteId != frame.RemoteId {
|
|
c.SetInvalidRemoteIdError(frame.RemoteId)
|
|
return
|
|
}
|
|
|
|
rc, err := c.App.GetRemoteCluster(frame.RemoteId)
|
|
if err != nil {
|
|
c.SetInvalidRemoteIdError(frame.RemoteId)
|
|
return
|
|
}
|
|
|
|
var ping model.RemoteClusterPing
|
|
if jsonErr := json.Unmarshal(frame.Msg.Payload, &ping); jsonErr != nil {
|
|
c.SetInvalidParam("msg.payload")
|
|
return
|
|
}
|
|
ping.RecvAt = model.GetMillis()
|
|
|
|
if metrics := c.App.Metrics(); metrics != nil {
|
|
metrics.IncrementRemoteClusterMsgReceivedCounter(rc.RemoteId)
|
|
}
|
|
|
|
resp, _ := json.Marshal(&ping)
|
|
w.Write(resp)
|
|
}
|
|
|
|
func remoteClusterAcceptMessage(c *Context, w http.ResponseWriter, r *http.Request) {
|
|
// make sure remote cluster service is running.
|
|
service, appErr := c.App.GetRemoteClusterService()
|
|
if appErr != nil {
|
|
c.Err = appErr
|
|
return
|
|
}
|
|
|
|
var frame model.RemoteClusterFrame
|
|
if jsonErr := json.NewDecoder(r.Body).Decode(&frame); jsonErr != nil {
|
|
c.Err = model.NewAppError("remoteClusterAcceptMessage", "api.unmarshal_error", nil, jsonErr.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if appErr := frame.IsValid(); appErr != nil {
|
|
c.Err = appErr
|
|
return
|
|
}
|
|
|
|
auditRec := c.MakeAuditRecord("remoteClusterAcceptMessage", audit.Fail)
|
|
defer c.LogAuditRec(auditRec)
|
|
|
|
remoteId := c.GetRemoteID(r)
|
|
if remoteId != frame.RemoteId {
|
|
c.SetInvalidRemoteIdError(frame.RemoteId)
|
|
return
|
|
}
|
|
|
|
rc, err := c.App.GetRemoteCluster(frame.RemoteId)
|
|
if err != nil {
|
|
c.SetInvalidRemoteIdError(frame.RemoteId)
|
|
return
|
|
}
|
|
auditRec.AddMeta("remoteCluster", rc)
|
|
|
|
// pass message to Remote Cluster Service and write response
|
|
resp := service.ReceiveIncomingMsg(rc, frame.Msg)
|
|
|
|
b, errMarshall := json.Marshal(resp)
|
|
if errMarshall != nil {
|
|
c.Err = model.NewAppError("remoteClusterAcceptMessage", "api.marshal_error", nil, errMarshall.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
w.Write(b)
|
|
}
|
|
|
|
func remoteClusterConfirmInvite(c *Context, w http.ResponseWriter, r *http.Request) {
|
|
// make sure remote cluster service is running.
|
|
if _, appErr := c.App.GetRemoteClusterService(); appErr != nil {
|
|
c.Err = appErr
|
|
return
|
|
}
|
|
|
|
var frame model.RemoteClusterFrame
|
|
if jsonErr := json.NewDecoder(r.Body).Decode(&frame); jsonErr != nil {
|
|
c.Err = model.NewAppError("remoteClusterConfirmInvite", "api.unmarshal_error", nil, jsonErr.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if appErr := frame.IsValid(); appErr != nil {
|
|
c.Err = appErr
|
|
return
|
|
}
|
|
|
|
auditRec := c.MakeAuditRecord("remoteClusterAcceptInvite", audit.Fail)
|
|
defer c.LogAuditRec(auditRec)
|
|
|
|
remoteId := c.GetRemoteID(r)
|
|
if remoteId != frame.RemoteId {
|
|
c.SetInvalidRemoteIdError(frame.RemoteId)
|
|
return
|
|
}
|
|
|
|
rc, err := c.App.GetRemoteCluster(frame.RemoteId)
|
|
if err != nil {
|
|
c.SetInvalidRemoteIdError(frame.RemoteId)
|
|
return
|
|
}
|
|
auditRec.AddMeta("remoteCluster", rc)
|
|
|
|
if time.Since(model.GetTimeForMillis(rc.CreateAt)) > remotecluster.InviteExpiresAfter {
|
|
c.Err = model.NewAppError("remoteClusterAcceptMessage", "api.context.invitation_expired.error", nil, "", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var confirm model.RemoteClusterInvite
|
|
if jsonErr := json.Unmarshal(frame.Msg.Payload, &confirm); jsonErr != nil {
|
|
c.SetInvalidParam("msg.payload")
|
|
return
|
|
}
|
|
|
|
rc.RemoteTeamId = confirm.RemoteTeamId
|
|
rc.SiteURL = confirm.SiteURL
|
|
rc.RemoteToken = confirm.Token
|
|
|
|
if _, err := c.App.UpdateRemoteCluster(rc); err != nil {
|
|
c.Err = err
|
|
return
|
|
}
|
|
|
|
auditRec.Success()
|
|
ReturnStatusOK(w)
|
|
}
|
|
|
|
func uploadRemoteData(c *Context, w http.ResponseWriter, r *http.Request) {
|
|
if !*c.App.Config().FileSettings.EnableFileAttachments {
|
|
c.Err = model.NewAppError("uploadRemoteData", "api.file.attachments.disabled.app_error",
|
|
nil, "", http.StatusNotImplemented)
|
|
return
|
|
}
|
|
|
|
c.RequireUploadId()
|
|
if c.Err != nil {
|
|
return
|
|
}
|
|
|
|
auditRec := c.MakeAuditRecord("uploadRemoteData", audit.Fail)
|
|
defer c.LogAuditRec(auditRec)
|
|
auditRec.AddMeta("upload_id", c.Params.UploadId)
|
|
|
|
us, err := c.App.GetUploadSession(c.Params.UploadId)
|
|
if err != nil {
|
|
c.Err = err
|
|
return
|
|
}
|
|
|
|
if us.RemoteId != c.GetRemoteID(r) {
|
|
c.Err = model.NewAppError("uploadRemoteData", "api.context.remote_id_mismatch.app_error",
|
|
nil, "", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
info, err := doUploadData(c, us, r)
|
|
if err != nil {
|
|
c.Err = err
|
|
return
|
|
}
|
|
|
|
auditRec.Success()
|
|
|
|
if info == nil {
|
|
w.WriteHeader(http.StatusNoContent)
|
|
return
|
|
}
|
|
|
|
if err := json.NewEncoder(w).Encode(info); err != nil {
|
|
mlog.Warn("Error while writing response", mlog.Err(err))
|
|
}
|
|
}
|
|
|
|
func remoteSetProfileImage(c *Context, w http.ResponseWriter, r *http.Request) {
|
|
defer io.Copy(ioutil.Discard, r.Body)
|
|
|
|
c.RequireUserId()
|
|
if c.Err != nil {
|
|
return
|
|
}
|
|
|
|
if *c.App.Config().FileSettings.DriverName == "" {
|
|
c.Err = model.NewAppError("remoteUploadProfileImage", "api.user.upload_profile_user.storage.app_error", nil, "", http.StatusNotImplemented)
|
|
return
|
|
}
|
|
|
|
if r.ContentLength > *c.App.Config().FileSettings.MaxFileSize {
|
|
c.Err = model.NewAppError("remoteUploadProfileImage", "api.user.upload_profile_user.too_large.app_error", nil, "", http.StatusRequestEntityTooLarge)
|
|
return
|
|
}
|
|
|
|
if err := r.ParseMultipartForm(*c.App.Config().FileSettings.MaxFileSize); err != nil {
|
|
c.Err = model.NewAppError("remoteUploadProfileImage", "api.user.upload_profile_user.parse.app_error", nil, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
m := r.MultipartForm
|
|
imageArray, ok := m.File["image"]
|
|
if !ok {
|
|
c.Err = model.NewAppError("remoteUploadProfileImage", "api.user.upload_profile_user.no_file.app_error", nil, "", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if len(imageArray) == 0 {
|
|
c.Err = model.NewAppError("remoteUploadProfileImage", "api.user.upload_profile_user.array.app_error", nil, "", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
auditRec := c.MakeAuditRecord("remoteUploadProfileImage", audit.Fail)
|
|
defer c.LogAuditRec(auditRec)
|
|
if imageArray[0] != nil {
|
|
auditRec.AddMeta("filename", imageArray[0].Filename)
|
|
}
|
|
|
|
user, err := c.App.GetUser(c.Params.UserId)
|
|
if err != nil || !user.IsRemote() {
|
|
c.SetInvalidURLParam("user_id")
|
|
return
|
|
}
|
|
auditRec.AddMeta("user", user)
|
|
|
|
imageData := imageArray[0]
|
|
if err := c.App.SetProfileImage(c.Params.UserId, imageData); err != nil {
|
|
c.Err = err
|
|
return
|
|
}
|
|
|
|
auditRec.Success()
|
|
c.LogAudit("")
|
|
|
|
ReturnStatusOK(w)
|
|
}
|