plone.directives form - passing variables with a redirect - plone

I have a plone form that basically gets search terms, performs a search, and then directs the user to another form. For this second form, I need to pass a couple variables.
class MySearch(form.SchemaForm):
grok.context(IMyContext)
grok.name('my-search')
ignoreContext = True
schema = ISearchSchema
#button.buttonAndHandler(_(u'Search Method'))
def searchMethod(self, action):
""" group update/removal """
data, errors = self.extractData()
if errors:
self.status = self.formErrorsMessage
return
results = somecall(data['term'])
if results:
self.request.set('myvar',results['myvar'])
self.request.response.redirect('##my-results')
else:
IStatusMessage(self.request).addStatusMessage(_(u"No results found"),"info")
return
This doesn't work - I guess a new request is generated so myvar is immediately lost. I could put this in a query string and include it in the redirect, but would prefer to send it as POST data if possible. I also tried something like
return getMultiAdapter((self.context,self.request),name='my-results')()
to see if I could use that as a starting point to passing in variables, but that just returns me to my-search.

The parameters set on the request object are not taken into account (nor should they) when issuing a redirect.
Append a query string to the redirection URL instead; urllib.urlencode() does the job admirably:
from urllib import urlencode
self.request.response.redirect('##my-results?' + urlencode({'myvar': results['myvar']}))
The .redirect() call returns a 303 See Other response with the URL you passed in the the method as the Location header; the browser then opens that new location, and will include any GET parameters you added to the URL.

Related

?How can I mock a manual redirect using python requests_mock?

I have a function where I'm doing a http request to a site that should do an automatic redirect but I'm doing this manually using allow_redirects=False. I have the function itself working something like this:
def make_redirect_request(self):
url = https://some.url.com
response = requests.get(url, headers={"header": "some header"}, status_code=302, allow_redirects=False)
redirected_response = requests.get(response.next.url, headers={"header": "some other header"}, status_code=200)
self.publish(redirected_response.content) # some publishing function for publishing content on page
This works as I would like it to, but I'm struggling to make a unittest that checks this correctly. I have tried something like this:
#unittest.mock.patch("publish")
#unittest.mock.patch("url", "mock_url")
def test_redirect_url(self, mock_publish):
with patch('requests.get', self.session.get) #predefined session with parameters I don't use in this function
mock_response = b"some byte response"
next_url = "mock_redirected_url"
self.adapter.register_uri("GET", "mock_url", status_code=302, allow_redirects=False, next=next_url)
#I want the next parameter to give me the url that I'm being redirected to, which is given by response.next.url in the actual function, but this doesn't work here and it also doesn't understand the allow_redirects parameter
self.adapter.register_uri("GET", next_url, content=mock_response, status_code=200)
self.session.mount("mock", self.adapter)
self.make_redirect_request()
mock_publish.assert_called_once()
I'm not sure how to get the first request to pass the url given by response.next.url to the second request, as the adapter doesn't seem to take the next and allows_redirects arguments.

DNN rewriting URL and adding Default.aspx? in Query-String

I have a Product list page on DNN.
On this module I have a function which is called when clicked. I am adding the name of the product and SKU in the URL as a Querystring. I noticed that DNN would rewrite ?Title= to /Title/ as well as &SKU= to /SKU/ when the SKU is normal without a forward slash. For example SKU/SR2018B
The URL below would work:
www.ourwebsite.com/Product-View/Title/staple-remover-black/sku/SR2018B
My main problem is when the SKU has a special character like a forward slash, for example: SS023/10. This will cause the URL to break. I am using an encoder for the SKU. Notice that ?Title did not change to /Title/ and now there is a Default.aspx? present in the URL below.
www.ourwebsite.com/Product-View?Title/staples-2313-1000pcs-100-pages/Default.aspx?sku=SS023%2f13
Here is my Code Behind when a person is redirected to the Detailed Page.
if (tabIdToRedirectTo == null) m_alerts.ShowModuleMessage(ModuleMessage.ModuleMessageType.RedError, $"An error occurred when attempting to Redirect to the '{settingKey}' Page!", ref plcMessages, true); else Response.Redirect(Globals.NavigateURL(tabIdToRedirectTo.TabID, "", "?Title="+ hiddendescription.Value + "&sku=" + HttpUtility.UrlEncode(hiddensku.Value), EmbeddedModule.GenerateFullQueryStringForEmbedding(EmbeddedCompanyCode, EmbeddedShowCustPricing)));
I believe it's how you're calling the Globals.NavigateUrl function. The call takes a params of strings which are your query strings in the key=value format. I usually like to easily see what I am about to pass so I do something like the following:
var qsParams = new List<string>{
"Title=" + hiddendescription.Value, // "Title=staples-2313-1000pcs-100-pages"
"sku=" + HttpUtility.UrlEncode(hiddensku.Value), // "sku=SS023%2f13"
EmbeddedModule.GenerateFullQueryStringForEmbedding(EmbeddedCompanyCode, EmbeddedShowCustPricing)
};
return Globals.NavigateURL(tabIdToRedirectTo.TabID, "", qsParams.ToArray());
Granted - I do not know what your EmbeddedModule.GenerateFullQueryStringForEmbedding does, but as long as it returns a key=value type output, it should be passed and processed well.

How to consume api rest using TurboGears2?

I want to show the data in the view
r = requests.get('https://jsonplaceholder.typicode.com/posts')
print(r)
print(r.headers)
print(r.encoding)
data = r.json()
log.debug(data)
log.debug(r)
for post in data:
s = format(post["id"],post['title'])
Any ideas?
Inside your web-app create a controller having #expose('json') as the decorator and then you can request that url the way you want. While requesting the url you may want to append .json at the end of the url. For example in your case
#expose('json')
def posts(self, *args, **kwargs):
#do your stuff
return dict(data=data)
and then you can easily call this url.
r = requests.get('https://jsonplaceholder.typicode.com/posts.json')

adding params in faraday middleware

I am trying to write a middleware that will set additional params to the query string. The use case is to be able to add additional authentication tokens, for eg, to the request as required by the backend, but wanting to inject it independent of the request creation itself.
This is what my middleware(pseudo code) looks like:
class MyMiddleware < Struct.new(:app, :key, :value)
def call(env)
env.params[key] = value #1
#env.params = {key => value} #2
app.call env
end
end
above raises NoMethodError (undefined method[]=' for nil:NilClass)`
above sets the params hash but the parameter is not encoded as part of the query string. The query string remains what it was before the middlewares start processing the request.
My analysis is that since the query string gets built from the params in rack_builder.rb:191
def build_response(connection, request)
app.call(build_env(connection, request))
end
def build_env(connection, request)
Env.new(request.method, request.body,
connection.build_exclusive_url(request.path, request.params), #<== rack_builder.rb:191
request.options, request.headers, connection.ssl,
connection.parallel_manager)
end
Middlewares don't get the opportunity to set additional params. While env has a params property, it is nil and doesn't appear to be touched during or after the middlewares get invoked.
So, I have the following questions:
1. Is there a supported way to achieve this?
2. If not, is there a way to rebuild the query string as part of the middleware executing?
3. Would it be better to defer the URL building to after most of the request middleware chain is executed (but of course, before the adapter gets to do its thing; or do it in the adapter)?
4. Any other options?
Appreciate any guidance.
The answer is here at github: https://github.com/lostisland/faraday/issues/483 by #mislav
Inside the middleware, the request URL is already fully constructed together with all the configured query parameters in a string. The only way to add or remove query parameters is to edit the env.url.query string, e.g.:
MyMiddleware = Struct.new(:app, :token) do
def call(env)
env.url.query = add_query_param(env.url.query, "token", token)
app.call env
end
def add_query_param(query, key, value)
query = query.to_s
query << "&" unless query.empty?
query << "#{Faraday::Utils.escape key}=#{Faraday::Utils.escape value}"
end
end
conn = Faraday.new "http://example.com" do |f|
f.use MyMiddleware, "MYTOKEN"
f.adapter :net_http
end
However, if your middleware is going to be like MyMiddleware above and just add a static query parameter to all requests, the much simpler approach is to avoid the middleware and just configure the Faraday connection instance to apply the same query parameter to all requests:
conn = Faraday.new "http://example.com" do |f|
f.params[:token] = "MYTOKEN"
f.adapter :net_http
end

Get string from current URL

I am writing an asp.net MVC Application. I have the application send a request to FreeAgent and if the request is successful a code is returned in the redirect of the URL.
For example this is a copy of a successful URL.
{
http://localhost:3425/FreeAgent/Home?code=144B2ymEKw3JfB9EDPIqCGeWKYLb9IKc-ABI6SZ0o&state=
}
They have added the ?code=144B2ymEKw3JfB9EDPIqCGeWKYLb9IKc-ABI6SZ0o&state= to my URL
I need the bit after the ?code= and before &state=
I can use this to get the URL
string code = Request.Url.AbsoluteUri;
but I need help extracting the code from this
edit:
The code will be different each time it is run
You can use the System.Uri and System.Web.HttpUtility classes
string uri = "http://localhost:3425/FreeAgent/Home?code=144B2ymEKw3JfB9EDPIqCGeWKYLb9IKc-ABI6SZ0o&state=";
string queryString = new System.Uri(uri).Query;
var queryDictionary = System.Web.HttpUtility.ParseQueryString(queryString);
Then the value of the code query parameter will be available in queryDictionary["code"]

Resources