I'm having a bit of a problem figuring out how to generate user friendly links to products for sharing.
I'm currently using /product/{uuid4_of_said_product}
Which is working quite fine - but it's a bit user unfriendly - it's kind of long and ugly.
And I do not wish to use and id as it would allow users to "guess" products. Not that that is too much of an issue - I would like to avoid it.
Do you have any hints on how to generate unique, user friendly, short sharing urls based on the unique item id or uuid?
Have you tried these https://github.com/corpix/shortid and one for django here https://github.com/nebstrebor/django-shortuuidfield
As Seluck suggested I decided to go with base64 encoding and decoding:
In the model my "link" property is now built from the standard url + base64.urlsafe_b64encode(str(media_id))
The url pattern I use to match the base64 pattern:
base64_pattern = r'(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$'
And finally in the view we decode the id to load the proper data:
media_id = base64.urlsafe_b64decode(str(media_id))
media = Media.objects.get(pk=media_id)
Related
I am working on an application built using Python3 and Django that generates PDFs (via HTML) using filled fields from a data model.
I've created a URL function that takes a value of document ID and type, and then generates a PDF of that document.
What I want to do is to email clients a link that contains that URL function with a specific document ID, however, the problem that I'm facing is that the generated URL has the document ID in the URL parameter, and this is terrible for security purposes as all they can do is change ID number on URL and get access to a different document (that they are not supposed to see)
My questions are:
A- Is there a way to create a unique link for every generated PDF that I can send to clients?
B- Would it be better to create another field in the model of a randomly generated 15 character value, that I use instead of the ID in the parameter?
Ok so I have fixed it by doing the following:
1- UUID was definetly the way, thank you #Toan Quoc Ho for that suggestion. I have added a UUID field to each of the models,
2- Because I wanted to keep my PK as ID, I had the problem of generating unique UUID fields of existing documents. So I followed this solution, and it worked magically. Only thing to note is that there can be no traffic when applying these changes, otherwise the database will crash, be aware.
3- I, then, used the UUID together with ID to determine documents and passed them as URL parameters using regex as (\d+)/([\w-]+)
Voila, that did exactly what I wanted. No two documents share the same UUID, and vice-versa. I could generate a link unique to each document, and block any other access.
I would use the new secrets module available in Python 3.6+. Here is an example:
from secrets import token_urlsafe
random_string = token_urlsafe(16)
print(random_string)
The result would be something like this - nslhgo0dYowR6CvMDEwC_A.
After trying everything suggested here, I still can't get SQLAlchemy to display the correct results!
I've used various combinations of Nick's answer, session.commit(), flush() and expire_all(), restarted MySQL, even restarted the entire freaking server, and I still get old results from SQLAlchemy...why????
The most infuriating thing about this whole issue is that I can see from any other application, or even from a direct connection.execute() call, that the updated data is there. I just can't get it to display on the webpage!
BTW this is in a Pyramid app, not Flask, but since Pyramid is 99% Flask it shouldn't make a difference, right?
MTIA for any help on this, it's driving me nuts!!
PS: I tried to add this as an answer to the linked question, but it was deleted for not being a valid answer. So for future reference, if I just want to add something to an existing question without having to post an entirely new one, how would I go about that?
EDIT: My apologies zvone, here is my code:
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
session = DBSession()
query = session.query(Item).join(Item.tagged)
filters = []
for term in searchTerms:
subterms = term.split(' ')
for subterm in subterms:
filters.append(Item.itemTitle.like('%' + subterm + '%'))
filters.append(Tag.tagName.like('%' + subterm + '%'))
query = query.filter(or_(*filters))
matchedItems = query.all()
And to make some more sense out of it, here's the context:
I'm building a basic CMS where users can upload and download items of any type (text files, images, etc.).
The whole idea of this page is to allow the user to search for items that have been tagged with certain expressions. Tags are entered in the search field as a comma-delimited string of search phrases, e.g. "movies, books, photos, search term with spaces". This string is split up into its counterparts to create searchTerms, a Python list of all the terms entered into the field.
You can see in the code where I'm iterating through searchTerms, splitting phrases into separate words and adding query filters for each word.
The problem arises when searching for "big, theory". I know for certain that 3 users on the production site have posted Big Bang Theory episodes, but after migrating these DB records to my dev server, I only get one search result (the old amount).
Many thanks again for the help! :D
I am having problem with doing simple things using Steams 64 bit id.
How can i use SteamAPI to get the general information? like displaying name, username, location.
I used SteamAuth to make my social authentication on website, which only has the function, that gets the id.
Example:
steamid = GetSteamID64()
username = GetUsername()
displayname = GetDisplay()
...
Does SteamAPI on have features related to this? is there any library in python that could support such thing?
There are a whole lot of WebAPI methods to get details about a Steam user. You seem to be looking for GetPlayerSummaries.
You'll need an API key to use it.
I've included a search form in my web2py application, in the following form:
myapp/controller/search?query=myquery
However, for security reasons web2py automatically replaces spaces and non-alphanumeric characters with underscores, which is okay for English-only sites but
an impediment for languages that use accent marks. For example, searching for "áéíóú" returns five underscores.
This could be solved by using POST instead of GET for the search form, but then the users wouldn't be able to bookmark the results.
Is there any option to solve this?
Thanks in advance.
Here's an idea that I've used in the past:
Use post to submit the query
Generate a unique string (e.g. youtube: https://www.youtube.com/watch?v=jX3DuS2Ak3g)
Associate the query to that string and store as key/value pair in session/app state/db (depending on how long you want it to live)
Redirect the user to that
If you don't want to occupy extra memory/space as they tend to grow a lot in some cases, you can substitute steps 2-3 with encrypting the string to something you can decrypt afterwards. You can do this in a middleware class so that it's transparent to your app's logic.
This is a general problem people face while handling urls.
You can use the quote/quote_plus module in urllib to normalize the strings -
For example, from the strings you suggested -
>>> print urllib.quote('éíóú')
%C3%A9%C3%AD%C3%B3%C3%BA
>>> print urllib.unquote('%C3%A9%C3%AD%C3%B3%C3%BA')
éíóú
you will have to perform the unquote when you retrieve it on the backend from the request.
There are also some other posts which might be helpful - urlencode implementation and unicode ready urls
I have a app that uses Python Requests to query a Tasty-Pie enabled Django app.
I have a model called Application, with a corresponding Tasty-Pie resource.
This model/Resource has several foreign keys that link Application to other models (e.g. Binary, Host, Colocation etc.)
I'm using a Tasty-Pie filter to get a subset of Applications, then I want to print a nice table of Applications, along with some fields from those related models.
Right now, I'm using the following to get a table of Applications:
def get_applications(self, parsed_args):
r = requests.get('http://foobar.com:8000/api/v1/application/?name__iregex={0}&format=json'.format(parsed_args.applications))
print(r.url)
return r
def application_iter(self, parsed_args):
for application in self.get_applications(parsed_args).json['objects']:
yield (application['name'], application['author'], application['some_other_field'])
def take_action(self, parsed_args):
return(('Name', 'Author', 'Some Other Field),
self.application_iter_iter(parsed_args),
)
My question is, what is the "recommended", or idiomatic way of pulling in all the related fields? Is there a way to extend the above to do this?
I get the impression that full=True is a bad practice, and that using resource URI's is a better way.
How can I do this whilst minimising the number of requests and DB hits?
Cheers,
Victor
why do you think that full=True is bad?
https://django-tastypie.readthedocs.org/en/latest/resources.html#why-resource-uris
Ideology aside, you should use whatever suits you. If you prefer fewer requests & fewer endpoints, use of full=True is available, but be aware of the consequences of each approach.
You can do whatewer you like if it can be read cleanly and if it does what you want. "full=True" is there to be used by developers