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

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.

Related

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')

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"]

Is there a way to assign an external URL to a HyperLink without appending http:// or https:// (ie, the protocol)?

I have a HyperLink defined like so:
<asp:HyperLink ID="hltest" runat="server"></asp:HyperLink>
In my code, I do this:
hltest.NavigateUrl = "www.google.com"
However, the actual link looks like this:
http://localhost:53305/www.google.com
I can append http:// to the URL, but this not the preferred method because this URL is maintainable by the user. If the user saves the URL as http://www.google.com then the URL will end up looking like http://http://www.google.com. I know that I can strip http:// from the URL and then add it back to ensure that it doesn't show up twice, but this is extra code/helper method that I would like to avoid writing.
Edit: This is the type of code I am trying to avoid having to write:
hltest.NavigateUrl = "http://" & "hTTp://www.google.com".ToLower().Replace("http://", String.Empty)
Update I know I specifically asked how to do this without appending the protocol to the URL, but it looks like there's just no other way to do it. The selected answer brought me to this solution:
Function GetExternalUrl(Url As String) As String
Return If(New Uri(Url, UriKind.RelativeOrAbsolute).IsAbsoluteUri, Url, "http://" & Url)
End Function
This is great because, if the user enters just www.google.com, it will append http:// to the URL. If the user provides the protocol (http, https, ftp, etc), it will preserve it.
Use the Uri class and handle it accordingly:
Uri uri = new Uri( userProvidedUri, UriKind.RelativeOrAbsolute );
if( !uri.IsAbsolute ) hltest.NavigateUrl = "http://" + userProvidedUri;
else hltest.NavigateUrl = userProvidedUri;

plone.directives form - passing variables with a redirect

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.

Resources