summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/README.md1
-rw-r--r--doc/api/Overview.md94
-rw-r--r--doc/install/Production-Ubuntu.md2
-rw-r--r--web/react/components/signup_user_complete.jsx27
-rw-r--r--web/react/package.json1
-rw-r--r--web/react/utils/constants.jsx23
-rw-r--r--web/react/utils/utils.jsx14
-rw-r--r--web/sass-files/sass/partials/_base.scss7
-rw-r--r--web/sass-files/sass/partials/_mentions.scss8
-rw-r--r--web/sass-files/sass/partials/_modal.scss3
-rw-r--r--web/sass-files/sass/partials/_search.scss10
-rw-r--r--web/sass-files/sass/partials/_settings.scss4
-rw-r--r--web/sass-files/sass/partials/_signup.scss3
13 files changed, 161 insertions, 36 deletions
diff --git a/doc/README.md b/doc/README.md
index d711b5d53..66af8f34c 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -19,6 +19,7 @@
- [Code Contribution Guidelines](developer/Code-Contribution-Guidelines.md)
- [Developer Machine Setup](developer/Setup.md)
- [Mattermost Style Guide](developer/Style-Guide.md)
+- [API Overview] (api/Overview.md)
## Usage Help
diff --git a/doc/api/Overview.md b/doc/api/Overview.md
new file mode 100644
index 000000000..02e11974e
--- /dev/null
+++ b/doc/api/Overview.md
@@ -0,0 +1,94 @@
+# API Overview
+
+This provides a basic overview of the Mattermost API. All examples assume there is a Mattermost instance running at http://localhost:8065.
+
+## Schema
+
+All API access is done through `yourdomain.com/api/v1/`, with all data being sent and received as JSON.
+
+
+## Authentication
+
+The majority of the Mattermost API involves interacting with teams. Therefore, most API methods require authentication as a user. There are two ways to authenticate into a Mattermost system.
+
+##### Session Token
+
+Make an HTTP POST to `yourdomain.com/api/v1/users/login` with a JSON body indicating the `name` of the team, the user's `email` and `password`.
+
+```
+curl -i -d '{"name":"exampleteam","email":"someone@nowhere.com","password":"thisisabadpassword"}' http://localhost:8065/api/v1/users/login
+```
+
+If successful, the response will contain a `Token` header and a User object in the body.
+
+```
+HTTP/1.1 200 OK
+Set-Cookie: MMSID=hyr5dmb1mbb49c44qmx4whniso; Path=/; Max-Age=2592000; HttpOnly
+Token: hyr5dmb1mbb49c44qmx4whniso
+X-Ratelimit-Limit: 10
+X-Ratelimit-Remaining: 9
+X-Ratelimit-Reset: 1
+X-Request-Id: smda55ckcfy89b6tia58shk5fh
+X-Version-Id: developer
+Date: Fri, 11 Sep 2015 13:21:14 GMT
+Content-Length: 657
+Content-Type: application/json; charset=utf-8
+
+{{user object as json}}
+```
+
+Include the `Token` as part of the `Authentication` header on your future API requests with the `Bearer` method.
+
+```
+curl -i -H 'Authorization: Bearer hyr5dmb1mbb49c44qmx4whniso' http://localhost:8065/api/v1/users/me
+```
+
+That's it! You should now be able to access the API as the user you logged in as.
+
+##### OAuth2
+
+Coming soon...
+
+
+## Client Errors
+
+All errors will return an appropriate HTTP response code along with the following JSON body:
+
+```
+{
+ "message": "", // the reason for the error
+ "detailed_error": "", // some extra details about the error
+ "request_id": "", // the ID of the request
+ "status_code": 0 // the HTTP status code
+}
+```
+
+
+## Rate Limiting
+
+Whenever you make an HTTP request to the Mattermost API you might notice the following headers included in the response:
+```
+X-Ratelimit-Limit: 10
+X-Ratelimit-Remaining: 9
+X-Ratelimit-Reset: 1441983590
+
+```
+
+These headers are telling you your current rate limit status.
+
+Header | Description
+--------------------- | -----------
+X-Ratelimit-Limit | The maximum number of requests you can make per second.
+X-Ratelimit-Remaining | The number of requests remaining in the current window.
+X-Ratelimit-Reset | The remaining UTC epoch seconds before the rate limit resets.
+
+If you exceed your rate limit for a window you will receive the following error in the body of the response:
+```
+HTTP/1.1 429 Too Many Requests
+Date: Tue, 10 Sep 2015 11:20:28 GMT
+X-RateLimit-Limit: 10
+X-RateLimit-Remaining: 0
+X-RateLimit-Reset: 1
+
+limit exceeded
+```
diff --git a/doc/install/Production-Ubuntu.md b/doc/install/Production-Ubuntu.md
index 0f1373c1a..05a56c412 100644
--- a/doc/install/Production-Ubuntu.md
+++ b/doc/install/Production-Ubuntu.md
@@ -8,7 +8,7 @@
## Set up Database Server
1. For the purposes of this guide we will assume this server has an IP address of 10.10.10.1
-1. Install PostgreSQL 9.3+ (or MySQL 5.2+)
+1. Install PostgreSQL 9.3+ (or MySQL 5.6+)
* ``` sudo apt-get install postgresql postgresql-contrib```
1. PostgreSQL created a user account called `postgres`. You will need to log into that account with:
* ``` sudo -i -u postgres```
diff --git a/web/react/components/signup_user_complete.jsx b/web/react/components/signup_user_complete.jsx
index ae3075495..4e17c6d06 100644
--- a/web/react/components/signup_user_complete.jsx
+++ b/web/react/components/signup_user_complete.jsx
@@ -20,8 +20,6 @@ export default class SignupUserComplete extends React.Component {
initialState.user = {};
initialState.user.team_id = this.props.teamId;
initialState.user.email = this.props.email;
- initialState.hash = this.props.hash;
- initialState.data = this.props.data;
initialState.original_email = this.props.email;
}
@@ -47,7 +45,7 @@ export default class SignupUserComplete extends React.Component {
return;
}
- const usernameError = Utils.isValidUsername(this.state.user.username);
+ const usernameError = Utils.isValidUsername(providedUsername);
if (usernameError === 'Cannot use a reserved word as a username.') {
this.setState({nameError: 'This username is reserved, please choose a new one.', emailError: '', passwordError: '', serverError: ''});
return;
@@ -67,26 +65,29 @@ export default class SignupUserComplete extends React.Component {
return;
}
+ const user = {
+ team_id: this.props.teamId,
+ email: providedEmail,
+ username: providedUsername,
+ password: providedPassword,
+ allow_marketing: true
+ };
+
this.setState({
- user: {
- email: providedEmail,
- username: providedUsername,
- password: providedPassword,
- allow_marketing: true
- },
+ user,
nameError: '',
emailError: '',
passwordError: '',
serverError: ''
});
- client.createUser(this.state.user, this.state.data, this.state.hash,
+ client.createUser(user, this.props.data, this.props.hash,
function createUserSuccess() {
client.track('signup', 'signup_user_02_complete');
- client.loginByEmail(this.props.teamName, this.state.user.email, this.state.user.password,
+ client.loginByEmail(this.props.teamName, user.email, user.password,
function emailLoginSuccess(data) {
- UserStore.setLastEmail(this.state.user.email);
+ UserStore.setLastEmail(user.email);
UserStore.setCurrentUser(data);
if (this.props.hash > 0) {
BrowserStore.setGlobalItem(this.props.hash, JSON.stringify({wizard: 'finished'}));
@@ -95,7 +96,7 @@ export default class SignupUserComplete extends React.Component {
}.bind(this),
function emailLoginFailure(err) {
if (err.message === 'Login failed because email address has not been verified') {
- window.location.href = '/verify_email?email=' + encodeURIComponent(this.state.user.email) + '&teamname=' + encodeURIComponent(this.props.teamName);
+ window.location.href = '/verify_email?email=' + encodeURIComponent(user.email) + '&teamname=' + encodeURIComponent(this.props.teamName);
} else {
this.setState({serverError: err.message});
}
diff --git a/web/react/package.json b/web/react/package.json
index 31295873b..a097b6aa8 100644
--- a/web/react/package.json
+++ b/web/react/package.json
@@ -10,7 +10,6 @@
"keymirror": "0.1.1",
"marked": "0.3.5",
"object-assign": "3.0.0",
- "react-zeroclipboard-mixin": "0.1.0",
"twemoji": "1.4.1"
},
"devDependencies": {
diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx
index 67414dc3b..aba63b91c 100644
--- a/web/react/utils/constants.jsx
+++ b/web/react/utils/constants.jsx
@@ -138,7 +138,8 @@ module.exports = {
newMessageSeparator: '#FF8800',
linkColor: '#2389d7',
buttonBg: '#2389d7',
- buttonColor: '#FFFFFF'
+ buttonColor: '#FFFFFF',
+ mentionHighlightBg: '#fff2bb'
},
organization: {
type: 'Organization',
@@ -159,7 +160,8 @@ module.exports = {
newMessageSeparator: '#FF8800',
linkColor: '#2f81b7',
buttonBg: '#1dacfc',
- buttonColor: '#FFFFFF'
+ buttonColor: '#FFFFFF',
+ mentionHighlightBg: '#fff2bb'
},
mattermostDark: {
type: 'Mattermost Dark',
@@ -180,15 +182,16 @@ module.exports = {
newMessageSeparator: '#5de5da',
linkColor: '#A4FFEB',
buttonBg: '#4CBBA4',
- buttonColor: '#FFFFFF'
+ buttonColor: '#FFFFFF',
+ mentionHighlightBg: '#338886'
},
windows10: {
type: 'Windows Dark',
sidebarBg: '#171717',
- sidebarText: '#eee',
+ sidebarText: '#999',
sidebarUnreadText: '#fff',
sidebarTextHoverBg: '#302e30',
- sidebarTextHoverColor: '#fff',
+ sidebarTextHoverColor: '#999',
sidebarTextActiveBg: '#484748',
sidebarTextActiveColor: '#FFFFFF',
sidebarHeaderBg: '#1f1f1f',
@@ -201,7 +204,8 @@ module.exports = {
newMessageSeparator: '#CC992D',
linkColor: '#0177e7',
buttonBg: '#0177e7',
- buttonColor: '#FFFFFF'
+ buttonColor: '#FFFFFF',
+ mentionHighlightBg: '#276198'
}
},
THEME_ELEMENTS: [
@@ -263,7 +267,7 @@ module.exports = {
},
{
id: 'newMessageSeparator',
- uiName: 'New message separator'
+ uiName: 'New Message Separator'
},
{
id: 'linkColor',
@@ -273,10 +277,13 @@ module.exports = {
id: 'buttonBg',
uiName: 'Button BG'
},
-
{
id: 'buttonColor',
uiName: 'Button Text'
+ },
+ {
+ id: 'mentionHighlightBg',
+ uiName: 'Mention Highlight BG'
}
]
};
diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx
index 307a311ab..b51d71254 100644
--- a/web/react/utils/utils.jsx
+++ b/web/react/utils/utils.jsx
@@ -468,6 +468,7 @@ export function applyTheme(theme) {
changeCss('.date-separator .separator__text, .new-separator .separator__text', 'background:' + theme.centerChannelBg, 1);
changeCss('.post-image__column .post-image__details', 'background:' + theme.centerChannelBg, 1);
changeCss('.sidebar--right, .dropdown-menu, .popover', 'background:' + theme.centerChannelBg, 1);
+ changeCss('.search-bar__container .search__form .search-bar, .form-control', 'background:' + theme.centerChannelBg, 1);
}
if (theme.centerChannelColor) {
@@ -491,20 +492,21 @@ export function applyTheme(theme) {
changeCss('.post-image__column', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 2);
changeCss('.post-image__column .post-image__details', 'color:' + theme.centerChannelColor, 2);
changeCss('.post-image__column a, .post-image__column a:hover, .post-image__column a:focus', 'color:' + theme.centerChannelColor, 1);
- changeCss('.search-bar__container .search__form .search-bar', 'background: transparent; color:' + theme.centerChannelColor, 1);
+ changeCss('.search-bar__container .search__form .search-bar, .form-control', 'color:' + theme.centerChannelColor, 2);
changeCss('@media(max-width: 768px){.search-bar__container .search__form .search-bar', 'background:' + changeOpacity(theme.centerChannelColor, 0.2) + '; color: inherit;', 1);
- changeCss('.search-bar__container .search__form', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1);
+ changeCss('.search-bar__container .search__form, .form-control', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1);
+ changeCss('.form-control:focus', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.3), 1);
changeCss('.channel-intro .channel-intro__content', 'background:' + changeOpacity(theme.centerChannelColor, 0.05), 1);
changeCss('.date-separator .separator__text', 'color:' + theme.centerChannelColor, 2);
changeCss('.date-separator .separator__hr, .modal-footer, .modal .custom-textarea, .post-right__container .post.post--root hr, .search-item-container', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1);
changeCss('.modal .custom-textarea:focus', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.3), 1);
changeCss('.channel-intro, .settings-modal .settings-table .settings-content .divider-dark, hr, .settings-modal .settings-table .settings-links', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.2), 1);
changeCss('.post.current--user .post-body, .post.post--comment.other--root.current--user .post-comment', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1);
- changeCss('.post.current--user .post-body, .post.post--comment.other--root.current--user .post-comment, .post.post--comment.other--root .post-comment, .post.same--root .post-body', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.07), 2);
+ changeCss('.post.current--user .post-body, .post.post--comment.other--root.current--user .post-comment, .post.post--comment.other--root .post-comment, .post.same--root .post-body, .modal .more-channel-table tbody>tr td, .member-div:first-child, .member-div', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.1), 2);
changeCss('@media(max-width: 1440px){.post.same--root', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.07), 2);
changeCss('@media(max-width: 1440px){.post.same--root', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.07), 2);
changeCss('@media(max-width: 1800px){.inner__wrap.move--left .post.post--comment.same--root', 'border-color:' + changeOpacity(theme.centerChannelColor, 0.07), 2);
- changeCss('.post:hover, .sidebar--right .sidebar--right__header, .settings-modal .settings-table .settings-content .section-min:hover', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1);
+ changeCss('.post:hover, .modal .more-channel-table tbody>tr:hover td, .sidebar--right .sidebar--right__header, .settings-modal .settings-table .settings-content .section-min:hover', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1);
changeCss('.date-separator.hovered--before:after, .date-separator.hovered--after:before, .new-separator.hovered--after:before, .new-separator.hovered--before:after', 'background:' + changeOpacity(theme.centerChannelColor, 0.07), 1);
changeCss('.command-name:hover, .mentions-name:hover, .mentions-focus, .dropdown-menu>li>a:focus, .dropdown-menu>li>a:hover', 'background:' + changeOpacity(theme.centerChannelColor, 0.15), 1);
changeCss('.post.current--user:hover .post-body ', 'background: none;', 1);
@@ -529,6 +531,10 @@ export function applyTheme(theme) {
if (theme.buttonColor) {
changeCss('.btn.btn-primary', 'color:' + theme.buttonColor, 2);
}
+
+ if (theme.mentionHighlightBg) {
+ changeCss('.mention-highlight, .search-highlight', 'background:' + theme.mentionHighlightBg, 1);
+ }
}
export function changeCss(className, classValue, classRepeat) {
// we need invisible container to store additional css definitions
diff --git a/web/sass-files/sass/partials/_base.scss b/web/sass-files/sass/partials/_base.scss
index 841db7c5a..4237ee1fa 100644
--- a/web/sass-files/sass/partials/_base.scss
+++ b/web/sass-files/sass/partials/_base.scss
@@ -97,6 +97,9 @@ a:focus, a:hover {
.form-control {
@include border-radius(2px);
+ &:focus {
+ @include box-shadow(none);
+ }
&.no-resize {
resize: none;
}
@@ -120,6 +123,10 @@ a:focus, a:hover {
z-index: 100;
}
+.nav>li>a:focus, .nav>li>a:hover {
+ background: transparent;
+}
+
.btn {
@include single-transition(all, 0.25s, ease-in);
@include border-radius(1px);
diff --git a/web/sass-files/sass/partials/_mentions.scss b/web/sass-files/sass/partials/_mentions.scss
index a2bd0dcea..fb74eb4f5 100644
--- a/web/sass-files/sass/partials/_mentions.scss
+++ b/web/sass-files/sass/partials/_mentions.scss
@@ -57,5 +57,11 @@
.mention-highlight {
background-color:#fff2bb;
- color: #333;
+ a {
+ color: inherit;
+ text-decoration: underline;
+ &:hover, &:active {
+ color: inherit;
+ }
+ }
} \ No newline at end of file
diff --git a/web/sass-files/sass/partials/_modal.scss b/web/sass-files/sass/partials/_modal.scss
index 96b26f251..2722333a4 100644
--- a/web/sass-files/sass/partials/_modal.scss
+++ b/web/sass-files/sass/partials/_modal.scss
@@ -144,11 +144,10 @@
font-size: 0.9em;
overflow: hidden;
text-overflow: ellipsis;
- color: #999;
+ @include opacity(0.8);
margin: 5px 0;
}
.more-channel-name {
- color: #444;
font-weight: 600;
font-size: 0.95em;
}
diff --git a/web/sass-files/sass/partials/_search.scss b/web/sass-files/sass/partials/_search.scss
index bcb8b5eac..a7b1ab190 100644
--- a/web/sass-files/sass/partials/_search.scss
+++ b/web/sass-files/sass/partials/_search.scss
@@ -104,7 +104,13 @@
padding: 10px;
}
-.search-highlight.theme, .search-highlight {
+.search-highlight {
background-color: #FFF2BB;
- color: #333;
+ a {
+ color: inherit;
+ text-decoration: underline;
+ &:hover, &:active {
+ color: inherit;
+ }
+ }
}
diff --git a/web/sass-files/sass/partials/_settings.scss b/web/sass-files/sass/partials/_settings.scss
index 42475efd5..9369cc097 100644
--- a/web/sass-files/sass/partials/_settings.scss
+++ b/web/sass-files/sass/partials/_settings.scss
@@ -240,10 +240,6 @@
margin-right:5px;
}
-.member-list-holder {
- background-color:#fff;
-}
-
.member-div {
border-bottom:1px solid lightgrey;
position:relative;
diff --git a/web/sass-files/sass/partials/_signup.scss b/web/sass-files/sass/partials/_signup.scss
index 924f0718a..47235eb50 100644
--- a/web/sass-files/sass/partials/_signup.scss
+++ b/web/sass-files/sass/partials/_signup.scss
@@ -12,6 +12,9 @@
&.padding--less {
padding-top: 50px;
}
+ .form-control:focus {
+ @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6));
+ }
h1, h2, h3, h4, h5, h6, p {
line-height: 1.3;