Merge remote-tracking branch 'origin/master' into gs-master
This commit is contained in:
		
						commit
						c55263027a
					
				
					 13 changed files with 2 additions and 226 deletions
				
			
		| 
						 | 
					@ -1,17 +0,0 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Api::V1::TrendsController < Api::BaseController
 | 
					 | 
				
			||||||
  before_action :set_tags
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  respond_to :json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def index
 | 
					 | 
				
			||||||
    render json: @tags, each_serializer: REST::TagSerializer
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  private
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def set_tags
 | 
					 | 
				
			||||||
    @tags = TrendingTags.get(limit_param(10))
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,32 +0,0 @@
 | 
				
			||||||
import api from '../api';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const TRENDS_FETCH_REQUEST = 'TRENDS_FETCH_REQUEST';
 | 
					 | 
				
			||||||
export const TRENDS_FETCH_SUCCESS = 'TRENDS_FETCH_SUCCESS';
 | 
					 | 
				
			||||||
export const TRENDS_FETCH_FAIL    = 'TRENDS_FETCH_FAIL';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const fetchTrends = () => (dispatch, getState) => {
 | 
					 | 
				
			||||||
  dispatch(fetchTrendsRequest());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  api(getState)
 | 
					 | 
				
			||||||
    .get('/api/v1/trends')
 | 
					 | 
				
			||||||
    .then(({ data }) => dispatch(fetchTrendsSuccess(data)))
 | 
					 | 
				
			||||||
    .catch(err => dispatch(fetchTrendsFail(err)));
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const fetchTrendsRequest = () => ({
 | 
					 | 
				
			||||||
  type: TRENDS_FETCH_REQUEST,
 | 
					 | 
				
			||||||
  skipLoading: true,
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const fetchTrendsSuccess = trends => ({
 | 
					 | 
				
			||||||
  type: TRENDS_FETCH_SUCCESS,
 | 
					 | 
				
			||||||
  trends,
 | 
					 | 
				
			||||||
  skipLoading: true,
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export const fetchTrendsFail = error => ({
 | 
					 | 
				
			||||||
  type: TRENDS_FETCH_FAIL,
 | 
					 | 
				
			||||||
  error,
 | 
					 | 
				
			||||||
  skipLoading: true,
 | 
					 | 
				
			||||||
  skipAlert: true,
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,4 @@
 | 
				
			||||||
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 { FormattedMessage } from 'react-intl';
 | 
					import { FormattedMessage } from 'react-intl';
 | 
				
			||||||
import AccountContainer from '../../../containers/account_container';
 | 
					import AccountContainer from '../../../containers/account_container';
 | 
				
			||||||
| 
						 | 
					@ -11,36 +10,14 @@ export default class SearchResults extends ImmutablePureComponent {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static propTypes = {
 | 
					  static propTypes = {
 | 
				
			||||||
    results: ImmutablePropTypes.map.isRequired,
 | 
					    results: ImmutablePropTypes.map.isRequired,
 | 
				
			||||||
    trends: ImmutablePropTypes.list,
 | 
					 | 
				
			||||||
    fetchTrends: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  componentDidMount () {
 | 
					 | 
				
			||||||
    const { fetchTrends } = this.props;
 | 
					 | 
				
			||||||
    fetchTrends();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  render () {
 | 
					  render () {
 | 
				
			||||||
    const { results, trends } = this.props;
 | 
					    const { results } = this.props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let accounts, statuses, hashtags;
 | 
					    let accounts, statuses, hashtags;
 | 
				
			||||||
    let count = 0;
 | 
					    let count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (results.isEmpty()) {
 | 
					 | 
				
			||||||
      return (
 | 
					 | 
				
			||||||
        <div className='search-results'>
 | 
					 | 
				
			||||||
          <div className='trends'>
 | 
					 | 
				
			||||||
            <div className='trends__header'>
 | 
					 | 
				
			||||||
              <i className='fa fa-fire fa-fw' />
 | 
					 | 
				
			||||||
              <FormattedMessage id='trends.header' defaultMessage='Trending now' />
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            {trends && trends.map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (results.get('accounts') && results.get('accounts').size > 0) {
 | 
					    if (results.get('accounts') && results.get('accounts').size > 0) {
 | 
				
			||||||
      count   += results.get('accounts').size;
 | 
					      count   += results.get('accounts').size;
 | 
				
			||||||
      accounts = (
 | 
					      accounts = (
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,14 +1,8 @@
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
import SearchResults from '../components/search_results';
 | 
					import SearchResults from '../components/search_results';
 | 
				
			||||||
import { fetchTrends } from '../../../actions/trends';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapStateToProps = state => ({
 | 
					const mapStateToProps = state => ({
 | 
				
			||||||
  results: state.getIn(['search', 'results']),
 | 
					  results: state.getIn(['search', 'results']),
 | 
				
			||||||
  trends: state.getIn(['trends', 'items']),
 | 
					 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const mapDispatchToProps = dispatch => ({
 | 
					export default connect(mapStateToProps)(SearchResults);
 | 
				
			||||||
  fetchTrends: () => dispatch(fetchTrends()),
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default connect(mapStateToProps, mapDispatchToProps)(SearchResults);
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,71 +0,0 @@
 | 
				
			||||||
import classNames from 'classnames';
 | 
					 | 
				
			||||||
import React from 'react';
 | 
					 | 
				
			||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
					 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					 | 
				
			||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
					 | 
				
			||||||
import { FormattedMessage, defineMessages } from 'react-intl';
 | 
					 | 
				
			||||||
import Hashtag from '../../../components/hashtag';
 | 
					 | 
				
			||||||
import { Link } from 'react-router-dom';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const messages = defineMessages({
 | 
					 | 
				
			||||||
  refresh_trends: { id: 'trends.refresh', defaultMessage: 'Refresh' },
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default class Trends extends ImmutablePureComponent {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  static defaultProps = {
 | 
					 | 
				
			||||||
    loading: false,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  static propTypes = {
 | 
					 | 
				
			||||||
    trends: ImmutablePropTypes.list,
 | 
					 | 
				
			||||||
    loading: PropTypes.bool.isRequired,
 | 
					 | 
				
			||||||
    showTrends: PropTypes.bool.isRequired,
 | 
					 | 
				
			||||||
    fetchTrends: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
    toggleTrends: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  componentDidMount () {
 | 
					 | 
				
			||||||
    setTimeout(() => this.props.fetchTrends(), 5000);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  handleRefreshTrends = () => {
 | 
					 | 
				
			||||||
    this.props.fetchTrends();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  handleToggle = () => {
 | 
					 | 
				
			||||||
    this.props.toggleTrends(!this.props.showTrends);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  render () {
 | 
					 | 
				
			||||||
    const { intl, trends, loading, showTrends } = this.props;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!trends || trends.size < 1) {
 | 
					 | 
				
			||||||
      return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return (
 | 
					 | 
				
			||||||
      <div className='getting-started__trends'>
 | 
					 | 
				
			||||||
        <div className='column-header__wrapper'>
 | 
					 | 
				
			||||||
          <h1 className='column-header'>
 | 
					 | 
				
			||||||
            <button>
 | 
					 | 
				
			||||||
              <i className='fa fa-fire fa-fw' />
 | 
					 | 
				
			||||||
              <FormattedMessage id='trends.header' defaultMessage='Trending now' />
 | 
					 | 
				
			||||||
            </button>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            <div className='column-header__buttons'>
 | 
					 | 
				
			||||||
              {showTrends && <button onClick={this.handleRefreshTrends} className='column-header__button' title={intl.formatMessage(messages.refresh_trends)} aria-label={intl.formatMessage(messages.refresh_trends)} disabled={loading}><i className={classNames('fa', 'fa-refresh', { 'fa-spin': loading })} /></button>}
 | 
					 | 
				
			||||||
              <button onClick={this.handleToggle} className='column-header__button'><i className={classNames('fa', showTrends ? 'fa-chevron-down' : 'fa-chevron-up')} /></button>
 | 
					 | 
				
			||||||
            </div>
 | 
					 | 
				
			||||||
          </h1>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        {showTrends && <div className='getting-started__scrollable'>
 | 
					 | 
				
			||||||
          {trends.take(3).map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}
 | 
					 | 
				
			||||||
          <Link to='/trends' className='load-more'><FormattedMessage id='status.load_more' defaultMessage='Load more' /></Link>
 | 
					 | 
				
			||||||
        </div>}
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,18 +0,0 @@
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					 | 
				
			||||||
import { injectIntl } from 'react-intl';
 | 
					 | 
				
			||||||
import { fetchTrends } from '../../../actions/trends';
 | 
					 | 
				
			||||||
import Trends from '../components/trends';
 | 
					 | 
				
			||||||
import { changeSetting } from '../../../actions/settings';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const mapStateToProps = state => ({
 | 
					 | 
				
			||||||
  trends: state.getIn(['trends', 'items']),
 | 
					 | 
				
			||||||
  loading: state.getIn(['trends', 'isLoading']),
 | 
					 | 
				
			||||||
  showTrends: state.getIn(['settings', 'trends', 'show']),
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const mapDispatchToProps = dispatch => ({
 | 
					 | 
				
			||||||
  fetchTrends: () => dispatch(fetchTrends()),
 | 
					 | 
				
			||||||
  toggleTrends: show => dispatch(changeSetting(['trends', 'show'], show)),
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(Trends));
 | 
					 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,6 @@ import { fetchFollowRequests } from '../../actions/accounts';
 | 
				
			||||||
import { List as ImmutableList } from 'immutable';
 | 
					import { List as ImmutableList } from 'immutable';
 | 
				
			||||||
import { Link } from 'react-router-dom';
 | 
					import { Link } from 'react-router-dom';
 | 
				
			||||||
import NavigationBar from '../compose/components/navigation_bar';
 | 
					import NavigationBar from '../compose/components/navigation_bar';
 | 
				
			||||||
import TrendsContainer from './containers/trends_container';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const messages = defineMessages({
 | 
					const messages = defineMessages({
 | 
				
			||||||
  home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
 | 
					  home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
 | 
				
			||||||
| 
						 | 
					@ -132,8 +131,6 @@ export default class GettingStarted extends ImmutablePureComponent {
 | 
				
			||||||
          {navItems}
 | 
					          {navItems}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        {multiColumn && <TrendsContainer />}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        {!multiColumn && <div className='flex-spacer' />}
 | 
					        {!multiColumn && <div className='flex-spacer' />}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <div className='getting-started getting-started__footer'>
 | 
					        <div className='getting-started getting-started__footer'>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,6 @@ import {
 | 
				
			||||||
  Mutes,
 | 
					  Mutes,
 | 
				
			||||||
  PinnedStatuses,
 | 
					  PinnedStatuses,
 | 
				
			||||||
  Lists,
 | 
					  Lists,
 | 
				
			||||||
  Trends,
 | 
					 | 
				
			||||||
} from './util/async-components';
 | 
					} from './util/async-components';
 | 
				
			||||||
import { HotKeys } from 'react-hotkeys';
 | 
					import { HotKeys } from 'react-hotkeys';
 | 
				
			||||||
import { me } from '../../initial_state';
 | 
					import { me } from '../../initial_state';
 | 
				
			||||||
| 
						 | 
					@ -155,7 +154,6 @@ class SwitchingColumnsArea extends React.PureComponent {
 | 
				
			||||||
          <WrappedRoute path='/pinned' component={PinnedStatuses} content={children} />
 | 
					          <WrappedRoute path='/pinned' component={PinnedStatuses} content={children} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <WrappedRoute path='/search' component={Compose} content={children} componentParams={{ isSearchPage: true }} />
 | 
					          <WrappedRoute path='/search' component={Compose} content={children} componentParams={{ isSearchPage: true }} />
 | 
				
			||||||
          <WrappedRoute path='/trends' component={Trends} content={children} />
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <WrappedRoute path='/statuses/new' component={Compose} content={children} />
 | 
					          <WrappedRoute path='/statuses/new' component={Compose} content={children} />
 | 
				
			||||||
          <WrappedRoute path='/statuses/:statusId' exact component={Status} content={children} />
 | 
					          <WrappedRoute path='/statuses/:statusId' exact component={Status} content={children} />
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -129,7 +129,3 @@ export function EmbedModal () {
 | 
				
			||||||
export function ListEditor () {
 | 
					export function ListEditor () {
 | 
				
			||||||
  return import(/* webpackChunkName: "features/list_editor" */'../../list_editor');
 | 
					  return import(/* webpackChunkName: "features/list_editor" */'../../list_editor');
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
export function Trends () {
 | 
					 | 
				
			||||||
  return import(/* webpackChunkName: "features/trends" */'../../trends');
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,7 +26,6 @@ import height_cache from './height_cache';
 | 
				
			||||||
import custom_emojis from './custom_emojis';
 | 
					import custom_emojis from './custom_emojis';
 | 
				
			||||||
import lists from './lists';
 | 
					import lists from './lists';
 | 
				
			||||||
import listEditor from './list_editor';
 | 
					import listEditor from './list_editor';
 | 
				
			||||||
import trends from './trends';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const reducers = {
 | 
					const reducers = {
 | 
				
			||||||
  dropdown_menu,
 | 
					  dropdown_menu,
 | 
				
			||||||
| 
						 | 
					@ -56,7 +55,6 @@ const reducers = {
 | 
				
			||||||
  custom_emojis,
 | 
					  custom_emojis,
 | 
				
			||||||
  lists,
 | 
					  lists,
 | 
				
			||||||
  listEditor,
 | 
					  listEditor,
 | 
				
			||||||
  trends,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default combineReducers(reducers);
 | 
					export default combineReducers(reducers);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,23 +0,0 @@
 | 
				
			||||||
import { TRENDS_FETCH_REQUEST, TRENDS_FETCH_SUCCESS, TRENDS_FETCH_FAIL } from '../actions/trends';
 | 
					 | 
				
			||||||
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const initialState = ImmutableMap({
 | 
					 | 
				
			||||||
  items: ImmutableList(),
 | 
					 | 
				
			||||||
  isLoading: false,
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
export default function trendsReducer(state = initialState, action) {
 | 
					 | 
				
			||||||
  switch(action.type) {
 | 
					 | 
				
			||||||
  case TRENDS_FETCH_REQUEST:
 | 
					 | 
				
			||||||
    return state.set('isLoading', true);
 | 
					 | 
				
			||||||
  case TRENDS_FETCH_SUCCESS:
 | 
					 | 
				
			||||||
    return state.withMutations(map => {
 | 
					 | 
				
			||||||
      map.set('items', fromJS(action.trends));
 | 
					 | 
				
			||||||
      map.set('isLoading', false);
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  case TRENDS_FETCH_FAIL:
 | 
					 | 
				
			||||||
    return state.set('isLoading', false);
 | 
					 | 
				
			||||||
  default:
 | 
					 | 
				
			||||||
    return state;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,7 @@
 | 
				
			||||||
# frozen_string_literal: true
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TrendingTags
 | 
					class TrendingTags
 | 
				
			||||||
  KEY                  = 'trending_tags'
 | 
					 | 
				
			||||||
  EXPIRE_HISTORY_AFTER = 7.days.seconds
 | 
					  EXPIRE_HISTORY_AFTER = 7.days.seconds
 | 
				
			||||||
  THRESHOLD            = 5
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  class << self
 | 
					  class << self
 | 
				
			||||||
    def record_use!(tag, account, at_time = Time.now.utc)
 | 
					    def record_use!(tag, account, at_time = Time.now.utc)
 | 
				
			||||||
| 
						 | 
					@ -11,30 +9,10 @@ class TrendingTags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      increment_historical_use!(tag.id, at_time)
 | 
					      increment_historical_use!(tag.id, at_time)
 | 
				
			||||||
      increment_unique_use!(tag.id, account.id, at_time)
 | 
					      increment_unique_use!(tag.id, account.id, at_time)
 | 
				
			||||||
      increment_vote!(tag.id, at_time)
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get(limit)
 | 
					 | 
				
			||||||
      tag_ids = redis.zrevrange(KEY, 0, limit).map(&:to_i)
 | 
					 | 
				
			||||||
      tags    = Tag.where(id: tag_ids).to_a.map { |tag| [tag.id, tag] }.to_h
 | 
					 | 
				
			||||||
      tag_ids.map { |tag_id| tags[tag_id] }.compact
 | 
					 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private
 | 
					    private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def increment_vote!(tag_id, at_time)
 | 
					 | 
				
			||||||
      expected = redis.pfcount("activity:tags:#{tag_id}:#{(at_time - 1.day).beginning_of_day.to_i}:accounts").to_f
 | 
					 | 
				
			||||||
      expected = 1.0 if expected.zero?
 | 
					 | 
				
			||||||
      observed = redis.pfcount("activity:tags:#{tag_id}:#{at_time.beginning_of_day.to_i}:accounts").to_f
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if expected > observed || observed < THRESHOLD
 | 
					 | 
				
			||||||
        redis.zrem(KEY, tag_id.to_s)
 | 
					 | 
				
			||||||
      else
 | 
					 | 
				
			||||||
        score = ((observed - expected)**2) / expected
 | 
					 | 
				
			||||||
        redis.zadd(KEY, score, tag_id.to_s)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def increment_historical_use!(tag_id, at_time)
 | 
					    def increment_historical_use!(tag_id, at_time)
 | 
				
			||||||
      key = "activity:tags:#{tag_id}:#{at_time.beginning_of_day.to_i}"
 | 
					      key = "activity:tags:#{tag_id}:#{at_time.beginning_of_day.to_i}"
 | 
				
			||||||
      redis.incrby(key, 1)
 | 
					      redis.incrby(key, 1)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -271,7 +271,6 @@ Rails.application.routes.draw do
 | 
				
			||||||
      resources :favourites, only: [:index]
 | 
					      resources :favourites, only: [:index]
 | 
				
			||||||
      resources :bookmarks,  only: [:index]
 | 
					      resources :bookmarks,  only: [:index]
 | 
				
			||||||
      resources :reports,    only: [:index, :create]
 | 
					      resources :reports,    only: [:index, :create]
 | 
				
			||||||
      resources :trends,     only: [:index]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      namespace :apps do
 | 
					      namespace :apps do
 | 
				
			||||||
        get :verify_credentials, to: 'credentials#show'
 | 
					        get :verify_credentials, to: 'credentials#show'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue