I have the follow code in my routes.coffee file, the Router.onBeforeAction(... function seems to be ignoring the except option and continually redirects to the 'sign-in' template. Why is this?
enforceLogin = ->
if Meteor.userId() is undefined or Meteor.userId() is null
isLoggedIn = false
Router.go '/sign-in'
else
isLoggedIn = true
return isLoggedIn
isCharacterNamed = ->
userCharacter = Characters.findOne ownedBy: Meteor.userId()
userCharacter.name is not undefined
checkCharacterNamed = (context) ->
if !isCharacterNamed()
Router.go 'create-character'
userCharactersSubscription = -> Meteor.subscribe 'userCharacters'
nonGameRoutes = ['sign-in', 'sign-up', 'sign-out', 'blog']
Router.map ->
#route 'home', path: '/'
#route 'adventures'
#route 'create-character', onBeforeAction: ->
enforceLogin()
if #ready()
if isCharacterNamed() then Router.go 'home'
#route 'blog'
#route 'admin/blog'
#route 'loading'
#route 'sign-in'
#route 'sign-up'
#route 'sign-out'
Router.onBeforeAction('loading')
Router.onBeforeAction enforceLogin, { except: nonGameRoutes }
Router.waitOn(userCharactersSubscription)
Router.onAfterAction ->
if #ready()
checkCharacterNamed()
#render()
else
#render('loading')
,
{ except: _.union(nonGameRoutes, ['create-character']) }
Try `Router.onBeforeAction enforceLogin, except: nonGameRoutes
Related
I'm following this guide, with Zipkin.
I have 3 microservices involed, A -> B -> C, I'm propagating headers from A to B and from B to C.
But in the Zipkin dashboard I only see entries for A -> B and B -> C, not A -> B -> C.
Those are the headers:
[
"x-request-id",
"x-b3-traceid",
"x-b3-spanid",
"x-b3-parentspanid",
"x-b3-sampled",
"x-b3-flags",
"x-ot-span-context"
]
I can see that in B x-b3-parentspanid is null and I guess that's wrong, but the other are working I think...how is it possible?
EDIT:
added code snippets to show headers propagation
A -> B propagation:
app.post("/job", (req, res) => postJob(req.body, req.headers).then((response) => res.send(response)))
...
const postJob = (job, headers) => rp({
method: "POST",
uri: `${API_ENDPOINT}/api/job`,
json: true,
body: job,
headers: Object.keys(headers).filter((key) => TRACING_HEADERS.includes(key)).map((key) => headers[key])
})
B -> C propagation:
#PostMapping("/api/job")
#ResponseBody
fun publish(
#RequestBody job: Job,
#RequestHeader("x-request-id") xreq: String?,
#RequestHeader("x-b3-traceid") xtraceid: String?,
#RequestHeader("x-b3-spanid") xspanid: String?,
#RequestHeader("x-b3-parentspanid") xparentspanid: String?,
#RequestHeader("x-b3-sampled") xsampled: String?,
#RequestHeader("x-b3-flags") xflags: String?,
#RequestHeader("x-ot-span-context") xotspan: String?
): JobResponse = jobsService.publishJob(
job, mapOf(
"x-request-id" to xreq,
"x-b3-traceid" to xtraceid,
"x-b3-spanid" to xspanid,
"x-b3-parentspanid" to xparentspanid,
"x-b3-sampled" to xsampled,
"x-b3-flags" to xflags,
"x-ot-span-context" to xotspan
)
)
...
fun publishJob(job: Job, headers: Map<String, String?>): JobResponse {
val enabled = restTemplate.exchange(
"${gatekeeperConfiguration.endpoint}/",
HttpMethod.GET,
HttpEntity(headers),
EnabledResponse::class.java
).body
if (!enabled!!.isEnabled) // TODO we intentionally want this to crash if body is null
return JobResponse(JobRequestStatus.REJECTED)
return if (this.queue.publish(job)) JobResponse(JobRequestStatus.OK)
else throw RuntimeException("I don't know what to do, yet")
}
Object.keys(headers).filter((key) => TRACING_HEADERS.includes(key)).map((key) => headers[key]) returns an array.
What you want is:
Object.keys(headers)
.filter(key => TRACING_HEADERS.includes(key))
.reduce((obj, key) => {
obj[key] = headers[key];
return obj;
}, {})
I'm pretty sure this isn't an istio / distributed tracing issue ;-)
b3-propagation of x-b3-parentspanid (https://github.com/openzipkin/b3-propagation) can be configured in your application.yml by adding:
opentracing:
jaeger:
enable-b3-propagation: true
The following coffeeScript is running properly without the references to setUpdateInterval.
class Notifications
constructor: ->
#notifications = $("[data-behavior='notifications']")
#setup() if #notifications.length > 0
setUpdateInterval()
setup: ->
$.ajax(
url: "/notifications.json"
dataType: "JSON"
method: "GET"
success: #handleSuccess
)
handleSuccess: (data) =>
items = $.map data, (notification) ->
"<li class='active'><a href='#{notification.url}'>#{notification.actor} #{notification.notifiable.type}</a></li>"
$("[data-behavior='unread-count']").text(items.length)
$("[data-behavior='notification-items']").html(items)
setUpdateInterval: (notifications) ->
callback = #setup.bind(this)
setInterval( callback, 15000 )
jQuery ->
new Notifications
What is incorrect with the additional line and bloc inserted?
Based on comment, the following functions.
constructor: ->
#notifications = $("[data-behavior='notifications']")
#setUpdateInterval()
#setup() if #notifications.length > 0
setup: ->
$.ajax(
url: "/notifications.json"
dataType: "JSON"
method: "GET"
success: #handleSuccess
)
setUpdateInterval: (notifications) ->
callback = #setup.bind(this)
setInterval( callback, 15000 )
I have been working around lately with the Twitter typeahead jQuery plugin. It is mostly working, but it gives me 'Undefined' as the search result.
Here is my folder.js.coffee:
$(document).ready ->
console.log("searchhhhh");
haunt = undefined
repos = undefined
repos = new Bloodhound(
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value')
queryTokenizer: Bloodhound.tokenizers.whitespace
limit: 10
prefetch:
url: '/auto_search.json',
filter: (list) ->
$.map list.results, (auto) ->
{ value: auto }
)
repos.initialize()
$('#auto_search').typeahead null,
name: 'repos'
displayKey: 'value'
source: repos.ttAdapter()
return
This worked.
$(document).ready ->
console.log("searchhhhh");
haunt = undefined
repos = undefined
repos = new Bloodhound(
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name')
queryTokenizer: Bloodhound.tokenizers.whitespace
limit: 10
prefetch:
url: '/auto_search.json',
filter: (list) ->
$.map list.results, (auto) ->
{ value: auto }
)
repos.initialize()
$('#auto_search').typeahead null,
name: 'repos'
displayKey: 'name'
source: repos.ttAdapter()
return
I am trying to modify the http status code of create.
POST /api/users
{
"lastname": "wqe",
"firstname": "qwe",
}
Returns 200 instead of 201
I can do something like that for errors:
var err = new Error();
err.statusCode = 406;
return callback(err, info);
But I can't find how to change status code for create.
I found the create method:
MySQL.prototype.create = function (model, data, callback) {
var fields = this.toFields(model, data);
var sql = 'INSERT INTO ' + this.tableEscaped(model);
if (fields) {
sql += ' SET ' + fields;
} else {
sql += ' VALUES ()';
}
this.query(sql, function (err, info) {
callback(err, info && info.insertId);
});
};
In your call to remoteMethod you can add a function to the response directly. This is accomplished with the rest.after option:
function responseStatus(status) {
return function(context, callback) {
var result = context.result;
if(testResult(result)) { // testResult is some method for checking that you have the correct return data
context.res.statusCode = status;
}
return callback();
}
}
MyModel.remoteMethod('create', {
description: 'Create a new object and persist it into the data source',
accepts: {arg: 'data', type: 'object', description: 'Model instance data', http: {source: 'body'}},
returns: {arg: 'data', type: mname, root: true},
http: {verb: 'post', path: '/'},
rest: {after: responseStatus(201) }
});
Note: It appears that strongloop will force a 204 "No Content" if the context.result value is falsey. To get around this I simply pass back an empty object {} with my desired status code.
You can specify a default success response code for a remote method in the http parameter.
MyModel.remoteMethod(
'create',
{
http: {path: '/', verb: 'post', status: 201},
...
}
);
For loopback verion 2 and 3+: you can also use afterRemote hook to modify the response:
module.exports = function(MyModel) {
MyModel.afterRemote('create', function(
context,
remoteMethodOutput,
next
) {
context.res.statusCode = 201;
next();
});
};
This way, you don't have to modify or touch original method or its signature. You can also customize the output along with the status code from this hook.
I've got a small react app I'm playing with, just go get the hang of the library. The app is just a series of lists, which are populated from a server. When a list item is clicked, the value of that item is added to a list filters at the app level, which will then be used to call new data to populate the lists.
The problem is that I can't seem to get my lists to reconcile with the new data from the app (parent), even when calling setState. Here's my code (coffee):
###
#jsx React.DOM
###
{div, h1, h2, h4, ul, li, form, input, br, p, strong, span, a} = React.DOM
SearchApp = React.createClass
handleTopItemClick: (filter) ->
facet = filter.field
filters = #state.filters
if filters.facets[facet] and filters.facets[facet].length > 0
filters.facets[facet].push filter.value
else
filters.facets[facet] = [filter.value]
strArr = []
_.each filters.facets, (valArr, field) ->
_.each valArr, (val) ->
strArr.push "+(#{field}:\"#{val}\")"
#setState
filters: filters
queryStr: strArr.join(' ').trim()
getInitialState: ->
filters:
facets: {}
queryStr: ''
render: ->
(div {
id: 'content'
className: "search-wrap"
},
(h1 {}, "Search")
(div
id: 'widgets',
(TopList
title: 'Top Domains'
params:
query: #state.queryStr
field: 'domain'
onItemClick: #handleTopItemClick
)
(TopList
title: 'Top Senders'
params:
query: #state.queryStr
field: 'from'
onItemClick: #handleTopItemClick
)
(TopList
title: 'Top Recipient'
params:
query: #state.queryStr
field: 'recipient'
onItemClick: #handleTopItemClick
)
)
)
TopItem = React.createClass
getDefaultProps: ->
value: ''
count: 0
field: null
render: ->
(li {},
(a {
onClick: #handleClick
className: 'top-item-filter'
title: #props.value
},
(strong {}, #props.value)
(span {}, #props.count)
)
)
handleClick: (event) ->
event.preventDefault()
#props.onItemClick #props.value
TopList = React.createClass
getInitialState: ->
data: []
params: #props.params
componentWillReceiveProps: (nextProps) ->
#setState params: nextProps.params
componentWillMount: ->
request.post("/facet").send(#state.params).end (results) =>
#setState data: JSON.parse(results.text)
render: ->
itemNodes = _.map #state.data, (item) =>
key = item.value
TopItem
value: item.value
count: item.count
key: key
onItemClick: #handleItemClick
(div {className: 'widget top-item'},
(h2 {className: 'widget-header'}, "#{#props.title}")
(ul {className: 'top-items-list'}, itemNodes)
)
handleItemClick: (value) ->
#props.onItemClick
value: value
field: #props.params.field
React.renderComponent SearchApp(null), document.getElementById("content")
The lists all render fine the first time around, fetching the unfiltered data as expected. When I click on a list item, the SearchApp receives the event, and updates its own state accordingly. componentWillReceiveProps is properly called on the TopList classes, but the setState call there doesn't update their state, and thus, they aren't reconciling. I've verified that nextProps contains the new information. What am I missing?
There isn't really any reason to save the props in state; and it's much less error prone to keep props as the source of truth. It also simplifies the code a bit.
For the actual issue, though; componentWillMount is only called once here. If you want to repeat the AJAX request when new params are passed; you can do that like so:
TopList = React.createClass
getInitialState: ->
data: []
getSearchResultsFromServer: (params) ->
request.post("/facet").send(params).end (results) =>
if #isMounted()
#setState data: JSON.parse(results.text)
componentWillReceiveProps: (nextProps) -> #getSearchResultsFromServer nextProps.params
componentDidMount: -> #getSearchResultsFromServer #props.params
render: ->
itemNodes = _.map #state.data, (item) =>
key = item.value
TopItem
value: item.value
count: item.count
key: key
onItemClick: #handleItemClick
(div {className: 'widget top-item'},
(h2 {className: 'widget-header'}, "#{#props.title}")
(ul {className: 'top-items-list'}, itemNodes)
)
handleItemClick: (value) ->
#props.onItemClick
value: value
field: #props.params.field
Ideally, your ajax library would support aborting requests; and in componentWillUnmount you abort those requests.