99
Dockerfile
Обычный файл
99
Dockerfile
Обычный файл
@@ -0,0 +1,99 @@
|
|||||||
|
# Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||||
|
# See License.txt for license information.
|
||||||
|
FROM ubuntu:14.04
|
||||||
|
|
||||||
|
# Install Dependancies
|
||||||
|
RUN apt-get update && apt-get install -y build-essential
|
||||||
|
RUN apt-get install -y curl
|
||||||
|
RUN curl -sL https://deb.nodesource.com/setup | bash -
|
||||||
|
RUN apt-get install -y nodejs
|
||||||
|
RUN apt-get install -y ruby-full
|
||||||
|
RUN gem install compass
|
||||||
|
|
||||||
|
# Postfix
|
||||||
|
RUN apt-get install -y postfix
|
||||||
|
|
||||||
|
#
|
||||||
|
# Install GO
|
||||||
|
#
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
gcc libc6-dev make git mercurial \
|
||||||
|
--no-install-recommends \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
ENV GOLANG_VERSION 1.4.2
|
||||||
|
|
||||||
|
RUN curl -sSL https://golang.org/dl/go$GOLANG_VERSION.src.tar.gz \
|
||||||
|
| tar -v -C /usr/src -xz
|
||||||
|
|
||||||
|
RUN cd /usr/src/go/src && ./make.bash --no-clean 2>&1
|
||||||
|
|
||||||
|
ENV PATH /usr/src/go/bin:$PATH
|
||||||
|
|
||||||
|
RUN mkdir -p /go/src /go/bin && chmod -R 777 /go
|
||||||
|
ENV GOPATH /go
|
||||||
|
ENV PATH /go/bin:$PATH
|
||||||
|
WORKDIR /go
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#
|
||||||
|
# Install SQL
|
||||||
|
#
|
||||||
|
|
||||||
|
ENV MYSQL_ROOT_PASSWORD=mostest
|
||||||
|
ENV MYSQL_USER=mmuser
|
||||||
|
ENV MYSQL_PASSWORD=mostest
|
||||||
|
ENV MYSQL_DATABASE=mattermost_test
|
||||||
|
|
||||||
|
RUN groupadd -r mysql && useradd -r -g mysql mysql
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y perl --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN apt-key adv --keyserver pool.sks-keyservers.net --recv-keys A4A9406876FCBD3C456770C88C718D3B5072E1F5
|
||||||
|
|
||||||
|
ENV MYSQL_MAJOR 5.6
|
||||||
|
ENV MYSQL_VERSION 5.6.25
|
||||||
|
|
||||||
|
RUN echo "deb http://repo.mysql.com/apt/debian/ wheezy mysql-${MYSQL_MAJOR}" > /etc/apt/sources.list.d/mysql.list
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& export DEBIAN_FRONTEND=noninteractive \
|
||||||
|
&& apt-get -y install mysql-server \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& rm -rf /var/lib/mysql && mkdir -p /var/lib/mysql
|
||||||
|
|
||||||
|
RUN sed -Ei 's/^(bind-address|log)/#&/' /etc/mysql/my.cnf
|
||||||
|
|
||||||
|
VOLUME /var/lib/mysql
|
||||||
|
# ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#
|
||||||
|
# Install Redis
|
||||||
|
#
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y wget
|
||||||
|
RUN wget http://download.redis.io/redis-stable.tar.gz; \
|
||||||
|
tar xvzf redis-stable.tar.gz; \
|
||||||
|
cd redis-stable; \
|
||||||
|
make install
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Copy over files
|
||||||
|
ADD . /go/src/github.com/mattermost/platform
|
||||||
|
|
||||||
|
# Insert postfix config
|
||||||
|
ADD ./docker/main.cf /etc/postfix/
|
||||||
|
|
||||||
|
RUN go get github.com/tools/godep
|
||||||
|
RUN cd /go/src/github.com/mattermost/platform; godep restore
|
||||||
|
RUN go install github.com/mattermost/platform
|
||||||
|
RUN cd /go/src/github.com/mattermost/platform/web/react; npm install
|
||||||
|
|
||||||
|
RUN chmod +x /go/src/github.com/mattermost/platform/docker/docker-entry.sh
|
||||||
|
ENTRYPOINT /go/src/github.com/mattermost/platform/docker/docker-entry.sh
|
||||||
|
|
||||||
|
# Ports
|
||||||
|
EXPOSE 80
|
||||||
11
NOTICE.txt
11
NOTICE.txt
@@ -1,4 +1,11 @@
|
|||||||
Mattermost Platform Preview
|
Mattermost Platform Preview
|
||||||
Copyright 2015 SpinPunch, Inc.
|
© 2015 Spinpunch, Inc. All Rights Reserved. See LICENSE.txt for license information.
|
||||||
|
|
||||||
Regular expression support is provided by the PCRE library package, which is open source software, written by Philip Hazel, and copyright by the University of Cambridge, England. The original software is available from ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/
|
NOTICES:
|
||||||
|
|
||||||
|
This product contains a modified portion of 'draw2d', a Go library to draw 2d geometrical forms on images by Laurent Le Goff
|
||||||
|
|
||||||
|
* LICENSE:
|
||||||
|
* http://opensource.org/licenses/BSD-3-Clause (BSD 3-Clause)
|
||||||
|
* HOMEPAGE:
|
||||||
|
* https://code.google.com/p/draw2d/
|
||||||
|
|||||||
33
README.md
33
README.md
@@ -1,4 +1,4 @@
|
|||||||
**Mattermost (Preview)<br>**
|
**Mattermost Preview<br>**
|
||||||
**Team Communication Service<br>**
|
**Team Communication Service<br>**
|
||||||
**Version 0.40**
|
**Version 0.40**
|
||||||
|
|
||||||
@@ -21,23 +21,24 @@ That said, any issues at all, please let us know on the Mattermost forum at: htt
|
|||||||
Developer Machine Setup (Mac)
|
Developer Machine Setup (Mac)
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
DOCKER
|
DOCKER SETUP
|
||||||
|
|
||||||
1. Follow the instructions at http://docs.docker.com/installation/mac/ Use the Boot2Docker command-line utility
|
1. Follow the instructions at http://docs.docker.com/installation/mac/
|
||||||
If you do command-line setup use: `boot2docker init eval “$(boot2docker shellinit)”`
|
<br>a) Use the Boot2Docker command-line utility
|
||||||
|
<br>b) If you do command-line setup use: `boot2docker init eval “$(boot2docker shellinit)”`
|
||||||
2. Get your Docker IP address with `boot2docker ip`
|
2. Get your Docker IP address with `boot2docker ip`
|
||||||
3. Add a line to your /etc/hosts that goes `<Docker IP> dockerhost`
|
3. Add a line to your /etc/hosts that goes `<Docker IP> dockerhost`
|
||||||
4. Run `boot2docker shellinit` and copy the export statements to your ~/.bash_profile
|
4. Run `boot2docker shellinit` and copy the export statements to your ~/.bash_profile
|
||||||
|
|
||||||
Any issues? Please let us know on our forums at: http://bit.ly/1MY1kul
|
Any issues? Please let us know on our forums at: http://bit.ly/1MY1kul
|
||||||
|
|
||||||
GO
|
GO SETUP
|
||||||
|
|
||||||
1. Download Go from http://golang.org/dl/
|
1. Download Go from http://golang.org/dl/
|
||||||
|
|
||||||
NODE.JS SETUP
|
NODE.JS SETUP
|
||||||
|
|
||||||
1. Install homebrew from brew.sh
|
1. Install homebrew from http://brew.sh
|
||||||
2. `brew install node`
|
2. `brew install node`
|
||||||
|
|
||||||
COMPASS SETUP
|
COMPASS SETUP
|
||||||
@@ -47,23 +48,19 @@ COMPASS SETUP
|
|||||||
|
|
||||||
MATTERMOST SETUP
|
MATTERMOST SETUP
|
||||||
|
|
||||||
1. Make a project directory for Mattermost, which will for the rest of this document be referred to as $PROJECT
|
1. Make a project directory for Mattermost, which we'll call **$PROJECT** for the rest of these instructions
|
||||||
2. Make a go directory in your $PROJECT directory
|
2. Make a `go` directory in your $PROJECT directory
|
||||||
3. Create/Open your ~/.bash_profile and add the following lines: `export GOPATH=$PROJECT/go export PATH=$PATH:$GOPATH/bin`
|
3. Open or create your ~/.bash_profile and add the following lines: <br> `export GOPATH=$PROJECT/go`<br> `export PATH=$PATH:$GOPATH/bin` <br>then refresh your bash profile with `source ~/.bash_profile`
|
||||||
4. Refresh your bash profile with `source ~/.bash_profile`
|
4. Then use `cd $GOPATH` and `mkdir -p src/github.com/mattermost` then cd into this directory and run `git clone github.com/mattermost/platform.git`
|
||||||
5. `cd $GOPATH`
|
5. If you do not have Mercurial, download it with: `brew install mercurial`
|
||||||
6. `mkdir -p src/github.com/mattermost` then cd into this directory
|
6. Then do `cd platform` and `make test`. Provided the test runs fine, you now have a complete build environment.
|
||||||
7. `git clone github.com/mattermost/platform.git`
|
7. Use `make run` to run your code
|
||||||
8. If you do not have Mercurial, download it with: `brew install mercurial`
|
|
||||||
9. `cd platform`
|
|
||||||
10. `make test`
|
|
||||||
11. Provided the test runs fine, you now have a complete build environment. Use `make run` to run your code
|
|
||||||
|
|
||||||
Any issues? Please let us know on our forums at: http://bit.ly/1MY1kul
|
Any issues? Please let us know on our forums at: http://bit.ly/1MY1kul
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
Mattermost Preview uses the Apache 2.0 open source license. For more details see: http://bit.ly/1Lc25Sv<br>
|
This software uses the Apache 2.0 open source license. For more details see: http://bit.ly/1Lc25Sv<br>
|
||||||
|
|
||||||
**XXXXXX TODO: Test install procedures**
|
**XXXXXX TODO: Test install procedures**
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"FileLocation": ""
|
"FileLocation": ""
|
||||||
},
|
},
|
||||||
"ServiceSettings": {
|
"ServiceSettings": {
|
||||||
"SiteName": "XXXXXXMustBeFilledIn",
|
"SiteName": "Mattermost Preview",
|
||||||
"Domain": "xxxxxxmustbefilledin.com",
|
"Domain": "xxxxxxmustbefilledin.com",
|
||||||
"Mode" : "dev",
|
"Mode" : "dev",
|
||||||
"AllowTesting" : false,
|
"AllowTesting" : false,
|
||||||
@@ -57,6 +57,7 @@
|
|||||||
"SMTPUsername": "",
|
"SMTPUsername": "",
|
||||||
"SMTPPassword": "",
|
"SMTPPassword": "",
|
||||||
"SMTPServer": "",
|
"SMTPServer": "",
|
||||||
|
"UseTLS": false,
|
||||||
"FeedbackEmail": "feedback@xxxxxxmustbefilledin.com",
|
"FeedbackEmail": "feedback@xxxxxxmustbefilledin.com",
|
||||||
"FeedbackName": "",
|
"FeedbackName": "",
|
||||||
"ApplePushServer": "",
|
"ApplePushServer": "",
|
||||||
|
|||||||
85
config/config_docker.json
Обычный файл
85
config/config_docker.json
Обычный файл
@@ -0,0 +1,85 @@
|
|||||||
|
{
|
||||||
|
"LogSettings": {
|
||||||
|
"ConsoleEnable": false,
|
||||||
|
"ConsoleLevel": "DEBUG",
|
||||||
|
"FileEnable": true,
|
||||||
|
"FileLevel": "INFO",
|
||||||
|
"FileFormat": "",
|
||||||
|
"FileLocation": ""
|
||||||
|
},
|
||||||
|
"ServiceSettings": {
|
||||||
|
"SiteName": "Mattermost Preview",
|
||||||
|
"Domain": "",
|
||||||
|
"Mode" : "prod",
|
||||||
|
"AllowTesting" : false,
|
||||||
|
"UseSSL": false,
|
||||||
|
"Port": "80",
|
||||||
|
"Version": "developer",
|
||||||
|
"Shards": {
|
||||||
|
},
|
||||||
|
"InviteSalt": "gxHVDcKUyP2y1eiyW8S8na1UYQAfq6J6",
|
||||||
|
"PublicLinkSalt": "TO3pTyXIZzwHiwyZgGql7lM7DG3zeId4",
|
||||||
|
"ResetSalt": "IPxFzSfnDFsNsRafZxz8NaYqFKhf9y2t",
|
||||||
|
"AnalyticsUrl": ""
|
||||||
|
},
|
||||||
|
"SqlSettings": {
|
||||||
|
"DriverName": "mysql",
|
||||||
|
"DataSource": "mmuser:mostest@tcp(localhost:3306)/mattermost_test",
|
||||||
|
"DataSourceReplicas": ["mmuser:mostest@tcp(localhost:3306)/mattermost_test"],
|
||||||
|
"MaxIdleConns": 10,
|
||||||
|
"MaxOpenConns": 10,
|
||||||
|
"Trace": false,
|
||||||
|
"AtRestEncryptKey": "Ya0xMrybACJ3sZZVWQC7e31h5nSDWZFS"
|
||||||
|
},
|
||||||
|
"RedisSettings": {
|
||||||
|
"DataSource": "localhost:6379",
|
||||||
|
"MaxOpenConns": 1000
|
||||||
|
},
|
||||||
|
"AWSSettings": {
|
||||||
|
"S3AccessKeyId": "",
|
||||||
|
"S3SecretAccessKey": "",
|
||||||
|
"S3Bucket": "",
|
||||||
|
"S3Region": "",
|
||||||
|
"Route53AccessKeyId": "",
|
||||||
|
"Route53SecretAccessKey": "",
|
||||||
|
"Route53ZoneId": "",
|
||||||
|
"Route53Region": ""
|
||||||
|
},
|
||||||
|
"ImageSettings": {
|
||||||
|
"ThumbnailWidth": 200,
|
||||||
|
"ThumbnailHeight": 0,
|
||||||
|
"PreviewWidth": 1024,
|
||||||
|
"PreviewHeight": 0,
|
||||||
|
"ProfileWidth": 128,
|
||||||
|
"ProfileHeight": 128
|
||||||
|
},
|
||||||
|
"EmailSettings": {
|
||||||
|
"SMTPUsername": "",
|
||||||
|
"SMTPPassword": "",
|
||||||
|
"SMTPServer": "localhost:25",
|
||||||
|
"UseTLS": false,
|
||||||
|
"FeedbackEmail": "feedback@xxxxxxmustbefilledin.com",
|
||||||
|
"FeedbackName": "",
|
||||||
|
"ApplePushServer": "",
|
||||||
|
"ApplePushCertPublic": "",
|
||||||
|
"ApplePushCertPrivate": ""
|
||||||
|
},
|
||||||
|
"PrivacySettings": {
|
||||||
|
"ShowEmailAddress": true,
|
||||||
|
"ShowPhoneNumber": true,
|
||||||
|
"ShowSkypeId": true,
|
||||||
|
"ShowFullName": true
|
||||||
|
},
|
||||||
|
"TeamSettings": {
|
||||||
|
"MaxUsersPerTeam": 150,
|
||||||
|
"AllowPublicLink": true,
|
||||||
|
"AllowValet": false,
|
||||||
|
"TermsLink": "/static/help/configure_links.html",
|
||||||
|
"PrivacyLink": "/static/help/configure_links.html",
|
||||||
|
"AboutLink": "/static/help/configure_links.html",
|
||||||
|
"HelpLink": "/static/help/configure_links.html",
|
||||||
|
"ReportProblemLink": "/static/help/configure_links.html",
|
||||||
|
"TourLink": "/static/help/configure_links.html",
|
||||||
|
"DefaultThemeColor": "#2389D7"
|
||||||
|
}
|
||||||
|
}
|
||||||
122
docker/docker-entry.sh
Исполняемый файл
122
docker/docker-entry.sh
Исполняемый файл
@@ -0,0 +1,122 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||||
|
# See License.txt for license information.
|
||||||
|
|
||||||
|
mkdir -p web/static/js
|
||||||
|
|
||||||
|
echo "127.0.0.1 dockerhost" >> /etc/hosts
|
||||||
|
/etc/init.d/networking restart
|
||||||
|
|
||||||
|
echo configuring mysql
|
||||||
|
|
||||||
|
# SQL!!!
|
||||||
|
set -e
|
||||||
|
|
||||||
|
get_option () {
|
||||||
|
local section=$1
|
||||||
|
local option=$2
|
||||||
|
local default=$3
|
||||||
|
ret=$(my_print_defaults $section | grep '^--'${option}'=' | cut -d= -f2-)
|
||||||
|
[ -z $ret ] && ret=$default
|
||||||
|
echo $ret
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Get config
|
||||||
|
DATADIR="$("mysqld" --verbose --help 2>/dev/null | awk '$1 == "datadir" { print $2; exit }')"
|
||||||
|
SOCKET=$(get_option mysqld socket "$DATADIR/mysql.sock")
|
||||||
|
PIDFILE=$(get_option mysqld pid-file "/var/run/mysqld/mysqld.pid")
|
||||||
|
|
||||||
|
if [ ! -d "$DATADIR/mysql" ]; then
|
||||||
|
if [ -z "$MYSQL_ROOT_PASSWORD" -a -z "$MYSQL_ALLOW_EMPTY_PASSWORD" ]; then
|
||||||
|
echo >&2 'error: database is uninitialized and MYSQL_ROOT_PASSWORD not set'
|
||||||
|
echo >&2 ' Did you forget to add -e MYSQL_ROOT_PASSWORD=... ?'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$DATADIR"
|
||||||
|
chown -R mysql:mysql "$DATADIR"
|
||||||
|
|
||||||
|
echo 'Running mysql_install_db'
|
||||||
|
mysql_install_db --user=mysql --datadir="$DATADIR" --rpm --keep-my-cnf
|
||||||
|
echo 'Finished mysql_install_db'
|
||||||
|
|
||||||
|
mysqld --user=mysql --datadir="$DATADIR" --skip-networking &
|
||||||
|
for i in $(seq 30 -1 0); do
|
||||||
|
[ -S "$SOCKET" ] && break
|
||||||
|
echo 'MySQL init process in progress...'
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
if [ $i = 0 ]; then
|
||||||
|
echo >&2 'MySQL init process failed.'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# These statements _must_ be on individual lines, and _must_ end with
|
||||||
|
# semicolons (no line breaks or comments are permitted).
|
||||||
|
# TODO proper SQL escaping on ALL the things D:
|
||||||
|
|
||||||
|
tempSqlFile=$(mktemp /tmp/mysql-first-time.XXXXXX.sql)
|
||||||
|
cat > "$tempSqlFile" <<-EOSQL
|
||||||
|
-- What's done in this file shouldn't be replicated
|
||||||
|
-- or products like mysql-fabric won't work
|
||||||
|
SET @@SESSION.SQL_LOG_BIN=0;
|
||||||
|
|
||||||
|
DELETE FROM mysql.user ;
|
||||||
|
CREATE USER 'root'@'%' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;
|
||||||
|
GRANT ALL ON *.* TO 'root'@'%' WITH GRANT OPTION ;
|
||||||
|
DROP DATABASE IF EXISTS test ;
|
||||||
|
EOSQL
|
||||||
|
|
||||||
|
if [ "$MYSQL_DATABASE" ]; then
|
||||||
|
echo "CREATE DATABASE IF NOT EXISTS \`$MYSQL_DATABASE\` ;" >> "$tempSqlFile"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$MYSQL_USER" -a "$MYSQL_PASSWORD" ]; then
|
||||||
|
echo "CREATE USER '"$MYSQL_USER"'@'%' IDENTIFIED BY '"$MYSQL_PASSWORD"' ;" >> "$tempSqlFile"
|
||||||
|
|
||||||
|
if [ "$MYSQL_DATABASE" ]; then
|
||||||
|
echo "GRANT ALL ON \`"$MYSQL_DATABASE"\`.* TO '"$MYSQL_USER"'@'%' ;" >> "$tempSqlFile"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo 'FLUSH PRIVILEGES ;' >> "$tempSqlFile"
|
||||||
|
|
||||||
|
mysql -uroot < "$tempSqlFile"
|
||||||
|
|
||||||
|
rm -f "$tempSqlFile"
|
||||||
|
kill $(cat $PIDFILE)
|
||||||
|
for i in $(seq 30 -1 0); do
|
||||||
|
[ -f "$PIDFILE" ] || break
|
||||||
|
echo 'MySQL init process in progress...'
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
if [ $i = 0 ]; then
|
||||||
|
echo >&2 'MySQL hangs during init process.'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo 'MySQL init process done. Ready for start up.'
|
||||||
|
fi
|
||||||
|
|
||||||
|
chown -R mysql:mysql "$DATADIR"
|
||||||
|
|
||||||
|
mysqld &
|
||||||
|
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
# ------------------------
|
||||||
|
|
||||||
|
echo starting postfix
|
||||||
|
/etc/init.d/postfix restart
|
||||||
|
|
||||||
|
echo starting redis
|
||||||
|
redis-server &
|
||||||
|
|
||||||
|
echo starting react processor
|
||||||
|
cd /go/src/github.com/mattermost/platform/web/react && npm start &
|
||||||
|
|
||||||
|
echo starting go web server
|
||||||
|
cd /go/src/github.com/mattermost/platform/; go run mattermost.go -config=config_docker.json &
|
||||||
|
|
||||||
|
echo starting compass watch
|
||||||
|
cd /go/src/github.com/mattermost/platform/web/sass-files && compass watch
|
||||||
28
docker/main.cf
Обычный файл
28
docker/main.cf
Обычный файл
@@ -0,0 +1,28 @@
|
|||||||
|
myorigin = mattermost.com
|
||||||
|
myhostname = mattermost.com
|
||||||
|
|
||||||
|
smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu)
|
||||||
|
biff = no
|
||||||
|
|
||||||
|
append_dot_mydomain = no
|
||||||
|
|
||||||
|
readme_directory = no
|
||||||
|
|
||||||
|
# TLS parameters
|
||||||
|
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
|
||||||
|
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
|
||||||
|
smtpd_use_tls=no
|
||||||
|
smtp_use_tls=no
|
||||||
|
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
|
||||||
|
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
|
||||||
|
|
||||||
|
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
|
||||||
|
alias_maps = hash:/etc/aliases
|
||||||
|
alias_database = hash:/etc/aliases
|
||||||
|
mydestination = localhost, localhost.localdomain, localhost
|
||||||
|
relayhost =
|
||||||
|
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
|
||||||
|
mailbox_size_limit = 0
|
||||||
|
recipient_delimiter = +
|
||||||
|
inet_interfaces = all
|
||||||
|
inet_protocols = all
|
||||||
@@ -109,7 +109,10 @@ func TestTeamStoreGetByDomain(t *testing.T) {
|
|||||||
o1.Domain = "a" + model.NewId() + "b"
|
o1.Domain = "a" + model.NewId() + "b"
|
||||||
o1.Email = model.NewId() + "@nowhere.com"
|
o1.Email = model.NewId() + "@nowhere.com"
|
||||||
o1.Type = model.TEAM_OPEN
|
o1.Type = model.TEAM_OPEN
|
||||||
<-store.Team().Save(&o1)
|
|
||||||
|
if err := (<-store.Team().Save(&o1)).Err; err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
if r1 := <-store.Team().GetByDomain(o1.Domain); r1.Err != nil {
|
if r1 := <-store.Team().GetByDomain(o1.Domain); r1.Err != nil {
|
||||||
t.Fatal(r1.Err)
|
t.Fatal(r1.Err)
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ type EmailSettings struct {
|
|||||||
SMTPUsername string
|
SMTPUsername string
|
||||||
SMTPPassword string
|
SMTPPassword string
|
||||||
SMTPServer string
|
SMTPServer string
|
||||||
|
UseTLS bool
|
||||||
FeedbackEmail string
|
FeedbackEmail string
|
||||||
FeedbackName string
|
FeedbackName string
|
||||||
ApplePushServer string
|
ApplePushServer string
|
||||||
@@ -216,6 +217,16 @@ func LoadConfig(fileName string) {
|
|||||||
panic("Error decoding configuration " + err.Error())
|
panic("Error decoding configuration " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Grabs the domain from enviroment variable if not in configuration
|
||||||
|
if config.ServiceSettings.Domain == "" {
|
||||||
|
config.ServiceSettings.Domain = os.Getenv("MATTERMOST_DOMAIN")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validates our mail settings
|
||||||
|
if err := CheckMailSettings(); err != nil {
|
||||||
|
l4g.Error("Email settings are not valid err=%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
configureLog(config.LogSettings)
|
configureLog(config.LogSettings)
|
||||||
|
|
||||||
Cfg = &config
|
Cfg = &config
|
||||||
|
|||||||
@@ -4,9 +4,24 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConfig(t *testing.T) {
|
func TestConfig(t *testing.T) {
|
||||||
LoadConfig("config.json")
|
LoadConfig("config.json")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEnvOverride(t *testing.T) {
|
||||||
|
os.Setenv("MATTERMOST_DOMAIN", "testdomain.com")
|
||||||
|
|
||||||
|
LoadConfig("config_docker.json")
|
||||||
|
if Cfg.ServiceSettings.Domain != "testdomain.com" {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadConfig("config.json")
|
||||||
|
if Cfg.ServiceSettings.Domain == "testdomain.com" {
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,6 +13,69 @@ import (
|
|||||||
"net/smtp"
|
"net/smtp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func CheckMailSettings() *model.AppError {
|
||||||
|
if len(Cfg.EmailSettings.SMTPServer) == 0 {
|
||||||
|
return model.NewAppError("CheckMailSettings", "No email settings present, mail will not be sent", "")
|
||||||
|
}
|
||||||
|
conn, err := connectToSMTPServer()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
c, err2 := newSMTPClient(conn)
|
||||||
|
if err2 != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer c.Quit()
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func connectToSMTPServer() (net.Conn, *model.AppError) {
|
||||||
|
host, _, _ := net.SplitHostPort(Cfg.EmailSettings.SMTPServer)
|
||||||
|
|
||||||
|
var conn net.Conn
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if Cfg.EmailSettings.UseTLS {
|
||||||
|
tlsconfig := &tls.Config{
|
||||||
|
InsecureSkipVerify: true,
|
||||||
|
ServerName: host,
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err = tls.Dial("tcp", Cfg.EmailSettings.SMTPServer, tlsconfig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("SendMail", "Failed to open TLS connection", err.Error())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
conn, err = net.Dial("tcp", Cfg.EmailSettings.SMTPServer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, model.NewAppError("SendMail", "Failed to open connection", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSMTPClient(conn net.Conn) (*smtp.Client, *model.AppError) {
|
||||||
|
host, _, _ := net.SplitHostPort(Cfg.EmailSettings.SMTPServer)
|
||||||
|
c, err := smtp.NewClient(conn, host)
|
||||||
|
if err != nil {
|
||||||
|
l4g.Error("Failed to open a connection to SMTP server %v", err)
|
||||||
|
return nil, model.NewAppError("SendMail", "Failed to open TLS connection", err.Error())
|
||||||
|
}
|
||||||
|
// GO does not support plain auth over a non encrypted connection.
|
||||||
|
// so if not tls then no auth
|
||||||
|
auth := smtp.PlainAuth("", Cfg.EmailSettings.SMTPUsername, Cfg.EmailSettings.SMTPPassword, host)
|
||||||
|
if Cfg.EmailSettings.UseTLS {
|
||||||
|
if err = c.Auth(auth); err != nil {
|
||||||
|
return nil, model.NewAppError("SendMail", "Failed to authenticate on SMTP server", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
}
|
||||||
|
|
||||||
func SendMail(to, subject, body string) *model.AppError {
|
func SendMail(to, subject, body string) *model.AppError {
|
||||||
|
|
||||||
fromMail := mail.Address{"", Cfg.EmailSettings.FeedbackEmail}
|
fromMail := mail.Address{"", Cfg.EmailSettings.FeedbackEmail}
|
||||||
@@ -36,38 +99,24 @@ func SendMail(to, subject, body string) *model.AppError {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
host, _, _ := net.SplitHostPort(Cfg.EmailSettings.SMTPServer)
|
conn, err1 := connectToSMTPServer()
|
||||||
|
if err1 != nil {
|
||||||
auth := smtp.PlainAuth("", Cfg.EmailSettings.SMTPUsername, Cfg.EmailSettings.SMTPPassword, host)
|
return err1
|
||||||
|
|
||||||
tlsconfig := &tls.Config{
|
|
||||||
InsecureSkipVerify: true,
|
|
||||||
ServerName: host,
|
|
||||||
}
|
|
||||||
|
|
||||||
conn, err := tls.Dial("tcp", Cfg.EmailSettings.SMTPServer, tlsconfig)
|
|
||||||
if err != nil {
|
|
||||||
return model.NewAppError("SendMail", "Failed to open TLS connection", err.Error())
|
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
c, err := smtp.NewClient(conn, host)
|
c, err2 := newSMTPClient(conn)
|
||||||
if err != nil {
|
if err2 != nil {
|
||||||
l4g.Error("Failed to open a connection to SMTP server %v", err)
|
return err2
|
||||||
return model.NewAppError("SendMail", "Failed to open TLS connection", err.Error())
|
|
||||||
}
|
}
|
||||||
defer c.Quit()
|
defer c.Quit()
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
|
|
||||||
if err = c.Auth(auth); err != nil {
|
if err := c.Mail(fromMail.Address); err != nil {
|
||||||
return model.NewAppError("SendMail", "Failed to authenticate on SMTP server", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = c.Mail(fromMail.Address); err != nil {
|
|
||||||
return model.NewAppError("SendMail", "Failed to add from email address", err.Error())
|
return model.NewAppError("SendMail", "Failed to add from email address", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = c.Rcpt(toMail.Address); err != nil {
|
if err := c.Rcpt(toMail.Address); err != nil {
|
||||||
return model.NewAppError("SendMail", "Failed to add to email address", err.Error())
|
return model.NewAppError("SendMail", "Failed to add to email address", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,20 +52,20 @@ var FindTeamDomain = React.createClass({
|
|||||||
<div>
|
<div>
|
||||||
<span className="signup-team__name">{ config.SiteName }</span>
|
<span className="signup-team__name">{ config.SiteName }</span>
|
||||||
<br/>
|
<br/>
|
||||||
<span className="signup-team__subdomain">Enter your {strings.TeamPlural} domain.</span>
|
<span className="signup-team__subdomain">Enter your {strings.Team}'s domain.</span>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
</div>
|
</div>
|
||||||
<form onSubmit={this.handleSubmit}>
|
<form onSubmit={this.handleSubmit}>
|
||||||
<div className={server_error ? 'form-group has-error' : 'form-group'}>
|
<div className={server_error ? 'form-group has-error' : 'form-group'}>
|
||||||
{ server_error }
|
{ server_error }
|
||||||
<input type="text" className="form-control" name="domain" ref="domain" placeholder="teamdomain" />
|
<input type="text" className="form-control" name="domain" ref="domain" placeholder="team domain" />
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<button type="submit" className="btn btn-primary">Continue</button>
|
<button type="submit" className="btn btn-primary">Continue</button>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span>Don't remember your {strings.TeamPlural} domain? <a href="/find_team">Find it here</a></span>
|
<span>Don't remember your {strings.Team}'s domain? <a href="/find_team">Find it here</a></span>
|
||||||
</div>
|
</div>
|
||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
@@ -74,7 +74,7 @@ var FindTeamDomain = React.createClass({
|
|||||||
<br/>
|
<br/>
|
||||||
<br/>
|
<br/>
|
||||||
<div>
|
<div>
|
||||||
<span>{"Want to create your own " + strings.Team + "?"} <a href="/" className="signup-team-login">Sign up now</a></span>
|
<span>{"Want to create your own " + strings.Team + "?"} <a href={utils.getHomeLink()} className="signup-team-login">Sign up now</a></span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -188,7 +188,7 @@ module.exports = React.createClass({
|
|||||||
<a href="/reset_password">I forgot my password</a>
|
<a href="/reset_password">I forgot my password</a>
|
||||||
</div>
|
</div>
|
||||||
<div className="external-link">
|
<div className="external-link">
|
||||||
<span>{"Want to create your own " + strings.Team + "?"} <a href={config.HomeLink} className="signup-team-login">Sign up now</a></span>
|
<span>{"Want to create your own " + strings.Team + "?"} <a href={utils.getHomeLink()} className="signup-team-login">Sign up now</a></span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -444,17 +444,13 @@ module.exports = React.createClass({
|
|||||||
if (post.create_at > last_viewed && !rendered_last_viewed) {
|
if (post.create_at > last_viewed && !rendered_last_viewed) {
|
||||||
rendered_last_viewed = true;
|
rendered_last_viewed = true;
|
||||||
postCtls.push(
|
postCtls.push(
|
||||||
<div>
|
<div className="new-seperator">
|
||||||
<div className="new-seperator">
|
<hr id="new_message" className="new-seperator__hr" />
|
||||||
<hr id="new_message" className="new-seperator__hr" />
|
<div className="new-seperator__text">New Messages</div>
|
||||||
<div className="new-seperator__text">New Messages</div>
|
</div>
|
||||||
</div>
|
|
||||||
{postCtl}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
postCtls.push(postCtl);
|
|
||||||
}
|
}
|
||||||
|
postCtls.push(postCtl);
|
||||||
previousPostDay = utils.getDateForUnixTicks(post.create_at);
|
previousPostDay = utils.getDateForUnixTicks(post.create_at);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -467,7 +467,8 @@ UsernamePage = React.createClass({
|
|||||||
</div>
|
</div>
|
||||||
{ name_error }
|
{ name_error }
|
||||||
</div>
|
</div>
|
||||||
<p>{"Pick something " + strings.Team + "mates will recognize. Your username is how you will appear to others"}</p>
|
<p>{"Pick something " + strings.Team + "mates will recognize. Your username is how you will appear to others."}</p>
|
||||||
|
<p>It can be made of lowercase letters and numbers.</p>
|
||||||
<button className="btn btn-default" onClick={this.submitBack}><i className="glyphicon glyphicon-chevron-left"></i> Back</button>
|
<button className="btn btn-default" onClick={this.submitBack}><i className="glyphicon glyphicon-chevron-left"></i> Back</button>
|
||||||
<button className="btn-primary btn" onClick={this.submitNext}>Next<i className="glyphicon glyphicon-chevron-right"></i></button>
|
<button className="btn-primary btn" onClick={this.submitNext}>Next<i className="glyphicon glyphicon-chevron-right"></i></button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ module.exports = React.createClass({
|
|||||||
<img className="signup-team-logo" src="/static/images/logo.png" />
|
<img className="signup-team-logo" src="/static/images/logo.png" />
|
||||||
<h4>Welcome to { config.SiteName }</h4>
|
<h4>Welcome to { config.SiteName }</h4>
|
||||||
<p>{"Choose your username and password for the " + this.props.team_name + " " + strings.Team +"."}</p>
|
<p>{"Choose your username and password for the " + this.props.team_name + " " + strings.Team +"."}</p>
|
||||||
|
<p>Your username can be made of lowercase letters and numbers.</p>
|
||||||
<label className="control-label">Username</label>
|
<label className="control-label">Username</label>
|
||||||
<div className={ name_error ? "form-group has-error" : "form-group" }>
|
<div className={ name_error ? "form-group has-error" : "form-group" }>
|
||||||
<input type="text" ref="name" className="form-control" placeholder="" maxLength="128" />
|
<input type="text" ref="name" className="form-control" placeholder="" maxLength="128" />
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ module.exports = React.createClass({
|
|||||||
|
|
||||||
// If there is a space after the last @, nothing to do.
|
// If there is a space after the last @, nothing to do.
|
||||||
if (lastSpace > atIndex || lastCharSpace > atIndex) {
|
if (lastSpace > atIndex || lastCharSpace > atIndex) {
|
||||||
this.setState({ mentionText: '-1' });
|
this.updateMentionTab('-1', null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -730,3 +730,15 @@ Image.prototype.load = function(url, progressCallback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Image.prototype.completedPercentage = 0;
|
Image.prototype.completedPercentage = 0;
|
||||||
|
|
||||||
|
module.exports.getHomeLink = function() {
|
||||||
|
if (config.HomeLink != "") {
|
||||||
|
return config.HomeLink;
|
||||||
|
}
|
||||||
|
var parts = window.location.host.split(".");
|
||||||
|
if (parts.length <= 1) {
|
||||||
|
return window.location.protocol + "//" + window.location.host;
|
||||||
|
}
|
||||||
|
parts[0] = "www";
|
||||||
|
return window.location.protocol + "//" + parts.join(".");
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ var config = {
|
|||||||
AboutLink: "/static/help/configure_links.html",
|
AboutLink: "/static/help/configure_links.html",
|
||||||
HelpLink: "/static/help/configure_links.html",
|
HelpLink: "/static/help/configure_links.html",
|
||||||
ReportProblemLink: "/static/help/configure_links.html",
|
ReportProblemLink: "/static/help/configure_links.html",
|
||||||
HomeLink: "http://localhost:8065",
|
HomeLink: "",
|
||||||
|
|
||||||
ThemeColors: ["#2389d7", "#008a17", "#dc4fad", "#ac193d", "#0072c6", "#d24726", "#ff8f32", "#82ba00", "#03b3b2", "#008299", "#4617b4", "#8c0095", "#004b8b", "#004b8b", "#570000", "#380000", "#585858", "#000000"]
|
ThemeColors: ["#2389d7", "#008a17", "#dc4fad", "#ac193d", "#0072c6", "#d24726", "#ff8f32", "#82ba00", "#03b3b2", "#008299", "#4617b4", "#8c0095", "#004b8b", "#004b8b", "#570000", "#380000", "#585858", "#000000"]
|
||||||
};
|
};
|
||||||
@@ -35,4 +35,4 @@ var strings = {
|
|||||||
TeamPlural: "teams",
|
TeamPlural: "teams",
|
||||||
Company: "company",
|
Company: "company",
|
||||||
CompanyPlural: "companies"
|
CompanyPlural: "companies"
|
||||||
}
|
};
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user