follows for maps in the ui for internal testing only still (#1072)
* follows for maps in the ui for testers * require user for these actions * match how map follow works
This commit is contained in:
parent
8d771543d8
commit
013e3c7f21
14 changed files with 145 additions and 30 deletions
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
class MapsController < ApplicationController
|
||||
before_action :require_user, only: [:create, :update, :destroy, :events]
|
||||
before_action :set_map, only: [:show, :conversation, :update, :destroy, :contains, :events, :export]
|
||||
before_action :require_user, only: [:create, :update, :destroy, :events, :follow, :unfollow]
|
||||
before_action :set_map, only: [:show, :conversation, :update, :destroy, :contains, :events, :export, :follow, :unfollow]
|
||||
after_action :verify_authorized
|
||||
|
||||
# GET maps/:id
|
||||
|
@ -138,6 +138,32 @@ class MapsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
# POST maps/:id/follow
|
||||
def follow
|
||||
follow = FollowService.follow(@map, current_user, 'followed')
|
||||
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
if follow
|
||||
head :ok
|
||||
else
|
||||
head :bad_request
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# POST maps/:id/unfollow
|
||||
def unfollow
|
||||
FollowService.unfollow(@map, current_user)
|
||||
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_map
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
class TopicsController < ApplicationController
|
||||
include TopicsHelper
|
||||
|
||||
before_action :require_user, only: [:create, :update, :destroy]
|
||||
before_action :require_user, only: [:create, :update, :destroy, :follow, :unfollow]
|
||||
before_action :set_topic, only: [:show, :update, :relative_numbers, :relatives, :network, :destroy, :follow, :unfollow]
|
||||
after_action :verify_authorized, except: :autocomplete_topic
|
||||
|
||||
respond_to :html, :js, :json
|
||||
|
@ -31,9 +32,6 @@ class TopicsController < ApplicationController
|
|||
|
||||
# GET topics/:id
|
||||
def show
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
@alltopics = [@topic].concat(policy_scope(Topic.relatives(@topic.id, current_user)).to_a)
|
||||
|
@ -49,9 +47,6 @@ class TopicsController < ApplicationController
|
|||
|
||||
# GET topics/:id/network
|
||||
def network
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
|
||||
@alltopics = [@topic].concat(policy_scope(Topic.relatives(@topic.id, current_user)).to_a)
|
||||
@allsynapses = policy_scope(Synapse.for_topic(@topic.id))
|
||||
|
||||
|
@ -71,9 +66,6 @@ class TopicsController < ApplicationController
|
|||
|
||||
# GET topics/:id/relative_numbers
|
||||
def relative_numbers
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
|
||||
topics_already_has = params[:network] ? params[:network].split(',').map(&:to_i) : []
|
||||
|
||||
alltopics = policy_scope(Topic.relatives(@topic.id, current_user)).to_a
|
||||
|
@ -94,9 +86,6 @@ class TopicsController < ApplicationController
|
|||
|
||||
# GET topics/:id/relatives
|
||||
def relatives
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
|
||||
topics_already_has = params[:network] ? params[:network].split(',').map(&:to_i) : []
|
||||
|
||||
alltopics = policy_scope(Topic.relatives(@topic.id, current_user)).to_a
|
||||
|
@ -149,8 +138,6 @@ class TopicsController < ApplicationController
|
|||
# PUT /topics/1
|
||||
# PUT /topics/1.json
|
||||
def update
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
@topic.updated_by = current_user
|
||||
@topic.assign_attributes(topic_params)
|
||||
|
||||
|
@ -165,8 +152,6 @@ class TopicsController < ApplicationController
|
|||
|
||||
# DELETE topics/:id
|
||||
def destroy
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
@topic.updated_by = current_user
|
||||
@topic.destroy
|
||||
respond_to do |format|
|
||||
|
@ -174,8 +159,39 @@ class TopicsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
# POST topics/:id/follow
|
||||
def follow
|
||||
follow = FollowService.follow(@topic, current_user, 'followed')
|
||||
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
if follow
|
||||
head :ok
|
||||
else
|
||||
head :bad_request
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# POST topics/:id/unfollow
|
||||
def unfollow
|
||||
FollowService.unfollow(@topic, current_user)
|
||||
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_topic
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
end
|
||||
|
||||
def topic_params
|
||||
params.require(:topic).permit(:id, :name, :desc, :link, :permission, :metacode_id, :defer_to_map_id)
|
||||
end
|
||||
|
|
|
@ -52,10 +52,20 @@ class User < ApplicationRecord
|
|||
|
||||
# override default as_json
|
||||
def as_json(_options = {})
|
||||
{ id: id,
|
||||
json = { id: id,
|
||||
name: name,
|
||||
image: image.url(:sixtyfour),
|
||||
admin: admin }
|
||||
if (_options[:follows])
|
||||
json['follows'] = {
|
||||
topics: following.where(followed_type: 'Topic').to_a.map(&:followed_id),
|
||||
maps: following.where(followed_type: 'Map').to_a.map(&:followed_id)
|
||||
}
|
||||
end
|
||||
if (_options[:email])
|
||||
json['email'] = email
|
||||
end
|
||||
json
|
||||
end
|
||||
|
||||
def as_json_for_autocomplete
|
||||
|
|
|
@ -90,4 +90,12 @@ class MapPolicy < ApplicationPolicy
|
|||
def unstar?
|
||||
user.present?
|
||||
end
|
||||
|
||||
def follow?
|
||||
show? && user.present?
|
||||
end
|
||||
|
||||
def unfollow?
|
||||
user.present?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -55,6 +55,14 @@ class TopicPolicy < ApplicationPolicy
|
|||
show?
|
||||
end
|
||||
|
||||
def follow?
|
||||
show? && user.present?
|
||||
end
|
||||
|
||||
def unfollow?
|
||||
user.present?
|
||||
end
|
||||
|
||||
# Helpers
|
||||
def map_policy
|
||||
@map_policy ||= Pundit.policy(user, record.defer_to_map)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<%= render :partial => 'shared/metacodeBgColors' %>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
<% if current_user %>
|
||||
Metamaps.ServerData.ActiveMapper = <%= current_user.to_json.html_safe %>
|
||||
Metamaps.ServerData.ActiveMapper = <%= current_user.to_json({follows: true, email: true}).html_safe %>
|
||||
<% else %>
|
||||
Metamaps.ServerData.ActiveMapper = null
|
||||
<% end %>
|
||||
|
|
|
@ -48,6 +48,8 @@ Metamaps::Application.routes.draw do
|
|||
|
||||
post :star, to: 'stars#create', default: { format: :json }
|
||||
post :unstar, to: 'stars#destroy', default: { format: :json }
|
||||
post :follow, default: { format: :json }
|
||||
post :unfollow, default: { format: :json }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -83,6 +85,8 @@ Metamaps::Application.routes.draw do
|
|||
get :network
|
||||
get :relative_numbers
|
||||
get :relatives
|
||||
post :follow, default: { format: :json }
|
||||
post :unfollow, default: { format: :json }
|
||||
end
|
||||
collection do
|
||||
get :autocomplete_topic
|
||||
|
|
|
@ -34,6 +34,9 @@ const Map = Backbone.Model.extend({
|
|||
return false
|
||||
}
|
||||
},
|
||||
isFollowedBy: function(mapper) {
|
||||
return mapper.get('follows') && mapper.get('follows').maps.indexOf(this.get('id')) > -1
|
||||
},
|
||||
getUser: function() {
|
||||
return Mapper.get(this.get('user_id'))
|
||||
},
|
||||
|
|
|
@ -5,7 +5,7 @@ import outdent from 'outdent'
|
|||
|
||||
const Mapper = Backbone.Model.extend({
|
||||
urlRoot: '/users',
|
||||
blacklist: ['created_at', 'updated_at'],
|
||||
blacklist: ['created_at', 'updated_at', 'follows'],
|
||||
toJSON: function(options) {
|
||||
return _.omit(this.attributes, this.blacklist)
|
||||
},
|
||||
|
@ -15,6 +15,20 @@ const Mapper = Backbone.Model.extend({
|
|||
<img src="${this.get('image')}" data-id="${this.id}" alt="${this.get('name')}" />
|
||||
<p>${this.get('name')}</p>
|
||||
</li>`
|
||||
},
|
||||
followMap: function(id) {
|
||||
this.get('follows').maps.push(id)
|
||||
},
|
||||
unfollowMap: function(id) {
|
||||
const idIndex = this.get('follows').maps.indexOf(id)
|
||||
if (idIndex > -1) this.get('follows').maps.splice(idIndex, 1)
|
||||
},
|
||||
followTopic: function(id) {
|
||||
this.get('follows').topics.push(id)
|
||||
},
|
||||
unfollowTopic: function(id) {
|
||||
const idIndex = this.get('follows').topics.indexOf(id)
|
||||
if (idIndex > -1) this.get('follows').topics.splice(idIndex, 1)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -47,6 +47,9 @@ const Topic = Backbone.Model.extend({
|
|||
if (mapper && this.get('user_id') === mapper.get('id')) return true
|
||||
else return false
|
||||
},
|
||||
isFollowedBy: function(mapper) {
|
||||
return mapper.get('follows') && mapper.get('follows').topics.indexOf(this.get('id')) > -1
|
||||
},
|
||||
getDate: function() {},
|
||||
getMetacode: function() {
|
||||
return DataModel.Metacodes.get(this.get('metacode_id'))
|
||||
|
|
|
@ -181,6 +181,9 @@ const Util = {
|
|||
})
|
||||
}
|
||||
return text
|
||||
},
|
||||
isTester: function(currentUser) {
|
||||
return ['connorturland@gmail.com', 'devin@callysto.com', 'chessscholar@gmail.com', 'solaureum@gmail.com', 'ishanshapiro@gmail.com'].indexOf(currentUser.get('email')) > -1
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,20 @@ const ExploreMaps = {
|
|||
url: `/maps/${map.id}/access_request`
|
||||
})
|
||||
GlobalUI.notifyUser('You will be notified by email if request accepted')
|
||||
},
|
||||
onFollow: function(map) {
|
||||
const isFollowing = map.isFollowedBy(Active.Mapper)
|
||||
$.post({
|
||||
url: `/maps/${map.id}/${isFollowing ? 'un' : ''}follow`
|
||||
})
|
||||
if (isFollowing) {
|
||||
GlobalUI.notifyUser('You are no longer following this map')
|
||||
Active.Mapper.unfollowMap(map.id)
|
||||
} else {
|
||||
GlobalUI.notifyUser('You are now following this map')
|
||||
Active.Mapper.followMap(map.id)
|
||||
}
|
||||
self.render()
|
||||
}
|
||||
}
|
||||
ReactDOM.render(
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, { Component, PropTypes } from 'react'
|
||||
import { find, values } from 'lodash'
|
||||
import Util from '../../Metamaps/Util'
|
||||
|
||||
const IN_CONVERSATION = 1 // shared with /realtime/reducer.js
|
||||
|
||||
|
@ -23,7 +24,8 @@ class Menu extends Component {
|
|||
}
|
||||
|
||||
render = () => {
|
||||
const { currentUser, map, onStar, onRequest } = this.props
|
||||
const { currentUser, map, onStar, onRequest, onFollow } = this.props
|
||||
const isFollowing = map.isFollowedBy(currentUser)
|
||||
const style = { display: this.state.open ? 'block' : 'none' }
|
||||
|
||||
return <div className='dropdownMenu'>
|
||||
|
@ -35,6 +37,7 @@ class Menu extends Component {
|
|||
<ul className='menuItems' style={ style }>
|
||||
<li className='star' onClick={ () => { this.toggle() && onStar(map) }}>Star Map</li>
|
||||
{ !map.authorizeToEdit(currentUser) && <li className='request' onClick={ () => { this.toggle() && onRequest(map) }}>Request Access</li> }
|
||||
{ Util.isTester(currentUser) && <li className='follow' onClick={ () => { this.toggle() && onFollow(map) }}>{isFollowing ? 'Unfollow' : 'Follow'}</li> }
|
||||
</ul>
|
||||
</div>
|
||||
}
|
||||
|
@ -43,7 +46,8 @@ Menu.propTypes = {
|
|||
currentUser: PropTypes.object.isRequired,
|
||||
map: PropTypes.object.isRequired,
|
||||
onStar: PropTypes.func.isRequired,
|
||||
onRequest: PropTypes.func.isRequired
|
||||
onRequest: PropTypes.func.isRequired,
|
||||
onFollow: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
const Metadata = (props) => {
|
||||
|
@ -80,7 +84,7 @@ const checkAndWrapInA = (shouldWrap, classString, mapId, element) => {
|
|||
|
||||
class MapCard extends Component {
|
||||
render = () => {
|
||||
const { map, mobile, juntoState, currentUser, onRequest, onStar } = this.props
|
||||
const { map, mobile, juntoState, currentUser, onRequest, onStar, onFollow } = this.props
|
||||
|
||||
const hasMap = (juntoState.liveMaps[map.id] && values(juntoState.liveMaps[map.id]).length) || null
|
||||
const realtimeMap = juntoState.liveMaps[map.id]
|
||||
|
@ -131,7 +135,7 @@ class MapCard extends Component {
|
|||
</div>) }
|
||||
{ !mobile && hasMapper && <div className='mapHasMapper'><MapperList mappers={ mapperList } /></div> }
|
||||
{ !mobile && hasConversation && <div className='mapHasConversation'><MapperList mappers={ mapperList } /></div> }
|
||||
{ !mobile && currentUser && <Menu currentUser={ currentUser } map={ map } onStar= { onStar } onRequest={ onRequest } /> }
|
||||
{ !mobile && currentUser && <Menu currentUser={ currentUser } map={ map } onStar= { onStar } onRequest={ onRequest } onFollow={ onFollow } /> }
|
||||
</div>
|
||||
</div>) }
|
||||
</div>
|
||||
|
@ -145,7 +149,8 @@ MapCard.propTypes = {
|
|||
juntoState: PropTypes.object,
|
||||
currentUser: PropTypes.object,
|
||||
onStar: PropTypes.func.isRequired,
|
||||
onRequest: PropTypes.func.isRequired
|
||||
onRequest: PropTypes.func.isRequired,
|
||||
onFollow: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default MapCard
|
||||
|
|
|
@ -46,7 +46,7 @@ class Maps extends Component {
|
|||
}
|
||||
|
||||
render = () => {
|
||||
const { maps, currentUser, juntoState, pending, section, user, onStar, onRequest } = this.props
|
||||
const { maps, currentUser, juntoState, pending, section, user, onStar, onRequest, onFollow } = this.props
|
||||
const style = { width: this.state.mapsWidth + 'px' }
|
||||
const mobile = document && document.body.clientWidth <= MOBILE_VIEW_BREAKPOINT
|
||||
|
||||
|
@ -56,7 +56,7 @@ class Maps extends Component {
|
|||
<div style={ style }>
|
||||
{ user ? <MapperCard user={ user } /> : null }
|
||||
{ currentUser && !user && !(pending && maps.length === 0) ? <div className="map newMap"><a href="/maps/new"><div className="newMapImage"></div><span>Create new map...</span></a></div> : null }
|
||||
{ maps.models.map(map => <MapCard key={ map.id } map={ map } mobile={ mobile } juntoState={ juntoState } currentUser={ currentUser } onStar={ onStar } onRequest={ onRequest } />) }
|
||||
{ maps.models.map(map => <MapCard key={ map.id } map={ map } mobile={ mobile } juntoState={ juntoState } currentUser={ currentUser } onStar={ onStar } onRequest={ onRequest } onFollow={ onFollow } />) }
|
||||
<div className='clearfloat'></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -79,7 +79,8 @@ Maps.propTypes = {
|
|||
loadMore: PropTypes.func,
|
||||
pending: PropTypes.bool.isRequired,
|
||||
onStar: PropTypes.func.isRequired,
|
||||
onRequest: PropTypes.func.isRequired
|
||||
onRequest: PropTypes.func.isRequired,
|
||||
onFollow: PropTypes.func.isRequired
|
||||
}
|
||||
|
||||
export default Maps
|
||||
|
|
Loading…
Reference in a new issue