parent
62292797ec
commit
48b9619439
@ -0,0 +1,72 @@
|
|||||||
|
import { connect } from 'react-redux';
|
||||||
|
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||||
|
import StatusListContainer from '../ui/containers/status_list_container';
|
||||||
|
import Column from '../ui/components/column';
|
||||||
|
import {
|
||||||
|
refreshTimeline,
|
||||||
|
updateTimeline
|
||||||
|
} from '../../actions/timelines';
|
||||||
|
|
||||||
|
const HashtagTimeline = React.createClass({
|
||||||
|
|
||||||
|
propTypes: {
|
||||||
|
params: React.PropTypes.object.isRequired,
|
||||||
|
dispatch: React.PropTypes.func.isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
mixins: [PureRenderMixin],
|
||||||
|
|
||||||
|
_subscribe (dispatch, id) {
|
||||||
|
if (typeof App !== 'undefined') {
|
||||||
|
this.subscription = App.cable.subscriptions.create({
|
||||||
|
channel: 'HashtagChannel',
|
||||||
|
tag: id
|
||||||
|
}, {
|
||||||
|
|
||||||
|
received (data) {
|
||||||
|
dispatch(updateTimeline('tag', JSON.parse(data.message)));
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_unsubscribe () {
|
||||||
|
if (typeof this.subscription !== 'undefined') {
|
||||||
|
this.subscription.unsubscribe();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillMount () {
|
||||||
|
const { dispatch } = this.props;
|
||||||
|
const { id } = this.props.params;
|
||||||
|
|
||||||
|
dispatch(refreshTimeline('tag', true, id));
|
||||||
|
this._subscribe(dispatch, id);
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillReceiveProps (nextProps) {
|
||||||
|
if (nextProps.params.id !== this.props.params.id) {
|
||||||
|
this.props.dispatch(refreshTimeline('tag', true, nextProps.params.id));
|
||||||
|
this._unsubscribe();
|
||||||
|
this._subscribe(this.props.dispatch, nextProps.params.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
componentWillUnmount () {
|
||||||
|
this._unsubscribe();
|
||||||
|
},
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { id } = this.props.params;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column icon='hashtag' heading={id}>
|
||||||
|
<StatusListContainer type='tag' id={id} />
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect()(HashtagTimeline);
|
@ -1,4 +1,17 @@
|
|||||||
module ApplicationCable
|
module ApplicationCable
|
||||||
class Channel < ActionCable::Channel::Base
|
class Channel < ActionCable::Channel::Base
|
||||||
|
protected
|
||||||
|
|
||||||
|
def hydrate_status(encoded_message)
|
||||||
|
message = ActiveSupport::JSON.decode(encoded_message)
|
||||||
|
status = Status.find_by(id: message['id'])
|
||||||
|
message['message'] = FeedManager.instance.inline_render(current_user.account, status)
|
||||||
|
|
||||||
|
[status, message]
|
||||||
|
end
|
||||||
|
|
||||||
|
def filter?(status)
|
||||||
|
status.nil? || current_user.account.blocking?(status.account) || (status.reblog? && current_user.account.blocking?(status.reblog.account))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
class HashtagChannel < ApplicationCable::Channel
|
||||||
|
def subscribed
|
||||||
|
tag = params[:tag].downcase
|
||||||
|
|
||||||
|
stream_from "timeline:hashtag:#{tag}", lambda { |encoded_message|
|
||||||
|
status, message = hydrate_status(encoded_message)
|
||||||
|
next if filter?(status)
|
||||||
|
transmit message
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
@ -1,19 +1,9 @@
|
|||||||
# Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading.
|
|
||||||
class PublicChannel < ApplicationCable::Channel
|
class PublicChannel < ApplicationCable::Channel
|
||||||
def subscribed
|
def subscribed
|
||||||
stream_from 'timeline:public', lambda { |encoded_message|
|
stream_from 'timeline:public', lambda { |encoded_message|
|
||||||
message = ActiveSupport::JSON.decode(encoded_message)
|
status, message = hydrate_status(encoded_message)
|
||||||
|
next if filter?(status)
|
||||||
status = Status.find_by(id: message['id'])
|
|
||||||
next if status.nil? || current_user.account.blocking?(status.account) || (status.reblog? && current_user.account.blocking?(status.reblog.account))
|
|
||||||
|
|
||||||
message['message'] = FeedManager.instance.inline_render(current_user.account, status)
|
|
||||||
|
|
||||||
transmit message
|
transmit message
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def unsubscribed
|
|
||||||
# Any cleanup needed when channel is unsubscribed
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
class TagsController < ApplicationController
|
||||||
|
def show
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,2 @@
|
|||||||
|
module TagsHelper
|
||||||
|
end
|
@ -1,5 +1,11 @@
|
|||||||
class Tag < ApplicationRecord
|
class Tag < ApplicationRecord
|
||||||
|
has_and_belongs_to_many :statuses
|
||||||
|
|
||||||
HASHTAG_RE = /[?:^|\s|\.|>]#([[:word:]_]+)/i
|
HASHTAG_RE = /[?:^|\s|\.|>]#([[:word:]_]+)/i
|
||||||
|
|
||||||
validates :name, presence: true, uniqueness: true
|
validates :name, presence: true, uniqueness: true
|
||||||
|
|
||||||
|
def to_param
|
||||||
|
name
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
class ProcessHashtagsService < BaseService
|
||||||
|
def call(status, tags = [])
|
||||||
|
if status.local?
|
||||||
|
tags = status.text.scan(Tag::HASHTAG_RE).map(&:first)
|
||||||
|
end
|
||||||
|
|
||||||
|
tags.map(&:downcase).each do |tag|
|
||||||
|
status.tags << Tag.where(name: tag).first_or_initialize(name: tag)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,2 @@
|
|||||||
|
attribute :name
|
||||||
|
node(:url) { |tag| tag_url(tag) }
|
@ -0,0 +1,8 @@
|
|||||||
|
class CreateStatusesTagsJoinTable < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
create_join_table :statuses, :tags do |t|
|
||||||
|
t.index :tag_id
|
||||||
|
t.index [:tag_id, :status_id], unique: true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
@ -0,0 +1,12 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe TagsController, type: :controller do
|
||||||
|
|
||||||
|
describe 'GET #show' do
|
||||||
|
it 'returns http success' do
|
||||||
|
get :show, params: { id: 'test' }
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
@ -0,0 +1,5 @@
|
|||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe TagsHelper, type: :helper do
|
||||||
|
|
||||||
|
end
|
Loading…
Reference in new issue