django email validation issue - python

I'm trying to create a custom column type using django_tables2 so that I can render contact details as a mailto: link when the result is a valid email address, and just standard text otherwise.
The issue that I'm having is that my value seems to be returned as iterated characters, and as per the code below, the first character of the email address is render as part of mailto: whilst the second character of the email address is rendered in the column. Aside from validate_email I have tried if "#" in and regex, all returning the same iterated character results.
class ContactColumn(tables.Column):
def render(self,value):
try:
validate_email(value)
return format_html('''{}''',*value)
except ValidationError:
return value
Can anyone point me in the right direction as to how to successfully render either a mailto: link or just standard text based on valid email address? Any help is much appreciated!

The problem here is your *value argument.
The asterisk means to unpack a sequence (here, a string) into its parts (characters) and use those for the arguments. (Search for "Python argument unpacking" to learn more.)
Instead, just do:
format_html('''{}''', value, value)

Related

Replace multiple values in string using replace, sub string and find in Python

So im pulling issues from our jira project and I need to replace url's with new formatted url's in the description.
old description contains the old sharepoint server URL's so I need to change them to our new online Sharepoint url.
I decided to use Python to make use of the atlassian plugin.
here is a version of how the description looks like in the jira issue currently:
Good day
we need a new validation on the External Reference when doing work pads or amending manually when we do refund, it seems that the user that updates this is using Tab or Enter and therefore the payment files fails ,
we need users to be validated while updating refund reference same way as we limited claims payments for updating invoice numbers
thank you
regards
*BRS & FRS:*
[BRS_FRS_PS_ACC_Payments_v20.0|http://portal.mycompany.local/mycompany/someproject/_layouts/15/start.aspx#/someproject/Forms/AllItems.aspx?RootFolder=%2Fmycompany%2Fsomeproject%2Fsomeproject%2F06%20Solution%20Documentation%2F03%20Accounting%2C%20Etc%2F07%20TIA%2FBRS%20%26%20FRS&View=%7B9A71C976%2D85D3%2D4D34%2D828B%2DE5B1B428EA5E%7D]
[BRS_FRS_PS_ACC_Workpads_Manual_Write_Off_and_Incomming_Paument_v5.0|http://portal.mycompany.local/mycompany/someproject/_layouts/15/start.aspx#/someproject/Forms/AllItems.aspx?RootFolder=%2Fmycompany%2Fsomeproject%2Fsomeproject%2F06%20Solution%20Documentation%2F03%20Accounting%2C%20Etc%2F07%20TIA%2FBRS%20%26%20FRS&View=%7B9A71C976%2D85D3%2D4D34%2D828B%2DE5B1B428EA5E%7D]
*Sign Offs:*
[BRS_FRS_PS_ACC_Payments_v20.0|http://portal.mycompany.local/mycompany/someproject/_layouts/15/start.aspx#/someproject/Forms/AllItems.aspx?RootFolder=%2Fmycompany%2Fsomeproject%2Fsomeproject%2F06%20Solution%20Documentation%2F03%20Accounting%2C%20Etc%2F07%20TIA%2FBRS%20%26%20FRS%2FSign%2Doffs%2FPayments%2FV20%2E0&FolderCTID=0x0120005C60D5FB65C2C84191CB5ACDFD820AA6&View=%7B9A71C976%2D85D3%2D4D34%2D828B%2DE5B1B428EA5E%7D]
[BRS_FRS_PS_ACC_Workpads_Manual_Write_Off_and_Incomming_Paument_v5.0|http://portal.mycompany.local/mycompany/someproject/_layouts/15/start.aspx#/someproject/Forms/AllItems.aspx?RootFolder=%2Fmycompany%2Fsomeproject%2Fsomeproject%2F06%20Solution%20Documentation%2F03%20Accounting%2C%20Etc%2F07%20TIA%2FBRS%20%26%20FRS%2FSign%2Doffs%2FWorkpads%20%26%20incoming%20payments%2FV5%2E0&FolderCTID=0x0120005C60D5FB65C2C84191CB5ACDFD820AA6&View=%7B9A71C976%2D85D3%2D4D34%2D828B%2DE5B1B428EA5E%7D]
*Technical Documentation:*
N/A
*Unit Testing:*
[TU_dd-1821|http://portal.mycompany.local/mycompany/someproject/SitePages/Home.aspx?RootFolder=%2Fmycompany%2Fsomeproject%2Fsomeproject%2F06%20Solution%20Documentation%2F03%20Accounting%2C%20Etc%2F07%20TIA%2FUnit%20Testing&FolderCTID=0x0120005C60D5FB65C2C84191CB5ACDFD820AA6&View=%7B5AF02A9E%2D451A%2D443D%2DB8CA%2DAF7C7ED6F00C%7D]
this is how i pulled in the issue from Jira( my plan is to scan through all issues and update.
from jira import JIRA
import re
jira = JIRA(server=('https://mycompanydev.atlassian.net'),basic_auth=('user', 'password'))
issue = jira.issue("S1-3000")
print("Ticket nr: ", issue)
olddescription = issue.fields.description
newdescription = olddescription
So i managed to change the first part of the url with this line:
newdescription = newdescription.replace("http://portal.mycompany.local/mycompany/someproject/_layouts/15/start.aspx#/someproject/Forms/AllItems.aspx?RootFolder=%2Fmycompany%2Fsomeproject%2F", "https://somecompany.sharepoint.com/sites/CCPortal/")
and this line:
newdescription = newdescription.replace("http://portal.mycompany.local/mycompany/someproject/SitePages/Home.aspx?RootFolder=%2Fmycompany%2Fsomeproject%2F", "https://mycompany.sharepoint.com/sites/CCPortal/")
this code completes successfully and changes the URL as intended.
Now i need to remove the end of the url from the string "View=" and the string "FolderCTID="
my line of code to do this:
newdescription = newdescription.replace(newdescription[newdescription.find("View=")-1:newdescription.find("]")],"")
and:
newdescription = newdescription.replace(newdescription[newdescription.find("FolderCTID="):newdescription.find("]")], "")
for some reason it only does the first 2 URLs:
result looks like this:
Good day
we need a new validation on the External Reference when doing work pads or amending manually when we do refund, it seems that the user that updates this is using Tab or Enter and therefore the payment files fails ,
we need users to be validated while updating refund reference same way as we limited claims payments for updating invoice numbers
thank you
regards
*BRS & FRS:*
[BRS_FRS_PS_ACC_Payments_v20.0|https://mycompany.sharepoint.com/sites/mycompany/someproject%2F06%20Solution%20Documentation%2F03%20Accounting%2C%20Etc%2F07%20TIA%2FBRS%20%26%20FRS]
[BRS_FRS_PS_ACC_Workpads_Manual_Write_Off_and_Incomming_Paument_v5.0|https://mycompany.sharepoint.com/sites/mycompany/someproject%2F06%20Solution%20Documentation%2F03%20Accounting%2C%20Etc%2F07%20TIA%2FBRS%20%26%20FRS]
*Sign Offs:*
[BRS_FRS_PS_ACC_Payments_v20.0|https://mycompany.sharepoint.com/sites/mycompany/someproject%2F06%20Solution%20Documentation%2F03%20Accounting%2C%20Etc%2F07%20TIA%2FBRS%20%26%20FRS%2FSign%2Doffs%2FPayments%2FV20%2E0&FolderCTID=0x0120005C60D5FB65C2C84191CB5ACDFD820AA6]
[BRS_FRS_PS_ACC_Workpads_Manual_Write_Off_and_Incomming_Paument_v5.0|https://mycompany.sharepoint.com/sites/mycompany/someproject%2F06%20Solution%20Documentation%2F03%20Accounting%2C%20Etc%2F07%20TIA%2FBRS%20%26%20FRS%2FSign%2Doffs%2FWorkpads%20%26%20incoming%20payments%2FV5%2E0&FolderCTID=0x0120005C60D5FB65C2C84191CB5ACDFD820AA6]
*Technical Documentation:*
N/A
*Unit Testing:*
[TU_MV-1821|https://mycompany.sharepoint.com/sites/mycompany/someproject%2F06%20Solution%20Documentation%2F03%20Accounting%2C%20Etc%2F07%20TIA%2FUnit%20Testing&FolderCTID=0x0120005C60D5FB65C2C84191CB5ACDFD820AA6&View=%7B5AF02A9E%2D451A%2D443D%2DB8CA%2DAF7C7ED6F00C%7D]
as you can see the code removed the first 2 "View=" strings with the trailing string to the end.
I cant figure out where I went wrong I also tried putting this in a while loop and just repeating the code 5 times for a test.
str.find returns the lowest index where the substring is found. So if newdescription has more than one "]", presumably because it contains more than one link, that means the returned index will only be correct for the first link.
str.find also accepts an optional start/end index to limit the search, so you can use the index of "View=" as an offset for the search for "]":
offset = newdescription.find("View=")
replace_me = newdescription[offset:newdescription.find("]", offset)]
newdescription = newdescription.replace(replace_me, "")

Django Full Text Search Not Matching Partial Words

I'm using Django Full Text search to search across multiple fields but have an issue when searching using partial strings.
Lets say we have a report object with the name 'Sample Report'.
vector = SearchVector('name') + SearchVector('author__username')
search = SearchQuery('Sa')
Report.objects.exclude(visible=False).annotate(search=vector).filter(search=search)
The following QuerySet is empty but if I include the full word 'Sample' then the report will appear in the QuerySet.
Is there anyway to use icontains or prefixing with django full text search?
This is working on Django 1.11:
tools = Tool.objects.annotate(
search=SearchVector('name', 'description', 'expert__user__username'),
).filter(search__icontains=form.cleaned_data['query_string'])
Note the icontains in the filter.
#santiagopim solution is correct but to address Matt's comment for if you get the following error:
ERROR: function replace(tsquery, unknown, unknown) does not exist
at character 1603 HINT: No function matches the given name
and argument types. You might need to add explicit type casts.
You have to remove the call to SearchQuery and just use a plain string.
I know this doesn't address the underlying issue for if you need to use SearchQuery but if you are like me and just need a quick fix, you can try the following.
vector = SearchVector('name') + SearchVector('author__username')
# NOTE: I commented out the line below
# search = SearchQuery('Sa')
search = 'Sa'
Report.objects.exclude(visible=False).annotate(search=vector)\
.filter(search__icontains =search)
This other answer might be helpful.

Validate email local component

I'm writing a registration form that only needs to accept the local component of a desired email address. The domain component is fixed to the site. I am attempting to validate it by selectively copying from validators.validate_email which Django provides for EmailField:
email_re = re.compile(
r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
# quoted-string, see also http://tools.ietf.org/html/rfc2822#section-3.2.5
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"'
r')#((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$)' # domain
r'|\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$', re.IGNORECASE) # literal form, ipv4 address (SMTP 4.1.3)
validate_email = EmailValidator(email_re, _(u'Enter a valid e-mail address.'), 'invalid')
Following is my code. My main issue is that I'm unable to adapt the regex. At this point I'm only testing it in a regex tester at http://www.pythonregex.com/ however it's failing:
^([-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*)$
This seems to be passing undesirable characters such as ?
The entire code for my Field, which is not necessarily relevant at this stage but I wouldn't mind some comment on it would be:
class LocalEmailField(CharField):
email_local_re = re.compile(r"^([-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*)$", re.IGNORECASE)
validate_email_local = RegexValidator(email_re, (u'Enter a valid e-mail username.'), 'invalid')
default_validators = [validate_email_local]
EDIT: To clarify, the user is only entering the text BEFORE the #, hence why I have no need to validate the #domain.com in the validator.
EDIT 2: So the form field and label will look like this:
Desired Email Address: [---type-able area---] #domain.com
You say "undesirable characters such as ?", but I think you're mistaken about what characters are desirable. The original regex allows question marks.
Note that you can also define your own validator that doesn't use a massive regex, and have some chance of decoding the logic later.
Some people, when confronted with a problem, think, “I know, I’ll use
regular expressions.” Now they have two problems. - Jamie
Zawinski
Checking via regex is an exercise in wasting your time. The best way is to attempt delivery; this way not only can you verify the email address, but also if the mailbox is actually active and can receive emails.
Otherwise you'll end up in an every-expanding regular expression that can't possibly hope to match all the rules.
"Haha boo hoo woo woo!"#foo.com is a valid address, so is qwerterukeriouo#gmail.com
Instead, offer the almost-standard "Please click on the link in the email we sent to blahblah#goo.com to verify your address." approach.
If you want to create email addresses, then you can write your own rules on what can be a part of the email component; and they can be a subset of the official allowed chars in the RFC.
For example, a conservative rule (that doesn't use regular expressions):
allowed_chars = [string.digits+string.letters+'-']
if len([x in user_input if x not in allowed_chars]):
print 'Sorry, invalid characters'
else:
if user_input[0] in string.digits+'-':
print 'Cannot start with a number or `-`'
else:
if check_if_already_exists(user_input):
print 'Sorry, already taken'
else:
print 'Congratulations!'
I'm still new to Django and Python, but why reinvent the wheel and maintain your own regex? If, apart from wanting users to enter only the local portion of their email address, you're happy with Django's built-in EmailField, you can subclass it quite easily and tweak the validation logic a bit:
DOMAIN_NAME = u'foo.com'
class LocalEmailField(models.EmailField):
def clean(local_part):
whole_address = '%s#%s' % (local_part, DOMAIN_NAME)
clean_address = super(LocalEmailField, self).clean(whole_address)
# Can do more checking here if necessary
clean_local, at_sign, clean_domain = clean_address.rpartition('#')
return clean_local
Have you looked at the documentation for Form and Field Validation and the .clean() method?
If you want to do it 100% correctly with regex, you need to use an engine with some form of extended regex which allow matching nested parentheses.
Python's default engine does not allow this, so you're better off compromising with a very simple (permissive) regex.

PayPal: How to sanitize field values for dynamically created Encrypted Website Payments buttons?

We have successfully implemented in our Python+pyramid program Encrypted Website Payments for PayPal, except for a tiny detail: input sanitization. Namely, we would like to help the user by providing as much data as possible to the PayPal from our user database. Now, it occurred to me that a malicious user could change his name to 'Mr Hacker\nprice=0.00' or similar, and thus completely negate the security offered by EWP. I did try URL-encoding the values, but PayPal does not seem to decode the percent escapes in the file.
Our code is based on the django-paypal library; the library completely neglects this issue, outputting happily bare name=value pairs without any checks:
plaintext = 'cert_id=%s\n' % CERT_ID
for name, field in self.fields.iteritems():
value = None
if name in self.initial:
value = self.initial[name]
elif field.initial is not None:
value = field.initial
if value is not None:
# ### Make this less hackish and put it in the widget.
if name == "return_url":
name = "return"
plaintext += u'%s=%s\n' % (name, value)
plaintext = plaintext.encode('utf-8')
So, how does one properly format the input for dynamically encrypted buttons? Or is there a better way to achieve similar functionality in Website Payments Standard to avoid this problem, yet as secure?
Update
What we craft is a string with contents like
item_number=BASIC
p3=1
cmd=_xclick-subscriptions
business=business#business.com
src=1
item_name=Percent%20encoding%20and%20UTF-8:%20%C3%B6
charset=UTF-8
t3=M
a3=10.0
sra=1
cert_id=ABCDEFGHIJKLM
currency_code=EUR
and encrypt it for EWP; the user posts the form to https://www.sandbox.paypal.com/cgi-bin/webscr. When the user clicks on the button, the PayPal page "Log in to complete your checkout" the item name displayed is "Percent%20encoding%20and%20UTF-8:%20%C3%B6". Thus, for EWP input it seems that percent encoding is not decoded.
You could filter out key-value pairs with regular expressions;
>>> import re
>>> text = 'Mr Hacker\nprice=0.00\nsecurity=false'
>>> re.sub('[\n][^\s]+=[^\s]*', '', text)
'Mr Hacker'
Or even more simple, ditch everything after the first newline;
>>> text.splitlines()[0]
'Mr Hacker'
The latter assumes that the first line is correct, which might not be the case.

Forwarded Email parsing in Python/Any other language?

I have some mails in txt format, that have been forwarded multiple times.
I want to extract the content/the main body of the mail. This should be at the last position in the hierarchy..right? (Someone point this out if I'm wrong).
The email module doesn't give me a way to extract the content. if I make a message object, the object doesn't have a field for the content of the body.
Any idea on how to do it? Any module that exists for the same or any any particular way you can think of except the most naive one of-course of starting from the back of the text file and looking till you find the header.
If there is an easy or straightforward way/module with any other language ( I doubt), please let me know that as well!
Any help is much appreciated!
The email module doesn't give me a way to extract the content. if I make a message object, the object doesn't have a field for the content of the body.
Of course it does. Have a look at the Python documentation and examples. In particular, look at the walk and payload methods.
Try get_payload on the parsed Message object. If there is only one message, the return type will be string, otherwise it will be a list of Message objects.
Something like this:
messages = parsed_message.get_payload()
while type(messages) <> Types.StringType:
messages = messages[-1].get_payload()

Categories