parent
082e57fc13
commit
cb22dce970
@ -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
|
||||
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
|
||||
|
@ -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
|
||||
def subscribed
|
||||
stream_from 'timeline:public', lambda { |encoded_message|
|
||||
message = ActiveSupport::JSON.decode(encoded_message)
|
||||
|
||||
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)
|
||||
|
||||
status, message = hydrate_status(encoded_message)
|
||||
next if filter?(status)
|
||||
transmit message
|
||||
}
|
||||
end
|
||||
|
||||
def unsubscribed
|
||||
# Any cleanup needed when channel is unsubscribed
|
||||
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
|
||||
has_and_belongs_to_many :statuses
|
||||
|
||||
HASHTAG_RE = /[?:^|\s|\.|>]#([[:word:]_]+)/i
|
||||
|
||||
validates :name, presence: true, uniqueness: true
|
||||
|
||||
def to_param
|
||||
name
|
||||
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