Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions api/functions/error_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,11 @@ def error_user_does_not_exist():

def error_invalid_credentials():
return str("Incorrect email or password")


def scalar_error_type(value_type, value):
return str("Value is not a valid " + str(value_type) + ": " + str(value))


def scalar_error_only_types(value_types, expected_types, value):
return str("Can only validate " + str(value_types) + " as " + str(expected_types) + " but got a: " + str(type(value)))
Empty file added api/scalars/__init__.py
Empty file.
49 changes: 49 additions & 0 deletions api/scalars/email_address.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import datetime
from re import compile
from graphene.types import Scalar
from graphql.language import ast
from graphql import GraphQLError

from functions.error_messages import *

EMAIL_ADDRESS_REGEX = r'''(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[
\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[
a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][
0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[
\x01-\x09\x0b\x0c\x0e-\x7f])+)\])'''

EMAIL_ADDRESS_REGEX = compile(EMAIL_ADDRESS_REGEX)


class EmailAddress(Scalar):
'''A field whose value conforms to the standard internet email address format as specified in RFC822: https://www.w3.org/Protocols/rfc822/.'''

@staticmethod
def serialize(value):
if not isinstance(value, str):
raise GraphQLError(scalar_error_type("String", value))

if not EMAIL_ADDRESS_REGEX.search(value):
raise GraphQLError(scalar_error_type("email address", value))

return value

@staticmethod
def parse_value(value):
if not isinstance(value, str):
raise GraphQLError(scalar_error_type("String", value))

if not EMAIL_ADDRESS_REGEX.search(value):
raise GraphQLError(scalar_error_type("email address", value))

return value

@staticmethod
def parse_literal(node):
if not isinstance(node, ast.StringValue):
raise GraphQLError(scalar_error_only_types("strings", "email address", str(ast.Type)))

if not EMAIL_ADDRESS_REGEX.search(node.value):
raise GraphQLError(scalar_error_type("email address", node.value))

return node.value
67 changes: 67 additions & 0 deletions api/tests/test_email_address_scalar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import sys
import os

import pytest
from graphene.test import Client
from graphql import GraphQLScalarType
from graphql.language import ast
from graphql import GraphQLError

import unittest

# This is the only way I could get imports to work for unit testing. TODO: See if there is a better way!
PACKAGE_PARENT = '..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))

from scalars.email_address import *


class TestEmailAddressScalar(unittest.TestCase):

def test_valid_email_serialize(self):
test_email = 'test.account@canada.ca'
assert EmailAddress.serialize(test_email)

def test_valid_email_parse_value(self):
test_email = "test.account@canada.ca"
assert EmailAddress.parse_value(test_email)

def test_valid_email_parse_literal(self):
assert EmailAddress.parse_literal(ast.StringValue(
value="test.account@canada.ca"
))

def test_invalid_email_serialize_not_email(self):
test_value = 'This Will Fail'
with self.assertRaisesRegex(GraphQLError, scalar_error_type("email address", test_value)):
EmailAddress.serialize(test_value)

def test_invalid_email_serialize_wrong_type(self):
test_value = 1234
with self.assertRaisesRegex(GraphQLError, scalar_error_type("String", test_value)):
EmailAddress.serialize(test_value)

def test_invalid_email_parse_value_not_email(self):
test_value = 'This Will Fail'
with self.assertRaisesRegex(GraphQLError, scalar_error_type("email address", test_value)):
EmailAddress.parse_value(test_value)

def test_invalid_email_parse_value_wrong_type(self):
test_value = 1234
with self.assertRaisesRegex(GraphQLError, scalar_error_type("String", test_value)):
EmailAddress.parse_value(test_value)

def test_invalid_email_parse_literal_not_email(self):
test_value = ast.StringValue(
value='This Will Fail'
)
with self.assertRaisesRegex(GraphQLError, scalar_error_type("email address", test_value.value)):
EmailAddress.parse_literal(test_value)

def test_invalid_email_parse_literal_wrong_ast_type(self):
test_value = ast.IntValue(
value="1234"
)
with self.assertRaisesRegex(GraphQLError, scalar_error_only_types("strings", "email address", str(ast.Type))):
EmailAddress.parse_literal(test_value)