Play 2.0 Framework, using a BodyParser with an authenticated request - parsing

I'd like to be able to use a BodyParser on an authenticated request and I'm having trouble figuring out how to do that if my Authentication is set up like the ZenTasks example.
My authentication method,
def IsAuthenticated(f: => String => Request[AnyContent] => Result) = {
Security.Authenticated(username, onUnauthorized) { user =>
Action(request => f(user)(request))
}
}
def HasRole(role: List[String])
(f: => String => Request[AnyContent] => Result) = IsAuthenticated {
user => request => if (role.contains(getRole(user))) {
f(user)(request) // This function returns the result.
} else {
Results.Forbidden
}
}
My controller method,
def controller = HasRole(List("admin")) { user => _ => {
Action(parse.temporaryFile){ implicit request =>
request.body.moveTo(new File("/tmp/filepath"))
Redirect(routes.home)
}
}
This is the error I'm seeing,
[error] found : play.api.mvc.Action[play.api.libs.Files.TemporaryFile]
[error] required: play.api.mvc.Result
[error] Action(parse.temporaryFile){ implicit request =>
[error] ^
Here is a related question: parse.json of authenticated play request
This person found a workaround, and I believe there is one for the temporary file example as well, but I'd like to know how (or why) what I'm doing is not working.

I believe I've figured this out, mainly because I left some details out of the original question that I did not realize were important.
The problem was that I was wrapping an Action { Action { } } because the IsAuthenticated method already had a call to the Action function inside it. What I ended up doing was overloading the IsAuthenticated function with a method that took BodyParser as a parameter. Because I am using the TemporaryFile method, which is not a subclass of AnyContent, I also had to change the request type.
Now, this is what my Secured trait looks like:
def IsAuthenticated(f: => String => Request[Any] => Result) = {
Security.Authenticated(username, onUnauthorized) { user =>
Action(request => f(user)(request))
}
}
def IsAuthenticated(b: BodyParser[Any] = parse.anyContent)
(f: => String => Request[Any] => Result) = {
Security.Authenticated(username, onUnauthorized) { user =>
Action(b)(request => f(user)(request))
}
}
def HasRole(role: List[String])(b: BodyParser[Any] = parse.anyContent)
(f: => String => Request[Any] => Result) = IsAuthenticated(b) {
user => request => getRole(user) match {
case Some(r) if role.contains(r) => f(user)(request)
case _ => Results.Forbidden
}
}
And this is what my controller looks like:
def controller = HasRole(List("admin"))(parse.temporaryFile) { user => request =>
request.body match {
case b:TemporaryFile => b.moveTo(new File("/tmp/file"))
case _ => Status(404)
}
}
Hope this helps someone else!

Related

How to use variables in GraphQL mutation for bulk adjust inventory?

I trying to bulk adjust inventory item of my Shopify product variants as explained in this article: https://www.shopify.com/partners/blog/multi-location_and_graphql
I tried hardcoding the variants ID in the query and it worked great :
<<-'GRAPHQL'
mutation {
inventoryBulkAdjustQuantityAtLocation(
locationId: "gid://shopify/Location/5537988719",
inventoryItemAdjustments: [
{inventoryItemId: "gid://shopify/InventoryItem/21112836292719", availableDelta: 1},
{inventoryItemId: "gid://shopify/InventoryItem/21112836325487", availableDelta: 10}
]) {
inventoryLevels {
available
}
}
}
GRAPHQL
Now I am trying to set the product variants ID as variables like follow:
require "graphql/client"
require "graphql/client/http"
class HomeController < ApplicationController
API_KEY = 'XXXXXX'.freeze
PASSWORD = 'XXXXXX'.freeze
SHARED_SECRET = 'XXXXXX'.freeze
SHOP_NAME = 'xxxxxx'.freeze
API_VERSION = '2019-04'.freeze
shop_url = "https://#{API_KEY}:#{PASSWORD}##{SHOP_NAME}.myshopify.com/admin"
ShopifyAPI::Base.site = shop_url
ShopifyAPI::Base.api_version = API_VERSION
CLIENT = ShopifyAPI::GraphQL.new
BULK_ADJUST = CLIENT.parse <<-'GRAPHQL'
mutation inventoryBulkAdjustQuantityAtLocation($inventoryItemAdjustments: [InventoryAdjustItemInput!]!, $locationId: ID!) {
inventoryBulkAdjustQuantityAtLocation(inventoryItemAdjustments: $inventoryItemAdjustments, locationId: $locationId) {
inventoryLevels {
id
}
userErrors {
field
message
}
}
}
GRAPHQL
def bulk_update_inventory
inventoryItemAdjustments = [
{ "inventoryItemId" => "gid://shopify/InventoryItem/1234", "availableDelta" => 1 },
{ "inventoryItemId" => "gid://shopify/InventoryItem/5678", "availableDelta" => 10 }
]
variables = {
"inventoryItemAdjustments" => inventoryItemAdjustments,
"locationId" => "gid://shopify/Location/9012"
}
result = CLIENT.query(BULK_ADJUST,
variables: variables)
render :json => { :result => result }
end
end
When I try to run the query I reach the following error:
Unknown action
The action 'bulk_update_inventory' could not be found for HomeController
There is anybody knows why do I have this error?
Finally got the answer!
The correct query was:
BULK_ADJUST = CLIENT.parse <<-'GRAPHQL'
mutation($inventoryItemAdjustments: [InventoryAdjustItemInput!]!, $locationId: ID!) {
inventoryBulkAdjustQuantityAtLocation(inventoryItemAdjustments: $inventoryItemAdjustments, locationId: $locationId) {
inventoryLevels {
id
}
userErrors {
field
message
}
}
}
GRAPHQL
The word "inventoryBulkAdjustQuantityAtLocation" after the "mutation" keyword had to be removed.
check your routes file and make sure you set one up for that special path.

How to call an error action from redux_epic?

I'm trying to do like so:
Stream<dynamic> searchEpic(
Stream<PerformSearchAction> actions,
EpicStore<AppState> store,
) {
return actions.asyncMap((action) => fetchPost()
.then((results) => SearchResultsAction(results['title']))
.catchError((error) => SearchErrorAction(error.message)));
}
However I get the follow error message:
type 'SearchErrorAction' is not a subtype of type "FutureOr SearchResultsAction "
I just needed to define that the type I wanted to work through the pipe as dynamic, like so:
Stream<dynamic> searchEpic(
Stream<PerformSearchAction> actions,
EpicStore<AppState> store,
) {
return actions.asyncMap<dynamic>((action) => fetchPost()
.then<dynamic>((results) => SearchResultsAction(results['title']))
.catchError((error) => SearchErrorAction(error.message)));
}

not able to add proper rule for firebase custom claim

I have created an auth token using Firebase documentation for ruby but then when I am trying to access the custom claim in the data security rules it does not work.
my JWT creation code looks something like this
$service_account_email = "service-account#my-project-abc123.iam.gserviceaccount.com"
$private_key = OpenSSL::PKey::RSA.new "-----BEGIN PRIVATE KEY-----\n..."
now_seconds = Time.now.to_i
payload = {:iss => $service_account_email,
:sub => $service_account_email,
:aud => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
:iat => now_seconds,
:exp => now_seconds+(60*60), # Maximum expiration time is one hour
:uid => uid,
:claims => {:modify_vessels => true}}
jwt_token = JWT.encode payload, private_key, "RS256"
render json: { :status => "ok", :email => usr, :jwt_token => jwt_token, :uid => uid } and return
I have tried below rules for accessing claims object but none of them work
{
"rules": {
"vessels" : {
"$uid" : {
".read":"auth.token.modify_vessels === true",
".write":"auth.token.modify_vessels === true"
}
}
}
}
and
{
"rules": {
"vessels" : {
"$uid" : {
".read":"auth.claims.modify_vessels === true",
".write":"auth.claims.modify_vessels === true"
}
}
}
}
Please Note :- I can do auth.uid and it works
Any help on this will be helpful

MongoDB Ruby aggregation with dates

I'm having trouble with the MongoDB ruby driver (via mongoid) using aggregation.
I would like to match against a date using comparison operators.
match = { '$match' => { 'created_at' => { '$gte' => DateTime.parse('2012-08-01') } } }
group = { '$group' => { '_id' => 'foo' } }
MyModel.collection.aggregate([match, group])
I don't know what to put in the first line for the date. The code as written above will throw me an undefined method __bson_dump__ for DateTime exception. Using a string doesn't seem to work, either.
Any suggestions are welcome. MongoID's built in methods give me what I need for the selection but not for the grouping.
Figured it out, use a Time object instead of DateTime
match = { '$match' => { 'created_at' => { '$gte' => Time.parse('2012-08-01') } } }
Try this.
h = { '$match' => { 'created_at' => { '$gte' => new Date("2012/08/01") } } }

Why savon :attributes! not working with an object called Objects

When supplying savon with:
hash = {
"Objects" => { //stuff here },
:attributes! => { "Objects" => {"xsi:type" => "Something"}}
}
I get:
<Objects>...</Objects>
When supplying savon with anything else i get the expected result:
hash = {
"foo" => { //stuff here },
:attributes! => { "foo" => {"xsi:type" => "Something"}}
}
I get:
<foo xsi:type="Something"></foo>
I must use the string "Objects" as the key. I am coding to a 3rd party SOAP web service. I cannot use a symbol because the first letter would become a lower cap.
thanks,
You have to change :attributes! to :#xsi:type=>"Something" within the hash where you want the attribute
Like:
"foo"=>{:#xsi:type=>'something', //stuff here}

Resources