Skip to content
This repository has been archived by the owner on Oct 1, 2019. It is now read-only.

Commit

Permalink
Merge stable into master
Browse files Browse the repository at this point in the history
  • Loading branch information
indeyets committed Nov 1, 2016
2 parents 4cf017d + 2ecccb0 commit 1500467
Show file tree
Hide file tree
Showing 24 changed files with 354 additions and 316 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"bookshelf": "^0.10.0",
"bunyan": "^1.8.1",
"chokidar": "^1.4.2",
"classnames": "~2.2.5",
"crypto": "0.0.3",
"dynamic-bem-classnames": "^1.0.2",
"ejs": "^2.3.4",
Expand Down Expand Up @@ -103,7 +104,8 @@
"strftime": "^0.9.2",
"twitter-text": "^1.13.2",
"url-assembler": "^1.2.4",
"uuid": "^2.0.1"
"uuid": "^2.0.1",
"zxcvbn": "~4.4.1"
},
"devDependencies": {
"adm-zip": "^0.4.7",
Expand Down
1 change: 0 additions & 1 deletion src/components/register.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,6 @@ export class Register extends React.Component {
if (!keys(this.state).find(v => v === attr)) {
return;
}

const input = field.value.replace(/[\f\n\r\t\v0-9]/g, '');
this.setState({ [attr]: input });

Expand Down
193 changes: 108 additions & 85 deletions src/components/settings/password-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,95 +16,102 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { PropTypes } from 'react';
import { form as inform, from } from 'react-inform';
import { form as inform, from, DisabledFormSubmit } from 'react-inform';
import { omit, reduce } from 'lodash';
import classNames from 'classnames';
import zxcvbn from 'zxcvbn';

import Message from '../message';

class PasswordForm extends React.Component {
static displayName = 'PasswordForm';

static propTypes = {
fields: PropTypes.shape({
oldPassword: PropTypes.shape({
error: PropTypes.string
}).isRequired,
newPassword: PropTypes.shape({
error: PropTypes.string
}).isRequired,
newPasswordRepeat: PropTypes.shape({
error: PropTypes.string
}).isRequired
const staticFields = {
oldPassword: {
label: 'Current password:'
},
newPassword: {
label: 'New password:'
},
newPasswordRepeat: {
label: 'Repeat new password:'
},
};

const PasswordForm = ({ fields, form, onSubmit }) => (
<form action="" autoComplete="off" onSubmit={onSubmit}>
<input name="autofillWorkaround" style={{ display: 'none' }} type="password" />

{reduce(
fields,
(acc, fieldValue, fieldName) => {
const wrapClassName = classNames('input_wrap', {
'input_wrap-error': !!fieldValue.error
});

acc.push(
<div key={fieldName}>
<div className="form__row tools_page__item tools_page__item--close">
<label className="form__label" htmlFor={fieldName}>
{staticFields[fieldName].label}
</label>
<div className={wrapClassName}>
<input
autoFocus={fieldName === 'oldPassword'}
className="input input-block input-narrow input-transparent"
id={fieldName}
name={fieldName}
required
type="password"
{...omit(fieldValue, ['error'])}
/>
</div>
</div>
{fieldValue.error &&
<div>
<Message message={fieldValue.error} />
</div>
}
</div>
);

return acc;
},
[]
)}

{form.isValid() &&
<div className="layout__raw_grid layout__raw_grid--reverse tools_page__item tools_page__item--close tools_page__item--flex">
<DisabledFormSubmit
className="button button-wide button-green button--new"
type="submit"
value="Save"
/>
</div>
}
</form>
);

PasswordForm.displayName = 'PasswordForm';

PasswordForm.propTypes = {
fields: PropTypes.shape({
oldPassword: PropTypes.shape({
error: PropTypes.string
}).isRequired,
newPassword: PropTypes.shape({
error: PropTypes.string
}).isRequired,
form: PropTypes.shape({
forceValidate: PropTypes.func.isRequired,
isValid: PropTypes.func.isRequired,
onValues: PropTypes.func.isRequired
newPasswordRepeat: PropTypes.shape({
error: PropTypes.string
}).isRequired
};

render() {
const { fields, form } = this.props;

return (
<form action="" className="paper__page" autoComplete={false}>
<h2 className="content__sub_title layout__row">Password</h2>

<input name="autofillWorkaround" style={{ display: 'none' }} type="password" />

<div className="layout__row">
<label className="layout__row layout__row-small" htmlFor="oldPassword">Current password</label>
<input
className="input input-block layout__row layout__row-small"
id="oldPassword"
name="oldPassword"
placeholder="secret"
required
type="password"
onChange={this._validateOldPassword}
{...fields.oldPassword}
/>
{fields.oldPassword.error &&
<Message message={fields.oldPassword.error} />
}
</div>

<div className="layout__row">
<label className="layout__row layout__row-small" htmlFor="newPassword">New password</label>
<input
className="input input-block layout__row layout__row-small"
id="newPassword"
name="newPassword"
placeholder="mystery"
required
type="password"
onChange={this._validateNewPassword}
{...fields.newPassword}
/>
{fields.newPassword.error &&
<Message message={fields.newPassword.error} />
}
</div>

<div className="layout__row">
<label className="layout__row layout__row-small" htmlFor="newPasswordRepeat">Repeat new password</label>
<input
className="input input-block layout__row layout__row-small"
id="newPasswordRepeat"
name="newPasswordRepeat"
placeholder="mystery"
required
type="password"
onChange={this._validateNewPasswordRepeat}
{...fields.newPasswordRepeat}
/>
{fields.newPasswordRepeat.error &&
<Message message={fields.newPasswordRepeat.error} />
}
</div>
</form>
);
}
}
}).isRequired,
form: PropTypes.shape({
isValid: PropTypes.func
}),
onSubmit: PropTypes.func
};

PasswordForm.defaultProps = {
onSubmit: () => {}
};

const validateNewPassword = (password) => {
if (password && password.length < 8) {
Expand All @@ -113,6 +120,20 @@ const validateNewPassword = (password) => {
return true;
};

const validateNewPasswordChars = (password) => {
if (!password.match(/[\x20-\x7E]$/)) {
return false;
}
return true;
};

const validateComplexity = (password) => {
if (zxcvbn(password).score < 3) {
return false;
}
return true;
};

const validateNewPasswordRepeat = (newPasswordRepeat, form) => {
if (form.newPassword !== newPasswordRepeat) {
return false;
Expand All @@ -126,7 +147,9 @@ const WrappedPasswordForm = inform(from({
},
newPassword: {
'Enter new password': n => n,
'Password must contain at least 8 symbols': validateNewPassword
'Password must contain at least 8 symbols': validateNewPassword,
'Password must contain only ASCII characters': validateNewPasswordChars,
'Password is too weak. Consider adding more words or symbols': validateComplexity
},
newPasswordRepeat: {
'Passwords don\'t match': validateNewPasswordRepeat
Expand Down
8 changes: 4 additions & 4 deletions src/components/tools/user-details.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export default function UserDetails({ current_user, following, triggers, user })
<div className="tools_page__details_col">
<div className="tools_details">
<div className="tools_details__left_col">
<Avatar isRound={false} size={140} user={user.toJS()} />
<Avatar isRound={false} size={140} user={user} />
</div>
<div>
<Link className="tools_details__title" to={`/user/${user.get('username')}`}>
Expand All @@ -49,10 +49,10 @@ export default function UserDetails({ current_user, following, triggers, user })
{fullName}
</div>
<FollowButton
active_user={current_user.toJS()}
following={following.toJS()}
active_user={current_user}
following={following}
triggers={triggers}
user={user.toJS()}
user={user}
/>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/tools/user-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default function UserList({ onClick, users, selectedUserId }) {
key={index}
onClick={handleClick}
>
<Avatar size={23} user={user.toJS()} />
<Avatar size={23} user={user} />
<span className="tools_item__child-padded">{user.get('username')}</span>
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const URL = {
[URL_NAMES.SETTINGS]: '/settings',
[URL_NAMES.EMAIL_SETTINGS]: '/settings/email',
[URL_NAMES.MANAGE_FOLLOWERS]: '/settings/followers',
[URL_NAMES.CHANGE_PASSWORD]: '/settings/password',
[URL_NAMES.CHANGE_PASSWORD]: '/tools/account/password',
[URL_NAMES.SCHOOL]: '/s/:url_name',
[URL_NAMES.HASHTAG]: '/tag/:name',
[URL_NAMES.GEOTAG]: '/geo/:url_name'
Expand Down
10 changes: 10 additions & 0 deletions src/less/blocks/button.less
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,13 @@
.button__icon {
margin-right: 5px;
}

.button--new {
padding: 15px 45px;
border-top-left-radius: 0px;
border-top-right-radius: 0px;
border-bottom-left-radius: 1px;
border-bottom-right-radius: 1px;
font-size: 12px;
line-height: 12px;
}
2 changes: 1 addition & 1 deletion src/less/blocks/color.less
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
@color__border: #d3d2d1;
@color__panel_bg: #f2eae3;

@color__green: #a2d544;
@color__green: #50a844;
@color__red: #fc2c5b;
@color__blue: #40b7e9;
@color__dark_blue: #689ACA;
Expand Down
16 changes: 16 additions & 0 deletions src/less/blocks/form.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.form {
&__row {
display: flex;

> * {
align-items: baseline;
}

.form__label {
flex-basis: 170px;
flex-shrink: 0;
text-align: right;
font-weight: bold;
}
}
}
31 changes: 31 additions & 0 deletions src/less/blocks/input.less
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,33 @@
border-color: #f2f2f2;
background: #f2f2f2;
}

&-narrow {
padding-top: 0;
padding-right: 0;
padding-bottom: 0;
}
}

.input_wrap {
padding-right: 40px;
width: 100%;

&-error {
position: relative;

&::after {
content: '';
position: absolute;
top: 2px;
right: 2px;

width: 16px;
height: 16px;
border-radius: 50%;
background-color: #fb4d49;
}
}
}

.input-textarea {
Expand All @@ -68,3 +95,7 @@
display: block;
width: 100%;
}

.input__label {
padding: 7px 10px;
}
9 changes: 9 additions & 0 deletions src/less/blocks/layout.less
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@
overflow: hidden;
}

.layout__raw_grid {
display: flex;
flex-direction: row;

&--reverse {
flex-direction: row-reverse;
}
}

.layout__grid {
display: flex;
margin-top: -@space;
Expand Down

0 comments on commit 1500467

Please sign in to comment.