Per-status control for unlisted mode, also federation for unlisted mode
Fix #233, fix #268
This commit is contained in:
parent
1b447c190e
commit
14bd46946d
31 changed files with 175 additions and 82 deletions
12
Gemfile.lock
12
Gemfile.lock
|
@ -1,6 +1,6 @@
|
||||||
GIT
|
GIT
|
||||||
remote: https://github.com/rails/rails.git
|
remote: https://github.com/rails/rails.git
|
||||||
revision: ecb394a31420f6fd1d0ab692c79f2dd44176e2c9
|
revision: c7a716aa5a692cae301d56b345faa5d79cbfc320
|
||||||
branch: 5-0-stable
|
branch: 5-0-stable
|
||||||
specs:
|
specs:
|
||||||
actioncable (5.0.0.1)
|
actioncable (5.0.0.1)
|
||||||
|
@ -110,7 +110,7 @@ GEM
|
||||||
coffee-script-source (1.10.0)
|
coffee-script-source (1.10.0)
|
||||||
colorize (0.8.1)
|
colorize (0.8.1)
|
||||||
concurrent-ruby (1.0.2)
|
concurrent-ruby (1.0.2)
|
||||||
connection_pool (2.2.0)
|
connection_pool (2.2.1)
|
||||||
crack (0.4.3)
|
crack (0.4.3)
|
||||||
safe_yaml (~> 1.0.0)
|
safe_yaml (~> 1.0.0)
|
||||||
debug_inspector (0.0.2)
|
debug_inspector (0.0.2)
|
||||||
|
@ -287,7 +287,7 @@ GEM
|
||||||
execjs
|
execjs
|
||||||
railties (>= 3.2)
|
railties (>= 3.2)
|
||||||
tilt
|
tilt
|
||||||
redis (3.3.1)
|
redis (3.3.2)
|
||||||
redis-actionpack (5.0.0)
|
redis-actionpack (5.0.0)
|
||||||
actionpack (>= 4.0.0, < 6)
|
actionpack (>= 4.0.0, < 6)
|
||||||
redis-rack (~> 2.0.0.pre)
|
redis-rack (~> 2.0.0.pre)
|
||||||
|
@ -348,10 +348,10 @@ GEM
|
||||||
sdoc (0.4.1)
|
sdoc (0.4.1)
|
||||||
json (~> 1.7, >= 1.7.7)
|
json (~> 1.7, >= 1.7.7)
|
||||||
rdoc (~> 4.0)
|
rdoc (~> 4.0)
|
||||||
sidekiq (4.2.1)
|
sidekiq (4.2.7)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
connection_pool (~> 2.2, >= 2.2.0)
|
connection_pool (~> 2.2, >= 2.2.0)
|
||||||
rack-protection (~> 1.5)
|
rack-protection (>= 1.5.0)
|
||||||
redis (~> 3.2, >= 3.2.1)
|
redis (~> 3.2, >= 3.2.1)
|
||||||
simple_form (3.2.1)
|
simple_form (3.2.1)
|
||||||
actionpack (> 4, < 5.1)
|
actionpack (> 4, < 5.1)
|
||||||
|
@ -374,7 +374,7 @@ GEM
|
||||||
tins (~> 1.0)
|
tins (~> 1.0)
|
||||||
terminal-table (1.7.0)
|
terminal-table (1.7.0)
|
||||||
unicode-display_width (~> 1.1)
|
unicode-display_width (~> 1.1)
|
||||||
thor (0.19.1)
|
thor (0.19.4)
|
||||||
thread (0.2.2)
|
thread (0.2.2)
|
||||||
thread_safe (0.3.5)
|
thread_safe (0.3.5)
|
||||||
tilt (2.0.5)
|
tilt (2.0.5)
|
||||||
|
|
|
@ -23,6 +23,7 @@ export const COMPOSE_MOUNT = 'COMPOSE_MOUNT';
|
||||||
export const COMPOSE_UNMOUNT = 'COMPOSE_UNMOUNT';
|
export const COMPOSE_UNMOUNT = 'COMPOSE_UNMOUNT';
|
||||||
|
|
||||||
export const COMPOSE_SENSITIVITY_CHANGE = 'COMPOSE_SENSITIVITY_CHANGE';
|
export const COMPOSE_SENSITIVITY_CHANGE = 'COMPOSE_SENSITIVITY_CHANGE';
|
||||||
|
export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE';
|
||||||
|
|
||||||
export function changeCompose(text) {
|
export function changeCompose(text) {
|
||||||
return {
|
return {
|
||||||
|
@ -65,7 +66,8 @@ export function submitCompose() {
|
||||||
status: getState().getIn(['compose', 'text'], ''),
|
status: getState().getIn(['compose', 'text'], ''),
|
||||||
in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null),
|
in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null),
|
||||||
media_ids: getState().getIn(['compose', 'media_attachments']).map(item => item.get('id')),
|
media_ids: getState().getIn(['compose', 'media_attachments']).map(item => item.get('id')),
|
||||||
sensitive: getState().getIn(['compose', 'sensitive'])
|
sensitive: getState().getIn(['compose', 'sensitive']),
|
||||||
|
unlisted: getState().getIn(['compose', 'unlisted'])
|
||||||
}).then(function (response) {
|
}).then(function (response) {
|
||||||
dispatch(submitComposeSuccess(response.data));
|
dispatch(submitComposeSuccess(response.data));
|
||||||
dispatch(updateTimeline('home', response.data));
|
dispatch(updateTimeline('home', response.data));
|
||||||
|
@ -207,3 +209,10 @@ export function changeComposeSensitivity(checked) {
|
||||||
checked
|
checked
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function changeComposeVisibility(checked) {
|
||||||
|
return {
|
||||||
|
type: COMPOSE_VISIBILITY_CHANGE,
|
||||||
|
checked
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -70,6 +70,7 @@ const ComposeForm = React.createClass({
|
||||||
suggestion_token: React.PropTypes.string,
|
suggestion_token: React.PropTypes.string,
|
||||||
suggestions: React.PropTypes.array,
|
suggestions: React.PropTypes.array,
|
||||||
sensitive: React.PropTypes.bool,
|
sensitive: React.PropTypes.bool,
|
||||||
|
unlisted: React.PropTypes.bool,
|
||||||
is_submitting: React.PropTypes.bool,
|
is_submitting: React.PropTypes.bool,
|
||||||
is_uploading: React.PropTypes.bool,
|
is_uploading: React.PropTypes.bool,
|
||||||
in_reply_to: ImmutablePropTypes.map,
|
in_reply_to: ImmutablePropTypes.map,
|
||||||
|
@ -79,7 +80,8 @@ const ComposeForm = React.createClass({
|
||||||
onClearSuggestions: React.PropTypes.func.isRequired,
|
onClearSuggestions: React.PropTypes.func.isRequired,
|
||||||
onFetchSuggestions: React.PropTypes.func.isRequired,
|
onFetchSuggestions: React.PropTypes.func.isRequired,
|
||||||
onSuggestionSelected: React.PropTypes.func.isRequired,
|
onSuggestionSelected: React.PropTypes.func.isRequired,
|
||||||
onChangeSensitivity: React.PropTypes.func.isRequired
|
onChangeSensitivity: React.PropTypes.func.isRequired,
|
||||||
|
onChangeVisibility: React.PropTypes.func.isRequired
|
||||||
},
|
},
|
||||||
|
|
||||||
mixins: [PureRenderMixin],
|
mixins: [PureRenderMixin],
|
||||||
|
@ -147,6 +149,10 @@ const ComposeForm = React.createClass({
|
||||||
this.props.onChangeSensitivity(e.target.checked);
|
this.props.onChangeSensitivity(e.target.checked);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleChangeVisibility (e) {
|
||||||
|
this.props.onChangeVisibility(e.target.checked);
|
||||||
|
},
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl } = this.props;
|
const { intl } = this.props;
|
||||||
let replyArea = '';
|
let replyArea = '';
|
||||||
|
@ -187,7 +193,12 @@ const ComposeForm = React.createClass({
|
||||||
<UploadButtonContainer style={{ paddingTop: '4px' }} />
|
<UploadButtonContainer style={{ paddingTop: '4px' }} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<label style={{ display: 'block', lineHeight: '24px', verticalAlign: 'middle', marginTop: '10px', borderTop: '1px solid #616b86', paddingTop: '10px' }}>
|
<label style={{ display: 'block', lineHeight: '24px', verticalAlign: 'middle', marginTop: '10px', borderTop: '1px solid #282c37', paddingTop: '10px' }}>
|
||||||
|
<Toggle checked={this.props.unlisted} onChange={this.handleChangeVisibility} />
|
||||||
|
<span style={{ display: 'inline-block', verticalAlign: 'middle', marginBottom: '14px', marginLeft: '8px', color: '#9baec8' }}><FormattedMessage id='compose_form.unlisted' defaultMessage='Unlisted mode' /></span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label style={{ display: 'block', lineHeight: '24px', verticalAlign: 'middle' }}>
|
||||||
<Toggle checked={this.props.sensitive} onChange={this.handleChangeSensitivity} />
|
<Toggle checked={this.props.sensitive} onChange={this.handleChangeSensitivity} />
|
||||||
<span style={{ display: 'inline-block', verticalAlign: 'middle', marginBottom: '14px', marginLeft: '8px', color: '#9baec8' }}><FormattedMessage id='compose_form.sensitive' defaultMessage='Mark content as sensitive' /></span>
|
<span style={{ display: 'inline-block', verticalAlign: 'middle', marginBottom: '14px', marginLeft: '8px', color: '#9baec8' }}><FormattedMessage id='compose_form.sensitive' defaultMessage='Mark content as sensitive' /></span>
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -7,7 +7,8 @@ import {
|
||||||
clearComposeSuggestions,
|
clearComposeSuggestions,
|
||||||
fetchComposeSuggestions,
|
fetchComposeSuggestions,
|
||||||
selectComposeSuggestion,
|
selectComposeSuggestion,
|
||||||
changeComposeSensitivity
|
changeComposeSensitivity,
|
||||||
|
changeComposeVisibility
|
||||||
} from '../../../actions/compose';
|
} from '../../../actions/compose';
|
||||||
import { makeGetStatus } from '../../../selectors';
|
import { makeGetStatus } from '../../../selectors';
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@ const makeMapStateToProps = () => {
|
||||||
suggestion_token: state.getIn(['compose', 'suggestion_token']),
|
suggestion_token: state.getIn(['compose', 'suggestion_token']),
|
||||||
suggestions: state.getIn(['compose', 'suggestions']).toJS(),
|
suggestions: state.getIn(['compose', 'suggestions']).toJS(),
|
||||||
sensitive: state.getIn(['compose', 'sensitive']),
|
sensitive: state.getIn(['compose', 'sensitive']),
|
||||||
|
unlisted: state.getIn(['compose', 'unlisted']),
|
||||||
is_submitting: state.getIn(['compose', 'is_submitting']),
|
is_submitting: state.getIn(['compose', 'is_submitting']),
|
||||||
is_uploading: state.getIn(['compose', 'is_uploading']),
|
is_uploading: state.getIn(['compose', 'is_uploading']),
|
||||||
in_reply_to: getStatus(state, state.getIn(['compose', 'in_reply_to']))
|
in_reply_to: getStatus(state, state.getIn(['compose', 'in_reply_to']))
|
||||||
|
@ -57,6 +59,10 @@ const mapDispatchToProps = function (dispatch) {
|
||||||
|
|
||||||
onChangeSensitivity (checked) {
|
onChangeSensitivity (checked) {
|
||||||
dispatch(changeComposeSensitivity(checked));
|
dispatch(changeComposeSensitivity(checked));
|
||||||
|
},
|
||||||
|
|
||||||
|
onChangeVisibility (checked) {
|
||||||
|
dispatch(changeComposeVisibility(checked));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -34,6 +34,8 @@ const en = {
|
||||||
"tabs_bar.notifications": "Mitteilungen",
|
"tabs_bar.notifications": "Mitteilungen",
|
||||||
"compose_form.placeholder": "Worüber möchstest du schreiben?",
|
"compose_form.placeholder": "Worüber möchstest du schreiben?",
|
||||||
"compose_form.publish": "Veröffentlichen",
|
"compose_form.publish": "Veröffentlichen",
|
||||||
|
"compose_form.sensitive": "Medien als sensitiv markieren",
|
||||||
|
"compose_form.unlisted": "Öffentlich nicht auflisten",
|
||||||
"navigation_bar.settings": "Einstellungen",
|
"navigation_bar.settings": "Einstellungen",
|
||||||
"navigation_bar.public_timeline": "Öffentlich",
|
"navigation_bar.public_timeline": "Öffentlich",
|
||||||
"navigation_bar.logout": "Abmelden",
|
"navigation_bar.logout": "Abmelden",
|
||||||
|
|
|
@ -38,6 +38,7 @@ const en = {
|
||||||
"compose_form.placeholder": "What is on your mind?",
|
"compose_form.placeholder": "What is on your mind?",
|
||||||
"compose_form.publish": "Toot",
|
"compose_form.publish": "Toot",
|
||||||
"compose_form.sensitive": "Mark content as sensitive",
|
"compose_form.sensitive": "Mark content as sensitive",
|
||||||
|
"compose_form.unlisted": "Unlisted mode",
|
||||||
"navigation_bar.settings": "Settings",
|
"navigation_bar.settings": "Settings",
|
||||||
"navigation_bar.public_timeline": "Public timeline",
|
"navigation_bar.public_timeline": "Public timeline",
|
||||||
"navigation_bar.logout": "Logout",
|
"navigation_bar.logout": "Logout",
|
||||||
|
|
|
@ -35,6 +35,8 @@ const es = {
|
||||||
"tabs_bar.notifications": "Notificaciones",
|
"tabs_bar.notifications": "Notificaciones",
|
||||||
"compose_form.placeholder": "¿En qué estás pensando?",
|
"compose_form.placeholder": "¿En qué estás pensando?",
|
||||||
"compose_form.publish": "Publicar",
|
"compose_form.publish": "Publicar",
|
||||||
|
"compose_form.sensitive": null,
|
||||||
|
"compose_form.unlisted": "No listado",
|
||||||
"navigation_bar.settings": "Ajustes",
|
"navigation_bar.settings": "Ajustes",
|
||||||
"navigation_bar.public_timeline": "Público",
|
"navigation_bar.public_timeline": "Público",
|
||||||
"navigation_bar.logout": "Cerrar sesión",
|
"navigation_bar.logout": "Cerrar sesión",
|
||||||
|
|
|
@ -37,6 +37,7 @@ const fr = {
|
||||||
"compose_form.placeholder": "Qu’avez-vous en tête ?",
|
"compose_form.placeholder": "Qu’avez-vous en tête ?",
|
||||||
"compose_form.publish": "Pouet",
|
"compose_form.publish": "Pouet",
|
||||||
"compose_form.sensitive": "Marquer le contenu comme délicat",
|
"compose_form.sensitive": "Marquer le contenu comme délicat",
|
||||||
|
"compose_form.unlisted": "Ne pas apparaître dans le fil public",
|
||||||
"navigation_bar.settings": "Paramètres",
|
"navigation_bar.settings": "Paramètres",
|
||||||
"navigation_bar.public_timeline": "Public",
|
"navigation_bar.public_timeline": "Public",
|
||||||
"navigation_bar.logout": "Déconnexion",
|
"navigation_bar.logout": "Déconnexion",
|
||||||
|
|
|
@ -37,6 +37,7 @@ const hu = {
|
||||||
"compose_form.placeholder": "Mire gondolsz?",
|
"compose_form.placeholder": "Mire gondolsz?",
|
||||||
"compose_form.publish": "Tülk!",
|
"compose_form.publish": "Tülk!",
|
||||||
"compose_form.sensitive": "Tartalom érzékenynek jelölése",
|
"compose_form.sensitive": "Tartalom érzékenynek jelölése",
|
||||||
|
"compose_form.unlisted": "Listázatlan mód",
|
||||||
"navigation_bar.settings": "Beállítások",
|
"navigation_bar.settings": "Beállítások",
|
||||||
"navigation_bar.public_timeline": "Nyilvános időfolyam",
|
"navigation_bar.public_timeline": "Nyilvános időfolyam",
|
||||||
"navigation_bar.logout": "Kijelentkezés",
|
"navigation_bar.logout": "Kijelentkezés",
|
||||||
|
|
|
@ -33,6 +33,8 @@ const pt = {
|
||||||
"tabs_bar.public": "Público",
|
"tabs_bar.public": "Público",
|
||||||
"compose_form.placeholder": "Que estás pensando?",
|
"compose_form.placeholder": "Que estás pensando?",
|
||||||
"compose_form.publish": "Publicar",
|
"compose_form.publish": "Publicar",
|
||||||
|
"compose_form.sensitive": null,
|
||||||
|
"compose_form.unlisted": null,
|
||||||
"navigation_bar.settings": "Configurações",
|
"navigation_bar.settings": "Configurações",
|
||||||
"navigation_bar.public_timeline": "Timeline Pública",
|
"navigation_bar.public_timeline": "Timeline Pública",
|
||||||
"navigation_bar.logout": "Logout",
|
"navigation_bar.logout": "Logout",
|
||||||
|
|
|
@ -16,7 +16,8 @@ import {
|
||||||
COMPOSE_SUGGESTIONS_CLEAR,
|
COMPOSE_SUGGESTIONS_CLEAR,
|
||||||
COMPOSE_SUGGESTIONS_READY,
|
COMPOSE_SUGGESTIONS_READY,
|
||||||
COMPOSE_SUGGESTION_SELECT,
|
COMPOSE_SUGGESTION_SELECT,
|
||||||
COMPOSE_SENSITIVITY_CHANGE
|
COMPOSE_SENSITIVITY_CHANGE,
|
||||||
|
COMPOSE_VISIBILITY_CHANGE
|
||||||
} from '../actions/compose';
|
} from '../actions/compose';
|
||||||
import { TIMELINE_DELETE } from '../actions/timelines';
|
import { TIMELINE_DELETE } from '../actions/timelines';
|
||||||
import { ACCOUNT_SET_SELF } from '../actions/accounts';
|
import { ACCOUNT_SET_SELF } from '../actions/accounts';
|
||||||
|
@ -25,6 +26,7 @@ import Immutable from 'immutable';
|
||||||
const initialState = Immutable.Map({
|
const initialState = Immutable.Map({
|
||||||
mounted: false,
|
mounted: false,
|
||||||
sensitive: false,
|
sensitive: false,
|
||||||
|
unlisted: false,
|
||||||
text: '',
|
text: '',
|
||||||
in_reply_to: null,
|
in_reply_to: null,
|
||||||
is_submitting: false,
|
is_submitting: false,
|
||||||
|
@ -91,6 +93,8 @@ export default function compose(state = initialState, action) {
|
||||||
return state.set('mounted', false);
|
return state.set('mounted', false);
|
||||||
case COMPOSE_SENSITIVITY_CHANGE:
|
case COMPOSE_SENSITIVITY_CHANGE:
|
||||||
return state.set('sensitive', action.checked);
|
return state.set('sensitive', action.checked);
|
||||||
|
case COMPOSE_VISIBILITY_CHANGE:
|
||||||
|
return state.set('unlisted', action.checked);
|
||||||
case COMPOSE_CHANGE:
|
case COMPOSE_CHANGE:
|
||||||
return state.set('text', action.text);
|
return state.set('text', action.text);
|
||||||
case COMPOSE_REPLY:
|
case COMPOSE_REPLY:
|
||||||
|
|
|
@ -52,7 +52,7 @@ class Api::V1::StatusesController < ApiController
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@status = PostStatusService.new.call(current_user.account, params[:status], params[:in_reply_to_id].blank? ? nil : Status.find(params[:in_reply_to_id]), media_ids: params[:media_ids], sensitive: params[:sensitive])
|
@status = PostStatusService.new.call(current_user.account, params[:status], params[:in_reply_to_id].blank? ? nil : Status.find(params[:in_reply_to_id]), media_ids: params[:media_ids], sensitive: params[:sensitive], unlisted: params[:unlisted])
|
||||||
render action: :show
|
render action: :show
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
module ObfuscateFilename
|
module ObfuscateFilename
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
@ -11,6 +12,6 @@ module ObfuscateFilename
|
||||||
file = params.dig(*path)
|
file = params.dig(*path)
|
||||||
return if file.nil?
|
return if file.nil?
|
||||||
|
|
||||||
file.original_filename = "media" + File.extname(file.original_filename)
|
file.original_filename = 'media' + File.extname(file.original_filename)
|
||||||
end
|
end
|
||||||
end
|
end
|
|
@ -24,7 +24,7 @@ class Settings::ProfilesController < ApplicationController
|
||||||
private
|
private
|
||||||
|
|
||||||
def account_params
|
def account_params
|
||||||
params.require(:account).permit(:display_name, :note, :avatar, :header, :silenced)
|
params.require(:account).permit(:display_name, :note, :avatar, :header)
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_account
|
def set_account
|
||||||
|
|
|
@ -38,7 +38,7 @@ module AtomBuilderHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def verb(xml, verb)
|
def verb(xml, verb)
|
||||||
xml['activity'].send('verb', "http://activitystrea.ms/schema/1.0/#{verb}")
|
xml['activity'].send('verb', TagManager::VERBS[verb])
|
||||||
end
|
end
|
||||||
|
|
||||||
def content(xml, content)
|
def content(xml, content)
|
||||||
|
@ -62,7 +62,7 @@ module AtomBuilderHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def object_type(xml, type)
|
def object_type(xml, type)
|
||||||
xml['activity'].send('object-type', "http://activitystrea.ms/schema/1.0/#{type}")
|
xml['activity'].send('object-type', TagManager::TYPES[type])
|
||||||
end
|
end
|
||||||
|
|
||||||
def uri(xml, uri)
|
def uri(xml, uri)
|
||||||
|
@ -108,7 +108,7 @@ module AtomBuilderHelper
|
||||||
end
|
end
|
||||||
|
|
||||||
def link_mention(xml, account)
|
def link_mention(xml, account)
|
||||||
xml.link(rel: 'mentioned', href: TagManager.instance.uri_for(account))
|
xml.link(:rel => 'mentioned', :href => TagManager.instance.uri_for(account), 'ostatus:object-type' => TagManager::TYPES[:person])
|
||||||
end
|
end
|
||||||
|
|
||||||
def link_enclosure(xml, media)
|
def link_enclosure(xml, media)
|
||||||
|
@ -139,6 +139,11 @@ module AtomBuilderHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def link_visibility(xml, item)
|
||||||
|
return unless item.respond_to?(:visibility) && item.public_visibility?
|
||||||
|
xml.link(:rel => 'mentioned', :href => TagManager::COLLECTIONS[:public], 'ostatus:object-type' => TagManager::TYPES[:collection])
|
||||||
|
end
|
||||||
|
|
||||||
def include_author(xml, account)
|
def include_author(xml, account)
|
||||||
object_type xml, :person
|
object_type xml, :person
|
||||||
uri xml, TagManager.instance.uri_for(account)
|
uri xml, TagManager.instance.uri_for(account)
|
||||||
|
@ -189,6 +194,8 @@ module AtomBuilderHelper
|
||||||
include_author xml, stream_entry.target.account
|
include_author xml, stream_entry.target.account
|
||||||
end
|
end
|
||||||
|
|
||||||
|
link_visibility xml, stream_entry.target
|
||||||
|
|
||||||
stream_entry.target.mentions.each do |mention|
|
stream_entry.target.mentions.each do |mention|
|
||||||
link_mention xml, mention.account
|
link_mention xml, mention.account
|
||||||
end
|
end
|
||||||
|
@ -204,11 +211,14 @@ module AtomBuilderHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
link_visibility xml, stream_entry.activity
|
||||||
|
|
||||||
stream_entry.mentions.each do |mentioned|
|
stream_entry.mentions.each do |mentioned|
|
||||||
link_mention xml, mentioned
|
link_mention xml, mentioned
|
||||||
end
|
end
|
||||||
|
|
||||||
if stream_entry.activity.is_a?(Status)
|
return unless stream_entry.activity.is_a?(Status)
|
||||||
|
|
||||||
stream_entry.activity.media_attachments.each do |media|
|
stream_entry.activity.media_attachments.each do |media|
|
||||||
link_enclosure xml, media
|
link_enclosure xml, media
|
||||||
end
|
end
|
||||||
|
@ -217,12 +227,18 @@ module AtomBuilderHelper
|
||||||
category xml, tag
|
category xml, tag
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def root_tag(xml, tag, &block)
|
def root_tag(xml, tag, &block)
|
||||||
xml.send(tag, { :xmlns => 'http://www.w3.org/2005/Atom', 'xmlns:thr' => 'http://purl.org/syndication/thread/1.0', 'xmlns:activity' => 'http://activitystrea.ms/spec/1.0/', 'xmlns:poco' => 'http://portablecontacts.net/spec/1.0', 'xmlns:media' => 'http://purl.org/syndication/atommedia' }, &block)
|
xml.send(tag, {
|
||||||
|
'xmlns' => TagManager::XMLNS,
|
||||||
|
'xmlns:thr' => TagManager::THR_XMLNS,
|
||||||
|
'xmlns:activity' => TagManager::AS_XMLNS,
|
||||||
|
'xmlns:poco' => TagManager::POCO_XMLNS,
|
||||||
|
'xmlns:media' => TagManager::MEDIA_XMLNS,
|
||||||
|
'xmlns:ostatus' => TagManager::OS_XMLNS,
|
||||||
|
}, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
def single_link_avatar(xml, account, size, px)
|
def single_link_avatar(xml, account, size, px)
|
||||||
|
|
|
@ -6,6 +6,37 @@ class TagManager
|
||||||
include Singleton
|
include Singleton
|
||||||
include RoutingHelper
|
include RoutingHelper
|
||||||
|
|
||||||
|
VERBS = {
|
||||||
|
post: 'http://activitystrea.ms/schema/1.0/post',
|
||||||
|
share: 'http://activitystrea.ms/schema/1.0/share',
|
||||||
|
favorite: 'http://activitystrea.ms/schema/1.0/favorite',
|
||||||
|
unfavorite: 'http://activitystrea.ms/schema/1.0/unfavorite',
|
||||||
|
delete: 'delete',
|
||||||
|
follow: 'http://activitystrea.ms/schema/1.0/follow',
|
||||||
|
unfollow: 'http://ostatus.org/schema/1.0/unfollow',
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
TYPES = {
|
||||||
|
activity: 'http://activitystrea.ms/schema/1.0/activity',
|
||||||
|
note: 'http://activitystrea.ms/schema/1.0/note',
|
||||||
|
comment: 'http://activitystrea.ms/schema/1.0/comment',
|
||||||
|
person: 'http://activitystrea.ms/schema/1.0/person',
|
||||||
|
collection: 'http://activitystrea.ms/schema/1.0/collection',
|
||||||
|
group: 'http://activitystrea.ms/schema/1.0/group',
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
COLLECTIONS = {
|
||||||
|
public: 'http://activityschema.org/collection/public',
|
||||||
|
}.freeze
|
||||||
|
|
||||||
|
XMLNS = 'http://www.w3.org/2005/Atom'
|
||||||
|
MEDIA_XMLNS = 'http://purl.org/syndication/atommedia'
|
||||||
|
AS_XMLNS = 'http://activitystrea.ms/spec/1.0/'
|
||||||
|
THR_XMLNS = 'http://purl.org/syndication/thread/1.0'
|
||||||
|
POCO_XMLNS = 'http://portablecontacts.net/spec/1.0'
|
||||||
|
DFRN_XMLNS = 'http://purl.org/macgirvin/dfrn/1.0'
|
||||||
|
OS_XMLNS = 'http://ostatus.org/schema/1.0'
|
||||||
|
|
||||||
def unique_tag(date, id, type)
|
def unique_tag(date, id, type)
|
||||||
"tag:#{Rails.configuration.x.local_domain},#{date.strftime('%Y-%m-%d')}:objectId=#{id}:objectType=#{type}"
|
"tag:#{Rails.configuration.x.local_domain},#{date.strftime('%Y-%m-%d')}:objectId=#{id}:objectType=#{type}"
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,8 @@ class Status < ApplicationRecord
|
||||||
include Streamable
|
include Streamable
|
||||||
include Cacheable
|
include Cacheable
|
||||||
|
|
||||||
|
enum visibility: [:public, :unlisted], _suffix: :visibility
|
||||||
|
|
||||||
belongs_to :account, inverse_of: :statuses
|
belongs_to :account, inverse_of: :statuses
|
||||||
|
|
||||||
belongs_to :thread, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :replies
|
belongs_to :thread, foreign_key: 'in_reply_to_id', class_name: 'Status', inverse_of: :replies
|
||||||
|
@ -100,6 +102,7 @@ class Status < ApplicationRecord
|
||||||
|
|
||||||
def as_public_timeline(account = nil)
|
def as_public_timeline(account = nil)
|
||||||
query = joins('LEFT OUTER JOIN accounts ON statuses.account_id = accounts.id')
|
query = joins('LEFT OUTER JOIN accounts ON statuses.account_id = accounts.id')
|
||||||
|
.where(visibility: :public)
|
||||||
.where('accounts.silenced = FALSE')
|
.where('accounts.silenced = FALSE')
|
||||||
.where('statuses.in_reply_to_id IS NULL')
|
.where('statuses.in_reply_to_id IS NULL')
|
||||||
.where('statuses.reblog_of_id IS NULL')
|
.where('statuses.reblog_of_id IS NULL')
|
||||||
|
@ -110,6 +113,7 @@ class Status < ApplicationRecord
|
||||||
def as_tag_timeline(tag, account = nil)
|
def as_tag_timeline(tag, account = nil)
|
||||||
query = tag.statuses
|
query = tag.statuses
|
||||||
.joins('LEFT OUTER JOIN accounts ON statuses.account_id = accounts.id')
|
.joins('LEFT OUTER JOIN accounts ON statuses.account_id = accounts.id')
|
||||||
|
.where(visibility: :public)
|
||||||
.where('accounts.silenced = FALSE')
|
.where('accounts.silenced = FALSE')
|
||||||
.where('statuses.in_reply_to_id IS NULL')
|
.where('statuses.in_reply_to_id IS NULL')
|
||||||
.where('statuses.reblog_of_id IS NULL')
|
.where('statuses.reblog_of_id IS NULL')
|
||||||
|
|
|
@ -8,7 +8,7 @@ class FanOutOnWriteService < BaseService
|
||||||
deliver_to_followers(status)
|
deliver_to_followers(status)
|
||||||
deliver_to_mentioned(status)
|
deliver_to_mentioned(status)
|
||||||
|
|
||||||
return if status.account.silenced?
|
return if status.account.silenced? || !status.public_visibility?
|
||||||
|
|
||||||
deliver_to_hashtags(status)
|
deliver_to_hashtags(status)
|
||||||
deliver_to_public(status)
|
deliver_to_public(status)
|
||||||
|
|
|
@ -10,7 +10,7 @@ class PostStatusService < BaseService
|
||||||
# @option [Enumerable] :media_ids Optional array of media IDs to attach
|
# @option [Enumerable] :media_ids Optional array of media IDs to attach
|
||||||
# @return [Status]
|
# @return [Status]
|
||||||
def call(account, text, in_reply_to = nil, options = {})
|
def call(account, text, in_reply_to = nil, options = {})
|
||||||
status = account.statuses.create!(text: text, thread: in_reply_to, sensitive: options[:sensitive])
|
status = account.statuses.create!(text: text, thread: in_reply_to, sensitive: options[:sensitive], visibility: options[:unlisted] ? :unlisted : :public)
|
||||||
attach_media(status, options[:media_ids])
|
attach_media(status, options[:media_ids])
|
||||||
process_mentions_service.call(status)
|
process_mentions_service.call(status)
|
||||||
process_hashtags_service.call(status)
|
process_hashtags_service.call(status)
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ProcessFeedService < BaseService
|
class ProcessFeedService < BaseService
|
||||||
ACTIVITY_NS = 'http://activitystrea.ms/spec/1.0/'
|
|
||||||
THREAD_NS = 'http://purl.org/syndication/thread/1.0'
|
|
||||||
|
|
||||||
def call(body, account)
|
def call(body, account)
|
||||||
xml = Nokogiri::XML(body)
|
xml = Nokogiri::XML(body)
|
||||||
xml.encoding = 'utf-8'
|
xml.encoding = 'utf-8'
|
||||||
|
@ -15,12 +12,12 @@ class ProcessFeedService < BaseService
|
||||||
private
|
private
|
||||||
|
|
||||||
def update_author(xml, account)
|
def update_author(xml, account)
|
||||||
return if xml.at_xpath('/xmlns:feed').nil?
|
return if xml.at_xpath('/xmlns:feed', xmlns: TagManager::XMLNS).nil?
|
||||||
UpdateRemoteProfileService.new.call(xml.at_xpath('/xmlns:feed'), account, true)
|
UpdateRemoteProfileService.new.call(xml.at_xpath('/xmlns:feed', xmlns: TagManager::XMLNS), account, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_entries(xml, account)
|
def process_entries(xml, account)
|
||||||
xml.xpath('//xmlns:entry').reverse_each.map { |entry| ProcessEntry.new.call(entry, account) }.compact
|
xml.xpath('//xmlns:entry', xmlns: TagManager::XMLNS).reverse_each.map { |entry| ProcessEntry.new.call(entry, account) }.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
class ProcessEntry
|
class ProcessEntry
|
||||||
|
@ -48,7 +45,7 @@ class ProcessFeedService < BaseService
|
||||||
status = status_from_xml(@xml)
|
status = status_from_xml(@xml)
|
||||||
|
|
||||||
if verb == :share
|
if verb == :share
|
||||||
original_status = status_from_xml(@xml.at_xpath('.//activity:object', activity: ACTIVITY_NS))
|
original_status = status_from_xml(@xml.at_xpath('.//activity:object', activity: TagManager::AS_XMLNS))
|
||||||
status.reblog = original_status
|
status.reblog = original_status
|
||||||
|
|
||||||
if original_status.nil?
|
if original_status.nil?
|
||||||
|
@ -138,9 +135,15 @@ class ProcessFeedService < BaseService
|
||||||
|
|
||||||
def mentions_from_xml(parent, xml)
|
def mentions_from_xml(parent, xml)
|
||||||
processed_account_ids = []
|
processed_account_ids = []
|
||||||
|
public_visibility = false
|
||||||
|
|
||||||
xml.xpath('./xmlns:link[@rel="mentioned"]').each do |link|
|
xml.xpath('./xmlns:link[@rel="mentioned"]', xmlns: TagManager::XMLNS).each do |link|
|
||||||
next if link['href'] == 'http://activityschema.org/collection/public'
|
if link['ostatus:object-type'] == TagManager::TYPES[:collection] && link['href'] == TagManager::COLLECTIONS[:public]
|
||||||
|
public_visibility = true
|
||||||
|
next
|
||||||
|
elsif link['ostatus:object-type'] == TagManager::TYPES[:group]
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
url = Addressable::URI.parse(link['href'])
|
url = Addressable::URI.parse(link['href'])
|
||||||
|
|
||||||
|
@ -160,15 +163,18 @@ class ProcessFeedService < BaseService
|
||||||
# So we can skip duplicate mentions
|
# So we can skip duplicate mentions
|
||||||
processed_account_ids << mentioned_account.id
|
processed_account_ids << mentioned_account.id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
parent.visibility = public_visibility ? :public : :unlisted
|
||||||
|
parent.save!
|
||||||
end
|
end
|
||||||
|
|
||||||
def hashtags_from_xml(parent, xml)
|
def hashtags_from_xml(parent, xml)
|
||||||
tags = xml.xpath('./xmlns:category').map { |category| category['term'] }.select { |t| !t.blank? }
|
tags = xml.xpath('./xmlns:category', xmlns: TagManager::XMLNS).map { |category| category['term'] }.select { |t| !t.blank? }
|
||||||
ProcessHashtagsService.new.call(parent, tags)
|
ProcessHashtagsService.new.call(parent, tags)
|
||||||
end
|
end
|
||||||
|
|
||||||
def media_from_xml(parent, xml)
|
def media_from_xml(parent, xml)
|
||||||
xml.xpath('./xmlns:link[@rel="enclosure"]').each do |link|
|
xml.xpath('./xmlns:link[@rel="enclosure"]', xmlns: TagManager::XMLNS).each do |link|
|
||||||
next unless link['href']
|
next unless link['href']
|
||||||
|
|
||||||
media = MediaAttachment.where(status: parent, remote_url: link['href']).first_or_initialize(account: parent.account, status: parent, remote_url: link['href'])
|
media = MediaAttachment.where(status: parent, remote_url: link['href']).first_or_initialize(account: parent.account, status: parent, remote_url: link['href'])
|
||||||
|
@ -183,52 +189,52 @@ class ProcessFeedService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def id(xml = @xml)
|
def id(xml = @xml)
|
||||||
xml.at_xpath('./xmlns:id').content
|
xml.at_xpath('./xmlns:id', xmlns: TagManager::XMLNS).content
|
||||||
end
|
end
|
||||||
|
|
||||||
def verb(xml = @xml)
|
def verb(xml = @xml)
|
||||||
raw = xml.at_xpath('./activity:verb', activity: ACTIVITY_NS).content
|
raw = xml.at_xpath('./activity:verb', activity: TagManager::AS_XMLNS).content
|
||||||
raw.gsub('http://activitystrea.ms/schema/1.0/', '').gsub('http://ostatus.org/schema/1.0/', '').to_sym
|
TagManager::VERBS.key(raw)
|
||||||
rescue
|
rescue
|
||||||
:post
|
:post
|
||||||
end
|
end
|
||||||
|
|
||||||
def type(xml = @xml)
|
def type(xml = @xml)
|
||||||
raw = xml.at_xpath('./activity:object-type', activity: ACTIVITY_NS).content
|
raw = xml.at_xpath('./activity:object-type', activity: TagManager::AS_XMLNS).content
|
||||||
raw.gsub('http://activitystrea.ms/schema/1.0/', '').gsub('http://ostatus.org/schema/1.0/', '').to_sym
|
TagManager::TYPES.key(raw)
|
||||||
rescue
|
rescue
|
||||||
:activity
|
:activity
|
||||||
end
|
end
|
||||||
|
|
||||||
def url(xml = @xml)
|
def url(xml = @xml)
|
||||||
link = xml.at_xpath('./xmlns:link[@rel="alternate"]')
|
link = xml.at_xpath('./xmlns:link[@rel="alternate"]', xmlns: TagManager::XMLNS)
|
||||||
link.nil? ? nil : link['href']
|
link.nil? ? nil : link['href']
|
||||||
end
|
end
|
||||||
|
|
||||||
def content(xml = @xml)
|
def content(xml = @xml)
|
||||||
xml.at_xpath('./xmlns:content').content
|
xml.at_xpath('./xmlns:content', xmlns: TagManager::XMLNS).content
|
||||||
end
|
end
|
||||||
|
|
||||||
def published(xml = @xml)
|
def published(xml = @xml)
|
||||||
xml.at_xpath('./xmlns:published').content
|
xml.at_xpath('./xmlns:published', xmlns: TagManager::XMLNS).content
|
||||||
end
|
end
|
||||||
|
|
||||||
def thread?(xml = @xml)
|
def thread?(xml = @xml)
|
||||||
!xml.at_xpath('./thr:in-reply-to', thr: THREAD_NS).nil?
|
!xml.at_xpath('./thr:in-reply-to', thr: TagManager::THR_XMLNS).nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
def thread(xml = @xml)
|
def thread(xml = @xml)
|
||||||
thr = xml.at_xpath('./thr:in-reply-to', thr: THREAD_NS)
|
thr = xml.at_xpath('./thr:in-reply-to', thr: TagManager::THR_XMLNS)
|
||||||
[thr['ref'], thr['href']]
|
[thr['ref'], thr['href']]
|
||||||
end
|
end
|
||||||
|
|
||||||
def account?(xml = @xml)
|
def account?(xml = @xml)
|
||||||
!xml.at_xpath('./xmlns:author').nil?
|
!xml.at_xpath('./xmlns:author', xmlns: TagManager::XMLNS).nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
def acct(xml = @xml)
|
def acct(xml = @xml)
|
||||||
username = xml.at_xpath('./xmlns:author/xmlns:name').content
|
username = xml.at_xpath('./xmlns:author/xmlns:name', xmlns: TagManager::XMLNS).content
|
||||||
url = xml.at_xpath('./xmlns:author/xmlns:uri').content
|
url = xml.at_xpath('./xmlns:author/xmlns:uri', xmlns: TagManager::XMLNS).content
|
||||||
domain = Addressable::URI.parse(url).host
|
domain = Addressable::URI.parse(url).host
|
||||||
|
|
||||||
"#{username}@#{domain}"
|
"#{username}@#{domain}"
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ProcessInteractionService < BaseService
|
class ProcessInteractionService < BaseService
|
||||||
ACTIVITY_NS = 'http://activitystrea.ms/spec/1.0/'
|
|
||||||
|
|
||||||
# Record locally the remote interaction with our user
|
# Record locally the remote interaction with our user
|
||||||
# @param [String] envelope Salmon envelope
|
# @param [String] envelope Salmon envelope
|
||||||
# @param [Account] target_account Account the Salmon was addressed to
|
# @param [Account] target_account Account the Salmon was addressed to
|
||||||
|
@ -14,8 +12,8 @@ class ProcessInteractionService < BaseService
|
||||||
|
|
||||||
return unless contains_author?(xml)
|
return unless contains_author?(xml)
|
||||||
|
|
||||||
username = xml.at_xpath('/xmlns:entry/xmlns:author/xmlns:name').content
|
username = xml.at_xpath('/xmlns:entry/xmlns:author/xmlns:name', xmlns: TagManager::XMLNS).content
|
||||||
url = xml.at_xpath('/xmlns:entry/xmlns:author/xmlns:uri').content
|
url = xml.at_xpath('/xmlns:entry/xmlns:author/xmlns:uri', xmlns: TagManager::XMLNS).content
|
||||||
domain = Addressable::URI.parse(url).host
|
domain = Addressable::URI.parse(url).host
|
||||||
account = Account.find_by(username: username, domain: domain)
|
account = Account.find_by(username: username, domain: domain)
|
||||||
|
|
||||||
|
@ -26,7 +24,7 @@ class ProcessInteractionService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
if salmon.verify(envelope, account.keypair)
|
if salmon.verify(envelope, account.keypair)
|
||||||
update_remote_profile_service.call(xml.at_xpath('/xmlns:entry'), account, true)
|
update_remote_profile_service.call(xml.at_xpath('/xmlns:entry', xmlns: TagManager::XMLNS), account, true)
|
||||||
|
|
||||||
case verb(xml)
|
case verb(xml)
|
||||||
when :follow
|
when :follow
|
||||||
|
@ -50,16 +48,17 @@ class ProcessInteractionService < BaseService
|
||||||
private
|
private
|
||||||
|
|
||||||
def contains_author?(xml)
|
def contains_author?(xml)
|
||||||
!(xml.at_xpath('/xmlns:entry/xmlns:author/xmlns:name').nil? || xml.at_xpath('/xmlns:entry/xmlns:author/xmlns:uri').nil?)
|
!(xml.at_xpath('/xmlns:entry/xmlns:author/xmlns:name', xmlns: TagManager::XMLNS).nil? || xml.at_xpath('/xmlns:entry/xmlns:author/xmlns:uri', xmlns: TagManager::XMLNS).nil?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def mentions_account?(xml, account)
|
def mentions_account?(xml, account)
|
||||||
xml.xpath('/xmlns:entry/xmlns:link[@rel="mentioned"]').each { |mention_link| return true if mention_link.attribute('href').value == TagManager.instance.url_for(account) }
|
xml.xpath('/xmlns:entry/xmlns:link[@rel="mentioned"]', xmlns: TagManager::XMLNS).each { |mention_link| return true if mention_link.attribute('href').value == TagManager.instance.url_for(account) }
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
def verb(xml)
|
def verb(xml)
|
||||||
xml.at_xpath('//activity:verb', activity: ACTIVITY_NS).content.gsub('http://activitystrea.ms/schema/1.0/', '').gsub('http://ostatus.org/schema/1.0/', '').to_sym
|
raw = xml.at_xpath('//activity:verb', activity: TagManager::AS_XMLNS).content
|
||||||
|
TagManager::VERBS.key(raw)
|
||||||
rescue
|
rescue
|
||||||
:post
|
:post
|
||||||
end
|
end
|
||||||
|
@ -74,7 +73,7 @@ class ProcessInteractionService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def delete_post!(xml, account)
|
def delete_post!(xml, account)
|
||||||
status = Status.find(xml.at_xpath('//xmlns:id').content)
|
status = Status.find(xml.at_xpath('//xmlns:id', xmlns: TagManager::XMLNS).content)
|
||||||
|
|
||||||
return if status.nil?
|
return if status.nil?
|
||||||
|
|
||||||
|
@ -96,7 +95,7 @@ class ProcessInteractionService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def activity_id(xml)
|
def activity_id(xml)
|
||||||
xml.at_xpath('//activity:object', activity: ACTIVITY_NS).at_xpath('./xmlns:id').content
|
xml.at_xpath('//activity:object', activity: TagManager::AS_XMLNS).at_xpath('./xmlns:id', xmlns: TagManager::XMLNS).content
|
||||||
end
|
end
|
||||||
|
|
||||||
def salmon
|
def salmon
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class UpdateRemoteProfileService < BaseService
|
class UpdateRemoteProfileService < BaseService
|
||||||
POCO_NS = 'http://portablecontacts.net/spec/1.0'
|
|
||||||
DFRN_NS = 'http://purl.org/macgirvin/dfrn/1.0'
|
|
||||||
|
|
||||||
def call(xml, account, resubscribe = false)
|
def call(xml, account, resubscribe = false)
|
||||||
return if xml.nil?
|
return if xml.nil?
|
||||||
|
|
||||||
author_xml = xml.at_xpath('./xmlns:author') || xml.at_xpath('./dfrn:owner', dfrn: DFRN_NS)
|
author_xml = xml.at_xpath('./xmlns:author', xmlns: TagManager::XMLNS) || xml.at_xpath('./dfrn:owner', dfrn: TagManager::DFRN_XMLNS)
|
||||||
hub_link = xml.at_xpath('./xmlns:link[@rel="hub"]')
|
hub_link = xml.at_xpath('./xmlns:link[@rel="hub"]', xmlns: TagManager::XMLNS)
|
||||||
|
|
||||||
unless author_xml.nil?
|
unless author_xml.nil?
|
||||||
account.display_name = author_xml.at_xpath('./poco:displayName', poco: POCO_NS).content unless author_xml.at_xpath('./poco:displayName', poco: POCO_NS).nil?
|
account.display_name = author_xml.at_xpath('./poco:displayName', poco: TagManager::POCO_XMLNS).content unless author_xml.at_xpath('./poco:displayName', poco: TagManager::POCO_XMLNS).nil?
|
||||||
account.note = author_xml.at_xpath('./poco:note', poco: POCO_NS).content unless author_xml.at_xpath('./poco:note').nil?
|
account.note = author_xml.at_xpath('./poco:note', poco: TagManager::POCO_XMLNS).content unless author_xml.at_xpath('./poco:note', poco: TagManager::POCO_XMLNS).nil?
|
||||||
account.avatar_remote_url = author_xml.at_xpath('./xmlns:link[@rel="avatar"]')['href'] unless author_xml.at_xpath('./xmlns:link[@rel="avatar"]').nil? || author_xml.at_xpath('./xmlns:link[@rel="avatar"]')['href'].blank?
|
account.avatar_remote_url = author_xml.at_xpath('./xmlns:link[@rel="avatar"]', xmlns: TagManager::XMLNS)['href'] unless author_xml.at_xpath('./xmlns:link[@rel="avatar"]', xmlns: TagManager::XMLNS).nil? || author_xml.at_xpath('./xmlns:link[@rel="avatar"]', xmlns: TagManager::XMLNS)['href'].blank?
|
||||||
end
|
end
|
||||||
|
|
||||||
old_hub_url = account.hub_url
|
old_hub_url = account.hub_url
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
= f.input :note, placeholder: t('simple_form.labels.defaults.note')
|
= f.input :note, placeholder: t('simple_form.labels.defaults.note')
|
||||||
= f.input :avatar, wrapper: :with_label
|
= f.input :avatar, wrapper: :with_label
|
||||||
= f.input :header, wrapper: :with_label
|
= f.input :header, wrapper: :with_label
|
||||||
= f.input :silenced, as: :boolean, wrapper: :with_label
|
|
||||||
|
|
||||||
.actions
|
.actions
|
||||||
= f.button :button, t('generic.save_changes'), type: :submit
|
= f.button :button, t('generic.save_changes'), type: :submit
|
||||||
|
|
|
@ -14,7 +14,6 @@ de:
|
||||||
new_password: Neues Passwort
|
new_password: Neues Passwort
|
||||||
note: Über mich
|
note: Über mich
|
||||||
password: Passwort
|
password: Passwort
|
||||||
silenced: Öffentliche Beiträge nicht auflisten
|
|
||||||
username: Nutzername
|
username: Nutzername
|
||||||
interactions:
|
interactions:
|
||||||
must_be_follower: Benachrichtigungen von nicht-Folgern blockieren
|
must_be_follower: Benachrichtigungen von nicht-Folgern blockieren
|
||||||
|
|
|
@ -14,7 +14,6 @@ en:
|
||||||
new_password: New password
|
new_password: New password
|
||||||
note: Bio
|
note: Bio
|
||||||
password: Password
|
password: Password
|
||||||
silenced: Unlisted mode
|
|
||||||
username: Username
|
username: Username
|
||||||
interactions:
|
interactions:
|
||||||
must_be_follower: Block notifications from non-followers
|
must_be_follower: Block notifications from non-followers
|
||||||
|
|
|
@ -14,7 +14,6 @@ es:
|
||||||
new_password: Nueva contraseña
|
new_password: Nueva contraseña
|
||||||
note: Biografía
|
note: Biografía
|
||||||
password: Contraseña
|
password: Contraseña
|
||||||
silenced: No listado
|
|
||||||
username: Nombre de usuario
|
username: Nombre de usuario
|
||||||
notification_emails:
|
notification_emails:
|
||||||
favourite: Enviar correo electrónico cuando alguien de a favorito en su publicación
|
favourite: Enviar correo electrónico cuando alguien de a favorito en su publicación
|
||||||
|
|
|
@ -14,7 +14,6 @@ fr:
|
||||||
new_password: Nouveau mot de passe
|
new_password: Nouveau mot de passe
|
||||||
note: Présentation
|
note: Présentation
|
||||||
password: Mot de passe
|
password: Mot de passe
|
||||||
silenced: Ne pas apparaître dans le fil public
|
|
||||||
username: Identifiant
|
username: Identifiant
|
||||||
interactions:
|
interactions:
|
||||||
must_be_follower: Masquer les notifications des personnes qui ne vous suivent pas
|
must_be_follower: Masquer les notifications des personnes qui ne vous suivent pas
|
||||||
|
|
|
@ -14,7 +14,6 @@ hu:
|
||||||
new_password: Új jelszó
|
new_password: Új jelszó
|
||||||
note: Önéletrajz
|
note: Önéletrajz
|
||||||
password: Jelszó
|
password: Jelszó
|
||||||
silenced: Listázatlan mód
|
|
||||||
username: Felhasználónév
|
username: Felhasználónév
|
||||||
notification_emails:
|
notification_emails:
|
||||||
favourite: E-mail küldése amikor valaki kedvencnek jelöli az állapotod
|
favourite: E-mail küldése amikor valaki kedvencnek jelöli az állapotod
|
||||||
|
|
5
db/migrate/20161130185319_add_visibility_to_statuses.rb
Normal file
5
db/migrate/20161130185319_add_visibility_to_statuses.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
class AddVisibilityToStatuses < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
add_column :statuses, :visibility, :integer, null: false, default: 0
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20161130142058) do
|
ActiveRecord::Schema.define(version: 20161130185319) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -176,6 +176,7 @@ ActiveRecord::Schema.define(version: 20161130142058) do
|
||||||
t.integer "reblog_of_id"
|
t.integer "reblog_of_id"
|
||||||
t.string "url"
|
t.string "url"
|
||||||
t.boolean "sensitive", default: false
|
t.boolean "sensitive", default: false
|
||||||
|
t.integer "visibility", default: 0, null: false
|
||||||
t.index ["account_id"], name: "index_statuses_on_account_id", using: :btree
|
t.index ["account_id"], name: "index_statuses_on_account_id", using: :btree
|
||||||
t.index ["in_reply_to_id"], name: "index_statuses_on_in_reply_to_id", using: :btree
|
t.index ["in_reply_to_id"], name: "index_statuses_on_in_reply_to_id", using: :btree
|
||||||
t.index ["reblog_of_id"], name: "index_statuses_on_reblog_of_id", using: :btree
|
t.index ["reblog_of_id"], name: "index_statuses_on_reblog_of_id", using: :btree
|
||||||
|
|
|
@ -13,7 +13,7 @@ RSpec.describe AtomBuilderHelper, type: :helper do
|
||||||
|
|
||||||
describe '#feed' do
|
describe '#feed' do
|
||||||
it 'creates a feed' do
|
it 'creates a feed' do
|
||||||
expect(used_in_builder { |xml| helper.feed(xml) }).to match '<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia"/>'
|
expect(used_in_builder { |xml| helper.feed(xml) }).to match '<feed xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:activity="http://activitystrea.ms/spec/1.0/" xmlns:poco="http://portablecontacts.net/spec/1.0" xmlns:media="http://purl.org/syndication/atommedia" xmlns:ostatus="http://ostatus.org/schema/1.0"/>'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ RSpec.describe AtomBuilderHelper, type: :helper do
|
||||||
|
|
||||||
describe '#verb' do
|
describe '#verb' do
|
||||||
it 'creates an entry' do
|
it 'creates an entry' do
|
||||||
expect(used_with_namespaces { |xml| helper.verb(xml, 'verb') }).to match '<activity:verb>http://activitystrea.ms/schema/1.0/verb</activity:verb>'
|
expect(used_with_namespaces { |xml| helper.verb(xml, :post) }).to match '<activity:verb>http://activitystrea.ms/schema/1.0/post</activity:verb>'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ RSpec.describe AtomBuilderHelper, type: :helper do
|
||||||
|
|
||||||
describe '#object_type' do
|
describe '#object_type' do
|
||||||
it 'creates an object type' do
|
it 'creates an object type' do
|
||||||
expect(used_with_namespaces { |xml| helper.object_type(xml, 'test') }).to match '<activity:object-type>http://activitystrea.ms/schema/1.0/test</activity:object-type>'
|
expect(used_with_namespaces { |xml| helper.object_type(xml, :person) }).to match '<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ RSpec.describe AtomBuilderHelper, type: :helper do
|
||||||
let(:account) { Fabricate(:account, username: 'alice') }
|
let(:account) { Fabricate(:account, username: 'alice') }
|
||||||
|
|
||||||
it 'creates a link' do
|
it 'creates a link' do
|
||||||
expect(used_in_builder { |xml| helper.link_mention(xml, account) }).to match '<link rel="mentioned" href="https://cb6e6126.ngrok.io/users/alice"/>'
|
expect(used_in_builder { |xml| helper.link_mention(xml, account) }).to match '<link rel="mentioned" href="https://cb6e6126.ngrok.io/users/alice" ostatus:object-type="http://activitystrea.ms/schema/1.0/person"/>'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue