Compare commits

...

15 Commits

Author SHA1 Message Date
Andrew 338b03bdfe Feature: add a rake task that's like register but also accepts password
and produces cleaner output
2019-05-22 16:04:48 -07:00
Eugen Rochko 370ec7e771 Bump version to 2.8.3 2019-05-19 22:35:49 +02:00
ThibG 9222c26e19 Fix “invited by” not showing up for invited accounts in admin interface (#10791) 2019-05-19 22:32:25 +02:00
Hinaloe 94439a1da7 fix `isSubmitting` prop case (#10785) 2019-05-19 22:32:14 +02:00
ThibG a6815a7578 Add post-deployment migration script to delete public-boosts-of-private-toots (#10783) 2019-05-19 16:27:11 +02:00
Ben Lubar d587a943a5 add og:image:alt for media attachments in embeds (#10779) 2019-05-19 16:26:00 +02:00
ThibG 3c27687a6e Prevent from publicly boosting one's own private toots (#10775) 2019-05-19 16:25:40 +02:00
ThibG ee17d81b8a Minor performance improvements and cleanup in formatter (#10765) 2019-05-19 16:25:39 +02:00
Neil Moore 9e95af3391 Adds click-able div that expands status (#10733) (#10766)
The clickable div is positioned under the account avatar and covers
all empty space below it to the end of the status.
2019-05-19 16:25:20 +02:00
nzws 91e25a20ce Fix some colors in light theme (#10754)
* Fix typo in light theme

* Fix background color of empty column
2019-05-19 16:25:20 +02:00
ThibG 47e0928c5b Change icon and label depending on whether media is marked as sensitive (#10748)
* Change icon and label depending on whether media is marked as sensitive

* WiP use a checkbox
2019-05-19 16:25:20 +02:00
Maciek Baron c407a4edf8 Improve poll link accessibility (#10720)
* Add distinction between hover and active/focus states
* Resolves #10198
2019-05-19 16:25:20 +02:00
Jeong Arm 7a6464bea0 Bring back crossed eye icon on gallery (#10715) 2019-05-19 16:25:20 +02:00
nzws 9679ec4fcb Fix some colors of high contrast theme (#10711)
* Fix "nothing here" text color of high contrast

* Fix counter border color of high contrast
2019-05-19 16:25:20 +02:00
ThibG b40dfc124b Add description on hover in media gallery (#10713) 2019-05-19 16:25:20 +02:00
20 changed files with 185 additions and 35 deletions

View File

@ -3,6 +3,28 @@ Changelog
All notable changes to this project will be documented in this file.
## [2.8.3] - 2019-05-19
### Added
- Add `og:image:alt` OpenGraph tag ([BenLubar](https://github.com/tootsuite/mastodon/pull/10779))
- Add clickable area below avatar in statuses in web UI ([Dar13](https://github.com/tootsuite/mastodon/pull/10766))
- Add crossed-out eye icon on account gallery in web UI ([Kjwon15](https://github.com/tootsuite/mastodon/pull/10715))
- Add media description tooltip to thumbnails in web UI ([ThibG](https://github.com/tootsuite/mastodon/pull/10713))
### Changed
- Change "mark as sensitive" button into a checkbox for clarity ([ThibG](https://github.com/tootsuite/mastodon/pull/10748))
### Fixed
- Fix bug allowing users to publicly boost their private statuses ([ThibG](https://github.com/tootsuite/mastodon/pull/10775), [ThibG](https://github.com/tootsuite/mastodon/pull/10783))
- Fix performance in formatter by a little ([ThibG](https://github.com/tootsuite/mastodon/pull/10765))
- Fix some colors in the light theme ([yuzulabo](https://github.com/tootsuite/mastodon/pull/10754))
- Fix some colors of the high contrast theme ([yuzulabo](https://github.com/tootsuite/mastodon/pull/10711))
- Fix ambivalent active state of poll refresh button in web UI ([MaciekBaron](https://github.com/tootsuite/mastodon/pull/10720))
- Fix duplicate posting being possible from web UI ([hinaloe](https://github.com/tootsuite/mastodon/pull/10785))
- Fix "invited by" not showing up in admin UI ([ThibG](https://github.com/tootsuite/mastodon/pull/10791))
## [2.8.2] - 2019-05-05
### Added

View File

@ -356,6 +356,7 @@ class Status extends ImmutablePureComponent {
{prepend}
<div className={classNames('status', `status-${status.get('visibility')}`, { 'status-reply': !!status.get('in_reply_to_id'), muted: this.props.muted, read: unread === false })} data-id={status.get('id')}>
<div className='status__expand' onClick={this.handleClick} role='presentation' />
<div className='status__info'>
<a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener'><RelativeTimestamp timestamp={status.get('created_at')} /></a>

View File

@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Icon from 'mastodon/components/icon';
import { autoPlayGif, displayMedia } from 'mastodon/initial_state';
import classNames from 'classnames';
import { decode } from 'blurhash';
@ -88,8 +89,10 @@ export default class MediaItem extends ImmutablePureComponent {
const width = `${Math.floor((displayWidth - 4) / 3) - 4}px`;
const height = width;
const status = attachment.get('status');
const title = status.get('spoiler_text') || attachment.get('description');
let thumbnail = '';
let icon;
if (attachment.get('type') === 'unknown') {
// Skip
@ -131,11 +134,20 @@ export default class MediaItem extends ImmutablePureComponent {
);
}
if (!visible) {
icon = (
<span className='account-gallery__item__icons'>
<Icon id='eye-slash' />
</span>
);
}
return (
<div className='account-gallery__item' style={{ width, height }}>
<a className='media-gallery__item-thumbnail' href={status.get('url')} target='_blank' onClick={this.handleClick}>
<a className='media-gallery__item-thumbnail' href={status.get('url')} target='_blank' onClick={this.handleClick} title={title}>
<canvas width={32} height={32} ref={this.setCanvasRef} className={classNames('media-gallery__preview', { 'media-gallery__preview--hidden': visible && loaded })} />
{visible && thumbnail}
{!visible && icon}
</a>
</div>
);

View File

@ -20,7 +20,7 @@ const mapStateToProps = state => ({
focusDate: state.getIn(['compose', 'focusDate']),
caretPosition: state.getIn(['compose', 'caretPosition']),
preselectDate: state.getIn(['compose', 'preselectDate']),
is_submitting: state.getIn(['compose', 'is_submitting']),
isSubmitting: state.getIn(['compose', 'is_submitting']),
isChangingUpload: state.getIn(['compose', 'is_changing_upload']),
isUploading: state.getIn(['compose', 'is_uploading']),
showSearch: state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']),

View File

@ -4,7 +4,6 @@ import PropTypes from 'prop-types';
import classNames from 'classnames';
import { changeComposeSensitivity } from 'mastodon/actions/compose';
import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
import Icon from 'mastodon/components/icon';
const messages = defineMessages({
marked: { id: 'compose_form.sensitive.marked', defaultMessage: 'Media is marked as sensitive' },
@ -38,9 +37,19 @@ class SensitiveButton extends React.PureComponent {
return (
<div className='compose-form__sensitive-button'>
<button className={classNames('icon-button', { active })} onClick={onClick} disabled={disabled} title={intl.formatMessage(active ? messages.marked : messages.unmarked)}>
<Icon id='eye-slash' /> <FormattedMessage id='compose_form.sensitive.hide' defaultMessage='Mark media as sensitive' />
</button>
<label className={classNames('icon-button', { active })} title={intl.formatMessage(active ? messages.marked : messages.unmarked)}>
<input
name='mark-sensitive'
type='checkbox'
checked={active}
onChange={onClick}
disabled={disabled}
/>
<span className={classNames('checkbox', { active })} />
<FormattedMessage id='compose_form.sensitive.hide' defaultMessage='Mark media as sensitive' />
</label>
</div>
);
}

View File

@ -67,3 +67,11 @@
text-decoration: none;
}
}
.nothing-here {
color: $darker-text-color;
}
.public-layout .public-account-header__tabs__tabs .counter.active::after {
border-bottom: 4px solid $ui-highlight-color;
}

View File

@ -162,7 +162,7 @@
.actions-modal ul li:not(:empty) a:focus button,
.actions-modal ul li:not(:empty) a:hover,
.actions-modal ul li:not(:empty) a:hover button,
.admin-wrapper .sidebar ul ul a.selected,
.admin-wrapper .sidebar ul li a.selected,
.simple_form .block-button,
.simple_form .button,
.simple_form button {
@ -230,6 +230,7 @@
.empty-column-indicator,
.error-column {
color: $primary-text-color;
background: $white;
}
// Change the default colors used on some parts of the profile pages

View File

@ -268,9 +268,34 @@
padding: 10px;
padding-top: 0;
.icon-button {
font-size: 14px;
font-weight: 500;
font-size: 14px;
font-weight: 500;
&.active {
color: $highlight-text-color;
}
input[type=checkbox] {
display: none;
}
.checkbox {
display: inline-block;
position: relative;
border: 1px solid $ui-primary-color;
box-sizing: border-box;
width: 18px;
height: 18px;
flex: 0 0 auto;
margin-right: 10px;
top: -1px;
border-radius: 4px;
vertical-align: middle;
&.active {
border-color: $highlight-text-color;
background: $highlight-text-color;
}
}
}
@ -1386,6 +1411,15 @@ a.account__display-name {
width: 48px;
}
.status__expand {
width: 68px;
position: absolute;
left: 0;
top: 0;
height: 100%;
cursor: pointer;
}
.muted {
.status__content p,
.status__content a {
@ -4829,6 +4863,14 @@ a.status-card.compact:hover {
border-radius: 4px;
overflow: hidden;
margin: 2px;
&__icons {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 24px;
}
}
.notification__filter-bar,

View File

@ -114,11 +114,14 @@
text-decoration: underline;
font-size: inherit;
&:hover,
&:focus,
&:active {
&:hover {
text-decoration: none;
}
&:active,
&:focus {
background-color: rgba($dark-text-color, .1);
}
}
.button {

View File

@ -187,7 +187,7 @@ class Formatter
end
def rewrite(text, entities)
chars = text.to_s.to_char_a
text = text.to_s
# Sort by start index
entities = entities.sort_by do |entity|
@ -199,12 +199,12 @@ class Formatter
last_index = entities.reduce(0) do |index, entity|
indices = entity.respond_to?(:indices) ? entity.indices : entity[:indices]
result << encode(chars[index...indices.first].join)
result << encode(text[index...indices.first])
result << yield(entity)
indices.last
end
result << encode(chars[last_index..-1].join)
result << encode(text[last_index..-1])
result.flatten.join
end
@ -231,23 +231,14 @@ class Formatter
# Note: I couldn't obtain list_slug with @user/list-name format
# for mention so this requires additional check
special = Extractor.extract_urls_with_indices(escaped, options).map do |extract|
# exactly one of :url, :hashtag, :screen_name, :cashtag keys is present
key = (extract.keys & [:url, :hashtag, :screen_name, :cashtag]).first
new_indices = [
old_to_new_index.find_index(extract[:indices].first),
old_to_new_index.find_index(extract[:indices].last),
]
has_prefix_char = [:hashtag, :screen_name, :cashtag].include?(key)
value_indices = [
new_indices.first + (has_prefix_char ? 1 : 0), # account for #, @ or $
new_indices.last - 1,
]
next extract.merge(
:indices => new_indices,
key => text[value_indices.first..value_indices.last]
indices: new_indices,
url: text[new_indices.first..new_indices.last - 1]
)
end

View File

@ -114,6 +114,10 @@ class User < ApplicationRecord
end
def invited?
invite_id.present?
end
def valid_invitation?
invite_id.present? && invite.valid_for_use?
end
@ -274,7 +278,7 @@ class User < ApplicationRecord
private
def set_approved
self.approved = open_registrations? || invited? || external?
self.approved = open_registrations? || valid_invitation? || external?
end
def open_registrations?

View File

@ -18,7 +18,9 @@ class ReblogService < BaseService
return reblog unless reblog.nil?
reblog = account.statuses.create!(reblog: reblogged_status, text: '', visibility: options[:visibility] || account.user&.setting_default_privacy)
visibility = options[:visibility] || account.user&.setting_default_privacy
visibility = reblogged_status.visibility if reblogged_status.hidden?
reblog = account.statuses.create!(reblog: reblogged_status, text: '', visibility: visibility)
DistributionWorker.perform_async(reblog.id)
Pubsubhubbub::DistributionWorker.perform_async(reblog.stream_entry.id)

View File

@ -2,7 +2,7 @@
class BlacklistedEmailValidator < ActiveModel::Validator
def validate(user)
return if user.invited?
return if user.valid_invitation?
@email = user.email

View File

@ -7,6 +7,8 @@
- unless media.file.meta.nil?
= opengraph 'og:image:width', media.file.meta.dig('original', 'width')
= opengraph 'og:image:height', media.file.meta.dig('original', 'height')
- if media.description.present?
= opengraph 'og:image:alt', media.description
- elsif media.video? || media.gifv?
- player_card = true
= opengraph 'og:image', full_asset_url(media.file.url(:small))

View File

@ -0,0 +1,23 @@
class RemoveBoostsWideningAudience < ActiveRecord::Migration[5.2]
disable_ddl_transaction!
def up
public_boosts = Status.find_by_sql(<<-SQL)
SELECT boost.id
FROM statuses AS boost
LEFT JOIN statuses AS boosted ON boost.reblog_of_id = boosted.id
WHERE
boost.id > 101746055577600000
AND (boost.local = TRUE OR boost.uri IS NULL)
AND boost.visibility IN (0, 1)
AND boost.reblog_of_id IS NOT NULL
AND boosted.visibility = 2
SQL
RemovalWorker.push_bulk(public_boosts.pluck(:id))
end
def down
raise ActiveRecord::IrreversibleMigration
end
end

View File

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2019_04_20_025523) do
ActiveRecord::Schema.define(version: 2019_05_19_130537) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

View File

@ -13,7 +13,7 @@ module Mastodon
end
def patch
2
3
end
def pre

View File

@ -388,6 +388,28 @@ namespace :mastodon do
end
end
desc 'Machine-readably add a user by providing their email, username and initial password.' \
'The user will receive a confirmation email.'
task add_user_automatic: :environment do
print 'Enter email: '
email = STDIN.gets.chomp
print 'Enter username: '
username = STDIN.gets.chomp
print 'Enter password: '
password = STDIN.gets.chomp
user = User.new(email: email, password: password, account_attributes: { username: username })
if user.save
puts 'User added and confirmation mail sent to user\'s email address.'
else
user.errors.each do |key, val|
STDERR.puts "#{key}: #{val}"
end
end
end
namespace :webpush do
desc 'Generate VAPID key'
task generate_vapid_key: :environment do

View File

@ -4,10 +4,9 @@ RSpec.describe ReblogService, type: :service do
let(:alice) { Fabricate(:account, username: 'alice') }
context 'creates a reblog with appropriate visibility' do
let(:bob) { Fabricate(:account, username: 'bob') }
let(:visibility) { :public }
let(:reblog_visibility) { :public }
let(:status) { Fabricate(:status, account: bob, visibility: visibility) }
let(:status) { Fabricate(:status, account: alice, visibility: visibility) }
subject { ReblogService.new }
@ -22,6 +21,15 @@ RSpec.describe ReblogService, type: :service do
expect(status.reblogs.first.visibility).to eq 'private'
end
end
describe 'public reblogs of private toots should remain private' do
let(:visibility) { :private }
let(:reblog_visibility) { :public }
it 'reblogs privately' do
expect(status.reblogs.first.visibility).to eq 'private'
end
end
end
context 'OStatus' do

View File

@ -8,7 +8,7 @@ RSpec.describe BlacklistedEmailValidator, type: :validator do
let(:errors) { double(add: nil) }
before do
allow(user).to receive(:invited?) { false }
allow(user).to receive(:valid_invitation?) { false }
allow_any_instance_of(described_class).to receive(:blocked_email?) { blocked_email }
described_class.new.validate(user)
end