PLT-2057 User as a first class object (#2648)

* Adding TeamMember to system

* Fixing all unit tests on the backend

* Fixing merge conflicts

* Fixing merge conflict

* Adding javascript unit tests

* Adding TeamMember to system

* Fixing all unit tests on the backend

* Fixing merge conflicts

* Fixing merge conflict

* Adding javascript unit tests

* Adding client side unit test

* Cleaning up the clint side tests

* Fixing msg

* Adding more client side unit tests

* Adding more using tests

* Adding last bit of client side unit tests and adding make cmd

* Fixing bad merge

* Fixing libraries

* Updating to new client side API

* Fixing borken unit test

* Fixing unit tests

* ugg...trying to beat gofmt

* ugg...trying to beat gofmt

* Cleaning up remainder of the server side routes

* Adding inital load api

* Increased coverage of webhook unit tests (#2660)

* Adding loading ... to root html

* Fixing bad merge

* Removing explicit content type so superagent will guess corectly (#2685)

* Fixing merge and unit tests

* Adding create team UI

* Fixing signup flows

* Adding LDAP unit tests and enterprise unit test helper (#2702)

* Add the ability to reset MFA from the commandline (#2706)

* Fixing compliance unit tests

* Fixing client side tests

* Adding open server to system console

* Moving websocket connection

* Fixing unit test

* Fixing unit tests

* Fixing unit tests

* Adding nickname and more LDAP unit tests (#2717)

* Adding join open teams

* Cleaning up all TODOs in the code

* Fixing web sockets

* Removing unused webockets file

* PLT-2533 Add the ability to reset a user's MFA from the system console (#2715)

* Add the ability to reset a user's MFA from the system console

* Add client side unit test for adminResetMfa

* Reorganizing authentication to fix LDAP error message (#2723)

* Fixing failing unit test

* Initial upgrade db code

* Adding upgrade script

* Fixing upgrade script after running on core

* Update OAuth and Claim routes to work with user model changes (#2739)

* Fixing perminant deletion. Adding ability to delete all user and the entire database (#2740)

* Fixing team invite ldap login call (#2741)

* Fixing bluebar and some img stuff

* Fix all the different file upload web utils (#2743)

* Fixing invalid session redirect (#2744)

* Redirect on bad channel name (#2746)

* Fixing a bunch of issue and removing dead code

* Patch to fix error message on leave channel (#2747)

* Setting EnableOpenServer to false by default

* Fixing config

* Fixing upgrade

* Fixing reported bugs

* Bug fixes for PLT-2057

* PLT-2563 Redo password recovery to use a database table (#2745)

* Redo password recovery to use a database table

* Update reset password audits

* Split out admin and user reset password APIs to be separate

* Delete password recovery when user is permanently deleted

* Consolidate password resetting into a single function

* Removed private channels as an option for outgoing webhooks (#2752)

* PLT-2577/PLT-2552 Fixes for backstage (#2753)

* Added URL to incoming webhook list

* Fixed client functions for adding/removing integrations

* Disallowed slash commands without trigger words

* Fixed clientside handling of errors on AddCommand page

* Minor auth cleanup (#2758)

* Changed EditPostModal to just close if you save without making any changes (#2759)

* Renamed client -> Client in async_client.jsx and fixed eslint warnings (#2756)

* Fixed url in channel info modal (#2755)

* Fixing reported issues

* Moving to version 3 of the apis

* Fixing command unit tests (#2760)

* Adding team admins

* Fixing DM issue

* Fixing eslint error

* Properly set EditPostModal's originalText state in all cases (#2762)

* Update client config check to assume features is defined if server is licensed (#2772)

* Fixing url link

* Fixing issue with websocket crashing when sending messages to different teams
This commit is contained in:
Corey Hulen 2016-04-21 22:37:01 -07:00
parent 5c755463ed
commit 2e5617c29b
268 changed files with 13214 additions and 9686 deletions

2
.gitignore vendored
View file

@ -47,6 +47,8 @@ _testmain.go
*mattermost.log
*npm-debug.log*
.tmp
# Vim temporary files
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]

5
Godeps/Godeps.json generated
View file

@ -9,6 +9,11 @@
"ImportPath": "github.com/NYTimes/gziphandler",
"Rev": "a88790d49798560db24af70fb6a10a66e2549a72"
},
{
"ImportPath": "github.com/gorilla/handlers",
"Comment": "v1.1-4-gd0f2612",
"Rev": "d0f261246491e3a8613039e90764460448dc05f5"
},
{
"ImportPath": "github.com/alecthomas/log4go",
"Rev": "8e9057c3b25c409a34c0b9737cdc82cbcafeabce"

View file

@ -0,0 +1,17 @@
language: go
sudo: false
matrix:
include:
- go: 1.4
- go: 1.5
- go: 1.6
install:
- go get golang.org/x/tools/cmd/vet
script:
- go get -t -v ./...
- diff -u <(echo -n) <(gofmt -d .)
- go tool vet .
- go test -v -race ./...

View file

@ -0,0 +1,22 @@
Copyright (c) 2013 The Gorilla Handlers Authors. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,53 @@
gorilla/handlers
================
[![GoDoc](https://godoc.org/github.com/gorilla/handlers?status.svg)](https://godoc.org/github.com/gorilla/handlers) [![Build Status](https://travis-ci.org/gorilla/handlers.svg?branch=master)](https://travis-ci.org/gorilla/handlers)
Package handlers is a collection of handlers (aka "HTTP middleware") for use
with Go's `net/http` package (or any framework supporting `http.Handler`), including:
* [**LoggingHandler**](https://godoc.org/github.com/gorilla/handlers#LoggingHandler) for logging HTTP requests in the Apache [Common Log
Format](http://httpd.apache.org/docs/2.2/logs.html#common).
* [**CombinedLoggingHandler**](https://godoc.org/github.com/gorilla/handlers#CombinedLoggingHandler) for logging HTTP requests in the Apache [Combined Log
Format](http://httpd.apache.org/docs/2.2/logs.html#combined) commonly used by
both Apache and nginx.
* [**CompressHandler**](https://godoc.org/github.com/gorilla/handlers#CompressHandler) for gzipping responses.
* [**ContentTypeHandler**](https://godoc.org/github.com/gorilla/handlers#ContentTypeHandler) for validating requests against a list of accepted
content types.
* [**MethodHandler**](https://godoc.org/github.com/gorilla/handlers#MethodHandler) for matching HTTP methods against handlers in a
`map[string]http.Handler`
* [**ProxyHeaders**](https://godoc.org/github.com/gorilla/handlers#ProxyHeaders) for populating `r.RemoteAddr` and `r.URL.Scheme` based on the
`X-Forwarded-For`, `X-Real-IP`, `X-Forwarded-Proto` and RFC7239 `Forwarded`
headers when running a Go server behind a HTTP reverse proxy.
* [**CanonicalHost**](https://godoc.org/github.com/gorilla/handlers#CanonicalHost) for re-directing to the preferred host when handling multiple
domains (i.e. multiple CNAME aliases).
* [**RecoveryHandler**](https://godoc.org/github.com/gorilla/handlers#RecoveryHandler) for recovering from unexpected panics.
Other handlers are documented [on the Gorilla
website](http://www.gorillatoolkit.org/pkg/handlers).
## Example
A simple example using `handlers.LoggingHandler` and `handlers.CompressHandler`:
```go
import (
"net/http"
"github.com/gorilla/handlers"
)
func main() {
r := http.NewServeMux()
// Only log requests to our admin dashboard to stdout
r.Handle("/admin", handlers.LoggingHandler(os.Stdout, http.HandlerFunc(ShowAdminDashboard)))
r.HandleFunc("/", ShowIndex)
// Wrap our server with our gzip handler to gzip compress all responses.
http.ListenAndServe(":8000", handlers.CompressHandler(r))
}
```
## License
BSD licensed. See the included LICENSE file for details.

View file

@ -0,0 +1,74 @@
package handlers
import (
"net/http"
"net/url"
"strings"
)
type canonical struct {
h http.Handler
domain string
code int
}
// CanonicalHost is HTTP middleware that re-directs requests to the canonical
// domain. It accepts a domain and a status code (e.g. 301 or 302) and
// re-directs clients to this domain. The existing request path is maintained.
//
// Note: If the provided domain is considered invalid by url.Parse or otherwise
// returns an empty scheme or host, clients are not re-directed.
//
// Example:
//
// r := mux.NewRouter()
// canonical := handlers.CanonicalHost("http://www.gorillatoolkit.org", 302)
// r.HandleFunc("/route", YourHandler)
//
// log.Fatal(http.ListenAndServe(":7000", canonical(r)))
//
func CanonicalHost(domain string, code int) func(h http.Handler) http.Handler {
fn := func(h http.Handler) http.Handler {
return canonical{h, domain, code}
}
return fn
}
func (c canonical) ServeHTTP(w http.ResponseWriter, r *http.Request) {
dest, err := url.Parse(c.domain)
if err != nil {
// Call the next handler if the provided domain fails to parse.
c.h.ServeHTTP(w, r)
return
}
if dest.Scheme == "" || dest.Host == "" {
// Call the next handler if the scheme or host are empty.
// Note that url.Parse won't fail on in this case.
c.h.ServeHTTP(w, r)
return
}
if !strings.EqualFold(cleanHost(r.Host), dest.Host) {
// Re-build the destination URL
dest := dest.Scheme + "://" + dest.Host + r.URL.Path
if r.URL.RawQuery != "" {
dest += "?" + r.URL.RawQuery
}
http.Redirect(w, r, dest, c.code)
return
}
c.h.ServeHTTP(w, r)
}
// cleanHost cleans invalid Host headers by stripping anything after '/' or ' '.
// This is backported from Go 1.5 (in response to issue #11206) and attempts to
// mitigate malformed Host headers that do not match the format in RFC7230.
func cleanHost(in string) string {
if i := strings.IndexAny(in, " /"); i != -1 {
return in[:i]
}
return in
}

View file

@ -0,0 +1,145 @@
// Copyright 2013 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package handlers
import (
"compress/flate"
"compress/gzip"
"io"
"net/http"
"strings"
)
type compressResponseWriter struct {
io.Writer
http.ResponseWriter
http.Hijacker
http.Flusher
http.CloseNotifier
}
func (w *compressResponseWriter) WriteHeader(c int) {
w.ResponseWriter.Header().Del("Content-Length")
w.ResponseWriter.WriteHeader(c)
}
func (w *compressResponseWriter) Header() http.Header {
return w.ResponseWriter.Header()
}
func (w *compressResponseWriter) Write(b []byte) (int, error) {
h := w.ResponseWriter.Header()
if h.Get("Content-Type") == "" {
h.Set("Content-Type", http.DetectContentType(b))
}
h.Del("Content-Length")
return w.Writer.Write(b)
}
type flusher interface {
Flush() error
}
func (w *compressResponseWriter) Flush() {
// Flush compressed data if compressor supports it.
if f, ok := w.Writer.(flusher); ok {
f.Flush()
}
// Flush HTTP response.
if w.Flusher != nil {
w.Flusher.Flush()
}
}
// CompressHandler gzip compresses HTTP responses for clients that support it
// via the 'Accept-Encoding' header.
func CompressHandler(h http.Handler) http.Handler {
return CompressHandlerLevel(h, gzip.DefaultCompression)
}
// CompressHandlerLevel gzip compresses HTTP responses with specified compression level
// for clients that support it via the 'Accept-Encoding' header.
//
// The compression level should be gzip.DefaultCompression, gzip.NoCompression,
// or any integer value between gzip.BestSpeed and gzip.BestCompression inclusive.
// gzip.DefaultCompression is used in case of invalid compression level.
func CompressHandlerLevel(h http.Handler, level int) http.Handler {
if level < gzip.DefaultCompression || level > gzip.BestCompression {
level = gzip.DefaultCompression
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
L:
for _, enc := range strings.Split(r.Header.Get("Accept-Encoding"), ",") {
switch strings.TrimSpace(enc) {
case "gzip":
w.Header().Set("Content-Encoding", "gzip")
w.Header().Add("Vary", "Accept-Encoding")
gw, _ := gzip.NewWriterLevel(w, level)
defer gw.Close()
h, hok := w.(http.Hijacker)
if !hok { /* w is not Hijacker... oh well... */
h = nil
}
f, fok := w.(http.Flusher)
if !fok {
f = nil
}
cn, cnok := w.(http.CloseNotifier)
if !cnok {
cn = nil
}
w = &compressResponseWriter{
Writer: gw,
ResponseWriter: w,
Hijacker: h,
Flusher: f,
CloseNotifier: cn,
}
break L
case "deflate":
w.Header().Set("Content-Encoding", "deflate")
w.Header().Add("Vary", "Accept-Encoding")
fw, _ := flate.NewWriter(w, level)
defer fw.Close()
h, hok := w.(http.Hijacker)
if !hok { /* w is not Hijacker... oh well... */
h = nil
}
f, fok := w.(http.Flusher)
if !fok {
f = nil
}
cn, cnok := w.(http.CloseNotifier)
if !cnok {
cn = nil
}
w = &compressResponseWriter{
Writer: fw,
ResponseWriter: w,
Hijacker: h,
Flusher: f,
CloseNotifier: cn,
}
break L
}
}
h.ServeHTTP(w, r)
})
}

View file

@ -0,0 +1,317 @@
package handlers
import (
"net/http"
"strconv"
"strings"
)
// CORSOption represents a functional option for configuring the CORS middleware.
type CORSOption func(*cors) error
type cors struct {
h http.Handler
allowedHeaders []string
allowedMethods []string
allowedOrigins []string
allowedOriginValidator OriginValidator
exposedHeaders []string
maxAge int
ignoreOptions bool
allowCredentials bool
}
// OriginValidator takes an origin string and returns whether or not that origin is allowed.
type OriginValidator func(string) bool
var (
defaultCorsMethods = []string{"GET", "HEAD", "POST"}
defaultCorsHeaders = []string{"Accept", "Accept-Language", "Content-Language", "Origin"}
// (WebKit/Safari v9 sends the Origin header by default in AJAX requests)
)
const (
corsOptionMethod string = "OPTIONS"
corsAllowOriginHeader string = "Access-Control-Allow-Origin"
corsExposeHeadersHeader string = "Access-Control-Expose-Headers"
corsMaxAgeHeader string = "Access-Control-Max-Age"
corsAllowMethodsHeader string = "Access-Control-Allow-Methods"
corsAllowHeadersHeader string = "Access-Control-Allow-Headers"
corsAllowCredentialsHeader string = "Access-Control-Allow-Credentials"
corsRequestMethodHeader string = "Access-Control-Request-Method"
corsRequestHeadersHeader string = "Access-Control-Request-Headers"
corsOriginHeader string = "Origin"
corsVaryHeader string = "Vary"
corsOriginMatchAll string = "*"
)
func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) {
origin := r.Header.Get(corsOriginHeader)
if !ch.isOriginAllowed(origin) {
ch.h.ServeHTTP(w, r)
return
}
if r.Method == corsOptionMethod {
if ch.ignoreOptions {
ch.h.ServeHTTP(w, r)
return
}
if _, ok := r.Header[corsRequestMethodHeader]; !ok {
w.WriteHeader(http.StatusBadRequest)
return
}
method := r.Header.Get(corsRequestMethodHeader)
if !ch.isMatch(method, ch.allowedMethods) {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
requestHeaders := strings.Split(r.Header.Get(corsRequestHeadersHeader), ",")
allowedHeaders := []string{}
for _, v := range requestHeaders {
canonicalHeader := http.CanonicalHeaderKey(strings.TrimSpace(v))
if canonicalHeader == "" || ch.isMatch(canonicalHeader, defaultCorsHeaders) {
continue
}
if !ch.isMatch(canonicalHeader, ch.allowedHeaders) {
w.WriteHeader(http.StatusForbidden)
return
}
allowedHeaders = append(allowedHeaders, canonicalHeader)
}
if len(allowedHeaders) > 0 {
w.Header().Set(corsAllowHeadersHeader, strings.Join(allowedHeaders, ","))
}
if ch.maxAge > 0 {
w.Header().Set(corsMaxAgeHeader, strconv.Itoa(ch.maxAge))
}
if !ch.isMatch(method, defaultCorsMethods) {
w.Header().Set(corsAllowMethodsHeader, method)
}
} else {
if len(ch.exposedHeaders) > 0 {
w.Header().Set(corsExposeHeadersHeader, strings.Join(ch.exposedHeaders, ","))
}
}
if ch.allowCredentials {
w.Header().Set(corsAllowCredentialsHeader, "true")
}
if len(ch.allowedOrigins) > 1 {
w.Header().Set(corsVaryHeader, corsOriginHeader)
}
w.Header().Set(corsAllowOriginHeader, origin)
if r.Method == corsOptionMethod {
return
}
ch.h.ServeHTTP(w, r)
}
// CORS provides Cross-Origin Resource Sharing middleware.
// Example:
//
// import (
// "net/http"
//
// "github.com/gorilla/handlers"
// "github.com/gorilla/mux"
// )
//
// func main() {
// r := mux.NewRouter()
// r.HandleFunc("/users", UserEndpoint)
// r.HandleFunc("/projects", ProjectEndpoint)
//
// // Apply the CORS middleware to our top-level router, with the defaults.
// http.ListenAndServe(":8000", handlers.CORS()(r))
// }
//
func CORS(opts ...CORSOption) func(http.Handler) http.Handler {
return func(h http.Handler) http.Handler {
ch := parseCORSOptions(opts...)
ch.h = h
return ch
}
}
func parseCORSOptions(opts ...CORSOption) *cors {
ch := &cors{
allowedMethods: defaultCorsMethods,
allowedHeaders: defaultCorsHeaders,
allowedOrigins: []string{corsOriginMatchAll},
}
for _, option := range opts {
option(ch)
}
return ch
}
//
// Functional options for configuring CORS.
//
// AllowedHeaders adds the provided headers to the list of allowed headers in a
// CORS request.
// This is an append operation so the headers Accept, Accept-Language,
// and Content-Language are always allowed.
// Content-Type must be explicitly declared if accepting Content-Types other than
// application/x-www-form-urlencoded, multipart/form-data, or text/plain.
func AllowedHeaders(headers []string) CORSOption {
return func(ch *cors) error {
for _, v := range headers {
normalizedHeader := http.CanonicalHeaderKey(strings.TrimSpace(v))
if normalizedHeader == "" {
continue
}
if !ch.isMatch(normalizedHeader, ch.allowedHeaders) {
ch.allowedHeaders = append(ch.allowedHeaders, normalizedHeader)
}
}
return nil
}
}
// AllowedMethods can be used to explicitly allow methods in the
// Access-Control-Allow-Methods header.
// This is a replacement operation so you must also
// pass GET, HEAD, and POST if you wish to support those methods.
func AllowedMethods(methods []string) CORSOption {
return func(ch *cors) error {
ch.allowedMethods = []string{}
for _, v := range methods {
normalizedMethod := strings.ToUpper(strings.TrimSpace(v))
if normalizedMethod == "" {
continue
}
if !ch.isMatch(normalizedMethod, ch.allowedMethods) {
ch.allowedMethods = append(ch.allowedMethods, normalizedMethod)
}
}
return nil
}
}
// AllowedOrigins sets the allowed origins for CORS requests, as used in the
// 'Allow-Access-Control-Origin' HTTP header.
// Note: Passing in a []string{"*"} will allow any domain.
func AllowedOrigins(origins []string) CORSOption {
return func(ch *cors) error {
for _, v := range origins {
if v == corsOriginMatchAll {
ch.allowedOrigins = []string{corsOriginMatchAll}
return nil
}
}
ch.allowedOrigins = origins
return nil
}
}
// AllowedOriginValidator sets a function for evaluating allowed origins in CORS requests, represented by the
// 'Allow-Access-Control-Origin' HTTP header.
func AllowedOriginValidator(fn OriginValidator) CORSOption {
return func(ch *cors) error {
ch.allowedOriginValidator = fn
return nil
}
}
// ExposeHeaders can be used to specify headers that are available
// and will not be stripped out by the user-agent.
func ExposedHeaders(headers []string) CORSOption {
return func(ch *cors) error {
ch.exposedHeaders = []string{}
for _, v := range headers {
normalizedHeader := http.CanonicalHeaderKey(strings.TrimSpace(v))
if normalizedHeader == "" {
continue
}
if !ch.isMatch(normalizedHeader, ch.exposedHeaders) {
ch.exposedHeaders = append(ch.exposedHeaders, normalizedHeader)
}
}
return nil
}
}
// MaxAge determines the maximum age (in seconds) between preflight requests. A
// maximum of 10 minutes is allowed. An age above this value will default to 10
// minutes.
func MaxAge(age int) CORSOption {
return func(ch *cors) error {
// Maximum of 10 minutes.
if age > 600 {
age = 600
}
ch.maxAge = age
return nil
}
}
// IgnoreOptions causes the CORS middleware to ignore OPTIONS requests, instead
// passing them through to the next handler. This is useful when your application
// or framework has a pre-existing mechanism for responding to OPTIONS requests.
func IgnoreOptions() CORSOption {
return func(ch *cors) error {
ch.ignoreOptions = true
return nil
}
}
// AllowCredentials can be used to specify that the user agent may pass
// authentication details along with the request.
func AllowCredentials() CORSOption {
return func(ch *cors) error {
ch.allowCredentials = true
return nil
}
}
func (ch *cors) isOriginAllowed(origin string) bool {
if origin == "" {
return false
}
if ch.allowedOriginValidator != nil {
return ch.allowedOriginValidator(origin)
}
for _, allowedOrigin := range ch.allowedOrigins {
if allowedOrigin == origin || allowedOrigin == corsOriginMatchAll {
return true
}
}
return false
}
func (ch *cors) isMatch(needle string, haystack []string) bool {
for _, v := range haystack {
if v == needle {
return true
}
}
return false
}

View file

@ -0,0 +1,9 @@
/*
Package handlers is a collection of handlers (aka "HTTP middleware") for use
with Go's net/http package (or any framework supporting http.Handler).
The package includes handlers for logging in standardised formats, compressing
HTTP responses, validating content types and other useful tools for manipulating
requests and responses.
*/
package handlers

View file

@ -0,0 +1,403 @@
// Copyright 2013 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package handlers
import (
"bufio"
"fmt"
"io"
"net"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
"time"
"unicode/utf8"
)
// MethodHandler is an http.Handler that dispatches to a handler whose key in the
// MethodHandler's map matches the name of the HTTP request's method, eg: GET
//
// If the request's method is OPTIONS and OPTIONS is not a key in the map then
// the handler responds with a status of 200 and sets the Allow header to a
// comma-separated list of available methods.
//
// If the request's method doesn't match any of its keys the handler responds
// with a status of HTTP 405 "Method Not Allowed" and sets the Allow header to a
// comma-separated list of available methods.
type MethodHandler map[string]http.Handler
func (h MethodHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
if handler, ok := h[req.Method]; ok {
handler.ServeHTTP(w, req)
} else {
allow := []string{}
for k := range h {
allow = append(allow, k)
}
sort.Strings(allow)
w.Header().Set("Allow", strings.Join(allow, ", "))
if req.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
} else {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
}
}
}
// loggingHandler is the http.Handler implementation for LoggingHandlerTo and its
// friends
type loggingHandler struct {
writer io.Writer
handler http.Handler
}
// combinedLoggingHandler is the http.Handler implementation for LoggingHandlerTo
// and its friends
type combinedLoggingHandler struct {
writer io.Writer
handler http.Handler
}
func (h loggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
t := time.Now()
logger := makeLogger(w)
url := *req.URL
h.handler.ServeHTTP(logger, req)
writeLog(h.writer, req, url, t, logger.Status(), logger.Size())
}
func (h combinedLoggingHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
t := time.Now()
logger := makeLogger(w)
url := *req.URL
h.handler.ServeHTTP(logger, req)
writeCombinedLog(h.writer, req, url, t, logger.Status(), logger.Size())
}
func makeLogger(w http.ResponseWriter) loggingResponseWriter {
var logger loggingResponseWriter = &responseLogger{w: w}
if _, ok := w.(http.Hijacker); ok {
logger = &hijackLogger{responseLogger{w: w}}
}
h, ok1 := logger.(http.Hijacker)
c, ok2 := w.(http.CloseNotifier)
if ok1 && ok2 {
return hijackCloseNotifier{logger, h, c}
}
if ok2 {
return &closeNotifyWriter{logger, c}
}
return logger
}
type loggingResponseWriter interface {
http.ResponseWriter
http.Flusher
Status() int
Size() int
}
// responseLogger is wrapper of http.ResponseWriter that keeps track of its HTTP
// status code and body size
type responseLogger struct {
w http.ResponseWriter
status int
size int
}
func (l *responseLogger) Header() http.Header {
return l.w.Header()
}
func (l *responseLogger) Write(b []byte) (int, error) {
if l.status == 0 {
// The status will be StatusOK if WriteHeader has not been called yet
l.status = http.StatusOK
}
size, err := l.w.Write(b)
l.size += size
return size, err
}
func (l *responseLogger) WriteHeader(s int) {
l.w.WriteHeader(s)
l.status = s
}
func (l *responseLogger) Status() int {
return l.status
}
func (l *responseLogger) Size() int {
return l.size
}
func (l *responseLogger) Flush() {
f, ok := l.w.(http.Flusher)
if ok {
f.Flush()
}
}
type hijackLogger struct {
responseLogger
}
func (l *hijackLogger) Hijack() (net.Conn, *bufio.ReadWriter, error) {
h := l.responseLogger.w.(http.Hijacker)
conn, rw, err := h.Hijack()
if err == nil && l.responseLogger.status == 0 {
// The status will be StatusSwitchingProtocols if there was no error and
// WriteHeader has not been called yet
l.responseLogger.status = http.StatusSwitchingProtocols
}
return conn, rw, err
}
type closeNotifyWriter struct {
loggingResponseWriter
http.CloseNotifier
}
type hijackCloseNotifier struct {
loggingResponseWriter
http.Hijacker
http.CloseNotifier
}
const lowerhex = "0123456789abcdef"
func appendQuoted(buf []byte, s string) []byte {
var runeTmp [utf8.UTFMax]byte
for width := 0; len(s) > 0; s = s[width:] {
r := rune(s[0])
width = 1
if r >= utf8.RuneSelf {
r, width = utf8.DecodeRuneInString(s)
}
if width == 1 && r == utf8.RuneError {
buf = append(buf, `\x`...)
buf = append(buf, lowerhex[s[0]>>4])
buf = append(buf, lowerhex[s[0]&0xF])
continue
}
if r == rune('"') || r == '\\' { // always backslashed
buf = append(buf, '\\')
buf = append(buf, byte(r))
continue
}
if strconv.IsPrint(r) {
n := utf8.EncodeRune(runeTmp[:], r)
buf = append(buf, runeTmp[:n]...)
continue
}
switch r {
case '\a':
buf = append(buf, `\a`...)
case '\b':
buf = append(buf, `\b`...)
case '\f':
buf = append(buf, `\f`...)
case '\n':
buf = append(buf, `\n`...)
case '\r':
buf = append(buf, `\r`...)
case '\t':
buf = append(buf, `\t`...)
case '\v':
buf = append(buf, `\v`...)
default:
switch {
case r < ' ':
buf = append(buf, `\x`...)
buf = append(buf, lowerhex[s[0]>>4])
buf = append(buf, lowerhex[s[0]&0xF])
case r > utf8.MaxRune:
r = 0xFFFD
fallthrough
case r < 0x10000:
buf = append(buf, `\u`...)
for s := 12; s >= 0; s -= 4 {
buf = append(buf, lowerhex[r>>uint(s)&0xF])
}
default:
buf = append(buf, `\U`...)
for s := 28; s >= 0; s -= 4 {
buf = append(buf, lowerhex[r>>uint(s)&0xF])
}
}
}
}
return buf
}
// buildCommonLogLine builds a log entry for req in Apache Common Log Format.
// ts is the timestamp with which the entry should be logged.
// status and size are used to provide the response HTTP status and size.
func buildCommonLogLine(req *http.Request, url url.URL, ts time.Time, status int, size int) []byte {
username := "-"
if url.User != nil {
if name := url.User.Username(); name != "" {
username = name
}
}
host, _, err := net.SplitHostPort(req.RemoteAddr)
if err != nil {
host = req.RemoteAddr
}
uri := req.RequestURI
// Requests using the CONNECT method over HTTP/2.0 must use
// the authority field (aka r.Host) to identify the target.
// Refer: https://httpwg.github.io/specs/rfc7540.html#CONNECT
if req.ProtoMajor == 2 && req.Method == "CONNECT" {
uri = req.Host
}
if uri == "" {
uri = url.RequestURI()
}
buf := make([]byte, 0, 3*(len(host)+len(username)+len(req.Method)+len(uri)+len(req.Proto)+50)/2)
buf = append(buf, host...)
buf = append(buf, " - "...)
buf = append(buf, username...)
buf = append(buf, " ["...)
buf = append(buf, ts.Format("02/Jan/2006:15:04:05 -0700")...)
buf = append(buf, `] "`...)
buf = append(buf, req.Method...)
buf = append(buf, " "...)
buf = appendQuoted(buf, uri)
buf = append(buf, " "...)
buf = append(buf, req.Proto...)
buf = append(buf, `" `...)
buf = append(buf, strconv.Itoa(status)...)
buf = append(buf, " "...)
buf = append(buf, strconv.Itoa(size)...)
return buf
}
// writeLog writes a log entry for req to w in Apache Common Log Format.
// ts is the timestamp with which the entry should be logged.
// status and size are used to provide the response HTTP status and size.
func writeLog(w io.Writer, req *http.Request, url url.URL, ts time.Time, status, size int) {
buf := buildCommonLogLine(req, url, ts, status, size)
buf = append(buf, '\n')
w.Write(buf)
}
// writeCombinedLog writes a log entry for req to w in Apache Combined Log Format.
// ts is the timestamp with which the entry should be logged.
// status and size are used to provide the response HTTP status and size.
func writeCombinedLog(w io.Writer, req *http.Request, url url.URL, ts time.Time, status, size int) {
buf := buildCommonLogLine(req, url, ts, status, size)
buf = append(buf, ` "`...)
buf = appendQuoted(buf, req.Referer())
buf = append(buf, `" "`...)
buf = appendQuoted(buf, req.UserAgent())
buf = append(buf, '"', '\n')
w.Write(buf)
}
// CombinedLoggingHandler return a http.Handler that wraps h and logs requests to out in
// Apache Combined Log Format.
//
// See http://httpd.apache.org/docs/2.2/logs.html#combined for a description of this format.
//
// LoggingHandler always sets the ident field of the log to -
func CombinedLoggingHandler(out io.Writer, h http.Handler) http.Handler {
return combinedLoggingHandler{out, h}
}
// LoggingHandler return a http.Handler that wraps h and logs requests to out in
// Apache Common Log Format (CLF).
//
// See http://httpd.apache.org/docs/2.2/logs.html#common for a description of this format.
//
// LoggingHandler always sets the ident field of the log to -
//
// Example:
//
// r := mux.NewRouter()
// r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// w.Write([]byte("This is a catch-all route"))
// })
// loggedRouter := handlers.LoggingHandler(os.Stdout, r)
// http.ListenAndServe(":1123", loggedRouter)
//
func LoggingHandler(out io.Writer, h http.Handler) http.Handler {
return loggingHandler{out, h}
}
// isContentType validates the Content-Type header matches the supplied
// contentType. That is, its type and subtype match.
func isContentType(h http.Header, contentType string) bool {
ct := h.Get("Content-Type")
if i := strings.IndexRune(ct, ';'); i != -1 {
ct = ct[0:i]
}
return ct == contentType
}
// ContentTypeHandler wraps and returns a http.Handler, validating the request
// content type is compatible with the contentTypes list. It writes a HTTP 415
// error if that fails.
//
// Only PUT, POST, and PATCH requests are considered.
func ContentTypeHandler(h http.Handler, contentTypes ...string) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !(r.Method == "PUT" || r.Method == "POST" || r.Method == "PATCH") {
h.ServeHTTP(w, r)
return
}
for _, ct := range contentTypes {
if isContentType(r.Header, ct) {
h.ServeHTTP(w, r)
return
}
}
http.Error(w, fmt.Sprintf("Unsupported content type %q; expected one of %q", r.Header.Get("Content-Type"), contentTypes), http.StatusUnsupportedMediaType)
})
}
const (
// HTTPMethodOverrideHeader is a commonly used
// http header to override a request method.
HTTPMethodOverrideHeader = "X-HTTP-Method-Override"
// HTTPMethodOverrideFormKey is a commonly used
// HTML form key to override a request method.
HTTPMethodOverrideFormKey = "_method"
)
// HTTPMethodOverrideHandler wraps and returns a http.Handler which checks for
// the X-HTTP-Method-Override header or the _method form key, and overrides (if
// valid) request.Method with its value.
//
// This is especially useful for HTTP clients that don't support many http verbs.
// It isn't secure to override e.g a GET to a POST, so only POST requests are
// considered. Likewise, the override method can only be a "write" method: PUT,
// PATCH or DELETE.
//
// Form method takes precedence over header method.
func HTTPMethodOverrideHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
om := r.FormValue(HTTPMethodOverrideFormKey)
if om == "" {
om = r.Header.Get(HTTPMethodOverrideHeader)
}
if om == "PUT" || om == "PATCH" || om == "DELETE" {
r.Method = om
}
}
h.ServeHTTP(w, r)
})
}

View file

@ -0,0 +1,113 @@
package handlers
import (
"net/http"
"regexp"
"strings"
)
var (
// De-facto standard header keys.
xForwardedFor = http.CanonicalHeaderKey("X-Forwarded-For")
xRealIP = http.CanonicalHeaderKey("X-Real-IP")
xForwardedProto = http.CanonicalHeaderKey("X-Forwarded-Scheme")
)
var (
// RFC7239 defines a new "Forwarded: " header designed to replace the
// existing use of X-Forwarded-* headers.
// e.g. Forwarded: for=192.0.2.60;proto=https;by=203.0.113.43
forwarded = http.CanonicalHeaderKey("Forwarded")
// Allows for a sub-match of the first value after 'for=' to the next
// comma, semi-colon or space. The match is case-insensitive.
forRegex = regexp.MustCompile(`(?i)(?:for=)([^(;|,| )]+)`)
// Allows for a sub-match for the first instance of scheme (http|https)
// prefixed by 'proto='. The match is case-insensitive.
protoRegex = regexp.MustCompile(`(?i)(?:proto=)(https|http)`)
)
// ProxyHeaders inspects common reverse proxy headers and sets the corresponding
// fields in the HTTP request struct. These are X-Forwarded-For and X-Real-IP
// for the remote (client) IP address, X-Forwarded-Proto for the scheme
// (http|https) and the RFC7239 Forwarded header, which may include both client
// IPs and schemes.
//
// NOTE: This middleware should only be used when behind a reverse
// proxy like nginx, HAProxy or Apache. Reverse proxies that don't (or are
// configured not to) strip these headers from client requests, or where these
// headers are accepted "as is" from a remote client (e.g. when Go is not behind
// a proxy), can manifest as a vulnerability if your application uses these
// headers for validating the 'trustworthiness' of a request.
func ProxyHeaders(h http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
// Set the remote IP with the value passed from the proxy.
if fwd := getIP(r); fwd != "" {
r.RemoteAddr = fwd
}
// Set the scheme (proto) with the value passed from the proxy.
if scheme := getScheme(r); scheme != "" {
r.URL.Scheme = scheme
}
// Call the next handler in the chain.
h.ServeHTTP(w, r)
}
return http.HandlerFunc(fn)
}
// getIP retrieves the IP from the X-Forwarded-For, X-Real-IP and RFC7239
// Forwarded headers (in that order).
func getIP(r *http.Request) string {
var addr string
if fwd := r.Header.Get(xForwardedFor); fwd != "" {
// Only grab the first (client) address. Note that '192.168.0.1,
// 10.1.1.1' is a valid key for X-Forwarded-For where addresses after
// the first may represent forwarding proxies earlier in the chain.
s := strings.Index(fwd, ", ")
if s == -1 {
s = len(fwd)
}
addr = fwd[:s]
} else if fwd := r.Header.Get(xRealIP); fwd != "" {
// X-Real-IP should only contain one IP address (the client making the
// request).
addr = fwd
} else if fwd := r.Header.Get(forwarded); fwd != "" {
// match should contain at least two elements if the protocol was
// specified in the Forwarded header. The first element will always be
// the 'for=' capture, which we ignore. In the case of multiple IP
// addresses (for=8.8.8.8, 8.8.4.4,172.16.1.20 is valid) we only
// extract the first, which should be the client IP.
if match := forRegex.FindStringSubmatch(fwd); len(match) > 1 {
// IPv6 addresses in Forwarded headers are quoted-strings. We strip
// these quotes.
addr = strings.Trim(match[1], `"`)
}
}
return addr
}
// getScheme retrieves the scheme from the X-Forwarded-Proto and RFC7239
// Forwarded headers (in that order).
func getScheme(r *http.Request) string {
var scheme string
// Retrieve the scheme from X-Forwarded-Proto.
if proto := r.Header.Get(xForwardedProto); proto != "" {
scheme = strings.ToLower(proto)
} else if proto := r.Header.Get(forwarded); proto != "" {
// match should contain at least two elements if the protocol was
// specified in the Forwarded header. The first element will always be
// the 'proto=' capture, which we ignore. In the case of multiple proto
// parameters (invalid) we only extract the first.
if match := protoRegex.FindStringSubmatch(proto); len(match) > 1 {
scheme = strings.ToLower(match[1])
}
}
return scheme
}

View file

@ -0,0 +1,86 @@
package handlers
import (
"log"
"net/http"
"runtime/debug"
)
type recoveryHandler struct {
handler http.Handler
logger *log.Logger
printStack bool
}
// RecoveryOption provides a functional approach to define
// configuration for a handler; such as setting the logging
// whether or not to print strack traces on panic.
type RecoveryOption func(http.Handler)
func parseRecoveryOptions(h http.Handler, opts ...RecoveryOption) http.Handler {
for _, option := range opts {
option(h)
}
return h
}
// RecoveryHandler is HTTP middleware that recovers from a panic,
// logs the panic, writes http.StatusInternalServerError, and
// continues to the next handler.
//
// Example:
//
// r := mux.NewRouter()
// r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// panic("Unexpected error!")
// })
//
// http.ListenAndServe(":1123", handlers.RecoveryHandler()(r))
func RecoveryHandler(opts ...RecoveryOption) func(h http.Handler) http.Handler {
return func(h http.Handler) http.Handler {
r := &recoveryHandler{handler: h}
return parseRecoveryOptions(r, opts...)
}
}
// RecoveryLogger is a functional option to override
// the default logger
func RecoveryLogger(logger *log.Logger) RecoveryOption {
return func(h http.Handler) {
r := h.(*recoveryHandler)
r.logger = logger
}
}
// PrintRecoveryStack is a functional option to enable
// or disable printing stack traces on panic.
func PrintRecoveryStack(print bool) RecoveryOption {
return func(h http.Handler) {
r := h.(*recoveryHandler)
r.printStack = print
}
}
func (h recoveryHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
defer func() {
if err := recover(); err != nil {
w.WriteHeader(http.StatusInternalServerError)
h.log(err)
}
}()
h.handler.ServeHTTP(w, req)
}
func (h recoveryHandler) log(message interface{}) {
if h.logger != nil {
h.logger.Println(message)
} else {
log.Println(message)
}
if h.printStack {
debug.PrintStack()
}
}

View file

@ -1,4 +1,4 @@
.PHONY: build package run stop run-client run-server stop-client stop-server restart-server restart-client start-docker clean-dist clean nuke check-style check-unit-tests test dist setup-mac prepare-enteprise build-linux build-osx build-windows
.PHONY: build package run stop run-client run-server stop-client stop-server restart-server restart-client start-docker clean-dist clean nuke check-style check-unit-tests test dist setup-mac prepare-enteprise run-client-tests setup-run-client-tests cleanup-run-client-tests test-client build-linux build-osx build-windows
# Build Flags
BUILD_NUMBER ?= $(BUILD_NUMBER:)
@ -63,10 +63,30 @@ start-docker:
echo starting mattermost-postgres; \
docker run --name mattermost-postgres -p 5432:5432 -e POSTGRES_USER=mmuser -e POSTGRES_PASSWORD=mostest \
-d postgres:9.4 > /dev/null; \
sleep 10; \
elif [ $(shell docker ps | grep -ci mattermost-postgres) -eq 0 ]; then \
echo restarting mattermost-postgres; \
docker start mattermost-postgres > /dev/null; \
fi
@echo Ldap test user test.one
@if [ $(shell docker ps -a | grep -ci mattermost-openldap) -eq 0 ]; then \
echo starting mattermost-openldap; \
docker run --name mattermost-openldap -p 389:389 -p 636:636 \
-e LDAP_TLS_VERIFY_CLIENT="never" \
-e LDAP_ORGANISATION="Mattermost Test" \
-e LDAP_DOMAIN="mm.test.com" \
-e LDAP_ADMIN_PASSWORD="mostest" \
-d osixia/openldap:1.1.2 > /dev/null;\
sleep 10; \
docker exec -ti mattermost-openldap bash -c 'echo -e "dn: ou=testusers,dc=mm,dc=test,dc=com\nobjectclass: organizationalunit" | ldapadd -x -D "cn=admin,dc=mm,dc=test,dc=com" -w mostest';\
docker exec -ti mattermost-openldap bash -c 'echo -e "dn: uid=test.one,ou=testusers,dc=mm,dc=test,dc=com\nobjectclass: iNetOrgPerson\nsn: User\ncn: Test1\nmail: success+testone@simulator.amazonses.com" | ldapadd -x -D "cn=admin,dc=mm,dc=test,dc=com" -w mostest';\
docker exec -ti mattermost-openldap bash -c 'ldappasswd -s Password1 -D "cn=admin,dc=mm,dc=test,dc=com" -x "uid=test.one,ou=testusers,dc=mm,dc=test,dc=com" -w mostest';\
docker exec -ti mattermost-openldap bash -c 'echo -e "dn: uid=test.two,ou=testusers,dc=mm,dc=test,dc=com\nobjectclass: iNetOrgPerson\nsn: User\ncn: Test2\nmail: success+testtwo@simulator.amazonses.com" | ldapadd -x -D "cn=admin,dc=mm,dc=test,dc=com" -w mostest';\
docker exec -ti mattermost-openldap bash -c 'ldappasswd -s Password1 -D "cn=admin,dc=mm,dc=test,dc=com" -x "uid=test.two,ou=testusers,dc=mm,dc=test,dc=com" -w mostest';\
docker exec -ti mattermost-openldap bash -c 'echo -e "dn: cn=tgroup,ou=testusers,dc=mm,dc=test,dc=com\nobjectclass: groupOfUniqueNames\nuniqueMember: uid=test.one,ou=testusers,dc=mm,dc=test,dc=com" | ldapadd -x -D "cn=admin,dc=mm,dc=test,dc=com" -w mostest';\
elif [ $(shell docker ps | grep -ci mattermost-openldap) -eq 0 ]; then \
echo restarting mattermost-openldap; \
docker start mattermost-openldap > /dev/null; \
sleep 10; \
fi
@ -82,22 +102,33 @@ stop-docker:
echo stopping mattermost-postgres; \
docker stop mattermost-postgres > /dev/null; \
fi
@if [ $(shell docker ps -a | grep -ci mattermost-openldap) -eq 1 ]; then \
echo stopping mattermost-openldap; \
docker stop mattermost-openldap > /dev/null; \
fi
clean-docker:
@echo Removing docker containers
@if [ $(shell docker ps -a | grep -ci mattermost-mysql) -eq 1 ]; then \
echo stopping mattermost-mysql; \
echo removing mattermost-mysql; \
docker stop mattermost-mysql > /dev/null; \
docker rm -v mattermost-mysql > /dev/null; \
fi
@if [ $(shell docker ps -a | grep -ci mattermost-postgres) -eq 1 ]; then \
echo stopping mattermost-postgres; \
echo removing mattermost-postgres; \
docker stop mattermost-postgres > /dev/null; \
docker rm -v mattermost-postgres > /dev/null; \
fi
@if [ $(shell docker ps -a | grep -ci mattermost-openldap) -eq 1 ]; then \
echo removing mattermost-openldap; \
docker stop mattermost-openldap > /dev/null; \
docker rm -v mattermost-openldap > /dev/null; \
fi
check-style:
@echo Running GOFMT
$(eval GOFMT_OUTPUT := $(shell gofmt -d -s api/ model/ store/ utils/ manualtesting/ einterfaces/ mattermost.go 2>&1))
@ -110,11 +141,32 @@ check-style:
fi
test: start-docker
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=180s ./api || exit 1
@echo Running tests
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=240s ./api || exit 1
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=12s ./model || exit 1
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./store || exit 1
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./utils || exit 1
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./web || exit 1
ifeq ($(BUILD_ENTERPRISE_READY),true)
@echo Running Enterprise tests
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s $(BUILD_ENTERPRISE_DIR)/ldap || exit 1
$(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s $(BUILD_ENTERPRISE_DIR)/compliance || exit 1
endif
setup-run-client-tests:
sed -i'.bak' 's|"EnableOpenServer": false,|"EnableOpenServer": true,|g' config/config.json
cleanup-run-client-tests:
sed -i'.bak' 's|"EnableOpenServer": true,|"EnableOpenServer": false,|g' config/config.json
run-client-tests:
cd $(BUILD_WEBAPP_DIR) && $(MAKE) test
sleep 10
@echo Running client side unit tests
cd $(BUILD_WEBAPP_DIR) && npm test
test-client: setup-run-client-tests run-server run-client-tests stop-server cleanup-run-client-tests
.prebuild:
@echo Preparation for running go code
@ -124,7 +176,7 @@ test: start-docker
prepare-enterprise:
ifeq ($(BUILD_ENTERPRISE_READY),true)
@echo Enterprise build selected, perparing
@echo Enterprise build selected, preparing
cp $(BUILD_ENTERPRISE_DIR)/imports.go .
endif

View file

@ -19,24 +19,25 @@ import (
"github.com/mssola/user_agent"
)
func InitAdmin(r *mux.Router) {
func InitAdmin() {
l4g.Debug(utils.T("api.admin.init.debug"))
sr := r.PathPrefix("/admin").Subrouter()
sr.Handle("/logs", ApiUserRequired(getLogs)).Methods("GET")
sr.Handle("/audits", ApiUserRequired(getAllAudits)).Methods("GET")
sr.Handle("/config", ApiUserRequired(getConfig)).Methods("GET")
sr.Handle("/save_config", ApiUserRequired(saveConfig)).Methods("POST")
sr.Handle("/test_email", ApiUserRequired(testEmail)).Methods("POST")
sr.Handle("/client_props", ApiAppHandler(getClientConfig)).Methods("GET")
sr.Handle("/log_client", ApiAppHandler(logClient)).Methods("POST")
sr.Handle("/analytics/{id:[A-Za-z0-9]+}/{name:[A-Za-z0-9_]+}", ApiUserRequired(getAnalytics)).Methods("GET")
sr.Handle("/analytics/{name:[A-Za-z0-9_]+}", ApiUserRequired(getAnalytics)).Methods("GET")
sr.Handle("/save_compliance_report", ApiUserRequired(saveComplianceReport)).Methods("POST")
sr.Handle("/compliance_reports", ApiUserRequired(getComplianceReports)).Methods("GET")
sr.Handle("/download_compliance_report/{id:[A-Za-z0-9]+}", ApiUserRequired(downloadComplianceReport)).Methods("GET")
sr.Handle("/upload_brand_image", ApiAdminSystemRequired(uploadBrandImage)).Methods("POST")
sr.Handle("/get_brand_image", ApiAppHandlerTrustRequester(getBrandImage)).Methods("GET")
BaseRoutes.Admin.Handle("/logs", ApiUserRequired(getLogs)).Methods("GET")
BaseRoutes.Admin.Handle("/audits", ApiUserRequired(getAllAudits)).Methods("GET")
BaseRoutes.Admin.Handle("/config", ApiUserRequired(getConfig)).Methods("GET")
BaseRoutes.Admin.Handle("/save_config", ApiUserRequired(saveConfig)).Methods("POST")
BaseRoutes.Admin.Handle("/test_email", ApiUserRequired(testEmail)).Methods("POST")
BaseRoutes.Admin.Handle("/client_props", ApiAppHandler(getClientConfig)).Methods("GET")
BaseRoutes.Admin.Handle("/log_client", ApiAppHandler(logClient)).Methods("POST")
BaseRoutes.Admin.Handle("/analytics/{id:[A-Za-z0-9]+}/{name:[A-Za-z0-9_]+}", ApiUserRequired(getAnalytics)).Methods("GET")
BaseRoutes.Admin.Handle("/analytics/{name:[A-Za-z0-9_]+}", ApiUserRequired(getAnalytics)).Methods("GET")
BaseRoutes.Admin.Handle("/save_compliance_report", ApiUserRequired(saveComplianceReport)).Methods("POST")
BaseRoutes.Admin.Handle("/compliance_reports", ApiUserRequired(getComplianceReports)).Methods("GET")
BaseRoutes.Admin.Handle("/download_compliance_report/{id:[A-Za-z0-9]+}", ApiUserRequired(downloadComplianceReport)).Methods("GET")
BaseRoutes.Admin.Handle("/upload_brand_image", ApiAdminSystemRequired(uploadBrandImage)).Methods("POST")
BaseRoutes.Admin.Handle("/get_brand_image", ApiAppHandlerTrustRequester(getBrandImage)).Methods("GET")
BaseRoutes.Admin.Handle("/reset_mfa", ApiAdminSystemRequired(adminResetMfa)).Methods("POST")
BaseRoutes.Admin.Handle("/reset_password", ApiAdminSystemRequired(adminResetPassword)).Methods("POST")
}
func getLogs(c *Context, w http.ResponseWriter, r *http.Request) {
@ -374,7 +375,7 @@ func getAnalytics(c *Context, w http.ResponseWriter, r *http.Request) {
iHookChan := Srv.Store.Webhook().AnalyticsIncomingCount(teamId)
oHookChan := Srv.Store.Webhook().AnalyticsOutgoingCount(teamId)
commandChan := Srv.Store.Command().AnalyticsCommandCount(teamId)
sessionChan := Srv.Store.Session().AnalyticsSessionCount(teamId)
sessionChan := Srv.Store.Session().AnalyticsSessionCount()
if r := <-fileChan; r.Err != nil {
c.Err = r.Err
@ -498,3 +499,51 @@ func getBrandImage(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write(img)
}
}
func adminResetMfa(c *Context, w http.ResponseWriter, r *http.Request) {
props := model.MapFromJson(r.Body)
userId := props["user_id"]
if len(userId) != 26 {
c.SetInvalidParam("adminResetMfa", "user_id")
return
}
if err := DeactivateMfa(userId); err != nil {
c.Err = err
return
}
c.LogAudit("")
rdata := map[string]string{}
rdata["status"] = "ok"
w.Write([]byte(model.MapToJson(rdata)))
}
func adminResetPassword(c *Context, w http.ResponseWriter, r *http.Request) {
props := model.MapFromJson(r.Body)
userId := props["user_id"]
if len(userId) != 26 {
c.SetInvalidParam("adminResetPassword", "user_id")
return
}
newPassword := props["new_password"]
if len(newPassword) < model.MIN_PASSWORD_LENGTH {
c.SetInvalidParam("adminResetPassword", "new_password")
return
}
if err := ResetPassword(c, userId, newPassword); err != nil {
c.Err = err
return
}
c.LogAudit("")
rdata := map[string]string{}
rdata["status"] = "ok"
w.Write([]byte(model.MapToJson(rdata)))
}

View file

@ -7,33 +7,18 @@ import (
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
"strings"
"testing"
)
func TestGetLogs(t *testing.T) {
Setup()
th := Setup().InitSystemAdmin().InitBasic()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
if _, err := Client.GetLogs(); err == nil {
if _, err := th.BasicClient.GetLogs(); err == nil {
t.Fatal("Shouldn't have permissions")
}
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
if logs, err := Client.GetLogs(); err != nil {
if logs, err := th.SystemAdminClient.GetLogs(); err != nil {
t.Fatal(err)
} else if len(logs.Data.([]string)) <= 0 {
t.Fatal()
@ -41,29 +26,13 @@ func TestGetLogs(t *testing.T) {
}
func TestGetAllAudits(t *testing.T) {
Setup()
th := Setup().InitBasic().InitSystemAdmin()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
if _, err := Client.GetAllAudits(); err == nil {
if _, err := th.BasicClient.GetAllAudits(); err == nil {
t.Fatal("Shouldn't have permissions")
}
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
if audits, err := Client.GetAllAudits(); err != nil {
if audits, err := th.SystemAdminClient.GetAllAudits(); err != nil {
t.Fatal(err)
} else if len(audits.Data.(model.Audits)) <= 0 {
t.Fatal()
@ -71,9 +40,9 @@ func TestGetAllAudits(t *testing.T) {
}
func TestGetClientProperties(t *testing.T) {
Setup()
th := Setup().InitBasic()
if result, err := Client.GetClientProperties(); err != nil {
if result, err := th.BasicClient.GetClientProperties(); err != nil {
t.Fatal(err)
} else {
props := result.Data.(map[string]string)
@ -85,29 +54,13 @@ func TestGetClientProperties(t *testing.T) {
}
func TestGetConfig(t *testing.T) {
Setup()
th := Setup().InitBasic().InitSystemAdmin()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
if _, err := Client.GetConfig(); err == nil {
if _, err := th.BasicClient.GetConfig(); err == nil {
t.Fatal("Shouldn't have permissions")
}
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
if result, err := Client.GetConfig(); err != nil {
if result, err := th.SystemAdminClient.GetConfig(); err != nil {
t.Fatal(err)
} else {
cfg := result.Data.(*model.Config)
@ -119,29 +72,15 @@ func TestGetConfig(t *testing.T) {
}
func TestSaveConfig(t *testing.T) {
Setup()
th := Setup().InitBasic().InitSystemAdmin()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
if _, err := Client.SaveConfig(utils.Cfg); err == nil {
if _, err := th.BasicClient.SaveConfig(utils.Cfg); err == nil {
t.Fatal("Shouldn't have permissions")
}
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
*utils.Cfg.TeamSettings.EnableOpenServer = false
Client.LoginByEmail(team.Name, user.Email, "pwd")
if result, err := Client.SaveConfig(utils.Cfg); err != nil {
if result, err := th.SystemAdminClient.SaveConfig(utils.Cfg); err != nil {
t.Fatal(err)
} else {
cfg := result.Data.(*model.Config)
@ -150,66 +89,31 @@ func TestSaveConfig(t *testing.T) {
t.Fatal()
}
}
*utils.Cfg.TeamSettings.EnableOpenServer = true
}
func TestEmailTest(t *testing.T) {
Setup()
th := Setup().InitBasic().InitSystemAdmin()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
if _, err := Client.TestEmail(utils.Cfg); err == nil {
if _, err := th.BasicClient.TestEmail(utils.Cfg); err == nil {
t.Fatal("Shouldn't have permissions")
}
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
if _, err := Client.TestEmail(utils.Cfg); err != nil {
if _, err := th.SystemAdminClient.TestEmail(utils.Cfg); err != nil {
t.Fatal(err)
}
}
func TestGetTeamAnalyticsStandard(t *testing.T) {
Setup()
th := Setup().InitBasic().InitSystemAdmin()
th.CreatePrivateChannel(th.BasicClient, th.BasicTeam)
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
post1 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
if _, err := Client.GetTeamAnalytics(team.Id, "standard"); err == nil {
if _, err := th.BasicClient.GetTeamAnalytics(th.BasicTeam.Id, "standard"); err == nil {
t.Fatal("Shouldn't have permissions")
}
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
if result, err := Client.GetTeamAnalytics(team.Id, "standard"); err != nil {
if result, err := th.SystemAdminClient.GetTeamAnalytics(th.BasicTeam.Id, "standard"); err != nil {
t.Fatal(err)
} else {
rows := result.Data.(model.AnalyticsRows)
@ -219,7 +123,7 @@ func TestGetTeamAnalyticsStandard(t *testing.T) {
t.Fatal()
}
if rows[0].Value != 2 {
if rows[0].Value != 3 {
t.Log(rows.ToJson())
t.Fatal()
}
@ -249,7 +153,7 @@ func TestGetTeamAnalyticsStandard(t *testing.T) {
t.Fatal()
}
if rows[3].Value != 1 {
if rows[3].Value != 2 {
t.Log(rows.ToJson())
t.Fatal()
}
@ -265,7 +169,7 @@ func TestGetTeamAnalyticsStandard(t *testing.T) {
}
}
if result, err := Client.GetSystemAnalytics("standard"); err != nil {
if result, err := th.SystemAdminClient.GetSystemAnalytics("standard"); err != nil {
t.Fatal(err)
} else {
rows := result.Data.(model.AnalyticsRows)
@ -275,7 +179,7 @@ func TestGetTeamAnalyticsStandard(t *testing.T) {
t.Fatal()
}
if rows[0].Value < 2 {
if rows[0].Value < 3 {
t.Log(rows.ToJson())
t.Fatal()
}
@ -323,39 +227,17 @@ func TestGetTeamAnalyticsStandard(t *testing.T) {
}
func TestGetPostCount(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
post1 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
th := Setup().InitBasic().InitSystemAdmin()
// manually update creation time, since it's always set to 0 upon saving and we only retrieve posts < today
Srv.Store.(*store.SqlStore).GetMaster().Exec("UPDATE Posts SET CreateAt = :CreateAt WHERE ChannelId = :ChannelId",
map[string]interface{}{"ChannelId": channel1.Id, "CreateAt": utils.MillisFromTime(utils.Yesterday())})
map[string]interface{}{"ChannelId": th.BasicChannel.Id, "CreateAt": utils.MillisFromTime(utils.Yesterday())})
if _, err := Client.GetTeamAnalytics(team.Id, "post_counts_day"); err == nil {
if _, err := th.BasicClient.GetTeamAnalytics(th.BasicTeam.Id, "post_counts_day"); err == nil {
t.Fatal("Shouldn't have permissions")
}
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
if result, err := Client.GetTeamAnalytics(team.Id, "post_counts_day"); err != nil {
if result, err := th.SystemAdminClient.GetTeamAnalytics(th.BasicTeam.Id, "post_counts_day"); err != nil {
t.Fatal(err)
} else {
rows := result.Data.(model.AnalyticsRows)
@ -368,39 +250,17 @@ func TestGetPostCount(t *testing.T) {
}
func TestUserCountsWithPostsByDay(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
post1 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
th := Setup().InitBasic().InitSystemAdmin()
// manually update creation time, since it's always set to 0 upon saving and we only retrieve posts < today
Srv.Store.(*store.SqlStore).GetMaster().Exec("UPDATE Posts SET CreateAt = :CreateAt WHERE ChannelId = :ChannelId",
map[string]interface{}{"ChannelId": channel1.Id, "CreateAt": utils.MillisFromTime(utils.Yesterday())})
map[string]interface{}{"ChannelId": th.BasicChannel.Id, "CreateAt": utils.MillisFromTime(utils.Yesterday())})
if _, err := Client.GetTeamAnalytics(team.Id, "user_counts_with_posts_day"); err == nil {
if _, err := th.BasicClient.GetTeamAnalytics(th.BasicTeam.Id, "user_counts_with_posts_day"); err == nil {
t.Fatal("Shouldn't have permissions")
}
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
if result, err := Client.GetTeamAnalytics(team.Id, "user_counts_with_posts_day"); err != nil {
if result, err := th.SystemAdminClient.GetTeamAnalytics(th.BasicTeam.Id, "user_counts_with_posts_day"); err != nil {
t.Fatal(err)
} else {
rows := result.Data.(model.AnalyticsRows)
@ -413,38 +273,15 @@ func TestUserCountsWithPostsByDay(t *testing.T) {
}
func TestGetTeamAnalyticsExtra(t *testing.T) {
Setup()
th := Setup().InitBasic().InitSystemAdmin()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
th.CreatePost(th.BasicClient, th.BasicChannel)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
post1 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
post2 := &model.Post{ChannelId: channel1.Id, Message: "#test a" + model.NewId() + "a"}
post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
if _, err := Client.GetTeamAnalytics("", "extra_counts"); err == nil {
if _, err := th.BasicClient.GetTeamAnalytics("", "extra_counts"); err == nil {
t.Fatal("Shouldn't have permissions")
}
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
if result, err := Client.GetTeamAnalytics(team.Id, "extra_counts"); err != nil {
if result, err := th.SystemAdminClient.GetTeamAnalytics(th.BasicTeam.Id, "extra_counts"); err != nil {
t.Fatal(err)
} else {
rows := result.Data.(model.AnalyticsRows)
@ -464,7 +301,7 @@ func TestGetTeamAnalyticsExtra(t *testing.T) {
t.Fatal()
}
if rows[1].Value != 1 {
if rows[1].Value != 0 {
t.Log(rows.ToJson())
t.Fatal()
}
@ -510,7 +347,7 @@ func TestGetTeamAnalyticsExtra(t *testing.T) {
}
}
if result, err := Client.GetSystemAnalytics("extra_counts"); err != nil {
if result, err := th.SystemAdminClient.GetSystemAnalytics("extra_counts"); err != nil {
t.Fatal(err)
} else {
rows := result.Data.(model.AnalyticsRows)
@ -525,11 +362,6 @@ func TestGetTeamAnalyticsExtra(t *testing.T) {
t.Fatal()
}
if rows[1].Value < 1 {
t.Log(rows.ToJson())
t.Fatal()
}
if rows[2].Name != "incoming_webhook_count" {
t.Log(rows.ToJson())
t.Fatal()
@ -551,3 +383,73 @@ func TestGetTeamAnalyticsExtra(t *testing.T) {
}
}
}
func TestAdminResetMfa(t *testing.T) {
th := Setup().InitBasic().InitSystemAdmin()
if _, err := th.BasicClient.AdminResetMfa("12345678901234567890123456"); err == nil {
t.Fatal("should have failed - not an admin")
}
if _, err := th.SystemAdminClient.AdminResetMfa(""); err == nil {
t.Fatal("should have failed - empty user id")
}
if _, err := th.SystemAdminClient.AdminResetMfa("12345678901234567890123456"); err == nil {
t.Fatal("should have failed - bad user id")
}
if _, err := th.SystemAdminClient.AdminResetMfa(th.BasicUser.Id); err == nil {
t.Fatal("should have failed - not licensed or configured")
}
// need to add more test cases when enterprise bits can be loaded into tests
}
func TestAdminResetPassword(t *testing.T) {
th := Setup().InitSystemAdmin()
Client := th.SystemAdminClient
team := th.SystemAdminTeam
user := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
LinkUserToTeam(user, team)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
if _, err := Client.AdminResetPassword("", "newpwd"); err == nil {
t.Fatal("Should have errored - empty user id")
}
if _, err := Client.AdminResetPassword("123", "newpwd"); err == nil {
t.Fatal("Should have errored - bad user id")
}
if _, err := Client.AdminResetPassword("12345678901234567890123456", "newpwd"); err == nil {
t.Fatal("Should have errored - bad user id")
}
if _, err := Client.AdminResetPassword("12345678901234567890123456", "newp"); err == nil {
t.Fatal("Should have errored - password too short")
}
user2 := &model.User{Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", AuthData: "1", AuthService: "random"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
LinkUserToTeam(user2, team)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
if _, err := Client.AdminResetPassword(user2.Id, "newpwd"); err == nil {
t.Fatal("should have errored - SSO user can't reset password")
}
if _, err := Client.AdminResetPassword(user.Id, "newpwd"); err != nil {
t.Fatal(err)
}
Client.Logout()
Client.Must(Client.LoginById(user.Id, "newpwd"))
Client.SetTeamId(team.Id)
if _, err := Client.AdminResetPassword(user.Id, "newpwd"); err == nil {
t.Fatal("Should have errored - not sytem admin")
}
}

View file

@ -6,6 +6,7 @@ package api
import (
"net/http"
"github.com/gorilla/mux"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
@ -13,20 +14,71 @@ import (
_ "github.com/nicksnyder/go-i18n/i18n"
)
type Routes struct {
Root *mux.Router // ''
ApiRoot *mux.Router // 'api/v3'
Users *mux.Router // 'api/v3/users'
NeedUser *mux.Router // 'api/v3/users/{user_id:[A-Za-z0-9]+}'
Teams *mux.Router // 'api/v3/teams'
NeedTeam *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}'
Channels *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels'
NeedChannel *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels/{channel_id:[A-Za-z0-9]+}'
Posts *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels/{channel_id:[A-Za-z0-9]+}/posts'
NeedPost *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/channels/{channel_id:[A-Za-z0-9]+}/posts/{post_id:[A-Za-z0-9]+}'
Commands *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/commands'
Hooks *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/hooks'
Files *mux.Router // 'api/v3/teams/{team_id:[A-Za-z0-9]+}/files'
OAuth *mux.Router // 'api/v3/oauth'
Admin *mux.Router // 'api/v3/admin'
Preferences *mux.Router // 'api/v3/preferences'
License *mux.Router // 'api/v3/license'
}
var BaseRoutes *Routes
func InitApi() {
r := Srv.Router.PathPrefix("/api/v1").Subrouter()
InitUser(r)
InitTeam(r)
InitChannel(r)
InitPost(r)
InitWebSocket(r)
InitFile(r)
InitCommand(r)
InitAdmin(r)
InitOAuth(r)
InitWebhook(r)
InitPreference(r)
InitLicense(r)
BaseRoutes = &Routes{}
BaseRoutes.Root = Srv.Router
BaseRoutes.ApiRoot = Srv.Router.PathPrefix(model.API_URL_SUFFIX).Subrouter()
BaseRoutes.Users = BaseRoutes.ApiRoot.PathPrefix("/users").Subrouter()
BaseRoutes.NeedUser = BaseRoutes.Users.PathPrefix("/{user_id:[A-Za-z0-9]+}").Subrouter()
BaseRoutes.Teams = BaseRoutes.ApiRoot.PathPrefix("/teams").Subrouter()
BaseRoutes.NeedTeam = BaseRoutes.Teams.PathPrefix("/{team_id:[A-Za-z0-9]+}").Subrouter()
BaseRoutes.Channels = BaseRoutes.NeedTeam.PathPrefix("/channels").Subrouter()
BaseRoutes.NeedChannel = BaseRoutes.Channels.PathPrefix("/{channel_id:[A-Za-z0-9]+}").Subrouter()
BaseRoutes.Posts = BaseRoutes.NeedChannel.PathPrefix("/posts").Subrouter()
BaseRoutes.NeedPost = BaseRoutes.Posts.PathPrefix("/{post_id:[A-Za-z0-9]+}").Subrouter()
BaseRoutes.Commands = BaseRoutes.NeedTeam.PathPrefix("/commands").Subrouter()
BaseRoutes.Files = BaseRoutes.NeedTeam.PathPrefix("/files").Subrouter()
BaseRoutes.Hooks = BaseRoutes.NeedTeam.PathPrefix("/hooks").Subrouter()
BaseRoutes.OAuth = BaseRoutes.ApiRoot.PathPrefix("/oauth").Subrouter()
BaseRoutes.Admin = BaseRoutes.ApiRoot.PathPrefix("/admin").Subrouter()
BaseRoutes.Preferences = BaseRoutes.ApiRoot.PathPrefix("/preferences").Subrouter()
BaseRoutes.License = BaseRoutes.ApiRoot.PathPrefix("/license").Subrouter()
InitUser()
InitTeam()
InitChannel()
InitPost()
InitWebSocket()
InitFile()
InitCommand()
InitAdmin()
InitOAuth()
InitWebhook()
InitPreference()
InitLicense()
// 404 on any api route before web.go has a chance to serve it
Srv.Router.Handle("/api/{anything:.*}", http.HandlerFunc(Handle404))

View file

@ -1,47 +0,0 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package api
import (
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
)
var Client *model.Client
func Setup() {
if Srv == nil {
utils.LoadConfig("config.json")
utils.InitTranslations()
utils.Cfg.TeamSettings.MaxUsersPerTeam = 50
NewServer()
StartServer()
InitApi()
Client = model.NewClient("http://localhost" + utils.Cfg.ServiceSettings.ListenAddress)
Srv.Store.MarkSystemRanUnitTests()
}
}
func SetupBenchmark() (*model.Team, *model.User, *model.Channel) {
Setup()
team := &model.Team{DisplayName: "Benchmark Team", Name: "z-z-" + model.NewId() + "a", Email: "benchmark@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Mr. Benchmarker", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
channel := &model.Channel{DisplayName: "Benchmark Channel", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel = Client.Must(Client.CreateChannel(channel)).Data.(*model.Channel)
return team, user, channel
}
func TearDown() {
if Srv != nil {
StopServer()
}
}

223
api/apitestlib.go Normal file
View file

@ -0,0 +1,223 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package api
import (
"time"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
l4g "github.com/alecthomas/log4go"
)
type TestHelper struct {
BasicClient *model.Client
BasicTeam *model.Team
BasicUser *model.User
BasicUser2 *model.User
BasicChannel *model.Channel
BasicPost *model.Post
SystemAdminClient *model.Client
SystemAdminTeam *model.Team
SystemAdminUser *model.User
SystemAdminChannel *model.Channel
}
func SetupEnterprise(platformDir string) *TestHelper {
if Srv == nil {
utils.LoadConfig(platformDir + "/config/config.json")
utils.InitTranslationsWithDir(platformDir + "/i18n")
utils.Cfg.TeamSettings.MaxUsersPerTeam = 50
utils.DisableDebugLogForTest()
utils.License.Features.SetDefaults()
NewServer()
StartServer()
utils.InitHTMLWithDir(platformDir + "/templates")
InitApi()
utils.EnableDebugLogForTest()
Srv.Store.MarkSystemRanUnitTests()
*utils.Cfg.TeamSettings.EnableOpenServer = true
}
return &TestHelper{}
}
func Setup() *TestHelper {
if Srv == nil {
utils.LoadConfig("config.json")
utils.InitTranslations()
utils.Cfg.TeamSettings.MaxUsersPerTeam = 50
utils.DisableDebugLogForTest()
NewServer()
StartServer()
InitApi()
utils.EnableDebugLogForTest()
Srv.Store.MarkSystemRanUnitTests()
*utils.Cfg.TeamSettings.EnableOpenServer = true
}
return &TestHelper{}
}
func (me *TestHelper) InitBasic() *TestHelper {
me.BasicClient = me.CreateClient()
me.BasicTeam = me.CreateTeam(me.BasicClient)
me.BasicUser = me.CreateUser(me.BasicClient)
LinkUserToTeam(me.BasicUser, me.BasicTeam)
me.BasicUser2 = me.CreateUser(me.BasicClient)
LinkUserToTeam(me.BasicUser2, me.BasicTeam)
me.BasicClient.SetTeamId(me.BasicTeam.Id)
me.LoginBasic()
me.BasicChannel = me.CreateChannel(me.BasicClient, me.BasicTeam)
me.BasicPost = me.CreatePost(me.BasicClient, me.BasicChannel)
return me
}
func (me *TestHelper) InitSystemAdmin() *TestHelper {
me.SystemAdminClient = me.CreateClient()
me.SystemAdminTeam = me.CreateTeam(me.SystemAdminClient)
me.SystemAdminUser = me.CreateUser(me.SystemAdminClient)
LinkUserToTeam(me.SystemAdminUser, me.SystemAdminTeam)
me.SystemAdminClient.SetTeamId(me.SystemAdminTeam.Id)
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, me.SystemAdminUser, model.ROLE_SYSTEM_ADMIN)
me.SystemAdminUser.Password = "Password1"
me.LoginSystemAdmin()
me.SystemAdminChannel = me.CreateChannel(me.SystemAdminClient, me.SystemAdminTeam)
return me
}
func (me *TestHelper) CreateClient() *model.Client {
return model.NewClient("http://localhost" + utils.Cfg.ServiceSettings.ListenAddress)
}
func (me *TestHelper) CreateTeam(client *model.Client) *model.Team {
id := model.NewId()
team := &model.Team{
DisplayName: "dn_" + id,
Name: "name" + id,
Email: "success+" + id + "@simulator.amazonses.com",
Type: model.TEAM_OPEN,
}
utils.DisableDebugLogForTest()
r := client.Must(client.CreateTeam(team)).Data.(*model.Team)
utils.EnableDebugLogForTest()
return r
}
func (me *TestHelper) CreateUser(client *model.Client) *model.User {
id := model.NewId()
user := &model.User{
Email: "success+" + id + "@simulator.amazonses.com",
Username: "un_" + id,
Nickname: "nn_" + id,
Password: "Password1",
}
utils.DisableDebugLogForTest()
ruser := client.Must(client.CreateUser(user, "")).Data.(*model.User)
ruser.Password = "Password1"
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
utils.EnableDebugLogForTest()
return ruser
}
func LinkUserToTeam(user *model.User, team *model.Team) {
utils.DisableDebugLogForTest()
err := JoinUserToTeam(team, user)
if err != nil {
l4g.Error(err.Error())
l4g.Close()
time.Sleep(time.Second)
panic(err)
}
utils.EnableDebugLogForTest()
}
func UpdateUserToTeamAdmin(user *model.User, team *model.Team) {
utils.DisableDebugLogForTest()
tm := &model.TeamMember{TeamId: team.Id, UserId: user.Id, Roles: model.ROLE_TEAM_ADMIN}
if tmr := <-Srv.Store.Team().UpdateMember(tm); tmr.Err != nil {
l4g.Error(tmr.Err.Error())
l4g.Close()
time.Sleep(time.Second)
panic(tmr.Err)
}
}
func (me *TestHelper) CreateChannel(client *model.Client, team *model.Team) *model.Channel {
return me.createChannel(client, team, model.CHANNEL_OPEN)
}
func (me *TestHelper) CreatePrivateChannel(client *model.Client, team *model.Team) *model.Channel {
return me.createChannel(client, team, model.CHANNEL_PRIVATE)
}
func (me *TestHelper) createChannel(client *model.Client, team *model.Team, channelType string) *model.Channel {
id := model.NewId()
channel := &model.Channel{
DisplayName: "dn_" + id,
Name: "name_" + id,
Type: channelType,
TeamId: team.Id,
}
utils.DisableDebugLogForTest()
r := client.Must(client.CreateChannel(channel)).Data.(*model.Channel)
utils.EnableDebugLogForTest()
return r
}
func (me *TestHelper) CreatePost(client *model.Client, channel *model.Channel) *model.Post {
id := model.NewId()
post := &model.Post{
ChannelId: channel.Id,
Message: "message_" + id,
}
utils.DisableDebugLogForTest()
r := client.Must(client.CreatePost(post)).Data.(*model.Post)
utils.EnableDebugLogForTest()
return r
}
func (me *TestHelper) LoginBasic() {
utils.DisableDebugLogForTest()
me.BasicClient.Must(me.BasicClient.LoginByEmail(me.BasicTeam.Name, me.BasicUser.Email, me.BasicUser.Password))
utils.EnableDebugLogForTest()
}
func (me *TestHelper) LoginBasic2() {
utils.DisableDebugLogForTest()
me.BasicClient.Must(me.BasicClient.LoginByEmail(me.BasicTeam.Name, me.BasicUser2.Email, me.BasicUser2.Password))
utils.EnableDebugLogForTest()
}
func (me *TestHelper) LoginSystemAdmin() {
utils.DisableDebugLogForTest()
me.SystemAdminClient.Must(me.SystemAdminClient.LoginByEmail(me.SystemAdminTeam.Name, me.SystemAdminUser.Email, me.SystemAdminUser.Password))
utils.EnableDebugLogForTest()
}
func TearDown() {
if Srv != nil {
StopServer()
}
}

99
api/authentication.go Normal file
View file

@ -0,0 +1,99 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package api
import (
"github.com/mattermost/platform/einterfaces"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
)
func checkPasswordAndAllCriteria(user *model.User, password string, mfaToken string) *model.AppError {
if err := checkUserPassword(user, password); err != nil {
return err
}
if err := checkUserAdditionalAuthenticationCriteria(user, mfaToken); err != nil {
return err
}
return nil
}
func checkUserPassword(user *model.User, password string) *model.AppError {
if !model.ComparePassword(user.Password, password) {
if result := <-Srv.Store.User().UpdateFailedPasswordAttempts(user.Id, user.FailedAttempts+1); result.Err != nil {
return result.Err
}
return model.NewLocAppError("checkUserPassword", "api.user.check_user_password.invalid.app_error", nil, "user_id="+user.Id)
} else {
if result := <-Srv.Store.User().UpdateFailedPasswordAttempts(user.Id, 0); result.Err != nil {
return result.Err
}
return nil
}
}
func checkUserAdditionalAuthenticationCriteria(user *model.User, mfaToken string) *model.AppError {
if err := checkUserMfa(user, mfaToken); err != nil {
return err
}
if err := checkEmailVerified(user); err != nil {
return err
}
if err := checkUserNotDisabled(user); err != nil {
return err
}
if err := checkUserLoginAttempts(user); err != nil {
return err
}
return nil
}
func checkUserMfa(user *model.User, token string) *model.AppError {
if !user.MfaActive || !utils.IsLicensed || !*utils.License.Features.MFA || !*utils.Cfg.ServiceSettings.EnableMultifactorAuthentication {
return nil
}
mfaInterface := einterfaces.GetMfaInterface()
if mfaInterface == nil {
return model.NewLocAppError("checkUserMfa", "api.user.check_user_mfa.not_available.app_error", nil, "")
}
if ok, err := mfaInterface.ValidateToken(user.MfaSecret, token); err != nil {
return err
} else if !ok {
return model.NewLocAppError("checkUserMfa", "api.user.check_user_mfa.bad_code.app_error", nil, "")
}
return nil
}
func checkUserLoginAttempts(user *model.User) *model.AppError {
if user.FailedAttempts >= utils.Cfg.ServiceSettings.MaximumLoginAttempts {
return model.NewLocAppError("checkUserLoginAttempts", "api.user.check_user_login_attempts.too_many.app_error", nil, "user_id="+user.Id)
}
return nil
}
func checkEmailVerified(user *model.User) *model.AppError {
if !user.EmailVerified && utils.Cfg.EmailSettings.RequireEmailVerification {
return model.NewLocAppError("Login", "api.user.login.not_verified.app_error", nil, "user_id="+user.Id)
}
return nil
}
func checkUserNotDisabled(user *model.User) *model.AppError {
if user.DeleteAt > 0 {
return model.NewLocAppError("Login", "api.user.login.inactive.app_error", nil, "user_id="+user.Id)
}
return nil
}

View file

@ -10,7 +10,7 @@ import (
type AutoChannelCreator struct {
client *model.Client
teamID string
team *model.Team
Fuzzy bool
DisplayNameLen utils.Range
DisplayNameCharset string
@ -19,10 +19,10 @@ type AutoChannelCreator struct {
ChannelType string
}
func NewAutoChannelCreator(client *model.Client, teamID string) *AutoChannelCreator {
func NewAutoChannelCreator(client *model.Client, team *model.Team) *AutoChannelCreator {
return &AutoChannelCreator{
client: client,
teamID: teamID,
team: team,
Fuzzy: false,
DisplayNameLen: CHANNEL_DISPLAY_NAME_LEN,
DisplayNameCharset: utils.ALPHANUMERIC,
@ -42,13 +42,17 @@ func (cfg *AutoChannelCreator) createRandomChannel() (*model.Channel, bool) {
name := utils.RandomName(cfg.NameLen, cfg.NameCharset)
channel := &model.Channel{
TeamId: cfg.teamID,
TeamId: cfg.team.Id,
DisplayName: displayName,
Name: name,
Type: cfg.ChannelType}
println(cfg.client.GetTeamRoute())
result, err := cfg.client.CreateChannel(channel)
if err != nil {
err.Translate(utils.T)
println(err.Error())
println(err.DetailedError)
return nil, false
}
return result.Data.(*model.Channel), true

View file

@ -28,14 +28,15 @@ func CreateTestEnvironmentWithTeams(client *model.Client, rangeTeams utils.Range
environment := TestEnvironment{teams, make([]TeamEnvironment, len(teams))}
for i, team := range teams {
userCreator := NewAutoUserCreator(client, team.Id)
userCreator := NewAutoUserCreator(client, team)
userCreator.Fuzzy = fuzzy
randomUser, err := userCreator.createRandomUser()
if err != true {
return TestEnvironment{}, false
}
client.LoginById(randomUser.Id, USER_PASSWORD)
teamEnvironment, err := CreateTestEnvironmentInTeam(client, team.Id, rangeChannels, rangeUsers, rangePosts, fuzzy)
client.SetTeamId(team.Id)
teamEnvironment, err := CreateTestEnvironmentInTeam(client, team, rangeChannels, rangeUsers, rangePosts, fuzzy)
if err != true {
return TestEnvironment{}, false
}
@ -45,7 +46,7 @@ func CreateTestEnvironmentWithTeams(client *model.Client, rangeTeams utils.Range
return environment, true
}
func CreateTestEnvironmentInTeam(client *model.Client, teamID string, rangeChannels utils.Range, rangeUsers utils.Range, rangePosts utils.Range, fuzzy bool) (TeamEnvironment, bool) {
func CreateTestEnvironmentInTeam(client *model.Client, team *model.Team, rangeChannels utils.Range, rangeUsers utils.Range, rangePosts utils.Range, fuzzy bool) (TeamEnvironment, bool) {
rand.Seed(time.Now().UTC().UnixNano())
// We need to create at least one user
@ -53,7 +54,7 @@ func CreateTestEnvironmentInTeam(client *model.Client, teamID string, rangeChann
rangeUsers.Begin = 1
}
userCreator := NewAutoUserCreator(client, teamID)
userCreator := NewAutoUserCreator(client, team)
userCreator.Fuzzy = fuzzy
users, err := userCreator.CreateTestUsers(rangeUsers)
if err != true {
@ -64,7 +65,7 @@ func CreateTestEnvironmentInTeam(client *model.Client, teamID string, rangeChann
usernames[i] = user.Username
}
channelCreator := NewAutoChannelCreator(client, teamID)
channelCreator := NewAutoChannelCreator(client, team)
channelCreator.Fuzzy = fuzzy
channels, err := channelCreator.CreateTestChannels(rangeChannels)
@ -79,6 +80,7 @@ func CreateTestEnvironmentInTeam(client *model.Client, teamID string, rangeChann
if err != true {
return TeamEnvironment{}, false
}
numPosts := utils.RandIntFromRange(rangePosts)
numImages := utils.RandIntFromRange(rangePosts) / 4
for j := 0; j < numPosts; j++ {

View file

@ -74,7 +74,7 @@ func (cfg *AutoPostCreator) UploadTestFile() ([]string, bool) {
return nil, false
}
resp, appErr := cfg.client.UploadFile("/files/upload", body.Bytes(), writer.FormDataContentType())
resp, appErr := cfg.client.UploadPostAttachment(body.Bytes(), writer.FormDataContentType())
if appErr != nil {
return nil, false
}

View file

@ -42,11 +42,11 @@ func (cfg *AutoTeamCreator) createRandomTeam() (*model.Team, bool) {
var teamDisplayName string
var teamName string
if cfg.Fuzzy {
teamEmail = utils.FuzzEmail()
teamEmail = "success+" + model.NewId() + "simulator.amazonses.com"
teamDisplayName = utils.FuzzName()
teamName = utils.FuzzName()
} else {
teamEmail = utils.RandomEmail(cfg.EmailLength, cfg.EmailCharset)
teamEmail = "success+" + model.NewId() + "simulator.amazonses.com"
teamDisplayName = utils.RandomName(cfg.NameLength, cfg.NameCharset)
teamName = utils.RandomName(cfg.NameLength, cfg.NameCharset) + model.NewId()
}

View file

@ -7,11 +7,13 @@ import (
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
l4g "github.com/alecthomas/log4go"
)
type AutoUserCreator struct {
client *model.Client
teamID string
team *model.Team
EmailLength utils.Range
EmailCharset string
NameLength utils.Range
@ -19,10 +21,10 @@ type AutoUserCreator struct {
Fuzzy bool
}
func NewAutoUserCreator(client *model.Client, teamID string) *AutoUserCreator {
func NewAutoUserCreator(client *model.Client, team *model.Team) *AutoUserCreator {
return &AutoUserCreator{
client: client,
teamID: teamID,
team: team,
EmailLength: USER_EMAIL_LEN,
EmailCharset: utils.LOWERCASE,
NameLength: USER_NAME_LEN,
@ -33,7 +35,7 @@ func NewAutoUserCreator(client *model.Client, teamID string) *AutoUserCreator {
// Basic test team and user so you always know one
func CreateBasicUser(client *model.Client) *model.AppError {
result, _ := client.FindTeamByName(BTEST_TEAM_NAME, true)
result, _ := client.FindTeamByName(BTEST_TEAM_NAME)
if result.Data.(bool) == false {
newteam := &model.Team{DisplayName: BTEST_TEAM_DISPLAY_NAME, Name: BTEST_TEAM_NAME, Email: BTEST_TEAM_EMAIL, Type: BTEST_TEAM_TYPE}
result, err := client.CreateTeam(newteam)
@ -41,12 +43,14 @@ func CreateBasicUser(client *model.Client) *model.AppError {
return err
}
basicteam := result.Data.(*model.Team)
newuser := &model.User{TeamId: basicteam.Id, Email: BTEST_USER_EMAIL, Nickname: BTEST_USER_NAME, Password: BTEST_USER_PASSWORD}
newuser := &model.User{Email: BTEST_USER_EMAIL, Nickname: BTEST_USER_NAME, Password: BTEST_USER_PASSWORD}
result, err = client.CreateUser(newuser, "")
if err != nil {
return err
}
store.Must(Srv.Store.User().VerifyEmail(result.Data.(*model.User).Id))
ruser := result.Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
store.Must(Srv.Store.Team().SaveMember(&model.TeamMember{TeamId: basicteam.Id, UserId: ruser.Id}))
}
return nil
}
@ -55,25 +59,30 @@ func (cfg *AutoUserCreator) createRandomUser() (*model.User, bool) {
var userEmail string
var userName string
if cfg.Fuzzy {
userEmail = utils.RandString(FUZZ_USER_EMAIL_PREFIX_LEN, utils.LOWERCASE) + "-" + utils.FuzzEmail()
userEmail = "success+" + model.NewId() + "simulator.amazonses.com"
userName = utils.FuzzName()
} else {
userEmail = utils.RandomEmail(cfg.EmailLength, cfg.EmailCharset)
userEmail = "success+" + model.NewId() + "simulator.amazonses.com"
userName = utils.RandomName(cfg.NameLength, cfg.NameCharset)
}
user := &model.User{
TeamId: cfg.teamID,
Email: userEmail,
Nickname: userName,
Password: USER_PASSWORD}
result, err := cfg.client.CreateUser(user, "")
result, err := cfg.client.CreateUserWithInvite(user, "", "", cfg.team.InviteId)
if err != nil {
err.Translate(utils.T)
l4g.Error(err.Error())
return nil, false
}
ruser := result.Data.(*model.User)
// We need to cheat to verify the user's email
store.Must(Srv.Store.User().VerifyEmail(result.Data.(*model.User).Id))
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
return result.Data.(*model.User), true
}

View file

@ -18,29 +18,28 @@ const (
defaultExtraMemberLimit = 100
)
func InitChannel(r *mux.Router) {
func InitChannel() {
l4g.Debug(utils.T("api.channel.init.debug"))
sr := r.PathPrefix("/channels").Subrouter()
sr.Handle("/", ApiUserRequiredActivity(getChannels, false)).Methods("GET")
sr.Handle("/more", ApiUserRequired(getMoreChannels)).Methods("GET")
sr.Handle("/counts", ApiUserRequiredActivity(getChannelCounts, false)).Methods("GET")
sr.Handle("/create", ApiUserRequired(createChannel)).Methods("POST")
sr.Handle("/create_direct", ApiUserRequired(createDirectChannel)).Methods("POST")
sr.Handle("/update", ApiUserRequired(updateChannel)).Methods("POST")
sr.Handle("/update_header", ApiUserRequired(updateChannelHeader)).Methods("POST")
sr.Handle("/update_purpose", ApiUserRequired(updateChannelPurpose)).Methods("POST")
sr.Handle("/update_notify_props", ApiUserRequired(updateNotifyProps)).Methods("POST")
sr.Handle("/{id:[A-Za-z0-9]+}/", ApiUserRequiredActivity(getChannel, false)).Methods("GET")
sr.Handle("/{id:[A-Za-z0-9]+}/extra_info", ApiUserRequired(getChannelExtraInfo)).Methods("GET")
sr.Handle("/{id:[A-Za-z0-9]+}/extra_info/{member_limit:-?[0-9]+}", ApiUserRequired(getChannelExtraInfo)).Methods("GET")
sr.Handle("/{id:[A-Za-z0-9]+}/join", ApiUserRequired(join)).Methods("POST")
sr.Handle("/{id:[A-Za-z0-9]+}/leave", ApiUserRequired(leave)).Methods("POST")
sr.Handle("/{id:[A-Za-z0-9]+}/delete", ApiUserRequired(deleteChannel)).Methods("POST")
sr.Handle("/{id:[A-Za-z0-9]+}/add", ApiUserRequired(addMember)).Methods("POST")
sr.Handle("/{id:[A-Za-z0-9]+}/remove", ApiUserRequired(removeMember)).Methods("POST")
sr.Handle("/{id:[A-Za-z0-9]+}/update_last_viewed_at", ApiUserRequired(updateLastViewedAt)).Methods("POST")
BaseRoutes.Channels.Handle("/", ApiUserRequiredActivity(getChannels, false)).Methods("GET")
BaseRoutes.Channels.Handle("/more", ApiUserRequired(getMoreChannels)).Methods("GET")
BaseRoutes.Channels.Handle("/counts", ApiUserRequiredActivity(getChannelCounts, false)).Methods("GET")
BaseRoutes.Channels.Handle("/create", ApiUserRequired(createChannel)).Methods("POST")
BaseRoutes.Channels.Handle("/create_direct", ApiUserRequired(createDirectChannel)).Methods("POST")
BaseRoutes.Channels.Handle("/update", ApiUserRequired(updateChannel)).Methods("POST")
BaseRoutes.Channels.Handle("/update_header", ApiUserRequired(updateChannelHeader)).Methods("POST")
BaseRoutes.Channels.Handle("/update_purpose", ApiUserRequired(updateChannelPurpose)).Methods("POST")
BaseRoutes.Channels.Handle("/update_notify_props", ApiUserRequired(updateNotifyProps)).Methods("POST")
BaseRoutes.NeedChannel.Handle("/", ApiUserRequiredActivity(getChannel, false)).Methods("GET")
BaseRoutes.NeedChannel.Handle("/extra_info", ApiUserRequired(getChannelExtraInfo)).Methods("GET")
BaseRoutes.NeedChannel.Handle("/extra_info/{member_limit:-?[0-9]+}", ApiUserRequired(getChannelExtraInfo)).Methods("GET")
BaseRoutes.NeedChannel.Handle("/join", ApiUserRequired(join)).Methods("POST")
BaseRoutes.NeedChannel.Handle("/leave", ApiUserRequired(leave)).Methods("POST")
BaseRoutes.NeedChannel.Handle("/delete", ApiUserRequired(deleteChannel)).Methods("POST")
BaseRoutes.NeedChannel.Handle("/add", ApiUserRequired(addMember)).Methods("POST")
BaseRoutes.NeedChannel.Handle("/remove", ApiUserRequired(removeMember)).Methods("POST")
BaseRoutes.NeedChannel.Handle("/update_last_viewed_at", ApiUserRequired(updateLastViewedAt)).Methods("POST")
}
func createChannel(c *Context, w http.ResponseWriter, r *http.Request) {
@ -52,6 +51,10 @@ func createChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if len(channel.TeamId) == 0 {
channel.TeamId = c.TeamId
}
if !c.HasPermissionsToTeam(channel.TeamId, "createChannel") {
return
}
@ -107,10 +110,6 @@ func createDirectChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if !c.HasPermissionsToTeam(c.Session.TeamId, "createDirectChannel") {
return
}
if sc, err := CreateDirectChannel(c, userId); err != nil {
c.Err = err
return
@ -131,7 +130,7 @@ func CreateDirectChannel(c *Context, otherUserId string) (*model.Channel, *model
channel.DisplayName = ""
channel.Name = model.GetDMNameFromIds(otherUserId, c.Session.UserId)
channel.TeamId = c.Session.TeamId
channel.TeamId = c.TeamId
channel.Header = ""
channel.Type = model.CHANNEL_DIRECT
@ -214,7 +213,7 @@ func updateChannel(c *Context, w http.ResponseWriter, r *http.Request) {
if oldChannel.Name == model.DEFAULT_CHANNEL {
if (len(channel.Name) > 0 && channel.Name != oldChannel.Name) || (len(channel.Type) > 0 && channel.Type != oldChannel.Type) {
c.Err = model.NewLocAppError("updateChannel", "api.channel.update_channel.tried.app_error", map[string]interface{}{"Channel": model.DEFAULT_CHANNEL}, "")
c.Err.StatusCode = http.StatusForbidden
c.Err.StatusCode = http.StatusBadRequest
return
}
}
@ -367,7 +366,7 @@ func getChannels(c *Context, w http.ResponseWriter, r *http.Request) {
// user is already in the team
if result := <-Srv.Store.Channel().GetChannels(c.Session.TeamId, c.Session.UserId); result.Err != nil {
if result := <-Srv.Store.Channel().GetChannels(c.TeamId, c.Session.UserId); result.Err != nil {
if result.Err.Id == "store.sql_channel.get_channels.not_found.app_error" {
// lets make sure the user is valid
if result := <-Srv.Store.User().Get(c.Session.UserId); result.Err != nil {
@ -392,7 +391,7 @@ func getMoreChannels(c *Context, w http.ResponseWriter, r *http.Request) {
// user is already in the team
if result := <-Srv.Store.Channel().GetMoreChannels(c.Session.TeamId, c.Session.UserId); result.Err != nil {
if result := <-Srv.Store.Channel().GetMoreChannels(c.TeamId, c.Session.UserId); result.Err != nil {
c.Err = result.Err
return
} else if HandleEtag(result.Data.(*model.ChannelList).Etag(), w, r) {
@ -408,7 +407,7 @@ func getChannelCounts(c *Context, w http.ResponseWriter, r *http.Request) {
// user is already in the team
if result := <-Srv.Store.Channel().GetChannelCounts(c.Session.TeamId, c.Session.UserId); result.Err != nil {
if result := <-Srv.Store.Channel().GetChannelCounts(c.TeamId, c.Session.UserId); result.Err != nil {
c.Err = model.NewLocAppError("getChannelCounts", "api.channel.get_channel_counts.app_error", nil, result.Err.Message)
return
} else if HandleEtag(result.Data.(*model.ChannelCounts).Etag(), w, r) {
@ -423,7 +422,7 @@ func getChannelCounts(c *Context, w http.ResponseWriter, r *http.Request) {
func join(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
channelId := params["id"]
channelId := params["channel_id"]
JoinChannel(c, channelId, "")
@ -498,7 +497,7 @@ func AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelM
}
go func() {
UpdateChannelAccessCache(channel.TeamId, user.Id, channel.Id)
InvalidateCacheForUser(user.Id)
message := model.NewMessage(channel.TeamId, channel.Id, user.Id, model.ACTION_USER_ADDED)
PublishAndForget(message)
@ -507,12 +506,12 @@ func AddUserToChannel(user *model.User, channel *model.Channel) (*model.ChannelM
return newMember, nil
}
func JoinDefaultChannels(user *model.User, channelRole string) *model.AppError {
func JoinDefaultChannels(teamId string, user *model.User, channelRole string) *model.AppError {
// We don't call JoinChannel here since c.Session is not populated on user creation
var err *model.AppError = nil
if result := <-Srv.Store.Channel().GetByName(user.TeamId, "town-square"); result.Err != nil {
if result := <-Srv.Store.Channel().GetByName(teamId, "town-square"); result.Err != nil {
err = result.Err
} else {
cm := &model.ChannelMember{ChannelId: result.Data.(*model.Channel).Id, UserId: user.Id,
@ -523,7 +522,7 @@ func JoinDefaultChannels(user *model.User, channelRole string) *model.AppError {
}
}
if result := <-Srv.Store.Channel().GetByName(user.TeamId, "off-topic"); result.Err != nil {
if result := <-Srv.Store.Channel().GetByName(teamId, "off-topic"); result.Err != nil {
err = result.Err
} else {
cm := &model.ChannelMember{ChannelId: result.Data.(*model.Channel).Id, UserId: user.Id,
@ -540,7 +539,7 @@ func JoinDefaultChannels(user *model.User, channelRole string) *model.AppError {
func leave(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id := params["id"]
id := params["channel_id"]
sc := Srv.Store.Channel().Get(id)
uc := Srv.Store.User().Get(c.Session.UserId)
@ -561,13 +560,13 @@ func leave(c *Context, w http.ResponseWriter, r *http.Request) {
if channel.Type == model.CHANNEL_DIRECT {
c.Err = model.NewLocAppError("leave", "api.channel.leave.direct.app_error", nil, "")
c.Err.StatusCode = http.StatusForbidden
c.Err.StatusCode = http.StatusBadRequest
return
}
if channel.Name == model.DEFAULT_CHANNEL {
c.Err = model.NewLocAppError("leave", "api.channel.leave.default.app_error", map[string]interface{}{"Channel": model.DEFAULT_CHANNEL}, "")
c.Err.StatusCode = http.StatusForbidden
c.Err.StatusCode = http.StatusBadRequest
return
}
@ -589,7 +588,7 @@ func leave(c *Context, w http.ResponseWriter, r *http.Request) {
func deleteChannel(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id := params["id"]
id := params["channel_id"]
sc := Srv.Store.Channel().Get(id)
scm := Srv.Store.Channel().GetMember(id, c.Session.UserId)
@ -637,7 +636,7 @@ func deleteChannel(c *Context, w http.ResponseWriter, r *http.Request) {
if channel.Name == model.DEFAULT_CHANNEL {
c.Err = model.NewLocAppError("deleteChannel", "api.channel.delete_channel.cannot.app_error", map[string]interface{}{"Channel": model.DEFAULT_CHANNEL}, "")
c.Err.StatusCode = http.StatusForbidden
c.Err.StatusCode = http.StatusBadRequest
return
}
@ -682,7 +681,7 @@ func deleteChannel(c *Context, w http.ResponseWriter, r *http.Request) {
func updateLastViewedAt(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id := params["id"]
id := params["channel_id"]
Srv.Store.Channel().UpdateLastViewedAt(id, c.Session.UserId)
@ -695,7 +694,7 @@ func updateLastViewedAt(c *Context, w http.ResponseWriter, r *http.Request) {
Srv.Store.Preference().Save(&model.Preferences{preference})
message := model.NewMessage(c.Session.TeamId, id, c.Session.UserId, model.ACTION_CHANNEL_VIEWED)
message := model.NewMessage(c.TeamId, id, c.Session.UserId, model.ACTION_CHANNEL_VIEWED)
message.Add("channel_id", id)
PublishAndForget(message)
@ -707,9 +706,9 @@ func updateLastViewedAt(c *Context, w http.ResponseWriter, r *http.Request) {
func getChannel(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id := params["id"]
id := params["channel_id"]
//pchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, id, c.Session.UserId)
//pchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, id, c.Session.UserId)
cchan := Srv.Store.Channel().Get(id)
cmchan := Srv.Store.Channel().GetMember(id, c.Session.UserId)
@ -737,7 +736,7 @@ func getChannel(c *Context, w http.ResponseWriter, r *http.Request) {
func getChannelExtraInfo(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id := params["id"]
id := params["channel_id"]
var memberLimit int
if memberLimitString, ok := params["member_limit"]; !ok {
@ -781,7 +780,7 @@ func getChannelExtraInfo(c *Context, w http.ResponseWriter, r *http.Request) {
extraMembers := ecmresult.Data.([]model.ExtraMember)
memberCount := ccmresult.Data.(int64)
if !c.HasPermissionsToTeam(channel.TeamId, "getChannelExtraInfo") {
if len(channel.TeamId) > 0 && !c.HasPermissionsToTeam(channel.TeamId, "getChannelExtraInfo") {
return
}
@ -803,7 +802,7 @@ func getChannelExtraInfo(c *Context, w http.ResponseWriter, r *http.Request) {
func addMember(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id := params["id"]
id := params["channel_id"]
data := model.MapFromJson(r.Body)
userId := data["user_id"]
@ -813,7 +812,7 @@ func addMember(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, id, c.Session.UserId)
cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, id, c.Session.UserId)
sc := Srv.Store.Channel().Get(id)
ouc := Srv.Store.User().Get(c.Session.UserId)
nuc := Srv.Store.User().Get(userId)
@ -857,7 +856,7 @@ func addMember(c *Context, w http.ResponseWriter, r *http.Request) {
func removeMember(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
channelId := params["id"]
channelId := params["channel_id"]
data := model.MapFromJson(r.Body)
userIdToRemove := data["user_id"]
@ -914,7 +913,7 @@ func RemoveUserFromChannel(userIdToRemove string, removerUserId string, channel
return cmresult.Err
}
UpdateChannelAccessCacheAndForget(channel.TeamId, userIdToRemove, channel.Id)
InvalidateCacheForUser(userIdToRemove)
message := model.NewMessage(channel.TeamId, channel.Id, userIdToRemove, model.ACTION_USER_REMOVED)
message.Add("remover_id", removerUserId)
@ -938,7 +937,7 @@ func updateNotifyProps(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, channelId, c.Session.UserId)
cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, channelId, c.Session.UserId)
if !c.HasPermissionsToUser(userId, "updateNotifyLevel") {
return

View file

@ -12,61 +12,47 @@ import (
const (
NUM_CHANNELS = 140
NUM_USERS = 40
)
func BenchmarkCreateChannel(b *testing.B) {
var (
NUM_CHANNELS_RANGE = utils.Range{NUM_CHANNELS, NUM_CHANNELS}
)
team, _, _ := SetupBenchmark()
th := Setup().InitBasic()
channelCreator := NewAutoChannelCreator(Client, team.Id)
channelCreator := NewAutoChannelCreator(th.BasicClient, th.BasicTeam)
// Benchmark Start
b.ResetTimer()
for i := 0; i < b.N; i++ {
channelCreator.CreateTestChannels(NUM_CHANNELS_RANGE)
channelCreator.CreateTestChannels(utils.Range{NUM_CHANNELS, NUM_CHANNELS})
}
}
func BenchmarkCreateDirectChannel(b *testing.B) {
var (
NUM_CHANNELS_RANGE = utils.Range{NUM_CHANNELS, NUM_CHANNELS}
)
team, _, _ := SetupBenchmark()
th := Setup().InitBasic()
userCreator := NewAutoUserCreator(Client, team.Id)
users, err := userCreator.CreateTestUsers(NUM_CHANNELS_RANGE)
userCreator := NewAutoUserCreator(th.BasicClient, th.BasicTeam)
users, err := userCreator.CreateTestUsers(utils.Range{NUM_USERS, NUM_USERS})
if err == false {
b.Fatal("Could not create users")
}
data := make([]map[string]string, len(users))
for i := range data {
newmap := map[string]string{
"user_id": users[i].Id,
}
data[i] = newmap
}
// Benchmark Start
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j := 0; j < NUM_CHANNELS; j++ {
Client.CreateDirectChannel(data[j])
for j := 0; j < NUM_USERS; j++ {
th.BasicClient.CreateDirectChannel(users[j].Id)
}
}
}
func BenchmarkUpdateChannel(b *testing.B) {
th := Setup().InitBasic()
var (
NUM_CHANNELS_RANGE = utils.Range{NUM_CHANNELS, NUM_CHANNELS}
CHANNEL_HEADER_LEN = 50
)
team, _, _ := SetupBenchmark()
channelCreator := NewAutoChannelCreator(Client, team.Id)
channelCreator := NewAutoChannelCreator(th.BasicClient, th.BasicTeam)
channels, valid := channelCreator.CreateTestChannels(NUM_CHANNELS_RANGE)
if valid == false {
b.Fatal("Unable to create test channels")
@ -80,7 +66,7 @@ func BenchmarkUpdateChannel(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j := range channels {
if _, err := Client.UpdateChannel(channels[j]); err != nil {
if _, err := th.BasicClient.UpdateChannel(channels[j]); err != nil {
b.Fatal(err)
}
}
@ -88,12 +74,13 @@ func BenchmarkUpdateChannel(b *testing.B) {
}
func BenchmarkGetChannels(b *testing.B) {
th := Setup().InitBasic()
var (
NUM_CHANNELS_RANGE = utils.Range{NUM_CHANNELS, NUM_CHANNELS}
)
team, _, _ := SetupBenchmark()
channelCreator := NewAutoChannelCreator(Client, team.Id)
channelCreator := NewAutoChannelCreator(th.BasicClient, th.BasicTeam)
_, valid := channelCreator.CreateTestChannels(NUM_CHANNELS_RANGE)
if valid == false {
b.Fatal("Unable to create test channels")
@ -102,17 +89,18 @@ func BenchmarkGetChannels(b *testing.B) {
// Benchmark Start
b.ResetTimer()
for i := 0; i < b.N; i++ {
Client.Must(Client.GetChannels(""))
th.BasicClient.Must(th.BasicClient.GetChannels(""))
}
}
func BenchmarkGetMoreChannels(b *testing.B) {
th := Setup().InitBasic()
var (
NUM_CHANNELS_RANGE = utils.Range{NUM_CHANNELS, NUM_CHANNELS}
)
team, _, _ := SetupBenchmark()
channelCreator := NewAutoChannelCreator(Client, team.Id)
channelCreator := NewAutoChannelCreator(th.BasicClient, th.BasicTeam)
_, valid := channelCreator.CreateTestChannels(NUM_CHANNELS_RANGE)
if valid == false {
b.Fatal("Unable to create test channels")
@ -121,44 +109,47 @@ func BenchmarkGetMoreChannels(b *testing.B) {
// Benchmark Start
b.ResetTimer()
for i := 0; i < b.N; i++ {
Client.Must(Client.GetMoreChannels(""))
th.BasicClient.Must(th.BasicClient.GetMoreChannels(""))
}
}
func BenchmarkJoinChannel(b *testing.B) {
th := Setup().InitBasic()
var (
NUM_CHANNELS_RANGE = utils.Range{NUM_CHANNELS, NUM_CHANNELS}
)
team, _, _ := SetupBenchmark()
channelCreator := NewAutoChannelCreator(Client, team.Id)
channelCreator := NewAutoChannelCreator(th.BasicClient, th.BasicTeam)
channels, valid := channelCreator.CreateTestChannels(NUM_CHANNELS_RANGE)
if valid == false {
b.Fatal("Unable to create test channels")
}
// Secondary test user to join channels created by primary test user
user := &model.User{TeamId: team.Id, Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "That Guy", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
user := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "That Guy", Password: "pwd"}
user = th.BasicClient.Must(th.BasicClient.CreateUser(user, "")).Data.(*model.User)
LinkUserToTeam(user, th.BasicTeam)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
th.BasicClient.LoginByEmail(th.BasicTeam.Name, user.Email, "pwd")
// Benchmark Start
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j := range channels {
Client.Must(Client.JoinChannel(channels[j].Id))
th.BasicClient.Must(th.BasicClient.JoinChannel(channels[j].Id))
}
}
}
func BenchmarkDeleteChannel(b *testing.B) {
th := Setup().InitBasic()
var (
NUM_CHANNELS_RANGE = utils.Range{NUM_CHANNELS, NUM_CHANNELS}
)
team, _, _ := SetupBenchmark()
channelCreator := NewAutoChannelCreator(Client, team.Id)
channelCreator := NewAutoChannelCreator(th.BasicClient, th.BasicTeam)
channels, valid := channelCreator.CreateTestChannels(NUM_CHANNELS_RANGE)
if valid == false {
b.Fatal("Unable to create test channels")
@ -168,18 +159,19 @@ func BenchmarkDeleteChannel(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j := range channels {
Client.Must(Client.DeleteChannel(channels[j].Id))
th.BasicClient.Must(th.BasicClient.DeleteChannel(channels[j].Id))
}
}
}
func BenchmarkGetChannelExtraInfo(b *testing.B) {
th := Setup().InitBasic()
var (
NUM_CHANNELS_RANGE = utils.Range{NUM_CHANNELS, NUM_CHANNELS}
)
team, _, _ := SetupBenchmark()
channelCreator := NewAutoChannelCreator(Client, team.Id)
channelCreator := NewAutoChannelCreator(th.BasicClient, th.BasicTeam)
channels, valid := channelCreator.CreateTestChannels(NUM_CHANNELS_RANGE)
if valid == false {
b.Fatal("Unable to create test channels")
@ -189,22 +181,23 @@ func BenchmarkGetChannelExtraInfo(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j := range channels {
Client.Must(Client.GetChannelExtraInfo(channels[j].Id, -1, ""))
th.BasicClient.Must(th.BasicClient.GetChannelExtraInfo(channels[j].Id, -1, ""))
}
}
}
func BenchmarkAddChannelMember(b *testing.B) {
th := Setup().InitBasic()
var (
NUM_USERS = 100
NUM_USERS_RANGE = utils.Range{NUM_USERS, NUM_USERS}
)
team, _, _ := SetupBenchmark()
channel := &model.Channel{DisplayName: "Test Channel", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel = Client.Must(Client.CreateChannel(channel)).Data.(*model.Channel)
channel := &model.Channel{DisplayName: "Test Channel", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: th.BasicTeam.Id}
channel = th.BasicClient.Must(th.BasicClient.CreateChannel(channel)).Data.(*model.Channel)
userCreator := NewAutoUserCreator(Client, team.Id)
userCreator := NewAutoUserCreator(th.BasicClient, th.BasicTeam)
users, valid := userCreator.CreateTestUsers(NUM_USERS_RANGE)
if valid == false {
b.Fatal("Unable to create test users")
@ -214,7 +207,7 @@ func BenchmarkAddChannelMember(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j := range users {
if _, err := Client.AddChannelMember(channel.Id, users[j].Id); err != nil {
if _, err := th.BasicClient.AddChannelMember(channel.Id, users[j].Id); err != nil {
b.Fatal(err)
}
}
@ -223,23 +216,24 @@ func BenchmarkAddChannelMember(b *testing.B) {
// Is this benchmark failing? Raise your file ulimit! 2048 worked for me.
func BenchmarkRemoveChannelMember(b *testing.B) {
th := Setup().InitBasic()
var (
NUM_USERS = 140
NUM_USERS_RANGE = utils.Range{NUM_USERS, NUM_USERS}
)
team, _, _ := SetupBenchmark()
channel := &model.Channel{DisplayName: "Test Channel", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel = Client.Must(Client.CreateChannel(channel)).Data.(*model.Channel)
channel := &model.Channel{DisplayName: "Test Channel", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: th.BasicTeam.Id}
channel = th.BasicClient.Must(th.BasicClient.CreateChannel(channel)).Data.(*model.Channel)
userCreator := NewAutoUserCreator(Client, team.Id)
userCreator := NewAutoUserCreator(th.BasicClient, th.BasicTeam)
users, valid := userCreator.CreateTestUsers(NUM_USERS_RANGE)
if valid == false {
b.Fatal("Unable to create test users")
}
for i := range users {
if _, err := Client.AddChannelMember(channel.Id, users[i].Id); err != nil {
if _, err := th.BasicClient.AddChannelMember(channel.Id, users[i].Id); err != nil {
b.Fatal(err)
}
}
@ -248,7 +242,7 @@ func BenchmarkRemoveChannelMember(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j := range users {
if _, err := Client.RemoveChannelMember(channel.Id, users[j].Id); err != nil {
if _, err := th.BasicClient.RemoveChannelMember(channel.Id, users[j].Id); err != nil {
b.Fatal(err)
}
}
@ -256,12 +250,13 @@ func BenchmarkRemoveChannelMember(b *testing.B) {
}
func BenchmarkUpdateNotifyProps(b *testing.B) {
th := Setup().InitBasic()
var (
NUM_CHANNELS_RANGE = utils.Range{NUM_CHANNELS, NUM_CHANNELS}
)
team, user, _ := SetupBenchmark()
channelCreator := NewAutoChannelCreator(Client, team.Id)
channelCreator := NewAutoChannelCreator(th.BasicClient, th.BasicTeam)
channels, valid := channelCreator.CreateTestChannels(NUM_CHANNELS_RANGE)
if valid == false {
b.Fatal("Unable to create test channels")
@ -272,7 +267,7 @@ func BenchmarkUpdateNotifyProps(b *testing.B) {
for i := range data {
newmap := map[string]string{
"channel_id": channels[i].Id,
"user_id": user.Id,
"user_id": th.BasicUser.Id,
"desktop": model.CHANNEL_NOTIFY_MENTION,
"mark_unread": model.CHANNEL_MARK_UNREAD_MENTION,
}
@ -283,7 +278,7 @@ func BenchmarkUpdateNotifyProps(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
for j := range channels {
Client.Must(Client.UpdateNotifyProps(data[j]))
th.BasicClient.Must(th.BasicClient.UpdateNotifyProps(data[j]))
}
}
}

View file

@ -14,19 +14,13 @@ import (
)
func TestCreateChannel(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
team2 := &model.Team{DisplayName: "Name Team 2", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
Client.Must(Client.Logout())
team2 := th.CreateTeam(th.BasicClient)
th.LoginBasic()
th.BasicClient.SetTeamId(team.Id)
channel := model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
rchannel, err := Client.CreateChannel(&channel)
@ -63,7 +57,7 @@ func TestCreateChannel(t *testing.T) {
}
}
if _, err := Client.DoApiPost("/channels/create", "garbage"); err == nil {
if _, err := Client.DoApiPost(Client.GetTeamRoute()+"/channels/create", "garbage"); err == nil {
t.Fatal("should have been an error")
}
@ -94,25 +88,12 @@ func TestCreateChannel(t *testing.T) {
}
func TestCreateDirectChannel(t *testing.T) {
Setup()
th := Setup().InitBasic()
Client := th.BasicClient
user := th.BasicUser
user2 := th.BasicUser2
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
data := make(map[string]string)
data["user_id"] = user2.Id
rchannel, err := Client.CreateDirectChannel(data)
rchannel, err := Client.CreateDirectChannel(th.BasicUser2.Id)
if err != nil {
t.Fatal(err)
}
@ -132,47 +113,31 @@ func TestCreateDirectChannel(t *testing.T) {
t.Fatal("channel type was not direct")
}
if _, err := Client.CreateDirectChannel(data); err == nil {
if _, err := Client.CreateDirectChannel(th.BasicUser2.Id); err == nil {
t.Fatal("channel already exists and should have failed")
}
data["user_id"] = "junk"
if _, err := Client.CreateDirectChannel(data); err == nil {
if _, err := Client.CreateDirectChannel("junk"); err == nil {
t.Fatal("should have failed with bad user id")
}
data["user_id"] = "12345678901234567890123456"
if _, err := Client.CreateDirectChannel(data); err == nil {
if _, err := Client.CreateDirectChannel("12345678901234567890123456"); err == nil {
t.Fatal("should have failed with non-existent user")
}
}
func TestUpdateChannel(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
userTeamAdmin := &model.User{TeamId: team.Id, Email: team.Email, Nickname: "Corey Hulen", Password: "pwd"}
userTeamAdmin = Client.Must(Client.CreateUser(userTeamAdmin, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(userTeamAdmin.Id))
userChannelAdmin := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
userChannelAdmin = Client.Must(Client.CreateUser(userChannelAdmin, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(userChannelAdmin.Id))
userStd := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
userStd = Client.Must(Client.CreateUser(userStd, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(userStd.Id))
userStd.Roles = ""
Client.LoginByEmail(team.Name, userChannelAdmin.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
user := th.BasicUser
user2 := th.CreateUser(th.BasicClient)
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
Client.AddChannelMember(channel1.Id, userTeamAdmin.Id)
Client.AddChannelMember(channel1.Id, user.Id)
header := "a" + model.NewId() + "a"
purpose := "a" + model.NewId() + "a"
@ -191,25 +156,6 @@ func TestUpdateChannel(t *testing.T) {
t.Fatal("Channel admin failed to skip displayName")
}
Client.LoginByEmail(team.Name, userTeamAdmin.Email, "pwd")
header = "b" + model.NewId() + "b"
purpose = "b" + model.NewId() + "b"
upChannel1 = &model.Channel{Id: channel1.Id, Header: header, Purpose: purpose}
upChannel1 = Client.Must(Client.UpdateChannel(upChannel1)).Data.(*model.Channel)
if upChannel1.Header != header {
t.Fatal("Team admin failed to update header")
}
if upChannel1.Purpose != purpose {
t.Fatal("Team admin failed to update purpose")
}
if upChannel1.DisplayName != channel1.DisplayName {
t.Fatal("Team admin failed to skip displayName")
}
rget := Client.Must(Client.GetChannels(""))
data := rget.Data.(*model.ChannelList)
for _, c := range data.Channels {
@ -223,7 +169,7 @@ func TestUpdateChannel(t *testing.T) {
}
}
Client.LoginByEmail(team.Name, userStd.Email, "pwd")
Client.LoginByEmail(team.Name, user2.Email, user2.Password)
if _, err := Client.UpdateChannel(upChannel1); err == nil {
t.Fatal("Standard User should have failed to update")
@ -231,16 +177,9 @@ func TestUpdateChannel(t *testing.T) {
}
func TestUpdateChannelHeader(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
@ -276,11 +215,7 @@ func TestUpdateChannelHeader(t *testing.T) {
t.Fatal("should have errored on bad channel header")
}
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
Client.LoginByEmail(team.Name, user2.Email, "pwd")
th.LoginBasic2()
data["channel_id"] = channel1.Id
data["channel_header"] = "new header"
@ -290,16 +225,9 @@ func TestUpdateChannelHeader(t *testing.T) {
}
func TestUpdateChannelPurpose(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
@ -335,11 +263,7 @@ func TestUpdateChannelPurpose(t *testing.T) {
t.Fatal("should have errored on bad channel purpose")
}
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
Client.LoginByEmail(team.Name, user2.Email, "pwd")
th.LoginBasic2()
data["channel_id"] = channel1.Id
data["channel_purpose"] = "new purpose"
@ -349,16 +273,9 @@ func TestUpdateChannelPurpose(t *testing.T) {
}
func TestGetChannel(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
@ -412,16 +329,9 @@ func TestGetChannel(t *testing.T) {
}
func TestGetMoreChannel(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
@ -429,11 +339,7 @@ func TestGetMoreChannel(t *testing.T) {
channel2 := &model.Channel{DisplayName: "B Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
Client.LoginByEmail(team.Name, user2.Email, "pwd")
th.LoginBasic2()
rget := Client.Must(Client.GetMoreChannels(""))
data := rget.Data.(*model.ChannelList)
@ -456,16 +362,9 @@ func TestGetMoreChannel(t *testing.T) {
}
func TestGetChannelCounts(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
@ -478,11 +377,11 @@ func TestGetChannelCounts(t *testing.T) {
} else {
counts := result.Data.(*model.ChannelCounts)
if len(counts.Counts) != 4 {
if len(counts.Counts) != 5 {
t.Fatal("wrong number of channel counts")
}
if len(counts.UpdateTimes) != 4 {
if len(counts.UpdateTimes) != 5 {
t.Fatal("wrong number of channel update times")
}
@ -497,16 +396,9 @@ func TestGetChannelCounts(t *testing.T) {
}
func TestJoinChannel(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
@ -514,11 +406,7 @@ func TestJoinChannel(t *testing.T) {
channel3 := &model.Channel{DisplayName: "B Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
Client.LoginByEmail(team.Name, user2.Email, "pwd")
th.LoginBasic2()
Client.Must(Client.JoinChannel(channel1.Id))
@ -526,13 +414,10 @@ func TestJoinChannel(t *testing.T) {
t.Fatal("shouldn't be able to join secret group")
}
data := make(map[string]string)
data["user_id"] = user1.Id
rchannel := Client.Must(Client.CreateDirectChannel(data)).Data.(*model.Channel)
user3 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
rchannel := Client.Must(Client.CreateDirectChannel(th.BasicUser.Id)).Data.(*model.Channel)
user3 := th.CreateUser(th.BasicClient)
LinkUserToTeam(user3, team)
Client.LoginByEmail(team.Name, user3.Email, "pwd")
if _, err := Client.JoinChannel(rchannel.Id); err == nil {
@ -541,16 +426,9 @@ func TestJoinChannel(t *testing.T) {
}
func TestLeaveChannel(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
@ -558,20 +436,14 @@ func TestLeaveChannel(t *testing.T) {
channel3 := &model.Channel{DisplayName: "B Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_PRIVATE, TeamId: team.Id}
channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
Client.LoginByEmail(team.Name, user2.Email, "pwd")
th.LoginBasic2()
Client.Must(Client.JoinChannel(channel1.Id))
// No error if you leave a channel you cannot see
Client.Must(Client.LeaveChannel(channel3.Id))
data := make(map[string]string)
data["user_id"] = user1.Id
rchannel := Client.Must(Client.CreateDirectChannel(data)).Data.(*model.Channel)
rchannel := Client.Must(Client.CreateDirectChannel(th.BasicUser.Id)).Data.(*model.Channel)
if _, err := Client.LeaveChannel(rchannel.Id); err == nil {
t.Fatal("should have errored, cannot leave direct channel")
@ -590,20 +462,12 @@ func TestLeaveChannel(t *testing.T) {
}
func TestDeleteChannel(t *testing.T) {
Setup()
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
userTeamAdmin := th.BasicUser
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
userTeamAdmin := &model.User{TeamId: team.Id, Email: team.Email, Nickname: "Corey Hulen", Password: "pwd"}
userTeamAdmin = Client.Must(Client.CreateUser(userTeamAdmin, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(userTeamAdmin.Id))
userChannelAdmin := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
userChannelAdmin = Client.Must(Client.CreateUser(userChannelAdmin, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(userChannelAdmin.Id))
Client.LoginByEmail(team.Name, userChannelAdmin.Email, "pwd")
th.LoginBasic2()
channelMadeByCA := &model.Channel{DisplayName: "C Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channelMadeByCA = Client.Must(Client.CreateChannel(channelMadeByCA)).Data.(*model.Channel)
@ -631,11 +495,9 @@ func TestDeleteChannel(t *testing.T) {
t.Fatal("should have failed to post to deleted channel")
}
userStd := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
userStd = Client.Must(Client.CreateUser(userStd, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(userStd.Id))
Client.LoginByEmail(team.Name, userStd.Email, "pwd")
userStd := th.CreateUser(th.BasicClient)
LinkUserToTeam(userStd, team)
Client.LoginByEmail(team.Name, userStd.Email, userStd.Password)
if _, err := Client.JoinChannel(channel1.Id); err == nil {
t.Fatal("should have failed to join deleted channel")
@ -660,16 +522,9 @@ func TestDeleteChannel(t *testing.T) {
}
func TestGetChannelExtraInfo(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
@ -701,8 +556,10 @@ func TestGetChannelExtraInfo(t *testing.T) {
Client2 := model.NewClient("http://localhost" + utils.Cfg.ServiceSettings.ListenAddress)
user2 := &model.User{TeamId: team.Id, Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Tester 2", Password: "pwd"}
user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Tester 2", Password: "pwd"}
user2 = Client2.Must(Client2.CreateUser(user2, "")).Data.(*model.User)
LinkUserToTeam(user2, team)
Client2.SetTeamId(team.Id)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
Client2.LoginByEmail(team.Name, user2.Email, "pwd")
@ -784,24 +641,14 @@ func TestGetChannelExtraInfo(t *testing.T) {
}
func TestAddChannelMember(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
user2 := th.BasicUser2
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
if _, err := Client.AddChannelMember(channel1.Id, user2.Id); err != nil {
t.Fatal(err)
}
@ -825,13 +672,13 @@ func TestAddChannelMember(t *testing.T) {
channel2 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
Client.LoginByEmail(team.Name, user2.Email, "pwd")
th.LoginBasic2()
if _, err := Client.AddChannelMember(channel2.Id, user2.Id); err == nil {
t.Fatal("Should have errored, user not in channel")
}
Client.LoginByEmail(team.Name, user1.Email, "pwd")
th.LoginBasic()
Client.Must(Client.DeleteChannel(channel2.Id))
@ -842,34 +689,24 @@ func TestAddChannelMember(t *testing.T) {
}
func TestRemoveChannelMember(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
userTeamAdmin := &model.User{TeamId: team.Id, Email: team.Email, Nickname: "Corey Hulen", Password: "pwd"}
userTeamAdmin = Client.Must(Client.CreateUser(userTeamAdmin, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(userTeamAdmin.Id))
userChannelAdmin := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
userChannelAdmin = Client.Must(Client.CreateUser(userChannelAdmin, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(userChannelAdmin.Id))
Client.LoginByEmail(team.Name, userChannelAdmin.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
user2 := th.BasicUser2
UpdateUserToTeamAdmin(user2, team)
channelMadeByCA := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channelMadeByCA = Client.Must(Client.CreateChannel(channelMadeByCA)).Data.(*model.Channel)
Client.Must(Client.AddChannelMember(channelMadeByCA.Id, userTeamAdmin.Id))
Client.Must(Client.AddChannelMember(channelMadeByCA.Id, user2.Id))
Client.LoginByEmail(team.Name, userTeamAdmin.Email, "pwd")
th.LoginBasic2()
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
userStd := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
userStd = Client.Must(Client.CreateUser(userStd, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(userStd.Id))
userStd := th.CreateUser(th.BasicClient)
LinkUserToTeam(userStd, team)
Client.Must(Client.AddChannelMember(channel1.Id, userStd.Id))
@ -894,13 +731,13 @@ func TestRemoveChannelMember(t *testing.T) {
channel2 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
Client.LoginByEmail(team.Name, userStd.Email, "pwd")
Client.LoginByEmail(team.Name, userStd.Email, userStd.Password)
if _, err := Client.RemoveChannelMember(channel2.Id, userStd.Id); err == nil {
t.Fatal("Should have errored, user not channel admin")
}
Client.LoginByEmail(team.Name, userTeamAdmin.Email, "pwd")
th.LoginBasic2()
Client.Must(Client.AddChannelMember(channel2.Id, userStd.Id))
Client.Must(Client.DeleteChannel(channel2.Id))
@ -912,16 +749,11 @@ func TestRemoveChannelMember(t *testing.T) {
}
func TestUpdateNotifyProps(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
user := th.BasicUser
user2 := th.BasicUser2
channel1 := &model.Channel{DisplayName: "A Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
@ -1019,10 +851,7 @@ func TestUpdateNotifyProps(t *testing.T) {
t.Fatal("Should have errored - bad mark unread level")
}
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
Client.LoginByEmail(team.Name, user2.Email, "pwd")
th.LoginBasic2()
data["channel_id"] = channel1.Id
data["user_id"] = user2.Id
@ -1034,16 +863,9 @@ func TestUpdateNotifyProps(t *testing.T) {
}
func TestFuzzyChannel(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
// Strings that should pass as acceptable channel names
var fuzzyStringsPass = []string{

View file

@ -12,7 +12,7 @@ import (
"strings"
l4g "github.com/alecthomas/log4go"
"github.com/gorilla/mux"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
)
@ -38,23 +38,21 @@ func GetCommandProvider(name string) CommandProvider {
return nil
}
func InitCommand(r *mux.Router) {
func InitCommand() {
l4g.Debug(utils.T("api.command.init.debug"))
sr := r.PathPrefix("/commands").Subrouter()
BaseRoutes.Commands.Handle("/execute", ApiUserRequired(executeCommand)).Methods("POST")
BaseRoutes.Commands.Handle("/list", ApiUserRequired(listCommands)).Methods("GET")
sr.Handle("/execute", ApiUserRequired(executeCommand)).Methods("POST")
sr.Handle("/list", ApiUserRequired(listCommands)).Methods("GET")
BaseRoutes.Commands.Handle("/create", ApiUserRequired(createCommand)).Methods("POST")
BaseRoutes.Commands.Handle("/list_team_commands", ApiUserRequired(listTeamCommands)).Methods("GET")
BaseRoutes.Commands.Handle("/regen_token", ApiUserRequired(regenCommandToken)).Methods("POST")
BaseRoutes.Commands.Handle("/delete", ApiUserRequired(deleteCommand)).Methods("POST")
sr.Handle("/create", ApiUserRequired(createCommand)).Methods("POST")
sr.Handle("/list_team_commands", ApiUserRequired(listTeamCommands)).Methods("GET")
sr.Handle("/regen_token", ApiUserRequired(regenCommandToken)).Methods("POST")
sr.Handle("/delete", ApiUserRequired(deleteCommand)).Methods("POST")
sr.Handle("/test", ApiAppHandler(testCommand)).Methods("POST")
sr.Handle("/test", ApiAppHandler(testCommand)).Methods("GET")
sr.Handle("/test_e", ApiAppHandler(testEphemeralCommand)).Methods("POST")
sr.Handle("/test_e", ApiAppHandler(testEphemeralCommand)).Methods("GET")
BaseRoutes.Teams.Handle("/command_test", ApiAppHandler(testCommand)).Methods("POST")
BaseRoutes.Teams.Handle("/command_test", ApiAppHandler(testCommand)).Methods("GET")
BaseRoutes.Teams.Handle("/command_test_e", ApiAppHandler(testEphemeralCommand)).Methods("POST")
BaseRoutes.Teams.Handle("/command_test_e", ApiAppHandler(testEphemeralCommand)).Methods("GET")
}
func listCommands(c *Context, w http.ResponseWriter, r *http.Request) {
@ -70,7 +68,7 @@ func listCommands(c *Context, w http.ResponseWriter, r *http.Request) {
}
if *utils.Cfg.ServiceSettings.EnableCommands {
if result := <-Srv.Store.Command().GetByTeam(c.Session.TeamId); result.Err != nil {
if result := <-Srv.Store.Command().GetByTeam(c.TeamId); result.Err != nil {
c.Err = result.Err
return
} else {
@ -99,7 +97,7 @@ func executeCommand(c *Context, w http.ResponseWriter, r *http.Request) {
}
if len(channelId) > 0 {
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, channelId, c.Session.UserId)
cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, channelId, c.Session.UserId)
if !c.HasPermissionsToChannel(cchan, "checkCommand") {
return
@ -124,10 +122,10 @@ func executeCommand(c *Context, w http.ResponseWriter, r *http.Request) {
}
chanChan := Srv.Store.Channel().Get(channelId)
teamChan := Srv.Store.Team().Get(c.Session.TeamId)
teamChan := Srv.Store.Team().Get(c.TeamId)
userChan := Srv.Store.User().Get(c.Session.UserId)
if result := <-Srv.Store.Command().GetByTeam(c.Session.TeamId); result.Err != nil {
if result := <-Srv.Store.Command().GetByTeam(c.TeamId); result.Err != nil {
c.Err = result.Err
return
} else {
@ -254,7 +252,7 @@ func handleResponse(c *Context, w http.ResponseWriter, response *model.CommandRe
post.Message = response.Text
post.CreateAt = model.GetMillis()
SendEphemeralPost(
c.Session.TeamId,
c.TeamId,
c.Session.UserId,
post,
)
@ -288,7 +286,7 @@ func createCommand(c *Context, w http.ResponseWriter, r *http.Request) {
}
cmd.CreatorId = c.Session.UserId
cmd.TeamId = c.Session.TeamId
cmd.TeamId = c.TeamId
if result := <-Srv.Store.Command().Save(cmd); result.Err != nil {
c.Err = result.Err
@ -315,7 +313,7 @@ func listTeamCommands(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
if result := <-Srv.Store.Command().GetByTeam(c.Session.TeamId); result.Err != nil {
if result := <-Srv.Store.Command().GetByTeam(c.TeamId); result.Err != nil {
c.Err = result.Err
return
} else {
@ -356,7 +354,7 @@ func regenCommandToken(c *Context, w http.ResponseWriter, r *http.Request) {
} else {
cmd = result.Data.(*model.Command)
if c.Session.TeamId != cmd.TeamId || (c.Session.UserId != cmd.CreatorId && !c.IsTeamAdmin()) {
if c.TeamId != cmd.TeamId || (c.Session.UserId != cmd.CreatorId && !c.IsTeamAdmin()) {
c.LogAudit("fail - inappropriate permissions")
c.Err = model.NewLocAppError("regenToken", "api.command.regen.app_error", nil, "user_id="+c.Session.UserId)
return
@ -402,7 +400,7 @@ func deleteCommand(c *Context, w http.ResponseWriter, r *http.Request) {
c.Err = result.Err
return
} else {
if c.Session.TeamId != result.Data.(*model.Command).TeamId || (c.Session.UserId != result.Data.(*model.Command).CreatorId && !c.IsTeamAdmin()) {
if c.TeamId != result.Data.(*model.Command).TeamId || (c.Session.UserId != result.Data.(*model.Command).CreatorId && !c.IsTeamAdmin()) {
c.LogAudit("fail - inappropriate permissions")
c.Err = model.NewLocAppError("deleteCommand", "api.command.delete.app_error", nil, "user_id="+c.Session.UserId)
return

View file

@ -8,23 +8,12 @@ import (
"time"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
)
func TestEchoCommand(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "AA", Name: "aa" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
channel1 := th.BasicChannel
echoTestString := "/echo test"
@ -36,7 +25,7 @@ func TestEchoCommand(t *testing.T) {
time.Sleep(100 * time.Millisecond)
p1 := Client.Must(Client.GetPosts(channel1.Id, 0, 2, "")).Data.(*model.PostList)
if len(p1.Order) != 1 {
if len(p1.Order) != 2 {
t.Fatal("Echo command failed to send")
}
}

View file

@ -33,7 +33,7 @@ func (me *JoinProvider) GetCommand(c *Context) *model.Command {
}
func (me *JoinProvider) DoCommand(c *Context, channelId string, message string) *model.CommandResponse {
if result := <-Srv.Store.Channel().GetMoreChannels(c.Session.TeamId, c.Session.UserId); result.Err != nil {
if result := <-Srv.Store.Channel().GetMoreChannels(c.TeamId, c.Session.UserId); result.Err != nil {
return &model.CommandResponse{Text: c.T("api.command_join.list.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
} else {
channels := result.Data.(*model.ChannelList)

View file

@ -8,20 +8,13 @@ import (
"testing"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
)
func TestJoinCommands(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
user2 := th.BasicUser2
channel0 := &model.Channel{DisplayName: "00", Name: "00" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel0 = Client.Must(Client.CreateChannel(channel0)).Data.(*model.Channel)
@ -34,13 +27,7 @@ func TestJoinCommands(t *testing.T) {
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
Client.Must(Client.LeaveChannel(channel2.Id))
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
data := make(map[string]string)
data["user_id"] = user2.Id
channel3 := Client.Must(Client.CreateDirectChannel(data)).Data.(*model.Channel)
channel3 := Client.Must(Client.CreateDirectChannel(user2.Id)).Data.(*model.Channel)
rs5 := Client.Must(Client.Command(channel0.Id, "/join "+channel2.Name, false)).Data.(*model.CommandResponse)
if !strings.HasSuffix(rs5.GotoLocation, "/"+team.Name+"/channels/"+channel2.Name) {
@ -54,7 +41,7 @@ func TestJoinCommands(t *testing.T) {
c1 := Client.Must(Client.GetChannels("")).Data.(*model.ChannelList)
if len(c1.Channels) != 5 { // 4 because of town-square, off-topic and direct
if len(c1.Channels) != 6 { // 4 because of town-square, off-topic and direct
t.Fatal("didn't join channel")
}

View file

@ -182,10 +182,19 @@ func (me *LoadTestProvider) SetupCommand(c *Context, channelId string, message s
}
}
} else {
var team *model.Team
if tr := <-Srv.Store.Team().Get(c.TeamId); tr.Err != nil {
return &model.CommandResponse{Text: "Failed to create testing environment", ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
} else {
team = tr.Data.(*model.Team)
}
client.MockSession(c.Session.Token)
client.SetTeamId(c.TeamId)
CreateTestEnvironmentInTeam(
client,
c.Session.TeamId,
team,
utils.Range{numChannels, numChannels},
utils.Range{numUsers, numUsers},
utils.Range{numPosts, numPosts},
@ -209,8 +218,16 @@ func (me *LoadTestProvider) UsersCommand(c *Context, channelId string, message s
usersr = utils.Range{2, 5}
}
var team *model.Team
if tr := <-Srv.Store.Team().Get(c.TeamId); tr.Err != nil {
return &model.CommandResponse{Text: "Failed to create testing environment", ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
} else {
team = tr.Data.(*model.Team)
}
client := model.NewClient(c.GetSiteURL())
userCreator := NewAutoUserCreator(client, c.Session.TeamId)
client.SetTeamId(team.Id)
userCreator := NewAutoUserCreator(client, team)
userCreator.Fuzzy = doFuzz
userCreator.CreateTestUsers(usersr)
@ -230,9 +247,18 @@ func (me *LoadTestProvider) ChannelsCommand(c *Context, channelId string, messag
if err == false {
channelsr = utils.Range{2, 5}
}
var team *model.Team
if tr := <-Srv.Store.Team().Get(c.TeamId); tr.Err != nil {
return &model.CommandResponse{Text: "Failed to create testing environment", ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
} else {
team = tr.Data.(*model.Team)
}
client := model.NewClient(c.GetSiteURL())
client.SetTeamId(team.Id)
client.MockSession(c.Session.Token)
channelCreator := NewAutoChannelCreator(client, c.Session.TeamId)
channelCreator := NewAutoChannelCreator(client, team)
channelCreator.Fuzzy = doFuzz
channelCreator.CreateTestChannels(channelsr)
@ -262,7 +288,7 @@ func (me *LoadTestProvider) PostsCommand(c *Context, channelId string, message s
}
var usernames []string
if result := <-Srv.Store.User().GetProfiles(c.Session.TeamId); result.Err == nil {
if result := <-Srv.Store.User().GetProfiles(c.TeamId); result.Err == nil {
profileUsers := result.Data.(map[string]*model.User)
usernames = make([]string, len(profileUsers))
i := 0
@ -273,6 +299,7 @@ func (me *LoadTestProvider) PostsCommand(c *Context, channelId string, message s
}
client := model.NewClient(c.GetSiteURL())
client.SetTeamId(c.TeamId)
client.MockSession(c.Session.Token)
testPoster := NewAutoPostCreator(client, channelId)
testPoster.Fuzzy = doFuzz

View file

@ -9,12 +9,14 @@ import (
"time"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
)
func TestLoadTestHelpCommands(t *testing.T) {
Setup()
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
// enable testing to use /loadtest but don't save it since we don't want to overwrite config.json
enableTesting := utils.Cfg.ServiceSettings.EnableTesting
defer func() {
@ -23,18 +25,6 @@ func TestLoadTestHelpCommands(t *testing.T) {
utils.Cfg.ServiceSettings.EnableTesting = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel := &model.Channel{DisplayName: "00", Name: "00" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel = Client.Must(Client.CreateChannel(channel)).Data.(*model.Channel)
rs := Client.Must(Client.Command(channel.Id, "/loadtest help", false)).Data.(*model.CommandResponse)
if !strings.Contains(rs.Text, "Mattermost load testing commands to help") {
t.Fatal(rs.Text)
@ -44,7 +34,10 @@ func TestLoadTestHelpCommands(t *testing.T) {
}
func TestLoadTestSetupCommands(t *testing.T) {
Setup()
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
// enable testing to use /loadtest but don't save it since we don't want to overwrite config.json
enableTesting := utils.Cfg.ServiceSettings.EnableTesting
defer func() {
@ -53,18 +46,6 @@ func TestLoadTestSetupCommands(t *testing.T) {
utils.Cfg.ServiceSettings.EnableTesting = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel := &model.Channel{DisplayName: "00", Name: "00" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel = Client.Must(Client.CreateChannel(channel)).Data.(*model.Channel)
rs := Client.Must(Client.Command(channel.Id, "/loadtest setup fuzz 1 1 1", false)).Data.(*model.CommandResponse)
if rs.Text != "Creating enviroment..." {
t.Fatal(rs.Text)
@ -74,7 +55,10 @@ func TestLoadTestSetupCommands(t *testing.T) {
}
func TestLoadTestUsersCommands(t *testing.T) {
Setup()
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
// enable testing to use /loadtest but don't save it since we don't want to overwrite config.json
enableTesting := utils.Cfg.ServiceSettings.EnableTesting
defer func() {
@ -83,18 +67,6 @@ func TestLoadTestUsersCommands(t *testing.T) {
utils.Cfg.ServiceSettings.EnableTesting = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel := &model.Channel{DisplayName: "00", Name: "00" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel = Client.Must(Client.CreateChannel(channel)).Data.(*model.Channel)
rs := Client.Must(Client.Command(channel.Id, "/loadtest users fuzz 1 2", false)).Data.(*model.CommandResponse)
if rs.Text != "Adding users..." {
t.Fatal(rs.Text)
@ -104,7 +76,10 @@ func TestLoadTestUsersCommands(t *testing.T) {
}
func TestLoadTestChannelsCommands(t *testing.T) {
Setup()
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
// enable testing to use /loadtest but don't save it since we don't want to overwrite config.json
enableTesting := utils.Cfg.ServiceSettings.EnableTesting
defer func() {
@ -113,18 +88,6 @@ func TestLoadTestChannelsCommands(t *testing.T) {
utils.Cfg.ServiceSettings.EnableTesting = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel := &model.Channel{DisplayName: "00", Name: "00" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel = Client.Must(Client.CreateChannel(channel)).Data.(*model.Channel)
rs := Client.Must(Client.Command(channel.Id, "/loadtest channels fuzz 1 2", false)).Data.(*model.CommandResponse)
if rs.Text != "Adding channels..." {
t.Fatal(rs.Text)
@ -134,7 +97,10 @@ func TestLoadTestChannelsCommands(t *testing.T) {
}
func TestLoadTestPostsCommands(t *testing.T) {
Setup()
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
// enable testing to use /loadtest but don't save it since we don't want to overwrite config.json
enableTesting := utils.Cfg.ServiceSettings.EnableTesting
defer func() {
@ -143,18 +109,6 @@ func TestLoadTestPostsCommands(t *testing.T) {
utils.Cfg.ServiceSettings.EnableTesting = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel := &model.Channel{DisplayName: "00", Name: "00" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel = Client.Must(Client.CreateChannel(channel)).Data.(*model.Channel)
rs := Client.Must(Client.Command(channel.Id, "/loadtest posts fuzz 2 3 2", false)).Data.(*model.CommandResponse)
if rs.Text != "Adding posts..." {
t.Fatal(rs.Text)
@ -164,7 +118,10 @@ func TestLoadTestPostsCommands(t *testing.T) {
}
func TestLoadTestUrlCommands(t *testing.T) {
Setup()
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
// enable testing to use /loadtest but don't save it since we don't want to overwrite config.json
enableTesting := utils.Cfg.ServiceSettings.EnableTesting
defer func() {
@ -173,18 +130,6 @@ func TestLoadTestUrlCommands(t *testing.T) {
utils.Cfg.ServiceSettings.EnableTesting = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel := &model.Channel{DisplayName: "00", Name: "00" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel = Client.Must(Client.CreateChannel(channel)).Data.(*model.Channel)
command := "/loadtest url "
if r := Client.Must(Client.Command(channel.Id, command, false)).Data.(*model.CommandResponse); r.Text != "Command must contain a url" {
t.Fatal("/loadtest url with no url should've failed")
@ -223,7 +168,10 @@ func TestLoadTestUrlCommands(t *testing.T) {
}
func TestLoadTestJsonCommands(t *testing.T) {
Setup()
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
// enable testing to use /loadtest but don't save it since we don't want to overwrite config.json
enableTesting := utils.Cfg.ServiceSettings.EnableTesting
defer func() {
@ -232,18 +180,6 @@ func TestLoadTestJsonCommands(t *testing.T) {
utils.Cfg.ServiceSettings.EnableTesting = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel := &model.Channel{DisplayName: "00", Name: "00" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel = Client.Must(Client.CreateChannel(channel)).Data.(*model.Channel)
command := "/loadtest json "
if r := Client.Must(Client.Command(channel.Id, command, false)).Data.(*model.CommandResponse); r.Text != "Command must contain a url" {
t.Fatal("/loadtest url with no url should've failed")
@ -255,9 +191,9 @@ func TestLoadTestJsonCommands(t *testing.T) {
t.Fatal("/loadtest url with invalid url should've failed")
}
command = "/loadtest url https://secure.beldienst.nl/test.json" // Chicken-egg so will replace with mattermost/platform URL soon
command = "/loadtest json test-slack-attachments"
if r := Client.Must(Client.Command(channel.Id, command, false)).Data.(*model.CommandResponse); r.Text != "Loading data..." {
t.Fatal("/loadtest url for README.md should've executed")
t.Fatal("/loadtest json should've executed")
}
time.Sleep(2 * time.Second)

View file

@ -8,25 +8,12 @@ import (
"testing"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
)
func TestLogoutTestCommand(t *testing.T) {
Setup()
th := Setup().InitBasic()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "AA", Name: "aa" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
rs1 := Client.Must(Client.Command(channel1.Id, "/logout", false)).Data.(*model.CommandResponse)
rs1 := th.BasicClient.Must(th.BasicClient.Command(th.BasicChannel.Id, "/logout", false)).Data.(*model.CommandResponse)
if !strings.HasSuffix(rs1.GotoLocation, "logout") {
t.Fatal("failed to logout")
}

View file

@ -8,35 +8,24 @@ import (
"time"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
)
func TestMeCommand(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "AA", Name: "aa" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
testString := "/me hello"
r1 := Client.Must(Client.Command(channel1.Id, testString, false)).Data.(*model.CommandResponse)
r1 := Client.Must(Client.Command(channel.Id, testString, false)).Data.(*model.CommandResponse)
if r1 == nil {
t.Fatal("Command failed to execute")
}
time.Sleep(100 * time.Millisecond)
p1 := Client.Must(Client.GetPosts(channel1.Id, 0, 2, "")).Data.(*model.PostList)
if len(p1.Order) != 1 {
p1 := Client.Must(Client.GetPosts(channel.Id, 0, 2, "")).Data.(*model.PostList)
if len(p1.Order) != 2 {
t.Fatal("Command failed to send")
} else {
if p1.Posts[p1.Order[0]].Message != `*hello*` {

View file

@ -46,7 +46,7 @@ func (me *msgProvider) DoCommand(c *Context, channelId string, message string) *
targetUser = strings.SplitN(message, " ", 2)[0]
targetUser = strings.TrimPrefix(targetUser, "@")
if profileList := <-Srv.Store.User().GetProfiles(c.Session.TeamId); profileList.Err != nil {
if profileList := <-Srv.Store.User().GetProfiles(c.TeamId); profileList.Err != nil {
c.Err = profileList.Err
return &model.CommandResponse{Text: c.T("api.command_msg.list.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
} else {
@ -62,7 +62,7 @@ func (me *msgProvider) DoCommand(c *Context, channelId string, message string) *
//Find the channel based on this user
channelName := model.GetDMNameFromIds(c.Session.UserId, userProfile.Id)
if channel := <-Srv.Store.Channel().GetByName(c.Session.TeamId, channelName); channel.Err != nil {
if channel := <-Srv.Store.Channel().GetByName(c.TeamId, channelName); channel.Err != nil {
if channel.Err.Id == "store.sql_channel.get_by_name.missing.app_error" {
if directChannel, err := CreateDirectChannel(c, userProfile.Id); err != nil {
c.Err = err
@ -78,7 +78,7 @@ func (me *msgProvider) DoCommand(c *Context, channelId string, message string) *
targetChannelId = channel.Data.(*model.Channel).Id
}
makeDirectChannelVisible(c.Session.TeamId, targetChannelId)
makeDirectChannelVisible(c.TeamId, targetChannelId)
if len(parsedMessage) > 0 {
post := &model.Post{}
post.Message = parsedMessage
@ -87,9 +87,11 @@ func (me *msgProvider) DoCommand(c *Context, channelId string, message string) *
return &model.CommandResponse{Text: c.T("api.command_msg.fail.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
}
}
return &model.CommandResponse{GotoLocation: c.GetTeamURL() + "/channels/" + channelName, Text: c.T("api.command_msg.success"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
}
}
}
return &model.CommandResponse{Text: c.T("api.command_msg.missing.app_error"), ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL}
}

View file

@ -4,39 +4,29 @@
package api
import (
"github.com/mattermost/platform/model"
"strings"
"testing"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
)
func TestMsgCommands(t *testing.T) {
Setup()
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
user1 := th.BasicUser
user2 := th.BasicUser2
user3 := th.CreateUser(th.BasicClient)
LinkUserToTeam(user3, team)
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "success+test@simulator.amazonses.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
Client.Must(Client.CreateDirectChannel(user2.Id))
Client.Must(Client.CreateDirectChannel(user3.Id))
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Username: "user1", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test2@simulator.amazonses.com", Nickname: "Corey Hulen 2", Username: "user2", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
user3 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test3@simulator.amazonses.com", Nickname: "Corey Hulen 3", Username: "user3", Password: "pwd"}
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
rs1 := Client.Must(Client.Command("", "/msg user2", false)).Data.(*model.CommandResponse)
rs1 := Client.Must(Client.Command("", "/msg "+user2.Username, false)).Data.(*model.CommandResponse)
if !strings.HasSuffix(rs1.GotoLocation, "/"+team.Name+"/channels/"+user1.Id+"__"+user2.Id) && !strings.HasSuffix(rs1.GotoLocation, "/"+team.Name+"/channels/"+user2.Id+"__"+user1.Id) {
t.Fatal("failed to create direct channel")
}
rs2 := Client.Must(Client.Command("", "/msg user3 foobar", false)).Data.(*model.CommandResponse)
rs2 := Client.Must(Client.Command("", "/msg "+user3.Username+" foobar", false)).Data.(*model.CommandResponse)
if !strings.HasSuffix(rs2.GotoLocation, "/"+team.Name+"/channels/"+user1.Id+"__"+user3.Id) && !strings.HasSuffix(rs2.GotoLocation, "/"+team.Name+"/channels/"+user3.Id+"__"+user1.Id) {
t.Fatal("failed to create second direct channel")
}
@ -44,7 +34,7 @@ func TestMsgCommands(t *testing.T) {
t.Fatalf("post did not get sent to direct message")
}
rs3 := Client.Must(Client.Command("", "/msg user2", false)).Data.(*model.CommandResponse)
rs3 := Client.Must(Client.Command("", "/msg "+user2.Username, false)).Data.(*model.CommandResponse)
if !strings.HasSuffix(rs3.GotoLocation, "/"+team.Name+"/channels/"+user1.Id+"__"+user2.Id) && !strings.HasSuffix(rs3.GotoLocation, "/"+team.Name+"/channels/"+user2.Id+"__"+user1.Id) {
t.Fatal("failed to go back to existing direct channel")
}

View file

@ -8,35 +8,24 @@ import (
"time"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
)
func TestShrugCommand(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "AA", Name: "aa" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
testString := "/shrug"
r1 := Client.Must(Client.Command(channel1.Id, testString, false)).Data.(*model.CommandResponse)
r1 := Client.Must(Client.Command(channel.Id, testString, false)).Data.(*model.CommandResponse)
if r1 == nil {
t.Fatal("Command failed to execute")
}
time.Sleep(100 * time.Millisecond)
p1 := Client.Must(Client.GetPosts(channel1.Id, 0, 2, "")).Data.(*model.PostList)
if len(p1.Order) != 1 {
p1 := Client.Must(Client.GetPosts(channel.Id, 0, 2, "")).Data.(*model.PostList)
if len(p1.Order) != 2 {
t.Fatal("Command failed to send")
} else {
if p1.Posts[p1.Order[0]].Message != `¯\\\_(ツ)\_/¯` {

View file

@ -8,21 +8,12 @@ import (
"time"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
)
func TestListCommands(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
if results, err := Client.ListCommands(); err != nil {
t.Fatal(err)
@ -43,7 +34,10 @@ func TestListCommands(t *testing.T) {
}
func TestCreateCommand(t *testing.T) {
Setup()
th := Setup().InitBasic().InitSystemAdmin()
Client := th.BasicClient
user := th.SystemAdminUser
team := th.SystemAdminTeam
enableCommands := *utils.Cfg.ServiceSettings.EnableCommands
defer func() {
@ -51,26 +45,13 @@ func TestCreateCommand(t *testing.T) {
}()
*utils.Cfg.ServiceSettings.EnableCommands = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
cmd := &model.Command{URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST}
cmd := &model.Command{URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST, Trigger: "trigger"}
if _, err := Client.CreateCommand(cmd); err == nil {
t.Fatal("should have failed because not admin")
}
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
Client = th.SystemAdminClient
var rcmd *model.Command
if result, err := Client.CreateCommand(cmd); err != nil {
@ -87,7 +68,7 @@ func TestCreateCommand(t *testing.T) {
t.Fatal("team ids didn't match")
}
cmd = &model.Command{CreatorId: "123", TeamId: "456", URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST}
cmd = &model.Command{CreatorId: "123", TeamId: "456", URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST, Trigger: "trigger"}
if result, err := Client.CreateCommand(cmd); err != nil {
t.Fatal(err)
} else {
@ -101,27 +82,16 @@ func TestCreateCommand(t *testing.T) {
}
func TestListTeamCommands(t *testing.T) {
Setup()
th := Setup().InitSystemAdmin()
Client := th.SystemAdminClient
enableCommands := *utils.Cfg.ServiceSettings.EnableCommands
defer func() {
utils.Cfg.ServiceSettings.EnableCommands = &enableCommands
}()
*utils.Cfg.ServiceSettings.EnableCommands = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
cmd1 := &model.Command{URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST}
cmd1 := &model.Command{URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST, Trigger: "trigger"}
cmd1 = Client.Must(Client.CreateCommand(cmd1)).Data.(*model.Command)
if result, err := Client.ListTeamCommands(); err != nil {
@ -136,27 +106,16 @@ func TestListTeamCommands(t *testing.T) {
}
func TestRegenToken(t *testing.T) {
Setup()
th := Setup().InitSystemAdmin()
Client := th.SystemAdminClient
enableCommands := *utils.Cfg.ServiceSettings.EnableCommands
defer func() {
utils.Cfg.ServiceSettings.EnableCommands = &enableCommands
}()
*utils.Cfg.ServiceSettings.EnableCommands = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "corey+test@test.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
cmd := &model.Command{URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST}
cmd := &model.Command{URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST, Trigger: "trigger"}
cmd = Client.Must(Client.CreateCommand(cmd)).Data.(*model.Command)
data := make(map[string]string)
@ -172,27 +131,16 @@ func TestRegenToken(t *testing.T) {
}
func TestDeleteCommand(t *testing.T) {
Setup()
th := Setup().InitSystemAdmin()
Client := th.SystemAdminClient
enableCommands := *utils.Cfg.ServiceSettings.EnableCommands
defer func() {
utils.Cfg.ServiceSettings.EnableCommands = &enableCommands
}()
*utils.Cfg.ServiceSettings.EnableCommands = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
cmd := &model.Command{URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST}
cmd := &model.Command{URL: "http://nowhere.com", Method: model.COMMAND_METHOD_POST, Trigger: "trigger"}
cmd = Client.Must(Client.CreateCommand(cmd)).Data.(*model.Command)
data := make(map[string]string)
@ -209,31 +157,18 @@ func TestDeleteCommand(t *testing.T) {
}
func TestTestCommand(t *testing.T) {
Setup()
th := Setup().InitSystemAdmin()
Client := th.SystemAdminClient
channel1 := th.SystemAdminChannel
enableCommands := *utils.Cfg.ServiceSettings.EnableCommands
defer func() {
utils.Cfg.ServiceSettings.EnableCommands = &enableCommands
}()
*utils.Cfg.ServiceSettings.EnableCommands = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
channel1 := &model.Channel{DisplayName: "AA", Name: "aa" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
cmd1 := &model.Command{
URL: "http://localhost" + utils.Cfg.ServiceSettings.ListenAddress + "/api/v1/commands/test",
URL: "http://localhost" + utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX + "/teams/command_test",
Method: model.COMMAND_METHOD_POST,
Trigger: "test",
}
@ -253,7 +188,7 @@ func TestTestCommand(t *testing.T) {
}
cmd2 := &model.Command{
URL: "http://localhost" + utils.Cfg.ServiceSettings.ListenAddress + "/api/v1/commands/test",
URL: "http://localhost" + utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX + "/teams/command_test",
Method: model.COMMAND_METHOD_GET,
Trigger: "test2",
}

View file

@ -11,10 +11,12 @@ import (
"strings"
l4g "github.com/alecthomas/log4go"
"github.com/gorilla/mux"
goi18n "github.com/nicksnyder/go-i18n/i18n"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
goi18n "github.com/nicksnyder/go-i18n/i18n"
)
var sessionCache *utils.Cache = utils.NewLru(model.SESSION_CACHE_SIZE)
@ -39,6 +41,7 @@ type Context struct {
siteURL string
T goi18n.TranslateFunc
Locale string
TeamId string
}
func ApiAppHandler(h func(*Context, http.ResponseWriter, *http.Request)) http.Handler {
@ -94,6 +97,8 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
c.T, c.Locale = utils.GetTranslationsAndLocale(w, r)
c.RequestId = model.NewId()
c.IpAddress = GetIpAddress(r)
c.TeamId = mux.Vars(r)["team_id"]
h.isApi = IsApiCall(r)
token := ""
isTokenFromQueryString := false
@ -116,7 +121,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if (h.requireSystemAdmin || h.requireUser) && !h.trustRequester {
if r.Header.Get(model.HEADER_REQUESTED_WITH) != model.HEADER_REQUESTED_WITH_XML {
c.Err = model.NewLocAppError("ServeHTTP", "api.context.session_expired.app_error", nil, "token="+token)
c.Err = model.NewLocAppError("ServeHTTP", "api.context.session_expired.app_error", nil, "token="+token+" Appears to bea CSRF attempt")
token = ""
}
}
@ -182,6 +187,10 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
c.SystemAdminRequired()
}
if c.Err == nil && len(c.TeamId) > 0 {
c.HasPermissionsToTeam(c.TeamId, "TeamRoute")
}
if c.Err == nil && h.isUserActivity && token != "" && len(c.Session.UserId) > 0 {
go func() {
if err := (<-Srv.Store.User().UpdateUserAndSessionActivity(c.Session.UserId, c.Session.Id, model.GetMillis())).Err; err != nil {
@ -308,13 +317,14 @@ func (c *Context) HasPermissionsToUser(userId string, where string) bool {
}
func (c *Context) HasPermissionsToTeam(teamId string, where string) bool {
if c.Session.TeamId == teamId {
if c.IsSystemAdmin() {
return true
}
// You're a mattermost system admin and you're on the VPN
if c.IsSystemAdmin() {
return true
for _, teamMember := range c.Session.TeamMembers {
if teamId == teamMember.TeamId {
return true
}
}
c.Err = model.NewLocAppError(where, "api.context.permissions.app_error", nil, "userId="+c.Session.UserId+", teamId="+teamId)
@ -353,10 +363,17 @@ func (c *Context) IsSystemAdmin() bool {
}
func (c *Context) IsTeamAdmin() bool {
if model.IsInRole(c.Session.Roles, model.ROLE_TEAM_ADMIN) || c.IsSystemAdmin() {
if c.IsSystemAdmin() {
return true
}
return false
team := c.Session.GetTeamByTeamId(c.TeamId)
if team == nil {
return false
}
return model.IsInRole(team.Roles, model.ROLE_TEAM_ADMIN)
}
func (c *Context) RemoveSessionCookie(w http.ResponseWriter, r *http.Request) {
@ -386,7 +403,7 @@ func (c *Context) setTeamURL(url string, valid bool) {
}
func (c *Context) SetTeamURLFromSession() {
if result := <-Srv.Store.Team().Get(c.Session.TeamId); result.Err == nil {
if result := <-Srv.Store.Team().Get(c.TeamId); result.Err == nil {
c.setTeamURL(c.GetSiteURL()+"/"+result.Data.(*model.Team).Name, true)
}
}
@ -413,6 +430,10 @@ func (c *Context) GetSiteURL() string {
return c.siteURL
}
func IsApiCall(r *http.Request) bool {
return strings.Index(r.URL.Path, "/api/") == 0
}
func GetIpAddress(r *http.Request) string {
address := r.Header.Get(model.HEADER_FORWARDED)
@ -427,69 +448,69 @@ func GetIpAddress(r *http.Request) string {
return address
}
func IsTestDomain(r *http.Request) bool {
// func IsTestDomain(r *http.Request) bool {
if strings.Index(r.Host, "localhost") == 0 {
return true
}
// if strings.Index(r.Host, "localhost") == 0 {
// return true
// }
if strings.Index(r.Host, "dockerhost") == 0 {
return true
}
// if strings.Index(r.Host, "dockerhost") == 0 {
// return true
// }
if strings.Index(r.Host, "test") == 0 {
return true
}
// if strings.Index(r.Host, "test") == 0 {
// return true
// }
if strings.Index(r.Host, "127.0.") == 0 {
return true
}
// if strings.Index(r.Host, "127.0.") == 0 {
// return true
// }
if strings.Index(r.Host, "192.168.") == 0 {
return true
}
// if strings.Index(r.Host, "192.168.") == 0 {
// return true
// }
if strings.Index(r.Host, "10.") == 0 {
return true
}
// if strings.Index(r.Host, "10.") == 0 {
// return true
// }
if strings.Index(r.Host, "176.") == 0 {
return true
}
// if strings.Index(r.Host, "176.") == 0 {
// return true
// }
return false
}
// return false
// }
func IsBetaDomain(r *http.Request) bool {
// func IsBetaDomain(r *http.Request) bool {
if strings.Index(r.Host, "beta") == 0 {
return true
}
// if strings.Index(r.Host, "beta") == 0 {
// return true
// }
if strings.Index(r.Host, "ci") == 0 {
return true
}
// if strings.Index(r.Host, "ci") == 0 {
// return true
// }
return false
}
// return false
// }
var privateIpAddress = []*net.IPNet{
{IP: net.IPv4(10, 0, 0, 1), Mask: net.IPv4Mask(255, 0, 0, 0)},
{IP: net.IPv4(176, 16, 0, 1), Mask: net.IPv4Mask(255, 255, 0, 0)},
{IP: net.IPv4(192, 168, 0, 1), Mask: net.IPv4Mask(255, 255, 255, 0)},
{IP: net.IPv4(127, 0, 0, 1), Mask: net.IPv4Mask(255, 255, 255, 252)},
}
// var privateIpAddress = []*net.IPNet{
// {IP: net.IPv4(10, 0, 0, 1), Mask: net.IPv4Mask(255, 0, 0, 0)},
// {IP: net.IPv4(176, 16, 0, 1), Mask: net.IPv4Mask(255, 255, 0, 0)},
// {IP: net.IPv4(192, 168, 0, 1), Mask: net.IPv4Mask(255, 255, 255, 0)},
// {IP: net.IPv4(127, 0, 0, 1), Mask: net.IPv4Mask(255, 255, 255, 252)},
// }
func IsPrivateIpAddress(ipAddress string) bool {
// func IsPrivateIpAddress(ipAddress string) bool {
for _, pips := range privateIpAddress {
if pips.Contains(net.ParseIP(ipAddress)) {
return true
}
}
// for _, pips := range privateIpAddress {
// if pips.Contains(net.ParseIP(ipAddress)) {
// return true
// }
// }
return false
}
// return false
// }
func RenderWebError(err *model.AppError, w http.ResponseWriter, r *http.Request) {
T, _ := utils.GetTranslationsAndLocale(w, r)
@ -513,9 +534,17 @@ func RenderWebError(err *model.AppError, w http.ResponseWriter, r *http.Request)
func Handle404(w http.ResponseWriter, r *http.Request) {
err := model.NewLocAppError("Handle404", "api.context.404.app_error", nil, "")
err.Translate(utils.T)
err.StatusCode = http.StatusNotFound
l4g.Error("%v: code=404 ip=%v", r.URL.Path, GetIpAddress(r))
RenderWebError(err, w, r)
if IsApiCall(r) {
w.WriteHeader(err.StatusCode)
err.DetailedError = "There doesn't appear to be an api call for the url='" + r.URL.Path + "'. Typo? are you missing a team_id or user_id as part of the url?"
w.Write([]byte(err.ToJson()))
} else {
RenderWebError(err, w, r)
}
}
func GetSession(token string) *model.Session {
@ -542,6 +571,20 @@ func GetSession(token string) *model.Session {
return session
}
func RemoveAllSessionsForUserId(userId string) {
keys := sessionCache.Keys()
for _, key := range keys {
if ts, ok := sessionCache.Get(key); ok {
session := ts.(*model.Session)
if session.UserId == userId {
sessionCache.Remove(key)
}
}
}
}
func AddSessionToCache(session *model.Session) {
sessionCache.AddWithExpiresInSecs(session.Token, session, int64(*utils.Cfg.ServiceSettings.SessionCacheInMinutes*60))
}

View file

@ -8,32 +8,6 @@ import (
"testing"
)
var ipAddressTests = []struct {
address string
expected bool
}{
{"126.255.255.255", false},
{"127.0.0.1", true},
{"127.0.0.4", false},
{"9.255.255.255", false},
{"10.0.0.1", true},
{"11.0.0.1", false},
{"176.15.155.255", false},
{"176.16.0.1", true},
{"176.31.0.1", false},
{"192.167.255.255", false},
{"192.168.0.1", true},
{"192.169.0.1", false},
}
func TestIpAddress(t *testing.T) {
for _, v := range ipAddressTests {
if IsPrivateIpAddress(v.address) != v.expected {
t.Errorf("expect %v as %v", v.address, v.expected)
}
}
}
func TestContext(t *testing.T) {
context := Context{}
@ -52,9 +26,26 @@ func TestContext(t *testing.T) {
if !context.HasPermissionsToUser("6", "") {
t.Fatal("should have permissions")
}
// context.IpAddress = "125.0.0.1"
// if context.HasPermissionsToUser("6", "") {
// t.Fatal("shouldn't have permissions")
// }
}
func TestCache(t *testing.T) {
session := &model.Session{
Id: model.NewId(),
Token: model.NewId(),
UserId: model.NewId(),
}
sessionCache.AddWithExpiresInSecs(session.Token, session, 5*60)
keys := sessionCache.Keys()
if len(keys) <= 0 {
t.Fatal("should have items")
}
RemoveAllSessionsForUserId(session.UserId)
rkeys := sessionCache.Keys()
if len(rkeys) != len(keys)-1 {
t.Fatal("should have one less")
}
}

View file

@ -60,7 +60,7 @@ func ExportToFile(options *ExportOptions) (link string, err *model.AppError) {
ExportToWriter(file, options)
}
return "/api/v1/files/get_export", nil
return model.API_URL_SUFFIX + "/files/get_export", nil
}
func ExportToWriter(w io.Writer, options *ExportOptions) *model.AppError {

View file

@ -57,15 +57,14 @@ const (
var fileInfoCache *utils.Cache = utils.NewLru(1000)
func InitFile(r *mux.Router) {
func InitFile() {
l4g.Debug(utils.T("api.file.init.debug"))
sr := r.PathPrefix("/files").Subrouter()
sr.Handle("/upload", ApiUserRequired(uploadFile)).Methods("POST")
sr.Handle("/get/{channel_id:[A-Za-z0-9]+}/{user_id:[A-Za-z0-9]+}/{filename:([A-Za-z0-9]+/)?.+(\\.[A-Za-z0-9]{3,})?}", ApiAppHandlerTrustRequester(getFile)).Methods("GET")
sr.Handle("/get_info/{channel_id:[A-Za-z0-9]+}/{user_id:[A-Za-z0-9]+}/{filename:([A-Za-z0-9]+/)?.+(\\.[A-Za-z0-9]{3,})?}", ApiAppHandler(getFileInfo)).Methods("GET")
sr.Handle("/get_public_link", ApiUserRequired(getPublicLink)).Methods("POST")
sr.Handle("/get_export", ApiUserRequired(getExport)).Methods("GET")
BaseRoutes.Files.Handle("/upload", ApiUserRequired(uploadFile)).Methods("POST")
BaseRoutes.Files.Handle("/get/{channel_id:[A-Za-z0-9]+}/{user_id:[A-Za-z0-9]+}/{filename:([A-Za-z0-9]+/)?.+(\\.[A-Za-z0-9]{3,})?}", ApiAppHandlerTrustRequester(getFile)).Methods("GET")
BaseRoutes.Files.Handle("/get_info/{channel_id:[A-Za-z0-9]+}/{user_id:[A-Za-z0-9]+}/{filename:([A-Za-z0-9]+/)?.+(\\.[A-Za-z0-9]{3,})?}", ApiAppHandler(getFileInfo)).Methods("GET")
BaseRoutes.Files.Handle("/get_public_link", ApiUserRequired(getPublicLink)).Methods("POST")
BaseRoutes.Files.Handle("/get_export", ApiUserRequired(getExport)).Methods("GET")
}
func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) {
@ -101,7 +100,7 @@ func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, channelId, c.Session.UserId)
cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, channelId, c.Session.UserId)
files := m.File["files"]
@ -147,7 +146,7 @@ func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
path := "teams/" + c.Session.TeamId + "/channels/" + channelId + "/users/" + c.Session.UserId + "/" + uid + "/" + filename
path := "teams/" + c.TeamId + "/channels/" + channelId + "/users/" + c.Session.UserId + "/" + uid + "/" + filename
if err := WriteFile(buf.Bytes(), path); err != nil {
c.Err = err
@ -164,7 +163,7 @@ func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) {
resStruct.ClientIds = append(resStruct.ClientIds, clientId)
}
handleImagesAndForget(imageNameList, imageDataList, c.Session.TeamId, channelId, c.Session.UserId)
handleImagesAndForget(imageNameList, imageDataList, c.TeamId, channelId, c.Session.UserId)
w.Write([]byte(resStruct.ToJson()))
}
@ -319,9 +318,9 @@ func getFileInfo(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, channelId, c.Session.UserId)
cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, channelId, c.Session.UserId)
path := "teams/" + c.Session.TeamId + "/channels/" + channelId + "/users/" + userId + "/" + filename
path := "teams/" + c.TeamId + "/channels/" + channelId + "/users/" + userId + "/" + filename
var info *model.FileInfo
if cached, ok := fileInfoCache.Get(path); ok {
@ -380,13 +379,13 @@ func getFile(c *Context, w http.ResponseWriter, r *http.Request) {
data := r.URL.Query().Get("d")
teamId := r.URL.Query().Get("t")
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, channelId, c.Session.UserId)
cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, channelId, c.Session.UserId)
path := ""
if len(teamId) == 26 {
path = "teams/" + teamId + "/channels/" + channelId + "/users/" + userId + "/" + filename
} else {
path = "teams/" + c.Session.TeamId + "/channels/" + channelId + "/users/" + userId + "/" + filename
path = "teams/" + c.TeamId + "/channels/" + channelId + "/users/" + userId + "/" + filename
}
fileData := make(chan []byte)
@ -460,6 +459,7 @@ func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
if !utils.Cfg.FileSettings.EnablePublicLink {
c.Err = model.NewLocAppError("getPublicLink", "api.file.get_public_link.disabled.app_error", nil, "")
c.Err.StatusCode = http.StatusForbidden
return
}
props := model.MapFromJson(r.Body)
@ -480,7 +480,7 @@ func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
userId := matches[0][2]
filename = matches[0][3]
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, channelId, c.Session.UserId)
cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, channelId, c.Session.UserId)
newProps := make(map[string]string)
newProps["filename"] = filename
@ -488,7 +488,7 @@ func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
data := model.MapToJson(newProps)
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.FileSettings.PublicLinkSalt))
url := fmt.Sprintf("%s/api/v1/files/get/%s/%s/%s?d=%s&h=%s&t=%s", c.GetSiteURL(), channelId, userId, filename, url.QueryEscape(data), url.QueryEscape(hash), c.Session.TeamId)
url := fmt.Sprintf("%s/files/get/%s/%s/%s?d=%s&h=%s&t=%s", c.GetSiteURL()+model.API_URL_SUFFIX, channelId, userId, filename, url.QueryEscape(data), url.QueryEscape(hash), c.TeamId)
if !c.HasPermissionsToChannel(cchan, "getPublicLink") {
return
@ -501,7 +501,7 @@ func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
}
func getExport(c *Context, w http.ResponseWriter, r *http.Request) {
if !c.HasPermissionsToTeam(c.Session.TeamId, "export") || !c.IsTeamAdmin() {
if !c.HasPermissionsToTeam(c.TeamId, "export") || !c.IsTeamAdmin() {
c.Err = model.NewLocAppError("getExport", "api.file.get_export.team_admin.app_error", nil, "userId="+c.Session.UserId)
c.Err.StatusCode = http.StatusForbidden
return

View file

@ -13,7 +13,9 @@ import (
)
func BenchmarkUploadFile(b *testing.B) {
_, _, channel := SetupBenchmark()
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
testPoster := NewAutoPostCreator(Client, channel.Id)
@ -25,7 +27,10 @@ func BenchmarkUploadFile(b *testing.B) {
}
func BenchmarkGetFile(b *testing.B) {
team, _, channel := SetupBenchmark()
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
channel := th.BasicChannel
testPoster := NewAutoPostCreator(Client, channel.Id)
filenames, err := testPoster.UploadTestFile()
@ -53,7 +58,9 @@ func BenchmarkGetFile(b *testing.B) {
}
func BenchmarkGetPublicLink(b *testing.B) {
_, _, channel := SetupBenchmark()
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
testPoster := NewAutoPostCreator(Client, channel.Id)
filenames, err := testPoster.UploadTestFile()

View file

@ -22,19 +22,11 @@ import (
)
func TestUploadFile(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
user := th.BasicUser
channel := th.BasicChannel
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
@ -45,6 +37,9 @@ func TestUploadFile(t *testing.T) {
path := utils.FindDir("tests")
file, err := os.Open(path + "/test.png")
if err != nil {
t.Fatal(err)
}
defer file.Close()
_, err = io.Copy(part, file)
@ -57,7 +52,7 @@ func TestUploadFile(t *testing.T) {
t.Fatal(err)
}
_, err = field.Write([]byte(channel1.Id))
_, err = field.Write([]byte(channel.Id))
if err != nil {
t.Fatal(err)
}
@ -67,7 +62,7 @@ func TestUploadFile(t *testing.T) {
t.Fatal(err)
}
resp, appErr := Client.UploadFile("/files/upload", body.Bytes(), writer.FormDataContentType())
resp, appErr := Client.UploadPostAttachment(body.Bytes(), writer.FormDataContentType())
if utils.Cfg.FileSettings.DriverName == model.IMAGE_DRIVER_S3 {
if appErr != nil {
t.Fatal(appErr)
@ -90,17 +85,17 @@ func TestUploadFile(t *testing.T) {
// wait a bit for files to ready
time.Sleep(5 * time.Second)
err = bucket.Del("teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename)
err = bucket.Del("teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + filename)
if err != nil {
t.Fatal(err)
}
err = bucket.Del("teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg")
err = bucket.Del("teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + fileId + "_thumb.jpg")
if err != nil {
t.Fatal(err)
}
err = bucket.Del("teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg")
err = bucket.Del("teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + fileId + "_preview.jpg")
if err != nil {
t.Fatal(err)
}
@ -115,17 +110,17 @@ func TestUploadFile(t *testing.T) {
// wait a bit for files to ready
time.Sleep(5 * time.Second)
path := utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename
path := utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + filename
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg"
path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + fileId + "_thumb.jpg"
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg"
path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + fileId + "_preview.jpg"
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
@ -137,25 +132,18 @@ func TestUploadFile(t *testing.T) {
}
func TestGetFile(t *testing.T) {
Setup()
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
user := th.BasicUser
channel := th.BasicChannel
enablePublicLink := utils.Cfg.FileSettings.EnablePublicLink
defer func() {
utils.Cfg.FileSettings.EnablePublicLink = enablePublicLink
}()
utils.Cfg.FileSettings.EnablePublicLink = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
if utils.Cfg.FileSettings.DriverName != "" {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
@ -181,7 +169,7 @@ func TestGetFile(t *testing.T) {
t.Fatal(err)
}
_, err = field.Write([]byte(channel1.Id))
_, err = field.Write([]byte(channel.Id))
if err != nil {
t.Fatal(err)
}
@ -191,7 +179,7 @@ func TestGetFile(t *testing.T) {
t.Fatal(err)
}
resp, upErr := Client.UploadFile("/files/upload", body.Bytes(), writer.FormDataContentType())
resp, upErr := Client.UploadPostAttachment(body.Bytes(), writer.FormDataContentType())
if upErr != nil {
t.Fatal(upErr)
}
@ -217,8 +205,9 @@ func TestGetFile(t *testing.T) {
team2 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
user2 := &model.User{TeamId: team2.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
LinkUserToTeam(user2, team2)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
newProps := make(map[string]string)
@ -229,6 +218,7 @@ func TestGetFile(t *testing.T) {
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.FileSettings.PublicLinkSalt))
Client.LoginByEmail(team2.Name, user2.Email, "pwd")
Client.SetTeamId(team2.Id)
if _, downErr := Client.GetFile(filenames[0]+"?d="+url.QueryEscape(data)+"&h="+url.QueryEscape(hash)+"&t="+team.Id, false); downErr != nil {
t.Fatal(downErr)
@ -278,17 +268,17 @@ func TestGetFile(t *testing.T) {
filename := filenames[len(filenames)-2] + "/" + filenames[len(filenames)-1]
fileId := strings.Split(filename, ".")[0]
err = bucket.Del("teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename)
err = bucket.Del("teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + filename)
if err != nil {
t.Fatal(err)
}
err = bucket.Del("teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg")
err = bucket.Del("teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + fileId + "_thumb.jpg")
if err != nil {
t.Fatal(err)
}
err = bucket.Del("teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg")
err = bucket.Del("teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + fileId + "_preview.jpg")
if err != nil {
t.Fatal(err)
}
@ -297,17 +287,17 @@ func TestGetFile(t *testing.T) {
filename := filenames[len(filenames)-2] + "/" + filenames[len(filenames)-1]
fileId := strings.Split(filename, ".")[0]
path := utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename
path := utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + filename
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg"
path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + fileId + "_thumb.jpg"
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg"
path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + fileId + "_preview.jpg"
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
@ -320,25 +310,18 @@ func TestGetFile(t *testing.T) {
}
func TestGetPublicLink(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
user := th.BasicUser
channel := th.BasicChannel
if utils.Cfg.FileSettings.DriverName != "" {
enablePublicLink := utils.Cfg.FileSettings.EnablePublicLink
defer func() {
utils.Cfg.FileSettings.EnablePublicLink = enablePublicLink
}()
utils.Cfg.FileSettings.EnablePublicLink = true
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
@ -364,7 +347,7 @@ func TestGetPublicLink(t *testing.T) {
t.Fatal(err)
}
_, err = field.Write([]byte(channel1.Id))
_, err = field.Write([]byte(channel.Id))
if err != nil {
t.Fatal(err)
}
@ -374,14 +357,14 @@ func TestGetPublicLink(t *testing.T) {
t.Fatal(err)
}
resp, upErr := Client.UploadFile("/files/upload", body.Bytes(), writer.FormDataContentType())
resp, upErr := Client.UploadPostAttachment(body.Bytes(), writer.FormDataContentType())
if upErr != nil {
t.Fatal(upErr)
}
filenames := resp.Data.(*model.FileUploadResponse).Filenames
post1 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a", Filenames: filenames}
post1 := &model.Post{ChannelId: channel.Id, Message: "a" + model.NewId() + "a", Filenames: filenames}
rpost1, postErr := Client.CreatePost(post1)
if postErr != nil {
@ -408,7 +391,8 @@ func TestGetPublicLink(t *testing.T) {
t.Fatal("Should have errored - bad file path")
}
Client.LoginByEmail(team.Name, user2.Email, "pwd")
th.LoginBasic2()
data["filename"] = filenames[0]
if _, err := Client.GetPublicLink(data); err == nil {
t.Fatal("should have errored, user not member of channel")
@ -427,17 +411,17 @@ func TestGetPublicLink(t *testing.T) {
filename := filenames[len(filenames)-2] + "/" + filenames[len(filenames)-1]
fileId := strings.Split(filename, ".")[0]
err = bucket.Del("teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename)
err = bucket.Del("teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + filename)
if err != nil {
t.Fatal(err)
}
err = bucket.Del("teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg")
err = bucket.Del("teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + fileId + "_thumb.jpg")
if err != nil {
t.Fatal(err)
}
err = bucket.Del("teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg")
err = bucket.Del("teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + fileId + "_preview.jpg")
if err != nil {
t.Fatal(err)
}
@ -446,17 +430,17 @@ func TestGetPublicLink(t *testing.T) {
filename := filenames[len(filenames)-2] + "/" + filenames[len(filenames)-1]
fileId := strings.Split(filename, ".")[0]
path := utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + filename
path := utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + filename
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_thumb.jpg"
path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + fileId + "_thumb.jpg"
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}
path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel1.Id + "/users/" + user1.Id + "/" + fileId + "_preview.jpg"
path = utils.Cfg.FileSettings.Directory + "teams/" + team.Id + "/channels/" + channel.Id + "/users/" + user.Id + "/" + fileId + "_preview.jpg"
if err := os.Remove(path); err != nil {
t.Fatal("Couldn't remove file at " + path)
}

View file

@ -22,7 +22,7 @@ func ImportPost(post *model.Post) {
}
}
func ImportUser(user *model.User) *model.User {
func ImportUser(teamId string, user *model.User) *model.User {
user.MakeNonNil()
if result := <-Srv.Store.User().Save(user); result.Err != nil {
@ -31,8 +31,8 @@ func ImportUser(user *model.User) *model.User {
} else {
ruser := result.Data.(*model.User)
if err := JoinDefaultChannels(ruser, ""); err != nil {
l4g.Error(utils.T("api.import.import_user.joining_default.error"), ruser.Id, ruser.TeamId, err)
if err := JoinDefaultChannels(teamId, ruser, ""); err != nil {
l4g.Error(utils.T("api.import.import_user.joining_default.error"), ruser.Id, teamId, err)
}
if cresult := <-Srv.Store.User().VerifyEmail(ruser.Id); cresult.Err != nil {

View file

@ -6,7 +6,6 @@ package api
import (
"bytes"
l4g "github.com/alecthomas/log4go"
"github.com/gorilla/mux"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
"io"
@ -19,13 +18,12 @@ const (
INVALID_LICENSE_ERROR = "api.license.add_license.invalid.app_error"
)
func InitLicense(r *mux.Router) {
func InitLicense() {
l4g.Debug(utils.T("api.license.init.debug"))
sr := r.PathPrefix("/license").Subrouter()
sr.Handle("/add", ApiAdminSystemRequired(addLicense)).Methods("POST")
sr.Handle("/remove", ApiAdminSystemRequired(removeLicense)).Methods("POST")
sr.Handle("/client_config", ApiAppHandler(getClientLicenceConfig)).Methods("GET")
BaseRoutes.License.Handle("/add", ApiAdminSystemRequired(addLicense)).Methods("POST")
BaseRoutes.License.Handle("/remove", ApiAdminSystemRequired(removeLicense)).Methods("POST")
BaseRoutes.License.Handle("/client_config", ApiAppHandler(getClientLicenceConfig)).Methods("GET")
}
func LoadLicense() {

View file

@ -9,7 +9,8 @@ import (
)
func TestGetLicenceConfig(t *testing.T) {
Setup()
th := Setup().InitBasic()
Client := th.BasicClient
if result, err := Client.GetClientLicenceConfig(""); err != nil {
t.Fatal(err)

View file

@ -4,7 +4,10 @@
package api
import (
"crypto/tls"
b64 "encoding/base64"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
@ -12,31 +15,29 @@ import (
l4g "github.com/alecthomas/log4go"
"github.com/gorilla/mux"
"github.com/mattermost/platform/einterfaces"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
)
func InitOAuth(r *mux.Router) {
func InitOAuth() {
l4g.Debug(utils.T("api.oauth.init.debug"))
sr := r.PathPrefix("/oauth").Subrouter()
BaseRoutes.OAuth.Handle("/register", ApiUserRequired(registerOAuthApp)).Methods("POST")
BaseRoutes.OAuth.Handle("/allow", ApiUserRequired(allowOAuth)).Methods("GET")
BaseRoutes.OAuth.Handle("/{service:[A-Za-z]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET")
BaseRoutes.OAuth.Handle("/{service:[A-Za-z]+}/login", AppHandlerIndependent(loginWithOAuth)).Methods("GET")
BaseRoutes.OAuth.Handle("/{service:[A-Za-z]+}/signup", AppHandlerIndependent(signupWithOAuth)).Methods("GET")
BaseRoutes.OAuth.Handle("/authorize", ApiUserRequired(authorizeOAuth)).Methods("GET")
BaseRoutes.OAuth.Handle("/access_token", ApiAppHandler(getAccessToken)).Methods("POST")
sr.Handle("/register", ApiUserRequired(registerOAuthApp)).Methods("POST")
sr.Handle("/allow", ApiUserRequired(allowOAuth)).Methods("GET")
sr.Handle("/{service:[A-Za-z]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET")
sr.Handle("/{service:[A-Za-z]+}/login", AppHandlerIndependent(loginWithOAuth)).Methods("GET")
sr.Handle("/{service:[A-Za-z]+}/signup", AppHandlerIndependent(signupWithOAuth)).Methods("GET")
sr.Handle("/authorize", ApiUserRequired(authorizeOAuth)).Methods("GET")
sr.Handle("/access_token", ApiAppHandler(getAccessToken)).Methods("POST")
mr := Srv.Router
mr.Handle("/authorize", ApiUserRequired(authorizeOAuth)).Methods("GET")
mr.Handle("/access_token", ApiAppHandler(getAccessToken)).Methods("POST")
BaseRoutes.Root.Handle("/authorize", ApiUserRequired(authorizeOAuth)).Methods("GET")
BaseRoutes.Root.Handle("/access_token", ApiAppHandler(getAccessToken)).Methods("POST")
// Handle all the old routes, to be later removed
mr.Handle("/{service:[A-Za-z]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET")
mr.Handle("/signup/{service:[A-Za-z]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET")
mr.Handle("/login/{service:[A-Za-z]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET")
BaseRoutes.Root.Handle("/{service:[A-Za-z]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET")
BaseRoutes.Root.Handle("/signup/{service:[A-Za-z]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET")
BaseRoutes.Root.Handle("/login/{service:[A-Za-z]+}/complete", AppHandlerIndependent(completeOAuth)).Methods("GET")
}
func registerOAuthApp(c *Context, w http.ResponseWriter, r *http.Request) {
@ -190,40 +191,40 @@ func completeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
uri := c.GetSiteURL() + "/signup/" + service + "/complete"
if body, team, props, err := AuthorizeOAuthUser(service, code, state, uri); err != nil {
if body, teamId, props, err := AuthorizeOAuthUser(service, code, state, uri); err != nil {
c.Err = err
return
} else {
action := props["action"]
switch action {
case model.OAUTH_ACTION_SIGNUP:
CreateOAuthUser(c, w, r, service, body, team)
CreateOAuthUser(c, w, r, service, body, teamId)
if c.Err == nil {
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host+"/"+team.Name, http.StatusTemporaryRedirect)
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host, http.StatusTemporaryRedirect)
}
break
case model.OAUTH_ACTION_LOGIN:
LoginByOAuth(c, w, r, service, body, team)
LoginByOAuth(c, w, r, service, body)
if c.Err == nil {
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host+"/"+team.Name, http.StatusTemporaryRedirect)
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host, http.StatusTemporaryRedirect)
}
break
case model.OAUTH_ACTION_EMAIL_TO_SSO:
CompleteSwitchWithOAuth(c, w, r, service, body, team, props["email"])
CompleteSwitchWithOAuth(c, w, r, service, body, props["email"])
if c.Err == nil {
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host+"/"+team.Name+"/login?extra=signin_change", http.StatusTemporaryRedirect)
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host+"/login?extra=signin_change", http.StatusTemporaryRedirect)
}
break
case model.OAUTH_ACTION_SSO_TO_EMAIL:
LoginByOAuth(c, w, r, service, body, team)
LoginByOAuth(c, w, r, service, body)
if c.Err == nil {
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host+"/"+team.Name+"/"+"/claim?email="+url.QueryEscape(props["email"]), http.StatusTemporaryRedirect)
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host+"/claim?email="+url.QueryEscape(props["email"]), http.StatusTemporaryRedirect)
}
break
default:
LoginByOAuth(c, w, r, service, body, team)
LoginByOAuth(c, w, r, service, body)
if c.Err == nil {
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host+"/"+team.Name, http.StatusTemporaryRedirect)
http.Redirect(w, r, GetProtocol(r)+"://"+r.Host, http.StatusTemporaryRedirect)
}
break
}
@ -257,7 +258,7 @@ func authorizeOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
}
var team *model.Team
if result := <-Srv.Store.Team().Get(c.Session.TeamId); result.Err != nil {
if result := <-Srv.Store.Team().Get(c.TeamId); result.Err != nil {
c.Err = result.Err
return
} else {
@ -389,7 +390,7 @@ func getAccessToken(c *Context, w http.ResponseWriter, r *http.Request) {
user = result.Data.(*model.User)
}
session := &model.Session{UserId: user.Id, TeamId: user.TeamId, Roles: user.Roles, IsOAuth: true}
session := &model.Session{UserId: user.Id, Roles: user.Roles, IsOAuth: true}
if result := <-Srv.Store.Session().Save(session); result.Err != nil {
c.Err = model.NewLocAppError("getAccessToken", "web.get_access_token.internal_session.app_error", nil, "")
@ -422,24 +423,11 @@ func loginWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
service := params["service"]
loginHint := r.URL.Query().Get("login_hint")
teamName := r.URL.Query().Get("team")
if len(teamName) == 0 {
c.Err = model.NewLocAppError("loginWithOAuth", "web.login_with_oauth.invalid_team.app_error", nil, "team_name="+teamName)
c.Err.StatusCode = http.StatusBadRequest
return
}
// Make sure team exists
if result := <-Srv.Store.Team().GetByName(teamName); result.Err != nil {
c.Err = result.Err
return
}
stateProps := map[string]string{}
stateProps["action"] = model.OAUTH_ACTION_LOGIN
if authUrl, err := GetAuthorizationCode(c, service, teamName, stateProps, loginHint); err != nil {
if authUrl, err := GetAuthorizationCode(c, service, stateProps, loginHint); err != nil {
c.Err = err
return
} else {
@ -450,31 +438,19 @@ func loginWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
func signupWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
service := params["service"]
teamName := r.URL.Query().Get("team")
if !utils.Cfg.TeamSettings.EnableUserCreation {
c.Err = model.NewLocAppError("signupTeam", "web.singup_with_oauth.disabled.app_error", nil, "")
c.Err = model.NewLocAppError("signupWithOAuth", "web.singup_with_oauth.disabled.app_error", nil, "")
c.Err.StatusCode = http.StatusNotImplemented
return
}
if len(teamName) == 0 {
c.Err = model.NewLocAppError("signupWithOAuth", "web.singup_with_oauth.invalid_team.app_error", nil, "team_name="+teamName)
c.Err.StatusCode = http.StatusBadRequest
return
}
hash := r.URL.Query().Get("h")
var team *model.Team
if result := <-Srv.Store.Team().GetByName(teamName); result.Err != nil {
c.Err = result.Err
return
} else {
team = result.Data.(*model.Team)
}
teamId := ""
inviteId := r.URL.Query().Get("id")
if IsVerifyHashRequired(nil, team, hash) {
if len(hash) > 0 {
data := r.URL.Query().Get("d")
props := model.MapFromJson(strings.NewReader(data))
@ -489,19 +465,173 @@ func signupWithOAuth(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
if team.Id != props["id"] {
c.Err = model.NewLocAppError("signupWithOAuth", "web.singup_with_oauth.invalid_team.app_error", nil, data)
return
teamId = props["id"]
} else if len(inviteId) != 0 {
if result := <-Srv.Store.Team().GetByInviteId(inviteId); result.Err != nil {
// soft fail, so we still create user but don't auto-join team
l4g.Error("%v", result.Err)
} else {
teamId = result.Data.(*model.Team).Id
}
}
stateProps := map[string]string{}
stateProps["action"] = model.OAUTH_ACTION_SIGNUP
if len(teamId) != 0 {
stateProps["team_id"] = teamId
}
if authUrl, err := GetAuthorizationCode(c, service, teamName, stateProps, ""); err != nil {
if authUrl, err := GetAuthorizationCode(c, service, stateProps, ""); err != nil {
c.Err = err
return
} else {
http.Redirect(w, r, authUrl, http.StatusFound)
}
}
func GetAuthorizationCode(c *Context, service string, props map[string]string, loginHint string) (string, *model.AppError) {
sso := utils.Cfg.GetSSOService(service)
if sso != nil && !sso.Enable {
return "", model.NewLocAppError("GetAuthorizationCode", "api.user.get_authorization_code.unsupported.app_error", nil, "service="+service)
}
clientId := sso.Id
endpoint := sso.AuthEndpoint
scope := sso.Scope
props["hash"] = model.HashPassword(clientId)
state := b64.StdEncoding.EncodeToString([]byte(model.MapToJson(props)))
redirectUri := c.GetSiteURL() + "/signup/" + service + "/complete"
authUrl := endpoint + "?response_type=code&client_id=" + clientId + "&redirect_uri=" + url.QueryEscape(redirectUri) + "&state=" + url.QueryEscape(state)
if len(scope) > 0 {
authUrl += "&scope=" + utils.UrlEncode(scope)
}
if len(loginHint) > 0 {
authUrl += "&login_hint=" + utils.UrlEncode(loginHint)
}
return authUrl, nil
}
func AuthorizeOAuthUser(service, code, state, redirectUri string) (io.ReadCloser, string, map[string]string, *model.AppError) {
sso := utils.Cfg.GetSSOService(service)
if sso == nil || !sso.Enable {
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.unsupported.app_error", nil, "service="+service)
}
stateStr := ""
if b, err := b64.StdEncoding.DecodeString(state); err != nil {
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, err.Error())
} else {
stateStr = string(b)
}
stateProps := model.MapFromJson(strings.NewReader(stateStr))
if !model.ComparePassword(stateProps["hash"], sso.Id) {
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.invalid_state.app_error", nil, "")
}
teamId := stateProps["team_id"]
p := url.Values{}
p.Set("client_id", sso.Id)
p.Set("client_secret", sso.Secret)
p.Set("code", code)
p.Set("grant_type", model.ACCESS_TOKEN_GRANT_TYPE)
p.Set("redirect_uri", redirectUri)
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: *utils.Cfg.ServiceSettings.EnableInsecureOutgoingConnections},
}
client := &http.Client{Transport: tr}
req, _ := http.NewRequest("POST", sso.TokenEndpoint, strings.NewReader(p.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Accept", "application/json")
var ar *model.AccessResponse
if resp, err := client.Do(req); err != nil {
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.token_failed.app_error", nil, err.Error())
} else {
ar = model.AccessResponseFromJson(resp.Body)
if ar == nil {
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.bad_response.app_error", nil, "")
}
}
if strings.ToLower(ar.TokenType) != model.ACCESS_TOKEN_TYPE {
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.bad_token.app_error", nil, "token_type="+ar.TokenType)
}
if len(ar.AccessToken) == 0 {
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.missing.app_error", nil, "")
}
p = url.Values{}
p.Set("access_token", ar.AccessToken)
req, _ = http.NewRequest("GET", sso.UserApiEndpoint, strings.NewReader(""))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Accept", "application/json")
req.Header.Set("Authorization", "Bearer "+ar.AccessToken)
if resp, err := client.Do(req); err != nil {
return nil, "", nil, model.NewLocAppError("AuthorizeOAuthUser", "api.user.authorize_oauth_user.service.app_error",
map[string]interface{}{"Service": service}, err.Error())
} else {
return resp.Body, teamId, stateProps, nil
}
}
func CompleteSwitchWithOAuth(c *Context, w http.ResponseWriter, r *http.Request, service string, userData io.ReadCloser, email string) {
authData := ""
ssoEmail := ""
provider := einterfaces.GetOauthProvider(service)
if provider == nil {
c.Err = model.NewLocAppError("CompleteClaimWithOAuth", "api.user.complete_switch_with_oauth.unavailable.app_error",
map[string]interface{}{"Service": service}, "")
return
} else {
ssoUser := provider.GetUserFromJson(userData)
authData = ssoUser.AuthData
ssoEmail = ssoUser.Email
}
if len(authData) == 0 {
c.Err = model.NewLocAppError("CompleteClaimWithOAuth", "api.user.complete_switch_with_oauth.parse.app_error",
map[string]interface{}{"Service": service}, "")
return
}
if len(email) == 0 {
c.Err = model.NewLocAppError("CompleteClaimWithOAuth", "api.user.complete_switch_with_oauth.blank_email.app_error", nil, "")
return
}
var user *model.User
if result := <-Srv.Store.User().GetByEmail(email); result.Err != nil {
c.Err = result.Err
return
} else {
user = result.Data.(*model.User)
}
RevokeAllSession(c, user.Id)
if c.Err != nil {
return
}
if result := <-Srv.Store.User().UpdateAuthData(user.Id, service, authData, ssoEmail); result.Err != nil {
c.Err = result.Err
return
}
sendSignInChangeEmailAndForget(c, user.Email, c.GetSiteURL(), strings.Title(service)+" SSO")
}

View file

@ -5,22 +5,14 @@ package api
import (
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
"net/url"
"strings"
"testing"
)
func TestRegisterApp(t *testing.T) {
Setup()
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
rteam, _ := Client.CreateTeam(&team)
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Password: "pwd"}
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
th := Setup().InitBasic()
Client := th.BasicClient
app := &model.OAuthApp{Name: "TestApp" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
@ -38,7 +30,7 @@ func TestRegisterApp(t *testing.T) {
t.Fatal("not logged in - should have failed")
}
Client.Must(Client.LoginById(ruser.Id, "pwd"))
th.LoginBasic()
if result, err := Client.RegisterApp(app); err != nil {
t.Fatal(err)
@ -70,19 +62,11 @@ func TestRegisterApp(t *testing.T) {
}
func TestAllowOAuth(t *testing.T) {
Setup()
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
rteam, _ := Client.CreateTeam(&team)
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Password: "pwd"}
ruser := Client.Must(Client.CreateUser(&user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(ruser.Id))
th := Setup().InitBasic()
Client := th.BasicClient
app := &model.OAuthApp{Name: "TestApp" + model.NewId(), Homepage: "https://nowhere.com", Description: "test", CallbackUrls: []string{"https://nowhere.com"}}
Client.Must(Client.LoginById(ruser.Id, "pwd"))
state := "123"
if !utils.Cfg.ServiceSettings.EnableOAuthServiceProvider {

View file

@ -22,21 +22,21 @@ import (
"time"
)
func InitPost(r *mux.Router) {
func InitPost() {
l4g.Debug(utils.T("api.post.init.debug"))
r.Handle("/posts/search", ApiUserRequired(searchPosts)).Methods("GET")
r.Handle("/posts/{post_id}", ApiUserRequired(getPostById)).Methods("GET")
BaseRoutes.NeedTeam.Handle("/posts/search", ApiUserRequired(searchPosts)).Methods("GET")
BaseRoutes.NeedTeam.Handle("/posts/{post_id}", ApiUserRequired(getPostById)).Methods("GET")
sr := r.PathPrefix("/channels/{id:[A-Za-z0-9]+}").Subrouter()
sr.Handle("/create", ApiUserRequired(createPost)).Methods("POST")
sr.Handle("/update", ApiUserRequired(updatePost)).Methods("POST")
sr.Handle("/posts/{offset:[0-9]+}/{limit:[0-9]+}", ApiUserRequiredActivity(getPosts, false)).Methods("GET")
sr.Handle("/posts/{time:[0-9]+}", ApiUserRequiredActivity(getPostsSince, false)).Methods("GET")
sr.Handle("/post/{post_id:[A-Za-z0-9]+}", ApiUserRequired(getPost)).Methods("GET")
sr.Handle("/post/{post_id:[A-Za-z0-9]+}/delete", ApiUserRequired(deletePost)).Methods("POST")
sr.Handle("/post/{post_id:[A-Za-z0-9]+}/before/{offset:[0-9]+}/{num_posts:[0-9]+}", ApiUserRequired(getPostsBefore)).Methods("GET")
sr.Handle("/post/{post_id:[A-Za-z0-9]+}/after/{offset:[0-9]+}/{num_posts:[0-9]+}", ApiUserRequired(getPostsAfter)).Methods("GET")
BaseRoutes.Posts.Handle("/create", ApiUserRequired(createPost)).Methods("POST")
BaseRoutes.Posts.Handle("/update", ApiUserRequired(updatePost)).Methods("POST")
BaseRoutes.Posts.Handle("/page/{offset:[0-9]+}/{limit:[0-9]+}", ApiUserRequiredActivity(getPosts, false)).Methods("GET")
BaseRoutes.Posts.Handle("/since/{time:[0-9]+}", ApiUserRequiredActivity(getPostsSince, false)).Methods("GET")
BaseRoutes.NeedPost.Handle("/get", ApiUserRequired(getPost)).Methods("GET")
BaseRoutes.NeedPost.Handle("/delete", ApiUserRequired(deletePost)).Methods("POST")
BaseRoutes.NeedPost.Handle("/before/{offset:[0-9]+}/{num_posts:[0-9]+}", ApiUserRequired(getPostsBefore)).Methods("GET")
BaseRoutes.NeedPost.Handle("/after/{offset:[0-9]+}/{num_posts:[0-9]+}", ApiUserRequired(getPostsAfter)).Methods("GET")
}
func createPost(c *Context, w http.ResponseWriter, r *http.Request) {
@ -47,7 +47,7 @@ func createPost(c *Context, w http.ResponseWriter, r *http.Request) {
}
// Create and save post object to channel
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, post.ChannelId, c.Session.UserId)
cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, post.ChannelId, c.Session.UserId)
if !c.HasPermissionsToChannel(cchan, "createPost") {
return
@ -228,15 +228,16 @@ func CreateWebhookPost(c *Context, channelId, text, overrideUsername, overrideIc
func handlePostEventsAndForget(c *Context, post *model.Post, triggerWebhooks bool) {
go func() {
tchan := Srv.Store.Team().Get(c.Session.TeamId)
tchan := Srv.Store.Team().Get(c.TeamId)
cchan := Srv.Store.Channel().Get(post.ChannelId)
uchan := Srv.Store.User().Get(post.UserId)
pchan := Srv.Store.User().GetProfiles(c.Session.TeamId)
pchan := Srv.Store.User().GetProfiles(c.TeamId)
dpchan := Srv.Store.User().GetDirectProfiles(c.Session.UserId)
mchan := Srv.Store.Channel().GetMembers(post.ChannelId)
var team *model.Team
if result := <-tchan; result.Err != nil {
l4g.Error(utils.T("api.post.handle_post_events_and_forget.team.error"), c.Session.TeamId, result.Err)
l4g.Error(utils.T("api.post.handle_post_events_and_forget.team.error"), c.TeamId, result.Err)
return
} else {
team = result.Data.(*model.Team)
@ -252,12 +253,22 @@ func handlePostEventsAndForget(c *Context, post *model.Post, triggerWebhooks boo
var profiles map[string]*model.User
if result := <-pchan; result.Err != nil {
l4g.Error(utils.T("api.post.handle_post_events_and_forget.profiles.error"), c.Session.TeamId, result.Err)
l4g.Error(utils.T("api.post.handle_post_events_and_forget.profiles.error"), c.TeamId, result.Err)
return
} else {
profiles = result.Data.(map[string]*model.User)
}
if result := <-dpchan; result.Err != nil {
l4g.Error(utils.T("api.post.handle_post_events_and_forget.profiles.error"), c.TeamId, result.Err)
return
} else {
dps := result.Data.(map[string]*model.User)
for k, v := range dps {
profiles[k] = v
}
}
var members []model.ChannelMember
if result := <-mchan; result.Err != nil {
l4g.Error(utils.T("api.post.handle_post_events_and_forget.members.error"), post.ChannelId, result.Err)
@ -282,7 +293,7 @@ func handlePostEventsAndForget(c *Context, post *model.Post, triggerWebhooks boo
}
if channel.Type == model.CHANNEL_DIRECT {
go makeDirectChannelVisible(c.Session.TeamId, post.ChannelId)
go makeDirectChannelVisible(c.TeamId, post.ChannelId)
}
}()
}
@ -352,7 +363,7 @@ func handleWebhookEventsAndForget(c *Context, post *model.Post, team *model.Team
return
}
hchan := Srv.Store.Webhook().GetOutgoingByTeam(c.Session.TeamId)
hchan := Srv.Store.Webhook().GetOutgoingByTeam(c.TeamId)
hooks := []*model.OutgoingWebhook{}
@ -416,8 +427,25 @@ func handleWebhookEventsAndForget(c *Context, post *model.Post, team *model.Team
respProps := model.MapFromJson(resp.Body)
// copy the context and create a mock session for posting the message
mockSession := model.Session{UserId: hook.CreatorId, TeamId: hook.TeamId, IsOAuth: false}
newContext := &Context{mockSession, model.NewId(), "", c.Path, nil, c.teamURLValid, c.teamURL, c.siteURL, c.T, c.Locale}
mockSession := model.Session{
UserId: hook.CreatorId,
TeamMembers: []*model.TeamMember{{TeamId: hook.TeamId, UserId: hook.CreatorId}},
IsOAuth: false,
}
newContext := &Context{
Session: mockSession,
RequestId: model.NewId(),
IpAddress: "",
Path: c.Path,
Err: nil,
teamURLValid: c.teamURLValid,
teamURL: c.teamURL,
siteURL: c.siteURL,
T: c.T,
Locale: c.Locale,
TeamId: hook.TeamId,
}
if text, ok := respProps["text"]; ok {
if _, err := CreateWebhookPost(newContext, post.ChannelId, text, respProps["username"], respProps["icon_url"], post.Props, post.Type); err != nil {
@ -706,7 +734,7 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel *
TLSClientConfig: &tls.Config{InsecureSkipVerify: *utils.Cfg.ServiceSettings.EnableInsecureOutgoingConnections},
}
httpClient := &http.Client{Transport: tr}
request, _ := http.NewRequest("POST", *utils.Cfg.EmailSettings.PushNotificationServer+"/api/v1/send_push", strings.NewReader(msg.ToJson()))
request, _ := http.NewRequest("POST", *utils.Cfg.EmailSettings.PushNotificationServer+model.API_URL_SUFFIX_V1+"/send_push", strings.NewReader(msg.ToJson()))
l4g.Debug(utils.T("api.post.send_notifications_and_forget.push_notification.debug"), msg.DeviceId, msg.Message)
if _, err := httpClient.Do(request); err != nil {
@ -719,7 +747,7 @@ func sendNotifications(c *Context, post *model.Post, team *model.Team, channel *
}
}
message := model.NewMessage(c.Session.TeamId, post.ChannelId, post.UserId, model.ACTION_POSTED)
message := model.NewMessage(c.TeamId, post.ChannelId, post.UserId, model.ACTION_POSTED)
message.Add("post", post.ToJson())
message.Add("channel_type", channel.Type)
@ -780,7 +808,7 @@ func checkForOutOfChannelMentions(c *Context, post *model.Post, channel *model.C
}
SendEphemeralPost(
c.Session.TeamId,
c.TeamId,
post.UserId,
&model.Post{
ChannelId: post.ChannelId,
@ -847,7 +875,7 @@ func updatePost(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, post.ChannelId, c.Session.UserId)
cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, post.ChannelId, c.Session.UserId)
pchan := Srv.Store.Post().Get(post.Id)
if !c.HasPermissionsToChannel(cchan, "updatePost") {
@ -889,7 +917,7 @@ func updatePost(c *Context, w http.ResponseWriter, r *http.Request) {
} else {
rpost := result.Data.(*model.Post)
message := model.NewMessage(c.Session.TeamId, rpost.ChannelId, c.Session.UserId, model.ACTION_POST_EDITED)
message := model.NewMessage(c.TeamId, rpost.ChannelId, c.Session.UserId, model.ACTION_POST_EDITED)
message.Add("post", rpost.ToJson())
PublishAndForget(message)
@ -901,7 +929,7 @@ func updatePost(c *Context, w http.ResponseWriter, r *http.Request) {
func getPosts(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id := params["id"]
id := params["channel_id"]
if len(id) != 26 {
c.SetInvalidParam("getPosts", "channelId")
return
@ -919,7 +947,7 @@ func getPosts(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, id, c.Session.UserId)
cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, id, c.Session.UserId)
etagChan := Srv.Store.Post().GetEtag(id)
if !c.HasPermissionsToChannel(cchan, "getPosts") {
@ -949,7 +977,7 @@ func getPosts(c *Context, w http.ResponseWriter, r *http.Request) {
func getPostsSince(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id := params["id"]
id := params["channel_id"]
if len(id) != 26 {
c.SetInvalidParam("getPostsSince", "channelId")
return
@ -961,7 +989,7 @@ func getPostsSince(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, id, c.Session.UserId)
cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, id, c.Session.UserId)
pchan := Srv.Store.Post().GetPostsSince(id, time)
if !c.HasPermissionsToChannel(cchan, "getPostsSince") {
@ -982,7 +1010,7 @@ func getPostsSince(c *Context, w http.ResponseWriter, r *http.Request) {
func getPost(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
channelId := params["id"]
channelId := params["channel_id"]
if len(channelId) != 26 {
c.SetInvalidParam("getPost", "channelId")
return
@ -994,7 +1022,7 @@ func getPost(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, channelId, c.Session.UserId)
cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, channelId, c.Session.UserId)
pchan := Srv.Store.Post().Get(postId)
if !c.HasPermissionsToChannel(cchan, "getPost") {
@ -1041,7 +1069,7 @@ func getPostById(c *Context, w http.ResponseWriter, r *http.Request) {
}
post := list.Posts[list.Order[0]]
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, post.ChannelId, c.Session.UserId)
cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, post.ChannelId, c.Session.UserId)
if !c.HasPermissionsToChannel(cchan, "getPostById") {
return
}
@ -1058,7 +1086,7 @@ func getPostById(c *Context, w http.ResponseWriter, r *http.Request) {
func deletePost(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
channelId := params["id"]
channelId := params["channel_id"]
if len(channelId) != 26 {
c.SetInvalidParam("deletePost", "channelId")
return
@ -1070,7 +1098,7 @@ func deletePost(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, channelId, c.Session.UserId)
cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, channelId, c.Session.UserId)
pchan := Srv.Store.Post().Get(postId)
if result := <-pchan; result.Err != nil {
@ -1106,11 +1134,11 @@ func deletePost(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
message := model.NewMessage(c.Session.TeamId, post.ChannelId, c.Session.UserId, model.ACTION_POST_DELETED)
message := model.NewMessage(c.TeamId, post.ChannelId, c.Session.UserId, model.ACTION_POST_DELETED)
message.Add("post", post.ToJson())
PublishAndForget(message)
DeletePostFilesAndForget(c.Session.TeamId, post)
DeletePostFilesAndForget(c.TeamId, post)
result := make(map[string]string)
result["id"] = postId
@ -1146,7 +1174,7 @@ func getPostsAfter(c *Context, w http.ResponseWriter, r *http.Request) {
func getPostsBeforeOrAfter(c *Context, w http.ResponseWriter, r *http.Request, before bool) {
params := mux.Vars(r)
id := params["id"]
id := params["channel_id"]
if len(id) != 26 {
c.SetInvalidParam("getPostsBeforeOrAfter", "channelId")
return
@ -1170,7 +1198,7 @@ func getPostsBeforeOrAfter(c *Context, w http.ResponseWriter, r *http.Request, b
return
}
cchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, id, c.Session.UserId)
cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, id, c.Session.UserId)
// We can do better than this etag in this situation
etagChan := Srv.Store.Post().GetEtag(id)
@ -1215,7 +1243,7 @@ func searchPosts(c *Context, w http.ResponseWriter, r *http.Request) {
for _, params := range paramsList {
// don't allow users to search for everything
if params.Terms != "*" {
channels = append(channels, Srv.Store.Post().Search(c.Session.TeamId, c.Session.UserId, params))
channels = append(channels, Srv.Store.Post().Search(c.TeamId, c.Session.UserId, params))
}
}

View file

@ -16,7 +16,10 @@ func BenchmarkCreatePost(b *testing.B) {
var (
NUM_POSTS_RANGE = utils.Range{NUM_POSTS, NUM_POSTS}
)
_, _, channel := SetupBenchmark()
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
testPoster := NewAutoPostCreator(Client, channel.Id)
@ -32,7 +35,10 @@ func BenchmarkUpdatePost(b *testing.B) {
NUM_POSTS_RANGE = utils.Range{NUM_POSTS, NUM_POSTS}
UPDATE_POST_LEN = 100
)
_, _, channel := SetupBenchmark()
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
testPoster := NewAutoPostCreator(Client, channel.Id)
posts, valid := testPoster.CreateTestPosts(NUM_POSTS_RANGE)
@ -59,7 +65,10 @@ func BenchmarkGetPosts(b *testing.B) {
var (
NUM_POSTS_RANGE = utils.Range{NUM_POSTS, NUM_POSTS}
)
_, _, channel := SetupBenchmark()
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
testPoster := NewAutoPostCreator(Client, channel.Id)
testPoster.CreateTestPosts(NUM_POSTS_RANGE)
@ -75,7 +84,10 @@ func BenchmarkSearchPosts(b *testing.B) {
var (
NUM_POSTS_RANGE = utils.Range{NUM_POSTS, NUM_POSTS}
)
_, _, channel := SetupBenchmark()
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
testPoster := NewAutoPostCreator(Client, channel.Id)
testPoster.CreateTestPosts(NUM_POSTS_RANGE)
@ -93,7 +105,10 @@ func BenchmarkEtagCache(b *testing.B) {
var (
NUM_POSTS_RANGE = utils.Range{NUM_POSTS, NUM_POSTS}
)
_, _, channel := SetupBenchmark()
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
testPoster := NewAutoPostCreator(Client, channel.Id)
testPoster.CreateTestPosts(NUM_POSTS_RANGE)
@ -111,7 +126,10 @@ func BenchmarkDeletePosts(b *testing.B) {
var (
NUM_POSTS_RANGE = utils.Range{NUM_POSTS, NUM_POSTS}
)
_, _, channel := SetupBenchmark()
th := Setup().InitBasic()
Client := th.BasicClient
channel := th.BasicChannel
testPoster := NewAutoPostCreator(Client, channel.Id)
posts, valid := testPoster.CreateTestPosts(NUM_POSTS_RANGE)

View file

@ -5,38 +5,24 @@ package api
import (
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
"net/http"
"strings"
//"strings"
"fmt"
"testing"
"time"
)
func TestCreatePost(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
team2 := &model.Team{DisplayName: "Name Team 2", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
channel2 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
team2 := th.CreateTeam(th.BasicClient)
user1 := th.BasicUser
user3 := th.CreateUser(th.BasicClient)
LinkUserToTeam(user3, team2)
channel1 := th.BasicChannel
channel2 := th.CreateChannel(Client, team)
filenames := []string{"/12345678901234567890123456/12345678901234567890123456/12345678901234567890123456/test.png", "/" + channel1.Id + "/" + user1.Id + "/test.png", "www.mattermost.com/fake/url", "junk"}
@ -97,21 +83,17 @@ func TestCreatePost(t *testing.T) {
t.Fatal("Should have been forbidden")
}
Client.LoginByEmail(team.Name, user2.Email, "pwd")
th.LoginBasic2()
post7 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
_, err = Client.CreatePost(post7)
if err.StatusCode != http.StatusForbidden {
t.Fatal("Should have been forbidden")
}
user3 := &model.User{TeamId: team2.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
Client.LoginByEmail(team2.Name, user3.Email, "pwd")
channel3 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team2.Id}
channel3 = Client.Must(Client.CreateChannel(channel3)).Data.(*model.Channel)
Client.LoginByEmail(team2.Name, user3.Email, user3.Password)
Client.SetTeamId(team2.Id)
channel3 := th.CreateChannel(Client, team2)
post8 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
_, err = Client.CreatePost(post8)
@ -125,29 +107,9 @@ func TestCreatePost(t *testing.T) {
}
func TestUpdatePost(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
team2 := &model.Team{DisplayName: "Name Team 2", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
channel2 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
channel1 := th.BasicChannel
post1 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
rpost1, err := Client.CreatePost(post1)
@ -196,19 +158,9 @@ func TestUpdatePost(t *testing.T) {
}
func TestGetPosts(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
channel1 := th.BasicChannel
time.Sleep(10 * time.Millisecond)
post1 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
@ -261,19 +213,9 @@ func TestGetPosts(t *testing.T) {
}
func TestGetPostsSince(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
channel1 := th.BasicChannel
time.Sleep(10 * time.Millisecond)
post0 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
@ -331,19 +273,9 @@ func TestGetPostsSince(t *testing.T) {
}
func TestGetPostsBeforeAfter(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
channel1 := th.BasicChannel
time.Sleep(10 * time.Millisecond)
post0 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
@ -379,7 +311,8 @@ func TestGetPostsBeforeAfter(t *testing.T) {
t.Fatal("wrong order")
}
if len(r1.Posts) != 2 {
if len(r1.Posts) != 3 {
t.Log(r1.Posts)
t.Fatal("wrong size")
}
@ -408,19 +341,9 @@ func TestGetPostsBeforeAfter(t *testing.T) {
}
func TestSearchPosts(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
channel1 := th.BasicChannel
post1 := &model.Post{ChannelId: channel1.Id, Message: "search for post1"}
post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
@ -458,19 +381,9 @@ func TestSearchPosts(t *testing.T) {
}
func TestSearchHashtagPosts(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
channel1 := th.BasicChannel
post1 := &model.Post{ChannelId: channel1.Id, Message: "#sgtitlereview with space"}
post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
@ -489,19 +402,10 @@ func TestSearchHashtagPosts(t *testing.T) {
}
func TestSearchPostsInChannel(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
channel1 := th.BasicChannel
team := th.BasicTeam
post1 := &model.Post{ChannelId: channel1.Id, Message: "sgtitlereview with space"}
post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
@ -529,7 +433,7 @@ func TestSearchPostsInChannel(t *testing.T) {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
if result := Client.Must(Client.SearchPosts("channel:" + channel1.Name)).Data.(*model.PostList); len(result.Order) != 1 {
if result := Client.Must(Client.SearchPosts("channel:" + channel1.Name)).Data.(*model.PostList); len(result.Order) != 2 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
@ -567,38 +471,29 @@ func TestSearchPostsInChannel(t *testing.T) {
}
func TestSearchPostsFromUser(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
channel2 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
channel1 := th.BasicChannel
team := th.BasicTeam
user1 := th.BasicUser
user2 := th.BasicUser2
channel2 := th.CreateChannel(Client, team)
Client.Must(Client.AddChannelMember(channel1.Id, th.BasicUser2.Id))
Client.Must(Client.AddChannelMember(channel2.Id, th.BasicUser2.Id))
user3 := th.CreateUser(Client)
LinkUserToTeam(user3, team)
Client.Must(Client.AddChannelMember(channel1.Id, user3.Id))
Client.Must(Client.AddChannelMember(channel2.Id, user3.Id))
post1 := &model.Post{ChannelId: channel1.Id, Message: "sgtitlereview with space"}
post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
Client.LoginByEmail(team.Name, user2.Email, "pwd")
Client.Must(Client.JoinChannel(channel1.Id))
Client.Must(Client.JoinChannel(channel2.Id))
th.LoginBasic2()
post2 := &model.Post{ChannelId: channel2.Id, Message: "sgtitlereview\n with return"}
post2 = Client.Must(Client.CreatePost(post2)).Data.(*model.Post)
if result := Client.Must(Client.SearchPosts("from: " + user1.Username)).Data.(*model.PostList); len(result.Order) != 1 {
if result := Client.Must(Client.SearchPosts("from: " + user1.Username)).Data.(*model.PostList); len(result.Order) != 2 {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
@ -617,13 +512,7 @@ func TestSearchPostsFromUser(t *testing.T) {
t.Fatalf("wrong number of posts returned %v", len(result.Order))
}
user3 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
Client.LoginByEmail(team.Name, user3.Email, "pwd")
Client.Must(Client.JoinChannel(channel1.Id))
Client.Must(Client.JoinChannel(channel2.Id))
Client.LoginByEmail(team.Name, user3.Email, user3.Password)
// wait for the join/leave messages to be created for user3 since they're done asynchronously
time.Sleep(100 * time.Millisecond)
@ -649,19 +538,9 @@ func TestSearchPostsFromUser(t *testing.T) {
}
func TestGetPostsCache(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
channel1 := th.BasicChannel
time.Sleep(10 * time.Millisecond)
post1 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
@ -698,23 +577,10 @@ func TestGetPostsCache(t *testing.T) {
}
func TestDeletePosts(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
userAdmin := &model.User{TeamId: team.Id, Email: team.Email, Nickname: "Corey Hulen", Password: "pwd"}
userAdmin = Client.Must(Client.CreateUser(userAdmin, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(userAdmin.Id))
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
channel1 := th.BasicChannel
UpdateUserToTeamAdmin(th.BasicUser2, th.BasicTeam)
time.Sleep(10 * time.Millisecond)
post1 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
@ -745,7 +611,7 @@ func TestDeletePosts(t *testing.T) {
r2 := Client.Must(Client.GetPosts(channel1.Id, 0, 10, "")).Data.(*model.PostList)
if len(r2.Posts) != 4 {
if len(r2.Posts) != 5 {
t.Fatal("should have returned 4 items")
}
@ -753,27 +619,17 @@ func TestDeletePosts(t *testing.T) {
post4 := &model.Post{ChannelId: channel1.Id, Message: "a" + model.NewId() + "a"}
post4 = Client.Must(Client.CreatePost(post4)).Data.(*model.Post)
Client.LoginByEmail(team.Name, userAdmin.Email, "pwd")
th.LoginBasic2()
Client.Must(Client.DeletePost(channel1.Id, post4.Id))
}
func TestEmailMention(t *testing.T) {
Setup()
th := Setup().InitBasic()
Client := th.BasicClient
channel1 := th.BasicChannel
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: "success+test@simulator.amazonses.com", Nickname: "Bob Bobby", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
post1 := &model.Post{ChannelId: channel1.Id, Message: "bob"}
post1 := &model.Post{ChannelId: channel1.Id, Message: th.BasicUser.Username}
post1 = Client.Must(Client.CreatePost(post1)).Data.(*model.Post)
// No easy way to verify the email was sent, but this will at least cause the server to throw errors if the code is broken
@ -781,19 +637,9 @@ func TestEmailMention(t *testing.T) {
}
func TestFuzzyPosts(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
channel1 := th.BasicChannel
filenames := []string{"junk"}
@ -808,21 +654,13 @@ func TestFuzzyPosts(t *testing.T) {
}
func TestMakeDirectChannelVisible(t *testing.T) {
Setup()
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
user1 := th.BasicUser
user2 := th.BasicUser2
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
// user2 will be created with prefs created to show user1 in the sidebar so set that to false to get rid of it
Client.LoginByEmail(team.Name, user2.Email, "pwd")
th.LoginBasic2()
preferences := &model.Preferences{
{
@ -834,9 +672,11 @@ func TestMakeDirectChannelVisible(t *testing.T) {
}
Client.Must(Client.SetPreferences(preferences))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
Client.Must(Client.Logout())
th.LoginBasic()
th.BasicClient.SetTeamId(team.Id)
channel := Client.Must(Client.CreateDirectChannel(map[string]string{"user_id": user2.Id})).Data.(*model.Channel)
channel := Client.Must(Client.CreateDirectChannel(user2.Id)).Data.(*model.Channel)
makeDirectChannelVisible(team.Id, channel.Id)
@ -845,38 +685,17 @@ func TestMakeDirectChannelVisible(t *testing.T) {
} else if pref := result.Data.(*model.Preference); pref.Value != "true" {
t.Fatal("Failed to set direct channel to be visible for user1")
}
Client.LoginByEmail(team.Name, user2.Email, "pwd")
if result, err := Client.GetPreference(model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW, user1.Id); err != nil {
t.Fatal("Errored trying to set direct channel to be visible for user2")
} else if pref := result.Data.(*model.Preference); pref.Value != "true" {
t.Fatal("Failed to set direct channel to be visible for user2")
}
}
func TestGetOutOfChannelMentions(t *testing.T) {
Setup()
team1 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Type: model.TEAM_OPEN}
team1 = Client.Must(Client.CreateTeam(team1)).Data.(*model.Team)
user1 := &model.User{TeamId: team1.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd", Username: "user1"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
user2 := &model.User{TeamId: team1.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd", Username: "user2"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
user3 := &model.User{TeamId: team1.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd", Username: "user3"}
user3 = Client.Must(Client.CreateUser(user3, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user3.Id))
Client.Must(Client.LoginByEmail(team1.Name, user1.Email, "pwd"))
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team1.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
th := Setup().InitBasic()
Client := th.BasicClient
channel1 := th.BasicChannel
team1 := th.BasicTeam
user1 := th.BasicUser
user2 := th.BasicUser2
user3 := th.CreateUser(Client)
LinkUserToTeam(user3, team1)
var allProfiles map[string]*model.User
if result := <-Srv.Store.User().GetProfiles(team1.Id); result.Err != nil {
@ -893,39 +712,37 @@ func TestGetOutOfChannelMentions(t *testing.T) {
}
// test a post that doesn't @mention anybody
post1 := &model.Post{ChannelId: channel1.Id, Message: "user1 user2 user3"}
post1 := &model.Post{ChannelId: channel1.Id, Message: fmt.Sprintf("%v %v %v", user1.Username, user2.Username, user3.Username)}
if mentioned := getOutOfChannelMentions(post1, allProfiles, members); len(mentioned) != 0 {
t.Fatalf("getOutOfChannelMentions returned %v when no users were mentioned", mentioned)
}
// test a post that @mentions someone in the channel
post2 := &model.Post{ChannelId: channel1.Id, Message: "@user1 is user1"}
post2 := &model.Post{ChannelId: channel1.Id, Message: fmt.Sprintf("@%v is %v", user1.Username, user1.Username)}
if mentioned := getOutOfChannelMentions(post2, allProfiles, members); len(mentioned) != 0 {
t.Fatalf("getOutOfChannelMentions returned %v when only users in the channel were mentioned", mentioned)
}
// test a post that @mentions someone not in the channel
post3 := &model.Post{ChannelId: channel1.Id, Message: "@user2 and @user3 aren't in the channel"}
post3 := &model.Post{ChannelId: channel1.Id, Message: fmt.Sprintf("@%v and @%v aren't in the channel", user2.Username, user3.Username)}
if mentioned := getOutOfChannelMentions(post3, allProfiles, members); len(mentioned) != 2 || (mentioned[0].Id != user2.Id && mentioned[0].Id != user3.Id) || (mentioned[1].Id != user2.Id && mentioned[1].Id != user3.Id) {
t.Fatalf("getOutOfChannelMentions returned %v when two users outside the channel were mentioned", mentioned)
}
// test a post that @mentions someone not in the channel as well as someone in the channel
post4 := &model.Post{ChannelId: channel1.Id, Message: "@user2 and @user1 might be in the channel"}
post4 := &model.Post{ChannelId: channel1.Id, Message: fmt.Sprintf("@%v and @%v might be in the channel", user2.Username, user1.Username)}
if mentioned := getOutOfChannelMentions(post4, allProfiles, members); len(mentioned) != 1 || mentioned[0].Id != user2.Id {
t.Fatalf("getOutOfChannelMentions returned %v when someone in the channel and someone outside the channel were mentioned", mentioned)
}
Client.Must(Client.Logout())
team2 := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Type: model.TEAM_OPEN}
team2 = Client.Must(Client.CreateTeam(team2)).Data.(*model.Team)
team2 := th.CreateTeam(Client)
user4 := th.CreateUser(Client)
LinkUserToTeam(user4, team2)
user4 := &model.User{TeamId: team2.Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd", Username: "user4"}
user4 = Client.Must(Client.CreateUser(user4, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user4.Id))
Client.Must(Client.LoginByEmail(team2.Name, user4.Email, "pwd"))
Client.Must(Client.LoginByEmail(team2.Name, user4.Email, user4.Password))
Client.SetTeamId(team2.Id)
channel2 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team2.Id}
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
@ -943,7 +760,7 @@ func TestGetOutOfChannelMentions(t *testing.T) {
}
// test a post that @mentions someone on a different team
post5 := &model.Post{ChannelId: channel2.Id, Message: "@user2 and @user3 might be in the channel"}
post5 := &model.Post{ChannelId: channel2.Id, Message: fmt.Sprintf("@%v and @%v might be in the channel", user2.Username, user3.Username)}
if mentioned := getOutOfChannelMentions(post5, allProfiles, members); len(mentioned) != 0 {
t.Fatalf("getOutOfChannelMentions returned %v when two users on a different team were mentioned", mentioned)
}

View file

@ -11,14 +11,13 @@ import (
"net/http"
)
func InitPreference(r *mux.Router) {
func InitPreference() {
l4g.Debug(utils.T("api.preference.init.debug"))
sr := r.PathPrefix("/preferences").Subrouter()
sr.Handle("/", ApiUserRequired(getAllPreferences)).Methods("GET")
sr.Handle("/save", ApiUserRequired(savePreferences)).Methods("POST")
sr.Handle("/{category:[A-Za-z0-9_]+}", ApiUserRequired(getPreferenceCategory)).Methods("GET")
sr.Handle("/{category:[A-Za-z0-9_]+}/{name:[A-Za-z0-9_]+}", ApiUserRequired(getPreference)).Methods("GET")
BaseRoutes.Preferences.Handle("/", ApiUserRequired(getAllPreferences)).Methods("GET")
BaseRoutes.Preferences.Handle("/save", ApiUserRequired(savePreferences)).Methods("POST")
BaseRoutes.Preferences.Handle("/{category:[A-Za-z0-9_]+}", ApiUserRequired(getPreferenceCategory)).Methods("GET")
BaseRoutes.Preferences.Handle("/{category:[A-Za-z0-9_]+}/{name:[A-Za-z0-9_]+}", ApiUserRequired(getPreference)).Methods("GET")
}
func getAllPreferences(c *Context, w http.ResponseWriter, r *http.Request) {
@ -44,7 +43,7 @@ func savePreferences(c *Context, w http.ResponseWriter, r *http.Request) {
c.Err = model.NewLocAppError("savePreferences", "api.preference.save_preferences.set.app_error", nil,
c.T("api.preference.save_preferences.set_details.app_error",
map[string]interface{}{"SessionUserId": c.Session.UserId, "PreferenceUserId": preference.UserId}))
c.Err.StatusCode = http.StatusUnauthorized
c.Err.StatusCode = http.StatusForbidden
return
}
}

View file

@ -5,23 +5,13 @@ package api
import (
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"testing"
)
func TestGetAllPreferences(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
th := Setup().InitBasic()
Client := th.BasicClient
user1 := th.BasicUser
category := model.NewId()
@ -43,7 +33,6 @@ func TestGetAllPreferences(t *testing.T) {
},
}
Client.LoginByEmail(team.Name, user1.Email, "pwd")
Client.Must(Client.SetPreferences(&preferences1))
if result, err := Client.GetAllPreferences(); err != nil {
@ -52,27 +41,19 @@ func TestGetAllPreferences(t *testing.T) {
t.Fatal("received the wrong number of preferences")
}
Client.LoginByEmail(team.Name, user2.Email, "pwd")
th.LoginBasic2()
// note that user2 will automatically have a preference set for them to show user1 for direct messages
if result, err := Client.GetAllPreferences(); err != nil {
t.Fatal(err)
} else if data := result.Data.(model.Preferences); len(data) != 2 {
} else if data := result.Data.(model.Preferences); len(data) == 0 {
t.Fatal("received the wrong number of preferences")
}
}
func TestSetPreferences(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
user1 := th.BasicUser
// save 10 preferences
var preferences model.Preferences
@ -98,12 +79,7 @@ func TestSetPreferences(t *testing.T) {
t.Fatal(err)
}
// not able to update as a different user
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
Client.LoginByEmail(team.Name, user2.Email, "pwd")
th.LoginBasic2()
if _, err := Client.SetPreferences(&preferences); err == nil {
t.Fatal("shouldn't have been able to update another user's preferences")
@ -111,18 +87,9 @@ func TestSetPreferences(t *testing.T) {
}
func TestGetPreferenceCategory(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
th := Setup().InitBasic()
Client := th.BasicClient
user1 := th.BasicUser
category := model.NewId()
@ -144,11 +111,8 @@ func TestGetPreferenceCategory(t *testing.T) {
},
}
Client.LoginByEmail(team.Name, user1.Email, "pwd")
Client.Must(Client.SetPreferences(&preferences1))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
if result, err := Client.GetPreferenceCategory(category); err != nil {
t.Fatal(err)
} else if data := result.Data.(model.Preferences); len(data) != 2 {
@ -157,7 +121,7 @@ func TestGetPreferenceCategory(t *testing.T) {
t.Fatal("received incorrect preferences")
}
Client.LoginByEmail(team.Name, user2.Email, "pwd")
th.LoginBasic2()
if result, err := Client.GetPreferenceCategory(category); err != nil {
t.Fatal(err)
@ -167,16 +131,9 @@ func TestGetPreferenceCategory(t *testing.T) {
}
func TestGetPreference(t *testing.T) {
Setup()
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
th := Setup().InitBasic()
Client := th.BasicClient
user := th.BasicUser
preferences := model.Preferences{
{

View file

@ -6,6 +6,7 @@ package api
import (
l4g "github.com/alecthomas/log4go"
"github.com/braintree/manners"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
@ -73,11 +74,10 @@ func StartServer() {
}
go func() {
err := manners.ListenAndServe(utils.Cfg.ServiceSettings.ListenAddress, handler)
err := manners.ListenAndServe(utils.Cfg.ServiceSettings.ListenAddress, handlers.RecoveryHandler(handlers.PrintRecoveryStack(true))(handler))
if err != nil {
l4g.Critical(utils.T("api.server.start_server.starting.critical"), err)
time.Sleep(time.Second)
panic(utils.T("api.server.start_server.starting.panic") + err.Error())
}
}()
}

View file

@ -1,79 +0,0 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package api
/*
func createSubDomain(subDomain string, target string) {
if utils.Cfg.AWSSettings.Route53AccessKeyId == "" {
return
}
creds := aws.Creds(utils.Cfg.AWSSettings.Route53AccessKeyId, utils.Cfg.AWSSettings.Route53SecretAccessKey, "")
r53 := route53.New(aws.DefaultConfig.Merge(&aws.Config{Credentials: creds, Region: utils.Cfg.AWSSettings.Route53Region}))
rr := route53.ResourceRecord{
Value: aws.String(target),
}
rrs := make([]*route53.ResourceRecord, 1)
rrs[0] = &rr
change := route53.Change{
Action: aws.String("CREATE"),
ResourceRecordSet: &route53.ResourceRecordSet{
Name: aws.String(fmt.Sprintf("%v.%v", subDomain, utils.Cfg.ServiceSettings.Domain)),
TTL: aws.Long(300),
Type: aws.String("CNAME"),
ResourceRecords: rrs,
},
}
changes := make([]*route53.Change, 1)
changes[0] = &change
r53req := &route53.ChangeResourceRecordSetsInput{
HostedZoneID: aws.String(utils.Cfg.AWSSettings.Route53ZoneId),
ChangeBatch: &route53.ChangeBatch{
Changes: changes,
},
}
if _, err := r53.ChangeResourceRecordSets(r53req); err != nil {
l4g.Error("erro in createSubDomain domain=%v err=%v", subDomain, err)
return
}
}
func doesSubDomainExist(subDomain string) bool {
// if it's configured for testing then skip this step
if utils.Cfg.AWSSettings.Route53AccessKeyId == "" {
return false
}
creds := aws.Creds(utils.Cfg.AWSSettings.Route53AccessKeyId, utils.Cfg.AWSSettings.Route53SecretAccessKey, "")
r53 := route53.New(aws.DefaultConfig.Merge(&aws.Config{Credentials: creds, Region: utils.Cfg.AWSSettings.Route53Region}))
r53req := &route53.ListResourceRecordSetsInput{
HostedZoneID: aws.String(utils.Cfg.AWSSettings.Route53ZoneId),
MaxItems: aws.String("1"),
StartRecordName: aws.String(fmt.Sprintf("%v.%v.", subDomain, utils.Cfg.ServiceSettings.Domain)),
}
if result, err := r53.ListResourceRecordSets(r53req); err != nil {
l4g.Error("error in doesSubDomainExist domain=%v err=%v", subDomain, err)
return true
} else {
for _, v := range result.ResourceRecordSets {
if v.Name != nil && *v.Name == fmt.Sprintf("%v.%v.", subDomain, utils.Cfg.ServiceSettings.Domain) {
return true
}
}
}
return false
}
*/

View file

@ -112,7 +112,6 @@ func SlackAddUsers(teamId string, slackusers []SlackUser, log *bytes.Buffer) map
password := model.NewId()
newUser := model.User{
TeamId: teamId,
Username: sUser.Username,
FirstName: firstName,
LastName: lastName,
@ -120,7 +119,7 @@ func SlackAddUsers(teamId string, slackusers []SlackUser, log *bytes.Buffer) map
Password: password,
}
if mUser := ImportUser(&newUser); mUser != nil {
if mUser := ImportUser(teamId, &newUser); mUser != nil {
addedUsers[sUser.Id] = mUser
log.WriteString(utils.T("api.slackimport.slack_add_users.email_pwd", map[string]interface{}{"Email": newUser.Email, "Password": password}))
} else {

View file

@ -6,38 +6,43 @@ package api
import (
"bytes"
"fmt"
l4g "github.com/alecthomas/log4go"
"github.com/gorilla/mux"
"github.com/mattermost/platform/einterfaces"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
"html/template"
"net/http"
"net/url"
"strconv"
"strings"
"time"
l4g "github.com/alecthomas/log4go"
"github.com/gorilla/mux"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
)
func InitTeam(r *mux.Router) {
func InitTeam() {
l4g.Debug(utils.T("api.team.init.debug"))
sr := r.PathPrefix("/teams").Subrouter()
sr.Handle("/create", ApiAppHandler(createTeam)).Methods("POST")
sr.Handle("/create_from_signup", ApiAppHandler(createTeamFromSignup)).Methods("POST")
sr.Handle("/create_with_ldap", ApiAppHandler(createTeamWithLdap)).Methods("POST")
sr.Handle("/create_with_sso/{service:[A-Za-z]+}", ApiAppHandler(createTeamFromSSO)).Methods("POST")
sr.Handle("/signup", ApiAppHandler(signupTeam)).Methods("POST")
sr.Handle("/all", ApiAppHandler(getAll)).Methods("GET")
sr.Handle("/find_team_by_name", ApiAppHandler(findTeamByName)).Methods("POST")
sr.Handle("/invite_members", ApiUserRequired(inviteMembers)).Methods("POST")
sr.Handle("/update", ApiUserRequired(updateTeam)).Methods("POST")
sr.Handle("/me", ApiUserRequired(getMyTeam)).Methods("GET")
sr.Handle("/get_invite_info", ApiAppHandler(getInviteInfo)).Methods("POST")
BaseRoutes.Teams.Handle("/create", ApiAppHandler(createTeam)).Methods("POST")
BaseRoutes.Teams.Handle("/create_from_signup", ApiAppHandler(createTeamFromSignup)).Methods("POST")
BaseRoutes.Teams.Handle("/signup", ApiAppHandler(signupTeam)).Methods("POST")
BaseRoutes.Teams.Handle("/all", ApiAppHandler(getAll)).Methods("GET")
BaseRoutes.Teams.Handle("/all_team_listings", ApiUserRequired(GetAllTeamListings)).Methods("GET")
BaseRoutes.Teams.Handle("/get_invite_info", ApiAppHandler(getInviteInfo)).Methods("POST")
BaseRoutes.Teams.Handle("/find_team_by_name", ApiAppHandler(findTeamByName)).Methods("POST")
BaseRoutes.Teams.Handle("/members/{id:[A-Za-z0-9]+}", ApiUserRequired(getMembers)).Methods("GET")
BaseRoutes.NeedTeam.Handle("/me", ApiUserRequired(getMyTeam)).Methods("GET")
BaseRoutes.NeedTeam.Handle("/update", ApiUserRequired(updateTeam)).Methods("POST")
BaseRoutes.NeedTeam.Handle("/invite_members", ApiUserRequired(inviteMembers)).Methods("POST")
BaseRoutes.NeedTeam.Handle("/add_user_to_team", ApiUserRequired(addUserToTeam)).Methods("POST")
// These should be moved to the global admain console
sr.Handle("/import_team", ApiUserRequired(importTeam)).Methods("POST")
sr.Handle("/export_team", ApiUserRequired(exportTeam)).Methods("GET")
BaseRoutes.Teams.Handle("/import_team", ApiUserRequired(importTeam)).Methods("POST")
BaseRoutes.Teams.Handle("/export_team", ApiUserRequired(exportTeam)).Methods("GET")
BaseRoutes.Teams.Handle("/add_user_to_team_from_invite", ApiUserRequired(addUserToTeamFromInvite)).Methods("POST")
}
func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
@ -92,67 +97,6 @@ func signupTeam(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(model.MapToJson(m)))
}
func createTeamFromSSO(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
service := params["service"]
sso := utils.Cfg.GetSSOService(service)
if sso != nil && !sso.Enable {
c.SetInvalidParam("createTeamFromSSO", "service")
return
}
team := model.TeamFromJson(r.Body)
if team == nil {
c.SetInvalidParam("createTeamFromSSO", "team")
return
}
if !isTeamCreationAllowed(c, team.Email) {
return
}
team.PreSave()
team.Name = model.CleanTeamName(team.Name)
if err := team.IsValid(*utils.Cfg.TeamSettings.RestrictTeamNames); err != nil {
c.Err = err
return
}
team.Id = ""
found := true
count := 0
for found {
if found = FindTeamByName(c, team.Name, "true"); c.Err != nil {
return
} else if found {
team.Name = team.Name + strconv.Itoa(count)
count += 1
}
}
if result := <-Srv.Store.Team().Save(team); result.Err != nil {
c.Err = result.Err
return
} else {
rteam := result.Data.(*model.Team)
if _, err := CreateDefaultChannels(c, rteam.Id); err != nil {
c.Err = nil
return
}
data := map[string]string{"follow_link": c.GetSiteURL() + "/api/v1/oauth/" + service + "/signup?team=" + rteam.Name}
w.Write([]byte(model.MapToJson(data)))
}
}
func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
if !utils.Cfg.EmailSettings.EnableSignUpWithEmail {
c.Err = model.NewLocAppError("createTeamFromSignup", "api.team.create_team_from_signup.email_disabled.app_error", nil, "")
@ -186,13 +130,11 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
password := teamSignup.User.Password
teamSignup.User.PreSave()
teamSignup.User.TeamId = model.NewId()
if err := teamSignup.User.IsValid(); err != nil {
c.Err = err
return
}
teamSignup.User.Id = ""
teamSignup.User.TeamId = ""
teamSignup.User.Password = password
if !model.ComparePassword(teamSignup.Hash, fmt.Sprintf("%v:%v", teamSignup.Data, utils.Cfg.EmailSettings.InviteSalt)) {
@ -206,10 +148,7 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
found := FindTeamByName(c, teamSignup.Team.Name, "true")
if c.Err != nil {
return
}
found := FindTeamByName(teamSignup.Team.Name)
if found {
c.Err = model.NewLocAppError("createTeamFromSignup", "api.team.create_team_from_signup.unavailable.app_error", nil, "d="+teamSignup.Team.Name)
@ -227,15 +166,16 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
teamSignup.User.TeamId = rteam.Id
teamSignup.User.EmailVerified = true
ruser, err := CreateUser(rteam, &teamSignup.User)
ruser, err := CreateUser(&teamSignup.User)
if err != nil {
c.Err = err
return
}
JoinUserToTeam(rteam, ruser)
InviteMembers(c, rteam, ruser, teamSignup.Invites)
teamSignup.Team = *rteam
@ -245,85 +185,38 @@ func createTeamFromSignup(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
func createTeamWithLdap(c *Context, w http.ResponseWriter, r *http.Request) {
ldap := einterfaces.GetLdapInterface()
if ldap == nil {
c.Err = model.NewLocAppError("createTeamWithLdap", "ent.ldap.do_login.licence_disable.app_error", nil, "")
func createTeam(c *Context, w http.ResponseWriter, r *http.Request) {
team := model.TeamFromJson(r.Body)
if team == nil {
c.SetInvalidParam("createTeam", "team")
return
}
teamSignup := model.TeamSignupFromJson(r.Body)
var user *model.User
if len(c.Session.UserId) > 0 {
uchan := Srv.Store.User().Get(c.Session.UserId)
if teamSignup == nil {
c.SetInvalidParam("createTeam", "teamSignup")
return
if result := <-uchan; result.Err != nil {
c.Err = result.Err
return
} else {
user = result.Data.(*model.User)
team.Email = user.Email
}
}
teamSignup.Team.PreSave()
if err := teamSignup.Team.IsValid(*utils.Cfg.TeamSettings.RestrictTeamNames); err != nil {
c.Err = err
return
}
if !isTeamCreationAllowed(c, teamSignup.Team.Email) {
return
}
teamSignup.Team.Id = ""
found := FindTeamByName(c, teamSignup.Team.Name, "true")
rteam := CreateTeam(c, team)
if c.Err != nil {
return
}
if found {
c.Err = model.NewLocAppError("createTeamFromSignup", "api.team.create_team_from_signup.unavailable.app_error", nil, "d="+teamSignup.Team.Name)
return
}
user, err := ldap.GetUser(teamSignup.User.Username)
if err != nil {
c.Err = err
return
}
err = ldap.CheckPassword(teamSignup.User.Username, teamSignup.User.Password)
if err != nil {
c.Err = err
return
}
if result := <-Srv.Store.Team().Save(&teamSignup.Team); result.Err != nil {
c.Err = result.Err
return
} else {
rteam := result.Data.(*model.Team)
if _, err := CreateDefaultChannels(c, rteam.Id); err != nil {
c.Err = nil
return
}
user.TeamId = rteam.Id
ruser, err := CreateUser(rteam, user)
if user != nil {
err := JoinUserToTeam(team, user)
if err != nil {
c.Err = err
return
}
teamSignup.Team = *rteam
teamSignup.User = *ruser
w.Write([]byte(teamSignup.ToJson()))
}
}
func createTeam(c *Context, w http.ResponseWriter, r *http.Request) {
team := model.TeamFromJson(r.Body)
rteam := CreateTeam(c, team)
if c.Err != nil {
return
}
w.Write([]byte(rteam.ToJson()))
@ -360,6 +253,31 @@ func CreateTeam(c *Context, team *model.Team) *model.Team {
}
}
func JoinUserToTeam(team *model.Team, user *model.User) *model.AppError {
tm := &model.TeamMember{TeamId: team.Id, UserId: user.Id}
channelRole := ""
if team.Email == user.Email {
tm.Roles = model.ROLE_TEAM_ADMIN
channelRole = model.CHANNEL_ROLE_ADMIN
}
if tmr := <-Srv.Store.Team().SaveMember(tm); tmr.Err != nil {
return tmr.Err
}
// Soft error if there is an issue joining the default channels
if err := JoinDefaultChannels(team.Id, user, channelRole); err != nil {
l4g.Error(utils.T("api.user.create_user.joining.error"), user.Id, team.Id, err)
}
RemoveAllSessionsForUserId(user.Id)
InvalidateCacheForUser(user.Id)
return nil
}
func isTeamCreationAllowed(c *Context, email string) bool {
email = strings.ToLower(email)
@ -389,6 +307,24 @@ func isTeamCreationAllowed(c *Context, email string) bool {
return true
}
func GetAllTeamListings(c *Context, w http.ResponseWriter, r *http.Request) {
if result := <-Srv.Store.Team().GetAllTeamListing(); result.Err != nil {
c.Err = result.Err
return
} else {
teams := result.Data.([]*model.Team)
m := make(map[string]*model.Team)
for _, v := range teams {
m[v.Id] = v
if !c.IsSystemAdmin() {
m[v.Id].Sanitize()
}
}
w.Write([]byte(model.TeamMapToJson(m)))
}
}
func getAll(c *Context, w http.ResponseWriter, r *http.Request) {
if result := <-Srv.Store.Team().GetAll(); result.Err != nil {
c.Err = result.Err
@ -435,42 +371,6 @@ func revokeAllSessions(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
func findTeamByName(c *Context, w http.ResponseWriter, r *http.Request) {
m := model.MapFromJson(r.Body)
name := strings.ToLower(strings.TrimSpace(m["name"]))
all := strings.ToLower(strings.TrimSpace(m["all"]))
found := FindTeamByName(c, name, all)
if c.Err != nil {
return
}
if found {
w.Write([]byte("true"))
} else {
w.Write([]byte("false"))
}
}
func FindTeamByName(c *Context, name string, all string) bool {
if name == "" || len(name) > 64 {
c.SetInvalidParam("findTeamByName", "domain")
return false
}
if result := <-Srv.Store.Team().GetByName(name); result.Err != nil {
return false
} else {
return true
}
return false
}
func inviteMembers(c *Context, w http.ResponseWriter, r *http.Request) {
invites := model.InvitesFromJson(r.Body)
if len(invites.Invites) == 0 {
@ -479,7 +379,7 @@ func inviteMembers(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
tchan := Srv.Store.Team().Get(c.Session.TeamId)
tchan := Srv.Store.Team().Get(c.TeamId)
uchan := Srv.Store.User().Get(c.Session.UserId)
var team *model.Team
@ -498,15 +398,6 @@ func inviteMembers(c *Context, w http.ResponseWriter, r *http.Request) {
user = result.Data.(*model.User)
}
var invNum int64 = 0
for i, invite := range invites.Invites {
if result := <-Srv.Store.User().GetByEmail(c.Session.TeamId, invite["email"]); result.Err == nil || result.Err.Id != store.MISSING_ACCOUNT_ERROR {
invNum = int64(i)
c.Err = model.NewLocAppError("invite_members", "api.team.invite_members.already.app_error", nil, strconv.FormatInt(invNum, 10))
return
}
}
ia := make([]string, len(invites.Invites))
for _, invite := range invites.Invites {
ia = append(ia, invite["email"])
@ -517,6 +408,146 @@ func inviteMembers(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(invites.ToJson()))
}
func addUserToTeam(c *Context, w http.ResponseWriter, r *http.Request) {
params := model.MapFromJson(r.Body)
userId := params["user_id"]
if len(userId) != 26 {
c.SetInvalidParam("addUserToTeam", "user_id")
return
}
tchan := Srv.Store.Team().Get(c.TeamId)
uchan := Srv.Store.User().Get(userId)
var team *model.Team
if result := <-tchan; result.Err != nil {
c.Err = result.Err
return
} else {
team = result.Data.(*model.Team)
}
var user *model.User
if result := <-uchan; result.Err != nil {
c.Err = result.Err
return
} else {
user = result.Data.(*model.User)
}
if !c.IsTeamAdmin() {
c.Err = model.NewLocAppError("addUserToTeam", "api.team.update_team.permissions.app_error", nil, "userId="+c.Session.UserId)
c.Err.StatusCode = http.StatusForbidden
return
}
err := JoinUserToTeam(team, user)
if err != nil {
c.Err = err
return
}
w.Write([]byte(model.MapToJson(params)))
}
func addUserToTeamFromInvite(c *Context, w http.ResponseWriter, r *http.Request) {
params := model.MapFromJson(r.Body)
hash := params["hash"]
data := params["data"]
inviteId := params["invite_id"]
teamId := ""
var team *model.Team
if len(hash) > 0 {
props := model.MapFromJson(strings.NewReader(data))
if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) {
c.Err = model.NewLocAppError("addUserToTeamFromInvite", "api.user.create_user.signup_link_invalid.app_error", nil, "")
return
}
t, err := strconv.ParseInt(props["time"], 10, 64)
if err != nil || model.GetMillis()-t > 1000*60*60*48 { // 48 hours
c.Err = model.NewLocAppError("addUserToTeamFromInvite", "api.user.create_user.signup_link_expired.app_error", nil, "")
return
}
teamId = props["id"]
// try to load the team to make sure it exists
if result := <-Srv.Store.Team().Get(teamId); result.Err != nil {
c.Err = result.Err
return
} else {
team = result.Data.(*model.Team)
}
}
if len(inviteId) > 0 {
if result := <-Srv.Store.Team().GetByInviteId(inviteId); result.Err != nil {
c.Err = result.Err
return
} else {
team = result.Data.(*model.Team)
teamId = team.Id
}
}
if len(teamId) == 0 {
c.Err = model.NewLocAppError("addUserToTeamFromInvite", "api.user.create_user.signup_link_invalid.app_error", nil, "")
return
}
uchan := Srv.Store.User().Get(c.Session.UserId)
var user *model.User
if result := <-uchan; result.Err != nil {
c.Err = result.Err
return
} else {
user = result.Data.(*model.User)
}
tm := c.Session.GetTeamByTeamId(teamId)
if tm == nil {
err := JoinUserToTeam(team, user)
if err != nil {
c.Err = err
return
}
}
team.Sanitize()
w.Write([]byte(team.ToJson()))
}
func FindTeamByName(name string) bool {
if result := <-Srv.Store.Team().GetByName(name); result.Err != nil {
return false
} else {
return true
}
}
func findTeamByName(c *Context, w http.ResponseWriter, r *http.Request) {
m := model.MapFromJson(r.Body)
name := strings.ToLower(strings.TrimSpace(m["name"]))
found := FindTeamByName(name)
if found {
w.Write([]byte("true"))
} else {
w.Write([]byte("false"))
}
}
func InviteMembers(c *Context, team *model.Team, user *model.User, invites []string) {
for _, invite := range invites {
if len(invite) > 0 {
@ -573,7 +604,7 @@ func updateTeam(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
team.Id = c.Session.TeamId
team.Id = c.TeamId
if !c.IsTeamAdmin() {
c.Err = model.NewLocAppError("updateTeam", "api.team.update_team.permissions.app_error", nil, "userId="+c.Session.UserId)
@ -592,7 +623,6 @@ func updateTeam(c *Context, w http.ResponseWriter, r *http.Request) {
oldTeam.DisplayName = team.DisplayName
oldTeam.InviteId = team.InviteId
oldTeam.AllowOpenInvite = team.AllowOpenInvite
oldTeam.AllowTeamListing = team.AllowTeamListing
oldTeam.CompanyName = team.CompanyName
oldTeam.AllowedDomains = team.AllowedDomains
//oldTeam.Type = team.Type
@ -617,16 +647,11 @@ func PermanentDeleteTeam(c *Context, team *model.Team) *model.AppError {
return result.Err
}
if result := <-Srv.Store.User().GetForExport(team.Id); result.Err != nil {
if result := <-Srv.Store.Channel().PermanentDeleteByTeam(team.Id); result.Err != nil {
return result.Err
} else {
users := result.Data.([]*model.User)
for _, user := range users {
PermanentDeleteUser(c, user)
}
}
if result := <-Srv.Store.Channel().PermanentDeleteByTeam(team.Id); result.Err != nil {
if result := <-Srv.Store.Team().RemoveAllMembersByTeam(team.Id); result.Err != nil {
return result.Err
}
@ -642,11 +667,11 @@ func PermanentDeleteTeam(c *Context, team *model.Team) *model.AppError {
func getMyTeam(c *Context, w http.ResponseWriter, r *http.Request) {
if len(c.Session.TeamId) == 0 {
if len(c.TeamId) == 0 {
return
}
if result := <-Srv.Store.Team().Get(c.Session.TeamId); result.Err != nil {
if result := <-Srv.Store.Team().Get(c.TeamId); result.Err != nil {
c.Err = result.Err
return
} else if HandleEtag(result.Data.(*model.Team).Etag(), w, r) {
@ -659,7 +684,7 @@ func getMyTeam(c *Context, w http.ResponseWriter, r *http.Request) {
}
func importTeam(c *Context, w http.ResponseWriter, r *http.Request) {
if !c.HasPermissionsToTeam(c.Session.TeamId, "import") || !c.IsTeamAdmin() {
if !c.HasPermissionsToTeam(c.TeamId, "import") || !c.IsTeamAdmin() {
c.Err = model.NewLocAppError("importTeam", "api.team.import_team.admin.app_error", nil, "userId="+c.Session.UserId)
c.Err.StatusCode = http.StatusForbidden
return
@ -714,7 +739,7 @@ func importTeam(c *Context, w http.ResponseWriter, r *http.Request) {
switch importFrom {
case "slack":
var err *model.AppError
if err, log = SlackImport(fileData, fileSize, c.Session.TeamId); err != nil {
if err, log = SlackImport(fileData, fileSize, c.TeamId); err != nil {
c.Err = err
c.Err.StatusCode = http.StatusBadRequest
}
@ -726,7 +751,7 @@ func importTeam(c *Context, w http.ResponseWriter, r *http.Request) {
}
func exportTeam(c *Context, w http.ResponseWriter, r *http.Request) {
if !c.HasPermissionsToTeam(c.Session.TeamId, "export") || !c.IsTeamAdmin() {
if !c.HasPermissionsToTeam(c.TeamId, "export") || !c.IsTeamAdmin() {
c.Err = model.NewLocAppError("exportTeam", "api.team.export_team.admin.app_error", nil, "userId="+c.Session.UserId)
c.Err.StatusCode = http.StatusForbidden
return
@ -765,3 +790,23 @@ func getInviteInfo(c *Context, w http.ResponseWriter, r *http.Request) {
w.Write([]byte(model.MapToJson(result)))
}
}
func getMembers(c *Context, w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
id := params["id"]
if c.Session.GetTeamByTeamId(id) == nil {
if !c.HasSystemAdminPermissions("getMembers") {
return
}
}
if result := <-Srv.Store.Team().GetMembers(id); result.Err != nil {
c.Err = result.Err
return
} else {
members := result.Data.([]*model.TeamMember)
w.Write([]byte(model.TeamMembersToJson(members)))
return
}
}

View file

@ -13,7 +13,9 @@ import (
)
func TestSignupTeam(t *testing.T) {
Setup()
th := Setup().InitBasic()
th.BasicClient.Logout()
Client := th.BasicClient
_, err := Client.SignupTeam("test@nowhere.com", "name")
if err != nil {
@ -22,7 +24,9 @@ func TestSignupTeam(t *testing.T) {
}
func TestCreateFromSignupTeam(t *testing.T) {
Setup()
th := Setup().InitBasic()
th.BasicClient.Logout()
Client := th.BasicClient
props := make(map[string]string)
props["email"] = strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com"
@ -47,6 +51,8 @@ func TestCreateFromSignupTeam(t *testing.T) {
}
ruser := rts.Data.(*model.TeamSignup).User
rteam := rts.Data.(*model.TeamSignup).Team
Client.SetTeamId(rteam.Id)
if result, err := Client.LoginById(ruser.Id, user.Password); err != nil {
t.Fatal(err)
@ -69,7 +75,9 @@ func TestCreateFromSignupTeam(t *testing.T) {
}
func TestCreateTeam(t *testing.T) {
Setup()
th := Setup().InitBasic()
th.BasicClient.Logout()
Client := th.BasicClient
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
rteam, err := Client.CreateTeam(&team)
@ -77,11 +85,13 @@ func TestCreateTeam(t *testing.T) {
t.Fatal(err)
}
user := &model.User{TeamId: rteam.Data.(*model.Team).Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
LinkUserToTeam(user, rteam.Data.(*model.Team))
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
Client.SetTeamId(rteam.Data.(*model.Team).Id)
c1 := Client.Must(Client.GetChannels("")).Data.(*model.ChannelList)
if len(c1.Channels) != 2 {
@ -108,23 +118,124 @@ func TestCreateTeam(t *testing.T) {
}
}
func TestGetAllTeams(t *testing.T) {
Setup()
func TestAddUserToTeam(t *testing.T) {
th := Setup().InitBasic()
th.BasicClient.Logout()
Client := th.BasicClient
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN, AllowTeamListing: true}
props := make(map[string]string)
props["email"] = strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com"
props["name"] = "Test Company name"
props["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(props)
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: props["email"], Type: model.TEAM_OPEN}
user := model.User{Email: props["email"], Nickname: "Corey Hulen", Password: "hello"}
ts := model.TeamSignup{Team: team, User: user, Invites: []string{"success+test@simulator.amazonses.com"}, Data: data, Hash: hash}
rts, err := Client.CreateTeamFromSignup(&ts)
if err != nil {
t.Fatal(err)
}
if rts.Data.(*model.TeamSignup).Team.DisplayName != team.DisplayName {
t.Fatal("full name didn't match")
}
ruser := rts.Data.(*model.TeamSignup).User
rteam := rts.Data.(*model.TeamSignup).Team
Client.SetTeamId(rteam.Id)
if result, err := Client.LoginById(ruser.Id, user.Password); err != nil {
t.Fatal(err)
} else {
if result.Data.(*model.User).Email != user.Email {
t.Fatal("email's didn't match")
}
}
user2 := th.CreateUser(th.BasicClient)
if result, err := th.BasicClient.AddUserToTeam(user2.Id); err != nil {
t.Fatal(err)
} else {
rm := result.Data.(map[string]string)
if rm["user_id"] != user2.Id {
t.Fatal("email's didn't match")
}
}
}
func TestAddUserToTeamFromInvite(t *testing.T) {
th := Setup().InitBasic()
th.BasicClient.Logout()
Client := th.BasicClient
props := make(map[string]string)
props["email"] = strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com"
props["name"] = "Test Company name"
props["time"] = fmt.Sprintf("%v", model.GetMillis())
data := model.MapToJson(props)
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt))
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: props["email"], Type: model.TEAM_OPEN}
user := model.User{Email: props["email"], Nickname: "Corey Hulen", Password: "hello"}
ts := model.TeamSignup{Team: team, User: user, Invites: []string{"success+test@simulator.amazonses.com"}, Data: data, Hash: hash}
rts, err := Client.CreateTeamFromSignup(&ts)
if err != nil {
t.Fatal(err)
}
if rts.Data.(*model.TeamSignup).Team.DisplayName != team.DisplayName {
t.Fatal("full name didn't match")
}
ruser := rts.Data.(*model.TeamSignup).User
rteam := rts.Data.(*model.TeamSignup).Team
Client.SetTeamId(rteam.Id)
if result, err := Client.LoginById(ruser.Id, user.Password); err != nil {
t.Fatal(err)
} else {
if result.Data.(*model.User).Email != user.Email {
t.Fatal("email's didn't match")
}
}
user2 := th.CreateUser(th.BasicClient)
Client.Must(Client.Logout())
Client.Must(Client.LoginByEmail("", user2.Email, user2.Password))
if result, err := th.BasicClient.AddUserToTeamFromInvite("", "", rteam.InviteId); err != nil {
t.Fatal(err)
} else {
rtm := result.Data.(*model.Team)
if rtm.Id != rteam.Id {
t.Fatal()
}
}
}
func TestGetAllTeams(t *testing.T) {
th := Setup().InitBasic()
th.BasicClient.Logout()
Client := th.BasicClient
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
LinkUserToTeam(user, team)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
enableIncomingHooks := *utils.Cfg.TeamSettings.EnableTeamListing
defer func() {
*utils.Cfg.TeamSettings.EnableTeamListing = enableIncomingHooks
}()
*utils.Cfg.TeamSettings.EnableTeamListing = true
Client.SetTeamId(team.Id)
if r1, err := Client.GetAllTeams(); err != nil {
t.Fatal(err)
@ -144,6 +255,56 @@ func TestGetAllTeams(t *testing.T) {
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
Client.SetTeamId(team.Id)
if r1, err := Client.GetAllTeams(); err != nil {
t.Fatal(err)
} else {
teams := r1.Data.(map[string]*model.Team)
if teams[team.Id].Name != team.Name {
t.Fatal()
}
if teams[team.Id].Email != team.Email {
t.Fatal()
}
}
}
func TestGetAllTeamListings(t *testing.T) {
th := Setup().InitBasic()
th.BasicClient.Logout()
Client := th.BasicClient
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN, AllowOpenInvite: true}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
LinkUserToTeam(user, team)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
Client.SetTeamId(team.Id)
if r1, err := Client.GetAllTeamListings(); err != nil {
t.Fatal(err)
} else {
teams := r1.Data.(map[string]*model.Team)
if teams[team.Id].Name != team.Name {
t.Fatal()
}
if teams[team.Id].Email != "" {
t.Fatal("Non admin users shoudn't get full listings")
}
}
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
Client.SetTeamId(team.Id)
if r1, err := Client.GetAllTeams(); err != nil {
t.Fatal(err)
@ -159,16 +320,20 @@ func TestGetAllTeams(t *testing.T) {
}
func TestTeamPermDelete(t *testing.T) {
Setup()
th := Setup().InitBasic()
th.BasicClient.Logout()
Client := th.BasicClient
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
LinkUserToTeam(user1, team)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
Client.SetTeamId(team.Id)
channel1 := &model.Channel{DisplayName: "TestGetPosts", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
@ -198,19 +363,23 @@ func TestTeamPermDelete(t *testing.T) {
}
func TestInviteMembers(t *testing.T) {
Setup()
th := Setup().InitBasic()
th.BasicClient.Logout()
Client := th.BasicClient
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user := &model.User{Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
LinkUserToTeam(user, team)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
Client.LoginByEmail(team.Name, user.Email, "pwd")
Client.SetTeamId(team.Id)
invite := make(map[string]string)
invite["email"] = model.NewId() + "success+test@simulator.amazonses.com"
invite["email"] = "success+" + model.NewId() + "@simulator.amazonses.com"
invite["first_name"] = "Test"
invite["last_name"] = "Guy"
invites := &model.Invites{Invites: []map[string]string{invite}}
@ -227,20 +396,25 @@ func TestInviteMembers(t *testing.T) {
}
func TestUpdateTeamDisplayName(t *testing.T) {
Setup()
th := Setup().InitBasic()
th.BasicClient.Logout()
Client := th.BasicClient
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "success+" + model.NewId() + "@simulator.amazonses.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: "test@nowhere.com", Nickname: "Corey Hulen", Password: "pwd"}
user := &model.User{Email: team.Email, Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
LinkUserToTeam(user, team)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 := &model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
LinkUserToTeam(user2, team)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
Client.LoginByEmail(team.Name, user2.Email, "pwd")
Client.SetTeamId(team.Id)
vteam := &model.Team{DisplayName: team.DisplayName, Name: team.Name, Email: team.Email, Type: team.Type}
vteam.DisplayName = "NewName"
@ -262,6 +436,9 @@ func TestUpdateTeamDisplayName(t *testing.T) {
}
func TestFuzzyTeamCreate(t *testing.T) {
th := Setup().InitBasic()
th.BasicClient.Logout()
Client := th.BasicClient
for i := 0; i < len(utils.FUZZY_STRINGS_NAMES) || i < len(utils.FUZZY_STRINGS_EMAILS); i++ {
testDisplayName := "Name"
@ -284,19 +461,24 @@ func TestFuzzyTeamCreate(t *testing.T) {
}
func TestGetMyTeam(t *testing.T) {
Setup()
th := Setup().InitBasic()
th.BasicClient.Logout()
Client := th.BasicClient
team := model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
rteam, _ := Client.CreateTeam(&team)
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
rteam, _ := Client.CreateTeam(team)
team = rteam.Data.(*model.Team)
user := model.User{TeamId: rteam.Data.(*model.Team).Id, Email: strings.ToLower(model.NewId()) + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user := model.User{Email: "success+" + model.NewId() + "@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
ruser, _ := Client.CreateUser(&user, "")
LinkUserToTeam(ruser.Data.(*model.User), rteam.Data.(*model.Team))
store.Must(Srv.Store.User().VerifyEmail(ruser.Data.(*model.User).Id))
Client.LoginByEmail(team.Name, user.Email, user.Password)
Client.SetTeamId(team.Id)
if result, err := Client.GetMyTeam(""); err != nil {
t.Fatal("Failed to get user")
t.Fatal(err)
} else {
if result.Data.(*model.Team).DisplayName != team.DisplayName {
t.Fatal("team names did not match")
@ -309,3 +491,14 @@ func TestGetMyTeam(t *testing.T) {
}
}
}
func TestGetTeamMembers(t *testing.T) {
th := Setup().InitBasic()
if result, err := th.BasicClient.GetTeamMembers(th.BasicTeam.Id); err != nil {
t.Fatal(err)
} else {
members := result.Data.([]*model.TeamMember)
t.Log(members)
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,6 @@ import (
l4g "github.com/alecthomas/log4go"
"github.com/gorilla/websocket"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
"time"
)
@ -21,14 +20,15 @@ const (
)
type WebConn struct {
WebSocket *websocket.Conn
Send chan *model.Message
TeamId string
UserId string
ChannelAccessCache map[string]bool
WebSocket *websocket.Conn
Send chan *model.Message
SessionId string
UserId string
hasPermissionsToChannel map[string]bool
hasPermissionsToTeam map[string]bool
}
func NewWebConn(ws *websocket.Conn, teamId string, userId string, sessionId string) *WebConn {
func NewWebConn(ws *websocket.Conn, userId string, sessionId string) *WebConn {
go func() {
achan := Srv.Store.User().UpdateUserAndSessionActivity(userId, sessionId, model.GetMillis())
pchan := Srv.Store.User().UpdateLastPingAt(userId, model.GetMillis())
@ -42,7 +42,14 @@ func NewWebConn(ws *websocket.Conn, teamId string, userId string, sessionId stri
}
}()
return &WebConn{Send: make(chan *model.Message, 64), WebSocket: ws, UserId: userId, TeamId: teamId, ChannelAccessCache: make(map[string]bool)}
return &WebConn{
Send: make(chan *model.Message, 64),
WebSocket: ws,
UserId: userId,
SessionId: sessionId,
hasPermissionsToChannel: make(map[string]bool),
hasPermissionsToTeam: make(map[string]bool),
}
}
func (c *WebConn) readPump() {
@ -69,7 +76,6 @@ func (c *WebConn) readPump() {
if err := c.WebSocket.ReadJSON(&msg); err != nil {
return
} else {
msg.TeamId = c.TeamId
msg.UserId = c.UserId
PublishAndForget(&msg)
}
@ -107,19 +113,53 @@ func (c *WebConn) writePump() {
}
}
func (c *WebConn) updateChannelAccessCache(channelId string) bool {
allowed := hasPermissionsToChannel(Srv.Store.Channel().CheckPermissionsTo(c.TeamId, channelId, c.UserId))
c.ChannelAccessCache[channelId] = allowed
return allowed
func (c *WebConn) InvalidateCache() {
c.hasPermissionsToChannel = make(map[string]bool)
c.hasPermissionsToTeam = make(map[string]bool)
}
func hasPermissionsToChannel(sc store.StoreChannel) bool {
if cresult := <-sc; cresult.Err != nil {
return false
} else if cresult.Data.(int64) != 1 {
return false
func (c *WebConn) HasPermissionsToTeam(teamId string) bool {
perm, ok := c.hasPermissionsToTeam[teamId]
if !ok {
session := GetSession(c.SessionId)
if session == nil {
perm = false
c.hasPermissionsToTeam[teamId] = perm
} else {
member := session.GetTeamByTeamId(teamId)
if member != nil {
perm = true
c.hasPermissionsToTeam[teamId] = perm
} else {
perm = true
c.hasPermissionsToTeam[teamId] = perm
}
}
}
return true
return perm
}
func (c *WebConn) HasPermissionsToChannel(channelId string) bool {
perm, ok := c.hasPermissionsToChannel[channelId]
if !ok {
if cresult := <-Srv.Store.Channel().CheckPermissionsToNoTeam(channelId, c.UserId); cresult.Err != nil {
perm = false
c.hasPermissionsToChannel[channelId] = perm
} else {
count := cresult.Data.(int64)
if count == 1 {
perm = true
c.hasPermissionsToChannel[channelId] = perm
} else {
perm = false
c.hasPermissionsToChannel[channelId] = perm
}
}
}
return perm
}

View file

@ -10,19 +10,21 @@ import (
)
type Hub struct {
teamHubs map[string]*TeamHub
register chan *WebConn
unregister chan *WebConn
broadcast chan *model.Message
stop chan string
connections map[*WebConn]bool
register chan *WebConn
unregister chan *WebConn
broadcast chan *model.Message
stop chan string
invalidateUser chan string
}
var hub = &Hub{
register: make(chan *WebConn),
unregister: make(chan *WebConn),
teamHubs: make(map[string]*TeamHub),
broadcast: make(chan *model.Message),
stop: make(chan string),
register: make(chan *WebConn),
unregister: make(chan *WebConn),
connections: make(map[*WebConn]bool),
broadcast: make(chan *model.Message),
stop: make(chan string),
invalidateUser: make(chan string),
}
func PublishAndForget(message *model.Message) {
@ -31,16 +33,8 @@ func PublishAndForget(message *model.Message) {
}()
}
func UpdateChannelAccessCache(teamId, userId, channelId string) {
if nh, ok := hub.teamHubs[teamId]; ok {
nh.UpdateChannelAccessCache(userId, channelId)
}
}
func UpdateChannelAccessCacheAndForget(teamId, userId, channelId string) {
go func() {
UpdateChannelAccessCache(teamId, userId, channelId)
}()
func InvalidateCacheForUser(userId string) {
hub.invalidateUser <- userId
}
func (h *Hub) Register(webConn *WebConn) {
@ -65,34 +59,92 @@ func (h *Hub) Start() {
go func() {
for {
select {
case webCon := <-h.register:
h.connections[webCon] = true
case c := <-h.register:
nh := h.teamHubs[c.TeamId]
if nh == nil {
nh = NewTeamHub(c.TeamId)
h.teamHubs[c.TeamId] = nh
nh.Start()
case webCon := <-h.unregister:
if _, ok := h.connections[webCon]; ok {
delete(h.connections, webCon)
close(webCon.Send)
}
case userId := <-h.invalidateUser:
for webCon := range h.connections {
if webCon.UserId == userId {
webCon.InvalidateCache()
}
}
nh.Register(c)
case c := <-h.unregister:
if nh, ok := h.teamHubs[c.TeamId]; ok {
nh.Unregister(c)
}
case msg := <-h.broadcast:
nh := h.teamHubs[msg.TeamId]
if nh != nil {
nh.broadcast <- msg
for webCon := range h.connections {
if shouldSendEvent(webCon, msg) {
select {
case webCon.Send <- msg:
default:
close(webCon.Send)
delete(h.connections, webCon)
}
}
}
case s := <-h.stop:
l4g.Debug(utils.T("api.web_hub.start.stopping.debug"), s)
for _, v := range h.teamHubs {
v.Stop()
for webCon := range h.connections {
webCon.WebSocket.Close()
}
return
}
}
}()
}
func shouldSendEvent(webCon *WebConn, msg *model.Message) bool {
if webCon.UserId == msg.UserId {
// Don't need to tell the user they are typing
if msg.Action == model.ACTION_TYPING {
return false
}
// We have to make sure the user is in the channel. Otherwise system messages that
// post about users in channels they are not in trigger warnings.
if len(msg.ChannelId) > 0 {
allowed := webCon.HasPermissionsToChannel(msg.ChannelId)
if !allowed {
return false
}
}
} else {
// Don't share a user's view or preference events with other users
if msg.Action == model.ACTION_CHANNEL_VIEWED {
return false
} else if msg.Action == model.ACTION_PREFERENCE_CHANGED {
return false
} else if msg.Action == model.ACTION_EPHEMERAL_MESSAGE {
// For now, ephemeral messages are sent directly to individual users
return false
}
// Only report events to users who are in the team for the event
if len(msg.TeamId) > 0 {
allowed := webCon.HasPermissionsToTeam(msg.TeamId)
if !allowed {
return false
}
}
// Only report events to users who are in the channel for the event
if len(msg.ChannelId) > 0 {
allowed := webCon.HasPermissionsToChannel(msg.ChannelId)
if !allowed {
return false
}
}
}
return true
}

View file

@ -5,16 +5,15 @@ package api
import (
l4g "github.com/alecthomas/log4go"
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
"net/http"
)
func InitWebSocket(r *mux.Router) {
func InitWebSocket() {
l4g.Debug(utils.T("api.web_socket.init.debug"))
r.Handle("/websocket", ApiUserRequiredTrustRequester(connect)).Methods("GET")
BaseRoutes.Users.Handle("/websocket", ApiUserRequiredTrustRequester(connect)).Methods("GET")
hub.Start()
}
@ -34,7 +33,7 @@ func connect(c *Context, w http.ResponseWriter, r *http.Request) {
return
}
wc := NewWebConn(ws, c.Session.TeamId, c.Session.UserId, c.Session.Id)
wc := NewWebConn(ws, c.Session.UserId, c.Session.Id)
hub.Register(wc)
go wc.writePump()
wc.readPump()

View file

@ -6,7 +6,6 @@ package api
import (
"github.com/gorilla/websocket"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
"net/http"
"testing"
@ -14,22 +13,14 @@ import (
)
func TestSocket(t *testing.T) {
Setup()
th := Setup().InitBasic()
Client := th.BasicClient
team := th.BasicTeam
channel1 := th.BasicChannel
channel2 := th.CreateChannel(Client, team)
Client.Must(Client.AddChannelMember(channel1.Id, th.BasicUser2.Id))
url := "ws://localhost" + utils.Cfg.ServiceSettings.ListenAddress + "/api/v1/websocket"
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user1 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user1 = Client.Must(Client.CreateUser(user1, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user1.Id))
Client.LoginByEmail(team.Name, user1.Email, "pwd")
channel1 := &model.Channel{DisplayName: "Test Web Scoket 1", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
channel2 := &model.Channel{DisplayName: "Test Web Scoket 2", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
url := "ws://localhost" + utils.Cfg.ServiceSettings.ListenAddress + model.API_URL_SUFFIX + "/users/websocket"
header1 := http.Header{}
header1.Set(model.HEADER_AUTH, "BEARER "+Client.AuthToken)
@ -39,10 +30,7 @@ func TestSocket(t *testing.T) {
t.Fatal(err)
}
user2 := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user2 = Client.Must(Client.CreateUser(user2, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user2.Id))
Client.LoginByEmail(team.Name, user2.Email, "pwd")
th.LoginBasic2()
header2 := http.Header{}
header2.Set(model.HEADER_AUTH, "BEARER "+Client.AuthToken)
@ -53,21 +41,11 @@ func TestSocket(t *testing.T) {
}
time.Sleep(300 * time.Millisecond)
Client.Must(Client.JoinChannel(channel1.Id))
// Read the user_added message that gets generated
var rmsg model.Message
if err := c2.ReadJSON(&rmsg); err != nil {
t.Fatal(err)
}
// Read the second user_added message that gets generated
if err := c2.ReadJSON(&rmsg); err != nil {
t.Fatal(err)
}
// Test sending message without a channelId
m := model.NewMessage("", "", "", model.ACTION_TYPING)
m := model.NewMessage(team.Id, "", "", model.ACTION_TYPING)
m.Add("RootId", model.NewId())
m.Add("ParentId", model.NewId())
@ -77,6 +55,8 @@ func TestSocket(t *testing.T) {
t.Fatal(err)
}
t.Log(rmsg.ToJson())
if team.Id != rmsg.TeamId {
t.Fatal("Ids do not match")
}
@ -86,7 +66,7 @@ func TestSocket(t *testing.T) {
}
// Test sending messsage to Channel you have access to
m = model.NewMessage("", channel1.Id, "", model.ACTION_TYPING)
m = model.NewMessage(team.Id, channel1.Id, "", model.ACTION_TYPING)
m.Add("RootId", model.NewId())
m.Add("ParentId", model.NewId())

View file

@ -1,123 +0,0 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package api
import (
l4g "github.com/alecthomas/log4go"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
)
type TeamHub struct {
connections map[*WebConn]bool
broadcast chan *model.Message
register chan *WebConn
unregister chan *WebConn
stop chan bool
teamId string
}
func NewTeamHub(teamId string) *TeamHub {
return &TeamHub{
broadcast: make(chan *model.Message),
register: make(chan *WebConn),
unregister: make(chan *WebConn),
connections: make(map[*WebConn]bool),
stop: make(chan bool),
teamId: teamId,
}
}
func (h *TeamHub) Register(webConn *WebConn) {
h.register <- webConn
}
func (h *TeamHub) Unregister(webConn *WebConn) {
h.unregister <- webConn
}
func (h *TeamHub) Stop() {
h.stop <- true
}
func (h *TeamHub) Start() {
go func() {
for {
select {
case webCon := <-h.register:
h.connections[webCon] = true
case webCon := <-h.unregister:
if _, ok := h.connections[webCon]; ok {
delete(h.connections, webCon)
close(webCon.Send)
}
case msg := <-h.broadcast:
for webCon := range h.connections {
if ShouldSendEvent(webCon, msg) {
select {
case webCon.Send <- msg:
default:
close(webCon.Send)
delete(h.connections, webCon)
}
}
}
case s := <-h.stop:
if s {
l4g.Debug(utils.T("api.web_team_hun.start.debug"), h.teamId)
for webCon := range h.connections {
webCon.WebSocket.Close()
}
return
}
}
}
}()
}
func (h *TeamHub) UpdateChannelAccessCache(userId string, channelId string) {
for webCon := range h.connections {
if webCon.UserId == userId {
webCon.updateChannelAccessCache(channelId)
break
}
}
}
func ShouldSendEvent(webCon *WebConn, msg *model.Message) bool {
if webCon.UserId == msg.UserId {
// Don't need to tell the user they are typing
if msg.Action == model.ACTION_TYPING {
return false
}
} else {
// Don't share a user's view or preference events with other users
if msg.Action == model.ACTION_CHANNEL_VIEWED {
return false
} else if msg.Action == model.ACTION_PREFERENCE_CHANGED {
return false
} else if msg.Action == model.ACTION_EPHEMERAL_MESSAGE {
// For now, ephemeral messages are sent directly to individual users
return false
}
// Only report events to a user who is the subject of the event, or is in the channel of the event
if len(msg.ChannelId) > 0 {
allowed, ok := webCon.ChannelAccessCache[msg.ChannelId]
if !ok {
allowed = webCon.updateChannelAccessCache(msg.ChannelId)
}
if !allowed {
return false
}
}
}
return true
}

View file

@ -14,20 +14,19 @@ import (
"github.com/mattermost/platform/utils"
)
func InitWebhook(r *mux.Router) {
func InitWebhook() {
l4g.Debug(utils.T("api.webhook.init.debug"))
sr := r.PathPrefix("/hooks").Subrouter()
sr.Handle("/incoming/create", ApiUserRequired(createIncomingHook)).Methods("POST")
sr.Handle("/incoming/delete", ApiUserRequired(deleteIncomingHook)).Methods("POST")
sr.Handle("/incoming/list", ApiUserRequired(getIncomingHooks)).Methods("GET")
BaseRoutes.Hooks.Handle("/incoming/create", ApiUserRequired(createIncomingHook)).Methods("POST")
BaseRoutes.Hooks.Handle("/incoming/delete", ApiUserRequired(deleteIncomingHook)).Methods("POST")
BaseRoutes.Hooks.Handle("/incoming/list", ApiUserRequired(getIncomingHooks)).Methods("GET")
sr.Handle("/outgoing/create", ApiUserRequired(createOutgoingHook)).Methods("POST")
sr.Handle("/outgoing/regen_token", ApiUserRequired(regenOutgoingHookToken)).Methods("POST")
sr.Handle("/outgoing/delete", ApiUserRequired(deleteOutgoingHook)).Methods("POST")
sr.Handle("/outgoing/list", ApiUserRequired(getOutgoingHooks)).Methods("GET")
BaseRoutes.Hooks.Handle("/outgoing/create", ApiUserRequired(createOutgoingHook)).Methods("POST")
BaseRoutes.Hooks.Handle("/outgoing/regen_token", ApiUserRequired(regenOutgoingHookToken)).Methods("POST")
BaseRoutes.Hooks.Handle("/outgoing/delete", ApiUserRequired(deleteOutgoingHook)).Methods("POST")
BaseRoutes.Hooks.Handle("/outgoing/list", ApiUserRequired(getOutgoingHooks)).Methods("GET")
sr.Handle("/{id:[A-Za-z0-9]+}", ApiAppHandler(incomingWebhook)).Methods("POST")
BaseRoutes.Hooks.Handle("/{id:[A-Za-z0-9]+}", ApiAppHandler(incomingWebhook)).Methods("POST")
// Old route. Remove eventually.
mr := Srv.Router
@ -59,10 +58,10 @@ func createIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) {
}
cchan := Srv.Store.Channel().Get(hook.ChannelId)
pchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, hook.ChannelId, c.Session.UserId)
pchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, hook.ChannelId, c.Session.UserId)
hook.UserId = c.Session.UserId
hook.TeamId = c.Session.TeamId
hook.TeamId = c.TeamId
var channel *model.Channel
if result := <-cchan; result.Err != nil {
@ -73,7 +72,7 @@ func createIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) {
}
if !c.HasPermissionsToChannel(pchan, "createIncomingHook") {
if channel.Type != model.CHANNEL_OPEN || channel.TeamId != c.Session.TeamId {
if channel.Type != model.CHANNEL_OPEN || channel.TeamId != c.TeamId {
c.LogAudit("fail - bad channel permissions")
return
}
@ -149,7 +148,7 @@ func getIncomingHooks(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
if result := <-Srv.Store.Webhook().GetIncomingByTeam(c.Session.TeamId); result.Err != nil {
if result := <-Srv.Store.Webhook().GetIncomingByTeam(c.TeamId); result.Err != nil {
c.Err = result.Err
return
} else {
@ -183,11 +182,11 @@ func createOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) {
}
hook.CreatorId = c.Session.UserId
hook.TeamId = c.Session.TeamId
hook.TeamId = c.TeamId
if len(hook.ChannelId) != 0 {
cchan := Srv.Store.Channel().Get(hook.ChannelId)
pchan := Srv.Store.Channel().CheckPermissionsTo(c.Session.TeamId, hook.ChannelId, c.Session.UserId)
pchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, hook.ChannelId, c.Session.UserId)
var channel *model.Channel
if result := <-cchan; result.Err != nil {
@ -199,11 +198,14 @@ func createOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) {
if channel.Type != model.CHANNEL_OPEN {
c.LogAudit("fail - not open channel")
c.Err = model.NewLocAppError("createOutgoingHook", "api.webhook.create_outgoing.not_open.app_error", nil, "")
return
}
if !c.HasPermissionsToChannel(pchan, "createOutgoingHook") {
if channel.Type != model.CHANNEL_OPEN || channel.TeamId != c.Session.TeamId {
if channel.Type != model.CHANNEL_OPEN || channel.TeamId != c.TeamId {
c.LogAudit("fail - bad channel permissions")
c.Err = model.NewLocAppError("createOutgoingHook", "api.webhook.create_outgoing.permissions.app_error", nil, "")
return
}
}
@ -237,7 +239,7 @@ func getOutgoingHooks(c *Context, w http.ResponseWriter, r *http.Request) {
}
}
if result := <-Srv.Store.Webhook().GetOutgoingByTeam(c.Session.TeamId); result.Err != nil {
if result := <-Srv.Store.Webhook().GetOutgoingByTeam(c.TeamId); result.Err != nil {
c.Err = result.Err
return
} else {
@ -292,7 +294,7 @@ func deleteOutgoingHook(c *Context, w http.ResponseWriter, r *http.Request) {
}
func regenOutgoingHookToken(c *Context, w http.ResponseWriter, r *http.Request) {
if !utils.Cfg.ServiceSettings.EnableIncomingWebhooks {
if !utils.Cfg.ServiceSettings.EnableOutgoingWebhooks {
c.Err = model.NewLocAppError("regenOutgoingHookToken", "api.webhook.regen_outgoing_token.disabled.app_error", nil, "")
c.Err.StatusCode = http.StatusNotImplemented
return
@ -323,7 +325,7 @@ func regenOutgoingHookToken(c *Context, w http.ResponseWriter, r *http.Request)
} else {
hook = result.Data.(*model.OutgoingWebhook)
if c.Session.TeamId != hook.TeamId && c.Session.UserId != hook.CreatorId && !c.IsTeamAdmin() {
if c.TeamId != hook.TeamId && c.Session.UserId != hook.CreatorId && !c.IsTeamAdmin() {
c.LogAudit("fail - inappropriate permissions")
c.Err = model.NewLocAppError("regenOutgoingHookToken", "api.webhook.regen_outgoing_token.permissions.app_error", nil, "user_id="+c.Session.UserId)
return
@ -398,7 +400,7 @@ func incomingWebhook(c *Context, w http.ResponseWriter, r *http.Request) {
if len(channelName) != 0 {
if channelName[0] == '@' {
if result := <-Srv.Store.User().GetByUsername(hook.TeamId, channelName[1:]); result.Err != nil {
if result := <-Srv.Store.User().GetByUsername(channelName[1:]); result.Err != nil {
c.Err = model.NewLocAppError("incomingWebhook", "web.incoming_webhook.user.app_error", nil, "err="+result.Err.Message)
return
} else {
@ -426,7 +428,11 @@ func incomingWebhook(c *Context, w http.ResponseWriter, r *http.Request) {
pchan := Srv.Store.Channel().CheckPermissionsTo(hook.TeamId, channel.Id, hook.UserId)
// create a mock session
c.Session = model.Session{UserId: hook.UserId, TeamId: hook.TeamId, IsOAuth: false}
c.Session = model.Session{
UserId: hook.UserId,
TeamMembers: []*model.TeamMember{{TeamId: hook.TeamId, UserId: hook.UserId}},
IsOAuth: false,
}
if !c.HasPermissionsToChannel(pchan, "createIncomingHook") && channel.Type != model.CHANNEL_OPEN {
c.Err = model.NewLocAppError("incomingWebhook", "web.incoming_webhook.permissions.app_error", nil, "")

View file

@ -4,416 +4,599 @@
package api
import (
"fmt"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
"testing"
"time"
)
func TestCreateIncomingHook(t *testing.T) {
Setup()
th := Setup().InitSystemAdmin()
Client := th.SystemAdminClient
user := th.SystemAdminUser
team := th.SystemAdminTeam
channel1 := th.CreateChannel(Client, team)
channel2 := th.CreatePrivateChannel(Client, team)
user2 := th.CreateUser(Client)
LinkUserToTeam(user2, team)
enableIncomingHooks := utils.Cfg.ServiceSettings.EnableIncomingWebhooks
enableOutgoingHooks := utils.Cfg.ServiceSettings.EnableOutgoingWebhooks
enableAdminOnlyHooks := utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations
defer func() {
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = enableIncomingHooks
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = enableOutgoingHooks
utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = enableAdminOnlyHooks
}()
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = true
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
channel2 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
*utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = true
hook := &model.IncomingWebhook{ChannelId: channel1.Id}
if utils.Cfg.ServiceSettings.EnableIncomingWebhooks {
var rhook *model.IncomingWebhook
if result, err := Client.CreateIncomingWebhook(hook); err != nil {
t.Fatal(err)
} else {
rhook = result.Data.(*model.IncomingWebhook)
}
if hook.ChannelId != rhook.ChannelId {
t.Fatal("channel ids didn't match")
}
if rhook.UserId != user.Id {
t.Fatal("user ids didn't match")
}
if rhook.TeamId != team.Id {
t.Fatal("team ids didn't match")
}
hook = &model.IncomingWebhook{ChannelId: "junk"}
if _, err := Client.CreateIncomingWebhook(hook); err == nil {
t.Fatal("should have failed - bad channel id")
}
hook = &model.IncomingWebhook{ChannelId: channel2.Id, UserId: "123", TeamId: "456"}
if result, err := Client.CreateIncomingWebhook(hook); err != nil {
t.Fatal(err)
} else {
if result.Data.(*model.IncomingWebhook).UserId != user.Id {
t.Fatal("bad user id wasn't overwritten")
}
if result.Data.(*model.IncomingWebhook).TeamId != team.Id {
t.Fatal("bad team id wasn't overwritten")
}
}
var rhook *model.IncomingWebhook
if result, err := Client.CreateIncomingWebhook(hook); err != nil {
t.Fatal(err)
} else {
if _, err := Client.CreateIncomingWebhook(hook); err == nil {
t.Fatal("should have errored - webhooks turned off")
rhook = result.Data.(*model.IncomingWebhook)
}
if hook.ChannelId != rhook.ChannelId {
t.Fatal("channel ids didn't match")
}
if rhook.UserId != user.Id {
t.Fatal("user ids didn't match")
}
if rhook.TeamId != team.Id {
t.Fatal("team ids didn't match")
}
hook = &model.IncomingWebhook{ChannelId: "junk"}
if _, err := Client.CreateIncomingWebhook(hook); err == nil {
t.Fatal("should have failed - bad channel id")
}
hook = &model.IncomingWebhook{ChannelId: channel2.Id, UserId: "123", TeamId: "456"}
if result, err := Client.CreateIncomingWebhook(hook); err != nil {
t.Fatal(err)
} else {
if result.Data.(*model.IncomingWebhook).UserId != user.Id {
t.Fatal("bad user id wasn't overwritten")
}
if result.Data.(*model.IncomingWebhook).TeamId != team.Id {
t.Fatal("bad team id wasn't overwritten")
}
}
Client.Logout()
Client.Must(Client.LoginById(user2.Id, user2.Password))
Client.SetTeamId(team.Id)
hook = &model.IncomingWebhook{ChannelId: channel1.Id}
if _, err := Client.CreateIncomingWebhook(hook); err == nil {
t.Fatal("should have failed - not system/team admin")
}
*utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = false
if _, err := Client.CreateIncomingWebhook(hook); err != nil {
t.Fatal(err)
}
hook = &model.IncomingWebhook{ChannelId: channel2.Id}
if _, err := Client.CreateIncomingWebhook(hook); err == nil {
t.Fatal("should have failed - channel is private and not a member")
}
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = false
if _, err := Client.CreateIncomingWebhook(hook); err == nil {
t.Fatal("should have errored - webhooks turned off")
}
}
func TestListIncomingHooks(t *testing.T) {
Setup()
th := Setup().InitSystemAdmin()
Client := th.SystemAdminClient
team := th.SystemAdminTeam
channel1 := th.CreateChannel(Client, team)
user2 := th.CreateUser(Client)
LinkUserToTeam(user2, team)
enableIncomingHooks := utils.Cfg.ServiceSettings.EnableIncomingWebhooks
enableOutgoingHooks := utils.Cfg.ServiceSettings.EnableOutgoingWebhooks
enableAdminOnlyHooks := utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations
defer func() {
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = enableIncomingHooks
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = enableOutgoingHooks
utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = enableAdminOnlyHooks
}()
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = true
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = true
*utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
hook1 := &model.IncomingWebhook{ChannelId: channel1.Id}
hook1 = Client.Must(Client.CreateIncomingWebhook(hook1)).Data.(*model.IncomingWebhook)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
hook2 := &model.IncomingWebhook{ChannelId: channel1.Id}
hook2 = Client.Must(Client.CreateIncomingWebhook(hook2)).Data.(*model.IncomingWebhook)
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
if utils.Cfg.ServiceSettings.EnableIncomingWebhooks {
hook1 := &model.IncomingWebhook{ChannelId: channel1.Id}
hook1 = Client.Must(Client.CreateIncomingWebhook(hook1)).Data.(*model.IncomingWebhook)
hook2 := &model.IncomingWebhook{ChannelId: channel1.Id}
hook2 = Client.Must(Client.CreateIncomingWebhook(hook2)).Data.(*model.IncomingWebhook)
if result, err := Client.ListIncomingWebhooks(); err != nil {
t.Fatal(err)
} else {
hooks := result.Data.([]*model.IncomingWebhook)
if len(hooks) != 2 {
t.Fatal("incorrect number of hooks")
}
}
if result, err := Client.ListIncomingWebhooks(); err != nil {
t.Fatal(err)
} else {
if _, err := Client.ListIncomingWebhooks(); err == nil {
t.Fatal("should have errored - webhooks turned off")
hooks := result.Data.([]*model.IncomingWebhook)
if len(hooks) != 2 {
t.Fatal("incorrect number of hooks")
}
}
Client.Logout()
Client.Must(Client.LoginById(user2.Id, user2.Password))
Client.SetTeamId(team.Id)
if _, err := Client.ListIncomingWebhooks(); err == nil {
t.Fatal("should have errored - not system/team admin")
}
*utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = false
if _, err := Client.ListIncomingWebhooks(); err != nil {
t.Fatal(err)
}
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = false
if _, err := Client.ListIncomingWebhooks(); err == nil {
t.Fatal("should have errored - webhooks turned off")
}
}
func TestDeleteIncomingHook(t *testing.T) {
Setup()
th := Setup().InitSystemAdmin()
Client := th.SystemAdminClient
team := th.SystemAdminTeam
channel1 := th.CreateChannel(Client, team)
user2 := th.CreateUser(Client)
LinkUserToTeam(user2, team)
enableIncomingHooks := utils.Cfg.ServiceSettings.EnableIncomingWebhooks
enableOutgoingHooks := utils.Cfg.ServiceSettings.EnableOutgoingWebhooks
enableAdminOnlyHooks := utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations
defer func() {
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = enableIncomingHooks
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = enableOutgoingHooks
utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = enableAdminOnlyHooks
}()
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = true
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = true
*utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
hook := &model.IncomingWebhook{ChannelId: channel1.Id}
hook = Client.Must(Client.CreateIncomingWebhook(hook)).Data.(*model.IncomingWebhook)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
if _, err := Client.DeleteIncomingWebhook(hook.Id); err != nil {
t.Fatal(err)
}
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
if _, err := Client.DeleteIncomingWebhook("junk"); err == nil {
t.Fatal("should have failed - bad id")
}
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
if _, err := Client.DeleteIncomingWebhook(""); err == nil {
t.Fatal("should have failed - empty id")
}
if utils.Cfg.ServiceSettings.EnableIncomingWebhooks {
hook := &model.IncomingWebhook{ChannelId: channel1.Id}
hook = Client.Must(Client.CreateIncomingWebhook(hook)).Data.(*model.IncomingWebhook)
hooks := Client.Must(Client.ListIncomingWebhooks()).Data.([]*model.IncomingWebhook)
if len(hooks) != 0 {
t.Fatal("delete didn't work properly")
}
data := make(map[string]string)
data["id"] = hook.Id
hook = &model.IncomingWebhook{ChannelId: channel1.Id}
hook = Client.Must(Client.CreateIncomingWebhook(hook)).Data.(*model.IncomingWebhook)
if _, err := Client.DeleteIncomingWebhook(data); err != nil {
t.Fatal(err)
}
Client.Logout()
Client.Must(Client.LoginById(user2.Id, user2.Password))
Client.SetTeamId(team.Id)
hooks := Client.Must(Client.ListIncomingWebhooks()).Data.([]*model.IncomingWebhook)
if len(hooks) != 0 {
t.Fatal("delete didn't work properly")
}
} else {
data := make(map[string]string)
data["id"] = "123"
if _, err := Client.DeleteIncomingWebhook(hook.Id); err == nil {
t.Fatal("should have failed - not system/team admin")
}
if _, err := Client.DeleteIncomingWebhook(data); err == nil {
t.Fatal("should have errored - webhooks turned off")
}
*utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = false
if _, err := Client.DeleteIncomingWebhook(hook.Id); err == nil {
t.Fatal("should have failed - not creator or team admin")
}
hook = &model.IncomingWebhook{ChannelId: channel1.Id}
hook = Client.Must(Client.CreateIncomingWebhook(hook)).Data.(*model.IncomingWebhook)
if _, err := Client.DeleteIncomingWebhook(hook.Id); err != nil {
t.Fatal(err)
}
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = false
if _, err := Client.DeleteIncomingWebhook(hook.Id); err == nil {
t.Fatal("should have errored - webhooks turned off")
}
}
func TestCreateOutgoingHook(t *testing.T) {
Setup()
enableIncomingHooks := utils.Cfg.ServiceSettings.EnableIncomingWebhooks
th := Setup().InitSystemAdmin()
Client := th.SystemAdminClient
user := th.SystemAdminUser
team := th.SystemAdminTeam
team2 := th.CreateTeam(Client)
channel1 := th.CreateChannel(Client, team)
channel2 := th.CreatePrivateChannel(Client, team)
user2 := th.CreateUser(Client)
LinkUserToTeam(user2, team)
user3 := th.CreateUser(Client)
LinkUserToTeam(user3, team2)
enableOutgoingHooks := utils.Cfg.ServiceSettings.EnableOutgoingWebhooks
enableAdminOnlyHooks := utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations
defer func() {
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = enableIncomingHooks
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = enableOutgoingHooks
utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = enableAdminOnlyHooks
}()
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = true
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
channel2 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel2 = Client.Must(Client.CreateChannel(channel2)).Data.(*model.Channel)
*utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = true
hook := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
if utils.Cfg.ServiceSettings.EnableOutgoingWebhooks {
var rhook *model.OutgoingWebhook
if result, err := Client.CreateOutgoingWebhook(hook); err != nil {
t.Fatal(err)
} else {
rhook = result.Data.(*model.OutgoingWebhook)
}
if hook.ChannelId != rhook.ChannelId {
t.Fatal("channel ids didn't match")
}
if rhook.CreatorId != user.Id {
t.Fatal("user ids didn't match")
}
if rhook.TeamId != team.Id {
t.Fatal("team ids didn't match")
}
hook = &model.OutgoingWebhook{ChannelId: "junk", CallbackURLs: []string{"http://nowhere.com"}}
if _, err := Client.CreateOutgoingWebhook(hook); err == nil {
t.Fatal("should have failed - bad channel id")
}
hook = &model.OutgoingWebhook{ChannelId: channel2.Id, CreatorId: "123", TeamId: "456", CallbackURLs: []string{"http://nowhere.com"}}
if result, err := Client.CreateOutgoingWebhook(hook); err != nil {
t.Fatal(err)
} else {
if result.Data.(*model.OutgoingWebhook).CreatorId != user.Id {
t.Fatal("bad user id wasn't overwritten")
}
if result.Data.(*model.OutgoingWebhook).TeamId != team.Id {
t.Fatal("bad team id wasn't overwritten")
}
}
var rhook *model.OutgoingWebhook
if result, err := Client.CreateOutgoingWebhook(hook); err != nil {
t.Fatal(err)
} else {
if _, err := Client.CreateOutgoingWebhook(hook); err == nil {
t.Fatal("should have errored - webhooks turned off")
rhook = result.Data.(*model.OutgoingWebhook)
}
if hook.ChannelId != rhook.ChannelId {
t.Fatal("channel ids didn't match")
}
if rhook.CreatorId != user.Id {
t.Fatal("user ids didn't match")
}
if rhook.TeamId != team.Id {
t.Fatal("team ids didn't match")
}
hook = &model.OutgoingWebhook{ChannelId: "junk", CallbackURLs: []string{"http://nowhere.com"}}
if _, err := Client.CreateOutgoingWebhook(hook); err == nil {
t.Fatal("should have failed - bad channel id")
}
hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CreatorId: "123", TeamId: "456", CallbackURLs: []string{"http://nowhere.com"}}
if result, err := Client.CreateOutgoingWebhook(hook); err != nil {
t.Fatal(err)
} else {
if result.Data.(*model.OutgoingWebhook).CreatorId != user.Id {
t.Fatal("bad user id wasn't overwritten")
}
if result.Data.(*model.OutgoingWebhook).TeamId != team.Id {
t.Fatal("bad team id wasn't overwritten")
}
}
hook = &model.OutgoingWebhook{ChannelId: channel2.Id, CallbackURLs: []string{"http://nowhere.com"}}
if _, err := Client.CreateOutgoingWebhook(hook); err == nil {
t.Fatal("should have failed - private channel")
}
hook = &model.OutgoingWebhook{CallbackURLs: []string{"http://nowhere.com"}}
if _, err := Client.CreateOutgoingWebhook(hook); err == nil {
t.Fatal("should have failed - blank channel and trigger words")
}
Client.Logout()
Client.Must(Client.LoginById(user2.Id, user2.Password))
Client.SetTeamId(team.Id)
hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
if _, err := Client.CreateOutgoingWebhook(hook); err == nil {
t.Fatal("should have failed - not system/team admin")
}
*utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = false
if _, err := Client.CreateOutgoingWebhook(hook); err != nil {
t.Fatal(err)
}
Client.Logout()
Client.Must(Client.LoginById(user3.Id, user3.Password))
Client.SetTeamId(team2.Id)
if _, err := Client.CreateOutgoingWebhook(hook); err == nil {
t.Fatal("should have failed - wrong team")
}
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = false
if _, err := Client.CreateOutgoingWebhook(hook); err == nil {
t.Fatal("should have errored - webhooks turned off")
}
}
func TestListOutgoingHooks(t *testing.T) {
Setup()
enableIncomingHooks := utils.Cfg.ServiceSettings.EnableIncomingWebhooks
th := Setup().InitSystemAdmin()
Client := th.SystemAdminClient
team := th.SystemAdminTeam
channel1 := th.CreateChannel(Client, team)
user2 := th.CreateUser(Client)
LinkUserToTeam(user2, team)
enableOutgoingHooks := utils.Cfg.ServiceSettings.EnableOutgoingWebhooks
enableAdminOnlyHooks := utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations
defer func() {
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = enableIncomingHooks
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = enableOutgoingHooks
utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = enableAdminOnlyHooks
}()
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = true
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = true
*utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
hook1 := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
hook1 = Client.Must(Client.CreateOutgoingWebhook(hook1)).Data.(*model.OutgoingWebhook)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
hook2 := &model.OutgoingWebhook{TriggerWords: []string{"trigger"}, CallbackURLs: []string{"http://nowhere.com"}}
hook2 = Client.Must(Client.CreateOutgoingWebhook(hook2)).Data.(*model.OutgoingWebhook)
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
if utils.Cfg.ServiceSettings.EnableOutgoingWebhooks {
hook1 := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
hook1 = Client.Must(Client.CreateOutgoingWebhook(hook1)).Data.(*model.OutgoingWebhook)
hook2 := &model.OutgoingWebhook{TriggerWords: []string{"trigger"}, CallbackURLs: []string{"http://nowhere.com"}}
hook2 = Client.Must(Client.CreateOutgoingWebhook(hook2)).Data.(*model.OutgoingWebhook)
if result, err := Client.ListOutgoingWebhooks(); err != nil {
t.Fatal(err)
} else {
hooks := result.Data.([]*model.OutgoingWebhook)
if len(hooks) != 2 {
t.Fatal("incorrect number of hooks")
}
}
if result, err := Client.ListOutgoingWebhooks(); err != nil {
t.Fatal(err)
} else {
if _, err := Client.ListOutgoingWebhooks(); err == nil {
t.Fatal("should have errored - webhooks turned off")
hooks := result.Data.([]*model.OutgoingWebhook)
if len(hooks) != 2 {
t.Fatal("incorrect number of hooks")
}
}
Client.Logout()
Client.Must(Client.LoginById(user2.Id, user2.Password))
Client.SetTeamId(team.Id)
if _, err := Client.ListOutgoingWebhooks(); err == nil {
t.Fatal("should have failed - not system/team admin")
}
*utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = false
if _, err := Client.ListOutgoingWebhooks(); err != nil {
t.Fatal(err)
}
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = false
if _, err := Client.ListOutgoingWebhooks(); err == nil {
t.Fatal("should have errored - webhooks turned off")
}
}
func TestDeleteOutgoingHook(t *testing.T) {
Setup()
enableIncomingHooks := utils.Cfg.ServiceSettings.EnableIncomingWebhooks
th := Setup().InitSystemAdmin()
Client := th.SystemAdminClient
team := th.SystemAdminTeam
channel1 := th.CreateChannel(Client, team)
user2 := th.CreateUser(Client)
LinkUserToTeam(user2, team)
enableOutgoingHooks := utils.Cfg.ServiceSettings.EnableOutgoingWebhooks
enableAdminOnlyHooks := utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations
defer func() {
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = enableIncomingHooks
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = enableOutgoingHooks
utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = enableAdminOnlyHooks
}()
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = true
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = true
*utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
hook := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
if _, err := Client.DeleteOutgoingWebhook("junk"); err == nil {
t.Fatal("should have failed - bad hook id")
}
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
if _, err := Client.DeleteOutgoingWebhook(""); err == nil {
t.Fatal("should have failed - empty hook id")
}
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
if _, err := Client.DeleteOutgoingWebhook(hook.Id); err != nil {
t.Fatal(err)
}
if utils.Cfg.ServiceSettings.EnableOutgoingWebhooks {
hook := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook)
hooks := Client.Must(Client.ListOutgoingWebhooks()).Data.([]*model.OutgoingWebhook)
if len(hooks) != 0 {
t.Fatal("delete didn't work properly")
}
data := make(map[string]string)
data["id"] = hook.Id
hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook)
if _, err := Client.DeleteOutgoingWebhook(data); err != nil {
t.Fatal(err)
}
Client.Logout()
Client.Must(Client.LoginById(user2.Id, user2.Password))
Client.SetTeamId(team.Id)
hooks := Client.Must(Client.ListOutgoingWebhooks()).Data.([]*model.OutgoingWebhook)
if len(hooks) != 0 {
t.Fatal("delete didn't work properly")
}
} else {
data := make(map[string]string)
data["id"] = "123"
if _, err := Client.DeleteOutgoingWebhook(hook.Id); err == nil {
t.Fatal("should have failed - not system/team admin")
}
if _, err := Client.DeleteOutgoingWebhook(data); err == nil {
t.Fatal("should have errored - webhooks turned off")
}
*utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = false
if _, err := Client.DeleteOutgoingWebhook(hook.Id); err == nil {
t.Fatal("should have failed - not creator or team admin")
}
hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook)
if _, err := Client.DeleteOutgoingWebhook(hook.Id); err != nil {
t.Fatal(err)
}
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = false
if _, err := Client.DeleteOutgoingWebhook(hook.Id); err == nil {
t.Fatal("should have errored - webhooks turned off")
}
}
func TestRegenOutgoingHookToken(t *testing.T) {
Setup()
enableIncomingHooks := utils.Cfg.ServiceSettings.EnableIncomingWebhooks
th := Setup().InitSystemAdmin()
Client := th.SystemAdminClient
team := th.SystemAdminTeam
team2 := th.CreateTeam(Client)
channel1 := th.CreateChannel(Client, team)
user2 := th.CreateUser(Client)
LinkUserToTeam(user2, team)
user3 := th.CreateUser(Client)
LinkUserToTeam(user3, team2)
enableOutgoingHooks := utils.Cfg.ServiceSettings.EnableOutgoingWebhooks
enableAdminOnlyHooks := utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations
defer func() {
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = enableOutgoingHooks
utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = enableAdminOnlyHooks
}()
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = true
*utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = true
hook := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook)
if _, err := Client.RegenOutgoingWebhookToken("junk"); err == nil {
t.Fatal("should have failed - bad id")
}
if _, err := Client.RegenOutgoingWebhookToken(""); err == nil {
t.Fatal("should have failed - empty id")
}
if result, err := Client.RegenOutgoingWebhookToken(hook.Id); err != nil {
t.Fatal(err)
} else {
if result.Data.(*model.OutgoingWebhook).Token == hook.Token {
t.Fatal("regen didn't work properly")
}
}
Client.Logout()
Client.Must(Client.LoginById(user2.Id, user2.Password))
Client.SetTeamId(team.Id)
if _, err := Client.RegenOutgoingWebhookToken(hook.Id); err == nil {
t.Fatal("should have failed - not system/team admin")
}
*utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = false
hook = &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook)
if _, err := Client.RegenOutgoingWebhookToken(hook.Id); err != nil {
t.Fatal(err)
}
Client.Logout()
Client.Must(Client.LoginById(user3.Id, user3.Password))
Client.SetTeamId(team2.Id)
if _, err := Client.RegenOutgoingWebhookToken(hook.Id); err == nil {
t.Fatal("should have failed - wrong team")
}
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = false
if _, err := Client.RegenOutgoingWebhookToken(hook.Id); err == nil {
t.Fatal("should have errored - webhooks turned off")
}
}
func TestIncomingWebhooks(t *testing.T) {
th := Setup().InitSystemAdmin()
Client := th.SystemAdminClient
team := th.SystemAdminTeam
channel1 := th.CreateChannel(Client, team)
user2 := th.CreateUser(Client)
LinkUserToTeam(user2, team)
enableIncomingHooks := utils.Cfg.ServiceSettings.EnableIncomingWebhooks
defer func() {
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = enableIncomingHooks
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = enableOutgoingHooks
}()
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = true
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = true
team := &model.Team{DisplayName: "Name", Name: "z-z-" + model.NewId() + "a", Email: "test@nowhere.com", Type: model.TEAM_OPEN}
team = Client.Must(Client.CreateTeam(team)).Data.(*model.Team)
hook := &model.IncomingWebhook{ChannelId: channel1.Id}
hook = Client.Must(Client.CreateIncomingWebhook(hook)).Data.(*model.IncomingWebhook)
user := &model.User{TeamId: team.Id, Email: model.NewId() + "success+test@simulator.amazonses.com", Nickname: "Corey Hulen", Password: "pwd"}
user = Client.Must(Client.CreateUser(user, "")).Data.(*model.User)
store.Must(Srv.Store.User().VerifyEmail(user.Id))
url := "/hooks/" + hook.Id
c := &Context{}
c.RequestId = model.NewId()
c.IpAddress = "cmd_line"
UpdateRoles(c, user, model.ROLE_SYSTEM_ADMIN)
Client.LoginByEmail(team.Name, user.Email, "pwd")
if _, err := Client.DoPost(url, "{\"text\":\"this is a test\"}", "application/json"); err != nil {
t.Fatal(err)
}
channel1 := &model.Channel{DisplayName: "Test API Name", Name: "a" + model.NewId() + "a", Type: model.CHANNEL_OPEN, TeamId: team.Id}
channel1 = Client.Must(Client.CreateChannel(channel1)).Data.(*model.Channel)
if _, err := Client.DoPost(url, fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"%s\"}", channel1.Name), "application/json"); err != nil {
t.Fatal(err)
}
if utils.Cfg.ServiceSettings.EnableOutgoingWebhooks {
hook := &model.OutgoingWebhook{ChannelId: channel1.Id, CallbackURLs: []string{"http://nowhere.com"}}
hook = Client.Must(Client.CreateOutgoingWebhook(hook)).Data.(*model.OutgoingWebhook)
if _, err := Client.DoPost(url, fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"#%s\"}", channel1.Name), "application/json"); err != nil {
t.Fatal(err)
}
data := make(map[string]string)
data["id"] = hook.Id
Client.Must(Client.CreateDirectChannel(user2.Id))
if result, err := Client.RegenOutgoingWebhookToken(data); err != nil {
t.Fatal(err)
} else {
if result.Data.(*model.OutgoingWebhook).Token == hook.Token {
t.Fatal("regen didn't work properly")
}
}
if _, err := Client.DoPost(url, fmt.Sprintf("{\"text\":\"this is a test\", \"channel\":\"@%s\"}", user2.Username), "application/json"); err != nil {
t.Fatal(err)
}
} else {
data := make(map[string]string)
data["id"] = "123"
if _, err := Client.DoPost(url, "payload={\"text\":\"this is a test\"}", "application/x-www-form-urlencoded"); err != nil {
t.Fatal(err)
}
if _, err := Client.RegenOutgoingWebhookToken(data); err == nil {
t.Fatal("should have errored - webhooks turned off")
}
attachmentPayload := `{
"text": "this is a test",
"attachments": [
{
"fallback": "Required plain-text summary of the attachment.",
"color": "#36a64f",
"pretext": "Optional text that appears above the attachment block",
"author_name": "Bobby Tables",
"author_link": "http://flickr.com/bobby/",
"author_icon": "http://flickr.com/icons/bobby.jpg",
"title": "Slack API Documentation",
"title_link": "https://api.slack.com/",
"text": "Optional text that appears within the attachment",
"fields": [
{
"title": "Priority",
"value": "High",
"short": false
}
],
"image_url": "http://my-website.com/path/to/image.jpg",
"thumb_url": "http://example.com/path/to/thumb.png"
}
]
}`
if _, err := Client.DoPost(url, attachmentPayload, "application/json"); err != nil {
t.Fatal(err)
}
if _, err := Client.DoPost(url, "{\"text\":\"\"}", "application/json"); err == nil {
t.Fatal("should have failed - no text")
}
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = false
if _, err := Client.DoPost(url, "{\"text\":\"this is a test\"}", "application/json"); err == nil {
t.Fatal("should have failed - webhooks turned off")
}
}

View file

@ -30,9 +30,9 @@
"MaxUsersPerTeam": 50,
"EnableTeamCreation": true,
"EnableUserCreation": true,
"EnableOpenServer": false,
"RestrictCreationToDomains": "",
"RestrictTeamNames": true,
"EnableTeamListing": false,
"EnableCustomBrand": false,
"CustomBrandText": ""
},
@ -143,6 +143,7 @@
"LastNameAttribute": "",
"EmailAttribute": "",
"UsernameAttribute": "",
"NicknameAttribute": "",
"IdAttribute": "",
"SkipCertificateVerification": false,
"QueryTimeout": 60,
@ -154,4 +155,4 @@
"Directory": "./data/",
"EnableDaily": false
}
}
}

View file

@ -8,10 +8,10 @@ import (
)
type LdapInterface interface {
DoLogin(team *model.Team, id string, password string) (*model.User, *model.AppError)
DoLogin(id string, password string) (*model.User, *model.AppError)
GetUser(id string) (*model.User, *model.AppError)
CheckPassword(id string, password string) *model.AppError
SwitchToEmail(userId, ldapId, ldapPassword string) *model.AppError
SwitchToLdap(userId, ldapId, ldapPassword string) *model.AppError
ValidateFilter(filter string) *model.AppError
}

View file

@ -8,7 +8,7 @@ import (
)
type MfaInterface interface {
GenerateQrCode(team *model.Team, user *model.User) ([]byte, *model.AppError)
GenerateQrCode(user *model.User) ([]byte, *model.AppError)
Activate(user *model.User, token string) *model.AppError
Deactivate(userId string) *model.AppError
ValidateToken(secret, token string) (bool, *model.AppError)

View file

@ -1313,11 +1313,11 @@
},
{
"id": "api.templates.singin_change_email.body.info",
"translation": "You updated your sign-in method for {{.TeamDisplayName}} on {{ .TeamURL }} to {{.Method}}.<br>If this change wasn't initiated by you, please contact your system administrator."
"translation": "You updated your sign-in method for on {{ .SiteName }} to {{.Method}}.<br>If this change wasn't initiated by you, please contact your system administrator."
},
{
"id": "api.templates.singin_change_email.subject",
"translation": "You updated your sign-in method for {{.TeamDisplayName}} on {{ .SiteName }}"
"translation": "You updated your sign-in method on {{ .SiteName }}"
},
{
"id": "api.templates.verify_body.button",
@ -1425,11 +1425,11 @@
},
{
"id": "api.user.create_oauth_user.already_attached.app_error",
"translation": "Team {{.DisplayName}} already has a user with the email address attached to your {{.Service}} account"
"translation": "An existing user is already attached to your {{.Service}} account"
},
{
"id": "api.user.create_oauth_user.already_used.app_error",
"translation": "This {{.Service}} account has already been used to sign up for team {{.DisplayName}}"
"translation": "This {{.Service}} account has already been used to sign up"
},
{
"id": "api.user.create_oauth_user.create.app_error",
@ -1451,6 +1451,10 @@
"id": "api.user.create_profile_image.initial.app_error",
"translation": "Could not add user initial to default profile picture"
},
{
"id": "api.user.create_user.no_open_server",
"translation": "This server does not allow open signups. Please speak with your Administrator to receive an invitation."
},
{
"id": "api.user.create_user.accepted_domain.app_error",
"translation": "The email you provided does not belong to an accepted domain. Please contact your administrator or sign up with a different email."
@ -1759,6 +1763,14 @@
"id": "api.webhook.create_incoming.disabled.app_errror",
"translation": "Incoming webhooks have been disabled by the system admin."
},
{
"id": "api.webhook.create_outgoing.not_open.app_error",
"translation": "Outgoing webhooks can only be created for public channels."
},
{
"id": "api.webhook.create_outgoing.permissions.app_error",
"translation": "Inappropriate permissions to create outcoming webhook."
},
{
"id": "api.webhook.create_outgoing.disabled.app_error",
"translation": "Outgoing webhooks have been disabled by the system admin."
@ -2111,6 +2123,18 @@
"id": "model.channel.is_valid.type.app_error",
"translation": "Invalid type"
},
{
"id": "model.team_member.is_valid.team_id.app_error",
"translation": "Invalid team id"
},
{
"id": "model.team_member.is_valid.user_id.app_error",
"translation": "Invalid user id"
},
{
"id": "model.team_member.is_valid.role.app_error",
"translation": "Invalid role"
},
{
"id": "model.channel.is_valid.update_at.app_error",
"translation": "Update at must be a valid time"
@ -2943,6 +2967,22 @@
"id": "store.sql_channel.update_member.app_error",
"translation": "We encountered an error updating the channel member"
},
{
"id": "store.sql_team.save_member.exists.app_error",
"translation": "A team member with that id already exists"
},
{
"id": "store.sql_team.save_member.save.app_error",
"translation": "We couldn't save the team member"
},
{
"id": "store.sql_team.get_members.app_error",
"translation": "We couldn't get the team members"
},
{
"id": "store.sql_team.remove_member.app_error",
"translation": "We couldn't remove the team member"
},
{
"id": "store.sql_command.analytics_command_count.app_error",
"translation": "We couldn't count the commands"
@ -3237,7 +3277,7 @@
},
{
"id": "store.sql_session.remove_all_sessions_for_team.app_error",
"translation": "We couldn't remove all the sessions for the team"
"translation": "We couldn't remove all the sessions"
},
{
"id": "store.sql_session.save.app_error",

View file

@ -1311,14 +1311,6 @@
"id": "api.templates.signup_team_subject",
"translation": "Configuración del equipo en {{ .SiteName }}"
},
{
"id": "api.templates.singin_change_email.body.info",
"translation": "Haz actualizado el método con el que inicias sesión en {{.TeamURL}} para el equipo {{.TeamDisplayName}} por {{.Method}}.<br>Si este cambio no fue realizado por ti, por favor contacta a un administrador del sistema."
},
{
"id": "api.templates.singin_change_email.subject",
"translation": "Cambio del método de inicio de sesión para {{.TeamDisplayName}} en {{ .SiteName }}"
},
{
"id": "api.templates.verify_body.button",
"translation": "Confirmar Correo"
@ -1423,14 +1415,6 @@
"id": "api.user.complete_switch_with_oauth.unavailable.app_error",
"translation": "OAuth para {{.Service}} no está disponible en este servidor"
},
{
"id": "api.user.create_oauth_user.already_attached.app_error",
"translation": "El Equipo {{.DisplayName}} ya tiene un usuario con esta dirección de correo asociada a tu cuenta de {{.Service}}"
},
{
"id": "api.user.create_oauth_user.already_used.app_error",
"translation": "Esta cuenta de {{.Service}} ya fue utilizada para registrarse en el equipo {{.DisplayName}}"
},
{
"id": "api.user.create_oauth_user.create.app_error",
"translation": "No se pudo crear el usuario basandose en el objeto de {{.Service}}"
@ -3235,10 +3219,6 @@
"id": "store.sql_session.remove.app_error",
"translation": "No pudimos remover la sesión"
},
{
"id": "store.sql_session.remove_all_sessions_for_team.app_error",
"translation": "No pudimos remover todas las sesiones para el equipo"
},
{
"id": "store.sql_session.save.app_error",
"translation": "No pudimos guardar la sesión"

View file

@ -1235,14 +1235,6 @@
"id": "api.templates.signup_team_subject",
"translation": "Paramétrage Équipe {{ .SiteName }}"
},
{
"id": "api.templates.singin_change_email.body.info",
"translation": "Vous avez mis à jour la méthode de connexion de {{.TeamDisplayName}} sur {{.TeamURL}} pour {{.Method}}.<br>Si cette modification n'a pas été effectuée par vous, veuillez prendre contact avec votre administrateur système."
},
{
"id": "api.templates.singin_change_email.subject",
"translation": "Vous avez mis à jour la méthode de connexion de {{.TeamDisplayName}} sur {{ .SiteName }}"
},
{
"id": "api.templates.verify_body.button",
"translation": "Vérifier l'adresse électronique"
@ -1339,14 +1331,6 @@
"id": "api.user.complete_switch_with_oauth.unavailable.app_error",
"translation": "{{.Service}} oauth non disponible sur ce serveur"
},
{
"id": "api.user.create_oauth_user.already_attached.app_error",
"translation": "L'équipe {{.DisplayName}} dispose déjà d'un utilisateur ayant la même adresse électronique que celle attachée à votre compte {{.Service}}"
},
{
"id": "api.user.create_oauth_user.already_used.app_error",
"translation": "Ce compte {{.Service}} a déjà été utilisé pour pour se connecter à l'équipe {{.DisplayName}}"
},
{
"id": "api.user.create_oauth_user.create.app_error",
"translation": "Impossible de créer un utilisateur à partir du user object {{.Service}}"

View file

@ -1311,14 +1311,6 @@
"id": "api.templates.signup_team_subject",
"translation": "{{ .SiteName }} Configuração da Equipe"
},
{
"id": "api.templates.singin_change_email.body.info",
"translation": "Você atualizou seu método de login para {{.TeamDisplayName}} no {{ .TeamURL }} para {{.Method}}.<br>Se esta mudança não foi iniciada por você, por favor entre em contato com o administrador do sistema."
},
{
"id": "api.templates.singin_change_email.subject",
"translation": "Você atualizou seu método de login para {{.TeamDisplayName}} em {{ .SiteName }}"
},
{
"id": "api.templates.verify_body.button",
"translation": "Verificar Email"
@ -1423,14 +1415,6 @@
"id": "api.user.complete_switch_with_oauth.unavailable.app_error",
"translation": "{{.Service}} oauth não disponível neste servidor"
},
{
"id": "api.user.create_oauth_user.already_attached.app_error",
"translation": "Equipe {{.DisplayName}} já tem um usuário com o endereço de email anexado a sua conta {{.Service}}"
},
{
"id": "api.user.create_oauth_user.already_used.app_error",
"translation": "Está conta {{.Service}} já foi utilizada para se inscrever na equipe {{.DisplayName}}"
},
{
"id": "api.user.create_oauth_user.create.app_error",
"translation": "Não foi possível criar o usuário fora do {{.Service}} do objeto de usuário"
@ -3235,10 +3219,6 @@
"id": "store.sql_session.remove.app_error",
"translation": "Não foi possível remover a sessão"
},
{
"id": "store.sql_session.remove_all_sessions_for_team.app_error",
"translation": "Não foi possível remover todas as sessões para a equipe"
},
{
"id": "store.sql_session.save.app_error",
"translation": "Não foi possível salvar a sessão"

View file

@ -66,7 +66,7 @@ func manualTest(c *api.Context, w http.ResponseWriter, r *http.Request) {
team := &model.Team{
DisplayName: teamDisplayName[0],
Name: utils.RandomName(utils.Range{20, 20}, utils.LOWERCASE),
Email: utils.RandomEmail(utils.Range{20, 20}, utils.LOWERCASE),
Email: "success+" + model.NewId() + "simulator.amazonses.com",
Type: model.TEAM_OPEN,
}
@ -88,8 +88,7 @@ func manualTest(c *api.Context, w http.ResponseWriter, r *http.Request) {
// Create user for testing
user := &model.User{
TeamId: teamID,
Email: utils.RandomEmail(utils.Range{20, 20}, utils.LOWERCASE),
Email: "success+" + model.NewId() + "simulator.amazonses.com",
Nickname: username[0],
Password: api.USER_PASSWORD}
@ -98,7 +97,10 @@ func manualTest(c *api.Context, w http.ResponseWriter, r *http.Request) {
c.Err = err
return
}
api.Srv.Store.User().VerifyEmail(result.Data.(*model.User).Id)
<-api.Srv.Store.User().VerifyEmail(result.Data.(*model.User).Id)
<-api.Srv.Store.Team().SaveMember(&model.TeamMember{TeamId: teamID, UserId: result.Data.(*model.User).Id})
newuser := result.Data.(*model.User)
userID = newuser.Id

View file

@ -22,6 +22,7 @@ import (
"github.com/mattermost/platform/einterfaces"
"github.com/mattermost/platform/manualtesting"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/mattermost/platform/utils"
"github.com/mattermost/platform/web"
@ -36,13 +37,18 @@ import (
//ENTERPRISE_IMPORTS
var flagCmdUpdateDb30 bool
var flagCmdCreateTeam bool
var flagCmdCreateUser bool
var flagCmdAssignRole bool
var flagCmdVersion bool
var flagCmdResetPassword bool
var flagCmdResetMfa bool
var flagCmdPermanentDeleteUser bool
var flagCmdPermanentDeleteTeam bool
var flagCmdPermanentDeleteAllUsers bool
var flagCmdResetDatabase bool
var flagUsername string
var flagCmdUploadLicense bool
var flagConfigFile string
var flagLicenseFile string
@ -69,6 +75,10 @@ func main() {
l4g.Info(utils.T("mattermost.working_dir"), pwd)
l4g.Info(utils.T("mattermost.config_file"), utils.FindConfigFile(flagConfigFile))
// Speical case for upgrading the db to 3.0
// ADDED for 3.0 REMOVE for 3.4
cmdUpdateDb30()
api.NewServer()
api.InitApi()
web.InitWeb()
@ -223,19 +233,24 @@ func parseCmds() {
}
flag.StringVar(&flagConfigFile, "config", "config.json", "")
flag.StringVar(&flagUsername, "username", "", "")
flag.StringVar(&flagLicenseFile, "license", "", "")
flag.StringVar(&flagEmail, "email", "", "")
flag.StringVar(&flagPassword, "password", "", "")
flag.StringVar(&flagTeamName, "team_name", "", "")
flag.StringVar(&flagRole, "role", "", "")
flag.BoolVar(&flagCmdUpdateDb30, "upgrade_db_30", false, "")
flag.BoolVar(&flagCmdCreateTeam, "create_team", false, "")
flag.BoolVar(&flagCmdCreateUser, "create_user", false, "")
flag.BoolVar(&flagCmdAssignRole, "assign_role", false, "")
flag.BoolVar(&flagCmdVersion, "version", false, "")
flag.BoolVar(&flagCmdResetPassword, "reset_password", false, "")
flag.BoolVar(&flagCmdResetMfa, "reset_mfa", false, "")
flag.BoolVar(&flagCmdPermanentDeleteUser, "permanent_delete_user", false, "")
flag.BoolVar(&flagCmdPermanentDeleteTeam, "permanent_delete_team", false, "")
flag.BoolVar(&flagCmdPermanentDeleteAllUsers, "permanent_delete_all_users", false, "")
flag.BoolVar(&flagCmdResetDatabase, "reset_database", false, "")
flag.BoolVar(&flagCmdUploadLicense, "upload_license", false, "")
flag.Parse()
@ -244,9 +259,12 @@ func parseCmds() {
flagCmdCreateUser ||
flagCmdAssignRole ||
flagCmdResetPassword ||
flagCmdResetMfa ||
flagCmdVersion ||
flagCmdPermanentDeleteUser ||
flagCmdPermanentDeleteTeam ||
flagCmdPermanentDeleteAllUsers ||
flagCmdResetDatabase ||
flagCmdUploadLicense)
}
@ -256,11 +274,258 @@ func runCmds() {
cmdCreateUser()
cmdAssignRole()
cmdResetPassword()
cmdResetMfa()
cmdPermDeleteUser()
cmdPermDeleteTeam()
cmdPermDeleteAllUsers()
cmdResetDatabase()
cmdUploadLicense()
}
type TeamForUpgrade struct {
Id string
Name string
}
// ADDED for 3.0 REMOVE for 3.4
func cmdUpdateDb30() {
if flagCmdUpdateDb30 {
api.Srv = &api.Server{}
api.Srv.Store = store.NewSqlStoreForUpgrade30()
store := api.Srv.Store.(*store.SqlStore)
l4g.Info("Attempting to run speical upgrade of the database schema to version 3.0 for user model changes")
time.Sleep(time.Second)
if !store.DoesColumnExist("Users", "TeamId") {
fmt.Println("**WARNING** the database schema appears to be upgraded to 3.0")
flushLogAndExit(1)
}
if !(store.SchemaVersion == "2.2.0" ||
store.SchemaVersion == "2.1.0" ||
store.SchemaVersion == "2.0.0") {
fmt.Println("**WARNING** the database schema needs to be version 2.2.0, 2.1.0 or 2.0.0 to upgrade")
flushLogAndExit(1)
}
var confirmBackup string
fmt.Println("\nPlease see http://www.mattermost.org/upgrade-to-3-0/")
fmt.Println("**WARNING** This upgrade process will be irreversible.")
fmt.Print("Have you performed a database backup? (YES/NO): ")
fmt.Scanln(&confirmBackup)
if confirmBackup != "YES" {
fmt.Fprintln(os.Stderr, "ABORTED: You did not answer YES exactly, in all capitals.")
flushLogAndExit(1)
}
var flagTeamName string
var teams []*TeamForUpgrade
if _, err := store.GetMaster().Select(&teams, "SELECT Id, Name FROM Teams"); err != nil {
l4g.Error("Failed to load all teams details=%v", err)
flushLogAndExit(1)
}
fmt.Println(fmt.Sprintf("We found %v teams.", len(teams)))
for _, team := range teams {
fmt.Println(team.Name)
}
fmt.Print("Please pick a primary team from the list above: ")
fmt.Scanln(&flagTeamName)
var team *TeamForUpgrade
for _, t := range teams {
if t.Name == flagTeamName {
team = t
break
}
}
if team == nil {
l4g.Error("Failed to find primary team details")
flushLogAndExit(1)
}
l4g.Info("Starting speical 3.0 database upgrade with performed_backup=YES team_name=%v", team.Name)
l4g.Info("Primary team %v will be left unchanged", team.Name)
l4g.Info("Upgrading primary team %v", team.Name)
uniqueEmails := make(map[string]bool)
uniqueUsernames := make(map[string]bool)
primaryUsers := convertTeamTo30(team, uniqueEmails, uniqueUsernames)
l4g.Info("Upgraded %v users", len(primaryUsers))
for _, otherTeam := range teams {
if otherTeam.Id != team.Id {
l4g.Info("Upgrading team %v", otherTeam.Name)
users := convertTeamTo30(otherTeam, uniqueEmails, uniqueUsernames)
l4g.Info("Upgraded %v users", len(users))
}
}
l4g.Info("Altering other scheme changes needed 3.0 for user model changes")
if _, err := store.GetMaster().Exec(`
UPDATE Channels
SET
TeamId = ''
WHERE
Type = 'D'
`,
); err != nil {
l4g.Error("Failed to update direct channel types details=%v", err)
flushLogAndExit(1)
}
extraLength := store.GetMaxLengthOfColumnIfExists("Audits", "ExtraInfo")
if len(extraLength) > 0 && extraLength != "1024" {
store.AlterColumnTypeIfExists("Audits", "ExtraInfo", "VARCHAR(1024)", "VARCHAR(1024)")
}
actionLength := store.GetMaxLengthOfColumnIfExists("Audits", "Action")
if len(actionLength) > 0 && actionLength != "512" {
store.AlterColumnTypeIfExists("Audits", "Action", "VARCHAR(512)", "VARCHAR(512)")
}
if store.DoesColumnExist("Sessions", "TeamId") {
store.RemoveColumnIfExists("Sessions", "TeamId")
store.GetMaster().Exec(`TRUNCATE Sessions`)
}
// ADDED for 2.2 REMOVE for 2.6
store.CreateColumnIfNotExists("Users", "MfaActive", "tinyint(1)", "boolean", "0")
store.CreateColumnIfNotExists("Users", "MfaSecret", "varchar(128)", "character varying(128)", "")
// ADDED for 2.2 REMOVE for 2.6
if store.DoesColumnExist("Users", "TeamId") {
store.RemoveIndexIfExists("idx_users_team_id", "Users")
store.CreateUniqueIndexIfNotExists("idx_users_email_unique", "Users", "Email")
store.CreateUniqueIndexIfNotExists("idx_users_username_unique", "Users", "Username")
store.RemoveColumnIfExists("Teams", "AllowTeamListing")
store.RemoveColumnIfExists("Users", "TeamId")
}
l4g.Info("Finished running speical upgrade of the database schema to version 3.0 for user model changes")
if result := <-store.System().Update(&model.System{Name: "Version", Value: model.CurrentVersion}); result.Err != nil {
l4g.Error("Failed to update system schema version details=%v", result.Err)
flushLogAndExit(1)
}
l4g.Info(utils.T("store.sql.upgraded.warn"), model.CurrentVersion)
fmt.Println("**SUCCESS** with upgrade")
flushLogAndExit(0)
}
}
type UserForUpgrade struct {
Id string
Username string
Email string
Roles string
TeamId string
}
func convertTeamTo30(team *TeamForUpgrade, uniqueEmails map[string]bool, uniqueUsernames map[string]bool) []*UserForUpgrade {
store := api.Srv.Store.(*store.SqlStore)
var users []*UserForUpgrade
if _, err := store.GetMaster().Select(&users, "SELECT Users.Id, Users.Username, Users.Email, Users.Roles, Users.TeamId FROM Users WHERE Users.TeamId = :TeamId", map[string]interface{}{"TeamId": team.Id}); err != nil {
l4g.Error("Failed to load profiles for team details=%v", err)
flushLogAndExit(1)
}
var members []*model.TeamMember
if result := <-api.Srv.Store.Team().GetMembers(team.Id); result.Err != nil {
l4g.Error("Failed to load team membership details=%v", result.Err)
flushLogAndExit(1)
} else {
members = result.Data.([]*model.TeamMember)
}
for _, user := range users {
shouldUpdateUser := false
previousRole := user.Roles
previousEmail := user.Email
previousUsername := user.Username
member := &model.TeamMember{
TeamId: team.Id,
UserId: user.Id,
}
if model.IsInRole(user.Roles, model.ROLE_TEAM_ADMIN) {
member.Roles = model.ROLE_TEAM_ADMIN
user.Roles = ""
shouldUpdateUser = true
}
exists := false
for _, member := range members {
if member.UserId == user.Id {
exists = true
break
}
}
if !exists {
if result := <-api.Srv.Store.Team().SaveMember(member); result.Err != nil {
l4g.Error("Failed to save membership for %v details=%v", user.Email, result.Err)
flushLogAndExit(1)
}
}
if uniqueEmails[user.Email] {
shouldUpdateUser = true
emailParts := strings.Split(user.Email, "@")
if len(emailParts) == 2 {
user.Email = emailParts[0] + "+" + team.Name + "@" + emailParts[1]
} else {
user.Email = user.Email + "." + team.Name
}
}
if uniqueUsernames[user.Username] {
shouldUpdateUser = true
user.Username = user.Username + "." + team.Name
}
if shouldUpdateUser {
if _, err := store.GetMaster().Exec(`
UPDATE Users
SET
Email = :Email,
Username = :Username,
Roles = :Roles
WHERE
Id = :Id
`,
map[string]interface{}{
"Email": user.Email,
"Username": user.Username,
"Roles": user.Roles,
"Id": user.Id,
},
); err != nil {
l4g.Error("Failed to update user %v details=%v", user.Email, err)
flushLogAndExit(1)
}
l4g.Info("modified user_id=%v, changed email from=%v to=%v, changed username from=%v to %v changed roles from=%v to=%v", user.Id, previousEmail, user.Email, previousUsername, user.Username, previousRole, user.Roles)
}
uniqueEmails[user.Email] = true
uniqueUsernames[user.Username] = true
}
return users
}
func cmdCreateTeam() {
if flagCmdCreateTeam {
if len(flagTeamName) == 0 {
@ -327,10 +592,9 @@ func cmdCreateUser() {
flushLogAndExit(1)
} else {
team = result.Data.(*model.Team)
user.TeamId = team.Id
}
_, err := api.CreateUser(team, user)
ruser, err := api.CreateUser(user)
if err != nil {
if err.Id != "store.sql_user.save.email_exists.app_error" {
l4g.Error("%v", err)
@ -338,6 +602,12 @@ func cmdCreateUser() {
}
}
err = api.JoinUserToTeam(team, ruser)
if err != nil {
l4g.Error("%v", err)
flushLogAndExit(1)
}
os.Exit(0)
}
}
@ -368,7 +638,7 @@ func cmdAssignRole() {
os.Exit(1)
}
if !model.IsValidRoles(flagRole) {
if !model.IsValidUserRoles(flagRole) {
fmt.Fprintln(os.Stderr, "flag invalid argument: -role")
flag.Usage()
os.Exit(1)
@ -376,16 +646,8 @@ func cmdAssignRole() {
c := getMockContext()
var team *model.Team
if result := <-api.Srv.Store.Team().GetByName(flagTeamName); result.Err != nil {
l4g.Error("%v", result.Err)
flushLogAndExit(1)
} else {
team = result.Data.(*model.Team)
}
var user *model.User
if result := <-api.Srv.Store.User().GetByEmail(team.Id, flagEmail); result.Err != nil {
if result := <-api.Srv.Store.User().GetByEmail(flagEmail); result.Err != nil {
l4g.Error("%v", result.Err)
flushLogAndExit(1)
} else {
@ -426,16 +688,8 @@ func cmdResetPassword() {
os.Exit(1)
}
var team *model.Team
if result := <-api.Srv.Store.Team().GetByName(flagTeamName); result.Err != nil {
l4g.Error("%v", result.Err)
flushLogAndExit(1)
} else {
team = result.Data.(*model.Team)
}
var user *model.User
if result := <-api.Srv.Store.User().GetByEmail(team.Id, flagEmail); result.Err != nil {
if result := <-api.Srv.Store.User().GetByEmail(flagEmail); result.Err != nil {
l4g.Error("%v", result.Err)
flushLogAndExit(1)
} else {
@ -451,14 +705,42 @@ func cmdResetPassword() {
}
}
func cmdPermDeleteUser() {
if flagCmdPermanentDeleteUser {
if len(flagTeamName) == 0 {
fmt.Fprintln(os.Stderr, "flag needs an argument: -team_name")
func cmdResetMfa() {
if flagCmdResetMfa {
if len(flagEmail) == 0 && len(flagUsername) == 0 {
fmt.Fprintln(os.Stderr, "flag needs an argument: -email OR -username")
flag.Usage()
os.Exit(1)
}
var user *model.User
if len(flagEmail) > 0 {
if result := <-api.Srv.Store.User().GetByEmail(flagEmail); result.Err != nil {
l4g.Error("%v", result.Err)
flushLogAndExit(1)
} else {
user = result.Data.(*model.User)
}
} else {
if result := <-api.Srv.Store.User().GetByUsername(flagUsername); result.Err != nil {
l4g.Error("%v", result.Err)
flushLogAndExit(1)
} else {
user = result.Data.(*model.User)
}
}
if err := api.DeactivateMfa(user.Id); err != nil {
l4g.Error("%v", err)
flushLogAndExit(1)
}
os.Exit(0)
}
}
func cmdPermDeleteUser() {
if flagCmdPermanentDeleteUser {
if len(flagEmail) == 0 {
fmt.Fprintln(os.Stderr, "flag needs an argument: -email")
flag.Usage()
@ -467,16 +749,8 @@ func cmdPermDeleteUser() {
c := getMockContext()
var team *model.Team
if result := <-api.Srv.Store.Team().GetByName(flagTeamName); result.Err != nil {
l4g.Error("%v", result.Err)
flushLogAndExit(1)
} else {
team = result.Data.(*model.Team)
}
var user *model.User
if result := <-api.Srv.Store.User().GetByEmail(team.Id, flagEmail); result.Err != nil {
if result := <-api.Srv.Store.User().GetByEmail(flagEmail); result.Err != nil {
l4g.Error("%v", result.Err)
flushLogAndExit(1)
} else {
@ -487,6 +761,7 @@ func cmdPermDeleteUser() {
fmt.Print("Have you performed a database backup? (YES/NO): ")
fmt.Scanln(&confirmBackup)
if confirmBackup != "YES" {
fmt.Print("ABORTED: You did not answer YES exactly, in all capitals.")
flushLogAndExit(1)
}
@ -494,6 +769,7 @@ func cmdPermDeleteUser() {
fmt.Printf("Are you sure you want to delete the user %v? All data will be permanently deleted? (YES/NO): ", user.Email)
fmt.Scanln(&confirm)
if confirm != "YES" {
fmt.Print("ABORTED: You did not answer YES exactly, in all capitals.")
flushLogAndExit(1)
}
@ -501,6 +777,7 @@ func cmdPermDeleteUser() {
l4g.Error("%v", err)
flushLogAndExit(1)
} else {
fmt.Print("SUCCESS: User deleted.")
flushLogAndExit(0)
}
}
@ -528,6 +805,7 @@ func cmdPermDeleteTeam() {
fmt.Print("Have you performed a database backup? (YES/NO): ")
fmt.Scanln(&confirmBackup)
if confirmBackup != "YES" {
fmt.Print("ABORTED: You did not answer YES exactly, in all capitals.")
flushLogAndExit(1)
}
@ -535,6 +813,7 @@ func cmdPermDeleteTeam() {
fmt.Printf("Are you sure you want to delete the team %v? All data will be permanently deleted? (YES/NO): ", team.Name)
fmt.Scanln(&confirm)
if confirm != "YES" {
fmt.Print("ABORTED: You did not answer YES exactly, in all capitals.")
flushLogAndExit(1)
}
@ -542,11 +821,67 @@ func cmdPermDeleteTeam() {
l4g.Error("%v", err)
flushLogAndExit(1)
} else {
fmt.Print("SUCCESS: Team deleted.")
flushLogAndExit(0)
}
}
}
func cmdPermDeleteAllUsers() {
if flagCmdPermanentDeleteAllUsers {
c := getMockContext()
var confirmBackup string
fmt.Print("Have you performed a database backup? (YES/NO): ")
fmt.Scanln(&confirmBackup)
if confirmBackup != "YES" {
fmt.Print("ABORTED: You did not answer YES exactly, in all capitals.")
flushLogAndExit(1)
}
var confirm string
fmt.Printf("Are you sure you want to delete all the users? All data will be permanently deleted? (YES/NO): ")
fmt.Scanln(&confirm)
if confirm != "YES" {
fmt.Print("ABORTED: You did not answer YES exactly, in all capitals.")
flushLogAndExit(1)
}
if err := api.PermanentDeleteAllUsers(c); err != nil {
l4g.Error("%v", err)
flushLogAndExit(1)
} else {
fmt.Print("SUCCESS: All users deleted.")
flushLogAndExit(0)
}
}
}
func cmdResetDatabase() {
if flagCmdResetDatabase {
var confirmBackup string
fmt.Print("Have you performed a database backup? (YES/NO): ")
fmt.Scanln(&confirmBackup)
if confirmBackup != "YES" {
fmt.Print("ABORTED: You did not answer YES exactly, in all capitals.")
flushLogAndExit(1)
}
var confirm string
fmt.Printf("Are you sure you want to delete everything? ALL data will be permanently deleted? (YES/NO): ")
fmt.Scanln(&confirm)
if confirm != "YES" {
fmt.Print("ABORTED: You did not answer YES exactly, in all capitals.")
flushLogAndExit(1)
}
api.Srv.Store.DropAllTables()
fmt.Print("SUCCESS: Database reset.")
flushLogAndExit(0)
}
}
func cmdUploadLicense() {
if flagCmdUploadLicense {
if model.BuildEnterpriseReady != "true" {
@ -574,7 +909,7 @@ func cmdUploadLicense() {
flushLogAndExit(0)
}
os.Exit(0)
flushLogAndExit(0)
}
}
@ -604,6 +939,8 @@ USAGE:
FLAGS:
-config="config.json" Path to the config file
-username="someuser" Username used in other commands
-license="ex.mattermost-license" Path to your license file
-email="user@example.com" Email address used in other commands
@ -644,14 +981,33 @@ COMMANDS:
Example:
platform -reset_password -team_name="name" -email="user@example.com" -password="newpassword"
-reset_mfa Turns off multi-factor authentication for a user. It requires the
-email or -username flag.
Example:
platform -reset_mfa -username="someuser"
-reset_database Completely erases the database causing the loss of all data. This
will reset Mattermost to it's initial state. (note this will not
erase your configuration.)
Example:
platform -reset_mfa -username="someuser"
-permanent_delete_user Permanently deletes a user and all related information
including posts from the database. It requires the
-email flag. You may need to restart the
server to invalidate the cache
Example:
platform -permanent_delete_user -email="user@example.com"
-permanent_delete_all_users Permanently deletes all users and all related information
including posts from the database. It requires the
-team_name, and -email flag. You may need to restart the
server to invalidate the cache
Example:
platform -permanent_delete_user -team_name="name" -email="user@example.com"
platform -permanent_delete_all_users -team_name="name" -email="user@example.com"
-permanent_delete_team Permanently deletes a team and all users along with
-permanent_delete_team Permanently deletes a team allong with
all related information including posts from the database.
It requires the -team_name flag. You may need to restart
the server to invalidate the cache.

View file

@ -28,7 +28,10 @@ const (
HEADER_AUTH = "Authorization"
HEADER_REQUESTED_WITH = "X-Requested-With"
HEADER_REQUESTED_WITH_XML = "XMLHttpRequest"
API_URL_SUFFIX = "/api/v1"
API_URL_SUFFIX_V1 = "/api/v1"
API_URL_SUFFIX_V3 = "/api/v3"
API_URL_SUFFIX = API_URL_SUFFIX_V3
)
type Result struct {
@ -39,16 +42,52 @@ type Result struct {
type Client struct {
Url string // The location of the server like "http://localhost:8065"
ApiUrl string // The api location of the server like "http://localhost:8065/api/v1"
ApiUrl string // The api location of the server like "http://localhost:8065/api/v3"
HttpClient *http.Client // The http client
AuthToken string
AuthType string
TeamId string
}
// NewClient constructs a new client with convienence methods for talking to
// the server.
func NewClient(url string) *Client {
return &Client{url, url + API_URL_SUFFIX, &http.Client{}, "", ""}
return &Client{url, url + API_URL_SUFFIX, &http.Client{}, "", "", ""}
}
func (c *Client) SetOAuthToken(token string) {
c.AuthToken = token
c.AuthType = HEADER_TOKEN
}
func (c *Client) ClearOAuthToken() {
c.AuthToken = ""
c.AuthType = HEADER_BEARER
}
func (c *Client) SetTeamId(teamId string) {
c.TeamId = teamId
}
func (c *Client) GetTeamId() string {
if len(c.TeamId) == 0 {
println(`You are trying to use a route that requires a team_id,
but you have not called SetTeamId() in client.go`)
}
return c.TeamId
}
func (c *Client) ClearTeamId() {
c.TeamId = ""
}
func (c *Client) GetTeamRoute() string {
return fmt.Sprintf("/teams/%v", c.GetTeamId())
}
func (c *Client) GetChannelRoute(channelId string) string {
return fmt.Sprintf("/teams/%v/channels/%v", c.GetTeamId(), channelId)
}
func (c *Client) DoPost(url, data, contentType string) (*http.Response, *AppError) {
@ -162,10 +201,19 @@ func (c *Client) GetAllTeams() (*Result, *AppError) {
}
}
func (c *Client) FindTeamByName(name string, allServers bool) (*Result, *AppError) {
func (c *Client) GetAllTeamListings() (*Result, *AppError) {
if r, err := c.DoApiGet("/teams/all_team_listings", "", ""); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), TeamMapFromJson(r.Body)}, nil
}
}
func (c *Client) FindTeamByName(name string) (*Result, *AppError) {
m := make(map[string]string)
m["name"] = name
m["all"] = fmt.Sprintf("%v", allServers)
if r, err := c.DoApiPost("/teams/find_team_by_name", MapToJson(m)); err != nil {
return nil, err
} else {
@ -179,8 +227,32 @@ func (c *Client) FindTeamByName(name string, allServers bool) (*Result, *AppErro
}
}
func (c *Client) AddUserToTeam(userId string) (*Result, *AppError) {
data := make(map[string]string)
data["user_id"] = userId
if r, err := c.DoApiPost(c.GetTeamRoute()+"/add_user_to_team", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
}
}
func (c *Client) AddUserToTeamFromInvite(hash, dataToHash, inviteId string) (*Result, *AppError) {
data := make(map[string]string)
data["hash"] = hash
data["data"] = dataToHash
data["invite_id"] = inviteId
if r, err := c.DoApiPost("/teams/add_user_to_team_from_invite", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
}
}
func (c *Client) InviteMembers(invites *Invites) (*Result, *AppError) {
if r, err := c.DoApiPost("/teams/invite_members", invites.ToJson()); err != nil {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/invite_members", invites.ToJson()); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -189,7 +261,7 @@ func (c *Client) InviteMembers(invites *Invites) (*Result, *AppError) {
}
func (c *Client) UpdateTeam(team *Team) (*Result, *AppError) {
if r, err := c.DoApiPost("/teams/update", team.ToJson()); err != nil {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/update", team.ToJson()); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -206,6 +278,18 @@ func (c *Client) CreateUser(user *User, hash string) (*Result, *AppError) {
}
}
func (c *Client) CreateUserWithInvite(user *User, hash string, data string, inviteId string) (*Result, *AppError) {
url := "/users/create?d=" + url.QueryEscape(data) + "&h=" + url.QueryEscape(hash) + "&iid=" + url.QueryEscape(inviteId)
if r, err := c.DoApiPost(url, user.ToJson()); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
}
}
func (c *Client) CreateUserFromSignup(user *User, data string, hash string) (*Result, *AppError) {
if r, err := c.DoApiPost("/users/create?d="+url.QueryEscape(data)+"&h="+hash, user.ToJson()); err != nil {
return nil, err
@ -216,7 +300,7 @@ func (c *Client) CreateUserFromSignup(user *User, data string, hash string) (*Re
}
func (c *Client) GetUser(id string, etag string) (*Result, *AppError) {
if r, err := c.DoApiGet("/users/"+id, "", etag); err != nil {
if r, err := c.DoApiGet("/users/"+id+"/get", "", etag); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -242,6 +326,24 @@ func (c *Client) GetProfiles(teamId string, etag string) (*Result, *AppError) {
}
}
func (c *Client) GetProfilesForTeam(teamId string, etag string) (*Result, *AppError) {
if r, err := c.DoApiGet("/users/profiles/"+teamId+"?skip_direct=true", "", etag); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
}
}
func (c *Client) GetDirectProfiles(etag string) (*Result, *AppError) {
if r, err := c.DoApiGet("/users/direct_profiles", "", etag); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
}
}
func (c *Client) LoginById(id string, password string) (*Result, *AppError) {
m := make(map[string]string)
m["id"] = id
@ -274,6 +376,26 @@ func (c *Client) LoginByEmailWithDevice(name string, email string, password stri
return c.login(m)
}
func (c *Client) LoginByLdap(userid string, password string, mfatoken string) (*Result, *AppError) {
m := make(map[string]string)
m["id"] = userid
m["password"] = password
m["token"] = mfatoken
if r, err := c.DoApiPost("/users/login_ldap", MapToJson(m)); err != nil {
return nil, err
} else {
c.AuthToken = r.Header.Get(HEADER_TOKEN)
c.AuthType = HEADER_BEARER
sessionToken := getCookie(SESSION_COOKIE_TOKEN, r)
if c.AuthToken != sessionToken.Value {
NewLocAppError("/users/login_ldap", "model.client.login.app_error", nil, "")
}
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
}
}
func (c *Client) login(m map[string]string) (*Result, *AppError) {
if r, err := c.DoApiPost("/users/login", MapToJson(m)); err != nil {
return nil, err
@ -297,16 +419,16 @@ func (c *Client) Logout() (*Result, *AppError) {
} else {
c.AuthToken = ""
c.AuthType = HEADER_BEARER
c.TeamId = ""
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
}
}
func (c *Client) CheckMfa(method, teamName, loginId string) (*Result, *AppError) {
func (c *Client) CheckMfa(method, loginId string) (*Result, *AppError) {
m := make(map[string]string)
m["method"] = method
m["team_name"] = teamName
m["login_id"] = loginId
if r, err := c.DoApiPost("/users/mfa", MapToJson(m)); err != nil {
@ -339,14 +461,16 @@ func (c *Client) UpdateMfa(activate bool, token string) (*Result, *AppError) {
}
}
func (c *Client) SetOAuthToken(token string) {
c.AuthToken = token
c.AuthType = HEADER_TOKEN
}
func (c *Client) AdminResetMfa(userId string) (*Result, *AppError) {
m := make(map[string]string)
m["user_id"] = userId
func (c *Client) ClearOAuthToken() {
c.AuthToken = ""
c.AuthType = HEADER_BEARER
if r, err := c.DoApiPost("/admin/reset_mfa", MapToJson(m)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
}
}
func (c *Client) RevokeSession(sessionAltId string) (*Result, *AppError) {
@ -411,7 +535,7 @@ func (c *Client) Command(channelId string, command string, suggest bool) (*Resul
m["command"] = command
m["channelId"] = channelId
m["suggest"] = strconv.FormatBool(suggest)
if r, err := c.DoApiPost("/commands/execute", MapToJson(m)); err != nil {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/execute", MapToJson(m)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -420,7 +544,7 @@ func (c *Client) Command(channelId string, command string, suggest bool) (*Resul
}
func (c *Client) ListCommands() (*Result, *AppError) {
if r, err := c.DoApiGet("/commands/list", "", ""); err != nil {
if r, err := c.DoApiGet(c.GetTeamRoute()+"/commands/list", "", ""); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -429,7 +553,7 @@ func (c *Client) ListCommands() (*Result, *AppError) {
}
func (c *Client) ListTeamCommands() (*Result, *AppError) {
if r, err := c.DoApiGet("/commands/list_team_commands", "", ""); err != nil {
if r, err := c.DoApiGet(c.GetTeamRoute()+"/commands/list_team_commands", "", ""); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -438,7 +562,7 @@ func (c *Client) ListTeamCommands() (*Result, *AppError) {
}
func (c *Client) CreateCommand(cmd *Command) (*Result, *AppError) {
if r, err := c.DoApiPost("/commands/create", cmd.ToJson()); err != nil {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/create", cmd.ToJson()); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -447,7 +571,7 @@ func (c *Client) CreateCommand(cmd *Command) (*Result, *AppError) {
}
func (c *Client) RegenCommandToken(data map[string]string) (*Result, *AppError) {
if r, err := c.DoApiPost("/commands/regen_token", MapToJson(data)); err != nil {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/regen_token", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -456,7 +580,7 @@ func (c *Client) RegenCommandToken(data map[string]string) (*Result, *AppError)
}
func (c *Client) DeleteCommand(data map[string]string) (*Result, *AppError) {
if r, err := c.DoApiPost("/commands/delete", MapToJson(data)); err != nil {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/delete", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -582,7 +706,7 @@ func (c *Client) GetSystemAnalytics(name string) (*Result, *AppError) {
}
func (c *Client) CreateChannel(channel *Channel) (*Result, *AppError) {
if r, err := c.DoApiPost("/channels/create", channel.ToJson()); err != nil {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/create", channel.ToJson()); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -590,8 +714,10 @@ func (c *Client) CreateChannel(channel *Channel) (*Result, *AppError) {
}
}
func (c *Client) CreateDirectChannel(data map[string]string) (*Result, *AppError) {
if r, err := c.DoApiPost("/channels/create_direct", MapToJson(data)); err != nil {
func (c *Client) CreateDirectChannel(userId string) (*Result, *AppError) {
data := make(map[string]string)
data["user_id"] = userId
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/create_direct", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -600,7 +726,7 @@ func (c *Client) CreateDirectChannel(data map[string]string) (*Result, *AppError
}
func (c *Client) UpdateChannel(channel *Channel) (*Result, *AppError) {
if r, err := c.DoApiPost("/channels/update", channel.ToJson()); err != nil {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update", channel.ToJson()); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -609,7 +735,7 @@ func (c *Client) UpdateChannel(channel *Channel) (*Result, *AppError) {
}
func (c *Client) UpdateChannelHeader(data map[string]string) (*Result, *AppError) {
if r, err := c.DoApiPost("/channels/update_header", MapToJson(data)); err != nil {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update_header", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -618,7 +744,7 @@ func (c *Client) UpdateChannelHeader(data map[string]string) (*Result, *AppError
}
func (c *Client) UpdateChannelPurpose(data map[string]string) (*Result, *AppError) {
if r, err := c.DoApiPost("/channels/update_purpose", MapToJson(data)); err != nil {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update_purpose", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -627,7 +753,7 @@ func (c *Client) UpdateChannelPurpose(data map[string]string) (*Result, *AppErro
}
func (c *Client) UpdateNotifyProps(data map[string]string) (*Result, *AppError) {
if r, err := c.DoApiPost("/channels/update_notify_props", MapToJson(data)); err != nil {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update_notify_props", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -636,7 +762,7 @@ func (c *Client) UpdateNotifyProps(data map[string]string) (*Result, *AppError)
}
func (c *Client) GetChannels(etag string) (*Result, *AppError) {
if r, err := c.DoApiGet("/channels/", "", etag); err != nil {
if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/", "", etag); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -645,7 +771,7 @@ func (c *Client) GetChannels(etag string) (*Result, *AppError) {
}
func (c *Client) GetChannel(id, etag string) (*Result, *AppError) {
if r, err := c.DoApiGet("/channels/"+id+"/", "", etag); err != nil {
if r, err := c.DoApiGet(c.GetChannelRoute(id)+"/", "", etag); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -654,7 +780,7 @@ func (c *Client) GetChannel(id, etag string) (*Result, *AppError) {
}
func (c *Client) GetMoreChannels(etag string) (*Result, *AppError) {
if r, err := c.DoApiGet("/channels/more", "", etag); err != nil {
if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/more", "", etag); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -663,7 +789,7 @@ func (c *Client) GetMoreChannels(etag string) (*Result, *AppError) {
}
func (c *Client) GetChannelCounts(etag string) (*Result, *AppError) {
if r, err := c.DoApiGet("/channels/counts", "", etag); err != nil {
if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/counts", "", etag); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -672,7 +798,7 @@ func (c *Client) GetChannelCounts(etag string) (*Result, *AppError) {
}
func (c *Client) JoinChannel(id string) (*Result, *AppError) {
if r, err := c.DoApiPost("/channels/"+id+"/join", ""); err != nil {
if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/join", ""); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -681,7 +807,7 @@ func (c *Client) JoinChannel(id string) (*Result, *AppError) {
}
func (c *Client) LeaveChannel(id string) (*Result, *AppError) {
if r, err := c.DoApiPost("/channels/"+id+"/leave", ""); err != nil {
if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/leave", ""); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -690,7 +816,7 @@ func (c *Client) LeaveChannel(id string) (*Result, *AppError) {
}
func (c *Client) DeleteChannel(id string) (*Result, *AppError) {
if r, err := c.DoApiPost("/channels/"+id+"/delete", ""); err != nil {
if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/delete", ""); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -701,7 +827,7 @@ func (c *Client) DeleteChannel(id string) (*Result, *AppError) {
func (c *Client) AddChannelMember(id, user_id string) (*Result, *AppError) {
data := make(map[string]string)
data["user_id"] = user_id
if r, err := c.DoApiPost("/channels/"+id+"/add", MapToJson(data)); err != nil {
if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/add", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -712,7 +838,7 @@ func (c *Client) AddChannelMember(id, user_id string) (*Result, *AppError) {
func (c *Client) RemoveChannelMember(id, user_id string) (*Result, *AppError) {
data := make(map[string]string)
data["user_id"] = user_id
if r, err := c.DoApiPost("/channels/"+id+"/remove", MapToJson(data)); err != nil {
if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/remove", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -721,7 +847,7 @@ func (c *Client) RemoveChannelMember(id, user_id string) (*Result, *AppError) {
}
func (c *Client) UpdateLastViewedAt(channelId string) (*Result, *AppError) {
if r, err := c.DoApiPost("/channels/"+channelId+"/update_last_viewed_at", ""); err != nil {
if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/update_last_viewed_at", ""); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -730,7 +856,7 @@ func (c *Client) UpdateLastViewedAt(channelId string) (*Result, *AppError) {
}
func (c *Client) GetChannelExtraInfo(id string, memberLimit int, etag string) (*Result, *AppError) {
if r, err := c.DoApiGet("/channels/"+id+"/extra_info/"+strconv.FormatInt(int64(memberLimit), 10), "", etag); err != nil {
if r, err := c.DoApiGet(c.GetChannelRoute(id)+"/extra_info/"+strconv.FormatInt(int64(memberLimit), 10), "", etag); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -739,7 +865,7 @@ func (c *Client) GetChannelExtraInfo(id string, memberLimit int, etag string) (*
}
func (c *Client) CreatePost(post *Post) (*Result, *AppError) {
if r, err := c.DoApiPost("/channels/"+post.ChannelId+"/create", post.ToJson()); err != nil {
if r, err := c.DoApiPost(c.GetChannelRoute(post.ChannelId)+"/posts/create", post.ToJson()); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -748,7 +874,7 @@ func (c *Client) CreatePost(post *Post) (*Result, *AppError) {
}
func (c *Client) UpdatePost(post *Post) (*Result, *AppError) {
if r, err := c.DoApiPost("/channels/"+post.ChannelId+"/update", post.ToJson()); err != nil {
if r, err := c.DoApiPost(c.GetChannelRoute(post.ChannelId)+"/posts/update", post.ToJson()); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -757,7 +883,7 @@ func (c *Client) UpdatePost(post *Post) (*Result, *AppError) {
}
func (c *Client) GetPosts(channelId string, offset int, limit int, etag string) (*Result, *AppError) {
if r, err := c.DoApiGet(fmt.Sprintf("/channels/%v/posts/%v/%v", channelId, offset, limit), "", etag); err != nil {
if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/page/%v/%v", offset, limit), "", etag); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -766,7 +892,7 @@ func (c *Client) GetPosts(channelId string, offset int, limit int, etag string)
}
func (c *Client) GetPostsSince(channelId string, time int64) (*Result, *AppError) {
if r, err := c.DoApiGet(fmt.Sprintf("/channels/%v/posts/%v", channelId, time), "", ""); err != nil {
if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/since/%v", time), "", ""); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -775,7 +901,7 @@ func (c *Client) GetPostsSince(channelId string, time int64) (*Result, *AppError
}
func (c *Client) GetPostsBefore(channelId string, postid string, offset int, limit int, etag string) (*Result, *AppError) {
if r, err := c.DoApiGet(fmt.Sprintf("/channels/%v/post/%v/before/%v/%v", channelId, postid, offset, limit), "", etag); err != nil {
if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/before/%v/%v", postid, offset, limit), "", etag); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -784,7 +910,7 @@ func (c *Client) GetPostsBefore(channelId string, postid string, offset int, lim
}
func (c *Client) GetPostsAfter(channelId string, postid string, offset int, limit int, etag string) (*Result, *AppError) {
if r, err := c.DoApiGet(fmt.Sprintf("/channels/%v/post/%v/after/%v/%v", channelId, postid, offset, limit), "", etag); err != nil {
if r, err := c.DoApiGet(fmt.Sprintf(c.GetChannelRoute(channelId)+"/posts/%v/after/%v/%v", postid, offset, limit), "", etag); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -793,7 +919,7 @@ func (c *Client) GetPostsAfter(channelId string, postid string, offset int, limi
}
func (c *Client) GetPost(channelId string, postId string, etag string) (*Result, *AppError) {
if r, err := c.DoApiGet(fmt.Sprintf("/channels/%v/post/%v", channelId, postId), "", etag); err != nil {
if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/get", postId), "", etag); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -802,7 +928,7 @@ func (c *Client) GetPost(channelId string, postId string, etag string) (*Result,
}
func (c *Client) DeletePost(channelId string, postId string) (*Result, *AppError) {
if r, err := c.DoApiPost(fmt.Sprintf("/channels/%v/post/%v/delete", channelId, postId), ""); err != nil {
if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/delete", postId), ""); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -811,7 +937,7 @@ func (c *Client) DeletePost(channelId string, postId string) (*Result, *AppError
}
func (c *Client) SearchPosts(terms string) (*Result, *AppError) {
if r, err := c.DoApiGet("/posts/search?terms="+url.QueryEscape(terms), "", ""); err != nil {
if r, err := c.DoApiGet(c.GetTeamRoute()+"/posts/search?terms="+url.QueryEscape(terms), "", ""); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -819,8 +945,16 @@ func (c *Client) SearchPosts(terms string) (*Result, *AppError) {
}
}
func (c *Client) UploadFile(url string, data []byte, contentType string) (*Result, *AppError) {
rq, _ := http.NewRequest("POST", c.ApiUrl+url, bytes.NewReader(data))
func (c *Client) UploadProfileFile(data []byte, contentType string) (*Result, *AppError) {
return c.uploadFile(c.ApiUrl+"/users/newimage", data, contentType)
}
func (c *Client) UploadPostAttachment(data []byte, contentType string) (*Result, *AppError) {
return c.uploadFile(c.ApiUrl+c.GetTeamRoute()+"/files/upload", data, contentType)
}
func (c *Client) uploadFile(url string, data []byte, contentType string) (*Result, *AppError) {
rq, _ := http.NewRequest("POST", url, bytes.NewReader(data))
rq.Header.Set("Content-Type", contentType)
if len(c.AuthToken) > 0 {
@ -842,7 +976,7 @@ func (c *Client) GetFile(url string, isFullUrl bool) (*Result, *AppError) {
if isFullUrl {
rq, _ = http.NewRequest("GET", url, nil)
} else {
rq, _ = http.NewRequest("GET", c.ApiUrl+"/files/get"+url, nil)
rq, _ = http.NewRequest("GET", c.ApiUrl+c.GetTeamRoute()+"/files/get"+url, nil)
}
if len(c.AuthToken) > 0 {
@ -861,7 +995,7 @@ func (c *Client) GetFile(url string, isFullUrl bool) (*Result, *AppError) {
func (c *Client) GetFileInfo(url string) (*Result, *AppError) {
var rq *http.Request
rq, _ = http.NewRequest("GET", c.ApiUrl+"/files/get_info"+url, nil)
rq, _ = http.NewRequest("GET", c.ApiUrl+c.GetTeamRoute()+"/files/get_info"+url, nil)
if len(c.AuthToken) > 0 {
rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
@ -878,7 +1012,7 @@ func (c *Client) GetFileInfo(url string) (*Result, *AppError) {
}
func (c *Client) GetPublicLink(data map[string]string) (*Result, *AppError) {
if r, err := c.DoApiPost("/files/get_public_link", MapToJson(data)); err != nil {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/files/get_public_link", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -950,7 +1084,9 @@ func (c *Client) UpdateUserPassword(userId, currentPassword, newPassword string)
}
}
func (c *Client) SendPasswordReset(data map[string]string) (*Result, *AppError) {
func (c *Client) SendPasswordReset(email string) (*Result, *AppError) {
data := map[string]string{}
data["email"] = email
if r, err := c.DoApiPost("/users/send_password_reset", MapToJson(data)); err != nil {
return nil, err
} else {
@ -959,7 +1095,10 @@ func (c *Client) SendPasswordReset(data map[string]string) (*Result, *AppError)
}
}
func (c *Client) ResetPassword(data map[string]string) (*Result, *AppError) {
func (c *Client) ResetPassword(code, newPassword string) (*Result, *AppError) {
data := map[string]string{}
data["code"] = code
data["new_password"] = newPassword
if r, err := c.DoApiPost("/users/reset_password", MapToJson(data)); err != nil {
return nil, err
} else {
@ -968,6 +1107,18 @@ func (c *Client) ResetPassword(data map[string]string) (*Result, *AppError) {
}
}
func (c *Client) AdminResetPassword(userId, newPassword string) (*Result, *AppError) {
data := map[string]string{}
data["user_id"] = userId
data["new_password"] = newPassword
if r, err := c.DoApiPost("/admin/reset_password", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
}
}
func (c *Client) GetStatuses(data []string) (*Result, *AppError) {
if r, err := c.DoApiPost("/users/status", ArrayToJson(data)); err != nil {
return nil, err
@ -978,7 +1129,7 @@ func (c *Client) GetStatuses(data []string) (*Result, *AppError) {
}
func (c *Client) GetMyTeam(etag string) (*Result, *AppError) {
if r, err := c.DoApiGet("/teams/me", "", etag); err != nil {
if r, err := c.DoApiGet(c.GetTeamRoute()+"/me", "", etag); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -986,6 +1137,15 @@ func (c *Client) GetMyTeam(etag string) (*Result, *AppError) {
}
}
func (c *Client) GetTeamMembers(teamId string) (*Result, *AppError) {
if r, err := c.DoApiGet("/teams/members/"+teamId, "", ""); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), TeamMembersFromJson(r.Body)}, nil
}
}
func (c *Client) RegisterApp(app *OAuthApp) (*Result, *AppError) {
if r, err := c.DoApiPost("/oauth/register", app.ToJson()); err != nil {
return nil, err
@ -1014,7 +1174,7 @@ func (c *Client) GetAccessToken(data url.Values) (*Result, *AppError) {
}
func (c *Client) CreateIncomingWebhook(hook *IncomingWebhook) (*Result, *AppError) {
if r, err := c.DoApiPost("/hooks/incoming/create", hook.ToJson()); err != nil {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/incoming/create", hook.ToJson()); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -1031,8 +1191,10 @@ func (c *Client) PostToWebhook(id, payload string) (*Result, *AppError) {
}
}
func (c *Client) DeleteIncomingWebhook(data map[string]string) (*Result, *AppError) {
if r, err := c.DoApiPost("/hooks/incoming/delete", MapToJson(data)); err != nil {
func (c *Client) DeleteIncomingWebhook(id string) (*Result, *AppError) {
data := make(map[string]string)
data["id"] = id
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/incoming/delete", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -1041,7 +1203,7 @@ func (c *Client) DeleteIncomingWebhook(data map[string]string) (*Result, *AppErr
}
func (c *Client) ListIncomingWebhooks() (*Result, *AppError) {
if r, err := c.DoApiGet("/hooks/incoming/list", "", ""); err != nil {
if r, err := c.DoApiGet(c.GetTeamRoute()+"/hooks/incoming/list", "", ""); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -1085,7 +1247,7 @@ func (c *Client) GetPreferenceCategory(category string) (*Result, *AppError) {
}
func (c *Client) CreateOutgoingWebhook(hook *OutgoingWebhook) (*Result, *AppError) {
if r, err := c.DoApiPost("/hooks/outgoing/create", hook.ToJson()); err != nil {
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/create", hook.ToJson()); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -1093,8 +1255,10 @@ func (c *Client) CreateOutgoingWebhook(hook *OutgoingWebhook) (*Result, *AppErro
}
}
func (c *Client) DeleteOutgoingWebhook(data map[string]string) (*Result, *AppError) {
if r, err := c.DoApiPost("/hooks/outgoing/delete", MapToJson(data)); err != nil {
func (c *Client) DeleteOutgoingWebhook(id string) (*Result, *AppError) {
data := make(map[string]string)
data["id"] = id
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/delete", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -1103,7 +1267,7 @@ func (c *Client) DeleteOutgoingWebhook(data map[string]string) (*Result, *AppErr
}
func (c *Client) ListOutgoingWebhooks() (*Result, *AppError) {
if r, err := c.DoApiGet("/hooks/outgoing/list", "", ""); err != nil {
if r, err := c.DoApiGet(c.GetTeamRoute()+"/hooks/outgoing/list", "", ""); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -1111,8 +1275,10 @@ func (c *Client) ListOutgoingWebhooks() (*Result, *AppError) {
}
}
func (c *Client) RegenOutgoingWebhookToken(data map[string]string) (*Result, *AppError) {
if r, err := c.DoApiPost("/hooks/outgoing/regen_token", MapToJson(data)); err != nil {
func (c *Client) RegenOutgoingWebhookToken(id string) (*Result, *AppError) {
data := make(map[string]string)
data["id"] = id
if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/regen_token", MapToJson(data)); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
@ -1134,11 +1300,11 @@ func (c *Client) GetClientLicenceConfig(etag string) (*Result, *AppError) {
}
}
func (c *Client) GetMeLoggedIn() (*Result, *AppError) {
if r, err := c.DoApiGet("/users/me_logged_in", "", ""); err != nil {
func (c *Client) GetInitialLoad() (*Result, *AppError) {
if r, err := c.DoApiGet("/users/initial_load", "", ""); err != nil {
return nil, err
} else {
return &Result{r.Header.Get(HEADER_REQUEST_ID),
r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
r.Header.Get(HEADER_ETAG_SERVER), InitialLoadFromJson(r.Body)}, nil
}
}

View file

@ -99,7 +99,7 @@ func (o *Command) IsValid() *AppError {
return NewLocAppError("Command.IsValid", "model.command.is_valid.team_id.app_error", nil, "")
}
if len(o.Trigger) > 128 {
if len(o.Trigger) == 0 || len(o.Trigger) > 128 {
return NewLocAppError("Command.IsValid", "model.command.is_valid.trigger.app_error", nil, "")
}

View file

@ -19,63 +19,115 @@ func TestCommandJson(t *testing.T) {
}
func TestCommandIsValid(t *testing.T) {
o := Command{}
o := Command{
Id: NewId(),
Token: NewId(),
CreateAt: GetMillis(),
UpdateAt: GetMillis(),
CreatorId: NewId(),
TeamId: NewId(),
Trigger: "trigger",
URL: "http://example.com",
Method: COMMAND_METHOD_GET,
DisplayName: "",
Description: "",
}
if err := o.IsValid(); err != nil {
t.Fatal(err)
}
o.Id = ""
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.Id = NewId()
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
if err := o.IsValid(); err != nil {
t.Fatal(err)
}
o.CreateAt = GetMillis()
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.UpdateAt = GetMillis()
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.CreatorId = "123"
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.CreatorId = NewId()
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.Token = "123"
o.Token = ""
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.Token = NewId()
if err := o.IsValid(); err != nil {
t.Fatal(err)
}
o.CreateAt = 0
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.TeamId = "123"
o.CreateAt = GetMillis()
if err := o.IsValid(); err != nil {
t.Fatal(err)
}
o.UpdateAt = 0
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.UpdateAt = GetMillis()
if err := o.IsValid(); err != nil {
t.Fatal(err)
}
o.CreatorId = ""
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.CreatorId = NewId()
if err := o.IsValid(); err != nil {
t.Fatal(err)
}
o.TeamId = ""
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.TeamId = NewId()
if err := o.IsValid(); err != nil {
t.Fatal(err)
}
o.Trigger = ""
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.URL = "nowhere.com/"
o.Trigger = strings.Repeat("1", 129)
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.URL = "http://nowhere.com/"
o.Trigger = strings.Repeat("1", 128)
if err := o.IsValid(); err != nil {
t.Fatal(err)
}
o.URL = ""
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.URL = "1234"
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.URL = "https://example.com"
if err := o.IsValid(); err != nil {
t.Fatal(err)
}
o.Method = "https://example.com"
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
@ -85,6 +137,11 @@ func TestCommandIsValid(t *testing.T) {
t.Fatal(err)
}
o.Method = COMMAND_METHOD_POST
if err := o.IsValid(); err != nil {
t.Fatal(err)
}
o.DisplayName = strings.Repeat("1", 65)
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")

View file

@ -155,9 +155,9 @@ type TeamSettings struct {
MaxUsersPerTeam int
EnableTeamCreation bool
EnableUserCreation bool
EnableOpenServer *bool
RestrictCreationToDomains string
RestrictTeamNames *bool
EnableTeamListing *bool
EnableCustomBrand *bool
CustomBrandText *string
}
@ -180,6 +180,7 @@ type LdapSettings struct {
LastNameAttribute *string
EmailAttribute *string
UsernameAttribute *string
NicknameAttribute *string
IdAttribute *string
// Advanced
@ -297,11 +298,6 @@ func (o *Config) SetDefaults() {
*o.TeamSettings.RestrictTeamNames = true
}
if o.TeamSettings.EnableTeamListing == nil {
o.TeamSettings.EnableTeamListing = new(bool)
*o.TeamSettings.EnableTeamListing = false
}
if o.TeamSettings.EnableCustomBrand == nil {
o.TeamSettings.EnableCustomBrand = new(bool)
*o.TeamSettings.EnableCustomBrand = false
@ -312,6 +308,11 @@ func (o *Config) SetDefaults() {
*o.TeamSettings.CustomBrandText = ""
}
if o.TeamSettings.EnableOpenServer == nil {
o.TeamSettings.EnableOpenServer = new(bool)
*o.TeamSettings.EnableOpenServer = false
}
if o.EmailSettings.EnableSignInWithEmail == nil {
o.EmailSettings.EnableSignInWithEmail = new(bool)
@ -476,6 +477,11 @@ func (o *Config) SetDefaults() {
o.LdapSettings.SkipCertificateVerification = new(bool)
*o.LdapSettings.SkipCertificateVerification = false
}
if o.LdapSettings.NicknameAttribute == nil {
o.LdapSettings.NicknameAttribute = new(string)
*o.LdapSettings.NicknameAttribute = ""
}
}
func (o *Config) IsValid() *AppError {

8
model/gitlab.go Normal file
View file

@ -0,0 +1,8 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
const (
USER_AUTH_SERVICE_GITLAB = "gitlab"
)

View file

@ -12,10 +12,6 @@ import (
"strings"
)
const (
USER_AUTH_SERVICE_GITLAB = "gitlab"
)
type GitLabProvider struct {
}
@ -29,7 +25,7 @@ type GitLabUser struct {
func init() {
provider := &GitLabProvider{}
einterfaces.RegisterOauthProvider(USER_AUTH_SERVICE_GITLAB, provider)
einterfaces.RegisterOauthProvider(model.USER_AUTH_SERVICE_GITLAB, provider)
}
func userFromGitLabUser(glu *GitLabUser) *model.User {
@ -51,7 +47,7 @@ func userFromGitLabUser(glu *GitLabUser) *model.User {
}
user.Email = glu.Email
user.AuthData = strconv.FormatInt(glu.Id, 10)
user.AuthService = USER_AUTH_SERVICE_GITLAB
user.AuthService = model.USER_AUTH_SERVICE_GITLAB
return user
}
@ -84,7 +80,7 @@ func (glu *GitLabUser) getAuthData() string {
}
func (m *GitLabProvider) GetIdentifier() string {
return USER_AUTH_SERVICE_GITLAB
return model.USER_AUTH_SERVICE_GITLAB
}
func (m *GitLabProvider) GetUserFromJson(data io.Reader) *model.User {

40
model/initial_load.go Normal file
View file

@ -0,0 +1,40 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"encoding/json"
"io"
)
type InitialLoad struct {
User *User `json:"user"`
TeamMembers []*TeamMember `json:"team_members"`
Teams []*Team `json:"teams"`
DirectProfiles map[string]*User `json:"direct_profiles"`
Preferences Preferences `json:"preferences"`
ClientCfg map[string]string `json:"client_cfg"`
LicenseCfg map[string]string `json:"license_cfg"`
NoAccounts bool `json:"no_accounts"`
}
func (me *InitialLoad) ToJson() string {
b, err := json.Marshal(me)
if err != nil {
return ""
} else {
return string(b)
}
}
func InitialLoadFromJson(data io.Reader) *InitialLoad {
decoder := json.NewDecoder(data)
var o InitialLoad
err := decoder.Decode(&o)
if err == nil {
return &o
} else {
return nil
}
}

View file

@ -0,0 +1,20 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"strings"
"testing"
)
func TestInitialLoadJson(t *testing.T) {
u := &User{Id: NewId()}
o := InitialLoad{User: u}
json := o.ToJson()
ro := InitialLoadFromJson(strings.NewReader(json))
if o.User.Id != ro.User.Id {
t.Fatal("Ids do not match")
}
}

View file

@ -0,0 +1,37 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
const (
PASSWORD_RECOVERY_CODE_SIZE = 128
PASSWORD_RECOVER_EXPIRY_TIME = 1000 * 60 * 60 // 1 hour
)
type PasswordRecovery struct {
UserId string
Code string
CreateAt int64
}
func (p *PasswordRecovery) IsValid() *AppError {
if len(p.UserId) != 26 {
return NewLocAppError("User.IsValid", "model.password_recovery.is_valid.user_id.app_error", nil, "")
}
if len(p.Code) != PASSWORD_RECOVERY_CODE_SIZE {
return NewLocAppError("User.IsValid", "model.password_recovery.is_valid.code.app_error", nil, "")
}
if p.CreateAt == 0 {
return NewLocAppError("User.IsValid", "model.password_recovery.is_valid.create_at.app_error", nil, "")
}
return nil
}
func (p *PasswordRecovery) PreSave() {
p.Code = NewRandomString(PASSWORD_RECOVERY_CODE_SIZE)
p.CreateAt = GetMillis()
}

View file

@ -17,17 +17,17 @@ const (
)
type Session struct {
Id string `json:"id"`
Token string `json:"token"`
CreateAt int64 `json:"create_at"`
ExpiresAt int64 `json:"expires_at"`
LastActivityAt int64 `json:"last_activity_at"`
UserId string `json:"user_id"`
TeamId string `json:"team_id"`
DeviceId string `json:"device_id"`
Roles string `json:"roles"`
IsOAuth bool `json:"is_oauth"`
Props StringMap `json:"props"`
Id string `json:"id"`
Token string `json:"token"`
CreateAt int64 `json:"create_at"`
ExpiresAt int64 `json:"expires_at"`
LastActivityAt int64 `json:"last_activity_at"`
UserId string `json:"user_id"`
DeviceId string `json:"device_id"`
Roles string `json:"roles"`
IsOAuth bool `json:"is_oauth"`
Props StringMap `json:"props"`
TeamMembers []*TeamMember `json:"team_members" db:"-"`
}
func (me *Session) ToJson() string {
@ -95,6 +95,16 @@ func (me *Session) AddProp(key string, value string) {
me.Props[key] = value
}
func (me *Session) GetTeamByTeamId(teamId string) *TeamMember {
for _, team := range me.TeamMembers {
if team.TeamId == teamId {
return team
}
}
return nil
}
func SessionsToJson(o []*Session) string {
if b, err := json.Marshal(o); err != nil {
return "[]"

View file

@ -18,19 +18,18 @@ const (
)
type Team struct {
Id string `json:"id"`
CreateAt int64 `json:"create_at"`
UpdateAt int64 `json:"update_at"`
DeleteAt int64 `json:"delete_at"`
DisplayName string `json:"display_name"`
Name string `json:"name"`
Email string `json:"email"`
Type string `json:"type"`
CompanyName string `json:"company_name"`
AllowedDomains string `json:"allowed_domains"`
InviteId string `json:"invite_id"`
AllowOpenInvite bool `json:"allow_open_invite"`
AllowTeamListing bool `json:"allow_team_listing"`
Id string `json:"id"`
CreateAt int64 `json:"create_at"`
UpdateAt int64 `json:"update_at"`
DeleteAt int64 `json:"delete_at"`
DisplayName string `json:"display_name"`
Name string `json:"name"`
Email string `json:"email"`
Type string `json:"type"`
CompanyName string `json:"company_name"`
AllowedDomains string `json:"allowed_domains"`
InviteId string `json:"invite_id"`
AllowOpenInvite bool `json:"allow_open_invite"`
}
type Invites struct {

78
model/team_member.go Normal file
View file

@ -0,0 +1,78 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"encoding/json"
"io"
"strings"
)
const (
ROLE_TEAM_ADMIN = "admin"
)
type TeamMember struct {
TeamId string `json:"team_id"`
UserId string `json:"user_id"`
Roles string `json:"roles"`
}
func (o *TeamMember) ToJson() string {
b, err := json.Marshal(o)
if err != nil {
return ""
} else {
return string(b)
}
}
func TeamMemberFromJson(data io.Reader) *TeamMember {
decoder := json.NewDecoder(data)
var o TeamMember
err := decoder.Decode(&o)
if err == nil {
return &o
} else {
return nil
}
}
func TeamMembersToJson(o []*TeamMember) string {
if b, err := json.Marshal(o); err != nil {
return "[]"
} else {
return string(b)
}
}
func TeamMembersFromJson(data io.Reader) []*TeamMember {
decoder := json.NewDecoder(data)
var o []*TeamMember
err := decoder.Decode(&o)
if err == nil {
return o
} else {
return nil
}
}
func (o *TeamMember) IsValid() *AppError {
if len(o.TeamId) != 26 {
return NewLocAppError("TeamMember.IsValid", "model.team_member.is_valid.team_id.app_error", nil, "")
}
if len(o.UserId) != 26 {
return NewLocAppError("TeamMember.IsValid", "model.team_member.is_valid.user_id.app_error", nil, "")
}
for _, role := range strings.Split(o.Roles, " ") {
if !(role == "" || role == ROLE_TEAM_ADMIN) {
return NewLocAppError("TeamMember.IsValid", "model.team_member.is_valid.role.app_error", nil, "role="+role)
}
}
return nil
}

43
model/team_member_test.go Normal file
View file

@ -0,0 +1,43 @@
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package model
import (
"strings"
"testing"
)
func TestTeamMemberJson(t *testing.T) {
o := TeamMember{TeamId: NewId(), UserId: NewId()}
json := o.ToJson()
ro := TeamMemberFromJson(strings.NewReader(json))
if o.TeamId != ro.TeamId {
t.Fatal("Ids do not match")
}
}
func TestTeamMemberIsValid(t *testing.T) {
o := TeamMember{}
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.TeamId = NewId()
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.UserId = NewId()
o.Roles = "blahblah"
if err := o.IsValid(); err == nil {
t.Fatal("should be invalid")
}
o.Roles = ""
if err := o.IsValid(); err != nil {
t.Fatal(err)
}
}

View file

@ -15,7 +15,6 @@ import (
)
const (
ROLE_TEAM_ADMIN = "admin"
ROLE_SYSTEM_ADMIN = "system_admin"
USER_AWAY_TIMEOUT = 5 * 60 * 1000 // 5 minutes
USER_OFFLINE_TIMEOUT = 1 * 60 * 1000 // 1 minute
@ -28,6 +27,7 @@ const (
DEFAULT_LOCALE = "en"
USER_AUTH_SERVICE_EMAIL = "email"
USER_AUTH_SERVICE_USERNAME = "username"
MIN_PASSWORD_LENGTH = 5
)
type User struct {
@ -35,7 +35,6 @@ type User struct {
CreateAt int64 `json:"create_at,omitempty"`
UpdateAt int64 `json:"update_at,omitempty"`
DeleteAt int64 `json:"delete_at"`
TeamId string `json:"team_id"`
Username string `json:"username"`
Password string `json:"password,omitempty"`
AuthData string `json:"auth_data,omitempty"`
@ -76,10 +75,6 @@ func (u *User) IsValid() *AppError {
return NewLocAppError("User.IsValid", "model.user.is_valid.update_at.app_error", nil, "user_id="+u.Id)
}
if len(u.TeamId) != 26 {
return NewLocAppError("User.IsValid", "model.user.is_valid.team_id.app_error", nil, "")
}
if !IsValidUsername(u.Username) {
return NewLocAppError("User.IsValid", "model.user.is_valid.username.app_error", nil, "user_id="+u.Id)
}
@ -228,6 +223,7 @@ func (u *User) IsAway() bool {
func (u *User) Sanitize(options map[string]bool) {
u.Password = ""
u.AuthData = ""
u.MfaSecret = ""
if len(options) != 0 && !options["email"] {
u.Email = ""
@ -246,6 +242,8 @@ func (u *User) ClearNonProfileFields() {
u.Password = ""
u.AuthData = ""
u.AuthService = ""
u.MfaActive = false
u.MfaSecret = ""
u.EmailVerified = false
u.LastPingAt = 0
u.AllowMarketing = false
@ -301,7 +299,7 @@ func (u *User) GetDisplayName() string {
}
}
func IsValidRoles(userRoles string) bool {
func IsValidUserRoles(userRoles string) bool {
roles := strings.Split(userRoles, " ")
@ -319,10 +317,6 @@ func isValidRole(role string) bool {
return true
}
if role == ROLE_TEAM_ADMIN {
return true
}
if role == ROLE_SYSTEM_ADMIN {
return true
}
@ -351,8 +345,8 @@ func IsInRole(userRoles string, inRole string) bool {
return false
}
func (u *User) IsSSOUser() bool {
if len(u.AuthData) != 0 && len(u.AuthService) != 0 && u.AuthService != USER_AUTH_SERVICE_LDAP {
func (u *User) IsOAuthUser() bool {
if u.AuthService == USER_AUTH_SERVICE_GITLAB {
return true
}
return false

View file

@ -63,11 +63,6 @@ func TestUserIsValid(t *testing.T) {
t.Fatal()
}
user.TeamId = NewId()
if err := user.IsValid(); err == nil {
t.Fatal()
}
user.Username = NewId() + "^hello#"
if err := user.IsValid(); err == nil {
t.Fatal()
@ -195,11 +190,11 @@ func TestCleanUsername(t *testing.T) {
func TestRoles(t *testing.T) {
if !IsValidRoles("admin") {
if IsValidUserRoles("admin") {
t.Fatal()
}
if IsValidRoles("junk") {
if IsValidUserRoles("junk") {
t.Fatal()
}

View file

@ -41,12 +41,10 @@ func (er *AppError) Error() string {
}
func (er *AppError) Translate(T goi18n.TranslateFunc) {
if len(er.Message) == 0 {
if er.params == nil {
er.Message = T(er.Id)
} else {
er.Message = T(er.Id, er.params)
}
if er.params == nil {
er.Message = T(er.Id)
} else {
er.Message = T(er.Id, er.params)
}
}
@ -83,6 +81,7 @@ func NewLocAppError(where string, id string, params map[string]interface{}, deta
ap := &AppError{}
ap.Id = id
ap.params = params
ap.Message = id
ap.Where = where
ap.DetailedError = details
ap.StatusCode = 500

View file

@ -13,6 +13,7 @@ import (
// It should be maitained in chronological order with most current
// release at the front of the list.
var versions = []string{
"3.0.0",
"2.2.0",
"2.1.0",
"2.0.0",

View file

@ -28,17 +28,6 @@ func NewSqlAuditStore(sqlStore *SqlStore) AuditStore {
}
func (s SqlAuditStore) UpgradeSchemaIfNeeded() {
// ADDED for 2.2 REMOVE for 2.6
extraLength := s.GetMaxLengthOfColumnIfExists("Audits", "ExtraInfo")
if len(extraLength) > 0 && extraLength != "1024" {
s.AlterColumnTypeIfExists("Audits", "ExtraInfo", "VARCHAR(1024)", "VARCHAR(1024)")
}
// ADDED for 2.2 REMOVE for 2.6
actionLength := s.GetMaxLengthOfColumnIfExists("Audits", "Action")
if len(actionLength) > 0 && actionLength != "512" {
s.AlterColumnTypeIfExists("Audits", "Action", "VARCHAR(512)", "VARCHAR(512)")
}
}
func (s SqlAuditStore) CreateIndexesIfNotExists() {

View file

@ -95,6 +95,7 @@ func (s SqlChannelStore) SaveDirectChannel(directchannel *model.Channel, member1
if transaction, err := s.GetMaster().Begin(); err != nil {
result.Err = model.NewLocAppError("SqlChannelStore.SaveDirectChannel", "store.sql_channel.save_direct_channel.open_transaction.app_error", nil, err.Error())
} else {
directchannel.TeamId = ""
channelResult := s.saveChannelT(transaction, directchannel)
if channelResult.Err != nil {
@ -330,7 +331,7 @@ func (s SqlChannelStore) GetChannels(teamId string, userId string) StoreChannel
result := StoreResult{}
var data []channelWithMember
_, err := s.GetReplica().Select(&data, "SELECT * FROM Channels, ChannelMembers WHERE Id = ChannelId AND TeamId = :TeamId AND UserId = :UserId AND DeleteAt = 0 ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId})
_, err := s.GetReplica().Select(&data, "SELECT * FROM Channels, ChannelMembers WHERE Id = ChannelId AND UserId = :UserId AND DeleteAt = 0 AND (TeamId = :TeamId OR TeamId = '') ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId})
if err != nil {
result.Err = model.NewLocAppError("SqlChannelStore.GetChannels", "store.sql_channel.get_channels.get.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error())
@ -411,7 +412,7 @@ func (s SqlChannelStore) GetChannelCounts(teamId string, userId string) StoreCha
result := StoreResult{}
var data []channelIdWithCountAndUpdateAt
_, err := s.GetReplica().Select(&data, "SELECT Id, TotalMsgCount, UpdateAt FROM Channels WHERE Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId) AND TeamId = :TeamId AND DeleteAt = 0 ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId})
_, err := s.GetReplica().Select(&data, "SELECT Id, TotalMsgCount, UpdateAt FROM Channels WHERE Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId) AND (TeamId = :TeamId OR TeamId = '') AND DeleteAt = 0 ORDER BY DisplayName", map[string]interface{}{"TeamId": teamId, "UserId": userId})
if err != nil {
result.Err = model.NewLocAppError("SqlChannelStore.GetChannelCounts", "store.sql_channel.get_channel_counts.get.app_error", nil, "teamId="+teamId+", userId="+userId+", err="+err.Error())
@ -441,7 +442,7 @@ func (s SqlChannelStore) GetByName(teamId string, name string) StoreChannel {
channel := model.Channel{}
if err := s.GetReplica().SelectOne(&channel, "SELECT * FROM Channels WHERE TeamId = :TeamId AND Name= :Name AND DeleteAt = 0", map[string]interface{}{"TeamId": teamId, "Name": name}); err != nil {
if err := s.GetReplica().SelectOne(&channel, "SELECT * FROM Channels WHERE (TeamId = :TeamId OR TeamId = '') AND Name = :Name AND DeleteAt = 0", map[string]interface{}{"TeamId": teamId, "Name": name}); err != nil {
if err == sql.ErrNoRows {
result.Err = model.NewLocAppError("SqlChannelStore.GetByName", MISSING_CHANNEL_ERROR, nil, "teamId="+teamId+", "+"name="+name+", "+err.Error())
} else {
@ -719,6 +720,37 @@ func (s SqlChannelStore) PermanentDeleteMembersByUser(userId string) StoreChanne
return storeChannel
}
func (s SqlChannelStore) CheckPermissionsToNoTeam(channelId string, userId string) StoreChannel {
storeChannel := make(StoreChannel)
go func() {
result := StoreResult{}
count, err := s.GetReplica().SelectInt(
`SELECT
COUNT(0)
FROM
Channels,
ChannelMembers
WHERE
Channels.Id = ChannelMembers.ChannelId
AND Channels.DeleteAt = 0
AND ChannelMembers.ChannelId = :ChannelId
AND ChannelMembers.UserId = :UserId`,
map[string]interface{}{"ChannelId": channelId, "UserId": userId})
if err != nil {
result.Err = model.NewLocAppError("SqlChannelStore.CheckPermissionsTo", "store.sql_channel.check_permissions.app_error", nil, "channel_id="+channelId+", user_id="+userId+", "+err.Error())
} else {
result.Data = count
}
storeChannel <- result
close(storeChannel)
}()
return storeChannel
}
func (s SqlChannelStore) CheckPermissionsTo(teamId string, channelId string, userId string) StoreChannel {
storeChannel := make(StoreChannel)
@ -733,7 +765,7 @@ func (s SqlChannelStore) CheckPermissionsTo(teamId string, channelId string, use
ChannelMembers
WHERE
Channels.Id = ChannelMembers.ChannelId
AND Channels.TeamId = :TeamId
AND (Channels.TeamId = :TeamId OR Channels.TeamId = '')
AND Channels.DeleteAt = 0
AND ChannelMembers.ChannelId = :ChannelId
AND ChannelMembers.UserId = :UserId`,
@ -765,7 +797,7 @@ func (s SqlChannelStore) CheckPermissionsToByName(teamId string, channelName str
ChannelMembers
WHERE
Channels.Id = ChannelMembers.ChannelId
AND Channels.TeamId = :TeamId
AND (Channels.TeamId = :TeamId OR Channels.TeamId = '')
AND Channels.Name = :Name
AND Channels.DeleteAt = 0
AND ChannelMembers.UserId = :UserId`,

View file

@ -67,17 +67,17 @@ func TestChannelStoreSaveDirectChannel(t *testing.T) {
o1.Name = "a" + model.NewId() + "b"
o1.Type = model.CHANNEL_DIRECT
u1 := model.User{}
u1.TeamId = model.NewId()
u1 := &model.User{}
u1.Email = model.NewId()
u1.Nickname = model.NewId()
Must(store.User().Save(&u1))
Must(store.User().Save(u1))
Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
u2 := model.User{}
u2.TeamId = model.NewId()
u2 := &model.User{}
u2.Email = model.NewId()
u2.Nickname = model.NewId()
Must(store.User().Save(&u2))
Must(store.User().Save(u2))
Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id}))
m1 := model.ChannelMember{}
m1.ChannelId = o1.Id
@ -163,17 +163,17 @@ func TestChannelStoreGet(t *testing.T) {
t.Fatal("Missing id should have failed")
}
u1 := model.User{}
u1.TeamId = model.NewId()
u1 := &model.User{}
u1.Email = model.NewId()
u1.Nickname = model.NewId()
Must(store.User().Save(&u1))
Must(store.User().Save(u1))
Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
u2 := model.User{}
u2.TeamId = model.NewId()
u2.Email = model.NewId()
u2.Nickname = model.NewId()
Must(store.User().Save(&u2))
Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id}))
o2 := model.Channel{}
o2.TeamId = model.NewId()
@ -309,16 +309,16 @@ func TestChannelMemberStore(t *testing.T) {
t1 := c1t1.ExtraUpdateAt
u1 := model.User{}
u1.TeamId = model.NewId()
u1.Email = model.NewId()
u1.Nickname = model.NewId()
Must(store.User().Save(&u1))
Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
u2 := model.User{}
u2.TeamId = model.NewId()
u2.Email = model.NewId()
u2.Nickname = model.NewId()
Must(store.User().Save(&u2))
Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id}))
o1 := model.ChannelMember{}
o1.ChannelId = c1.Id
@ -405,16 +405,16 @@ func TestChannelDeleteMemberStore(t *testing.T) {
t1 := c1t1.ExtraUpdateAt
u1 := model.User{}
u1.TeamId = model.NewId()
u1.Email = model.NewId()
u1.Nickname = model.NewId()
Must(store.User().Save(&u1))
Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id}))
u2 := model.User{}
u2.TeamId = model.NewId()
u2.Email = model.NewId()
u2.Nickname = model.NewId()
Must(store.User().Save(&u2))
Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id}))
o1 := model.ChannelMember{}
o1.ChannelId = c1.Id
@ -469,6 +469,11 @@ func TestChannelStorePermissionsTo(t *testing.T) {
t.Fatal("should have permissions")
}
count = (<-store.Channel().CheckPermissionsToNoTeam(o1.Id, m1.UserId)).Data.(int64)
if count != 1 {
t.Fatal("should have permissions")
}
count = (<-store.Channel().CheckPermissionsTo("junk", o1.Id, m1.UserId)).Data.(int64)
if count != 0 {
t.Fatal("shouldn't have permissions")
@ -479,11 +484,21 @@ func TestChannelStorePermissionsTo(t *testing.T) {
t.Fatal("shouldn't have permissions")
}
count = (<-store.Channel().CheckPermissionsToNoTeam("junk", m1.UserId)).Data.(int64)
if count != 0 {
t.Fatal("shouldn't have permissions")
}
count = (<-store.Channel().CheckPermissionsTo(o1.TeamId, o1.Id, "junk")).Data.(int64)
if count != 0 {
t.Fatal("shouldn't have permissions")
}
count = (<-store.Channel().CheckPermissionsToNoTeam(o1.Id, "junk")).Data.(int64)
if count != 0 {
t.Fatal("shouldn't have permissions")
}
channelId := (<-store.Channel().CheckPermissionsToByName(o1.TeamId, o1.Name, m1.UserId)).Data.(string)
if channelId != o1.Id {
t.Fatal("should have permissions")
@ -786,12 +801,12 @@ func TestGetMemberCount(t *testing.T) {
t.Logf("c1.Id = %v", c1.Id)
u1 := model.User{
TeamId: teamId,
u1 := &model.User{
Email: model.NewId(),
DeleteAt: 0,
}
Must(store.User().Save(&u1))
Must(store.User().Save(u1))
Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
m1 := model.ChannelMember{
ChannelId: c1.Id,
@ -807,11 +822,11 @@ func TestGetMemberCount(t *testing.T) {
}
u2 := model.User{
TeamId: teamId,
Email: model.NewId(),
DeleteAt: 0,
}
Must(store.User().Save(&u2))
Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u2.Id}))
m2 := model.ChannelMember{
ChannelId: c1.Id,
@ -828,11 +843,11 @@ func TestGetMemberCount(t *testing.T) {
// make sure members of other channels aren't counted
u3 := model.User{
TeamId: teamId,
Email: model.NewId(),
DeleteAt: 0,
}
Must(store.User().Save(&u3))
Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u3.Id}))
m3 := model.ChannelMember{
ChannelId: c2.Id,
@ -848,12 +863,12 @@ func TestGetMemberCount(t *testing.T) {
}
// make sure inactive users aren't counted
u4 := model.User{
TeamId: teamId,
u4 := &model.User{
Email: model.NewId(),
DeleteAt: 10000,
}
Must(store.User().Save(&u4))
Must(store.User().Save(u4))
Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u4.Id}))
m4 := model.ChannelMember{
ChannelId: c1.Id,
@ -892,12 +907,12 @@ func TestUpdateExtrasByUser(t *testing.T) {
t.Logf("c1.Id = %v", c1.Id)
u1 := model.User{
TeamId: teamId,
u1 := &model.User{
Email: model.NewId(),
DeleteAt: 0,
}
Must(store.User().Save(&u1))
Must(store.User().Save(u1))
Must(store.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: u1.Id}))
m1 := model.ChannelMember{
ChannelId: c1.Id,
@ -907,7 +922,7 @@ func TestUpdateExtrasByUser(t *testing.T) {
Must(store.Channel().SaveMember(&m1))
u1.DeleteAt = model.GetMillis()
Must(store.User().Update(&u1, true))
Must(store.User().Update(u1, true))
if result := <-store.Channel().ExtraUpdateByUser(u1.Id, u1.DeleteAt); result.Err != nil {
t.Fatal("failed to update extras by user: %v", result.Err)
@ -920,7 +935,7 @@ func TestUpdateExtrasByUser(t *testing.T) {
}
u1.DeleteAt = 0
Must(store.User().Update(&u1, true))
Must(store.User().Update(u1, true))
if result := <-store.Channel().ExtraUpdateByUser(u1.Id, u1.DeleteAt); result.Err != nil {
t.Fatal("failed to update extras by user: %v", result.Err)

View file

@ -16,6 +16,7 @@ func TestCommandStoreSave(t *testing.T) {
o1.Method = model.COMMAND_METHOD_POST
o1.TeamId = model.NewId()
o1.URL = "http://nowhere.com/"
o1.Trigger = "trigger"
if err := (<-store.Command().Save(&o1)).Err; err != nil {
t.Fatal("couldn't save item", err)
@ -34,6 +35,7 @@ func TestCommandStoreGet(t *testing.T) {
o1.Method = model.COMMAND_METHOD_POST
o1.TeamId = model.NewId()
o1.URL = "http://nowhere.com/"
o1.Trigger = "trigger"
o1 = (<-store.Command().Save(o1)).Data.(*model.Command)
@ -58,6 +60,7 @@ func TestCommandStoreGetByTeam(t *testing.T) {
o1.Method = model.COMMAND_METHOD_POST
o1.TeamId = model.NewId()
o1.URL = "http://nowhere.com/"
o1.Trigger = "trigger"
o1 = (<-store.Command().Save(o1)).Data.(*model.Command)
@ -86,6 +89,7 @@ func TestCommandStoreDelete(t *testing.T) {
o1.Method = model.COMMAND_METHOD_POST
o1.TeamId = model.NewId()
o1.URL = "http://nowhere.com/"
o1.Trigger = "trigger"
o1 = (<-store.Command().Save(o1)).Data.(*model.Command)
@ -115,6 +119,7 @@ func TestCommandStoreDeleteByUser(t *testing.T) {
o1.Method = model.COMMAND_METHOD_POST
o1.TeamId = model.NewId()
o1.URL = "http://nowhere.com/"
o1.Trigger = "trigger"
o1 = (<-store.Command().Save(o1)).Data.(*model.Command)
@ -144,6 +149,7 @@ func TestCommandStoreUpdate(t *testing.T) {
o1.Method = model.COMMAND_METHOD_POST
o1.TeamId = model.NewId()
o1.URL = "http://nowhere.com/"
o1.Trigger = "trigger"
o1 = (<-store.Command().Save(o1)).Data.(*model.Command)
@ -162,6 +168,7 @@ func TestCommandCount(t *testing.T) {
o1.Method = model.COMMAND_METHOD_POST
o1.TeamId = model.NewId()
o1.URL = "http://nowhere.com/"
o1.Trigger = "trigger"
o1 = (<-store.Command().Save(o1)).Data.(*model.Command)

View file

@ -58,16 +58,16 @@ func TestComplianceExport(t *testing.T) {
t1 = Must(store.Team().Save(t1)).(*model.Team)
u1 := &model.User{}
u1.TeamId = t1.Id
u1.Email = model.NewId()
u1.Username = model.NewId()
u1 = Must(store.User().Save(u1)).(*model.User)
Must(store.Team().SaveMember(&model.TeamMember{TeamId: t1.Id, UserId: u1.Id}))
u2 := &model.User{}
u2.TeamId = t1.Id
u2.Email = model.NewId()
u2.Username = model.NewId()
u2 = Must(store.User().Save(u2)).(*model.User)
Must(store.Team().SaveMember(&model.TeamMember{TeamId: t1.Id, UserId: u2.Id}))
c1 := &model.Channel{}
c1.TeamId = t1.Id

Some files were not shown because too many files have changed in this diff Show more