Skip to content
Snippets Groups Projects
Commit e9bc4a4a authored by Eugen Rochko's avatar Eugen Rochko
Browse files

Limit usernames to 30 chars, statuses to 500, open account after follow form success

parent 62b38482
No related branches found
No related tags found
No related merge requests found
......@@ -12,7 +12,7 @@ export function changeFollow(text) {
};
};
export function submitFollow() {
export function submitFollow(router) {
return function (dispatch, getState) {
dispatch(submitFollowRequest());
......@@ -20,6 +20,7 @@ export function submitFollow() {
uri: getState().getIn(['follow', 'text'])
}).then(function (response) {
dispatch(submitFollowSuccess(response.data));
router.push(`/accounts/${response.data.id}`);
}).catch(function (error) {
dispatch(submitFollowFail(error));
});
......
......@@ -22,6 +22,10 @@ const MediaGallery = React.createClass({
let bottom = 'auto';
let right = 'auto';
if (size === 1) {
width = 100;
}
if (size === 4 || (size === 3 && i > 0)) {
height = 50;
}
......
......@@ -18,9 +18,9 @@ const ActionBar = React.createClass({
return (
<div style={{ background: '#2f3441', display: 'flex', flexDirection: 'row', borderTop: '1px solid #363c4b', borderBottom: '1px solid #363c4b', padding: '10px 0' }}>
<div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton title='Reply' icon='reply' onClick={this.props.onReply.bind(this, status)} /></div>
<div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton active={status.get('reblogged')} title='Reblog' icon='retweet' onClick={this.props.onReblog.bind(this, status)} /></div>
<div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton active={status.get('favourited')} title='Favourite' icon='star' onClick={this.props.onFavourite.bind(this, status)} /></div>
<div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton title='Reply' icon='reply' onClick={() => this.props.onReply(status)} /></div>
<div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton active={status.get('reblogged')} title='Reblog' icon='retweet' onClick={() => this.props.onReblog(status)} /></div>
<div style={{ flex: '1 1 auto', textAlign: 'center' }}><IconButton active={status.get('favourited')} title='Favourite' icon='star' onClick={() => this.props.onFavourite(status)} /></div>
</div>
);
}
......
......@@ -3,15 +3,18 @@ import PureRenderMixin from 'react-addons-pure-render-mixin';
const CharacterCounter = React.createClass({
propTypes: {
text: React.PropTypes.string.isRequired
text: React.PropTypes.string.isRequired,
max: React.PropTypes.number.isRequired
},
mixins: [PureRenderMixin],
render () {
const diff = this.props.max - this.props.text.length;
return (
<span style={{ fontSize: '16px', cursor: 'default' }}>
{this.props.text.length}
{diff}
</span>
);
}
......
......@@ -53,7 +53,7 @@ const ComposeForm = React.createClass({
<div style={{ marginTop: '10px', overflow: 'hidden' }}>
<div style={{ float: 'right' }}><Button text='Publish' onClick={this.handleSubmit} disabled={this.props.is_submitting} /></div>
<div style={{ float: 'right', marginRight: '16px', lineHeight: '36px' }}><CharacterCounter text={this.props.text} /></div>
<div style={{ float: 'right', marginRight: '16px', lineHeight: '36px' }}><CharacterCounter max={500} text={this.props.text} /></div>
</div>
</div>
);
......
......@@ -3,6 +3,10 @@ import PureRenderMixin from 'react-addons-pure-render-mixin';
const FollowForm = React.createClass({
contextTypes: {
router: React.PropTypes.object
},
propTypes: {
text: React.PropTypes.string.isRequired,
is_submitting: React.PropTypes.bool,
......@@ -18,12 +22,12 @@ const FollowForm = React.createClass({
handleKeyUp (e) {
if (e.keyCode === 13) {
this.props.onSubmit();
this.handleSubmit();
}
},
handleSubmit () {
this.props.onSubmit();
this.props.onSubmit(this.context.router);
},
render () {
......
......@@ -15,8 +15,8 @@ const mapDispatchToProps = function (dispatch) {
dispatch(changeFollow(text));
},
onSubmit: function () {
dispatch(submitFollow());
onSubmit: function (router) {
dispatch(submitFollow(router));
}
}
};
......
......@@ -6,7 +6,7 @@ class Account < ApplicationRecord
# Local users
has_one :user, inverse_of: :account
validates :username, presence: true, format: { with: /\A[a-z0-9_]+\z/i, message: 'only letters, numbers and underscores' }, uniqueness: { scope: :domain, case_sensitive: false }, if: 'local?'
validates :username, presence: true, format: { with: /\A[a-z0-9_]+\z/i, message: 'only letters, numbers and underscores' }, uniqueness: { scope: :domain, case_sensitive: false }, length: { maximum: 30 }, if: 'local?'
validates :username, presence: true, uniqueness: { scope: :domain, case_sensitive: true }, unless: 'local?'
# Avatar upload
......
......@@ -15,7 +15,7 @@ class Status < ApplicationRecord
validates :account, presence: true
validates :uri, uniqueness: true, unless: 'local?'
validates :text, presence: true, if: Proc.new { |s| s.local? && !s.reblog? }
validates :text, presence: true, length: { maximum: 500 }, if: Proc.new { |s| s.local? && !s.reblog? }
scope :with_counters, -> { select('statuses.*, (select count(r.id) from statuses as r where r.reblog_of_id = statuses.id) as reblogs_count, (select count(f.id) from favourites as f where f.status_id = statuses.id) as favourites_count') }
scope :with_includes, -> { includes(:account, :media_attachments, :stream_entry, mentions: :account, reblog: [:account, mentions: :account], thread: :account) }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment