misc: apply double-quote-string-fixer (#80252)

This commit is contained in:
Valentin Deniaud 2023-08-03 14:47:00 +02:00
parent 6e5428362a
commit b019f07d9e
81 changed files with 1901 additions and 1901 deletions

View File

@ -2,7 +2,7 @@
import os import os
import sys import sys
if __name__ == "__main__": if __name__ == '__main__':
config_file = False config_file = False
argv = sys.argv[1:] argv = sys.argv[1:]
@ -13,7 +13,7 @@ if __name__ == "__main__":
if config_file: if config_file:
os.environ['AUTHENTIC2_SETTINGS_FILE'] = config_file os.environ['AUTHENTIC2_SETTINGS_FILE'] = config_file
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentic2.settings") os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'authentic2.settings')
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line

View File

@ -13,63 +13,63 @@ from optparse import OptionParser
# parse arguments # parse arguments
newline = 10 * '\t' newline = 10 * '\t'
parser = OptionParser( parser = OptionParser(
usage="%prog [options] [file1 file2 ... filen]", usage='%prog [options] [file1 file2 ... filen]',
version="%prog 1.0", version='%prog 1.0',
epilog="If no files are specified all xml files in current directory will be selected. \n" epilog='If no files are specified all xml files in current directory will be selected. \n'
+ "Useful when there is not known precise file name only location", + 'Useful when there is not known precise file name only location',
) )
parser.add_option( parser.add_option(
"-o", '-o',
"--output", '--output',
dest="filename", dest='filename',
default="coverage-merged.xml", default='coverage-merged.xml',
help="output file xml name", help='output file xml name',
metavar="FILE", metavar='FILE',
) )
parser.add_option( parser.add_option(
"-p", "--path", dest="path", default="./", help="xml location, default current directory", metavar="FILE" '-p', '--path', dest='path', default='./', help='xml location, default current directory', metavar='FILE'
) )
parser.add_option( parser.add_option(
"-l", "--log", dest="loglevel", default="DEBUG", help="Log level DEBUG, INFO, WARNING, ERROR, CRITICAL" '-l', '--log', dest='loglevel', default='DEBUG', help='Log level DEBUG, INFO, WARNING, ERROR, CRITICAL'
) )
parser.add_option( parser.add_option(
"-f", '-f',
"--filteronly", '--filteronly',
dest="filteronly", dest='filteronly',
default=False, default=False,
action='store_true', action='store_true',
help="If set all files will be filtered by keep rules otherwise " help='If set all files will be filtered by keep rules otherwise '
+ "all given files will be merged and filtered.", + 'all given files will be merged and filtered.',
) )
parser.add_option( parser.add_option(
"-s", '-s',
"--suffix", '--suffix',
dest="suffix", dest='suffix',
default='', default='',
help="Additional suffix which will be added to filtered files so they original files can be preserved", help='Additional suffix which will be added to filtered files so they original files can be preserved',
) )
parser.add_option( parser.add_option(
"-k", '-k',
"--keep", '--keep',
dest="packagefilters", dest='packagefilters',
default=None, default=None,
metavar="NAME", metavar='NAME',
action="append", action='append',
help="preserves only specific packages. e.g.: " help='preserves only specific packages. e.g.: '
+ newline + newline
+ "'python merge.py -k src.la.*'" + "'python merge.py -k src.la.*'"
+ newline + newline
+ "will keep all packgages in folder " + 'will keep all packgages in folder '
+ "src/la/ and all subfolders of this folders. " + 'src/la/ and all subfolders of this folders. '
+ newline + newline
+ "There can be mutiple rules e.g.:" + 'There can be mutiple rules e.g.:'
+ newline + newline
+ "'python merge.py -k src.la.* -k unit_tests.la.'" + "'python merge.py -k src.la.* -k unit_tests.la.'"
+ newline + newline
+ "Format of the rule is simple dot (.) separated names with wildcard (*) allowed, e.g: " + 'Format of the rule is simple dot (.) separated names with wildcard (*) allowed, e.g: '
+ newline + newline
+ "package.subpackage.*", + 'package.subpackage.*',
) )
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
@ -129,7 +129,7 @@ def merge_xml(xmlfile1, xmlfile2, outputfile):
merge(packages1root, packages1, packages2, 'name', merge_packages) merge(packages1root, packages1, packages2, 'name', merge_packages)
# write result to output file # write result to output file
xml1.write(outputfile, encoding="UTF-8", xml_declaration=True) xml1.write(outputfile, encoding='UTF-8', xml_declaration=True)
def filter_xml(xmlfile): def filter_xml(xmlfile):
@ -265,7 +265,7 @@ if filteronly:
xml = ET.parse(xmlfile) xml = ET.parse(xmlfile)
filter_xml(xml) filter_xml(xml)
logging.debug(f'{currfile}/{totalfiles} filtering: {xmlfile}') logging.debug(f'{currfile}/{totalfiles} filtering: {xmlfile}')
xml.write(xmlfile + filtersuffix, encoding="UTF-8", xml_declaration=True) xml.write(xmlfile + filtersuffix, encoding='UTF-8', xml_declaration=True)
currfile += 1 currfile += 1
else: else:
# merge all given files # merge all given files
@ -278,7 +278,7 @@ else:
xmlfile = xmlfiles.pop(0) xmlfile = xmlfiles.pop(0)
xml = ET.parse(xmlfile) xml = ET.parse(xmlfile)
filter_xml(xml) filter_xml(xml)
xml.write(finalxml, encoding="UTF-8", xml_declaration=True) xml.write(finalxml, encoding='UTF-8', xml_declaration=True)
sys.exit(0) sys.exit(0)
currfile = 1 currfile = 1

View File

@ -99,7 +99,7 @@ class sdist(_sdist):
sub_commands = [('compile_translations', None)] + _sdist.sub_commands sub_commands = [('compile_translations', None)] + _sdist.sub_commands
def run(self): def run(self):
print("creating VERSION file") print('creating VERSION file')
if os.path.exists('VERSION'): if os.path.exists('VERSION'):
os.remove('VERSION') os.remove('VERSION')
version = get_version() version = get_version()
@ -107,7 +107,7 @@ class sdist(_sdist):
version_file.write(version) version_file.write(version)
version_file.close() version_file.close()
_sdist.run(self) _sdist.run(self)
print("removing VERSION file") print('removing VERSION file')
if os.path.exists('VERSION'): if os.path.exists('VERSION'):
os.remove('VERSION') os.remove('VERSION')
@ -146,15 +146,15 @@ def get_version():
setup( setup(
name="authentic2", name='authentic2',
version=get_version(), version=get_version(),
license="AGPLv3+", license='AGPLv3+',
description="Authentic 2, a versatile identity management server", description='Authentic 2, a versatile identity management server',
url="http://dev.entrouvert.org/projects/authentic/", url='http://dev.entrouvert.org/projects/authentic/',
author="Entr'ouvert", author="Entr'ouvert",
author_email="authentic@listes.entrouvert.com", author_email='authentic@listes.entrouvert.com',
maintainer="Benjamin Dauvergne", maintainer='Benjamin Dauvergne',
maintainer_email="bdauvergne@entrouvert.com", maintainer_email='bdauvergne@entrouvert.com',
scripts=('manage.py',), scripts=('manage.py',),
packages=find_packages('src'), packages=find_packages('src'),
package_dir={ package_dir={
@ -193,9 +193,9 @@ setup(
], ],
zip_safe=False, zip_safe=False,
classifiers=[ classifiers=[
"Development Status :: 5 - Production/Stable", 'Development Status :: 5 - Production/Stable',
"Environment :: Web Environment", 'Environment :: Web Environment',
"Framework :: Django", 'Framework :: Django',
'Intended Audience :: End Users/Desktop', 'Intended Audience :: End Users/Desktop',
'Intended Audience :: Developers', 'Intended Audience :: Developers',
'Intended Audience :: System Administrators', 'Intended Audience :: System Administrators',
@ -203,10 +203,10 @@ setup(
'Intended Audience :: Legal Industry', 'Intended Audience :: Legal Industry',
'Intended Audience :: Science/Research', 'Intended Audience :: Science/Research',
'Intended Audience :: Telecommunications Industry', 'Intended Audience :: Telecommunications Industry',
"License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)", 'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)',
"Operating System :: OS Independent", 'Operating System :: OS Independent',
"Programming Language :: Python", 'Programming Language :: Python',
"Topic :: System :: Systems Administration :: Authentication/Directory", 'Topic :: System :: Systems Administration :: Authentication/Directory',
], ],
cmdclass={ cmdclass={
'build': build, 'build': build,

View File

@ -53,7 +53,7 @@ class RoleAdmin(admin.ModelAdmin):
'service', 'service',
) )
readonly_fields = ('uuid',) readonly_fields = ('uuid',)
prepopulated_fields = {"slug": ("name",)} prepopulated_fields = {'slug': ('name',)}
filter_horizontal = ('members', 'permissions') filter_horizontal = ('members', 'permissions')
list_display = ('__str__', 'slug', 'ou', 'service', 'admin_scope') list_display = ('__str__', 'slug', 'ou', 'service', 'admin_scope')
list_select_related = True list_select_related = True
@ -77,7 +77,7 @@ class OrganizationalUnitAdmin(admin.ModelAdmin):
'colour', 'colour',
) )
readonly_fields = ('uuid',) readonly_fields = ('uuid',)
prepopulated_fields = {"slug": ("name",)} prepopulated_fields = {'slug': ('name',)}
list_display = ('name', 'slug') list_display = ('name', 'slug')

View File

@ -11,7 +11,7 @@ class PermAnyLookupDict:
def __iter__(self): def __iter__(self):
# I am large, I contain multitudes. # I am large, I contain multitudes.
raise TypeError("PermAnyLookupDict is not iterable.") raise TypeError('PermAnyLookupDict is not iterable.')
def __getitem__(self, perm_name): def __getitem__(self, perm_name):
return self.user.has_perm_any('%s.%s' % (self.app_label, perm_name)) return self.user.has_perm_any('%s.%s' % (self.app_label, perm_name))
@ -29,7 +29,7 @@ class PermAnyWrapper:
def __iter__(self): def __iter__(self):
# I am large, I contain multitudes. # I am large, I contain multitudes.
raise TypeError("PermAnyWrapper is not iterable.") raise TypeError('PermAnyWrapper is not iterable.')
def __bool__(self): def __bool__(self):
raise TypeError('PermAnyWrapper has not boolean value') raise TypeError('PermAnyWrapper has not boolean value')

View File

@ -87,9 +87,9 @@ class OrganizationalUnit(AbstractBase):
) )
USER_CAN_RESET_PASSWD_CHOICES = ( USER_CAN_RESET_PASSWD_CHOICES = (
(None, _("System default")), (None, _('System default')),
(True, _("Yes")), (True, _('Yes')),
(False, _("No")), (False, _('No')),
) )
PolicyValue = namedtuple( PolicyValue = namedtuple(
@ -292,10 +292,10 @@ class Permission(models.Model):
def export_json(self): def export_json(self):
return { return {
"operation": self.operation.natural_key_json(), 'operation': self.operation.natural_key_json(),
"ou": self.ou and self.ou.natural_key_json(), 'ou': self.ou and self.ou.natural_key_json(),
'target_ct': self.target_ct.natural_key_json(), 'target_ct': self.target_ct.natural_key_json(),
"target": self.target.natural_key_json(), 'target': self.target.natural_key_json(),
} }
@classmethod @classmethod

View File

@ -51,7 +51,7 @@ class CleanupAdminMixin(admin.ModelAdmin):
@admin.register(Nonce) @admin.register(Nonce)
class NonceModelAdmin(admin.ModelAdmin): class NonceModelAdmin(admin.ModelAdmin):
list_display = ("value", "context", "not_on_or_after") list_display = ('value', 'context', 'not_on_or_after')
class AttributeValueAdmin(admin.ModelAdmin): class AttributeValueAdmin(admin.ModelAdmin):
@ -190,11 +190,11 @@ class UserRealmListFilter(admin.SimpleListFilter):
class UserChangeForm(BaseUserForm): class UserChangeForm(BaseUserForm):
error_messages = { error_messages = {
'missing_credential': _("You must at least give a username or an email to your user"), 'missing_credential': _('You must at least give a username or an email to your user'),
} }
password = ReadOnlyPasswordHashField( password = ReadOnlyPasswordHashField(
label=_("Password"), label=_('Password'),
help_text=_( help_text=_(
"Raw passwords are not stored, so there is no way to see this user's password, but you can change" "Raw passwords are not stored, so there is no way to see this user's password, but you can change"
" the password using <a href=\"password/\">this form</a>." " the password using <a href=\"password/\">this form</a>."
@ -215,7 +215,7 @@ class UserChangeForm(BaseUserForm):
# Regardless of what the user provides, return the initial value. # Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the # This is done here, rather than on the field, because the
# field does not have access to the initial value # field does not have access to the initial value
return self.initial["password"] return self.initial['password']
def clean(self): def clean(self):
if not self.cleaned_data.get('username') and not self.cleaned_data.get('email'): if not self.cleaned_data.get('username') and not self.cleaned_data.get('email'):
@ -236,22 +236,22 @@ class UserCreationForm(BaseUserForm):
error_messages = { error_messages = {
'password_mismatch': _("The two password fields didn't match."), 'password_mismatch': _("The two password fields didn't match."),
'missing_credential': _("You must at least give a username or an email to your user"), 'missing_credential': _('You must at least give a username or an email to your user'),
} }
password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput) password1 = forms.CharField(label=_('Password'), widget=forms.PasswordInput)
password2 = forms.CharField( password2 = forms.CharField(
label=_("Password confirmation"), label=_('Password confirmation'),
widget=forms.PasswordInput, widget=forms.PasswordInput,
help_text=_("Enter the same password as above, for verification."), help_text=_('Enter the same password as above, for verification.'),
) )
class Meta: class Meta:
model = User model = User
fields = ("username",) fields = ('username',)
def clean_password2(self): def clean_password2(self):
password1 = self.cleaned_data.get("password1") password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get("password2") password2 = self.cleaned_data.get('password2')
if password1 and password2 and password1 != password2: if password1 and password2 and password1 != password2:
raise forms.ValidationError( raise forms.ValidationError(
self.error_messages['password_mismatch'], self.error_messages['password_mismatch'],
@ -268,7 +268,7 @@ class UserCreationForm(BaseUserForm):
def save(self, commit=True): def save(self, commit=True):
user = super().save(commit=False) user = super().save(commit=False)
user.set_password(self.cleaned_data["password1"]) user.set_password(self.cleaned_data['password1'])
if commit: if commit:
user.save() user.save()
return user return user

View File

@ -528,12 +528,12 @@ class BaseUserSerializer(serializers.ModelSerializer):
try: try:
hasher = identify_hasher(attrs.get('hashed_password')) hasher = identify_hasher(attrs.get('hashed_password'))
except ValueError: except ValueError:
errors['hashed_password'] = "unknown hash format" errors['hashed_password'] = 'unknown hash format'
else: else:
try: try:
hasher.safe_summary(attrs.get('hashed_password')) hasher.safe_summary(attrs.get('hashed_password'))
except Exception: except Exception:
errors['hashed_password'] = "hash format error" errors['hashed_password'] = 'hash format error'
if errors: if errors:
raise serializers.ValidationError(errors) raise serializers.ValidationError(errors)
return attrs return attrs
@ -779,7 +779,7 @@ class UsersAPI(api_mixins.GetOrCreateMixinView, HookMixin, ExceptionHandlerMixin
if self.request.user.has_ou_perm(perm, ou): if self.request.user.has_ou_perm(perm, ou):
allowed_ous.append(ou) allowed_ous.append(ou)
if not allowed_ous: if not allowed_ous:
raise PermissionDenied("You do not have permission to perform this action.") raise PermissionDenied('You do not have permission to perform this action.')
queryset = queryset.filter(ou__in=allowed_ous) queryset = queryset.filter(ou__in=allowed_ous)
return queryset return queryset

View File

@ -40,10 +40,10 @@ class Command(BaseCommand):
help='Specifies the database to use. Default is "default".', help='Specifies the database to use. Default is "default".',
) )
def _get_pass(self, prompt="Password: "): def _get_pass(self, prompt='Password: '):
p = getpass.getpass(prompt=force_str(prompt)) p = getpass.getpass(prompt=force_str(prompt))
if not p: if not p:
raise CommandError("aborted") raise CommandError('aborted')
return p return p
def handle(self, *args, **options): def handle(self, *args, **options):
@ -87,9 +87,9 @@ class Command(BaseCommand):
p1, p2 = 1, 2 # To make them initially mismatch. p1, p2 = 1, 2 # To make them initially mismatch.
while p1 != p2 and count < MAX_TRIES: while p1 != p2 and count < MAX_TRIES:
p1 = self._get_pass() p1 = self._get_pass()
p2 = self._get_pass("Password (again): ") p2 = self._get_pass('Password (again): ')
if p1 != p2: if p1 != p2:
self.stdout.write("Passwords do not match. Please try again.\n") self.stdout.write('Passwords do not match. Please try again.\n')
count = count + 1 count = count + 1
if count == MAX_TRIES: if count == MAX_TRIES:

View File

@ -21,7 +21,7 @@ from authentic2.custom_user.models import User
class Command(BaseCommand): class Command(BaseCommand):
help = "Fix user attributes" help = 'Fix user attributes'
requires_system_checks = [] requires_system_checks = []

View File

@ -172,7 +172,7 @@ class UserQuerySet(models.QuerySet):
def set_trigram_similarity_threshold(self, threshold=None): def set_trigram_similarity_threshold(self, threshold=None):
with connection.cursor() as cursor: with connection.cursor() as cursor:
cursor.execute( cursor.execute(
"SET pg_trgm.similarity_threshold = %f" % (threshold or app_settings.A2_FTS_THRESHOLD) 'SET pg_trgm.similarity_threshold = %f' % (threshold or app_settings.A2_FTS_THRESHOLD)
) )
def get_by_email(self, email): def get_by_email(self, email):

View File

@ -60,8 +60,8 @@ class Migration(migrations.Migration):
TrigramExtension(), TrigramExtension(),
RunSQLIfExtension( RunSQLIfExtension(
sql=[ sql=[
"CREATE INDEX IF NOT EXISTS custom_user_user_email_trgm_idx ON custom_user_user USING gist" 'CREATE INDEX IF NOT EXISTS custom_user_user_email_trgm_idx ON custom_user_user USING gist'
" (LOWER(email) public.gist_trgm_ops)" ' (LOWER(email) public.gist_trgm_ops)'
], ],
reverse_sql=['DROP INDEX custom_user_user_email_trgm_idx'], reverse_sql=['DROP INDEX custom_user_user_email_trgm_idx'],
), ),

View File

@ -230,16 +230,16 @@ class User(AbstractBaseUser):
'The groups this user belongs to. A user will get all permissions granted to each of his/her' 'The groups this user belongs to. A user will get all permissions granted to each of his/her'
' group.' ' group.'
), ),
related_name="user_set", related_name='user_set',
related_query_name="user", related_query_name='user',
) )
user_permissions = models.ManyToManyField( user_permissions = models.ManyToManyField(
to=AuthPermission, to=AuthPermission,
verbose_name=_('user permissions'), verbose_name=_('user permissions'),
blank=True, blank=True,
help_text=_('Specific permissions for this user.'), help_text=_('Specific permissions for this user.'),
related_name="user_set", related_name='user_set',
related_query_name="user", related_query_name='user',
) )
# events dates # events dates
@ -277,7 +277,7 @@ class User(AbstractBaseUser):
""" """
permissions = set() permissions = set()
for backend in auth.get_backends(): for backend in auth.get_backends():
if hasattr(backend, "get_group_permissions"): if hasattr(backend, 'get_group_permissions'):
permissions.update(backend.get_group_permissions(self, obj)) permissions.update(backend.get_group_permissions(self, obj))
return permissions return permissions
@ -329,7 +329,7 @@ class User(AbstractBaseUser):
def filter_by_perm(self, perm_or_perms, qs): def filter_by_perm(self, perm_or_perms, qs):
results = [] results = []
for backend in auth.get_backends(): for backend in auth.get_backends():
if hasattr(backend, "filter_by_perm"): if hasattr(backend, 'filter_by_perm'):
results.append(backend.filter_by_perm(self, perm_or_perms, qs)) results.append(backend.filter_by_perm(self, perm_or_perms, qs))
if results: if results:
return functools.reduce(operator.__or__, results) return functools.reduce(operator.__or__, results)
@ -342,7 +342,7 @@ class User(AbstractBaseUser):
return True return True
for backend in auth.get_backends(): for backend in auth.get_backends():
if hasattr(backend, "has_perm_any"): if hasattr(backend, 'has_perm_any'):
if backend.has_perm_any(self, perm_or_perms): if backend.has_perm_any(self, perm_or_perms):
return True return True
return False return False
@ -353,7 +353,7 @@ class User(AbstractBaseUser):
return True return True
for backend in auth.get_backends(): for backend in auth.get_backends():
if hasattr(backend, "has_ou_perm"): if hasattr(backend, 'has_ou_perm'):
if backend.has_ou_perm(self, perm, ou): if backend.has_ou_perm(self, perm, ou):
return True return True
return False return False
@ -369,7 +369,7 @@ class User(AbstractBaseUser):
return full_name.strip() or self.username or self.email return full_name.strip() or self.username or self.email
def get_short_name(self): def get_short_name(self):
"Returns the short name for the user." 'Returns the short name for the user.'
return self.first_name or self.username or self.email or self.uuid[:6] return self.first_name or self.username or self.email or self.uuid[:6]
def email_user(self, subject, message, from_email=None): def email_user(self, subject, message, from_email=None):
@ -379,7 +379,7 @@ class User(AbstractBaseUser):
send_mail(subject, message, from_email, [self.email]) send_mail(subject, message, from_email, [self.email])
def get_username(self): def get_username(self):
"Return the identifying username for this User" 'Return the identifying username for this User'
return self.username or self.email or self.get_full_name() or self.uuid return self.username or self.email or self.get_full_name() or self.uuid
def roles_and_parents(self): def roles_and_parents(self):

View File

@ -228,7 +228,7 @@ class RoleDeserializer:
ou = get_default_ou() ou = get_default_ou()
else: else:
name = self._role_d.get('name') or self._role_d.get('slug') or self._role_d.get('uuid') name = self._role_d.get('name') or self._role_d.get('slug') or self._role_d.get('uuid')
raise ValidationError(_("Missing Organizational Unit for role: %s") % name) raise ValidationError(_('Missing Organizational Unit for role: %s') % name)
obj = search_role(self._role_d, ou=self._import_context.set_ou) obj = search_role(self._role_d, ou=self._import_context.set_ou)
@ -292,7 +292,7 @@ class RoleDeserializer:
for parent_d in self._parents: for parent_d in self._parents:
parent = search_role(parent_d) parent = search_role(parent_d)
if not parent: if not parent:
raise ValidationError(_("Could not find parent role: %s") % parent_d) raise ValidationError(_('Could not find parent role: %s') % parent_d)
created.append(RoleParenting.objects.create(child=self._obj, direct=True, parent=parent)) created.append(RoleParenting.objects.create(child=self._obj, direct=True, parent=parent))
return created, deleted return created, deleted
@ -347,13 +347,13 @@ class ImportResult:
self._bulk_update('permissions', created, deleted) self._bulk_update('permissions', created, deleted)
def to_str(self, verbose=False): def to_str(self, verbose=False):
res = "" res = ''
for attr in ('roles', 'ous', 'parentings', 'permissions', 'attributes'): for attr in ('roles', 'ous', 'parentings', 'permissions', 'attributes'):
data = getattr(self, attr) data = getattr(self, attr)
for status in ('created', 'updated', 'deleted'): for status in ('created', 'updated', 'deleted'):
if status in data: if status in data:
s_data = data[status] s_data = data[status]
res += "%s %s %s\n" % (len(s_data), attr, status) res += '%s %s %s\n' % (len(s_data), attr, status)
return res return res
@ -408,13 +408,13 @@ def import_site(json_d, import_context=None):
if import_context.ou_delete_orphans: if import_context.ou_delete_orphans:
raise ValidationError( raise ValidationError(
_("Unsupported context value for ou_delete_orphans : %s") % (import_context.ou_delete_orphans) _('Unsupported context value for ou_delete_orphans : %s') % (import_context.ou_delete_orphans)
) )
if import_context.role_delete_orphans: if import_context.role_delete_orphans:
# FIXME : delete each role that is in DB but not in the export # FIXME : delete each role that is in DB but not in the export
raise ValidationError( raise ValidationError(
_("Unsupported context value for role_delete_orphans : %s") _('Unsupported context value for role_delete_orphans : %s')
% (import_context.role_delete_orphans) % (import_context.role_delete_orphans)
) )

View File

@ -99,7 +99,7 @@ def get_disco_return_url_from_metadata(entity_id):
value = int(endpoint.attributes['index'].value) value = int(endpoint.attributes['index'].value)
ep = endpoint ep = endpoint
if not ep: if not ep:
logger.warning("get_disco_return_url_from_metadata: no valid endpoint for %s", entity_id) logger.warning('get_disco_return_url_from_metadata: no valid endpoint for %s', entity_id)
return None return None
logger.debug('get_disco_return_url_from_metadata: found endpoint with index %s', value) logger.debug('get_disco_return_url_from_metadata: found endpoint with index %s', value)
@ -132,13 +132,13 @@ def add_param_to_url(url, param_name, value):
def disco(request): def disco(request):
if not request.method == "GET": if not request.method == 'GET':
message = _('HTTP verb not supported %s' % request.method) message = _('HTTP verb not supported %s' % request.method)
return error_page(request, message, logger=logger) return error_page(request, message, logger=logger)
entityID = None entityID = None
_return = None _return = None
policy = ("urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol:single",) policy = ('urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol:single',)
returnIDParam = None returnIDParam = None
isPassive = False isPassive = False
@ -151,7 +151,7 @@ def disco(request):
if not is_known_idp(idp_selected): if not is_known_idp(idp_selected):
message = 'The idp is unknown.' message = 'The idp is unknown.'
logger.warning("disco: Unknown selected idp %s", idp_selected) logger.warning('disco: Unknown selected idp %s', idp_selected)
save_key_values(request, entityID, _return, policy, returnIDParam, isPassive) save_key_values(request, entityID, _return, policy, returnIDParam, isPassive)
return HttpResponseRedirect(reverse(idp_selection)) return HttpResponseRedirect(reverse(idp_selection))

View File

@ -44,7 +44,7 @@ logger = logging.getLogger(__name__)
class PasswordResetForm(HoneypotForm): class PasswordResetForm(HoneypotForm):
next_url = forms.CharField(widget=forms.HiddenInput, required=False) next_url = forms.CharField(widget=forms.HiddenInput, required=False)
email = ValidatedEmailField(label=_("Email"), required=False) email = ValidatedEmailField(label=_('Email'), required=False)
phone = PhoneField( phone = PhoneField(
label=_('Phone number'), label=_('Phone number'),
@ -246,13 +246,13 @@ class NotifyOfPasswordChange:
'user': user, 'user': user,
'password': self.cleaned_data['new_password1'], 'password': self.cleaned_data['new_password1'],
} }
utils_misc.send_templated_mail(user, "authentic2/password_change", ctx) utils_misc.send_templated_mail(user, 'authentic2/password_change', ctx)
return user return user
class SetPasswordForm(NotifyOfPasswordChange, PasswordResetMixin, auth_forms.SetPasswordForm): class SetPasswordForm(NotifyOfPasswordChange, PasswordResetMixin, auth_forms.SetPasswordForm):
new_password1 = NewPasswordField(label=_("New password")) new_password1 = NewPasswordField(label=_('New password'))
new_password2 = CheckPasswordField(label=_("New password confirmation")) new_password2 = CheckPasswordField(label=_('New password confirmation'))
def __init__(self, user, *args, **kwargs): def __init__(self, user, *args, **kwargs):
super().__init__(user, *args, **kwargs) super().__init__(user, *args, **kwargs)
@ -271,7 +271,7 @@ class PasswordChangeForm(
): ):
old_password = PasswordField(label=_('Old password')) old_password = PasswordField(label=_('Old password'))
new_password1 = NewPasswordField(label=_('New password')) new_password1 = NewPasswordField(label=_('New password'))
new_password2 = CheckPasswordField(label=_("New password confirmation")) new_password2 = CheckPasswordField(label=_('New password confirmation'))
old_password.widget.attrs.update({'autocomplete': 'current-password'}) old_password.widget.attrs.update({'autocomplete': 'current-password'})

View File

@ -36,7 +36,7 @@ class EmailChangeFormNoPassword(forms.Form):
class EmailChangeForm(EmailChangeFormNoPassword): class EmailChangeForm(EmailChangeFormNoPassword):
password = forms.CharField(label=_("Password"), widget=forms.PasswordInput) password = forms.CharField(label=_('Password'), widget=forms.PasswordInput)
def clean_email(self): def clean_email(self):
email = self.cleaned_data['email'] email = self.cleaned_data['email']
@ -45,7 +45,7 @@ class EmailChangeForm(EmailChangeFormNoPassword):
return email return email
def clean_password(self): def clean_password(self):
password = self.cleaned_data["password"] password = self.cleaned_data['password']
if not self.user.check_password(password): if not self.user.check_password(password):
raise forms.ValidationError( raise forms.ValidationError(
_('Incorrect password.'), _('Incorrect password.'),
@ -63,7 +63,7 @@ class PhoneChangeFormNoPassword(forms.Form):
class PhoneChangeForm(PhoneChangeFormNoPassword): class PhoneChangeForm(PhoneChangeFormNoPassword):
password = forms.CharField(label=_("Password"), widget=forms.PasswordInput) password = forms.CharField(label=_('Password'), widget=forms.PasswordInput)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.authenticator = kwargs.pop('password_authenticator') self.authenticator = kwargs.pop('password_authenticator')
@ -80,7 +80,7 @@ class PhoneChangeForm(PhoneChangeFormNoPassword):
return phone return phone
def clean_password(self): def clean_password(self):
password = self.cleaned_data["password"] password = self.cleaned_data['password']
if not self.user.check_password(password): if not self.user.check_password(password):
raise forms.ValidationError( raise forms.ValidationError(
_('Incorrect password.'), _('Incorrect password.'),
@ -91,7 +91,7 @@ class PhoneChangeForm(PhoneChangeFormNoPassword):
class BaseUserForm(LockedFieldFormMixin, forms.ModelForm): class BaseUserForm(LockedFieldFormMixin, forms.ModelForm):
error_messages = { error_messages = {
'duplicate_username': _("A user with that username already exists."), 'duplicate_username': _('A user with that username already exists.'),
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):

View File

@ -169,7 +169,7 @@ class RegistrationCompletionFormNoPassword(profile_forms.BaseUserForm):
class RegistrationCompletionForm(RegistrationCompletionFormNoPassword): class RegistrationCompletionForm(RegistrationCompletionFormNoPassword):
password1 = NewPasswordField(label=_('Password')) password1 = NewPasswordField(label=_('Password'))
password2 = CheckPasswordField(label=_("Password (again)")) password2 = CheckPasswordField(label=_('Password (again)'))
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)

View File

@ -150,7 +150,7 @@ class PickerWidgetMixin:
def render(self, name, value, attrs=None, renderer=None): def render(self, name, value, attrs=None, renderer=None):
attrs = attrs or {} attrs = attrs or {}
final_attrs = self.build_attrs(attrs) final_attrs = self.build_attrs(attrs)
final_attrs['class'] = "controls input-append date" final_attrs['class'] = 'controls input-append date'
rendered_widget = super().render(name, value, attrs=final_attrs, renderer=renderer) rendered_widget = super().render(name, value, attrs=final_attrs, renderer=renderer)
# if not set, autoclose have to be true. # if not set, autoclose have to be true.
@ -159,9 +159,9 @@ class PickerWidgetMixin:
# Build javascript options out of python dictionary # Build javascript options out of python dictionary
options_list = [] options_list = []
for key, value in iter(self.options.items()): for key, value in iter(self.options.items()):
options_list.append("%s: %s" % (key, json.dumps(value))) options_list.append('%s: %s' % (key, json.dumps(value)))
js_options = ",\n".join(options_list) js_options = ',\n'.join(options_list)
# Use provided id or generate hex to avoid collisions in document # Use provided id or generate hex to avoid collisions in document
id = final_attrs.get('id', uuid.uuid4().hex) id = final_attrs.get('id', uuid.uuid4().hex)
@ -318,7 +318,7 @@ class CheckPasswordInput(PasswordInput):
class ProfileImageInput(ClearableFileInput): class ProfileImageInput(ClearableFileInput):
template_name = "authentic2/profile_image_input.html" template_name = 'authentic2/profile_image_input.html'
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
attrs = kwargs.pop('attrs', {}) attrs = kwargs.pop('attrs', {})

View File

@ -32,7 +32,7 @@ class Drupal7PasswordHasher(hashers.BasePasswordHasher):
Secure password hashing using the algorithm used by Drupal 7 (recommended) Secure password hashing using the algorithm used by Drupal 7 (recommended)
""" """
algorithm = "drupal7_sha512" algorithm = 'drupal7_sha512'
iterations = 10000 iterations = 10000
digest = hashlib.sha512 digest = hashlib.sha512
alphabet = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' alphabet = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
@ -85,7 +85,7 @@ class Drupal7PasswordHasher(hashers.BasePasswordHasher):
password = password.encode() password = password.encode()
for dummy in range(iterations + 1): for dummy in range(iterations + 1):
h = self.digest(h + password).digest() h = self.digest(h + password).digest()
return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, self.b64encode(h)[:43]) return '%s$%d$%s$%s' % (self.algorithm, iterations, salt, self.b64encode(h)[:43])
def verify(self, password, encoded): def verify(self, password, encoded):
algorithm, iterations, salt, dummy = encoded.split('$', 3) algorithm, iterations, salt, dummy = encoded.split('$', 3)
@ -118,7 +118,7 @@ class CommonPasswordHasher(hashers.BasePasswordHasher):
assert password assert password
assert '$' not in salt assert '$' not in salt
hash = self.digest(force_bytes(salt + password)).hexdigest() hash = self.digest(force_bytes(salt + password)).hexdigest()
return "%s$%s$%s" % (self.algorithm, salt, hash) return '%s$%s$%s' % (self.algorithm, salt, hash)
def verify(self, password, encoded): def verify(self, password, encoded):
algorithm, salt, dummy_hash = encoded.split('$', 2) algorithm, salt, dummy_hash = encoded.split('$', 2)
@ -173,7 +173,7 @@ class OpenLDAPPasswordHasher(CommonPasswordHasher):
assert b'$' not in salt assert b'$' not in salt
hash = self.digest(force_bytes(password + salt)).hexdigest() hash = self.digest(force_bytes(password + salt)).hexdigest()
salt = force_str(hexlify(salt), encoding='ascii') salt = force_str(hexlify(salt), encoding='ascii')
return "%s$%s$%s" % (self.algorithm, salt, hash) return '%s$%s$%s' % (self.algorithm, salt, hash)
def verify(self, password, encoded): def verify(self, password, encoded):
algorithm, salt, hash = encoded.split('$', 2) algorithm, salt, hash = encoded.split('$', 2)
@ -224,7 +224,7 @@ class JoomlaPasswordHasher(CommonPasswordHasher):
assert b'$' not in salt assert b'$' not in salt
hash = self.digest(force_bytes(password) + salt).hexdigest() hash = self.digest(force_bytes(password) + salt).hexdigest()
salt = force_str(hexlify(force_bytes(salt)), encoding='ascii') salt = force_str(hexlify(force_bytes(salt)), encoding='ascii')
return "%s$md5$%s$%s" % (self.algorithm, salt, hash) return '%s$md5$%s$%s' % (self.algorithm, salt, hash)
def verify(self, password, encoded): def verify(self, password, encoded):
algorithm, dummy_subalgo, salt, dummy_hash = encoded.split('$', 3) algorithm, dummy_subalgo, salt, dummy_hash = encoded.split('$', 3)
@ -272,7 +272,7 @@ class PloneSHA1PasswordHasher(hashers.SHA1PasswordHasher):
Plone uses `password + salt`, Django has `salt + password`. Plone uses `password + salt`, Django has `salt + password`.
""" """
algorithm = "plonesha1" algorithm = 'plonesha1'
_prefix = '{SSHA}' _prefix = '{SSHA}'
def encode(self, password, salt): def encode(self, password, salt):
@ -283,7 +283,7 @@ class PloneSHA1PasswordHasher(hashers.SHA1PasswordHasher):
salt = force_bytes(salt) salt = force_bytes(salt)
hashed = base64.b64encode(hashlib.sha1(password + salt).digest() + salt) hashed = base64.b64encode(hashlib.sha1(password + salt).digest() + salt)
return "%s$%s%s" % (self.algorithm, self._prefix, force_str(hashed)) return '%s$%s%s' % (self.algorithm, self._prefix, force_str(hashed))
def verify(self, password, encoded): def verify(self, password, encoded):
"""Verify the given password against the encoded string.""" """Verify the given password against the encoded string."""

View File

@ -23,7 +23,7 @@ from django.shortcuts import render
def consent_federation(request, nonce='', provider_id=None): def consent_federation(request, nonce='', provider_id=None):
"""On a GET produce a form asking for consentment, """On a GET produce a form asking for consentment,
On a POST handle the form and redirect to next""" On a POST handle the form and redirect to next"""
if request.method == "GET": if request.method == 'GET':
return render( return render(
request, request,
'interaction/consent_federation.html', 'interaction/consent_federation.html',

View File

@ -97,9 +97,9 @@ class SamlBackend:
def logout_list(self, request): def logout_list(self, request):
all_sessions = models.LibertySession.objects.filter(django_session_key=request.session.session_key) all_sessions = models.LibertySession.objects.filter(django_session_key=request.session.session_key)
self.logger.debug("all_sessions %r", all_sessions) self.logger.debug('all_sessions %r', all_sessions)
provider_ids = {s.provider_id for s in all_sessions} provider_ids = {s.provider_id for s in all_sessions}
self.logger.debug("provider_ids %r", provider_ids) self.logger.debug('provider_ids %r', provider_ids)
result = [] result = []
for provider_id in provider_ids: for provider_id in provider_ids:
name = provider_id name = provider_id

View File

@ -513,7 +513,7 @@ def sso(request):
For SOAP a session must be established previously through the login For SOAP a session must be established previously through the login
page. No authentication through the SOAP request is supported. page. No authentication through the SOAP request is supported.
""" """
if request.method == "GET": if request.method == 'GET':
logger.debug('called by GET') logger.debug('called by GET')
consent_answer = request.GET.get('consent_answer', '') consent_answer = request.GET.get('consent_answer', '')
if consent_answer: if consent_answer:
@ -544,14 +544,14 @@ def sso(request):
extra={'request': request}, extra={'request': request},
) )
return HttpResponseBadRequest( return HttpResponseBadRequest(
_("SAMLv2 Single Sign On: invalid message for WebSSO profile with HTTP-Redirect binding"), _('SAMLv2 Single Sign On: invalid message for WebSSO profile with HTTP-Redirect binding'),
content_type='text/plain', content_type='text/plain',
) )
except lasso.ProfileInvalidProtocolprofileError: except lasso.ProfileInvalidProtocolprofileError:
log_info_authn_request_details(login) log_info_authn_request_details(login)
message = _( message = _(
"SAMLv2 Single Sign On: the request cannot be answered because no valid protocol binding" 'SAMLv2 Single Sign On: the request cannot be answered because no valid protocol binding'
" could be found" ' could be found'
) )
logger.warning('the request cannot be answered because no valid protocol binding could be found') logger.warning('the request cannot be answered because no valid protocol binding could be found')
return HttpResponseBadRequest(message, content_type='text/plain') return HttpResponseBadRequest(message, content_type='text/plain')
@ -689,7 +689,7 @@ def need_consent_for_federation(request, login, nid_format):
def continue_sso(request): def continue_sso(request):
consent_answer = None consent_answer = None
consent_attribute_answer = None consent_attribute_answer = None
if request.method == "GET": if request.method == 'GET':
logger.debug('called by GET') logger.debug('called by GET')
consent_answer = request.GET.get('consent_answer', '') consent_answer = request.GET.get('consent_answer', '')
if consent_answer: if consent_answer:

View File

@ -49,7 +49,7 @@ class Command(BaseCommand):
} }
def add_arguments(self, parser): def add_arguments(self, parser):
parser.add_argument("--fake", action='store_true', help='do nothing', default=False) parser.add_argument('--fake', action='store_true', help='do nothing', default=False)
def handle(self, *args, **options): def handle(self, *args, **options):
self.fake = options['fake'] self.fake = options['fake']

View File

@ -68,7 +68,7 @@ class Command(BaseCommand):
def handle(self, filename, **options): def handle(self, filename, **options):
translation.activate(settings.LANGUAGE_CODE) translation.activate(settings.LANGUAGE_CODE)
dry_run = options['dry_run'] dry_run = options['dry_run']
msg = "Dry run\n" if dry_run else "Real run\n" msg = 'Dry run\n' if dry_run else 'Real run\n'
c_kwargs = create_context_args(options) c_kwargs = create_context_args(options)
try: try:
with open(filename) as f: with open(filename) as f:
@ -80,5 +80,5 @@ class Command(BaseCommand):
except DryRunException: except DryRunException:
pass pass
sys.stdout.write(result.to_str()) sys.stdout.write(result.to_str())
sys.stdout.write("Success\n") sys.stdout.write('Success\n')
translation.deactivate() translation.deactivate()

View File

@ -111,7 +111,7 @@ class Command(BaseCommand):
'''Load LDAP ldif file''' '''Load LDAP ldif file'''
can_import_django_settings = True can_import_django_settings = True
requires_system_checks = "__all__" requires_system_checks = '__all__'
help = 'Load/update LDIF files as users' help = 'Load/update LDIF files as users'
def add_arguments(self, parser): def add_arguments(self, parser):

View File

@ -41,10 +41,10 @@ class Command(BaseCommand):
help='Specifies the database to use. Default is "default".', help='Specifies the database to use. Default is "default".',
) )
def _get_pass(self, prompt="Password: "): def _get_pass(self, prompt='Password: '):
p = getpass.getpass(prompt=prompt) p = getpass.getpass(prompt=prompt)
if not p: if not p:
raise CommandError("aborted") raise CommandError('aborted')
return p return p
def handle(self, *args, **options): def handle(self, *args, **options):

View File

@ -145,8 +145,8 @@ class ChooseUserAuthorizationsForm(CssClass, forms.Form):
class UserEditForm(LimitQuerysetFormMixin, CssClass, BaseUserForm): class UserEditForm(LimitQuerysetFormMixin, CssClass, BaseUserForm):
css_class = "user-form" css_class = 'user-form'
form_id = "id_user_edit_form" form_id = 'id_user_edit_form'
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
request = kwargs.get('request') request = kwargs.get('request')
@ -193,8 +193,8 @@ class UserChangePasswordForm(CssClass, forms.ModelForm):
require_password = True require_password = True
def clean_password2(self): def clean_password2(self):
password1 = self.cleaned_data.get("password1") password1 = self.cleaned_data.get('password1')
password2 = self.cleaned_data.get("password2") password2 = self.cleaned_data.get('password2')
if password1 and password2 and password1 != password2: if password1 and password2 and password1 != password2:
raise forms.ValidationError( raise forms.ValidationError(
self.error_messages['password_mismatch'], self.error_messages['password_mismatch'],
@ -232,7 +232,7 @@ class UserChangePasswordForm(CssClass, forms.ModelForm):
new_password = generate_password() new_password = generate_password()
self.cleaned_data['send_mail'] = True self.cleaned_data['send_mail'] = True
elif self.cleaned_data.get('password1'): elif self.cleaned_data.get('password1'):
new_password = self.cleaned_data["password1"] new_password = self.cleaned_data['password1']
if new_password: if new_password:
user.set_password(new_password) user.set_password(new_password)
@ -252,8 +252,8 @@ class UserChangePasswordForm(CssClass, forms.ModelForm):
return user return user
generate_password = forms.BooleanField(initial=False, label=_('Generate new password'), required=False) generate_password = forms.BooleanField(initial=False, label=_('Generate new password'), required=False)
password1 = NewPasswordField(label=_("Password"), required=False) password1 = NewPasswordField(label=_('Password'), required=False)
password2 = CheckPasswordField(label=_("Confirmation"), required=False) password2 = CheckPasswordField(label=_('Confirmation'), required=False)
send_mail = forms.BooleanField(initial=False, label=_('Send informations to user'), required=False) send_mail = forms.BooleanField(initial=False, label=_('Send informations to user'), required=False)
def __init__(self, **kwargs): def __init__(self, **kwargs):
@ -266,8 +266,8 @@ class UserChangePasswordForm(CssClass, forms.ModelForm):
class UserAddForm(UserChangePasswordForm, UserEditForm): class UserAddForm(UserChangePasswordForm, UserEditForm):
css_class = "user-form" css_class = 'user-form'
form_id = "id_user_add_form" form_id = 'id_user_add_form'
require_password = False require_password = False
notification_template_prefix = 'authentic2/manager/new-account-notification' notification_template_prefix = 'authentic2/manager/new-account-notification'
@ -417,7 +417,7 @@ class OUSearchForm(FormWithRequest):
# get possible OUs from this list # get possible OUs from this list
related_query_name = self.queryset.model._meta.get_field('ou').related_query_name() related_query_name = self.queryset.model._meta.get_field('ou').related_query_name()
objects_ou_qs = OrganizationalUnit.objects.filter( objects_ou_qs = OrganizationalUnit.objects.filter(
**{"%s__in" % related_query_name: self.queryset} **{'%s__in' % related_query_name: self.queryset}
).distinct() ).distinct()
# to combine queryset with distinct, each queryset must have the distinct flag # to combine queryset with distinct, each queryset must have the distinct flag
self.ou_qs = self.ou_qs.distinct() | objects_ou_qs self.ou_qs = self.ou_qs.distinct() | objects_ou_qs

View File

@ -816,8 +816,8 @@ class UserOrRoleSelect2View(DetailView):
return JsonResponse( return JsonResponse(
{ {
"results": [self.get_choice(obj) for obj in list(role_page) + list(user_page)], 'results': [self.get_choice(obj) for obj in list(role_page) + list(user_page)],
"more": has_next, 'more': has_next,
} }
) )

View File

@ -36,7 +36,7 @@ TABLES_MAJOR_VERSION = int(tables.__version__.split('.', maxsplit=1)[0])
class Table(tables.Table): class Table(tables.Table):
class Meta: class Meta:
row_attrs = {"data-pk": lambda record: record.pk} row_attrs = {'data-pk': lambda record: record.pk}
class PermissionLinkColumn(tables.LinkColumn): class PermissionLinkColumn(tables.LinkColumn):
@ -98,12 +98,12 @@ class UserTable(Table):
args=[A('pk')], args=[A('pk')],
order_by=('last_name', 'first_name', 'email', 'username'), order_by=('last_name', 'first_name', 'email', 'username'),
text=lambda record: record.get_full_name(), text=lambda record: record.get_full_name(),
attrs={"td": {"class": "link"}}, attrs={'td': {'class': 'link'}},
) )
username = tables.Column( username = tables.Column(
attrs={ attrs={
"td": {"class": "username"}, 'td': {'class': 'username'},
"th": {"class": "username orderable"}, 'th': {'class': 'username orderable'},
} }
) )
email = VerifiableEmailColumn() email = VerifiableEmailColumn()
@ -119,18 +119,18 @@ class UserTable(Table):
class RoleMembersTable(UserTable): class RoleMembersTable(UserTable):
direct = tables.BooleanColumn( direct = tables.BooleanColumn(
verbose_name=_('Direct member'), orderable=False, attrs={"td": {"class": "direct"}} verbose_name=_('Direct member'), orderable=False, attrs={'td': {'class': 'direct'}}
) )
via = tables.TemplateColumn( via = tables.TemplateColumn(
'{% for role in record.via %}<a href="{% url "a2-manager-role-members" pk=role.pk %}">{{ role' '{% for role in record.via %}<a href="{% url "a2-manager-role-members" pk=role.pk %}">{{ role'
' }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}', ' }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}',
verbose_name=_('Inherited from'), verbose_name=_('Inherited from'),
orderable=False, orderable=False,
attrs={"td": {"class": "via"}}, attrs={'td': {'class': 'via'}},
) )
class Meta(UserTable.Meta): class Meta(UserTable.Meta):
row_attrs = {"data-pk": lambda record: 'user-%s' % record.pk} row_attrs = {'data-pk': lambda record: 'user-%s' % record.pk}
class UserOrRoleColumn(UserLinkColumn): class UserOrRoleColumn(UserLinkColumn):
@ -146,13 +146,13 @@ class MixedUserRoleTable(Table):
verbose_name=_('Members'), verbose_name=_('Members'),
text=str, text=str,
orderable=False, orderable=False,
attrs={"td": {"class": "name"}}, attrs={'td': {'class': 'name'}},
) )
class Meta(Table.Meta): class Meta(Table.Meta):
attrs = {'class': 'main clickable-rows', 'id': 'user-table'} attrs = {'class': 'main clickable-rows', 'id': 'user-table'}
row_attrs = { row_attrs = {
"data-pk": lambda record: '%s-%s' % ('user' if isinstance(record, User) else 'role', record.pk) 'data-pk': lambda record: '%s-%s' % ('user' if isinstance(record, User) else 'role', record.pk)
} }
@ -162,12 +162,12 @@ class RoleTable(Table):
kwargs={'pk': A('pk')}, kwargs={'pk': A('pk')},
accessor='name', accessor='name',
verbose_name=_('label'), verbose_name=_('label'),
attrs={"td": {"class": "name"}}, attrs={'td': {'class': 'name'}},
) )
ou = tables.Column() ou = tables.Column()
slug = tables.Column(attrs={"td": {"class": "slug"}}) slug = tables.Column(attrs={'td': {'class': 'slug'}})
member_count = tables.Column( member_count = tables.Column(
verbose_name=_('Direct member count'), orderable=False, attrs={"td": {"class": "member_count"}} verbose_name=_('Direct member count'), orderable=False, attrs={'td': {'class': 'member_count'}}
) )
def render_name(self, record, bound_column): def render_name(self, record, bound_column):
@ -192,10 +192,10 @@ class OUTable(Table):
kwargs={'pk': A('pk')}, kwargs={'pk': A('pk')},
accessor='name', accessor='name',
verbose_name=_('label'), verbose_name=_('label'),
attrs={"td": {"class": "name"}}, attrs={'td': {'class': 'name'}},
) )
slug = tables.Column(attrs={"td": {"class": "slug"}}) slug = tables.Column(attrs={'td': {'class': 'slug'}})
default = tables.BooleanColumn(attrs={"td": {"class": "default"}}) default = tables.BooleanColumn(attrs={'td': {'class': 'default'}})
class Meta(Table.Meta): class Meta(Table.Meta):
model = OrganizationalUnit model = OrganizationalUnit
@ -210,13 +210,13 @@ class OuUserRolesTable(Table):
kwargs={'pk': A('pk')}, kwargs={'pk': A('pk')},
accessor='name', accessor='name',
verbose_name=_('label'), verbose_name=_('label'),
attrs={"td": {"class": "name"}}, attrs={'td': {'class': 'name'}},
) )
via = tables.TemplateColumn( via = tables.TemplateColumn(
'''{% for rel in record.via %}{{ rel.child }} {% if not forloop.last %}, {% endif %}{% endfor %}''', '''{% for rel in record.via %}{{ rel.child }} {% if not forloop.last %}, {% endif %}{% endfor %}''',
verbose_name=_('Inherited from'), verbose_name=_('Inherited from'),
orderable=False, orderable=False,
attrs={"td": {"class": "via"}}, attrs={'td': {'class': 'via'}},
) )
member = tables.TemplateColumn( member = tables.TemplateColumn(
'{%% load i18n %%}<input class="role-member{%% if not record.member and record.via %%}' '{%% load i18n %%}<input class="role-member{%% if not record.member and record.via %%}'
@ -229,7 +229,7 @@ class OuUserRolesTable(Table):
), ),
verbose_name=_('Member'), verbose_name=_('Member'),
order_by=('member', 'via', 'name'), order_by=('member', 'via', 'name'),
attrs={"td": {"class": "member"}}, attrs={'td': {'class': 'member'}},
) )
def render_name(self, record, bound_column): def render_name(self, record, bound_column):
@ -255,7 +255,7 @@ class UserRolesTable(Table):
kwargs={'pk': A('pk')}, kwargs={'pk': A('pk')},
accessor='name', accessor='name',
verbose_name=_('label'), verbose_name=_('label'),
attrs={"td": {"class": "name"}}, attrs={'td': {'class': 'name'}},
) )
ou = tables.Column() ou = tables.Column()
via = tables.TemplateColumn( via = tables.TemplateColumn(
@ -263,7 +263,7 @@ class UserRolesTable(Table):
'{{ rel.child }} {% if not forloop.last %}, {% endif %}{% endfor %}{% endif %}', '{{ rel.child }} {% if not forloop.last %}, {% endif %}{% endfor %}{% endif %}',
verbose_name=_('Inherited from'), verbose_name=_('Inherited from'),
orderable=False, orderable=False,
attrs={"td": {"class": "via"}}, attrs={'td': {'class': 'via'}},
) )
def render_name(self, record, bound_column): def render_name(self, record, bound_column):
@ -331,19 +331,19 @@ class InheritanceRolesTable(Table):
kwargs={'pk': A('pk')}, kwargs={'pk': A('pk')},
accessor='name', accessor='name',
verbose_name=_('label'), verbose_name=_('label'),
attrs={"td": {"class": "name"}}, attrs={'td': {'class': 'name'}},
) )
via = tables.TemplateColumn( via = tables.TemplateColumn(
'''{% for rel in record.via %}{{ rel.name }}{% if not forloop.last %}, {% endif %}{% endfor %}''', '''{% for rel in record.via %}{{ rel.name }}{% if not forloop.last %}, {% endif %}{% endfor %}''',
verbose_name=_('Inherited from'), verbose_name=_('Inherited from'),
orderable=False, orderable=False,
attrs={"td": {"class": "via"}}, attrs={'td': {'class': 'via'}},
) )
member = tables.TemplateColumn( member = tables.TemplateColumn(
'<input class="role-member{% if record.indeterminate %} indeterminate{% endif %}" name="role-{{ record.pk }}" ' '<input class="role-member{% if record.indeterminate %} indeterminate{% endif %}" name="role-{{ record.pk }}" '
'type="checkbox" {% if record.checked %}checked{% endif %}/>', 'type="checkbox" {% if record.checked %}checked{% endif %}/>',
verbose_name='', verbose_name='',
attrs={"td": {"class": "member"}}, attrs={'td': {'class': 'member'}},
) )
class Meta(Table.Meta): class Meta(Table.Meta):

View File

@ -51,9 +51,9 @@ def get_user_dataset(qs):
return '' return ''
if hasattr(rec, 'strftime'): if hasattr(rec, 'strftime'):
if isinstance(rec, datetime.datetime): if isinstance(rec, datetime.datetime):
_format = "%Y-%m-%d %H:%M:%S" _format = '%Y-%m-%d %H:%M:%S'
else: else:
_format = "%Y-%m-%d" _format = '%Y-%m-%d'
return rec.strftime(_format) return rec.strftime(_format)
return rec return rec

View File

@ -129,7 +129,7 @@ class PermissionMixin:
return self.permission_model.objects.get(pk=self.kwargs[self.permission_pk_url_kwarg]) return self.permission_model.objects.get(pk=self.kwargs[self.permission_pk_url_kwarg])
except self.permission_model.DoesNotExist: except self.permission_model.DoesNotExist:
raise Http404( raise Http404(
gettext("No %(verbose_name)s found matching the query") gettext('No %(verbose_name)s found matching the query')
% {'verbose_name': self.permission_model._meta.verbose_name} % {'verbose_name': self.permission_model._meta.verbose_name}
) )
elif hasattr(self, 'get_object') and ( elif hasattr(self, 'get_object') and (
@ -751,7 +751,7 @@ homepage = HomepageView.as_view()
class TechnicalInformationView(TitleMixin, MediaMixin, TemplateView): class TechnicalInformationView(TitleMixin, MediaMixin, TemplateView):
template_name = 'authentic2/manager/tech_info.html' template_name = 'authentic2/manager/tech_info.html'
title = _("Technical information") title = _('Technical information')
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if not request.user.is_superuser: if not request.user.is_superuser:

View File

@ -208,7 +208,7 @@ class XForwardedForMiddleware(MiddlewareMixin):
def process_request(self, request): def process_request(self, request):
if 'x-forwarded-for' in request.headers: if 'x-forwarded-for' in request.headers:
request.META['REMOTE_ADDR'] = request.headers['X-Forwarded-For'].split(",")[0].strip() request.META['REMOTE_ADDR'] = request.headers['X-Forwarded-For'].split(',')[0].strip()
return None return None

View File

@ -157,7 +157,7 @@ class Migration(migrations.Migration):
default=300, default=300,
help_text=( help_text=(
"if iframe logout is used, it's the time between the onload event for this iframe" "if iframe logout is used, it's the time between the onload event for this iframe"
" and the moment we consider its loading to be really finished" ' and the moment we consider its loading to be really finished'
), ),
verbose_name='iframe logout timeout (ms)', verbose_name='iframe logout timeout (ms)',
), ),

View File

@ -11,18 +11,18 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.RunSQL( migrations.RunSQL(
sql=[ sql=[
"CREATE EXTENSION IF NOT EXISTS unaccent SCHEMA public", 'CREATE EXTENSION IF NOT EXISTS unaccent SCHEMA public',
"CREATE EXTENSION IF NOT EXISTS pg_trgm SCHEMA public", 'CREATE EXTENSION IF NOT EXISTS pg_trgm SCHEMA public',
"CREATE OR REPLACE FUNCTION public.immutable_unaccent(text) RETURNS varchar AS $$ SELECT" 'CREATE OR REPLACE FUNCTION public.immutable_unaccent(text) RETURNS varchar AS $$ SELECT'
" public.unaccent('public.unaccent',$1::text); $$ LANGUAGE 'sql' IMMUTABLE", " public.unaccent('public.unaccent',$1::text); $$ LANGUAGE 'sql' IMMUTABLE",
"CREATE INDEX custom_user_name_gist_idx ON custom_user_user USING gist" 'CREATE INDEX custom_user_name_gist_idx ON custom_user_user USING gist'
" (LOWER(public.immutable_unaccent(first_name || ' ' || last_name)) public.gist_trgm_ops)", " (LOWER(public.immutable_unaccent(first_name || ' ' || last_name)) public.gist_trgm_ops)",
], ],
reverse_sql=[ reverse_sql=[
"DROP INDEX IF EXISTS custom_user_name_gist_idx", 'DROP INDEX IF EXISTS custom_user_name_gist_idx',
"DROP FUNCTION IF EXISTS public.immutable_unaccent(text)", 'DROP FUNCTION IF EXISTS public.immutable_unaccent(text)',
"DROP EXTENSION IF EXISTS pg_trgm", 'DROP EXTENSION IF EXISTS pg_trgm',
"DROP EXTENSION IF EXISTS unaccent", 'DROP EXTENSION IF EXISTS unaccent',
], ],
), ),
] ]

View File

@ -11,7 +11,7 @@ def clean_admin_tools_tables(apps, schema_editor):
try: try:
with schema_editor.connection.cursor() as cursor: with schema_editor.connection.cursor() as cursor:
cursor.execute( cursor.execute(
"SELECT table_name FROM information_schema.tables WHERE table_schema = current_schema() AND" 'SELECT table_name FROM information_schema.tables WHERE table_schema = current_schema() AND'
" table_name LIKE 'admin_tools%'" " table_name LIKE 'admin_tools%'"
) )
rows = cursor.fetchall() rows = cursor.fetchall()

View File

@ -86,7 +86,7 @@ class CreatePartialIndexes(Operation):
schema_editor.execute('DROP INDEX IF EXISTS "%s_%s"' % (self.index_name, i)) schema_editor.execute('DROP INDEX IF EXISTS "%s_%s"' % (self.index_name, i))
def describe(self): def describe(self):
return "Create partial indexes" return 'Create partial indexes'
class DropPartialIndexes(CreatePartialIndexes): class DropPartialIndexes(CreatePartialIndexes):
@ -102,4 +102,4 @@ class DropPartialIndexes(CreatePartialIndexes):
super().database_forwards(app_label, schema_editor, from_state, to_state) super().database_forwards(app_label, schema_editor, from_state, to_state)
def describe(self): def describe(self):
return "Drop partial indexes" return 'Drop partial indexes'

View File

@ -42,15 +42,15 @@ from authentic2.utils.cache import RequestCache
from .. import nonce from .. import nonce
AUTHENTIC_STATUS_CODE_NS = "http://authentic.entrouvert.org/status_code/" AUTHENTIC_STATUS_CODE_NS = 'http://authentic.entrouvert.org/status_code/'
AUTHENTIC_SAME_ID_SENTINEL = 'urn:authentic.entrouvert.org:same-as-provider-entity-id' AUTHENTIC_SAME_ID_SENTINEL = 'urn:authentic.entrouvert.org:same-as-provider-entity-id'
AUTHENTIC_STATUS_CODE_UNKNOWN_PROVIDER = AUTHENTIC_STATUS_CODE_NS + "UnknownProvider" AUTHENTIC_STATUS_CODE_UNKNOWN_PROVIDER = AUTHENTIC_STATUS_CODE_NS + 'UnknownProvider'
AUTHENTIC_STATUS_CODE_MISSING_NAMEID = AUTHENTIC_STATUS_CODE_NS + "MissingNameID" AUTHENTIC_STATUS_CODE_MISSING_NAMEID = AUTHENTIC_STATUS_CODE_NS + 'MissingNameID'
AUTHENTIC_STATUS_CODE_MISSING_SESSION_INDEX = AUTHENTIC_STATUS_CODE_NS + "MissingSessionIndex" AUTHENTIC_STATUS_CODE_MISSING_SESSION_INDEX = AUTHENTIC_STATUS_CODE_NS + 'MissingSessionIndex'
AUTHENTIC_STATUS_CODE_UNKNOWN_SESSION = AUTHENTIC_STATUS_CODE_NS + "UnknownSession" AUTHENTIC_STATUS_CODE_UNKNOWN_SESSION = AUTHENTIC_STATUS_CODE_NS + 'UnknownSession'
AUTHENTIC_STATUS_CODE_MISSING_DESTINATION = AUTHENTIC_STATUS_CODE_NS + "MissingDestination" AUTHENTIC_STATUS_CODE_MISSING_DESTINATION = AUTHENTIC_STATUS_CODE_NS + 'MissingDestination'
AUTHENTIC_STATUS_CODE_INTERNAL_SERVER_ERROR = AUTHENTIC_STATUS_CODE_NS + "InternalServerError" AUTHENTIC_STATUS_CODE_INTERNAL_SERVER_ERROR = AUTHENTIC_STATUS_CODE_NS + 'InternalServerError'
AUTHENTIC_STATUS_CODE_UNAUTHORIZED = AUTHENTIC_STATUS_CODE_NS + "Unauthorized" AUTHENTIC_STATUS_CODE_UNAUTHORIZED = AUTHENTIC_STATUS_CODE_NS + 'Unauthorized'
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -542,7 +542,7 @@ def soap_fault(request, faultcode='soap:Client', faultstring=None):
</soap:Envelope>''' </soap:Envelope>'''
% locals() % locals()
) )
return HttpResponse(content, content_type="text/xml") return HttpResponse(content, content_type='text/xml')
@RequestCache @RequestCache

View File

@ -128,7 +128,7 @@ class MultiSelectFormField(forms.MultipleChoiceField):
class MultiSelectField(models.Field): class MultiSelectField(models.Field):
def get_internal_type(self): def get_internal_type(self):
return "CharField" return 'CharField'
def get_choices_default(self): def get_choices_default(self):
return self.get_choices(include_blank=False) return self.get_choices(include_blank=False)
@ -153,7 +153,7 @@ class MultiSelectField(models.Field):
if isinstance(value, str): if isinstance(value, str):
return value return value
elif isinstance(value, list): elif isinstance(value, list):
return ",".join(value) return ','.join(value)
def validate(self, value, model_instance): def validate(self, value, model_instance):
out = set() out = set()
@ -170,7 +170,7 @@ class MultiSelectField(models.Field):
return value return value
if not value: if not value:
return [] return []
return value.split(",") return value.split(',')
def from_db_value(self, value, expression, connection): def from_db_value(self, value, expression, connection):
return self.to_python(value) return self.to_python(value)
@ -181,6 +181,6 @@ class MultiSelectField(models.Field):
def func(self, fieldname=name, choicedict=None): def func(self, fieldname=name, choicedict=None):
choicedict = choicedict or dict(self.choices) choicedict = choicedict or dict(self.choices)
return ",".join([choicedict.get(value, value) for value in getattr(self, fieldname)]) return ','.join([choicedict.get(value, value) for value in getattr(self, fieldname)])
setattr(cls, 'get_%s_display' % self.name, func) setattr(cls, 'get_%s_display' % self.name, func)

View File

@ -33,7 +33,7 @@ from .models import LibertyProvider, LibertyServiceProvider
class AddLibertyProviderFromUrlForm(forms.Form): class AddLibertyProviderFromUrlForm(forms.Form):
name = forms.CharField(max_length=140, label=_('Name')) name = forms.CharField(max_length=140, label=_('Name'))
slug = forms.SlugField( slug = forms.SlugField(
max_length=140, label=_('Shortcut'), help_text=_("Internal nickname for the service provider") max_length=140, label=_('Shortcut'), help_text=_('Internal nickname for the service provider')
) )
url = forms.URLField(label=_("Metadata's URL")) url = forms.URLField(label=_("Metadata's URL"))
ou = forms.ModelChoiceField( ou = forms.ModelChoiceField(

File diff suppressed because it is too large Load Diff

View File

@ -255,7 +255,7 @@ class Command(BaseCommand):
can_import_django_settings = True can_import_django_settings = True
output_transaction = True output_transaction = True
requires_system_checks = "__all__" requires_system_checks = '__all__'
help = 'Load the specified SAMLv2 metadata file' help = 'Load the specified SAMLv2 metadata file'

View File

@ -692,7 +692,7 @@ class Migration(migrations.Migration):
default=300, default=300,
help_text=( help_text=(
"if iframe logout is used, it's the time between the onload event for this iframe" "if iframe logout is used, it's the time between the onload event for this iframe"
" and the moment we consider its loading to be really finished" ' and the moment we consider its loading to be really finished'
), ),
verbose_name='iframe logout timeout', verbose_name='iframe logout timeout',
), ),

View File

@ -127,35 +127,35 @@ NAME_ID_FORMATS = collections.OrderedDict(
( (
'transient', 'transient',
{ {
'caption': _("Transient"), 'caption': _('Transient'),
'samlv2': lasso.SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT, 'samlv2': lasso.SAML2_NAME_IDENTIFIER_FORMAT_TRANSIENT,
}, },
), ),
( (
'email', 'email',
{ {
'caption': _("Email"), 'caption': _('Email'),
'samlv2': lasso.SAML2_NAME_IDENTIFIER_FORMAT_EMAIL, 'samlv2': lasso.SAML2_NAME_IDENTIFIER_FORMAT_EMAIL,
}, },
), ),
( (
'username', 'username',
{ {
'caption': _("Username (use with Google Apps)"), 'caption': _('Username (use with Google Apps)'),
'samlv2': lasso.SAML2_NAME_IDENTIFIER_FORMAT_UNSPECIFIED, 'samlv2': lasso.SAML2_NAME_IDENTIFIER_FORMAT_UNSPECIFIED,
}, },
), ),
( (
'uuid', 'uuid',
{ {
'caption': _("UUID"), 'caption': _('UUID'),
'samlv2': lasso.SAML2_NAME_IDENTIFIER_FORMAT_UNSPECIFIED, 'samlv2': lasso.SAML2_NAME_IDENTIFIER_FORMAT_UNSPECIFIED,
}, },
), ),
( (
'edupersontargetedid', 'edupersontargetedid',
{ {
'caption': _("Use eduPersonTargetedID attribute"), 'caption': _('Use eduPersonTargetedID attribute'),
'samlv2': lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT, 'samlv2': lasso.SAML2_NAME_IDENTIFIER_FORMAT_PERSISTENT,
}, },
), ),
@ -222,16 +222,16 @@ class SPOptionsIdPPolicy(models.Model):
name = models.CharField(_('name'), max_length=80, unique=True) name = models.CharField(_('name'), max_length=80, unique=True)
enabled = models.BooleanField(verbose_name=_('Enabled'), default=False, db_index=True) enabled = models.BooleanField(verbose_name=_('Enabled'), default=False, db_index=True)
prefered_assertion_consumer_binding = models.CharField( prefered_assertion_consumer_binding = models.CharField(
verbose_name=_("Prefered assertion consumer binding"), verbose_name=_('Prefered assertion consumer binding'),
default='meta', default='meta',
max_length=4, max_length=4,
choices=ASSERTION_CONSUMER_PROFILES, choices=ASSERTION_CONSUMER_PROFILES,
) )
encrypt_nameid = models.BooleanField(verbose_name=_("Encrypt NameID"), default=False) encrypt_nameid = models.BooleanField(verbose_name=_('Encrypt NameID'), default=False)
encrypt_assertion = models.BooleanField(verbose_name=_("Encrypt Assertion"), default=False) encrypt_assertion = models.BooleanField(verbose_name=_('Encrypt Assertion'), default=False)
authn_request_signed = models.BooleanField(verbose_name=_("Authentication request signed"), default=False) authn_request_signed = models.BooleanField(verbose_name=_('Authentication request signed'), default=False)
idp_initiated_sso = models.BooleanField( idp_initiated_sso = models.BooleanField(
verbose_name=_("Allow IdP initiated SSO"), default=False, db_index=True verbose_name=_('Allow IdP initiated SSO'), default=False, db_index=True
) )
# XXX: format in the metadata file, should be suffixed with a star to mark # XXX: format in the metadata file, should be suffixed with a star to mark
# them as special # them as special
@ -239,7 +239,7 @@ class SPOptionsIdPPolicy(models.Model):
max_length=256, default=DEFAULT_NAME_ID_FORMAT, choices=NAME_ID_FORMATS_CHOICES max_length=256, default=DEFAULT_NAME_ID_FORMAT, choices=NAME_ID_FORMATS_CHOICES
) )
accepted_name_id_format = MultiSelectField( accepted_name_id_format = MultiSelectField(
verbose_name=_("NameID formats accepted"), verbose_name=_('NameID formats accepted'),
max_length=1024, max_length=1024,
blank=True, blank=True,
choices=NAME_ID_FORMATS_CHOICES, choices=NAME_ID_FORMATS_CHOICES,
@ -251,9 +251,9 @@ class SPOptionsIdPPolicy(models.Model):
verbose_name=_('Ask user for consent when creating a federation'), default=False verbose_name=_('Ask user for consent when creating a federation'), default=False
) )
accept_slo = models.BooleanField( accept_slo = models.BooleanField(
verbose_name=_("Accept to receive Single Logout requests"), default=True, db_index=True verbose_name=_('Accept to receive Single Logout requests'), default=True, db_index=True
) )
forward_slo = models.BooleanField(verbose_name=_("Forward Single Logout requests"), default=True) forward_slo = models.BooleanField(verbose_name=_('Forward Single Logout requests'), default=True)
needs_iframe_logout = models.BooleanField( needs_iframe_logout = models.BooleanField(
verbose_name=_('needs iframe logout'), verbose_name=_('needs iframe logout'),
help_text=_( help_text=_(
@ -271,7 +271,7 @@ class SPOptionsIdPPolicy(models.Model):
default=300, default=300,
) )
http_method_for_slo_request = models.IntegerField( http_method_for_slo_request = models.IntegerField(
verbose_name=_("HTTP binding for the SLO requests"), verbose_name=_('HTTP binding for the SLO requests'),
choices=HTTP_METHOD, choices=HTTP_METHOD,
default=lasso.HTTP_METHOD_REDIRECT, default=lasso.HTTP_METHOD_REDIRECT,
) )
@ -473,7 +473,7 @@ class LibertyServiceProvider(models.Model):
) )
sp_options_policy = models.ForeignKey( sp_options_policy = models.ForeignKey(
SPOptionsIdPPolicy, SPOptionsIdPPolicy,
related_name="sp_options_policy", related_name='sp_options_policy',
verbose_name=_('service provider options policy'), verbose_name=_('service provider options policy'),
blank=True, blank=True,
null=True, null=True,
@ -556,11 +556,11 @@ class LibertyFederation(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL) user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.SET_NULL)
sp = models.ForeignKey('LibertyServiceProvider', null=True, blank=True, on_delete=models.CASCADE) sp = models.ForeignKey('LibertyServiceProvider', null=True, blank=True, on_delete=models.CASCADE)
name_id_format = models.CharField(max_length=100, verbose_name="NameIDFormat", blank=True, null=True) name_id_format = models.CharField(max_length=100, verbose_name='NameIDFormat', blank=True, null=True)
name_id_content = models.CharField(max_length=100, verbose_name="NameID") name_id_content = models.CharField(max_length=100, verbose_name='NameID')
name_id_qualifier = models.CharField(max_length=256, verbose_name="NameQualifier", blank=True, null=True) name_id_qualifier = models.CharField(max_length=256, verbose_name='NameQualifier', blank=True, null=True)
name_id_sp_name_qualifier = models.CharField( name_id_sp_name_qualifier = models.CharField(
max_length=256, verbose_name="SPNameQualifier", blank=True, null=True max_length=256, verbose_name='SPNameQualifier', blank=True, null=True
) )
termination_notified = models.BooleanField(blank=True, default=False) termination_notified = models.BooleanField(blank=True, default=False)
creation = models.DateTimeField(auto_now_add=True) creation = models.DateTimeField(auto_now_add=True)
@ -599,8 +599,8 @@ class LibertyFederation(models.Model):
return not qs.exists() return not qs.exists()
class Meta: class Meta:
verbose_name = _("SAML federation") verbose_name = _('SAML federation')
verbose_name_plural = _("SAML federations") verbose_name_plural = _('SAML federations')
def __str__(self): def __str__(self):
return str(self.name_id_content) return str(self.name_id_content)
@ -613,10 +613,10 @@ class LibertySession(models.Model):
session_index = models.CharField(max_length=80) session_index = models.CharField(max_length=80)
provider_id = models.CharField(max_length=256) provider_id = models.CharField(max_length=256)
federation = models.ForeignKey(LibertyFederation, blank=True, null=True, on_delete=models.CASCADE) federation = models.ForeignKey(LibertyFederation, blank=True, null=True, on_delete=models.CASCADE)
name_id_qualifier = models.CharField(max_length=256, verbose_name=_("Qualifier"), null=True) name_id_qualifier = models.CharField(max_length=256, verbose_name=_('Qualifier'), null=True)
name_id_format = models.CharField(max_length=100, verbose_name=_("NameIDFormat"), null=True) name_id_format = models.CharField(max_length=100, verbose_name=_('NameIDFormat'), null=True)
name_id_content = models.CharField(max_length=100, verbose_name=_("NameID")) name_id_content = models.CharField(max_length=100, verbose_name=_('NameID'))
name_id_sp_name_qualifier = models.CharField(max_length=256, verbose_name=_("SPNameQualifier"), null=True) name_id_sp_name_qualifier = models.CharField(max_length=256, verbose_name=_('SPNameQualifier'), null=True)
creation = models.DateTimeField(auto_now_add=True) creation = models.DateTimeField(auto_now_add=True)
objects = managers.LibertySessionManager() objects = managers.LibertySessionManager()
@ -654,8 +654,8 @@ class LibertySession(models.Model):
return '<LibertySession %s>' % self.__dict__ return '<LibertySession %s>' % self.__dict__
class Meta: class Meta:
verbose_name = _("SAML session") verbose_name = _('SAML session')
verbose_name_plural = _("SAML sessions") verbose_name_plural = _('SAML sessions')
indexes = [ indexes = [
models.Index(fields=['provider_id', 'django_session_key']), models.Index(fields=['provider_id', 'django_session_key']),
] ]
@ -672,8 +672,8 @@ class KeyValue(models.Model):
return str(self.key) return str(self.key)
class Meta: class Meta:
verbose_name = _("key value association") verbose_name = _('key value association')
verbose_name_plural = _("key value associations") verbose_name_plural = _('key value associations')
def save_key_values(key, *values): def save_key_values(key, *values):

View File

@ -275,7 +275,7 @@ def iso8601_to_datetime(date_string):
m = re.match(r'(\d+-\d+-\d+T\d+:\d+:\d+)(?:\.\d+)?Z$', date_string) m = re.match(r'(\d+-\d+-\d+T\d+:\d+:\d+)(?:\.\d+)?Z$', date_string)
if not m: if not m:
raise ValueError('Invalid ISO8601 date') raise ValueError('Invalid ISO8601 date')
tm = time.strptime(m.group(1) + 'Z', "%Y-%m-%dT%H:%M:%SZ") tm = time.strptime(m.group(1) + 'Z', '%Y-%m-%dT%H:%M:%SZ')
return datetime.datetime.fromtimestamp(time.mktime(tm)) return datetime.datetime.fromtimestamp(time.mktime(tm))

View File

@ -50,11 +50,11 @@ def parse_attribute_filters_file(path):
def fixqname(element, qname): def fixqname(element, qname):
prefix, local = qname.split(":") prefix, local = qname.split(':')
try: try:
return "{%s}%s" % (element.namespaces[prefix], local) return '{%s}%s' % (element.namespaces[prefix], local)
except KeyError: except KeyError:
raise SyntaxError("unknown namespace prefix (%s)" % prefix) raise SyntaxError('unknown namespace prefix (%s)' % prefix)
def parse_attribute_filter_et(root): def parse_attribute_filter_et(root):

View File

@ -50,7 +50,7 @@ def PreDeserializer(objects, **options):
db = options.pop('using', DEFAULT_DB_ALIAS) db = options.pop('using', DEFAULT_DB_ALIAS)
for d in objects: for d in objects:
Model = _get_model(d["model"]) Model = _get_model(d['model'])
for pfield in Model._meta.private_fields: for pfield in Model._meta.private_fields:
if not isinstance(pfield, GenericForeignKey): if not isinstance(pfield, GenericForeignKey):
continue continue

View File

@ -334,8 +334,8 @@ REST_FRAMEWORK = {
# Authentic2 Auth SAML # Authentic2 Auth SAML
MELLON_ADAPTER = ('authentic2_auth_saml.adapters.AuthenticAdapter',) MELLON_ADAPTER = ('authentic2_auth_saml.adapters.AuthenticAdapter',)
MELLON_LOOKUP_BY_ATTRIBUTES = [ MELLON_LOOKUP_BY_ATTRIBUTES = [
{"saml_attribute": "email", "user_field": "email", "ignore-case": True}, {'saml_attribute': 'email', 'user_field': 'email', 'ignore-case': True},
{"saml_attribute": "username", "user_field": "username"}, {'saml_attribute': 'username', 'user_field': 'username'},
] ]
# timeout used in python-requests call, in seconds # timeout used in python-requests call, in seconds
@ -372,7 +372,7 @@ DJANGO_RBAC_PERMISSIONS_HIERARCHY = {
FORM_RENDERER = 'django.forms.renderers.TemplatesSetting' FORM_RENDERER = 'django.forms.renderers.TemplatesSetting'
SILENCED_SYSTEM_CHECKS = ["auth.W004"] SILENCED_SYSTEM_CHECKS = ['auth.W004']
SMS_SENDER = 'EO' SMS_SENDER = 'EO'
SMS_URL = '' SMS_URL = ''

View File

@ -73,19 +73,19 @@ class ExpressionError(ValidationError):
def is_valid_hostname(hostname): def is_valid_hostname(hostname):
if hostname[-1] == ".": if hostname[-1] == '.':
# strip exactly one dot from the right, if present # strip exactly one dot from the right, if present
hostname = hostname[:-1] hostname = hostname[:-1]
if len(hostname) > 253: if len(hostname) > 253:
return False return False
labels = hostname.split(".") labels = hostname.split('.')
# the TLD must be not all-numeric # the TLD must be not all-numeric
if re.match(r"[0-9]+$", labels[-1]): if re.match(r'[0-9]+$', labels[-1]):
return False return False
allowed = re.compile(r"(?!-)[a-z0-9-]{1,63}(?<!-)$", re.IGNORECASE) allowed = re.compile(r'(?!-)[a-z0-9-]{1,63}(?<!-)$', re.IGNORECASE)
return all(allowed.match(label) for label in labels) return all(allowed.match(label) for label in labels)

View File

@ -616,7 +616,7 @@ def login(request, template_name='authentic2/login.html', redirect_field_name=RE
} }
# Cancel button # Cancel button
if request.method == "POST" and constants.CANCEL_FIELD_NAME in request.POST: if request.method == 'POST' and constants.CANCEL_FIELD_NAME in request.POST:
return utils_misc.continue_to_next_url(request, params={'cancel': 1}) return utils_misc.continue_to_next_url(request, params={'cancel': 1})
# Create blocks # Create blocks
@ -708,7 +708,7 @@ class ProfileView(HomeURLMixin, cbv.TemplateNamesMixin, TemplateView):
request = self.request request = self.request
if request.method == "POST": if request.method == 'POST':
for frontend in frontends: for frontend in frontends:
if 'submit-%s' % frontend.get_identifier() in request.POST: if 'submit-%s' % frontend.get_identifier() in request.POST:
form = frontend.form()(data=request.POST) form = frontend.form()(data=request.POST)
@ -1049,7 +1049,7 @@ class LoggedInView(View):
logged_in = never_cache(LoggedInView.as_view()) logged_in = never_cache(LoggedInView.as_view())
def csrf_failure_view(request, reason=""): def csrf_failure_view(request, reason=''):
messages.warning(request, _('The page is out of date, it was reloaded for you')) messages.warning(request, _('The page is out of date, it was reloaded for you'))
return HttpResponseRedirect(request.get_full_path()) return HttpResponseRedirect(request.get_full_path())
@ -2004,7 +2004,7 @@ class AccountDeleteView(HomeURLMixin, RecentAuthenticationMixin, TemplateView):
if self.request.user.email_verified: if self.request.user.email_verified:
utils_misc.send_account_deletion_code(self.request, self.request.user) utils_misc.send_account_deletion_code(self.request, self.request.user)
messages.info( messages.info(
request, _("An account deletion validation email has been sent to your email address.") request, _('An account deletion validation email has been sent to your email address.')
) )
elif self.request.user.phone_verified_on and phone: elif self.request.user.phone_verified_on and phone:
try: try:

View File

@ -36,7 +36,7 @@ from django.core.wsgi import get_wsgi_application
# XXX: monkeypatch logging # XXX: monkeypatch logging
from . import logger # pylint: disable=unused-import from . import logger # pylint: disable=unused-import
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "authentic2.settings") os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'authentic2.settings')
# This application object is used by any WSGI server configured to use this # This application object is used by any WSGI server configured to use this
# file. This includes Django's development server, if the WSGI_APPLICATION # file. This includes Django's development server, if the WSGI_APPLICATION

View File

@ -31,7 +31,7 @@ class Command(BaseCommand):
'''Load LDAP ldif file''' '''Load LDAP ldif file'''
can_import_django_settings = True can_import_django_settings = True
requires_system_checks = "__all__" requires_system_checks = '__all__'
help = 'Register an OpenID Connect OP' help = 'Register an OpenID Connect OP'
def add_arguments(self, parser): def add_arguments(self, parser):

View File

@ -80,7 +80,7 @@ class AttributeInlineAdmin(admin.TabularInline):
class ServiceAdmin(admin.ModelAdmin): class ServiceAdmin(admin.ModelAdmin):
form = ServiceForm form = ServiceForm
list_display = ('name', 'ou', 'slug', 'urls', 'identifier_attribute') list_display = ('name', 'ou', 'slug', 'urls', 'identifier_attribute')
prepopulated_fields = {"slug": ("name",)} prepopulated_fields = {'slug': ('name',)}
fieldsets = ( fieldsets = (
( (
None, None,

View File

@ -58,7 +58,7 @@ class Migration(migrations.Migration):
default=300, default=300,
help_text=( help_text=(
"if iframe logout is used, it's the time between the onload event for this iframe" "if iframe logout is used, it's the time between the onload event for this iframe"
" and the moment we consider its loading to be really finished" ' and the moment we consider its loading to be really finished'
), ),
verbose_name='iframe logout timeout (ms)', verbose_name='iframe logout timeout (ms)',
), ),

View File

@ -49,7 +49,7 @@ class OIDCClientForm(SlugMixin, forms.ModelForm):
] ]
labels = { labels = {
'has_api_access': _("Has access to Authentic's synchronization API"), 'has_api_access': _("Has access to Authentic's synchronization API"),
'activate_user_profiles': _("Activates user profiles selection"), 'activate_user_profiles': _('Activates user profiles selection'),
} }
widgets = {'colour': forms.TextInput(attrs={'type': 'color'})} widgets = {'colour': forms.TextInput(attrs={'type': 'color'})}

View File

@ -877,10 +877,10 @@ def test_api_role_add_members(app, api_user, role, member, member_rando2):
else: else:
status = 201 status = 201
payload = {"data": []} payload = {'data': []}
for m in [member, member_rando2, member_rando2]: # test no duplicate for m in [member, member_rando2, member_rando2]: # test no duplicate
payload['data'].append({"uuid": m.uuid}) payload['data'].append({'uuid': m.uuid})
resp = app.post_json(f'/api/roles/{role.uuid}/relationships/members/', params=payload, status=status) resp = app.post_json(f'/api/roles/{role.uuid}/relationships/members/', params=payload, status=status)
@ -917,10 +917,10 @@ def test_api_role_remove_members(app, api_user, role, member, member_rando2):
else: else:
status = 200 status = 200
payload = {"data": []} payload = {'data': []}
for m in [member, member_rando2, member_rando2]: # test no duplicate for m in [member, member_rando2, member_rando2]: # test no duplicate
payload['data'].append({"uuid": m.uuid}) payload['data'].append({'uuid': m.uuid})
resp = app.delete_json(f'/api/roles/{role.uuid}/relationships/members/', params=payload, status=status) resp = app.delete_json(f'/api/roles/{role.uuid}/relationships/members/', params=payload, status=status)
@ -960,11 +960,11 @@ def test_api_role_set_members(app, api_user, role, member, member_rando2, ou_ran
else: else:
status = 200 status = 200
payload = {"data": []} payload = {'data': []}
role.members.add(user) role.members.add(user)
for m in [member, member_rando2, member_rando2]: # test no duplicate for m in [member, member_rando2, member_rando2]: # test no duplicate
payload['data'].append({"uuid": m.uuid}) payload['data'].append({'uuid': m.uuid})
resp = app.put_json(f'/api/roles/{role.uuid}/relationships/members/', params=payload, status=status) resp = app.put_json(f'/api/roles/{role.uuid}/relationships/members/', params=payload, status=status)
@ -1041,21 +1041,21 @@ def test_api_role_members_payload_missing(app, api_user, role):
def test_api_role_members_wrong_payload_types(app, superuser, role_random, member_rando2): def test_api_role_members_wrong_payload_types(app, superuser, role_random, member_rando2):
app.authorization = ('Basic', (superuser.username, superuser.username)) app.authorization = ('Basic', (superuser.username, superuser.username))
payload = [{"data": [{'uuid': member_rando2.uuid}]}] payload = [{'data': [{'uuid': member_rando2.uuid}]}]
resp = app.post_json(f'/api/roles/{role_random.uuid}/relationships/members/', params=payload, status=400) resp = app.post_json(f'/api/roles/{role_random.uuid}/relationships/members/', params=payload, status=400)
assert resp.json['result'] == 0 assert resp.json['result'] == 0
assert resp.json['errors'] == ['Payload must be a dictionary'] assert resp.json['errors'] == ['Payload must be a dictionary']
payload = {"data": [[member_rando2.uuid]]} payload = {'data': [[member_rando2.uuid]]}
resp = app.post_json(f'/api/roles/{role_random.uuid}/relationships/members/', params=payload, status=400) resp = app.post_json(f'/api/roles/{role_random.uuid}/relationships/members/', params=payload, status=400)
assert resp.json['result'] == 0 assert resp.json['result'] == 0
assert resp.json['errors'] == ["List elements of the 'data' dict entry must be dictionaries"] assert resp.json['errors'] == ["List elements of the 'data' dict entry must be dictionaries"]
payload = {"data": [member_rando2.uuid]} payload = {'data': [member_rando2.uuid]}
resp = app.post_json(f'/api/roles/{role_random.uuid}/relationships/members/', params=payload, status=400) resp = app.post_json(f'/api/roles/{role_random.uuid}/relationships/members/', params=payload, status=400)
@ -1317,14 +1317,14 @@ def test_api_drf_authentication_class(app, admin, user_ou1, oidc_client):
app.authorization = ('Basic', ('foo', 'bar')) app.authorization = ('Basic', ('foo', 'bar'))
resp = app.get(url, status=401) resp = app.get(url, status=401)
assert resp.json['result'] == 0 assert resp.json['result'] == 0
assert resp.json['errors'] == "Invalid username/password." assert resp.json['errors'] == 'Invalid username/password.'
# test inactive client # test inactive client
admin.is_active = False admin.is_active = False
admin.save() admin.save()
app.authorization = ('Basic', (admin.username, admin.username)) app.authorization = ('Basic', (admin.username, admin.username))
resp = app.get(url, status=401) resp = app.get(url, status=401)
assert resp.json['result'] == 0 assert resp.json['result'] == 0
assert resp.json['errors'] == "User inactive or deleted." assert resp.json['errors'] == 'User inactive or deleted.'
# test oidc client unauthorized for user_ou1 # test oidc client unauthorized for user_ou1
app.authorization = ('Basic', (oidc_client.username, oidc_client.username)) app.authorization = ('Basic', (oidc_client.username, oidc_client.username))
app.get(url, status=404) app.get(url, status=404)
@ -1356,7 +1356,7 @@ def test_api_check_password(app, superuser, oidc_client, user_ou1):
payload = {'username': 'whatever', 'password': 'password'} payload = {'username': 'whatever', 'password': 'password'}
resp = app.post_json(reverse('a2-api-check-password'), params=payload, status=200) resp = app.post_json(reverse('a2-api-check-password'), params=payload, status=200)
assert resp.json['result'] == 0 assert resp.json['result'] == 0
assert resp.json['errors'] == ["Invalid username/password."] assert resp.json['errors'] == ['Invalid username/password.']
# test with valid credentials # test with valid credentials
payload = {'username': user_ou1.username, 'password': user_ou1.username} payload = {'username': user_ou1.username, 'password': user_ou1.username}
resp = app.post_json(reverse('a2-api-check-password'), params=payload, status=200) resp = app.post_json(reverse('a2-api-check-password'), params=payload, status=200)
@ -1600,8 +1600,8 @@ def test_api_post_ou_no_slug(app, superuser):
} }
resp = app.post_json('/api/ous/', params=ou_data, status=400) resp = app.post_json('/api/ous/', params=ou_data, status=400)
assert resp.json['errors']['__all__'] == [ assert resp.json['errors']['__all__'] == [
"The fields name must make a unique set.", 'The fields name must make a unique set.',
"The fields slug must make a unique set.", 'The fields slug must make a unique set.',
] ]
# no slug no name # no slug no name
ou_data = { ou_data = {
@ -2634,15 +2634,15 @@ def test_api_statistics_list(app, admin):
'id': 'login', 'id': 'login',
'filters': [ 'filters': [
{ {
"id": "time_interval", 'id': 'time_interval',
"label": "Time interval", 'label': 'Time interval',
"options": [ 'options': [
{"id": "day", "label": "Day"}, {'id': 'day', 'label': 'Day'},
{"id": "month", "label": "Month"}, {'id': 'month', 'label': 'Month'},
{"id": "year", "label": "Year"}, {'id': 'year', 'label': 'Year'},
], ],
"required": True, 'required': True,
"default": "month", 'default': 'month',
}, },
{'id': 'service', 'label': 'Service', 'options': []}, {'id': 'service', 'label': 'Service', 'options': []},
], ],
@ -2655,15 +2655,15 @@ def test_api_statistics_list(app, admin):
'id': 'service-login', 'id': 'service-login',
'filters': [ 'filters': [
{ {
"id": "time_interval", 'id': 'time_interval',
"label": "Time interval", 'label': 'Time interval',
"options": [ 'options': [
{"id": "day", "label": "Day"}, {'id': 'day', 'label': 'Day'},
{"id": "month", "label": "Month"}, {'id': 'month', 'label': 'Month'},
{"id": "year", "label": "Year"}, {'id': 'year', 'label': 'Year'},
], ],
"required": True, 'required': True,
"default": "month", 'default': 'month',
}, },
], ],
'deprecated': True, 'deprecated': True,
@ -2829,7 +2829,7 @@ def test_api_statistics(app, admin, freezer, event_type_name, event_name):
headers = basic_authorization_header(admin) headers = basic_authorization_header(admin)
resp = app.get('/api/statistics/login/?time_interval=month', headers=headers) resp = app.get('/api/statistics/login/?time_interval=month', headers=headers)
assert resp.json == {"data": {"series": [], "x_labels": [], "subfilters": []}, "err": 0} assert resp.json == {'data': {'series': [], 'x_labels': [], 'subfilters': []}, 'err': 0}
user = User.objects.create(username='john.doe', email='john.doe@example.com', ou=get_default_ou()) user = User.objects.create(username='john.doe', email='john.doe@example.com', ou=get_default_ou())
ou = OU.objects.create(name='Second OU', slug='second') ou = OU.objects.create(name='Second OU', slug='second')

View File

@ -765,7 +765,7 @@ def test_fc_authenticator_data_migration(migration, settings):
FcAuthenticator = old_apps.get_model(app, 'FcAuthenticator') FcAuthenticator = old_apps.get_model(app, 'FcAuthenticator')
settings.AUTH_FRONTENDS_KWARGS = { settings.AUTH_FRONTENDS_KWARGS = {
"fc": {"priority": 3, "show_condition": "'backoffice' not in login_hint"} 'fc': {'priority': 3, 'show_condition': "'backoffice' not in login_hint"}
} }
settings.A2_FC_ENABLE = True settings.A2_FC_ENABLE = True
settings.A2_FC_CLIENT_ID = '211286433e39cce01db448d80181bdfd005554b19cd51b3fe7943f6b3b86ab6k' settings.A2_FC_CLIENT_ID = '211286433e39cce01db448d80181bdfd005554b19cd51b3fe7943f6b3b86ab6k'
@ -835,7 +835,7 @@ def test_fc_authenticator_data_migration_bad_settings(migration, settings):
old_apps = migration.before(migrate_from) old_apps = migration.before(migrate_from)
FcAuthenticator = old_apps.get_model(app, 'FcAuthenticator') FcAuthenticator = old_apps.get_model(app, 'FcAuthenticator')
settings.AUTH_FRONTENDS_KWARGS = {"fc": {"priority": None, "show_condition": None}} settings.AUTH_FRONTENDS_KWARGS = {'fc': {'priority': None, 'show_condition': None}}
settings.A2_FC_ENABLE = False settings.A2_FC_ENABLE = False
settings.A2_FC_CLIENT_ID = 'x' * 260 settings.A2_FC_CLIENT_ID = 'x' * 260
settings.A2_FC_CLIENT_SECRET = None settings.A2_FC_CLIENT_SECRET = None

View File

@ -196,7 +196,7 @@ def test_saml_authenticator_data_migration_bad_settings(migration, settings):
old_apps = migration.before(migrate_from) old_apps = migration.before(migrate_from)
SAMLAuthenticator = old_apps.get_model(app, 'SAMLAuthenticator') SAMLAuthenticator = old_apps.get_model(app, 'SAMLAuthenticator')
settings.AUTH_FRONTENDS_KWARGS = {"saml": {"priority": None, "show_condition": None}} settings.AUTH_FRONTENDS_KWARGS = {'saml': {'priority': None, 'show_condition': None}}
settings.MELLON_METADATA_CACHE_TIME = 2**16 settings.MELLON_METADATA_CACHE_TIME = 2**16
settings.MELLON_METADATA_HTTP_TIMEOUT = -1 settings.MELLON_METADATA_HTTP_TIMEOUT = -1
settings.MELLON_PROVISION = None settings.MELLON_PROVISION = None

View File

@ -27,37 +27,37 @@ from authentic2_idp_oidc.models import OIDCClaim, OIDCClient
from tests import utils from tests import utils
JWKSET = { JWKSET = {
"keys": [ 'keys': [
{ {
"qi": "h_zifVD-ChelxZUVxhICNcgGkQz26b-EdIlLY9rN7SX_aD3sLI_JHEHV4Bz3kV5eW8O4qJ8SHhfUdHGK-" 'qi': 'h_zifVD-ChelxZUVxhICNcgGkQz26b-EdIlLY9rN7SX_aD3sLI_JHEHV4Bz3kV5eW8O4qJ8SHhfUdHGK-'
"gRH7FVOGoXnXACf47QoXowHzsPLL64wCuZENTl7hIRGLY-BInULkfTQfuiVSMoxPjsVNTMBzMiz0bNjMQyMyvW5xH4", 'gRH7FVOGoXnXACf47QoXowHzsPLL64wCuZENTl7hIRGLY-BInULkfTQfuiVSMoxPjsVNTMBzMiz0bNjMQyMyvW5xH4',
"kty": "RSA", 'kty': 'RSA',
"d": "pUcL4-LDBy3rqJWip269h5Hd6nLvqjXltfkVe_mL-LwZPHmCrUaj_SX54SnCY3Wyf7kxhoMYUac62lQ71923uJPFFdiavAujbNrtZPq32i4C-" 'd': 'pUcL4-LDBy3rqJWip269h5Hd6nLvqjXltfkVe_mL-LwZPHmCrUaj_SX54SnCY3Wyf7kxhoMYUac62lQ71923uJPFFdiavAujbNrtZPq32i4C-'
"1apWXW8OGJr8VoVDqalxj9SAq1G54wbbsaAPrZdyuqy-esNxDqDigfbM-cWgngBBYo5CSsfnmnd05N2cUS26L7QzWbNHwilnBTE9e_J7rK3xUCDKrobv6_LiI-" '1apWXW8OGJr8VoVDqalxj9SAq1G54wbbsaAPrZdyuqy-esNxDqDigfbM-cWgngBBYo5CSsfnmnd05N2cUS26L7QzWbNHwilnBTE9e_J7rK3xUCDKrobv6_LiI-'
"AhMmBHJSrCxjexh0wzfBi_Ntj9BGCcPThDjG8SQvaV-aLNdLfIy2XO3i076RLBB6Hm_yHuAparrwp-pPE48eQdiYjrSAFalz4ojWQ3_ByLA6uAQ", 'AhMmBHJSrCxjexh0wzfBi_Ntj9BGCcPThDjG8SQvaV-aLNdLfIy2XO3i076RLBB6Hm_yHuAparrwp-pPE48eQdiYjrSAFalz4ojWQ3_ByLA6uAQ',
"q": "2FvfeWnIlWNUipan7DIBlJrmz5EinJNxrQ-BNwPHrAoIM8qvyC7jPy09YxZs5Y9CMMZSal6C4Nm2LHBFxHU9z1qd5" 'q': '2FvfeWnIlWNUipan7DIBlJrmz5EinJNxrQ-BNwPHrAoIM8qvyC7jPy09YxZs5Y9CMMZSal6C4Nm2LHBFxHU9z1qd5'
"XDzbk19G-y1lDqZizVXr876TpiAjuq03rcoMQm8dQru_pVjUdgxR64vKyJ9CaFMAqcpZeEMIqAvzhQG8uE", 'XDzbk19G-y1lDqZizVXr876TpiAjuq03rcoMQm8dQru_pVjUdgxR64vKyJ9CaFMAqcpZeEMIqAvzhQG8uE',
"dp": "Kg4HPGpzenhK2ser6nfM1Yt-pkqBbWQotvqsxGptECXpbN7vweupvL5kJPeRrbsXKp9QE7DXTN1sG9puJxMSwtgiv" 'dp': 'Kg4HPGpzenhK2ser6nfM1Yt-pkqBbWQotvqsxGptECXpbN7vweupvL5kJPeRrbsXKp9QE7DXTN1sG9puJxMSwtgiv'
"4hr9Va9e9WOC6PMd2VY7tgw5uKMpPLMc5y82PusRhBoRh0SUUsjyQxK9PGtWYnGZXbAoaIYPdMyDlosfqU", '4hr9Va9e9WOC6PMd2VY7tgw5uKMpPLMc5y82PusRhBoRh0SUUsjyQxK9PGtWYnGZXbAoaIYPdMyDlosfqU',
"dq": "QuUNEHYTjZTbo8n2-4FumarXKGBAalbwM8jyc7cYemnTpWfKt8M_gd4T99oMK2IC3h_DhZ3ZK3pE6DKCb76sMLtczH8C1RziTMsATWdc5_zDMtl07O4b-" 'dq': 'QuUNEHYTjZTbo8n2-4FumarXKGBAalbwM8jyc7cYemnTpWfKt8M_gd4T99oMK2IC3h_DhZ3ZK3pE6DKCb76sMLtczH8C1RziTMsATWdc5_zDMtl07O4b-'
"ZQ5_g51P8w515pc0JwRzFFi0z3Y2aZdMKgNX1id5SES5nXOshHhICE", 'ZQ5_g51P8w515pc0JwRzFFi0z3Y2aZdMKgNX1id5SES5nXOshHhICE',
"n": "0lN6CiJGFD8BSPV_azLoEl6Nq-WlHkU743D5rqvzw1sOaxstMGxAhVk2YIhWwfvapV6XjO_yvc4778VBTELOdjRw6BGUdBJepdwkL__TPyjEVhqMQj9MKhE" 'n': '0lN6CiJGFD8BSPV_azLoEl6Nq-WlHkU743D5rqvzw1sOaxstMGxAhVk2YIhWwfvapV6XjO_yvc4778VBTELOdjRw6BGUdBJepdwkL__TPyjEVhqMQj9MKhE'
"U4GUy9w0Lsilb5D01kfrOKpmdcYw4jhcDvb0H4-LZgh1Vk84vF4WaQCUg_AX4drVDQOjoU8kuWIM8gz9w6zEsbIw-gtMRpFwS8ncA0zDX5VfyC77iMxzFftDIP2g" 'U4GUy9w0Lsilb5D01kfrOKpmdcYw4jhcDvb0H4-LZgh1Vk84vF4WaQCUg_AX4drVDQOjoU8kuWIM8gz9w6zEsbIw-gtMRpFwS8ncA0zDX5VfyC77iMxzFftDIP2g'
"M5GvdevMzvP9IRkRRBhP9vV4JchBFPHSA9OPJcnySjJJNW6aAJn6P6JasN1z68khjufM09J8UzmLAZYOq7gUG95Ox1KsV-g337Q", 'M5GvdevMzvP9IRkRRBhP9vV4JchBFPHSA9OPJcnySjJJNW6aAJn6P6JasN1z68khjufM09J8UzmLAZYOq7gUG95Ox1KsV-g337Q',
"e": "AQAB", 'e': 'AQAB',
"p": "-Nyj_Sw3f2HUqSssCZv84y7b3blOtGGAhfYN_JtGfcTQv2bOtxrIUzeonCi-Z_1W4hO10tqxJcOB0ibtDqkDlLhnLaIYOBfriITRFK83EJG5sC-" 'p': '-Nyj_Sw3f2HUqSssCZv84y7b3blOtGGAhfYN_JtGfcTQv2bOtxrIUzeonCi-Z_1W4hO10tqxJcOB0ibtDqkDlLhnLaIYOBfriITRFK83EJG5sC-'
"0KTmFzUXFTA2aMc1QgP-Fu6gUfQpPqLgWxhx8EFhkBlBZshKU5-C-385Sco0", '0KTmFzUXFTA2aMc1QgP-Fu6gUfQpPqLgWxhx8EFhkBlBZshKU5-C-385Sco0',
"kid": "46c686ea-7d4e-41cd-a462-2125fc1dee0e", 'kid': '46c686ea-7d4e-41cd-a462-2125fc1dee0e',
}, },
{ {
"kty": "EC", 'kty': 'EC',
"d": "wwULaR9UYWZW6U2oEbkz3sO1lhPSj6DyA6e7PiUfhog", 'd': 'wwULaR9UYWZW6U2oEbkz3sO1lhPSj6DyA6e7PiUfhog',
"use": "sig", 'use': 'sig',
"crv": "P-256", 'crv': 'P-256',
"x": "HZMHZkX-63heqA5pvWn-UR7bgcXZNEcQa5wfvG_BzTw", 'x': 'HZMHZkX-63heqA5pvWn-UR7bgcXZNEcQa5wfvG_BzTw',
"y": "SUCuwjjiyKvGq5Odr0sjDqjha_CBqks0JQFrR7Ei5OQ", 'y': 'SUCuwjjiyKvGq5Odr0sjDqjha_CBqks0JQFrR7Ei5OQ',
"alg": "ES256", 'alg': 'ES256',
"kid": "ac85baf4-835b-49b2-8272-ffecce7654c9", 'kid': 'ac85baf4-835b-49b2-8272-ffecce7654c9',
}, },
] ]
} }

View File

@ -54,8 +54,8 @@ def test_add_oidc_service_superuser(superuser_app):
assert oidc_client.activate_user_profiles is True assert oidc_client.activate_user_profiles is True
assert resp.location == f'/manage/services/{oidc_client.pk}/' assert resp.location == f'/manage/services/{oidc_client.pk}/'
resp = resp.follow() resp = resp.follow()
assert "Settings" in resp.text assert 'Settings' in resp.text
assert "Delete" in resp.text assert 'Delete' in resp.text
def test_add_oidc_service_admin(app): def test_add_oidc_service_admin(app):
@ -79,8 +79,8 @@ def test_add_oidc_service_admin(app):
assert oidc_client.activate_user_profiles is False assert oidc_client.activate_user_profiles is False
assert resp.location == f'/manage/services/{oidc_client.pk}/' assert resp.location == f'/manage/services/{oidc_client.pk}/'
resp = resp.follow() resp = resp.follow()
assert "Settings" in resp.text assert 'Settings' in resp.text
assert "Delete" in resp.text assert 'Delete' in resp.text
class TestEdit: class TestEdit:
@ -126,8 +126,8 @@ class TestEdit:
resp = form.submit() resp = form.submit()
assert resp.location == '..' assert resp.location == '..'
resp = resp.follow() resp = resp.follow()
assert "New Test" in resp.text assert 'New Test' in resp.text
assert "#ff00ff" in resp.text assert '#ff00ff' in resp.text
def test_delete(self, app): def test_delete(self, app):
resp = app.get('/manage/services/') resp = app.get('/manage/services/')
@ -210,7 +210,7 @@ class TestEdit:
def test_edit_claim(self, app, oidc_client, claim): def test_edit_claim(self, app, oidc_client, claim):
resp = app.get(f'/manage/services/{oidc_client.pk}/settings/') resp = app.get(f'/manage/services/{oidc_client.pk}/settings/')
assert "claim" in resp.text assert 'claim' in resp.text
resp = resp.click('Edit', index=1) resp = resp.click('Edit', index=1)
form = resp.form form = resp.form
form['value'] = 'new value' form['value'] = 'new value'
@ -221,7 +221,7 @@ class TestEdit:
def test_delete_claim(self, app, oidc_client): def test_delete_claim(self, app, oidc_client):
resp = app.get(f'/manage/services/{oidc_client.pk}/settings/') resp = app.get(f'/manage/services/{oidc_client.pk}/settings/')
assert "claim" in resp.text assert 'claim' in resp.text
resp = resp.click('Delete') resp = resp.click('Delete')
form = resp.form form = resp.form
resp = form.submit() resp = form.submit()

View File

@ -1850,7 +1850,7 @@ def test_consents_view(app, oidc_client, simple_user):
utils.login(app, simple_user) utils.login(app, simple_user)
response = app.get(url, status=200) response = app.get(url, status=200)
assert "You have not given any authorization to access your account profile data." in response.text assert 'You have not given any authorization to access your account profile data.' in response.text
# create an ou authz # create an ou authz
ou1 = OrganizationalUnit.objects.create(name='Orgunit1', slug='orgunit1') ou1 = OrganizationalUnit.objects.create(name='Orgunit1', slug='orgunit1')
@ -1878,7 +1878,7 @@ def test_consents_view(app, oidc_client, simple_user):
) )
response = app.get(url, status=200) response = app.get(url, status=200)
assert "You have given authorizations to access your account profile data." in response.text assert 'You have given authorizations to access your account profile data.' in response.text
assert len(response.html.find_all('button', {'class': 'consents--revoke-button'})) == 4 assert len(response.html.find_all('button', {'class': 'consents--revoke-button'})) == 4
# revoke two service authz # revoke two service authz

View File

@ -371,7 +371,7 @@ def test_login_profile_reversible_sub(app, oidc_client, profile_user, profile_se
id_token = response.json['id_token'] id_token = response.json['id_token']
jwkset = get_jwkset() jwkset = get_jwkset()
key = jwkset.get_key("ac85baf4-835b-49b2-8272-ffecce7654c9") key = jwkset.get_key('ac85baf4-835b-49b2-8272-ffecce7654c9')
algs = ['ES256'] algs = ['ES256']
jwt = JWT(jwt=id_token, key=key, algs=algs) jwt = JWT(jwt=id_token, key=key, algs=algs)
claims = json.loads(jwt.claims) claims = json.loads(jwt.claims)

View File

@ -239,7 +239,7 @@ def test_role_with_permission_export_json(db):
operation=op, operation=op,
ou=ou, ou=ou,
target_ct=ContentType.objects.get_for_model(ContentType), target_ct=ContentType.objects.get_for_model(ContentType),
target_id=ContentType.objects.get(app_label="saml", model="libertyprovider").pk, target_id=ContentType.objects.get(app_label='saml', model='libertyprovider').pk,
) )
role.permissions.add(perm_saml) role.permissions.add(perm_saml)
perm_role = Permission.objects.create( perm_role = Permission.objects.create(

View File

@ -595,7 +595,7 @@ def test_sso(app, caplog, code, oidc_provider, oidc_provider_jwkset, hooks):
) )
utils.assert_event( utils.assert_event(
'user.login.failure', 'user.login.failure',
reason="auth_oidc: error received some_other_error (prompt: whatever)", reason='auth_oidc: error received some_other_error (prompt: whatever)',
) )
assert len(hooks.auth_oidc_backend_modify_user) == 0 assert len(hooks.auth_oidc_backend_modify_user) == 0
with utils.check_log(caplog, 'created user'): with utils.check_log(caplog, 'created user'):

View File

@ -56,7 +56,7 @@ def test_change_phone(app, nomail_user, user_ou1, phone_activated_authn, setting
path='/accounts/change-phone/', path='/accounts/change-phone/',
password=nomail_user.username, password=nomail_user.username,
) )
assert "Your current phone number is +33122446688." in resp.text assert 'Your current phone number is +33122446688.' in resp.text
resp.form.set('phone_1', '122446666') resp.form.set('phone_1', '122446666')
resp.form.set('password', nomail_user.username) resp.form.set('password', nomail_user.username)
@ -99,7 +99,7 @@ def test_change_phone_nondefault_attribute(app, nomail_user, user_ou1, phone_act
path='/accounts/change-phone/', path='/accounts/change-phone/',
password=nomail_user.username, password=nomail_user.username,
) )
assert "Your current phone number is +33122444444." in resp.text assert 'Your current phone number is +33122444444.' in resp.text
resp.form.set('phone_1', '122666666') resp.form.set('phone_1', '122666666')
resp.form.set('password', nomail_user.username) resp.form.set('password', nomail_user.username)
@ -238,7 +238,7 @@ def test_change_phone_identifier_attribute_changed(
path='/accounts/change-phone/', path='/accounts/change-phone/',
password=nomail_user.username, password=nomail_user.username,
) )
assert "Your current phone number is +33122446688." in resp.text assert 'Your current phone number is +33122446688.' in resp.text
resp.form.set('phone_1', '122446666') resp.form.set('phone_1', '122446666')
resp.form.set('password', nomail_user.username) resp.form.set('password', nomail_user.username)
@ -274,7 +274,7 @@ def test_change_phone_authn_deactivated(app, nomail_user, user_ou1, phone_activa
phone_activated_authn.save() phone_activated_authn.save()
resp = app.get('/accounts/change-phone/') resp = app.get('/accounts/change-phone/')
assert "Your current phone number is +33122446688." in resp.text assert 'Your current phone number is +33122446688.' in resp.text
resp.form.set('phone_1', '122446666') resp.form.set('phone_1', '122446666')
resp.form.set('password', nomail_user.username) resp.form.set('password', nomail_user.username)

View File

@ -466,7 +466,7 @@ def test_clean_unused_account_always_alert(db, simple_user, mailoutbox, freezer)
assert len(mailoutbox) == 1 assert len(mailoutbox) == 1
@pytest.mark.parametrize("deletion_delay", [730, 500, 65]) @pytest.mark.parametrize('deletion_delay', [730, 500, 65])
def test_clean_unused_account_displayed_message(simple_user, mailoutbox, deletion_delay): def test_clean_unused_account_displayed_message(simple_user, mailoutbox, deletion_delay):
simple_user.ou.clean_unused_accounts_alert = deletion_delay - 30 simple_user.ou.clean_unused_accounts_alert = deletion_delay - 30
simple_user.ou.clean_unused_accounts_deletion = deletion_delay simple_user.ou.clean_unused_accounts_deletion = deletion_delay

View File

@ -323,7 +323,7 @@ def test_role_deserializer_parenting_non_existing_parent(db):
with pytest.raises(ValidationError) as excinfo: with pytest.raises(ValidationError) as excinfo:
rd.parentings() rd.parentings()
assert "Could not find parent role" in str(excinfo.value) assert 'Could not find parent role' in str(excinfo.value)
def test_role_deserializer_emails(db): def test_role_deserializer_emails(db):
@ -348,14 +348,14 @@ def test_role_deserializer_permissions(db):
other_role_dict = {'name': 'other role', 'slug': 'other-role-slug', 'uuid': get_hex_uuid(), 'ou': ou} other_role_dict = {'name': 'other role', 'slug': 'other-role-slug', 'uuid': get_hex_uuid(), 'ou': ou}
other_role = Role.objects.create(**other_role_dict) other_role = Role.objects.create(**other_role_dict)
other_role_dict['permisison'] = { other_role_dict['permisison'] = {
"operation": {"slug": "admin"}, 'operation': {'slug': 'admin'},
"ou": {"slug": "default", "name": "Collectivit\u00e9 par d\u00e9faut"}, 'ou': {'slug': 'default', 'name': 'Collectivit\u00e9 par d\u00e9faut'},
'target_ct': {'app_label': 'a2_rbac', 'model': 'role'}, 'target_ct': {'app_label': 'a2_rbac', 'model': 'role'},
"target": { 'target': {
"slug": "role-deux", 'slug': 'role-deux',
"ou": {"slug": "default", "name": "Collectivit\u00e9 par d\u00e9faut"}, 'ou': {'slug': 'default', 'name': 'Collectivit\u00e9 par d\u00e9faut'},
"service": None, 'service': None,
"name": "role deux", 'name': 'role deux',
}, },
} }
some_role_dict = { some_role_dict = {
@ -370,7 +370,7 @@ def test_role_deserializer_permissions(db):
'operation': {'slug': 'add'}, 'operation': {'slug': 'add'},
'ou': None, 'ou': None,
'target_ct': {'app_label': 'a2_rbac', 'model': 'role'}, 'target_ct': {'app_label': 'a2_rbac', 'model': 'role'},
'target': {"slug": 'other-role-slug', 'ou': {'slug': 'some-ou'}, 'service': None}, 'target': {'slug': 'other-role-slug', 'ou': {'slug': 'some-ou'}, 'service': None},
} }
] ]
@ -405,14 +405,14 @@ def test_permission_on_role(db):
some_role_dict = {'name': 'some role', 'slug': 'some-role-slug', 'ou': None, 'service': None} some_role_dict = {'name': 'some role', 'slug': 'some-role-slug', 'ou': None, 'service': None}
some_role_dict['permissions'] = [ some_role_dict['permissions'] = [
{ {
"operation": {"slug": "admin"}, 'operation': {'slug': 'admin'},
"ou": {"slug": "perm-ou", "name": "perm-ou"}, 'ou': {'slug': 'perm-ou', 'name': 'perm-ou'},
'target_ct': {'app_label': 'a2_rbac', 'model': 'role'}, 'target_ct': {'app_label': 'a2_rbac', 'model': 'role'},
"target": { 'target': {
"slug": "perm-role", 'slug': 'perm-role',
"ou": {"slug": "perm-ou", "name": "perm ou"}, 'ou': {'slug': 'perm-ou', 'name': 'perm ou'},
"service": None, 'service': None,
"name": "perm role", 'name': 'perm role',
}, },
} }
] ]
@ -433,10 +433,10 @@ def test_permission_on_contentype(db):
some_role_dict = {'name': 'some role', 'slug': 'some-role-slug', 'ou': None, 'service': None} some_role_dict = {'name': 'some role', 'slug': 'some-role-slug', 'ou': None, 'service': None}
some_role_dict['permissions'] = [ some_role_dict['permissions'] = [
{ {
"operation": {"slug": "admin"}, 'operation': {'slug': 'admin'},
"ou": {"slug": "perm-ou", "name": "perm-ou"}, 'ou': {'slug': 'perm-ou', 'name': 'perm-ou'},
'target_ct': {"model": "contenttype", "app_label": "contenttypes"}, 'target_ct': {'model': 'contenttype', 'app_label': 'contenttypes'},
"target": {"model": "logentry", "app_label": "admin"}, 'target': {'model': 'logentry', 'app_label': 'admin'},
} }
] ]

View File

@ -82,9 +82,9 @@ def test_import_site_cmd_infos_on_stdout(db, monkeypatch, capsys, json_fixture):
management.call_command('import_site', json_fixture(content)) management.call_command('import_site', json_fixture(content))
out, dummy = capsys.readouterr() out, dummy = capsys.readouterr()
assert "Real run" in out assert 'Real run' in out
assert "1 roles created" in out assert '1 roles created' in out
assert "0 roles updated" in out assert '0 roles updated' in out
def test_import_site_transaction_rollback_on_error(db, monkeypatch, capsys, json_fixture): def test_import_site_transaction_rollback_on_error(db, monkeypatch, capsys, json_fixture):

View File

@ -63,15 +63,15 @@ OBJECTGUID_B64 = base64.b64encode(OBJECTGUID_RAW).decode()
CN_INCOMPLETE = 'Jean Dupond' CN_INCOMPLETE = 'Jean Dupond'
DN_INCOMPLETE = 'cn=%s,o=ôrga' % escape_dn_chars(CN_INCOMPLETE) DN_INCOMPLETE = 'cn=%s,o=ôrga' % escape_dn_chars(CN_INCOMPLETE)
EO_O = "EO" EO_O = 'EO'
EO_STREET = "169 rue du Chateau" EO_STREET = '169 rue du Chateau'
EO_POSTALCODE = "75014" EO_POSTALCODE = '75014'
EO_CITY = "PARIS" EO_CITY = 'PARIS'
EE_O = "EE" EE_O = 'EE'
EE_STREET = "44 rue de l'Ouest" EE_STREET = "44 rue de l'Ouest"
EE_POSTALCODE = "75014" EE_POSTALCODE = '75014'
EE_CITY = "PARIS" EE_CITY = 'PARIS'
base_dir = os.path.dirname(__file__) base_dir = os.path.dirname(__file__)
key_file = os.path.join(base_dir, 'key.pem') key_file = os.path.join(base_dir, 'key.pem')
@ -1521,7 +1521,7 @@ pwdSafeModify: FALSE
for _ in range(pwdMaxFailure): for _ in range(pwdMaxFailure):
assert authenticate(username=USERNAME, password='incorrect') is None assert authenticate(username=USERNAME, password='incorrect') is None
assert "failed to login" in caplog.text assert 'failed to login' in caplog.text
def test_authenticate_ppolicy_pwdMaxFailure(slapd_ppolicy, settings, db, caplog): def test_authenticate_ppolicy_pwdMaxFailure(slapd_ppolicy, settings, db, caplog):
@ -2197,19 +2197,19 @@ def test_config_to_lowercase(db):
del config_normalized[key] del config_normalized[key]
assert config_normalized == { assert config_normalized == {
"fname_field": "givenname", 'fname_field': 'givenname',
"lname_field": "surname", 'lname_field': 'surname',
"email_field": "email", 'email_field': 'email',
"attributes": ["zob", "coin"], 'attributes': ['zob', 'coin'],
"mandatory_attributes_values": {"xxx": ["A"]}, 'mandatory_attributes_values': {'xxx': ['A']},
"member_of_attribute": "memberof", 'member_of_attribute': 'memberof',
"group_mapping": [["cn=coin,ou=groups,dc=coin,dc=fr", ["Group 1"]]], 'group_mapping': [['cn=coin,ou=groups,dc=coin,dc=fr', ['Group 1']]],
"group_to_role_mapping": [["cn=coin,ou=groups,dc=coin,dc=fr", ["Group 1"]]], 'group_to_role_mapping': [['cn=coin,ou=groups,dc=coin,dc=fr', ['Group 1']]],
"attribute_mappings": [ 'attribute_mappings': [
["xxx", "yyy"], ['xxx', 'yyy'],
], ],
"external_id_tuples": [ 'external_id_tuples': [
["a", "b", "c"], ['a', 'b', 'c'],
], ],
'user_attributes': [ 'user_attributes': [
{ {

View File

@ -580,7 +580,7 @@ def test_password_authenticator_data_migration(migration, settings):
LoginPasswordAuthenticator = old_apps.get_model(app, 'LoginPasswordAuthenticator') LoginPasswordAuthenticator = old_apps.get_model(app, 'LoginPasswordAuthenticator')
settings.AUTH_FRONTENDS_KWARGS = { settings.AUTH_FRONTENDS_KWARGS = {
"password": {"priority": -1, "show_condition": "'backoffice' not in login_hint"} 'password': {'priority': -1, 'show_condition': "'backoffice' not in login_hint"}
} }
settings.A2_LOGIN_FORM_OU_SELECTOR = True settings.A2_LOGIN_FORM_OU_SELECTOR = True
settings.A2_AUTH_PASSWORD_ENABLE = False settings.A2_AUTH_PASSWORD_ENABLE = False

View File

@ -838,18 +838,18 @@ def test_manager_site_import(app, db, superuser):
site_export = { site_export = {
'roles': [ 'roles': [
{ {
"description": "", 'description': '',
"service": None, 'service': None,
"name": "basic", 'name': 'basic',
"attributes": [], 'attributes': [],
"ou": { 'ou': {
"slug": "default", 'slug': 'default',
"uuid": "ba60d9e6c2874636883bdd604b23eab2", 'uuid': 'ba60d9e6c2874636883bdd604b23eab2',
"name": "Collectivit\u00e9 par d\u00e9faut", 'name': 'Collectivit\u00e9 par d\u00e9faut',
}, },
"external_id": "", 'external_id': '',
"slug": "basic", 'slug': 'basic',
"uuid": "6eb7bbf64bf547119120f925f0e560ac", 'uuid': '6eb7bbf64bf547119120f925f0e560ac',
} }
] ]
} }
@ -867,14 +867,14 @@ def test_manager_site_import_error(app, db, superuser):
site_export = { site_export = {
'roles': [ 'roles': [
{ {
"description": "", 'description': '',
"service": None, 'service': None,
"name": "basic", 'name': 'basic',
"attributes": [], 'attributes': [],
"ou": {"slug": "unkown-ou", "uuid": "ba60d9e6c2874636883bdd604b23eab2", "name": "unkown ou"}, 'ou': {'slug': 'unkown-ou', 'uuid': 'ba60d9e6c2874636883bdd604b23eab2', 'name': 'unkown ou'},
"external_id": "", 'external_id': '',
"slug": "basic", 'slug': 'basic',
"uuid": "6eb7bbf64bf547119120f925f0e560ac", 'uuid': '6eb7bbf64bf547119120f925f0e560ac',
} }
] ]
} }

View File

@ -277,7 +277,7 @@ def test_edit(superuser, app, ou1, ou2):
response = form.submit() response = form.submit()
assert ( assert (
response.pyquery('.error').text() response.pyquery('.error').text()
== "The following roles do not belong to organizational unit OU2: role-1, role-3." == 'The following roles do not belong to organizational unit OU2: role-1, role-3.'
) )
response.form.set('ou', ou2.id) response.form.set('ou', ou2.id)
response.form['apiclient_roles'].force_value([]) response.form['apiclient_roles'].force_value([])

View File

@ -100,20 +100,20 @@ def test_authenticators_password(app, superuser_or_admin, settings):
resp.form['show_condition'] = '}' resp.form['show_condition'] = '}'
resp = resp.form.submit() resp = resp.form.submit()
assert "could not parse expression: unmatched" in resp.text assert 'could not parse expression: unmatched' in resp.text
resp.form['show_condition'] = "'backoffice' in login_hint or remote_addr == '1.2.3.4'" resp.form['show_condition'] = "'backoffice' in login_hint or remote_addr == '1.2.3.4'"
resp = resp.form.submit().follow() resp = resp.form.submit().follow()
assert 'Click "Edit" to change configuration.' not in resp.text assert 'Click "Edit" to change configuration.' not in resp.text
if DJ_VERSION[0] <= 2: if DJ_VERSION[0] <= 2:
assert ( assert (
"Show condition: &#39;backoffice&#39; in login_hint or remote_addr == &#39;1.2.3.4&#39;" 'Show condition: &#39;backoffice&#39; in login_hint or remote_addr == &#39;1.2.3.4&#39;'
in resp.text in resp.text
) )
else: else:
# html-rendered quote characters change in django 3 onwards… # html-rendered quote characters change in django 3 onwards…
assert ( assert (
"Show condition: &#x27;backoffice&#x27; in login_hint or remote_addr == &#x27;1.2.3.4&#x27;" 'Show condition: &#x27;backoffice&#x27; in login_hint or remote_addr == &#x27;1.2.3.4&#x27;'
in resp.text in resp.text
) )
assert_event('authenticator.edit', user=superuser_or_admin, session=app.session) assert_event('authenticator.edit', user=superuser_or_admin, session=app.session)
@ -621,7 +621,7 @@ def test_authenticators_saml(app, superuser, ou1, ou2):
authenticator.refresh_from_db() authenticator.refresh_from_db()
assert authenticator.attribute_mapping == [ assert authenticator.attribute_mapping == [
{"attribute": "email", "saml_attribute": "mail", "mandatory": False} {'attribute': 'email', 'saml_attribute': 'mail', 'mandatory': False}
] ]
resp = resp.click('Edit') resp = resp.click('Edit')

View File

@ -45,24 +45,24 @@ def test_journal_authorization(app, db, simple_user, admin):
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def events(db, superuser, freezer): def events(db, superuser, freezer):
session1 = Session(session_key="1234") session1 = Session(session_key='1234')
session2 = Session(session_key="abcd") session2 = Session(session_key='abcd')
ou = get_default_ou() ou = get_default_ou()
user = User.objects.create( user = User.objects.create(
username="user", email="user@example.com", ou=ou, uuid="1" * 32, first_name='Johnny', last_name='doe' username='user', email='user@example.com', ou=ou, uuid='1' * 32, first_name='Johnny', last_name='doe'
) )
profile_type = ProfileType.objects.create(name='One Type', slug='one-type') profile_type = ProfileType.objects.create(name='One Type', slug='one-type')
profile = Profile.objects.create(user=user, profile_type=profile_type, identifier='aaa') profile = Profile.objects.create(user=user, profile_type=profile_type, identifier='aaa')
agent = User.objects.create(username="agent", email="agent@example.com", ou=ou, uuid="2" * 32) agent = User.objects.create(username='agent', email='agent@example.com', ou=ou, uuid='2' * 32)
role_user = Role.objects.create(name="role1", ou=ou) role_user = Role.objects.create(name='role1', ou=ou)
role_agent = Role.objects.create(name="role2", ou=ou) role_agent = Role.objects.create(name='role2', ou=ou)
service = Service.objects.create(name="service") service = Service.objects.create(name='service')
authenticator = LoginPasswordAuthenticator.objects.create(slug='test') authenticator = LoginPasswordAuthenticator.objects.create(slug='test')
saml_authenticator = SAMLAuthenticator.objects.create(slug='saml') saml_authenticator = SAMLAuthenticator.objects.create(slug='saml')
set_attribute_action = SetAttributeAction.objects.create(authenticator=saml_authenticator) set_attribute_action = SetAttributeAction.objects.create(authenticator=saml_authenticator)
deleted_user = User.objects.create(username="deleted", email="deleted@example.com", ou=ou, uuid="3" * 32) deleted_user = User.objects.create(username='deleted', email='deleted@example.com', ou=ou, uuid='3' * 32)
class EventFactory: class EventFactory:
date = make_aware(datetime.datetime(2020, 1, 1)) date = make_aware(datetime.datetime(2020, 1, 1))
@ -70,133 +70,133 @@ def events(db, superuser, freezer):
def __call__(self, name, **kwargs): def __call__(self, name, **kwargs):
freezer.move_to(self.date) freezer.move_to(self.date)
journal.record(name, **kwargs) journal.record(name, **kwargs)
assert Event.objects.latest("timestamp").type.name == name assert Event.objects.latest('timestamp').type.name == name
self.date += datetime.timedelta(hours=1) self.date += datetime.timedelta(hours=1)
make = EventFactory() make = EventFactory()
make("user.registration.request", email=user.email) make('user.registration.request', email=user.email)
make( make(
"user.registration", 'user.registration',
user=user, user=user,
session=session1, session=session1,
service=service, service=service,
how="france-connect", how='france-connect',
) )
make("user.logout", user=user, session=session1) make('user.logout', user=user, session=session1)
make("user.login.failure", service=service, authenticator=saml_authenticator, username="user") make('user.login.failure', service=service, authenticator=saml_authenticator, username='user')
make("user.login.failure", authenticator=saml_authenticator, username="agent") make('user.login.failure', authenticator=saml_authenticator, username='agent')
make("user.login", user=user, session=session1, how="password") make('user.login', user=user, session=session1, how='password')
make("user.password.change", user=user, session=session1) make('user.password.change', user=user, session=session1)
edit_profile_form = mock.Mock(spec=["instance", "initial", "changed_data", "cleaned_data"]) edit_profile_form = mock.Mock(spec=['instance', 'initial', 'changed_data', 'cleaned_data'])
edit_profile_form.initial = {'email': "user@example.com", 'first_name': "John"} edit_profile_form.initial = {'email': 'user@example.com', 'first_name': 'John'}
edit_profile_form.changed_data = ["first_name"] edit_profile_form.changed_data = ['first_name']
edit_profile_form.cleaned_data = {'first_name': "Jane"} edit_profile_form.cleaned_data = {'first_name': 'Jane'}
make("user.profile.edit", user=user, session=session1, form=edit_profile_form) make('user.profile.edit', user=user, session=session1, form=edit_profile_form)
make("user.service.sso.authorization", user=user, session=session1, service=service) make('user.service.sso.authorization', user=user, session=session1, service=service)
make("user.service.sso", user=user, session=session1, service=service, how="password") make('user.service.sso', user=user, session=session1, service=service, how='password')
make("user.service.sso.unauthorization", user=user, session=session1, service=service) make('user.service.sso.unauthorization', user=user, session=session1, service=service)
make("user.deletion", user=user, session=session1, service=service) make('user.deletion', user=user, session=session1, service=service)
make("user.password.reset.request", email="USER@example.com", user=user) make('user.password.reset.request', email='USER@example.com', user=user)
make("user.password.reset.failure", email="USER@example.com") make('user.password.reset.failure', email='USER@example.com')
make("user.password.reset", user=user) make('user.password.reset', user=user)
make("user.login", user=agent, session=session2, how="saml") make('user.login', user=agent, session=session2, how='saml')
create_form = mock.Mock(spec=["instance"]) create_form = mock.Mock(spec=['instance'])
create_form.instance = user create_form.instance = user
make("manager.user.creation", user=agent, session=session2, form=create_form) make('manager.user.creation', user=agent, session=session2, form=create_form)
edit_form = mock.Mock(spec=["instance", "initial", "changed_data", "cleaned_data"]) edit_form = mock.Mock(spec=['instance', 'initial', 'changed_data', 'cleaned_data'])
edit_form.instance = user edit_form.instance = user
edit_form.initial = {'email': "user@example.com", 'first_name': "John"} edit_form.initial = {'email': 'user@example.com', 'first_name': 'John'}
edit_form.changed_data = ["first_name"] edit_form.changed_data = ['first_name']
edit_form.cleaned_data = {'first_name': "Jane"} edit_form.cleaned_data = {'first_name': 'Jane'}
make("manager.user.profile.edit", user=agent, session=session2, form=edit_form) make('manager.user.profile.edit', user=agent, session=session2, form=edit_form)
change_email_form = mock.Mock(spec=["instance", "cleaned_data"]) change_email_form = mock.Mock(spec=['instance', 'cleaned_data'])
change_email_form.instance = user change_email_form.instance = user
change_email_form.cleaned_data = {'new_email': "jane@example.com"} change_email_form.cleaned_data = {'new_email': 'jane@example.com'}
make( make(
"manager.user.email.change.request", 'manager.user.email.change.request',
user=agent, user=agent,
session=session2, session=session2,
form=change_email_form, form=change_email_form,
) )
password_change_form = mock.Mock(spec=["instance", "cleaned_data"]) password_change_form = mock.Mock(spec=['instance', 'cleaned_data'])
password_change_form.instance = user password_change_form.instance = user
password_change_form.cleaned_data = {'generate_password': False, 'send_mail': False} password_change_form.cleaned_data = {'generate_password': False, 'send_mail': False}
make( make(
"manager.user.password.change", 'manager.user.password.change',
user=agent, user=agent,
session=session2, session=session2,
form=password_change_form, form=password_change_form,
) )
password_change_form.cleaned_data["send_mail"] = True password_change_form.cleaned_data['send_mail'] = True
make( make(
"manager.user.password.change", 'manager.user.password.change',
user=agent, user=agent,
session=session2, session=session2,
form=password_change_form, form=password_change_form,
) )
make( make(
"manager.user.password.reset.request", 'manager.user.password.reset.request',
user=agent, user=agent,
session=session2, session=session2,
target_user=user, target_user=user,
) )
make( make(
"manager.user.password.change.force", 'manager.user.password.change.force',
user=agent, user=agent,
session=session2, session=session2,
target_user=user, target_user=user,
) )
make( make(
"manager.user.password.change.unforce", 'manager.user.password.change.unforce',
user=agent, user=agent,
session=session2, session=session2,
target_user=user, target_user=user,
) )
make("manager.user.activation", user=agent, session=session2, target_user=user) make('manager.user.activation', user=agent, session=session2, target_user=user)
make("manager.user.deactivation", user=agent, session=session2, target_user=user) make('manager.user.deactivation', user=agent, session=session2, target_user=user)
make("manager.user.deletion", user=agent, session=session2, target_user=user) make('manager.user.deletion', user=agent, session=session2, target_user=user)
make( make(
"manager.user.sso.authorization.deletion", 'manager.user.sso.authorization.deletion',
user=agent, user=agent,
session=session2, session=session2,
service=service, service=service,
target_user=user, target_user=user,
) )
make("manager.role.creation", user=agent, session=session2, role=role_user) make('manager.role.creation', user=agent, session=session2, role=role_user)
role_edit_form = mock.Mock(spec=["instance", "initial", "changed_data", "cleaned_data"]) role_edit_form = mock.Mock(spec=['instance', 'initial', 'changed_data', 'cleaned_data'])
role_edit_form.instance = role_user role_edit_form.instance = role_user
role_edit_form.initial = {'name': role_user.name} role_edit_form.initial = {'name': role_user.name}
role_edit_form.changed_data = ["name"] role_edit_form.changed_data = ['name']
role_edit_form.cleaned_data = {'name': "changed role name"} role_edit_form.cleaned_data = {'name': 'changed role name'}
make( make(
"manager.role.edit", 'manager.role.edit',
user=agent, user=agent,
session=session2, session=session2,
role=role_user, role=role_user,
form=role_edit_form, form=role_edit_form,
) )
make("manager.role.deletion", user=agent, session=session2, role=role_user) make('manager.role.deletion', user=agent, session=session2, role=role_user)
make( make(
"manager.role.membership.grant", 'manager.role.membership.grant',
user=agent, user=agent,
session=session2, session=session2,
role=role_user, role=role_user,
member=user, member=user,
) )
make( make(
"manager.role.membership.removal", 'manager.role.membership.removal',
user=agent, user=agent,
session=session2, session=session2,
role=role_user, role=role_user,
@ -204,14 +204,14 @@ def events(db, superuser, freezer):
) )
make( make(
"manager.role.inheritance.addition", 'manager.role.inheritance.addition',
user=agent, user=agent,
session=session2, session=session2,
parent=role_agent, parent=role_agent,
child=role_user, child=role_user,
) )
make( make(
"manager.role.inheritance.removal", 'manager.role.inheritance.removal',
user=agent, user=agent,
session=session2, session=session2,
parent=role_agent, parent=role_agent,
@ -219,14 +219,14 @@ def events(db, superuser, freezer):
) )
make( make(
"manager.role.administrator.role.addition", 'manager.role.administrator.role.addition',
user=agent, user=agent,
session=session2, session=session2,
role=role_user, role=role_user,
admin_role=role_agent, admin_role=role_agent,
) )
make( make(
"manager.role.administrator.role.removal", 'manager.role.administrator.role.removal',
user=agent, user=agent,
session=session2, session=session2,
role=role_user, role=role_user,
@ -234,14 +234,14 @@ def events(db, superuser, freezer):
) )
make( make(
"manager.role.administrator.user.addition", 'manager.role.administrator.user.addition',
user=agent, user=agent,
session=session2, session=session2,
role=role_user, role=role_user,
admin_user=user, admin_user=user,
) )
make( make(
"manager.role.administrator.user.removal", 'manager.role.administrator.user.removal',
user=agent, user=agent,
session=session2, session=session2,
role=role_user, role=role_user,
@ -290,8 +290,8 @@ def events(db, superuser, freezer):
reason='ldap-reactivation', reason='ldap-reactivation',
) )
make("user.service.sso.refusal", user=user, session=session1, service=service) make('user.service.sso.refusal', user=user, session=session1, service=service)
make("user.service.sso.denial", user=user, session=session1, service=service) make('user.service.sso.denial', user=user, session=session1, service=service)
make( make(
'user.profile.add', 'user.profile.add',
@ -341,11 +341,11 @@ def events(db, superuser, freezer):
make('user.notification.activity', actor=service, target_user=user) make('user.notification.activity', actor=service, target_user=user)
make('user.notification.activity', actor=superuser, target_user=user) make('user.notification.activity', actor=superuser, target_user=user)
make("user.password.reset", user=deleted_user) make('user.password.reset', user=deleted_user)
deleted_user.delete() deleted_user.delete()
# verify we created at least one event for each type # verify we created at least one event for each type
assert set(Event.objects.values_list("type__name", flat=True)) == set(_registry) assert set(Event.objects.values_list('type__name', flat=True)) == set(_registry)
return locals() return locals()
@ -354,23 +354,23 @@ def extract_journal(response):
rows = [] rows = []
seen_event_ids = set() seen_event_ids = set()
while True: while True:
for tr in response.pyquery("tr[data-event-type]"): for tr in response.pyquery('tr[data-event-type]'):
# page can overlap when they contain less than 20 items (to prevent orphan rows) # page can overlap when they contain less than 20 items (to prevent orphan rows)
event_id = tr.attrib["data-event-id"] event_id = tr.attrib['data-event-id']
if event_id not in seen_event_ids: if event_id not in seen_event_ids:
rows.append(response.pyquery(tr)) rows.append(response.pyquery(tr))
seen_event_ids.add(event_id) seen_event_ids.add(event_id)
if "Previous page" not in response: if 'Previous page' not in response:
break break
response = response.click("Previous page", index=0) response = response.click('Previous page', index=0)
rows.reverse() rows.reverse()
content = [ content = [
{ {
'timestamp': text_content(row.find(".journal-list--timestamp-column")[0]).strip(), 'timestamp': text_content(row.find('.journal-list--timestamp-column')[0]).strip(),
'type': row[0].attrib["data-event-type"], 'type': row[0].attrib['data-event-type'],
'user': text_content(row.find(".journal-list--user-column")[0]).strip(), 'user': text_content(row.find('.journal-list--user-column')[0]).strip(),
'message': text_content(row.find(".journal-list--message-column")[0]), 'message': text_content(row.find('.journal-list--message-column')[0]),
} }
for row in rows for row in rows
] ]
@ -378,7 +378,7 @@ def extract_journal(response):
def test_global_journal(app, superuser, events): def test_global_journal(app, superuser, events):
response = login(app, user=superuser, path="/manage/") response = login(app, user=superuser, path='/manage/')
set_attribute_action = SetAttributeAction.objects.get() set_attribute_action = SetAttributeAction.objects.get()
# remove event about admin login # remove event about admin login
@ -387,7 +387,7 @@ def test_global_journal(app, superuser, events):
# get deleted user # get deleted user
deleted_user = DeletedUser.objects.all().first() deleted_user = DeletedUser.objects.all().first()
response = response.click("Global journal") response = response.click('Global journal')
content = extract_journal(response) content = extract_journal(response)
@ -801,10 +801,10 @@ def test_global_journal(app, superuser, events):
def test_user_journal(app, superuser, events): def test_user_journal(app, superuser, events):
response = login(app, user=superuser, path="/manage/") response = login(app, user=superuser, path='/manage/')
user = User.objects.get(username="user") user = User.objects.get(username='user')
response = app.get("/manage/users/%s/journal/" % user.id) response = app.get('/manage/users/%s/journal/' % user.id)
content = extract_journal(response) content = extract_journal(response)
assert content == [ assert content == [
@ -1054,11 +1054,11 @@ def test_user_journal(app, superuser, events):
def test_role_journal(app, superuser, events): def test_role_journal(app, superuser, events):
response = login(app, user=superuser, path="/manage/") response = login(app, user=superuser, path='/manage/')
role1 = Role.objects.get(name="role1") role1 = Role.objects.get(name='role1')
role2 = Role.objects.get(name="role2") role2 = Role.objects.get(name='role2')
response = app.get("/manage/roles/%s/journal/" % role1.id) response = app.get('/manage/roles/%s/journal/' % role1.id)
content = extract_journal(response) content = extract_journal(response)
assert content == [ assert content == [
@ -1130,7 +1130,7 @@ def test_role_journal(app, superuser, events):
}, },
] ]
response = app.get("/manage/roles/%s/journal/" % role2.id) response = app.get('/manage/roles/%s/journal/' % role2.id)
content = extract_journal(response) content = extract_journal(response)
assert content == [ assert content == [
@ -1239,7 +1239,7 @@ def test_roles_journal(app, superuser, events):
def test_date_navigation(app, superuser, events): def test_date_navigation(app, superuser, events):
response = login(app, user=superuser, path="/manage/journal/") response = login(app, user=superuser, path='/manage/journal/')
response = response.click('2020') response = response.click('2020')
assert not response.context['form'].errors assert not response.context['form'].errors
@ -1255,7 +1255,7 @@ def test_date_navigation(app, superuser, events):
def test_search(app, superuser, events): def test_search(app, superuser, events):
response = login(app, user=superuser, path="/manage/journal/") response = login(app, user=superuser, path='/manage/journal/')
response.form.set('search', 'event:registration') response.form.set('search', 'event:registration')
response = response.form.submit() response = response.form.submit()
assert len(response.pyquery('tbody tr')) == 2 assert len(response.pyquery('tbody tr')) == 2
@ -1376,7 +1376,7 @@ def test_search(app, superuser, events):
def test_search_empty(app, superuser, events): def test_search_empty(app, superuser, events):
response = login(app, user=superuser, path="/manage/journal/") response = login(app, user=superuser, path='/manage/journal/')
response.form.set('search', 'abcd123') response.form.set('search', 'abcd123')
response = response.form.submit() response = response.form.submit()
assert 'No event found.' in response.text assert 'No event found.' in response.text
@ -1389,7 +1389,7 @@ def test_search_empty(app, superuser, events):
def test_delete_user(app, superuser, events): def test_delete_user(app, superuser, events):
old_user_id = events['user'].id old_user_id = events['user'].id
events['user'].delete() events['user'].delete()
response = login(app, user=superuser, path="/manage/journal/") response = login(app, user=superuser, path='/manage/journal/')
response.form.set('search', events['user'].email) response.form.set('search', events['user'].email)
response = response.form.submit() response = response.form.submit()
assert len(response.pyquery('tbody tr')) == 20 assert len(response.pyquery('tbody tr')) == 20
@ -1397,7 +1397,7 @@ def test_delete_user(app, superuser, events):
def test_event_type_list(app, superuser, events): def test_event_type_list(app, superuser, events):
response = login(app, user=superuser, path="/manage/journal/") response = login(app, user=superuser, path='/manage/journal/')
response = response.click('View available event types') response = response.click('View available event types')
for e in Event.objects.all(): for e in Event.objects.all():
@ -1406,7 +1406,7 @@ def test_event_type_list(app, superuser, events):
def test_delete_authenticator(app, superuser, events): def test_delete_authenticator(app, superuser, events):
events['authenticator'].delete() events['authenticator'].delete()
response = login(app, superuser, path="/manage/journal/") response = login(app, superuser, path='/manage/journal/')
response.form.set('search', 'event:authenticator.creation') response.form.set('search', 'event:authenticator.creation')
response = response.form.submit() response = response.form.submit()
assert len(response.pyquery('tbody tr')) == 1 assert len(response.pyquery('tbody tr')) == 1

View File

@ -72,16 +72,16 @@ def test_manager_ou_import(app, admin, ou1, role_ou1, ou2, role_ou2):
# in case roles are present in export file, they must not be imported # in case roles are present in export file, they must not be imported
export['roles'] = [ export['roles'] = [
{ {
"uuid": "27255f404cb140df9a577da76b59f285", 'uuid': '27255f404cb140df9a577da76b59f285',
"slug": "should_not_exist", 'slug': 'should_not_exist',
"name": "should_not_exist", 'name': 'should_not_exist',
} }
] ]
resp = resp.click('Import') resp = resp.click('Import')
resp.form['site_json'] = Upload('export.json', json.dumps(export).encode(), 'application/json') resp.form['site_json'] = Upload('export.json', json.dumps(export).encode(), 'application/json')
resp = resp.form.submit().follow() resp = resp.form.submit().follow()
assert not Role.objects.filter(slug="should_not_exist").exists() assert not Role.objects.filter(slug='should_not_exist').exists()
def test_ou_edit_form_local_options_overriden(app, admin, ou1, settings): def test_ou_edit_form_local_options_overriden(app, admin, ou1, settings):
@ -92,13 +92,13 @@ def test_ou_edit_form_local_options_overriden(app, admin, ou1, settings):
response = app.get('/manage/organizational-units/%s/edit/' % ou1.pk) response = app.get('/manage/organizational-units/%s/edit/' % ou1.pk)
assert 'disabled' not in response.pyquery("input#id_email_is_unique")[0].attrib assert 'disabled' not in response.pyquery('input#id_email_is_unique')[0].attrib
assert response.pyquery("input#id_username_is_unique")[0].attrib['disabled'] assert response.pyquery('input#id_username_is_unique')[0].attrib['disabled']
settings.A2_EMAIL_IS_UNIQUE = True settings.A2_EMAIL_IS_UNIQUE = True
settings.A2_USERNAME_IS_UNIQUE = False settings.A2_USERNAME_IS_UNIQUE = False
response = app.get('/manage/organizational-units/%s/edit/' % ou1.pk) response = app.get('/manage/organizational-units/%s/edit/' % ou1.pk)
assert response.pyquery("input#id_email_is_unique")[0].attrib['disabled'] assert response.pyquery('input#id_email_is_unique')[0].attrib['disabled']
assert 'disabled' not in response.pyquery("input#id_username_is_unique")[0].attrib assert 'disabled' not in response.pyquery('input#id_username_is_unique')[0].attrib

View File

@ -95,8 +95,8 @@ def test_send_password_reset_by_sms_code(app, nomail_user, settings, phone_activ
assert body['message'].startswith('Your code is') assert body['message'].startswith('Your code is')
code = SMSCode.objects.get() code = SMSCode.objects.get()
assert body['message'][-code_length:] == code.value assert body['message'][-code_length:] == code.value
assert ("Your code is valid for the next %s minute" % (SMSCode.CODE_DURATION // 60)) in resp.text assert ('Your code is valid for the next %s minute' % (SMSCode.CODE_DURATION // 60)) in resp.text
assert "The code you received by SMS." in resp.text assert 'The code you received by SMS.' in resp.text
resp.form.set('sms_code', code.value) resp.form.set('sms_code', code.value)
resp = resp.form.submit().follow() resp = resp.form.submit().follow()
assert Token.objects.count() == 1 assert Token.objects.count() == 1
@ -199,7 +199,7 @@ def test_send_password_reset_by_sms_code_next_url(app, nomail_user, settings, ph
assert user == nomail_user assert user == nomail_user
assert resp.location == '/accounts/consents/' assert resp.location == '/accounts/consents/'
resp = resp.follow() resp = resp.follow()
assert "Consent Management" in resp assert 'Consent Management' in resp
def test_password_reset_empty_form(app, db, settings, phone_activated_authn): def test_password_reset_empty_form(app, db, settings, phone_activated_authn):

View File

@ -637,7 +637,7 @@ def test_registration_activate_passwords_not_equal(app, db, settings, mailoutbox
response.form.set('password1', 'azerty12AZ') response.form.set('password1', 'azerty12AZ')
response.form.set('password2', 'AAAazerty12AZ') response.form.set('password2', 'AAAazerty12AZ')
response = response.form.submit() response = response.form.submit()
assert "The two password fields didn" in response.text assert 'The two password fields didn' in response.text
def test_authentication_method(app, db, rf, hooks): def test_authentication_method(app, db, rf, hooks):
@ -680,13 +680,13 @@ def test_authentication_method(app, db, rf, hooks):
def test_registration_with_email_suggestions(app, db, settings): def test_registration_with_email_suggestions(app, db, settings):
url = utils_misc.make_url('registration_register') url = utils_misc.make_url('registration_register')
response = app.get(url) response = app.get(url)
assert "email_domains_suggestions.js" in response.text assert 'email_domains_suggestions.js' in response.text
assert "field-live-hint" in response.text assert 'field-live-hint' in response.text
settings.A2_SUGGESTED_EMAIL_DOMAINS = [] settings.A2_SUGGESTED_EMAIL_DOMAINS = []
response = app.get(url) response = app.get(url)
assert "email_domains_suggestions.js" not in response.text assert 'email_domains_suggestions.js' not in response.text
assert "field-live-hint" not in response.text assert 'field-live-hint' not in response.text
def test_registration_no_email_full_profile_no_password(app, db, rf, mailoutbox): def test_registration_no_email_full_profile_no_password(app, db, rf, mailoutbox):
@ -960,7 +960,7 @@ def test_registration_erroneous_phone_identifier(app, db, settings, phone_activa
resp.form.set('phone_1', 'thatsnotquiteit') resp.form.set('phone_1', 'thatsnotquiteit')
resp = resp.form.submit() resp = resp.form.submit()
assert ( assert (
"Phone number must be either in E.164 globally unique format or dialable from 33 country code (FR)." 'Phone number must be either in E.164 globally unique format or dialable from 33 country code (FR).'
in resp.pyquery('.error')[0].text_content() in resp.pyquery('.error')[0].text_content()
) )
@ -1029,7 +1029,7 @@ def test_phone_registration_improperly_configured(app, db, settings, freezer, ca
assert not Token.objects.count() assert not Token.objects.count()
assert not SMSCode.objects.count() assert not SMSCode.objects.count()
assert ( assert (
"Something went wrong while trying to send the SMS code to you" 'Something went wrong while trying to send the SMS code to you'
in resp.pyquery('li.warning')[0].text_content() in resp.pyquery('li.warning')[0].text_content()
) )
assert caplog.records[0].message == 'settings.SMS_URL is not set' assert caplog.records[0].message == 'settings.SMS_URL is not set'
@ -1049,7 +1049,7 @@ def test_phone_registration_connection_error(app, db, settings, freezer, caplog,
mock_send.return_value = mock_response mock_send.return_value = mock_response
resp = resp.form.submit().follow().maybe_follow() resp = resp.form.submit().follow().maybe_follow()
assert ( assert (
"Something went wrong while trying to send the SMS code to you" 'Something went wrong while trying to send the SMS code to you'
in resp.pyquery('li.warning')[0].text_content() in resp.pyquery('li.warning')[0].text_content()
) )
assert ( assert (
@ -1072,8 +1072,8 @@ def test_phone_registration(app, db, settings, phone_activated_authn):
assert body['message'].startswith('Your code is') assert body['message'].startswith('Your code is')
code = SMSCode.objects.get() code = SMSCode.objects.get()
assert body['message'][-code_length:] == code.value assert body['message'][-code_length:] == code.value
assert ("Your code is valid for the next %s minute" % (SMSCode.CODE_DURATION // 60)) in resp.text assert ('Your code is valid for the next %s minute' % (SMSCode.CODE_DURATION // 60)) in resp.text
assert "The code you received by SMS." in resp.text assert 'The code you received by SMS.' in resp.text
resp.form.set('sms_code', code.value) resp.form.set('sms_code', code.value)
resp = resp.form.submit().follow() resp = resp.form.submit().follow()
assert Token.objects.count() == 1 assert Token.objects.count() == 1
@ -1083,7 +1083,7 @@ def test_phone_registration(app, db, settings, phone_activated_authn):
resp.form.set('first_name', 'John') resp.form.set('first_name', 'John')
resp.form.set('last_name', 'Doe') resp.form.set('last_name', 'Doe')
resp = resp.form.submit().follow() resp = resp.form.submit().follow()
assert "You have just created an account" in resp.text assert 'You have just created an account' in resp.text
user = User.objects.get(first_name='John', last_name='Doe') user = User.objects.get(first_name='John', last_name='Doe')
assert user.attributes.phone == '+33612345678' assert user.attributes.phone == '+33612345678'
@ -1115,7 +1115,7 @@ def test_phone_registration_nondefault_attribute(app, db, settings):
resp.form.set('first_name', 'John') resp.form.set('first_name', 'John')
resp.form.set('last_name', 'Doe') resp.form.set('last_name', 'Doe')
resp = resp.form.submit().follow() resp = resp.form.submit().follow()
assert "You have just created an account" in resp.text assert 'You have just created an account' in resp.text
user = User.objects.get(first_name='John', last_name='Doe') user = User.objects.get(first_name='John', last_name='Doe')
assert user.attributes.another_phone == '+33612345678' assert user.attributes.another_phone == '+33612345678'

View File

@ -193,9 +193,9 @@ def test_manager_role_import(app, admin, ou1, role_ou1, ou2, role_ou2):
# in case ous are present in export file, they must not be imported # in case ous are present in export file, they must not be imported
export['ous'] = [ export['ous'] = [
{ {
"uuid": "27255f404cb140df9a577da76b59f285", 'uuid': '27255f404cb140df9a577da76b59f285',
"slug": "should_not_exist", 'slug': 'should_not_exist',
"name": "should_not_exist", 'name': 'should_not_exist',
} }
] ]
resp = app.get('/manage/roles/') # unselect ou1 resp = app.get('/manage/roles/') # unselect ou1
@ -204,10 +204,10 @@ def test_manager_role_import(app, admin, ou1, role_ou1, ou2, role_ou2):
resp.form['ou'] = get_default_ou().pk resp.form['ou'] = get_default_ou().pk
resp = resp.form.submit().follow() resp = resp.form.submit().follow()
assert not OrganizationalUnit.objects.filter(slug="should_not_exist").exists() assert not OrganizationalUnit.objects.filter(slug='should_not_exist').exists()
# missing ou in export file # missing ou in export file
export = {"roles": [{"slug": "agent", "name": "Agent"}]} export = {'roles': [{'slug': 'agent', 'name': 'Agent'}]}
resp = app.get('/manage/roles/') resp = app.get('/manage/roles/')
resp = resp.click('Import') resp = resp.click('Import')
resp.form['site_json'] = Upload('export.json', json.dumps(export).encode(), 'application/json') resp.form['site_json'] = Upload('export.json', json.dumps(export).encode(), 'application/json')

View File

@ -721,9 +721,9 @@ def test_user_import_attributes(transactional_db, app, admin):
login(app, admin, '/manage/users/') login(app, admin, '/manage/users/')
csv_lines = [ csv_lines = [
"email key verified,first_name,last_name,more,title,bike,saintsday,birthdate,zip,phone", 'email key verified,first_name,last_name,more,title,bike,saintsday,birthdate,zip,phone',
"elliot@universalpictures.com,Elliott,Thomas,petit,Mr,True,2019-7-20,1972-05-26,75014,0123456789", 'elliot@universalpictures.com,Elliott,Thomas,petit,Mr,True,2019-7-20,1972-05-26,75014,0123456789',
"et@universalpictures.com,ET,the Extra-Terrestrial,long,??,False,1/2/3/4,0002-2-22,42,home", 'et@universalpictures.com,ET,the Extra-Terrestrial,long,??,False,1/2/3/4,0002-2-22,42,home',
] ]
response = import_csv('\n'.join(csv_lines), app) response = import_csv('\n'.join(csv_lines), app)
urls = re.findall('<a href="(/manage/users/import/[^/]+/[^/]+/)">', response.text) urls = re.findall('<a href="(/manage/users/import/[^/]+/[^/]+/)">', response.text)
@ -743,7 +743,7 @@ def test_user_import_attributes(transactional_db, app, admin):
assert elliot.attributes.values['zip'].content == '75014' assert elliot.attributes.values['zip'].content == '75014'
assert elliot.attributes.values['phone'].content == '+33123456789' assert elliot.attributes.values['phone'].content == '+33123456789'
csv_lines[2] = "et@universalpictures.com,ET,the Extra-Terrestrial,,,,,,42000,+3281123456" csv_lines[2] = 'et@universalpictures.com,ET,the Extra-Terrestrial,,,,,,42000,+3281123456'
response = import_csv('\n'.join(csv_lines), app) response = import_csv('\n'.join(csv_lines), app)
assert '0 rows have errors' in response.text assert '0 rows have errors' in response.text
@ -762,12 +762,12 @@ def test_detail_view(app, admin, simple_user, freezer, user_ou1, ou1):
url = f'/manage/users/{simple_user.pk}/' url = f'/manage/users/{simple_user.pk}/'
resp = login(app, admin, url) resp = login(app, admin, url)
assert str(simple_user.uuid) in resp.text assert str(simple_user.uuid) in resp.text
assert "Last activity" not in resp.text assert 'Last activity' not in resp.text
assert not resp.pyquery('.a2-manager-user-last-activity') assert not resp.pyquery('.a2-manager-user-last-activity')
simple_user.keepalive = datetime.datetime(2023, 2, 1, 7) simple_user.keepalive = datetime.datetime(2023, 2, 1, 7)
simple_user.save() simple_user.save()
resp = app.get(url) resp = app.get(url)
assert "Last activity on Feb. 1, 2023" in resp.pyquery('.a2-manager-user-last-activity')[0].text assert 'Last activity on Feb. 1, 2023' in resp.pyquery('.a2-manager-user-last-activity')[0].text
logout(app) logout(app)
ou1.clean_unused_accounts_alert = 700 ou1.clean_unused_accounts_alert = 700
@ -781,29 +781,29 @@ def test_detail_view(app, admin, simple_user, freezer, user_ou1, ou1):
freezer.move_to('2023-01-01') freezer.move_to('2023-01-01')
resp = login(app, admin, url) resp = login(app, admin, url)
assert ( assert (
"Deletion alert email planned for Dec. 1, 2024." 'Deletion alert email planned for Dec. 1, 2024.'
in resp.pyquery('.a2-manager-user-date-alert')[0].text in resp.pyquery('.a2-manager-user-date-alert')[0].text
) )
assert ( assert (
"Account deletion planned for Dec. 31, 2024." 'Account deletion planned for Dec. 31, 2024.'
in resp.pyquery('.a2-manager-user-date-deletion')[0].text in resp.pyquery('.a2-manager-user-date-deletion')[0].text
) )
logout(app) logout(app)
freezer.move_to('2024-12-10') freezer.move_to('2024-12-10')
resp = login(app, admin, url) resp = login(app, admin, url)
assert "Deletion alert email sent on Dec. 1, 2024." in resp.pyquery('.a2-manager-user-date-alert')[0].text assert 'Deletion alert email sent on Dec. 1, 2024.' in resp.pyquery('.a2-manager-user-date-alert')[0].text
assert ( assert (
"Account deletion planned for Dec. 31, 2024." 'Account deletion planned for Dec. 31, 2024.'
in resp.pyquery('.a2-manager-user-date-deletion')[0].text in resp.pyquery('.a2-manager-user-date-deletion')[0].text
) )
logout(app) logout(app)
freezer.move_to('2025-01-01') freezer.move_to('2025-01-01')
resp = login(app, admin, url) resp = login(app, admin, url)
assert "Deletion alert email sent on Dec. 1, 2024." in resp.pyquery('.a2-manager-user-date-alert')[0].text assert 'Deletion alert email sent on Dec. 1, 2024.' in resp.pyquery('.a2-manager-user-date-alert')[0].text
assert ( assert (
"Account deletion pending (should have been performed on Dec. 31, 2024)." 'Account deletion pending (should have been performed on Dec. 31, 2024).'
in resp.pyquery('.a2-manager-user-date-deletion')[0].text in resp.pyquery('.a2-manager-user-date-deletion')[0].text
) )

View File

@ -197,7 +197,7 @@ class TestDeleteAccountEmailVerified:
assert len(mailoutbox) == 2 assert len(mailoutbox) == 2
assert mailoutbox[1].subject == 'Account deletion on testserver' assert mailoutbox[1].subject == 'Account deletion on testserver'
assert mailoutbox[0].to == [simple_user.email] assert mailoutbox[0].to == [simple_user.email]
assert "Set-Cookie: messages=" in str(response) # Deletion performed assert 'Set-Cookie: messages=' in str(response) # Deletion performed
assert urlparse(response.location).path == '/' assert urlparse(response.location).path == '/'
def test_account_delete_when_logged_out(self, app, simple_user, mailoutbox): def test_account_delete_when_logged_out(self, app, simple_user, mailoutbox):
@ -220,7 +220,7 @@ class TestDeleteAccountEmailVerified:
assert len(mailoutbox) == 2 assert len(mailoutbox) == 2
assert mailoutbox[1].subject == 'Account deletion on testserver' assert mailoutbox[1].subject == 'Account deletion on testserver'
assert mailoutbox[0].to == [simple_user.email] assert mailoutbox[0].to == [simple_user.email]
assert "Set-Cookie: messages=" in str(response) # Deletion performed assert 'Set-Cookie: messages=' in str(response) # Deletion performed
assert urlparse(response.location).path == '/' assert urlparse(response.location).path == '/'
def test_account_delete_by_other_user(self, app, simple_user, user_ou1, mailoutbox): def test_account_delete_by_other_user(self, app, simple_user, user_ou1, mailoutbox):
@ -246,7 +246,7 @@ class TestDeleteAccountEmailVerified:
assert len(mailoutbox) == 2 assert len(mailoutbox) == 2
assert mailoutbox[1].subject == 'Account deletion on testserver' assert mailoutbox[1].subject == 'Account deletion on testserver'
assert mailoutbox[0].to == [simple_user.email] assert mailoutbox[0].to == [simple_user.email]
assert "Set-Cookie: messages=" in str(response) # Deletion performed assert 'Set-Cookie: messages=' in str(response) # Deletion performed
assert urlparse(response.location).path == '/' assert urlparse(response.location).path == '/'
def test_account_delete_fake_token(self, app, simple_user, mailoutbox): def test_account_delete_fake_token(self, app, simple_user, mailoutbox):
@ -255,7 +255,7 @@ class TestDeleteAccountEmailVerified:
.follow() .follow()
.follow() .follow()
) )
assert "The account deletion request is invalid, try again" in response.text assert 'The account deletion request is invalid, try again' in response.text
def test_account_delete_expired_token(self, app, simple_user, mailoutbox, freezer): def test_account_delete_expired_token(self, app, simple_user, mailoutbox, freezer):
freezer.move_to('2019-08-01') freezer.move_to('2019-08-01')
@ -264,7 +264,7 @@ class TestDeleteAccountEmailVerified:
freezer.move_to('2019-08-04') # Too late... freezer.move_to('2019-08-04') # Too late...
link = get_link_from_mail(mailoutbox[0]) link = get_link_from_mail(mailoutbox[0])
response = app.get(link).follow() response = app.get(link).follow()
assert "The account deletion request is too old, try again" in response.text assert 'The account deletion request is too old, try again' in response.text
def test_account_delete_valid_token_unexistent_user(self, app, simple_user, mailoutbox): def test_account_delete_valid_token_unexistent_user(self, app, simple_user, mailoutbox):
page = login(app, simple_user, path=reverse('delete_account')) page = login(app, simple_user, path=reverse('delete_account'))
@ -296,7 +296,7 @@ class TestDeleteAccountEmailNotVerified:
assert len(mailoutbox) == 1 assert len(mailoutbox) == 1
assert mailoutbox[0].subject == 'Account deletion on testserver' assert mailoutbox[0].subject == 'Account deletion on testserver'
assert mailoutbox[0].to == [simple_user.email] assert mailoutbox[0].to == [simple_user.email]
assert "Set-Cookie: messages=" in str(response) # Deletion performed assert 'Set-Cookie: messages=' in str(response) # Deletion performed
assert urlparse(response.location).path == '/' assert urlparse(response.location).path == '/'
def test_account_delete_old_authentication(self, app, simple_user, mailoutbox, freezer): def test_account_delete_old_authentication(self, app, simple_user, mailoutbox, freezer):
@ -316,7 +316,7 @@ class TestDeleteAccountEmailNotVerified:
assert len(mailoutbox) == 1 assert len(mailoutbox) == 1
assert mailoutbox[0].subject == 'Account deletion on testserver' assert mailoutbox[0].subject == 'Account deletion on testserver'
assert mailoutbox[0].to == [simple_user.email] assert mailoutbox[0].to == [simple_user.email]
assert "Set-Cookie: messages=" in str(response) # Deletion performed assert 'Set-Cookie: messages=' in str(response) # Deletion performed
assert urlparse(response.location).path == '/' assert urlparse(response.location).path == '/'

View File

@ -168,7 +168,7 @@ def assert_equals_url(url1, url2, **kwargs):
elt2[k] = elt1.get(k, v) elt2[k] = elt1.get(k, v)
else: else:
elt2[k] = set(v) elt2[k] = set(v)
assert elt1 == elt2, "URLs are not equal: %s != %s" % (splitted1, splitted2) assert elt1 == elt2, 'URLs are not equal: %s != %s' % (splitted1, splitted2)
def assert_redirects_complex(response, expected_url, **kwargs): def assert_redirects_complex(response, expected_url, **kwargs):