Merge that good fresh upstream shit
This commit is contained in:
commit
8deb2072ef
21 changed files with 253 additions and 23 deletions
3
Gemfile
3
Gemfile
|
@ -28,8 +28,7 @@ gem 'devise', '~> 4.2'
|
||||||
gem 'devise-two-factor', '~> 3.0'
|
gem 'devise-two-factor', '~> 3.0'
|
||||||
gem 'doorkeeper', '~> 4.2'
|
gem 'doorkeeper', '~> 4.2'
|
||||||
gem 'fast_blank', '~> 1.0'
|
gem 'fast_blank', '~> 1.0'
|
||||||
gem 'gemoji', '~> 3.0'
|
gem 'goldfinger', '~> 2.0'
|
||||||
gem 'goldfinger', '~> 1.2'
|
|
||||||
gem 'hiredis', '~> 0.6'
|
gem 'hiredis', '~> 0.6'
|
||||||
gem 'redis-namespace', '~> 1.5'
|
gem 'redis-namespace', '~> 1.5'
|
||||||
gem 'htmlentities', '~> 4.3'
|
gem 'htmlentities', '~> 4.3'
|
||||||
|
|
15
Gemfile.lock
15
Gemfile.lock
|
@ -163,13 +163,13 @@ GEM
|
||||||
fuubar (2.2.0)
|
fuubar (2.2.0)
|
||||||
rspec-core (~> 3.0)
|
rspec-core (~> 3.0)
|
||||||
ruby-progressbar (~> 1.4)
|
ruby-progressbar (~> 1.4)
|
||||||
gemoji (3.0.0)
|
|
||||||
globalid (0.4.0)
|
globalid (0.4.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
goldfinger (1.2.0)
|
goldfinger (2.0.0)
|
||||||
addressable (~> 2.4)
|
addressable (~> 2.5)
|
||||||
http (~> 2.0)
|
http (~> 2.2)
|
||||||
nokogiri (~> 1.6)
|
nokogiri (~> 1.8)
|
||||||
|
oj (~> 3.0)
|
||||||
hamlit (2.8.4)
|
hamlit (2.8.4)
|
||||||
temple (>= 0.8.0)
|
temple (>= 0.8.0)
|
||||||
thor
|
thor
|
||||||
|
@ -522,8 +522,7 @@ DEPENDENCIES
|
||||||
faker (~> 1.7)
|
faker (~> 1.7)
|
||||||
fast_blank (~> 1.0)
|
fast_blank (~> 1.0)
|
||||||
fuubar (~> 2.2)
|
fuubar (~> 2.2)
|
||||||
gemoji (~> 3.0)
|
goldfinger (~> 2.0)
|
||||||
goldfinger (~> 1.2)
|
|
||||||
hamlit-rails (~> 0.2)
|
hamlit-rails (~> 0.2)
|
||||||
hiredis (~> 0.6)
|
hiredis (~> 0.6)
|
||||||
htmlentities (~> 4.3)
|
htmlentities (~> 4.3)
|
||||||
|
@ -591,4 +590,4 @@ RUBY VERSION
|
||||||
ruby 2.4.1p111
|
ruby 2.4.1p111
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.15.1
|
1.15.2
|
||||||
|
|
|
@ -6,15 +6,26 @@ module Admin
|
||||||
@instances = ordered_instances
|
@instances = ordered_instances
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def resubscribe
|
||||||
|
params.require(:by_domain)
|
||||||
|
Pubsubhubbub::SubscribeWorker.push_bulk(subscribeable_accounts.pluck(:id))
|
||||||
|
redirect_to admin_instances_path
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def paginated_instances
|
def paginated_instances
|
||||||
Account.remote.by_domain_accounts.page(params[:page])
|
Account.remote.by_domain_accounts.page(params[:page])
|
||||||
end
|
end
|
||||||
|
|
||||||
helper_method :paginated_instances
|
helper_method :paginated_instances
|
||||||
|
|
||||||
def ordered_instances
|
def ordered_instances
|
||||||
paginated_instances.map { |account| Instance.new(account) }
|
paginated_instances.map { |account| Instance.new(account) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def subscribeable_accounts
|
||||||
|
Account.with_followers.remote.where(domain: params[:by_domain])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,19 +1,24 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module EmojiHelper
|
module EmojiHelper
|
||||||
EMOJI_PATTERN = /(?<=[^[:alnum:]:]|\n|^):([\w+-]+):(?=[^[:alnum:]:]|$)/x
|
|
||||||
|
|
||||||
def emojify(text)
|
def emojify(text)
|
||||||
return text if text.blank?
|
return text if text.blank?
|
||||||
|
|
||||||
text.gsub(EMOJI_PATTERN) do |match|
|
text.gsub(emoji_pattern) do |match|
|
||||||
emoji = Emoji.find_by_alias($1) # rubocop:disable Rails/DynamicFindBy,Style/PerlBackrefs
|
emoji = Emoji.instance.unicode($1) # rubocop:disable Style/PerlBackrefs
|
||||||
|
|
||||||
if emoji
|
if emoji
|
||||||
emoji.raw
|
emoji
|
||||||
else
|
else
|
||||||
match
|
match
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def emoji_pattern
|
||||||
|
@emoji_pattern ||=
|
||||||
|
/(?<=[^[:alnum:]:]|\n|^)
|
||||||
|
(#{Emoji.instance.names.map { |name| Regexp.escape(name) }.join('|')})
|
||||||
|
(?=[^[:alnum:]:]|$)/x
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,6 +28,7 @@ export const COMPOSE_SPOILERNESS_CHANGE = 'COMPOSE_SPOILERNESS_CHANGE';
|
||||||
export const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE';
|
export const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE';
|
||||||
export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE';
|
export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE';
|
||||||
export const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE';
|
export const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE';
|
||||||
|
export const COMPOSE_COMPOSING_CHANGE = 'COMPOSE_COMPOSING_CHANGE';
|
||||||
|
|
||||||
export const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT';
|
export const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT';
|
||||||
|
|
||||||
|
@ -288,3 +289,10 @@ export function insertEmojiCompose(position, emoji) {
|
||||||
emoji,
|
emoji,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function changeComposing(value) {
|
||||||
|
return {
|
||||||
|
type: COMPOSE_COMPOSING_CHANGE,
|
||||||
|
value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import Avatar from '../../../components/avatar';
|
import Avatar from '../../../components/avatar';
|
||||||
|
import IconButton from '../../../components/icon_button';
|
||||||
import Permalink from '../../../components/permalink';
|
import Permalink from '../../../components/permalink';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
@ -9,6 +11,7 @@ export default class NavigationBar extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
account: ImmutablePropTypes.map.isRequired,
|
account: ImmutablePropTypes.map.isRequired,
|
||||||
|
onClose: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
@ -25,6 +28,8 @@ export default class NavigationBar extends ImmutablePureComponent {
|
||||||
|
|
||||||
<a href='/settings/profile' className='navigation-bar__profile-edit'><FormattedMessage id='navigation_bar.edit_profile' defaultMessage='Edit profile' /></a>
|
<a href='/settings/profile' className='navigation-bar__profile-edit'><FormattedMessage id='navigation_bar.edit_profile' defaultMessage='Edit profile' /></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<IconButton title='' icon='close' onClick={this.props.onClose} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import SearchContainer from './containers/search_container';
|
||||||
import Motion from 'react-motion/lib/Motion';
|
import Motion from 'react-motion/lib/Motion';
|
||||||
import spring from 'react-motion/lib/spring';
|
import spring from 'react-motion/lib/spring';
|
||||||
import SearchResultsContainer from './containers/search_results_container';
|
import SearchResultsContainer from './containers/search_results_container';
|
||||||
|
import { changeComposing } from '../../actions/compose';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
start: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
|
start: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
|
||||||
|
@ -59,6 +60,14 @@ export default class Compose extends React.PureComponent {
|
||||||
this.props.dispatch(openModal('SETTINGS', {}));
|
this.props.dispatch(openModal('SETTINGS', {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onFocus = () => {
|
||||||
|
this.props.dispatch(changeComposing(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
onBlur = () => {
|
||||||
|
this.props.dispatch(changeComposing(false));
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { multiColumn, showSearch, intl } = this.props;
|
const { multiColumn, showSearch, intl } = this.props;
|
||||||
|
|
||||||
|
@ -96,8 +105,8 @@ export default class Compose extends React.PureComponent {
|
||||||
<SearchContainer />
|
<SearchContainer />
|
||||||
|
|
||||||
<div className='drawer__pager'>
|
<div className='drawer__pager'>
|
||||||
<div className='drawer__inner'>
|
<div className='drawer__inner' onFocus={this.onFocus}>
|
||||||
<NavigationContainer />
|
<NavigationContainer onClose={this.onBlur} />
|
||||||
<ComposeFormContainer />
|
<ComposeFormContainer />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ const mapStateToProps = state => ({
|
||||||
systemFontUi: state.getIn(['meta', 'system_font_ui']),
|
systemFontUi: state.getIn(['meta', 'system_font_ui']),
|
||||||
layout: state.getIn(['local_settings', 'layout']),
|
layout: state.getIn(['local_settings', 'layout']),
|
||||||
isWide: state.getIn(['local_settings', 'stretch']),
|
isWide: state.getIn(['local_settings', 'stretch']),
|
||||||
|
isComposing: state.getIn(['compose', 'is_composing']),
|
||||||
});
|
});
|
||||||
|
|
||||||
@connect(mapStateToProps)
|
@connect(mapStateToProps)
|
||||||
|
@ -56,6 +57,7 @@ export default class UI extends React.PureComponent {
|
||||||
layout: PropTypes.string,
|
layout: PropTypes.string,
|
||||||
isWide: PropTypes.bool,
|
isWide: PropTypes.bool,
|
||||||
systemFontUi: PropTypes.bool,
|
systemFontUi: PropTypes.bool,
|
||||||
|
isComposing: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
|
@ -137,6 +139,19 @@ export default class UI extends React.PureComponent {
|
||||||
this.props.dispatch(refreshNotifications());
|
this.props.dispatch(refreshNotifications());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shouldComponentUpdate (nextProps) {
|
||||||
|
if (nextProps.isComposing !== this.props.isComposing) {
|
||||||
|
// Avoid expensive update just to toggle a class
|
||||||
|
this.node.classList.toggle('is-composing', nextProps.isComposing);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Why isn't this working?!?
|
||||||
|
// return super.shouldComponentUpdate(nextProps, nextState);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
window.removeEventListener('resize', this.handleResize);
|
window.removeEventListener('resize', this.handleResize);
|
||||||
document.removeEventListener('dragenter', this.handleDragEnter);
|
document.removeEventListener('dragenter', this.handleDragEnter);
|
||||||
|
|
|
@ -21,6 +21,7 @@ import {
|
||||||
COMPOSE_SPOILERNESS_CHANGE,
|
COMPOSE_SPOILERNESS_CHANGE,
|
||||||
COMPOSE_SPOILER_TEXT_CHANGE,
|
COMPOSE_SPOILER_TEXT_CHANGE,
|
||||||
COMPOSE_VISIBILITY_CHANGE,
|
COMPOSE_VISIBILITY_CHANGE,
|
||||||
|
COMPOSE_COMPOSING_CHANGE,
|
||||||
COMPOSE_EMOJI_INSERT,
|
COMPOSE_EMOJI_INSERT,
|
||||||
} from '../actions/compose';
|
} from '../actions/compose';
|
||||||
import { TIMELINE_DELETE } from '../actions/timelines';
|
import { TIMELINE_DELETE } from '../actions/timelines';
|
||||||
|
@ -41,6 +42,7 @@ const initialState = ImmutableMap({
|
||||||
focusDate: null,
|
focusDate: null,
|
||||||
preselectDate: null,
|
preselectDate: null,
|
||||||
in_reply_to: null,
|
in_reply_to: null,
|
||||||
|
is_composing: false,
|
||||||
is_submitting: false,
|
is_submitting: false,
|
||||||
is_uploading: false,
|
is_uploading: false,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
|
@ -154,7 +156,9 @@ export default function compose(state = initialState, action) {
|
||||||
case COMPOSE_MOUNT:
|
case COMPOSE_MOUNT:
|
||||||
return state.set('mounted', true);
|
return state.set('mounted', true);
|
||||||
case COMPOSE_UNMOUNT:
|
case COMPOSE_UNMOUNT:
|
||||||
return state.set('mounted', false);
|
return state
|
||||||
|
.set('mounted', false)
|
||||||
|
.set('is_composing', false);
|
||||||
case COMPOSE_ADVANCED_OPTIONS_CHANGE:
|
case COMPOSE_ADVANCED_OPTIONS_CHANGE:
|
||||||
return state
|
return state
|
||||||
.set('advanced_options',
|
.set('advanced_options',
|
||||||
|
@ -182,6 +186,8 @@ export default function compose(state = initialState, action) {
|
||||||
return state
|
return state
|
||||||
.set('text', action.text)
|
.set('text', action.text)
|
||||||
.set('idempotencyKey', uuid());
|
.set('idempotencyKey', uuid());
|
||||||
|
case COMPOSE_COMPOSING_CHANGE:
|
||||||
|
return state.set('is_composing', action.value);
|
||||||
case COMPOSE_REPLY:
|
case COMPOSE_REPLY:
|
||||||
return state.withMutations(map => {
|
return state.withMutations(map => {
|
||||||
map.set('in_reply_to', action.status.get('id'));
|
map.set('in_reply_to', action.status.get('id'));
|
||||||
|
|
|
@ -90,6 +90,20 @@ function main() {
|
||||||
noteCounter.textContent = 500 - length(noteWithoutMetadata);
|
noteCounter.textContent = 500 - length(noteWithoutMetadata);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
delegate(document, '#account_avatar', 'change', ({ target }) => {
|
||||||
|
const avatar = document.querySelector('.card.compact .avatar img');
|
||||||
|
const [file] = target.files || [];
|
||||||
|
const url = URL.createObjectURL(file);
|
||||||
|
avatar.src = url;
|
||||||
|
});
|
||||||
|
|
||||||
|
delegate(document, '#account_header', 'change', ({ target }) => {
|
||||||
|
const header = document.querySelector('.card.compact');
|
||||||
|
const [file] = target.files || [];
|
||||||
|
const url = URL.createObjectURL(file);
|
||||||
|
header.style.backgroundImage = `url(${url})`;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
loadPolyfills().then(main).catch(error => {
|
loadPolyfills().then(main).catch(error => {
|
||||||
|
|
|
@ -31,6 +31,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.compact {
|
||||||
|
padding: 30px 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
img {
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
display: block;
|
display: block;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
@ -1464,6 +1464,11 @@
|
||||||
.permalink {
|
.permalink {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-button {
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation-bar__profile {
|
.navigation-bar__profile {
|
||||||
|
@ -4160,3 +4165,66 @@ noscript {
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 1024px) and (max-height: 400px) {
|
||||||
|
$duration: 400ms;
|
||||||
|
$delay: 100ms;
|
||||||
|
|
||||||
|
.tabs-bar,
|
||||||
|
.search {
|
||||||
|
will-change: margin-top;
|
||||||
|
transition: margin-top $duration $delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation-bar {
|
||||||
|
will-change: padding-bottom;
|
||||||
|
transition: padding-bottom $duration $delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation-bar {
|
||||||
|
& > a:first-child {
|
||||||
|
will-change: margin-top, margin-left, width;
|
||||||
|
transition: margin-top $duration $delay, margin-left $duration ($duration + $delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .navigation-bar__profile-edit {
|
||||||
|
will-change: margin-top;
|
||||||
|
transition: margin-top $duration $delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > .icon-button {
|
||||||
|
will-change: opacity;
|
||||||
|
transition: opacity $duration $delay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.is-composing {
|
||||||
|
.tabs-bar,
|
||||||
|
.search {
|
||||||
|
margin-top: -50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation-bar {
|
||||||
|
padding-bottom: 0;
|
||||||
|
|
||||||
|
& > a:first-child {
|
||||||
|
margin-top: -50px;
|
||||||
|
margin-left: -40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation-bar__profile {
|
||||||
|
padding-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navigation-bar__profile-edit {
|
||||||
|
position: absolute;
|
||||||
|
margin-top: -50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-button {
|
||||||
|
pointer-events: auto;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -40,6 +40,10 @@ code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
strong {
|
strong {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
40
app/lib/emoji.rb
Normal file
40
app/lib/emoji.rb
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'singleton'
|
||||||
|
|
||||||
|
class Emoji
|
||||||
|
include Singleton
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
data = Oj.load(File.open(File.join(Rails.root, 'lib', 'assets', 'emoji.json')))
|
||||||
|
|
||||||
|
@map = {}
|
||||||
|
|
||||||
|
data.each do |_, emoji|
|
||||||
|
keys = [emoji['shortname']] + emoji['aliases']
|
||||||
|
unicode = codepoint_to_unicode(emoji['unicode'])
|
||||||
|
|
||||||
|
keys.each do |key|
|
||||||
|
@map[key] = unicode
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def unicode(shortcode)
|
||||||
|
@map[shortcode]
|
||||||
|
end
|
||||||
|
|
||||||
|
def names
|
||||||
|
@map.keys
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def codepoint_to_unicode(codepoint)
|
||||||
|
if codepoint.include?('-')
|
||||||
|
codepoint.split('-').map(&:hex).pack('U')
|
||||||
|
else
|
||||||
|
[codepoint.hex].pack('U')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,3 +3,5 @@
|
||||||
= instance.domain
|
= instance.domain
|
||||||
%td.count
|
%td.count
|
||||||
= instance.accounts_count
|
= instance.accounts_count
|
||||||
|
%td
|
||||||
|
= table_link_to 'paper-plane-o', t('admin.accounts.resubscribe'), resubscribe_admin_instances_url(by_domain: instance.domain), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }
|
||||||
|
|
|
@ -7,9 +7,16 @@
|
||||||
.fields-group
|
.fields-group
|
||||||
= f.input :display_name, placeholder: t('simple_form.labels.defaults.display_name'), hint: t('simple_form.hints.defaults.display_name', count: 30 - @account.display_name.size).html_safe
|
= f.input :display_name, placeholder: t('simple_form.labels.defaults.display_name'), hint: t('simple_form.hints.defaults.display_name', count: 30 - @account.display_name.size).html_safe
|
||||||
= f.input :note, placeholder: t('simple_form.labels.defaults.note'), hint: t('simple_form.hints.defaults.note', count: 500 - @account.note.size).html_safe
|
= f.input :note, placeholder: t('simple_form.labels.defaults.note'), hint: t('simple_form.hints.defaults.note', count: 500 - @account.note.size).html_safe
|
||||||
|
|
||||||
|
.card.compact{ style: "background-image: url(#{@account.header.url(:original)})" }
|
||||||
|
.avatar= image_tag @account.avatar.url(:original)
|
||||||
|
|
||||||
|
.fields-group
|
||||||
= f.input :avatar, wrapper: :with_label, input_html: { accept: AccountAvatar::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.avatar')
|
= f.input :avatar, wrapper: :with_label, input_html: { accept: AccountAvatar::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.avatar')
|
||||||
|
|
||||||
= f.input :header, wrapper: :with_label, input_html: { accept: AccountHeader::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.header')
|
= f.input :header, wrapper: :with_label, input_html: { accept: AccountHeader::IMAGE_MIME_TYPES.join(',') }, hint: t('simple_form.hints.defaults.header')
|
||||||
|
|
||||||
|
.fields-group
|
||||||
= f.input :locked, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.locked')
|
= f.input :locked, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.locked')
|
||||||
|
|
||||||
.actions
|
.actions
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
Warden::Manager.after_set_user except: :fetch do |user, warden|
|
Warden::Manager.after_set_user except: :fetch do |user, warden|
|
||||||
SessionActivation.deactivate warden.cookies.signed['_session_id']
|
if user.session_active?(warden.cookies.signed['_session_id'] || warden.raw_session['auth_id'])
|
||||||
|
session_id = warden.cookies.signed['_session_id'] || warden.raw_session['auth_id']
|
||||||
|
else
|
||||||
|
session_id = user.activate_session(warden.request)
|
||||||
|
end
|
||||||
|
|
||||||
warden.cookies.signed['_session_id'] = {
|
warden.cookies.signed['_session_id'] = {
|
||||||
value: user.activate_session(warden.request),
|
value: session_id,
|
||||||
expires: 1.year.from_now,
|
expires: 1.year.from_now,
|
||||||
httponly: true,
|
httponly: true,
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,12 @@ Rails.application.routes.draw do
|
||||||
resources :subscriptions, only: [:index]
|
resources :subscriptions, only: [:index]
|
||||||
resources :domain_blocks, only: [:index, :new, :create, :show, :destroy]
|
resources :domain_blocks, only: [:index, :new, :create, :show, :destroy]
|
||||||
resource :settings, only: [:edit, :update]
|
resource :settings, only: [:edit, :update]
|
||||||
resources :instances, only: [:index]
|
|
||||||
|
resources :instances, only: [:index] do
|
||||||
|
collection do
|
||||||
|
post :resubscribe
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
resources :reports, only: [:index, :show, :update] do
|
resources :reports, only: [:index, :show, :update] do
|
||||||
resources :reported_statuses, only: [:create, :update, :destroy]
|
resources :reported_statuses, only: [:create, :update, :destroy]
|
||||||
|
|
1
lib/assets/emoji.json
Normal file
1
lib/assets/emoji.json
Normal file
File diff suppressed because one or more lines are too long
15
spec/lib/emoji_spec.rb
Normal file
15
spec/lib/emoji_spec.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe Emoji do
|
||||||
|
describe '#unicode' do
|
||||||
|
it 'returns a unicode for a shortcode' do
|
||||||
|
expect(Emoji.instance.unicode(':joy:')).to eq '😂'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#names' do
|
||||||
|
it 'returns an array' do
|
||||||
|
expect(Emoji.instance.names).to be_an Array
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -78,7 +78,7 @@ RSpec.describe ResolveRemoteAccountService do
|
||||||
Thread.new do
|
Thread.new do
|
||||||
true while wait_for_start
|
true while wait_for_start
|
||||||
begin
|
begin
|
||||||
return_values << subject.call('foo@localdomain.com')
|
return_values << ResolveRemoteAccountService.new.call('foo@localdomain.com')
|
||||||
rescue ActiveRecord::RecordNotUnique
|
rescue ActiveRecord::RecordNotUnique
|
||||||
fail_occurred = true
|
fail_occurred = true
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue