From c6cf91a40df69341dca8cec5e5971ff21cca0e04 Mon Sep 17 00:00:00 2001 From: Justin ! Date: Sun, 4 Oct 2020 00:59:41 -0400 Subject: Fix pep8 errors --- .flake8 | 1 + devel/fields.py | 4 +- devel/forms.py | 32 +- devel/management/commands/generate_keyring.py | 7 +- devel/management/commands/pgp_import.py | 17 +- .../commands/read_reproducible_status.py | 6 +- devel/management/commands/rematch_developers.py | 21 +- devel/management/commands/reporead.py | 79 ++-- devel/management/commands/reporead_inotify.py | 4 +- devel/management/commands/retire_user.py | 7 +- devel/migrations/0001_squashed_0002_staffgroup.py | 492 ++++++++++++++++++++- devel/migrations/0002_auto_20181216_1605.py | 443 ++++++++++++++++++- devel/migrations/0003_auto_20191009_1924.py | 444 ++++++++++++++++++- devel/migrations/0005_auto_20200628_1600.py | 4 +- devel/models.py | 54 +-- devel/reports.py | 10 +- devel/templatetags/group.py | 1 + devel/tests/test_devel.py | 4 +- devel/tests/test_pgp_import.py | 8 +- devel/tests/test_reporead.py | 17 +- devel/tests/test_reports.py | 4 +- devel/tests/test_retire_user.py | 5 +- devel/tests/test_user.py | 94 ++-- devel/utils.py | 14 +- devel/views.py | 5 +- feeds.py | 16 +- local_settings.py.example | 60 +-- main/admin.py | 6 +- main/log.py | 2 +- main/management/commands/donor_import.py | 28 +- main/migrations/0001_initial.py | 29 +- main/migrations/0002_repo_public_testing.py | 3 +- main/models.py | 141 +++--- main/templatetags/attributes.py | 4 +- main/templatetags/cdn.py | 1 + main/templatetags/flags.py | 2 +- main/templatetags/pgp.py | 6 +- main/tests/test_donor_import.py | 3 - main/tests/test_templatetags_pgp.py | 1 - main/utils.py | 3 +- mirrors/admin.py | 16 +- mirrors/management/commands/mirrorcheck.py | 14 +- mirrors/management/commands/mirrorresolv.py | 4 +- .../0001_squashed_0002_mirrorurl_bandwidth.py | 32 +- mirrors/models.py | 26 +- mirrors/templatetags/mirror_status.py | 2 + mirrors/tests/__init__.py | 16 +- mirrors/tests/test_mirrorcheck.py | 2 +- mirrors/tests/test_mirrorrsync.py | 1 + mirrors/tests/test_templatetags.py | 2 +- mirrors/utils.py | 42 +- mirrors/views/__init__.py | 34 +- mirrors/views/api.py | 15 +- mirrors/views/mirrorlist.py | 44 +- .../0001_squashed_0002_news_send_announce.py | 3 +- news/models.py | 11 +- news/tests.py | 4 +- news/urls.py | 2 +- news/views.py | 14 +- packages/admin.py | 12 +- packages/alpm.py | 7 +- packages/management/commands/populate_signoffs.py | 18 +- .../0001_squashed_0003_auto_20170524_0704.py | 55 ++- packages/models.py | 109 ++--- packages/templatetags/package_extras.py | 6 +- packages/tests.py | 12 +- packages/urls.py | 40 +- packages/urls_groups.py | 2 +- packages/utils.py | 55 ++- packages/views/__init__.py | 44 +- packages/views/display.py | 29 +- packages/views/flag.py | 65 ++- packages/views/search.py | 36 +- packages/views/signoff.py | 52 +-- planet/admin.py | 3 + planet/migrations/0001_initial.py | 3 +- planet/models.py | 2 + planet/tests/test_command.py | 1 + releng/admin.py | 3 +- .../0001_squashed_0005_auto_20180616_0947.py | 23 +- releng/migrations/0003_release_pgp_key.py | 3 +- releng/views.py | 6 +- settings.py | 6 +- sitemaps.py | 45 +- .../0001_squashed_0002_remove_todolist_old_id.py | 12 +- todolists/models.py | 6 +- todolists/tests/test_models.py | 6 +- todolists/tests/test_views.py | 5 +- todolists/urls.py | 2 +- todolists/utils.py | 8 +- todolists/views.py | 54 +-- urls.py | 24 +- visualize/views.py | 12 +- 93 files changed, 2255 insertions(+), 877 deletions(-) diff --git a/.flake8 b/.flake8 index 6deafc26..8a79e886 100644 --- a/.flake8 +++ b/.flake8 @@ -1,2 +1,3 @@ [flake8] max-line-length = 120 +ignore = E731, E241, W503, E741 diff --git a/devel/fields.py b/devel/fields.py index dd22a92e..a74abb97 100644 --- a/devel/fields.py +++ b/devel/fields.py @@ -5,8 +5,8 @@ from django.core.validators import RegexValidator class PGPKeyField(models.CharField): def __init__(self, *args, **kwargs): super(PGPKeyField, self).__init__(*args, **kwargs) - self.validators.append(RegexValidator(r'^[0-9A-F]{40}$', - "Ensure this value consists of 40 hex characters.", 'hex_char')) + self.validators.append( + RegexValidator(r'^[0-9A-F]{40}$', "Ensure this value consists of 40 hex characters.", 'hex_char')) def to_python(self, value): if value == '' or value is None: diff --git a/devel/forms.py b/devel/forms.py index e6ccf68b..a3d589e0 100644 --- a/devel/forms.py +++ b/devel/forms.py @@ -12,12 +12,13 @@ from .models import UserProfile class ProfileForm(forms.Form): - email = forms.EmailField(label='Private email (not shown publicly):', - help_text="Used for out-of-date notifications, etc.") - passwd1 = forms.CharField(label='New Password', required=False, - widget=forms.PasswordInput) - passwd2 = forms.CharField(label='Confirm Password', required=False, - widget=forms.PasswordInput) + email = forms.EmailField( + label='Private email (not shown publicly):', + help_text="Used for out-of-date notifications, etc.") + passwd1 = forms.CharField( + label='New Password', required=False, widget=forms.PasswordInput) + passwd2 = forms.CharField( + label='Confirm Password', required=False, widget=forms.PasswordInput) def clean(self): if self.cleaned_data['passwd1'] != self.cleaned_data['passwd2']: @@ -43,8 +44,7 @@ class NewUserForm(forms.ModelForm): private_email = forms.EmailField() first_name = forms.CharField(required=False) last_name = forms.CharField(required=False) - groups = forms.ModelMultipleChoiceField(required=False, - queryset=Group.objects.all()) + groups = forms.ModelMultipleChoiceField(required=False, queryset=Group.objects.all()) class Meta: model = UserProfile @@ -66,16 +66,16 @@ class NewUserForm(forms.ModelForm): def clean_username(self): username = self.cleaned_data['username'] if User.objects.filter(username=username).exists(): - raise forms.ValidationError( - "A user with that username already exists.") + raise forms.ValidationError("A user with that username already exists.") return username def save(self, commit=True): profile = super(NewUserForm, self).save(False) pwletters = ascii_letters + digits password = ''.join([random.choice(pwletters) for _ in range(8)]) - user = User.objects.create_user(username=self.cleaned_data['username'], - email=self.cleaned_data['private_email'], password=password) + user = User.objects.create_user( + username=self.cleaned_data['username'], + email=self.cleaned_data['private_email'], password=password) user.first_name = self.cleaned_data['first_name'] user.last_name = self.cleaned_data['last_name'] user.save() @@ -95,9 +95,9 @@ class NewUserForm(forms.ModelForm): } send_mail("Your new archweb account", - template.render(ctx), - 'Arch Website Notification ', - [user.email], - fail_silently=False) + template.render(ctx), + 'Arch Website Notification ', + [user.email], + fail_silently=False) # vim: set ts=4 sw=4 et: diff --git a/devel/management/commands/generate_keyring.py b/devel/management/commands/generate_keyring.py index a61cffa9..3e6a3e9f 100644 --- a/devel/management/commands/generate_keyring.py +++ b/devel/management/commands/generate_keyring.py @@ -22,6 +22,7 @@ logging.basicConfig( stream=sys.stderr) logger = logging.getLogger() + class Command(BaseCommand): args = " [ownertrust_path]" help = "Assemble a GPG keyring with all known developer keys." @@ -52,8 +53,8 @@ def generate_keyring(keyserver, keyring): # Screw you Django, for not letting one natively do value != key_ids = UserProfile.objects.filter( - pgp_key__isnull=False).extra(where=["pgp_key != ''"]).values_list( - "pgp_key", flat=True) + pgp_key__isnull=False).extra(where=["pgp_key != ''"]).values_list( + "pgp_key", flat=True) logger.info("%d keys fetched from user profiles", len(key_ids)) master_key_ids = MasterKey.objects.values_list("pgp_key", flat=True) logger.info("%d keys fetched from master keys", len(master_key_ids)) @@ -63,7 +64,7 @@ def generate_keyring(keyserver, keyring): if '/' not in keyring: keyring = './%s' % keyring gpg_cmd = ["gpg", "--no-default-keyring", "--keyring", keyring, - "--keyserver", keyserver, "--recv-keys"] + "--keyserver", keyserver, "--recv-keys"] logger.info("running command: %r", gpg_cmd) gpg_cmd.extend(key_ids) gpg_cmd.extend(master_key_ids) diff --git a/devel/management/commands/pgp_import.py b/devel/management/commands/pgp_import.py index a0b9cbec..00ff5a49 100644 --- a/devel/management/commands/pgp_import.py +++ b/devel/management/commands/pgp_import.py @@ -28,6 +28,7 @@ logging.basicConfig( stream=sys.stderr) logger = logging.getLogger() + class Command(BaseCommand): args = "" help = "Import keys and signatures from a given GPG keyring." @@ -71,7 +72,7 @@ def call_gpg(keyring, *args): if '/' not in keyring: keyring = './%s' % keyring gpg_cmd = ["gpg2", "--no-default-keyring", "--keyring", keyring, - "--with-colons", "--fixed-list-mode"] + "--with-colons", "--fixed-list-mode"] gpg_cmd.extend(args) logger.info("running command: %s", ' '.join(gpg_cmd)) proc = subprocess.Popen(gpg_cmd, stdout=subprocess.PIPE) @@ -153,7 +154,7 @@ def import_keys(keyring): 'parent_id': parent_id, } dkey, created = DeveloperKey.objects.get_or_create( - key=data.key, created=data.created, defaults=other) + key=data.key, created=data.created, defaults=other) data.db_id = dkey.id # set or update any additional data we might need to @@ -216,8 +217,7 @@ def parse_sigdata(data): signer = parts[4] revoked = get_date(parts[5]) # revoke any prior edges that match - matches = [e for e in edges if e.signer == signer - and e.signee == current_pubkey] + matches = [e for e in edges if e.signer == signer and e.signee == current_pubkey] for edge in matches: edge.revoked = revoked @@ -230,17 +230,16 @@ def import_signatures(keyring): # now prune the data down to what we actually want. # prune edges not in nodes, remove duplicates, and self-sigs - pruned_edges = {edge for edge in edges - if edge.signer in nodes and edge.signer != edge.signee} + pruned_edges = {edge for edge in edges if edge.signer in nodes and edge.signer != edge.signee} logger.info("creating or finding up to %d signatures", len(pruned_edges)) created_ct = updated_ct = 0 with transaction.atomic(): for edge in pruned_edges: sig, created = PGPSignature.objects.get_or_create( - signer=edge.signer, signee=edge.signee, - created=edge.created, expires=edge.expires, - defaults={ 'revoked': edge.revoked }) + signer=edge.signer, signee=edge.signee, + created=edge.created, expires=edge.expires, + defaults={'revoked': edge.revoked}) if sig.revoked != edge.revoked: sig.revoked = edge.revoked sig.save() diff --git a/devel/management/commands/read_reproducible_status.py b/devel/management/commands/read_reproducible_status.py index ba317753..8db8b6cd 100644 --- a/devel/management/commands/read_reproducible_status.py +++ b/devel/management/commands/read_reproducible_status.py @@ -119,7 +119,8 @@ def import_rebuilderd_status(url): rbstatus.was_repro = False if rbstatus.pkgver != pkgver or rbstatus.pkgrel != pkgrel or rbstatus.epoch != epoch: - logger.info('updating status for package: %s to %s', pkg['name'], RebuilderdStatus.REBUILDERD_STATUSES[status][1]) + logger.info('updating status for package: %s to %s', pkg['name'], + RebuilderdStatus.REBUILDERD_STATUSES[status][1]) rbstatus.epoch = epoch rbstatus.pkgver = pkgver rbstatus.pkgrel = pkgrel @@ -127,7 +128,8 @@ def import_rebuilderd_status(url): rbstatus.arch = arch rbstatus.repo = repository elif rbstatus.status != status: # Rebuilderd rebuild the same package? - logger.info('status for package: %s changed to %s', pkg['name'], RebuilderdStatus.REBUILDERD_STATUSES[status][1]) + logger.info('status for package: %s changed to %s', pkg['name'], + RebuilderdStatus.REBUILDERD_STATUSES[status][1]) rbstatus.status = status # TODO: does django know when a model was really modified? diff --git a/devel/management/commands/rematch_developers.py b/devel/management/commands/rematch_developers.py index 7178d1d8..f6cc95c8 100644 --- a/devel/management/commands/rematch_developers.py +++ b/devel/management/commands/rematch_developers.py @@ -28,6 +28,7 @@ logging.basicConfig( stream=sys.stderr) logger = logging.getLogger() + class Command(BaseCommand): help = "Match and map objects in database to developer emails" @@ -44,6 +45,7 @@ class Command(BaseCommand): match_packager(finder) match_flagrequest(finder) + @transaction.atomic def match_packager(finder): logger.info("getting all unmatched packager strings") @@ -51,7 +53,7 @@ def match_packager(finder): mapping = {} unmatched = Package.objects.filter(packager__isnull=True).values_list( - 'packager_str', flat=True).order_by().distinct() + 'packager_str', flat=True).order_by().distinct() logger.info("%d packager strings retrieved", len(unmatched)) for packager in unmatched: @@ -63,11 +65,11 @@ def match_packager(finder): matched_count += 1 for packager_str, user in mapping.items(): - package_count += Package.objects.filter(packager__isnull=True, - packager_str=packager_str).update(packager=user) + package_count += Package.objects.filter( + packager__isnull=True, + packager_str=packager_str).update(packager=user) - logger.info("%d packages updated, %d packager strings matched", - package_count, matched_count) + logger.info("%d packages updated, %d packager strings matched", package_count, matched_count) @transaction.atomic @@ -77,7 +79,7 @@ def match_flagrequest(finder): mapping = {} unmatched = FlagRequest.objects.filter(user__isnull=True).values_list( - 'user_email', flat=True).order_by().distinct() + 'user_email', flat=True).order_by().distinct() logger.info("%d email addresses retrieved", len(unmatched)) for user_email in unmatched: @@ -89,10 +91,9 @@ def match_flagrequest(finder): matched_count += 1 for user_email, user in mapping.items(): - req_count += FlagRequest.objects.filter(user__isnull=True, - user_email=user_email).update(user=user) + req_count += FlagRequest.objects.filter( + user__isnull=True, user_email=user_email).update(user=user) - logger.info("%d request emails updated, %d emails matched", - req_count, matched_count) + logger.info("%d request emails updated, %d emails matched", req_count, matched_count) # vim: set ts=4 sw=4 et: diff --git a/devel/management/commands/reporead.py b/devel/management/commands/reporead.py index ba80ebe5..afb4d5d3 100644 --- a/devel/management/commands/reporead.py +++ b/devel/management/commands/reporead.py @@ -46,6 +46,7 @@ TRACE = 5 logging.addLevelName(TRACE, 'TRACE') logger = logging.getLogger() + class Command(BaseCommand): help = "Runs a package repository import for the given arch and file." missing_args_message = 'missing arch and file.' @@ -56,13 +57,17 @@ class Command(BaseCommand): action='store_true', dest='force', default=False, - help='Force a re-import of data for all packages instead of only new ones. Will not touch the \'last updated\' value.') + help='Force a re-import of data for all packages \ + instead of only new ones. Will not touch \ + the \'last updated\' value.') parser.add_argument('--filesonly', action='store_true', dest='filesonly', default=False, - help='Load filelists if they are outdated, but will not add or remove any packages. Will not touch the \'last updated\' value.') + help='Load filelists if they are outdated, but will \ + not add or remove any packages. Will not touch the \ + \'last updated\' value.') def handle(self, arch=None, filename=None, **options): if not arch: @@ -86,11 +91,11 @@ class Command(BaseCommand): class RepoPackage(object): """An interim 'container' object for holding Arch package data.""" - bare = ( 'name', 'base', 'arch', 'filename', - 'md5sum', 'sha256sum', 'url', 'packager' ) - number = ( 'csize', 'isize' ) - collections = ( 'depends', 'optdepends', 'makedepends', 'checkdepends', - 'conflicts', 'provides', 'replaces', 'groups', 'license') + bare = ('name', 'base', 'arch', 'filename', + 'md5sum', 'sha256sum', 'url', 'packager') + number = ('csize', 'isize') + collections = ('depends', 'optdepends', 'makedepends', 'checkdepends', + 'conflicts', 'provides', 'replaces', 'groups', 'license') def __init__(self, repo): self.repo = repo @@ -124,8 +129,8 @@ class RepoPackage(object): self.builddate = builddate.replace(tzinfo=utc) except ValueError: logger.warning( - 'Package %s had unparsable build date %s', - self.name, v[0]) + 'Package %s had unparsable build date %s', + self.name, v[0]) else: # anything left in collections setattr(self, k, tuple(v)) @@ -137,7 +142,7 @@ class RepoPackage(object): info = parse_info(data_file) except UnicodeDecodeError: logger.warning("Could not correctly decode files list for %s", - self.name) + self.name) return None return info['files'] @@ -151,6 +156,7 @@ class RepoPackage(object): DEPEND_RE = re.compile(r"^(.+?)((>=|<=|=|>|<)(.+))?$") + def create_depend(package, dep_str, deptype='D'): depend = Depend(pkg=package, deptype=deptype) # lop off any description first, don't get confused by epoch @@ -166,10 +172,11 @@ def create_depend(package, dep_str, deptype='D'): depend.version = match.group(4) else: logger.warning('Package %s had unparsable depend string %s', - package.pkgname, dep_str) + package.pkgname, dep_str) return None return depend + def create_related(model, package, rel_str, equals_only=False): related = model(pkg=package) match = DEPEND_RE.match(rel_str) @@ -181,13 +188,13 @@ def create_related(model, package, rel_str, equals_only=False): related.comparison = comp elif comp != '=': logger.warning( - 'Package %s had unexpected comparison operator %s for %s in %s', - package.pkgname, comp, model.__name__, rel_str) + 'Package %s had unexpected comparison operator %s for %s in %s', + package.pkgname, comp, model.__name__, rel_str) if match.group(4): related.version = match.group(4) else: logger.warning('Package %s had unparsable %s string %s', - package.pkgname, model.___name__, rel_str) + package.pkgname, model.___name__, rel_str) return None return related @@ -206,8 +213,10 @@ def create_multivalued(dbpkg, repopkg, db_attr, repo_attr): if new_items: model.objects.bulk_create(new_items) + finder = UserFinder() + def populate_pkg(dbpkg, repopkg, force=False, timestamp=None): # we reset the flag date only if the upstream version components change; # e.g. epoch or pkgver, but not pkgrel @@ -259,8 +268,7 @@ def populate_pkg(dbpkg, repopkg, force=False, timestamp=None): Conflict.objects.bulk_create(conflicts) dbpkg.provides.all().delete() - provides = [create_related(Provision, dbpkg, y, equals_only=True) - for y in repopkg.provides] + provides = [create_related(Provision, dbpkg, y, equals_only=True) for y in repopkg.provides] Provision.objects.bulk_create(provides) dbpkg.replaces.all().delete() @@ -272,7 +280,7 @@ def populate_pkg(dbpkg, repopkg, force=False, timestamp=None): pkg_same_version = lambda pkg, dbpkg: pkg.ver == dbpkg.pkgver \ - and pkg.rel == dbpkg.pkgrel and pkg.epoch == dbpkg.epoch + and pkg.rel == dbpkg.pkgrel and pkg.epoch == dbpkg.epoch def delete_pkg_files(dbpkg): @@ -303,8 +311,8 @@ def populate_files(dbpkg, repopkg, force=False): if not force: if not pkg_same_version(repopkg, dbpkg): logger.info("DB version (%s) didn't match repo version " - "(%s) for package %s, skipping file list addition", - dbpkg.full_version, repopkg.full_version, dbpkg.pkgname) + "(%s) for package %s, skipping file list addition", + dbpkg.full_version, repopkg.full_version, dbpkg.pkgname) return if not dbpkg.files_last_update or not dbpkg.last_update: pass @@ -319,7 +327,7 @@ def populate_files(dbpkg, repopkg, force=False): return delete_pkg_files(dbpkg) logger.info("adding %d files for package %s", - len(files), dbpkg.pkgname) + len(files), dbpkg.pkgname) pkg_files = [] # sort in normal alpha-order that pacman uses, rather than makepkg's # default breadth-first, directory-first ordering @@ -332,9 +340,9 @@ def populate_files(dbpkg, repopkg, force=False): if filename == '': filename = None pkgfile = PackageFile(pkg=dbpkg, - is_directory=(filename is None), - directory=dirname, - filename=filename) + is_directory=(filename is None), + directory=dirname, + filename=filename) pkg_files.append(pkgfile) batched_bulk_create(PackageFile, pkg_files) dbpkg.files_last_update = now() @@ -348,13 +356,12 @@ def update_common(archname, reponame, pkgs, sanity_check=True): with transaction.atomic(): # force the transaction dirty, even though we will only do reads # https://github.com/django/django/blob/3c447b108ac70757001171f7a4791f493880bf5b/docs/releases/1.3.txt#L606 - #transaction.set_dirty() + # transaction.set_dirty() repository = Repo.objects.get(name__iexact=reponame) architecture = Arch.objects.get(name=archname) # no-arg order_by() removes even the default ordering; we don't need it - dbpkgs = Package.objects.filter( - arch=architecture, repo=repository).order_by() + dbpkgs = Package.objects.filter(arch=architecture, repo=repository).order_by() logger.info("%d packages in current web DB", len(dbpkgs)) logger.info("%d packages in new updating DB", len(pkgs)) @@ -368,7 +375,7 @@ def update_common(archname, reponame, pkgs, sanity_check=True): # Fewer than 20 packages makes the percentage check unreliable, but it # also means we expect the repo to fluctuate a lot. msg = "Package database %s (%s) has %.1f%% the number of packages " \ - "the web database" + "the web database" if not sanity_check: pass elif repository.testing or repository.public_testing or repository.staging: @@ -383,6 +390,7 @@ def update_common(archname, reponame, pkgs, sanity_check=True): return dbpkgs + def db_update(archname, reponame, pkgs, force=False): """ Parses a list of packages and updates the packages database accordingly. @@ -407,7 +415,7 @@ def db_update(archname, reponame, pkgs, force=False): logger.info("Adding package %s", pkg.name) timestamp = now() dbpkg = Package(pkgname=pkg.name, arch=architecture, repo=repository, - created=timestamp) + created=timestamp) try: with transaction.atomic(): populate_pkg(dbpkg, pkg, timestamp=timestamp) @@ -417,8 +425,7 @@ def db_update(archname, reponame, pkgs, force=False): pkgname=pkg.name).exclude(id=dbpkg.id).exists(): if not User.objects.filter( package_relations__pkgbase=dbpkg.pkgbase, - package_relations__type=PackageRelation.MAINTAINER - ).exists(): + package_relations__type=PackageRelation.MAINTAINER).exists(): packager = finder.find(pkg.packager) if packager: prel = PackageRelation(pkgbase=dbpkg.pkgbase, @@ -426,12 +433,11 @@ def db_update(archname, reponame, pkgs, force=False): type=PackageRelation.MAINTAINER) prel.save() - except IntegrityError: if architecture.agnostic: logger.warning("Could not add package %s; " - "not fatal if another thread beat us to it.", - pkg.name) + "not fatal if another thread beat us to it.", + pkg.name) else: logger.exception("Could not add package %s", pkg.name) @@ -579,6 +585,7 @@ def parse_repo(repopath): logger.info("Finished repo parsing, %d total packages", len(pkgs)) return (reponame, pkgs.values()) + def locate_arch(arch): "Check if arch is valid." if isinstance(arch, Arch): @@ -586,8 +593,7 @@ def locate_arch(arch): try: return Arch.objects.get(name=arch) except Arch.DoesNotExist: - raise CommandError( - 'Specified architecture %s is not currently known.' % arch) + raise CommandError('Specified architecture %s is not currently known.' % arch) def read_repo(primary_arch, repo_file, options): @@ -612,8 +618,7 @@ def read_repo(primary_arch, repo_file, options): packages_arches[package.arch].append(package) else: raise Exception( - "Package %s in database %s had wrong architecture %s" % ( - package.name, repo_file, package.arch)) + f"Package {package.name} in database {repo_file} had wrong architecture {package.arch}") del packages database = router.db_for_write(Package) diff --git a/devel/management/commands/reporead_inotify.py b/devel/management/commands/reporead_inotify.py index fadcb881..d3003f77 100644 --- a/devel/management/commands/reporead_inotify.py +++ b/devel/management/commands/reporead_inotify.py @@ -205,8 +205,8 @@ class EventHandler(pyinotify.ProcessEvent): arch = self.arch_lookup.get(event.path, None) if arch is None: logger.warning( - 'Could not determine arch for %s, skipping update', - path) + 'Could not determine arch for %s, skipping update', + path) return database = Database(arch, path) self.databases[path] = database diff --git a/devel/management/commands/retire_user.py b/devel/management/commands/retire_user.py index 0a7259f3..8f4c6017 100644 --- a/devel/management/commands/retire_user.py +++ b/devel/management/commands/retire_user.py @@ -25,9 +25,9 @@ logging.basicConfig( logger = logging.getLogger() MAPPING = { - 'Developers': 'Retired Developers', - 'Trusted Users': 'Retired Trusted Users', - 'Support Staff': 'Retired Support Staff', + 'Developers': 'Retired Developers', + 'Trusted Users': 'Retired Trusted Users', + 'Support Staff': 'Retired Support Staff', } @@ -38,7 +38,6 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument('user', type=str) - def handle(self, *args, **options): v = int(options.get('verbosity', 0)) if v == 0: diff --git a/devel/migrations/0001_squashed_0002_staffgroup.py b/devel/migrations/0001_squashed_0002_staffgroup.py index 90e8e3a1..b4788118 100644 --- a/devel/migrations/0001_squashed_0002_staffgroup.py +++ b/devel/migrations/0001_squashed_0002_staffgroup.py @@ -28,19 +28,31 @@ class Migration(migrations.Migration): ('created', models.DateTimeField()), ('expires', models.DateTimeField(blank=True, null=True)), ('revoked', models.DateTimeField(blank=True, null=True)), - ('owner', models.ForeignKey(help_text='The developer this key belongs to', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='all_keys', to=settings.AUTH_USER_MODEL)), - ('parent', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='devel.DeveloperKey')), + ('owner', models.ForeignKey( + help_text='The developer this key belongs to', + null=True, on_delete=django.db.models.deletion.CASCADE, + related_name='all_keys', to=settings.AUTH_USER_MODEL)), + ('parent', models.ForeignKey( + null=True, on_delete=django.db.models.deletion.SET_NULL, to='devel.DeveloperKey')), ], ), migrations.CreateModel( name='MasterKey', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('pgp_key', devel.fields.PGPKeyField(help_text='consists of 40 hex digits; use `gpg --fingerprint`', max_length=40, verbose_name='PGP key fingerprint')), + ('pgp_key', devel.fields.PGPKeyField( + help_text='consists of 40 hex digits; use `gpg --fingerprint`', + max_length=40, verbose_name='PGP key fingerprint')), ('created', models.DateField()), ('revoked', models.DateField(blank=True, null=True)), - ('owner', models.ForeignKey(help_text='The developer holding this master key', on_delete=django.db.models.deletion.CASCADE, related_name='masterkey_owner', to=settings.AUTH_USER_MODEL)), - ('revoker', models.ForeignKey(help_text='The developer holding the revocation certificate', on_delete=django.db.models.deletion.CASCADE, related_name='masterkey_revoker', to=settings.AUTH_USER_MODEL)), + ('owner', models.ForeignKey( + help_text='The developer holding this master key', + on_delete=django.db.models.deletion.CASCADE, + related_name='masterkey_owner', to=settings.AUTH_USER_MODEL)), + ('revoker', models.ForeignKey( + help_text='The developer holding the revocation certificate', + on_delete=django.db.models.deletion.CASCADE, + related_name='masterkey_revoker', to=settings.AUTH_USER_MODEL)), ], options={ 'ordering': ('created',), @@ -51,8 +63,10 @@ class Migration(migrations.Migration): name='PGPSignature', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('signer', devel.fields.PGPKeyField(db_index=True, max_length=40, verbose_name='Signer key fingerprint')), - ('signee', devel.fields.PGPKeyField(db_index=True, max_length=40, verbose_name='Signee key fingerprint')), + ('signer', devel.fields.PGPKeyField( + db_index=True, max_length=40, verbose_name='Signer key fingerprint')), + ('signee', devel.fields.PGPKeyField( + db_index=True, max_length=40, verbose_name='Signee key fingerprint')), ('created', models.DateField()), ('expires', models.DateField(blank=True, null=True)), ('revoked', models.DateField(blank=True, null=True)), @@ -67,12 +81,459 @@ class Migration(migrations.Migration): name='UserProfile', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('notify', models.BooleanField(default=True, help_text="When enabled, send user 'flag out-of-date' notifications", verbose_name='Send notifications')), - ('time_zone', models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Godthab', 'America/Godthab'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Punta_Arenas', 'America/Punta_Arenas'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Atyrau', 'Asia/Atyrau'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Barnaul', 'Asia/Barnaul'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Famagusta', 'Asia/Famagusta'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Tomsk', 'Asia/Tomsk'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yangon', 'Asia/Yangon'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Sydney', 'Australia/Sydney'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Astrakhan', 'Europe/Astrakhan'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Kirov', 'Europe/Kirov'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Saratov', 'Europe/Saratov'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GMT', 'GMT'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('US/Alaska', 'US/Alaska'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('UTC', 'UTC')], default=b'UTC', help_text=b'Used for developer clock page', max_length=100)), + ('notify', models.BooleanField( + default=True, help_text="When enabled, send user 'flag out-of-date' notifications", + verbose_name='Send notifications')), + ('time_zone', models.CharField( + choices=[ + ('Africa/Abidjan', 'Africa/Abidjan'), + ('Africa/Accra', 'Africa/Accra'), + ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), + ('Africa/Algiers', 'Africa/Algiers'), + ('Africa/Asmara', 'Africa/Asmara'), + ('Africa/Bamako', 'Africa/Bamako'), + ('Africa/Bangui', 'Africa/Bangui'), + ('Africa/Banjul', 'Africa/Banjul'), + ('Africa/Bissau', 'Africa/Bissau'), + ('Africa/Blantyre', 'Africa/Blantyre'), + ('Africa/Brazzaville', 'Africa/Brazzaville'), + ('Africa/Bujumbura', 'Africa/Bujumbura'), + ('Africa/Cairo', 'Africa/Cairo'), + ('Africa/Casablanca', 'Africa/Casablanca'), + ('Africa/Ceuta', 'Africa/Ceuta'), + ('Africa/Conakry', 'Africa/Conakry'), + ('Africa/Dakar', 'Africa/Dakar'), + ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), + ('Africa/Djibouti', 'Africa/Djibouti'), + ('Africa/Douala', 'Africa/Douala'), + ('Africa/El_Aaiun', 'Africa/El_Aaiun'), + ('Africa/Freetown', 'Africa/Freetown'), + ('Africa/Gaborone', 'Africa/Gaborone'), + ('Africa/Harare', 'Africa/Harare'), + ('Africa/Johannesburg', 'Africa/Johannesburg'), + ('Africa/Juba', 'Africa/Juba'), + ('Africa/Kampala', 'Africa/Kampala'), + ('Africa/Khartoum', 'Africa/Khartoum'), + ('Africa/Kigali', 'Africa/Kigali'), + ('Africa/Kinshasa', 'Africa/Kinshasa'), + ('Africa/Lagos', 'Africa/Lagos'), + ('Africa/Libreville', 'Africa/Libreville'), + ('Africa/Lome', 'Africa/Lome'), + ('Africa/Luanda', 'Africa/Luanda'), + ('Africa/Lubumbashi', 'Africa/Lubumbashi'), + ('Africa/Lusaka', 'Africa/Lusaka'), + ('Africa/Malabo', 'Africa/Malabo'), + ('Africa/Maputo', 'Africa/Maputo'), + ('Africa/Maseru', 'Africa/Maseru'), + ('Africa/Mbabane', 'Africa/Mbabane'), + ('Africa/Mogadishu', 'Africa/Mogadishu'), + ('Africa/Monrovia', 'Africa/Monrovia'), + ('Africa/Nairobi', 'Africa/Nairobi'), + ('Africa/Ndjamena', 'Africa/Ndjamena'), + ('Africa/Niamey', 'Africa/Niamey'), + ('Africa/Nouakchott', 'Africa/Nouakchott'), + ('Africa/Ouagadougou', 'Africa/Ouagadougou'), + ('Africa/Porto-Novo', 'Africa/Porto-Novo'), + ('Africa/Sao_Tome', 'Africa/Sao_Tome'), + ('Africa/Tripoli', 'Africa/Tripoli'), + ('Africa/Tunis', 'Africa/Tunis'), + ('Africa/Windhoek', 'Africa/Windhoek'), + ('America/Adak', 'America/Adak'), + ('America/Anchorage', 'America/Anchorage'), + ('America/Anguilla', 'America/Anguilla'), + ('America/Antigua', 'America/Antigua'), + ('America/Araguaina', 'America/Araguaina'), + ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), + ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), + ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), + ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), + ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), + ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), + ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), + ('America/Argentina/Salta', 'America/Argentina/Salta'), + ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), + ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), + ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), + ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), + ('America/Aruba', 'America/Aruba'), + ('America/Asuncion', 'America/Asuncion'), + ('America/Atikokan', 'America/Atikokan'), + ('America/Bahia', 'America/Bahia'), + ('America/Bahia_Banderas', 'America/Bahia_Banderas'), + ('America/Barbados', 'America/Barbados'), + ('America/Belem', 'America/Belem'), + ('America/Belize', 'America/Belize'), + ('America/Blanc-Sablon', 'America/Blanc-Sablon'), + ('America/Boa_Vista', 'America/Boa_Vista'), + ('America/Bogota', 'America/Bogota'), + ('America/Boise', 'America/Boise'), + ('America/Cambridge_Bay', 'America/Cambridge_Bay'), + ('America/Campo_Grande', 'America/Campo_Grande'), + ('America/Cancun', 'America/Cancun'), + ('America/Caracas', 'America/Caracas'), + ('America/Cayenne', 'America/Cayenne'), + ('America/Cayman', 'America/Cayman'), + ('America/Chicago', 'America/Chicago'), + ('America/Chihuahua', 'America/Chihuahua'), + ('America/Costa_Rica', 'America/Costa_Rica'), + ('America/Creston', 'America/Creston'), + ('America/Cuiaba', 'America/Cuiaba'), + ('America/Curacao', 'America/Curacao'), + ('America/Danmarkshavn', 'America/Danmarkshavn'), + ('America/Dawson', 'America/Dawson'), + ('America/Dawson_Creek', 'America/Dawson_Creek'), + ('America/Denver', 'America/Denver'), + ('America/Detroit', 'America/Detroit'), + ('America/Dominica', 'America/Dominica'), + ('America/Edmonton', 'America/Edmonton'), + ('America/Eirunepe', 'America/Eirunepe'), + ('America/El_Salvador', 'America/El_Salvador'), + ('America/Fort_Nelson', 'America/Fort_Nelson'), + ('America/Fortaleza', 'America/Fortaleza'), + ('America/Glace_Bay', 'America/Glace_Bay'), + ('America/Godthab', 'America/Godthab'), + ('America/Goose_Bay', 'America/Goose_Bay'), + ('America/Grand_Turk', 'America/Grand_Turk'), + ('America/Grenada', 'America/Grenada'), + ('America/Guadeloupe', 'America/Guadeloupe'), + ('America/Guatemala', 'America/Guatemala'), + ('America/Guayaquil', 'America/Guayaquil'), + ('America/Guyana', 'America/Guyana'), + ('America/Halifax', 'America/Halifax'), + ('America/Havana', 'America/Havana'), + ('America/Hermosillo', 'America/Hermosillo'), + ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), + ('America/Indiana/Knox', 'America/Indiana/Knox'), + ('America/Indiana/Marengo', 'America/Indiana/Marengo'), + ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), + ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), + ('America/Indiana/Vevay', 'America/Indiana/Vevay'), + ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), + ('America/Indiana/Winamac', 'America/Indiana/Winamac'), + ('America/Inuvik', 'America/Inuvik'), + ('America/Iqaluit', 'America/Iqaluit'), + ('America/Jamaica', 'America/Jamaica'), + ('America/Juneau', 'America/Juneau'), + ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), + ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), + ('America/Kralendijk', 'America/Kralendijk'), + ('America/La_Paz', 'America/La_Paz'), + ('America/Lima', 'America/Lima'), + ('America/Los_Angeles', 'America/Los_Angeles'), + ('America/Lower_Princes', 'America/Lower_Princes'), + ('America/Maceio', 'America/Maceio'), + ('America/Managua', 'America/Managua'), + ('America/Manaus', 'America/Manaus'), + ('America/Marigot', 'America/Marigot'), + ('America/Martinique', 'America/Martinique'), + ('America/Matamoros', 'America/Matamoros'), + ('America/Mazatlan', 'America/Mazatlan'), + ('America/Menominee', 'America/Menominee'), + ('America/Merida', 'America/Merida'), + ('America/Metlakatla', 'America/Metlakatla'), + ('America/Mexico_City', 'America/Mexico_City'), + ('America/Miquelon', 'America/Miquelon'), + ('America/Moncton', 'America/Moncton'), + ('America/Monterrey', 'America/Monterrey'), + ('America/Montevideo', 'America/Montevideo'), + ('America/Montserrat', 'America/Montserrat'), + ('America/Nassau', 'America/Nassau'), + ('America/New_York', 'America/New_York'), + ('America/Nipigon', 'America/Nipigon'), + ('America/Nome', 'America/Nome'), + ('America/Noronha', 'America/Noronha'), + ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), + ('America/North_Dakota/Center', 'America/North_Dakota/Center'), + ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), + ('America/Ojinaga', 'America/Ojinaga'), + ('America/Panama', 'America/Panama'), + ('America/Pangnirtung', 'America/Pangnirtung'), + ('America/Paramaribo', 'America/Paramaribo'), + ('America/Phoenix', 'America/Phoenix'), + ('America/Port-au-Prince', 'America/Port-au-Prince'), + ('America/Port_of_Spain', 'America/Port_of_Spain'), + ('America/Porto_Velho', 'America/Porto_Velho'), + ('America/Puerto_Rico', 'America/Puerto_Rico'), + ('America/Punta_Arenas', 'America/Punta_Arenas'), + ('America/Rainy_River', 'America/Rainy_River'), + ('America/Rankin_Inlet', 'America/Rankin_Inlet'), + ('America/Recife', 'America/Recife'), + ('America/Regina', 'America/Regina'), + ('America/Resolute', 'America/Resolute'), + ('America/Rio_Branco', 'America/Rio_Branco'), + ('America/Santarem', 'America/Santarem'), + ('America/Santiago', 'America/Santiago'), + ('America/Santo_Domingo', 'America/Santo_Domingo'), + ('America/Sao_Paulo', 'America/Sao_Paulo'), + ('America/Scoresbysund', 'America/Scoresbysund'), + ('America/Sitka', 'America/Sitka'), + ('America/St_Barthelemy', 'America/St_Barthelemy'), + ('America/St_Johns', 'America/St_Johns'), + ('America/St_Kitts', 'America/St_Kitts'), + ('America/St_Lucia', 'America/St_Lucia'), + ('America/St_Thomas', 'America/St_Thomas'), + ('America/St_Vincent', 'America/St_Vincent'), + ('America/Swift_Current', 'America/Swift_Current'), + ('America/Tegucigalpa', 'America/Tegucigalpa'), + ('America/Thule', 'America/Thule'), + ('America/Thunder_Bay', 'America/Thunder_Bay'), + ('America/Tijuana', 'America/Tijuana'), + ('America/Toronto', 'America/Toronto'), + ('America/Tortola', 'America/Tortola'), + ('America/Vancouver', 'America/Vancouver'), + ('America/Whitehorse', 'America/Whitehorse'), + ('America/Winnipeg', 'America/Winnipeg'), + ('America/Yakutat', 'America/Yakutat'), + ('America/Yellowknife', 'America/Yellowknife'), + ('Antarctica/Casey', 'Antarctica/Casey'), + ('Antarctica/Davis', 'Antarctica/Davis'), + ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), + ('Antarctica/Macquarie', 'Antarctica/Macquarie'), + ('Antarctica/Mawson', 'Antarctica/Mawson'), + ('Antarctica/McMurdo', 'Antarctica/McMurdo'), + ('Antarctica/Palmer', 'Antarctica/Palmer'), + ('Antarctica/Rothera', 'Antarctica/Rothera'), + ('Antarctica/Syowa', 'Antarctica/Syowa'), + ('Antarctica/Troll', 'Antarctica/Troll'), + ('Antarctica/Vostok', 'Antarctica/Vostok'), + ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), + ('Asia/Aden', 'Asia/Aden'), + ('Asia/Almaty', 'Asia/Almaty'), + ('Asia/Amman', 'Asia/Amman'), + ('Asia/Anadyr', 'Asia/Anadyr'), + ('Asia/Aqtau', 'Asia/Aqtau'), + ('Asia/Aqtobe', 'Asia/Aqtobe'), + ('Asia/Ashgabat', 'Asia/Ashgabat'), + ('Asia/Atyrau', 'Asia/Atyrau'), + ('Asia/Baghdad', 'Asia/Baghdad'), + ('Asia/Bahrain', 'Asia/Bahrain'), + ('Asia/Baku', 'Asia/Baku'), + ('Asia/Bangkok', 'Asia/Bangkok'), + ('Asia/Barnaul', 'Asia/Barnaul'), + ('Asia/Beirut', 'Asia/Beirut'), + ('Asia/Bishkek', 'Asia/Bishkek'), + ('Asia/Brunei', 'Asia/Brunei'), + ('Asia/Chita', 'Asia/Chita'), + ('Asia/Choibalsan', 'Asia/Choibalsan'), + ('Asia/Colombo', 'Asia/Colombo'), + ('Asia/Damascus', 'Asia/Damascus'), + ('Asia/Dhaka', 'Asia/Dhaka'), + ('Asia/Dili', 'Asia/Dili'), + ('Asia/Dubai', 'Asia/Dubai'), + ('Asia/Dushanbe', 'Asia/Dushanbe'), + ('Asia/Famagusta', 'Asia/Famagusta'), + ('Asia/Gaza', 'Asia/Gaza'), + ('Asia/Hebron', 'Asia/Hebron'), + ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), + ('Asia/Hong_Kong', 'Asia/Hong_Kong'), + ('Asia/Hovd', 'Asia/Hovd'), + ('Asia/Irkutsk', 'Asia/Irkutsk'), + ('Asia/Jakarta', 'Asia/Jakarta'), + ('Asia/Jayapura', 'Asia/Jayapura'), + ('Asia/Jerusalem', 'Asia/Jerusalem'), + ('Asia/Kabul', 'Asia/Kabul'), + ('Asia/Kamchatka', 'Asia/Kamchatka'), + ('Asia/Karachi', 'Asia/Karachi'), + ('Asia/Kathmandu', 'Asia/Kathmandu'), + ('Asia/Khandyga', 'Asia/Khandyga'), + ('Asia/Kolkata', 'Asia/Kolkata'), + ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), + ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), + ('Asia/Kuching', 'Asia/Kuching'), + ('Asia/Kuwait', 'Asia/Kuwait'), + ('Asia/Macau', 'Asia/Macau'), + ('Asia/Magadan', 'Asia/Magadan'), + ('Asia/Makassar', 'Asia/Makassar'), + ('Asia/Manila', 'Asia/Manila'), + ('Asia/Muscat', 'Asia/Muscat'), + ('Asia/Nicosia', 'Asia/Nicosia'), + ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), + ('Asia/Novosibirsk', 'Asia/Novosibirsk'), + ('Asia/Omsk', 'Asia/Omsk'), + ('Asia/Oral', 'Asia/Oral'), + ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), + ('Asia/Pontianak', 'Asia/Pontianak'), + ('Asia/Pyongyang', 'Asia/Pyongyang'), + ('Asia/Qatar', 'Asia/Qatar'), + ('Asia/Qyzylorda', 'Asia/Qyzylorda'), + ('Asia/Riyadh', 'Asia/Riyadh'), + ('Asia/Sakhalin', 'Asia/Sakhalin'), + ('Asia/Samarkand', 'Asia/Samarkand'), + ('Asia/Seoul', 'Asia/Seoul'), + ('Asia/Shanghai', 'Asia/Shanghai'), + ('Asia/Singapore', 'Asia/Singapore'), + ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), + ('Asia/Taipei', 'Asia/Taipei'), + ('Asia/Tashkent', 'Asia/Tashkent'), + ('Asia/Tbilisi', 'Asia/Tbilisi'), + ('Asia/Tehran', 'Asia/Tehran'), + ('Asia/Thimphu', 'Asia/Thimphu'), + ('Asia/Tokyo', 'Asia/Tokyo'), + ('Asia/Tomsk', 'Asia/Tomsk'), + ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), + ('Asia/Urumqi', 'Asia/Urumqi'), + ('Asia/Ust-Nera', 'Asia/Ust-Nera'), + ('Asia/Vientiane', 'Asia/Vientiane'), + ('Asia/Vladivostok', 'Asia/Vladivostok'), + ('Asia/Yakutsk', 'Asia/Yakutsk'), + ('Asia/Yangon', 'Asia/Yangon'), + ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), + ('Asia/Yerevan', 'Asia/Yerevan'), + ('Atlantic/Azores', 'Atlantic/Azores'), + ('Atlantic/Bermuda', 'Atlantic/Bermuda'), + ('Atlantic/Canary', 'Atlantic/Canary'), + ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), + ('Atlantic/Faroe', 'Atlantic/Faroe'), + ('Atlantic/Madeira', 'Atlantic/Madeira'), + ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), + ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), + ('Atlantic/St_Helena', 'Atlantic/St_Helena'), + ('Atlantic/Stanley', 'Atlantic/Stanley'), + ('Australia/Adelaide', 'Australia/Adelaide'), + ('Australia/Brisbane', 'Australia/Brisbane'), + ('Australia/Broken_Hill', 'Australia/Broken_Hill'), + ('Australia/Currie', 'Australia/Currie'), + ('Australia/Darwin', 'Australia/Darwin'), + ('Australia/Eucla', 'Australia/Eucla'), + ('Australia/Hobart', 'Australia/Hobart'), + ('Australia/Lindeman', 'Australia/Lindeman'), + ('Australia/Lord_Howe', 'Australia/Lord_Howe'), + ('Australia/Melbourne', 'Australia/Melbourne'), + ('Australia/Perth', 'Australia/Perth'), + ('Australia/Sydney', 'Australia/Sydney'), + ('Canada/Atlantic', 'Canada/Atlantic'), + ('Canada/Central', 'Canada/Central'), + ('Canada/Eastern', 'Canada/Eastern'), + ('Canada/Mountain', 'Canada/Mountain'), + ('Canada/Newfoundland', 'Canada/Newfoundland'), + ('Canada/Pacific', 'Canada/Pacific'), + ('Europe/Amsterdam', 'Europe/Amsterdam'), + ('Europe/Andorra', 'Europe/Andorra'), + ('Europe/Astrakhan', 'Europe/Astrakhan'), + ('Europe/Athens', 'Europe/Athens'), + ('Europe/Belgrade', 'Europe/Belgrade'), + ('Europe/Berlin', 'Europe/Berlin'), + ('Europe/Bratislava', 'Europe/Bratislava'), + ('Europe/Brussels', 'Europe/Brussels'), + ('Europe/Bucharest', 'Europe/Bucharest'), + ('Europe/Budapest', 'Europe/Budapest'), + ('Europe/Busingen', 'Europe/Busingen'), + ('Europe/Chisinau', 'Europe/Chisinau'), + ('Europe/Copenhagen', 'Europe/Copenhagen'), + ('Europe/Dublin', 'Europe/Dublin'), + ('Europe/Gibraltar', 'Europe/Gibraltar'), + ('Europe/Guernsey', 'Europe/Guernsey'), + ('Europe/Helsinki', 'Europe/Helsinki'), + ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), + ('Europe/Istanbul', 'Europe/Istanbul'), + ('Europe/Jersey', 'Europe/Jersey'), + ('Europe/Kaliningrad', 'Europe/Kaliningrad'), + ('Europe/Kiev', 'Europe/Kiev'), + ('Europe/Kirov', 'Europe/Kirov'), + ('Europe/Lisbon', 'Europe/Lisbon'), + ('Europe/Ljubljana', 'Europe/Ljubljana'), + ('Europe/London', 'Europe/London'), + ('Europe/Luxembourg', 'Europe/Luxembourg'), + ('Europe/Madrid', 'Europe/Madrid'), + ('Europe/Malta', 'Europe/Malta'), + ('Europe/Mariehamn', 'Europe/Mariehamn'), + ('Europe/Minsk', 'Europe/Minsk'), + ('Europe/Monaco', 'Europe/Monaco'), + ('Europe/Moscow', 'Europe/Moscow'), + ('Europe/Oslo', 'Europe/Oslo'), + ('Europe/Paris', 'Europe/Paris'), + ('Europe/Podgorica', 'Europe/Podgorica'), + ('Europe/Prague', 'Europe/Prague'), + ('Europe/Riga', 'Europe/Riga'), + ('Europe/Rome', 'Europe/Rome'), + ('Europe/Samara', 'Europe/Samara'), + ('Europe/San_Marino', 'Europe/San_Marino'), + ('Europe/Sarajevo', 'Europe/Sarajevo'), + ('Europe/Saratov', 'Europe/Saratov'), + ('Europe/Simferopol', 'Europe/Simferopol'), + ('Europe/Skopje', 'Europe/Skopje'), + ('Europe/Sofia', 'Europe/Sofia'), + ('Europe/Stockholm', 'Europe/Stockholm'), + ('Europe/Tallinn', 'Europe/Tallinn'), + ('Europe/Tirane', 'Europe/Tirane'), + ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), + ('Europe/Uzhgorod', 'Europe/Uzhgorod'), + ('Europe/Vaduz', 'Europe/Vaduz'), + ('Europe/Vatican', 'Europe/Vatican'), + ('Europe/Vienna', 'Europe/Vienna'), + ('Europe/Vilnius', 'Europe/Vilnius'), + ('Europe/Volgograd', 'Europe/Volgograd'), + ('Europe/Warsaw', 'Europe/Warsaw'), + ('Europe/Zagreb', 'Europe/Zagreb'), + ('Europe/Zaporozhye', 'Europe/Zaporozhye'), + ('Europe/Zurich', 'Europe/Zurich'), + ('GMT', 'GMT'), + ('Indian/Antananarivo', 'Indian/Antananarivo'), + ('Indian/Chagos', 'Indian/Chagos'), + ('Indian/Christmas', 'Indian/Christmas'), + ('Indian/Cocos', 'Indian/Cocos'), + ('Indian/Comoro', 'Indian/Comoro'), + ('Indian/Kerguelen', 'Indian/Kerguelen'), + ('Indian/Mahe', 'Indian/Mahe'), + ('Indian/Maldives', 'Indian/Maldives'), + ('Indian/Mauritius', 'Indian/Mauritius'), + ('Indian/Mayotte', 'Indian/Mayotte'), + ('Indian/Reunion', 'Indian/Reunion'), + ('Pacific/Apia', 'Pacific/Apia'), + ('Pacific/Auckland', 'Pacific/Auckland'), + ('Pacific/Bougainville', 'Pacific/Bougainville'), + ('Pacific/Chatham', 'Pacific/Chatham'), + ('Pacific/Chuuk', 'Pacific/Chuuk'), + ('Pacific/Easter', 'Pacific/Easter'), + ('Pacific/Efate', 'Pacific/Efate'), + ('Pacific/Enderbury', 'Pacific/Enderbury'), + ('Pacific/Fakaofo', 'Pacific/Fakaofo'), + ('Pacific/Fiji', 'Pacific/Fiji'), + ('Pacific/Funafuti', 'Pacific/Funafuti'), + ('Pacific/Galapagos', 'Pacific/Galapagos'), + ('Pacific/Gambier', 'Pacific/Gambier'), + ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), + ('Pacific/Guam', 'Pacific/Guam'), + ('Pacific/Honolulu', 'Pacific/Honolulu'), + ('Pacific/Kiritimati', 'Pacific/Kiritimati'), + ('Pacific/Kosrae', 'Pacific/Kosrae'), + ('Pacific/Kwajalein', 'Pacific/Kwajalein'), + ('Pacific/Majuro', 'Pacific/Majuro'), + ('Pacific/Marquesas', 'Pacific/Marquesas'), + ('Pacific/Midway', 'Pacific/Midway'), + ('Pacific/Nauru', 'Pacific/Nauru'), + ('Pacific/Niue', 'Pacific/Niue'), + ('Pacific/Norfolk', 'Pacific/Norfolk'), + ('Pacific/Noumea', 'Pacific/Noumea'), + ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), + ('Pacific/Palau', 'Pacific/Palau'), + ('Pacific/Pitcairn', 'Pacific/Pitcairn'), + ('Pacific/Pohnpei', 'Pacific/Pohnpei'), + ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), + ('Pacific/Rarotonga', 'Pacific/Rarotonga'), + ('Pacific/Saipan', 'Pacific/Saipan'), + ('Pacific/Tahiti', 'Pacific/Tahiti'), + ('Pacific/Tarawa', 'Pacific/Tarawa'), + ('Pacific/Tongatapu', 'Pacific/Tongatapu'), + ('Pacific/Wake', 'Pacific/Wake'), + ('Pacific/Wallis', 'Pacific/Wallis'), + ('US/Alaska', 'US/Alaska'), + ('US/Arizona', 'US/Arizona'), + ('US/Central', 'US/Central'), + ('US/Eastern', 'US/Eastern'), + ('US/Hawaii', 'US/Hawaii'), + ('US/Mountain', 'US/Mountain'), + ('US/Pacific', 'US/Pacific'), + ('UTC', 'UTC')], + default=b'UTC', + help_text=b'Used for developer clock page', + max_length=100)), ('alias', models.CharField(help_text='Required field', max_length=50)), ('public_email', models.CharField(help_text='Required field', max_length=50)), ('other_contact', models.CharField(blank=True, max_length=100, null=True)), - ('pgp_key', devel.fields.PGPKeyField(blank=True, help_text='consists of 40 hex digits; use `gpg --fingerprint`', max_length=40, null=True, verbose_name='PGP key fingerprint')), + ('pgp_key', devel.fields.PGPKeyField( + blank=True, help_text='consists of 40 hex digits; use `gpg --fingerprint`', + max_length=40, null=True, verbose_name='PGP key fingerprint')), ('website', models.CharField(blank=True, max_length=200, null=True)), ('yob', models.IntegerField(blank=True, null=True, verbose_name='Year of birth')), ('country', django_countries.fields.CountryField(blank=True, max_length=2)), @@ -82,11 +543,16 @@ class Migration(migrations.Migration): ('occupation', models.CharField(blank=True, max_length=50, null=True)), ('roles', models.CharField(blank=True, max_length=255, null=True)), ('favorite_distros', models.CharField(blank=True, max_length=255, null=True)), - ('picture', models.FileField(default='devs/silhouette.png', help_text='Ideally 125px by 125px', upload_to='devs')), - ('latin_name', models.CharField(blank=True, help_text='Latin-form name; used only for non-Latin full names', max_length=255, null=True)), + ('picture', models.FileField( + default='devs/silhouette.png', help_text='Ideally 125px by 125px', upload_to='devs')), + ('latin_name', models.CharField( + blank=True, help_text='Latin-form name; used only for non-Latin full names', + max_length=255, null=True)), ('last_modified', models.DateTimeField(editable=False)), ('allowed_repos', models.ManyToManyField(blank=True, to='main.Repo')), - ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='userprofile', to=settings.AUTH_USER_MODEL)), + ('user', models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name='userprofile', to=settings.AUTH_USER_MODEL)), ], options={ 'get_latest_by': 'last_modified', diff --git a/devel/migrations/0002_auto_20181216_1605.py b/devel/migrations/0002_auto_20181216_1605.py index 23dd8c6b..9827d0ae 100644 --- a/devel/migrations/0002_auto_20181216_1605.py +++ b/devel/migrations/0002_auto_20181216_1605.py @@ -13,6 +13,447 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='userprofile', name='time_zone', - field=models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Godthab', 'America/Godthab'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Punta_Arenas', 'America/Punta_Arenas'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Atyrau', 'Asia/Atyrau'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Barnaul', 'Asia/Barnaul'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Famagusta', 'Asia/Famagusta'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Tomsk', 'Asia/Tomsk'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yangon', 'Asia/Yangon'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Sydney', 'Australia/Sydney'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Astrakhan', 'Europe/Astrakhan'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Kirov', 'Europe/Kirov'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Saratov', 'Europe/Saratov'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GMT', 'GMT'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('US/Alaska', 'US/Alaska'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('UTC', 'UTC')], default='UTC', help_text='Used for developer clock page', max_length=100), + field=models.CharField( + choices=[ + ('Africa/Abidjan', 'Africa/Abidjan'), + ('Africa/Accra', 'Africa/Accra'), + ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), + ('Africa/Algiers', 'Africa/Algiers'), + ('Africa/Asmara', 'Africa/Asmara'), + ('Africa/Bamako', 'Africa/Bamako'), + ('Africa/Bangui', 'Africa/Bangui'), + ('Africa/Banjul', 'Africa/Banjul'), + ('Africa/Bissau', 'Africa/Bissau'), + ('Africa/Blantyre', 'Africa/Blantyre'), + ('Africa/Brazzaville', 'Africa/Brazzaville'), + ('Africa/Bujumbura', 'Africa/Bujumbura'), + ('Africa/Cairo', 'Africa/Cairo'), + ('Africa/Casablanca', 'Africa/Casablanca'), + ('Africa/Ceuta', 'Africa/Ceuta'), + ('Africa/Conakry', 'Africa/Conakry'), + ('Africa/Dakar', 'Africa/Dakar'), + ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), + ('Africa/Djibouti', 'Africa/Djibouti'), + ('Africa/Douala', 'Africa/Douala'), + ('Africa/El_Aaiun', 'Africa/El_Aaiun'), + ('Africa/Freetown', 'Africa/Freetown'), + ('Africa/Gaborone', 'Africa/Gaborone'), + ('Africa/Harare', 'Africa/Harare'), + ('Africa/Johannesburg', 'Africa/Johannesburg'), + ('Africa/Juba', 'Africa/Juba'), + ('Africa/Kampala', 'Africa/Kampala'), + ('Africa/Khartoum', 'Africa/Khartoum'), + ('Africa/Kigali', 'Africa/Kigali'), + ('Africa/Kinshasa', 'Africa/Kinshasa'), + ('Africa/Lagos', 'Africa/Lagos'), + ('Africa/Libreville', 'Africa/Libreville'), + ('Africa/Lome', 'Africa/Lome'), + ('Africa/Luanda', 'Africa/Luanda'), + ('Africa/Lubumbashi', 'Africa/Lubumbashi'), + ('Africa/Lusaka', 'Africa/Lusaka'), + ('Africa/Malabo', 'Africa/Malabo'), + ('Africa/Maputo', 'Africa/Maputo'), + ('Africa/Maseru', 'Africa/Maseru'), + ('Africa/Mbabane', 'Africa/Mbabane'), + ('Africa/Mogadishu', 'Africa/Mogadishu'), + ('Africa/Monrovia', 'Africa/Monrovia'), + ('Africa/Nairobi', 'Africa/Nairobi'), + ('Africa/Ndjamena', 'Africa/Ndjamena'), + ('Africa/Niamey', 'Africa/Niamey'), + ('Africa/Nouakchott', 'Africa/Nouakchott'), + ('Africa/Ouagadougou', 'Africa/Ouagadougou'), + ('Africa/Porto-Novo', 'Africa/Porto-Novo'), + ('Africa/Sao_Tome', 'Africa/Sao_Tome'), + ('Africa/Tripoli', 'Africa/Tripoli'), + ('Africa/Tunis', 'Africa/Tunis'), + ('Africa/Windhoek', 'Africa/Windhoek'), + ('America/Adak', 'America/Adak'), + ('America/Anchorage', 'America/Anchorage'), + ('America/Anguilla', 'America/Anguilla'), + ('America/Antigua', 'America/Antigua'), + ('America/Araguaina', 'America/Araguaina'), + ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), + ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), + ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), + ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), + ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), + ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), + ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), + ('America/Argentina/Salta', 'America/Argentina/Salta'), + ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), + ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), + ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), + ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), + ('America/Aruba', 'America/Aruba'), + ('America/Asuncion', 'America/Asuncion'), + ('America/Atikokan', 'America/Atikokan'), + ('America/Bahia', 'America/Bahia'), + ('America/Bahia_Banderas', 'America/Bahia_Banderas'), + ('America/Barbados', 'America/Barbados'), + ('America/Belem', 'America/Belem'), + ('America/Belize', 'America/Belize'), + ('America/Blanc-Sablon', 'America/Blanc-Sablon'), + ('America/Boa_Vista', 'America/Boa_Vista'), + ('America/Bogota', 'America/Bogota'), + ('America/Boise', 'America/Boise'), + ('America/Cambridge_Bay', 'America/Cambridge_Bay'), + ('America/Campo_Grande', 'America/Campo_Grande'), + ('America/Cancun', 'America/Cancun'), + ('America/Caracas', 'America/Caracas'), + ('America/Cayenne', 'America/Cayenne'), + ('America/Cayman', 'America/Cayman'), + ('America/Chicago', 'America/Chicago'), + ('America/Chihuahua', 'America/Chihuahua'), + ('America/Costa_Rica', 'America/Costa_Rica'), + ('America/Creston', 'America/Creston'), + ('America/Cuiaba', 'America/Cuiaba'), + ('America/Curacao', 'America/Curacao'), + ('America/Danmarkshavn', 'America/Danmarkshavn'), + ('America/Dawson', 'America/Dawson'), + ('America/Dawson_Creek', 'America/Dawson_Creek'), + ('America/Denver', 'America/Denver'), + ('America/Detroit', 'America/Detroit'), + ('America/Dominica', 'America/Dominica'), + ('America/Edmonton', 'America/Edmonton'), + ('America/Eirunepe', 'America/Eirunepe'), + ('America/El_Salvador', 'America/El_Salvador'), + ('America/Fort_Nelson', 'America/Fort_Nelson'), + ('America/Fortaleza', 'America/Fortaleza'), + ('America/Glace_Bay', 'America/Glace_Bay'), + ('America/Godthab', 'America/Godthab'), + ('America/Goose_Bay', 'America/Goose_Bay'), + ('America/Grand_Turk', 'America/Grand_Turk'), + ('America/Grenada', 'America/Grenada'), + ('America/Guadeloupe', 'America/Guadeloupe'), + ('America/Guatemala', 'America/Guatemala'), + ('America/Guayaquil', 'America/Guayaquil'), + ('America/Guyana', 'America/Guyana'), + ('America/Halifax', 'America/Halifax'), + ('America/Havana', 'America/Havana'), + ('America/Hermosillo', 'America/Hermosillo'), + ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), + ('America/Indiana/Knox', 'America/Indiana/Knox'), + ('America/Indiana/Marengo', 'America/Indiana/Marengo'), + ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), + ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), + ('America/Indiana/Vevay', 'America/Indiana/Vevay'), + ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), + ('America/Indiana/Winamac', 'America/Indiana/Winamac'), + ('America/Inuvik', 'America/Inuvik'), + ('America/Iqaluit', 'America/Iqaluit'), + ('America/Jamaica', 'America/Jamaica'), + ('America/Juneau', 'America/Juneau'), + ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), + ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), + ('America/Kralendijk', 'America/Kralendijk'), + ('America/La_Paz', 'America/La_Paz'), + ('America/Lima', 'America/Lima'), + ('America/Los_Angeles', 'America/Los_Angeles'), + ('America/Lower_Princes', 'America/Lower_Princes'), + ('America/Maceio', 'America/Maceio'), + ('America/Managua', 'America/Managua'), + ('America/Manaus', 'America/Manaus'), + ('America/Marigot', 'America/Marigot'), + ('America/Martinique', 'America/Martinique'), + ('America/Matamoros', 'America/Matamoros'), + ('America/Mazatlan', 'America/Mazatlan'), + ('America/Menominee', 'America/Menominee'), + ('America/Merida', 'America/Merida'), + ('America/Metlakatla', 'America/Metlakatla'), + ('America/Mexico_City', 'America/Mexico_City'), + ('America/Miquelon', 'America/Miquelon'), + ('America/Moncton', 'America/Moncton'), + ('America/Monterrey', 'America/Monterrey'), + ('America/Montevideo', 'America/Montevideo'), + ('America/Montserrat', 'America/Montserrat'), + ('America/Nassau', 'America/Nassau'), + ('America/New_York', 'America/New_York'), + ('America/Nipigon', 'America/Nipigon'), + ('America/Nome', 'America/Nome'), + ('America/Noronha', 'America/Noronha'), + ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), + ('America/North_Dakota/Center', 'America/North_Dakota/Center'), + ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), + ('America/Ojinaga', 'America/Ojinaga'), + ('America/Panama', 'America/Panama'), + ('America/Pangnirtung', 'America/Pangnirtung'), + ('America/Paramaribo', 'America/Paramaribo'), + ('America/Phoenix', 'America/Phoenix'), + ('America/Port-au-Prince', 'America/Port-au-Prince'), + ('America/Port_of_Spain', 'America/Port_of_Spain'), + ('America/Porto_Velho', 'America/Porto_Velho'), + ('America/Puerto_Rico', 'America/Puerto_Rico'), + ('America/Punta_Arenas', 'America/Punta_Arenas'), + ('America/Rainy_River', 'America/Rainy_River'), + ('America/Rankin_Inlet', 'America/Rankin_Inlet'), + ('America/Recife', 'America/Recife'), + ('America/Regina', 'America/Regina'), + ('America/Resolute', 'America/Resolute'), + ('America/Rio_Branco', 'America/Rio_Branco'), + ('America/Santarem', 'America/Santarem'), + ('America/Santiago', 'America/Santiago'), + ('America/Santo_Domingo', 'America/Santo_Domingo'), + ('America/Sao_Paulo', 'America/Sao_Paulo'), + ('America/Scoresbysund', 'America/Scoresbysund'), + ('America/Sitka', 'America/Sitka'), + ('America/St_Barthelemy', 'America/St_Barthelemy'), + ('America/St_Johns', 'America/St_Johns'), + ('America/St_Kitts', 'America/St_Kitts'), + ('America/St_Lucia', 'America/St_Lucia'), + ('America/St_Thomas', 'America/St_Thomas'), + ('America/St_Vincent', 'America/St_Vincent'), + ('America/Swift_Current', 'America/Swift_Current'), + ('America/Tegucigalpa', 'America/Tegucigalpa'), + ('America/Thule', 'America/Thule'), + ('America/Thunder_Bay', 'America/Thunder_Bay'), + ('America/Tijuana', 'America/Tijuana'), + ('America/Toronto', 'America/Toronto'), + ('America/Tortola', 'America/Tortola'), + ('America/Vancouver', 'America/Vancouver'), + ('America/Whitehorse', 'America/Whitehorse'), + ('America/Winnipeg', 'America/Winnipeg'), + ('America/Yakutat', 'America/Yakutat'), + ('America/Yellowknife', 'America/Yellowknife'), + ('Antarctica/Casey', 'Antarctica/Casey'), + ('Antarctica/Davis', 'Antarctica/Davis'), + ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), + ('Antarctica/Macquarie', 'Antarctica/Macquarie'), + ('Antarctica/Mawson', 'Antarctica/Mawson'), + ('Antarctica/McMurdo', 'Antarctica/McMurdo'), + ('Antarctica/Palmer', 'Antarctica/Palmer'), + ('Antarctica/Rothera', 'Antarctica/Rothera'), + ('Antarctica/Syowa', 'Antarctica/Syowa'), + ('Antarctica/Troll', 'Antarctica/Troll'), + ('Antarctica/Vostok', 'Antarctica/Vostok'), + ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), + ('Asia/Aden', 'Asia/Aden'), + ('Asia/Almaty', 'Asia/Almaty'), + ('Asia/Amman', 'Asia/Amman'), + ('Asia/Anadyr', 'Asia/Anadyr'), + ('Asia/Aqtau', 'Asia/Aqtau'), + ('Asia/Aqtobe', 'Asia/Aqtobe'), + ('Asia/Ashgabat', 'Asia/Ashgabat'), + ('Asia/Atyrau', 'Asia/Atyrau'), + ('Asia/Baghdad', 'Asia/Baghdad'), + ('Asia/Bahrain', 'Asia/Bahrain'), + ('Asia/Baku', 'Asia/Baku'), + ('Asia/Bangkok', 'Asia/Bangkok'), + ('Asia/Barnaul', 'Asia/Barnaul'), + ('Asia/Beirut', 'Asia/Beirut'), + ('Asia/Bishkek', 'Asia/Bishkek'), + ('Asia/Brunei', 'Asia/Brunei'), + ('Asia/Chita', 'Asia/Chita'), + ('Asia/Choibalsan', 'Asia/Choibalsan'), + ('Asia/Colombo', 'Asia/Colombo'), + ('Asia/Damascus', 'Asia/Damascus'), + ('Asia/Dhaka', 'Asia/Dhaka'), + ('Asia/Dili', 'Asia/Dili'), + ('Asia/Dubai', 'Asia/Dubai'), + ('Asia/Dushanbe', 'Asia/Dushanbe'), + ('Asia/Famagusta', 'Asia/Famagusta'), + ('Asia/Gaza', 'Asia/Gaza'), + ('Asia/Hebron', 'Asia/Hebron'), + ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), + ('Asia/Hong_Kong', 'Asia/Hong_Kong'), + ('Asia/Hovd', 'Asia/Hovd'), + ('Asia/Irkutsk', 'Asia/Irkutsk'), + ('Asia/Jakarta', 'Asia/Jakarta'), + ('Asia/Jayapura', 'Asia/Jayapura'), + ('Asia/Jerusalem', 'Asia/Jerusalem'), + ('Asia/Kabul', 'Asia/Kabul'), + ('Asia/Kamchatka', 'Asia/Kamchatka'), + ('Asia/Karachi', 'Asia/Karachi'), + ('Asia/Kathmandu', 'Asia/Kathmandu'), + ('Asia/Khandyga', 'Asia/Khandyga'), + ('Asia/Kolkata', 'Asia/Kolkata'), + ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), + ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), + ('Asia/Kuching', 'Asia/Kuching'), + ('Asia/Kuwait', 'Asia/Kuwait'), + ('Asia/Macau', 'Asia/Macau'), + ('Asia/Magadan', 'Asia/Magadan'), + ('Asia/Makassar', 'Asia/Makassar'), + ('Asia/Manila', 'Asia/Manila'), + ('Asia/Muscat', 'Asia/Muscat'), + ('Asia/Nicosia', 'Asia/Nicosia'), + ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), + ('Asia/Novosibirsk', 'Asia/Novosibirsk'), + ('Asia/Omsk', 'Asia/Omsk'), + ('Asia/Oral', 'Asia/Oral'), + ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), + ('Asia/Pontianak', 'Asia/Pontianak'), + ('Asia/Pyongyang', 'Asia/Pyongyang'), + ('Asia/Qatar', 'Asia/Qatar'), + ('Asia/Qyzylorda', 'Asia/Qyzylorda'), + ('Asia/Riyadh', 'Asia/Riyadh'), + ('Asia/Sakhalin', 'Asia/Sakhalin'), + ('Asia/Samarkand', 'Asia/Samarkand'), + ('Asia/Seoul', 'Asia/Seoul'), + ('Asia/Shanghai', 'Asia/Shanghai'), + ('Asia/Singapore', 'Asia/Singapore'), + ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), + ('Asia/Taipei', 'Asia/Taipei'), + ('Asia/Tashkent', 'Asia/Tashkent'), + ('Asia/Tbilisi', 'Asia/Tbilisi'), + ('Asia/Tehran', 'Asia/Tehran'), + ('Asia/Thimphu', 'Asia/Thimphu'), + ('Asia/Tokyo', 'Asia/Tokyo'), + ('Asia/Tomsk', 'Asia/Tomsk'), + ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), + ('Asia/Urumqi', 'Asia/Urumqi'), + ('Asia/Ust-Nera', 'Asia/Ust-Nera'), + ('Asia/Vientiane', 'Asia/Vientiane'), + ('Asia/Vladivostok', 'Asia/Vladivostok'), + ('Asia/Yakutsk', 'Asia/Yakutsk'), + ('Asia/Yangon', 'Asia/Yangon'), + ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), + ('Asia/Yerevan', 'Asia/Yerevan'), + ('Atlantic/Azores', 'Atlantic/Azores'), + ('Atlantic/Bermuda', 'Atlantic/Bermuda'), + ('Atlantic/Canary', 'Atlantic/Canary'), + ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), + ('Atlantic/Faroe', 'Atlantic/Faroe'), + ('Atlantic/Madeira', 'Atlantic/Madeira'), + ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), + ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), + ('Atlantic/St_Helena', 'Atlantic/St_Helena'), + ('Atlantic/Stanley', 'Atlantic/Stanley'), + ('Australia/Adelaide', 'Australia/Adelaide'), + ('Australia/Brisbane', 'Australia/Brisbane'), + ('Australia/Broken_Hill', 'Australia/Broken_Hill'), + ('Australia/Currie', 'Australia/Currie'), + ('Australia/Darwin', 'Australia/Darwin'), + ('Australia/Eucla', 'Australia/Eucla'), + ('Australia/Hobart', 'Australia/Hobart'), + ('Australia/Lindeman', 'Australia/Lindeman'), + ('Australia/Lord_Howe', 'Australia/Lord_Howe'), + ('Australia/Melbourne', 'Australia/Melbourne'), + ('Australia/Perth', 'Australia/Perth'), + ('Australia/Sydney', 'Australia/Sydney'), + ('Canada/Atlantic', 'Canada/Atlantic'), + ('Canada/Central', 'Canada/Central'), + ('Canada/Eastern', 'Canada/Eastern'), + ('Canada/Mountain', 'Canada/Mountain'), + ('Canada/Newfoundland', 'Canada/Newfoundland'), + ('Canada/Pacific', 'Canada/Pacific'), + ('Europe/Amsterdam', 'Europe/Amsterdam'), + ('Europe/Andorra', 'Europe/Andorra'), + ('Europe/Astrakhan', 'Europe/Astrakhan'), + ('Europe/Athens', 'Europe/Athens'), + ('Europe/Belgrade', 'Europe/Belgrade'), + ('Europe/Berlin', 'Europe/Berlin'), + ('Europe/Bratislava', 'Europe/Bratislava'), + ('Europe/Brussels', 'Europe/Brussels'), + ('Europe/Bucharest', 'Europe/Bucharest'), + ('Europe/Budapest', 'Europe/Budapest'), + ('Europe/Busingen', 'Europe/Busingen'), + ('Europe/Chisinau', 'Europe/Chisinau'), + ('Europe/Copenhagen', 'Europe/Copenhagen'), + ('Europe/Dublin', 'Europe/Dublin'), + ('Europe/Gibraltar', 'Europe/Gibraltar'), + ('Europe/Guernsey', 'Europe/Guernsey'), + ('Europe/Helsinki', 'Europe/Helsinki'), + ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), + ('Europe/Istanbul', 'Europe/Istanbul'), + ('Europe/Jersey', 'Europe/Jersey'), + ('Europe/Kaliningrad', 'Europe/Kaliningrad'), + ('Europe/Kiev', 'Europe/Kiev'), + ('Europe/Kirov', 'Europe/Kirov'), + ('Europe/Lisbon', 'Europe/Lisbon'), + ('Europe/Ljubljana', 'Europe/Ljubljana'), + ('Europe/London', 'Europe/London'), + ('Europe/Luxembourg', 'Europe/Luxembourg'), + ('Europe/Madrid', 'Europe/Madrid'), + ('Europe/Malta', 'Europe/Malta'), + ('Europe/Mariehamn', 'Europe/Mariehamn'), + ('Europe/Minsk', 'Europe/Minsk'), + ('Europe/Monaco', 'Europe/Monaco'), + ('Europe/Moscow', 'Europe/Moscow'), + ('Europe/Oslo', 'Europe/Oslo'), + ('Europe/Paris', 'Europe/Paris'), + ('Europe/Podgorica', 'Europe/Podgorica'), + ('Europe/Prague', 'Europe/Prague'), + ('Europe/Riga', 'Europe/Riga'), + ('Europe/Rome', 'Europe/Rome'), + ('Europe/Samara', 'Europe/Samara'), + ('Europe/San_Marino', 'Europe/San_Marino'), + ('Europe/Sarajevo', 'Europe/Sarajevo'), + ('Europe/Saratov', 'Europe/Saratov'), + ('Europe/Simferopol', 'Europe/Simferopol'), + ('Europe/Skopje', 'Europe/Skopje'), + ('Europe/Sofia', 'Europe/Sofia'), + ('Europe/Stockholm', 'Europe/Stockholm'), + ('Europe/Tallinn', 'Europe/Tallinn'), + ('Europe/Tirane', 'Europe/Tirane'), + ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), + ('Europe/Uzhgorod', 'Europe/Uzhgorod'), + ('Europe/Vaduz', 'Europe/Vaduz'), + ('Europe/Vatican', 'Europe/Vatican'), + ('Europe/Vienna', 'Europe/Vienna'), + ('Europe/Vilnius', 'Europe/Vilnius'), + ('Europe/Volgograd', 'Europe/Volgograd'), + ('Europe/Warsaw', 'Europe/Warsaw'), + ('Europe/Zagreb', 'Europe/Zagreb'), + ('Europe/Zaporozhye', 'Europe/Zaporozhye'), + ('Europe/Zurich', 'Europe/Zurich'), + ('GMT', 'GMT'), + ('Indian/Antananarivo', 'Indian/Antananarivo'), + ('Indian/Chagos', 'Indian/Chagos'), + ('Indian/Christmas', 'Indian/Christmas'), + ('Indian/Cocos', 'Indian/Cocos'), + ('Indian/Comoro', 'Indian/Comoro'), + ('Indian/Kerguelen', 'Indian/Kerguelen'), + ('Indian/Mahe', 'Indian/Mahe'), + ('Indian/Maldives', 'Indian/Maldives'), + ('Indian/Mauritius', 'Indian/Mauritius'), + ('Indian/Mayotte', 'Indian/Mayotte'), + ('Indian/Reunion', 'Indian/Reunion'), + ('Pacific/Apia', 'Pacific/Apia'), + ('Pacific/Auckland', 'Pacific/Auckland'), + ('Pacific/Bougainville', 'Pacific/Bougainville'), + ('Pacific/Chatham', 'Pacific/Chatham'), + ('Pacific/Chuuk', 'Pacific/Chuuk'), + ('Pacific/Easter', 'Pacific/Easter'), + ('Pacific/Efate', 'Pacific/Efate'), + ('Pacific/Enderbury', 'Pacific/Enderbury'), + ('Pacific/Fakaofo', 'Pacific/Fakaofo'), + ('Pacific/Fiji', 'Pacific/Fiji'), + ('Pacific/Funafuti', 'Pacific/Funafuti'), + ('Pacific/Galapagos', 'Pacific/Galapagos'), + ('Pacific/Gambier', 'Pacific/Gambier'), + ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), + ('Pacific/Guam', 'Pacific/Guam'), + ('Pacific/Honolulu', 'Pacific/Honolulu'), + ('Pacific/Kiritimati', 'Pacific/Kiritimati'), + ('Pacific/Kosrae', 'Pacific/Kosrae'), + ('Pacific/Kwajalein', 'Pacific/Kwajalein'), + ('Pacific/Majuro', 'Pacific/Majuro'), + ('Pacific/Marquesas', 'Pacific/Marquesas'), + ('Pacific/Midway', 'Pacific/Midway'), + ('Pacific/Nauru', 'Pacific/Nauru'), + ('Pacific/Niue', 'Pacific/Niue'), + ('Pacific/Norfolk', 'Pacific/Norfolk'), + ('Pacific/Noumea', 'Pacific/Noumea'), + ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), + ('Pacific/Palau', 'Pacific/Palau'), + ('Pacific/Pitcairn', 'Pacific/Pitcairn'), + ('Pacific/Pohnpei', 'Pacific/Pohnpei'), + ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), + ('Pacific/Rarotonga', 'Pacific/Rarotonga'), + ('Pacific/Saipan', 'Pacific/Saipan'), + ('Pacific/Tahiti', 'Pacific/Tahiti'), + ('Pacific/Tarawa', 'Pacific/Tarawa'), + ('Pacific/Tongatapu', 'Pacific/Tongatapu'), + ('Pacific/Wake', 'Pacific/Wake'), + ('Pacific/Wallis', 'Pacific/Wallis'), + ('US/Alaska', 'US/Alaska'), + ('US/Arizona', 'US/Arizona'), + ('US/Central', 'US/Central'), + ('US/Eastern', 'US/Eastern'), + ('US/Hawaii', 'US/Hawaii'), + ('US/Mountain', 'US/Mountain'), + ('US/Pacific', 'US/Pacific'), + ('UTC', 'UTC')], + default='UTC', help_text='Used for developer clock page', max_length=100), ), ] diff --git a/devel/migrations/0003_auto_20191009_1924.py b/devel/migrations/0003_auto_20191009_1924.py index e292a877..2581dacd 100644 --- a/devel/migrations/0003_auto_20191009_1924.py +++ b/devel/migrations/0003_auto_20191009_1924.py @@ -13,6 +13,448 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='userprofile', name='time_zone', - field=models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Godthab', 'America/Godthab'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Punta_Arenas', 'America/Punta_Arenas'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Atyrau', 'Asia/Atyrau'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Barnaul', 'Asia/Barnaul'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Famagusta', 'Asia/Famagusta'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qostanay', 'Asia/Qostanay'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Tomsk', 'Asia/Tomsk'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yangon', 'Asia/Yangon'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Sydney', 'Australia/Sydney'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Astrakhan', 'Europe/Astrakhan'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Kirov', 'Europe/Kirov'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Saratov', 'Europe/Saratov'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GMT', 'GMT'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('US/Alaska', 'US/Alaska'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('UTC', 'UTC')], default='UTC', help_text='Used for developer clock page', max_length=100), + field=models.CharField( + choices=[ + ('Africa/Abidjan', 'Africa/Abidjan'), + ('Africa/Accra', 'Africa/Accra'), + ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), + ('Africa/Algiers', 'Africa/Algiers'), + ('Africa/Asmara', 'Africa/Asmara'), + ('Africa/Bamako', 'Africa/Bamako'), + ('Africa/Bangui', 'Africa/Bangui'), + ('Africa/Banjul', 'Africa/Banjul'), + ('Africa/Bissau', 'Africa/Bissau'), + ('Africa/Blantyre', 'Africa/Blantyre'), + ('Africa/Brazzaville', 'Africa/Brazzaville'), + ('Africa/Bujumbura', 'Africa/Bujumbura'), + ('Africa/Cairo', 'Africa/Cairo'), + ('Africa/Casablanca', 'Africa/Casablanca'), + ('Africa/Ceuta', 'Africa/Ceuta'), + ('Africa/Conakry', 'Africa/Conakry'), + ('Africa/Dakar', 'Africa/Dakar'), + ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), + ('Africa/Djibouti', 'Africa/Djibouti'), + ('Africa/Douala', 'Africa/Douala'), + ('Africa/El_Aaiun', 'Africa/El_Aaiun'), + ('Africa/Freetown', 'Africa/Freetown'), + ('Africa/Gaborone', 'Africa/Gaborone'), + ('Africa/Harare', 'Africa/Harare'), + ('Africa/Johannesburg', 'Africa/Johannesburg'), + ('Africa/Juba', 'Africa/Juba'), + ('Africa/Kampala', 'Africa/Kampala'), + ('Africa/Khartoum', 'Africa/Khartoum'), + ('Africa/Kigali', 'Africa/Kigali'), + ('Africa/Kinshasa', 'Africa/Kinshasa'), + ('Africa/Lagos', 'Africa/Lagos'), + ('Africa/Libreville', 'Africa/Libreville'), + ('Africa/Lome', 'Africa/Lome'), + ('Africa/Luanda', 'Africa/Luanda'), + ('Africa/Lubumbashi', 'Africa/Lubumbashi'), + ('Africa/Lusaka', 'Africa/Lusaka'), + ('Africa/Malabo', 'Africa/Malabo'), + ('Africa/Maputo', 'Africa/Maputo'), + ('Africa/Maseru', 'Africa/Maseru'), + ('Africa/Mbabane', 'Africa/Mbabane'), + ('Africa/Mogadishu', 'Africa/Mogadishu'), + ('Africa/Monrovia', 'Africa/Monrovia'), + ('Africa/Nairobi', 'Africa/Nairobi'), + ('Africa/Ndjamena', 'Africa/Ndjamena'), + ('Africa/Niamey', 'Africa/Niamey'), + ('Africa/Nouakchott', 'Africa/Nouakchott'), + ('Africa/Ouagadougou', 'Africa/Ouagadougou'), + ('Africa/Porto-Novo', 'Africa/Porto-Novo'), + ('Africa/Sao_Tome', 'Africa/Sao_Tome'), + ('Africa/Tripoli', 'Africa/Tripoli'), + ('Africa/Tunis', 'Africa/Tunis'), + ('Africa/Windhoek', 'Africa/Windhoek'), + ('America/Adak', 'America/Adak'), + ('America/Anchorage', 'America/Anchorage'), + ('America/Anguilla', 'America/Anguilla'), + ('America/Antigua', 'America/Antigua'), + ('America/Araguaina', 'America/Araguaina'), + ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), + ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), + ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), + ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), + ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), + ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), + ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), + ('America/Argentina/Salta', 'America/Argentina/Salta'), + ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), + ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), + ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), + ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), + ('America/Aruba', 'America/Aruba'), + ('America/Asuncion', 'America/Asuncion'), + ('America/Atikokan', 'America/Atikokan'), + ('America/Bahia', 'America/Bahia'), + ('America/Bahia_Banderas', 'America/Bahia_Banderas'), + ('America/Barbados', 'America/Barbados'), + ('America/Belem', 'America/Belem'), + ('America/Belize', 'America/Belize'), + ('America/Blanc-Sablon', 'America/Blanc-Sablon'), + ('America/Boa_Vista', 'America/Boa_Vista'), + ('America/Bogota', 'America/Bogota'), + ('America/Boise', 'America/Boise'), + ('America/Cambridge_Bay', 'America/Cambridge_Bay'), + ('America/Campo_Grande', 'America/Campo_Grande'), + ('America/Cancun', 'America/Cancun'), + ('America/Caracas', 'America/Caracas'), + ('America/Cayenne', 'America/Cayenne'), + ('America/Cayman', 'America/Cayman'), + ('America/Chicago', 'America/Chicago'), + ('America/Chihuahua', 'America/Chihuahua'), + ('America/Costa_Rica', 'America/Costa_Rica'), + ('America/Creston', 'America/Creston'), + ('America/Cuiaba', 'America/Cuiaba'), + ('America/Curacao', 'America/Curacao'), + ('America/Danmarkshavn', 'America/Danmarkshavn'), + ('America/Dawson', 'America/Dawson'), + ('America/Dawson_Creek', 'America/Dawson_Creek'), + ('America/Denver', 'America/Denver'), + ('America/Detroit', 'America/Detroit'), + ('America/Dominica', 'America/Dominica'), + ('America/Edmonton', 'America/Edmonton'), + ('America/Eirunepe', 'America/Eirunepe'), + ('America/El_Salvador', 'America/El_Salvador'), + ('America/Fort_Nelson', 'America/Fort_Nelson'), + ('America/Fortaleza', 'America/Fortaleza'), + ('America/Glace_Bay', 'America/Glace_Bay'), + ('America/Godthab', 'America/Godthab'), + ('America/Goose_Bay', 'America/Goose_Bay'), + ('America/Grand_Turk', 'America/Grand_Turk'), + ('America/Grenada', 'America/Grenada'), + ('America/Guadeloupe', 'America/Guadeloupe'), + ('America/Guatemala', 'America/Guatemala'), + ('America/Guayaquil', 'America/Guayaquil'), + ('America/Guyana', 'America/Guyana'), + ('America/Halifax', 'America/Halifax'), + ('America/Havana', 'America/Havana'), + ('America/Hermosillo', 'America/Hermosillo'), + ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), + ('America/Indiana/Knox', 'America/Indiana/Knox'), + ('America/Indiana/Marengo', 'America/Indiana/Marengo'), + ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), + ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), + ('America/Indiana/Vevay', 'America/Indiana/Vevay'), + ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), + ('America/Indiana/Winamac', 'America/Indiana/Winamac'), + ('America/Inuvik', 'America/Inuvik'), + ('America/Iqaluit', 'America/Iqaluit'), + ('America/Jamaica', 'America/Jamaica'), + ('America/Juneau', 'America/Juneau'), + ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), + ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), + ('America/Kralendijk', 'America/Kralendijk'), + ('America/La_Paz', 'America/La_Paz'), + ('America/Lima', 'America/Lima'), + ('America/Los_Angeles', 'America/Los_Angeles'), + ('America/Lower_Princes', 'America/Lower_Princes'), + ('America/Maceio', 'America/Maceio'), + ('America/Managua', 'America/Managua'), + ('America/Manaus', 'America/Manaus'), + ('America/Marigot', 'America/Marigot'), + ('America/Martinique', 'America/Martinique'), + ('America/Matamoros', 'America/Matamoros'), + ('America/Mazatlan', 'America/Mazatlan'), + ('America/Menominee', 'America/Menominee'), + ('America/Merida', 'America/Merida'), + ('America/Metlakatla', 'America/Metlakatla'), + ('America/Mexico_City', 'America/Mexico_City'), + ('America/Miquelon', 'America/Miquelon'), + ('America/Moncton', 'America/Moncton'), + ('America/Monterrey', 'America/Monterrey'), + ('America/Montevideo', 'America/Montevideo'), + ('America/Montserrat', 'America/Montserrat'), + ('America/Nassau', 'America/Nassau'), + ('America/New_York', 'America/New_York'), + ('America/Nipigon', 'America/Nipigon'), + ('America/Nome', 'America/Nome'), + ('America/Noronha', 'America/Noronha'), + ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), + ('America/North_Dakota/Center', 'America/North_Dakota/Center'), + ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), + ('America/Ojinaga', 'America/Ojinaga'), + ('America/Panama', 'America/Panama'), + ('America/Pangnirtung', 'America/Pangnirtung'), + ('America/Paramaribo', 'America/Paramaribo'), + ('America/Phoenix', 'America/Phoenix'), + ('America/Port-au-Prince', 'America/Port-au-Prince'), + ('America/Port_of_Spain', 'America/Port_of_Spain'), + ('America/Porto_Velho', 'America/Porto_Velho'), + ('America/Puerto_Rico', 'America/Puerto_Rico'), + ('America/Punta_Arenas', 'America/Punta_Arenas'), + ('America/Rainy_River', 'America/Rainy_River'), + ('America/Rankin_Inlet', 'America/Rankin_Inlet'), + ('America/Recife', 'America/Recife'), + ('America/Regina', 'America/Regina'), + ('America/Resolute', 'America/Resolute'), + ('America/Rio_Branco', 'America/Rio_Branco'), + ('America/Santarem', 'America/Santarem'), + ('America/Santiago', 'America/Santiago'), + ('America/Santo_Domingo', 'America/Santo_Domingo'), + ('America/Sao_Paulo', 'America/Sao_Paulo'), + ('America/Scoresbysund', 'America/Scoresbysund'), + ('America/Sitka', 'America/Sitka'), + ('America/St_Barthelemy', 'America/St_Barthelemy'), + ('America/St_Johns', 'America/St_Johns'), + ('America/St_Kitts', 'America/St_Kitts'), + ('America/St_Lucia', 'America/St_Lucia'), + ('America/St_Thomas', 'America/St_Thomas'), + ('America/St_Vincent', 'America/St_Vincent'), + ('America/Swift_Current', 'America/Swift_Current'), + ('America/Tegucigalpa', 'America/Tegucigalpa'), + ('America/Thule', 'America/Thule'), + ('America/Thunder_Bay', 'America/Thunder_Bay'), + ('America/Tijuana', 'America/Tijuana'), + ('America/Toronto', 'America/Toronto'), + ('America/Tortola', 'America/Tortola'), + ('America/Vancouver', 'America/Vancouver'), + ('America/Whitehorse', 'America/Whitehorse'), + ('America/Winnipeg', 'America/Winnipeg'), + ('America/Yakutat', 'America/Yakutat'), + ('America/Yellowknife', 'America/Yellowknife'), + ('Antarctica/Casey', 'Antarctica/Casey'), + ('Antarctica/Davis', 'Antarctica/Davis'), + ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), + ('Antarctica/Macquarie', 'Antarctica/Macquarie'), + ('Antarctica/Mawson', 'Antarctica/Mawson'), + ('Antarctica/McMurdo', 'Antarctica/McMurdo'), + ('Antarctica/Palmer', 'Antarctica/Palmer'), + ('Antarctica/Rothera', 'Antarctica/Rothera'), + ('Antarctica/Syowa', 'Antarctica/Syowa'), + ('Antarctica/Troll', 'Antarctica/Troll'), + ('Antarctica/Vostok', 'Antarctica/Vostok'), + ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), + ('Asia/Aden', 'Asia/Aden'), + ('Asia/Almaty', 'Asia/Almaty'), + ('Asia/Amman', 'Asia/Amman'), + ('Asia/Anadyr', 'Asia/Anadyr'), + ('Asia/Aqtau', 'Asia/Aqtau'), + ('Asia/Aqtobe', 'Asia/Aqtobe'), + ('Asia/Ashgabat', 'Asia/Ashgabat'), + ('Asia/Atyrau', 'Asia/Atyrau'), + ('Asia/Baghdad', 'Asia/Baghdad'), + ('Asia/Bahrain', 'Asia/Bahrain'), + ('Asia/Baku', 'Asia/Baku'), + ('Asia/Bangkok', 'Asia/Bangkok'), + ('Asia/Barnaul', 'Asia/Barnaul'), + ('Asia/Beirut', 'Asia/Beirut'), + ('Asia/Bishkek', 'Asia/Bishkek'), + ('Asia/Brunei', 'Asia/Brunei'), + ('Asia/Chita', 'Asia/Chita'), + ('Asia/Choibalsan', 'Asia/Choibalsan'), + ('Asia/Colombo', 'Asia/Colombo'), + ('Asia/Damascus', 'Asia/Damascus'), + ('Asia/Dhaka', 'Asia/Dhaka'), + ('Asia/Dili', 'Asia/Dili'), + ('Asia/Dubai', 'Asia/Dubai'), + ('Asia/Dushanbe', 'Asia/Dushanbe'), + ('Asia/Famagusta', 'Asia/Famagusta'), + ('Asia/Gaza', 'Asia/Gaza'), + ('Asia/Hebron', 'Asia/Hebron'), + ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), + ('Asia/Hong_Kong', 'Asia/Hong_Kong'), + ('Asia/Hovd', 'Asia/Hovd'), + ('Asia/Irkutsk', 'Asia/Irkutsk'), + ('Asia/Jakarta', 'Asia/Jakarta'), + ('Asia/Jayapura', 'Asia/Jayapura'), + ('Asia/Jerusalem', 'Asia/Jerusalem'), + ('Asia/Kabul', 'Asia/Kabul'), + ('Asia/Kamchatka', 'Asia/Kamchatka'), + ('Asia/Karachi', 'Asia/Karachi'), + ('Asia/Kathmandu', 'Asia/Kathmandu'), + ('Asia/Khandyga', 'Asia/Khandyga'), + ('Asia/Kolkata', 'Asia/Kolkata'), + ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), + ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), + ('Asia/Kuching', 'Asia/Kuching'), + ('Asia/Kuwait', 'Asia/Kuwait'), + ('Asia/Macau', 'Asia/Macau'), + ('Asia/Magadan', 'Asia/Magadan'), + ('Asia/Makassar', 'Asia/Makassar'), + ('Asia/Manila', 'Asia/Manila'), + ('Asia/Muscat', 'Asia/Muscat'), + ('Asia/Nicosia', 'Asia/Nicosia'), + ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), + ('Asia/Novosibirsk', 'Asia/Novosibirsk'), + ('Asia/Omsk', 'Asia/Omsk'), + ('Asia/Oral', 'Asia/Oral'), + ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), + ('Asia/Pontianak', 'Asia/Pontianak'), + ('Asia/Pyongyang', 'Asia/Pyongyang'), + ('Asia/Qatar', 'Asia/Qatar'), + ('Asia/Qostanay', 'Asia/Qostanay'), + ('Asia/Qyzylorda', 'Asia/Qyzylorda'), + ('Asia/Riyadh', 'Asia/Riyadh'), + ('Asia/Sakhalin', 'Asia/Sakhalin'), + ('Asia/Samarkand', 'Asia/Samarkand'), + ('Asia/Seoul', 'Asia/Seoul'), + ('Asia/Shanghai', 'Asia/Shanghai'), + ('Asia/Singapore', 'Asia/Singapore'), + ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), + ('Asia/Taipei', 'Asia/Taipei'), + ('Asia/Tashkent', 'Asia/Tashkent'), + ('Asia/Tbilisi', 'Asia/Tbilisi'), + ('Asia/Tehran', 'Asia/Tehran'), + ('Asia/Thimphu', 'Asia/Thimphu'), + ('Asia/Tokyo', 'Asia/Tokyo'), + ('Asia/Tomsk', 'Asia/Tomsk'), + ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), + ('Asia/Urumqi', 'Asia/Urumqi'), + ('Asia/Ust-Nera', 'Asia/Ust-Nera'), + ('Asia/Vientiane', 'Asia/Vientiane'), + ('Asia/Vladivostok', 'Asia/Vladivostok'), + ('Asia/Yakutsk', 'Asia/Yakutsk'), + ('Asia/Yangon', 'Asia/Yangon'), + ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), + ('Asia/Yerevan', 'Asia/Yerevan'), + ('Atlantic/Azores', 'Atlantic/Azores'), + ('Atlantic/Bermuda', 'Atlantic/Bermuda'), + ('Atlantic/Canary', 'Atlantic/Canary'), + ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), + ('Atlantic/Faroe', 'Atlantic/Faroe'), + ('Atlantic/Madeira', 'Atlantic/Madeira'), + ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), + ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), + ('Atlantic/St_Helena', 'Atlantic/St_Helena'), + ('Atlantic/Stanley', 'Atlantic/Stanley'), + ('Australia/Adelaide', 'Australia/Adelaide'), + ('Australia/Brisbane', 'Australia/Brisbane'), + ('Australia/Broken_Hill', 'Australia/Broken_Hill'), + ('Australia/Currie', 'Australia/Currie'), + ('Australia/Darwin', 'Australia/Darwin'), + ('Australia/Eucla', 'Australia/Eucla'), + ('Australia/Hobart', 'Australia/Hobart'), + ('Australia/Lindeman', 'Australia/Lindeman'), + ('Australia/Lord_Howe', 'Australia/Lord_Howe'), + ('Australia/Melbourne', 'Australia/Melbourne'), + ('Australia/Perth', 'Australia/Perth'), + ('Australia/Sydney', 'Australia/Sydney'), + ('Canada/Atlantic', 'Canada/Atlantic'), + ('Canada/Central', 'Canada/Central'), + ('Canada/Eastern', 'Canada/Eastern'), + ('Canada/Mountain', 'Canada/Mountain'), + ('Canada/Newfoundland', 'Canada/Newfoundland'), + ('Canada/Pacific', 'Canada/Pacific'), + ('Europe/Amsterdam', 'Europe/Amsterdam'), + ('Europe/Andorra', 'Europe/Andorra'), + ('Europe/Astrakhan', 'Europe/Astrakhan'), + ('Europe/Athens', 'Europe/Athens'), + ('Europe/Belgrade', 'Europe/Belgrade'), + ('Europe/Berlin', 'Europe/Berlin'), + ('Europe/Bratislava', 'Europe/Bratislava'), + ('Europe/Brussels', 'Europe/Brussels'), + ('Europe/Bucharest', 'Europe/Bucharest'), + ('Europe/Budapest', 'Europe/Budapest'), + ('Europe/Busingen', 'Europe/Busingen'), + ('Europe/Chisinau', 'Europe/Chisinau'), + ('Europe/Copenhagen', 'Europe/Copenhagen'), + ('Europe/Dublin', 'Europe/Dublin'), + ('Europe/Gibraltar', 'Europe/Gibraltar'), + ('Europe/Guernsey', 'Europe/Guernsey'), + ('Europe/Helsinki', 'Europe/Helsinki'), + ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), + ('Europe/Istanbul', 'Europe/Istanbul'), + ('Europe/Jersey', 'Europe/Jersey'), + ('Europe/Kaliningrad', 'Europe/Kaliningrad'), + ('Europe/Kiev', 'Europe/Kiev'), + ('Europe/Kirov', 'Europe/Kirov'), + ('Europe/Lisbon', 'Europe/Lisbon'), + ('Europe/Ljubljana', 'Europe/Ljubljana'), + ('Europe/London', 'Europe/London'), + ('Europe/Luxembourg', 'Europe/Luxembourg'), + ('Europe/Madrid', 'Europe/Madrid'), + ('Europe/Malta', 'Europe/Malta'), + ('Europe/Mariehamn', 'Europe/Mariehamn'), + ('Europe/Minsk', 'Europe/Minsk'), + ('Europe/Monaco', 'Europe/Monaco'), + ('Europe/Moscow', 'Europe/Moscow'), + ('Europe/Oslo', 'Europe/Oslo'), + ('Europe/Paris', 'Europe/Paris'), + ('Europe/Podgorica', 'Europe/Podgorica'), + ('Europe/Prague', 'Europe/Prague'), + ('Europe/Riga', 'Europe/Riga'), + ('Europe/Rome', 'Europe/Rome'), + ('Europe/Samara', 'Europe/Samara'), + ('Europe/San_Marino', 'Europe/San_Marino'), + ('Europe/Sarajevo', 'Europe/Sarajevo'), + ('Europe/Saratov', 'Europe/Saratov'), + ('Europe/Simferopol', 'Europe/Simferopol'), + ('Europe/Skopje', 'Europe/Skopje'), + ('Europe/Sofia', 'Europe/Sofia'), + ('Europe/Stockholm', 'Europe/Stockholm'), + ('Europe/Tallinn', 'Europe/Tallinn'), + ('Europe/Tirane', 'Europe/Tirane'), + ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), + ('Europe/Uzhgorod', 'Europe/Uzhgorod'), + ('Europe/Vaduz', 'Europe/Vaduz'), + ('Europe/Vatican', 'Europe/Vatican'), + ('Europe/Vienna', 'Europe/Vienna'), + ('Europe/Vilnius', 'Europe/Vilnius'), + ('Europe/Volgograd', 'Europe/Volgograd'), + ('Europe/Warsaw', 'Europe/Warsaw'), + ('Europe/Zagreb', 'Europe/Zagreb'), + ('Europe/Zaporozhye', 'Europe/Zaporozhye'), + ('Europe/Zurich', 'Europe/Zurich'), + ('GMT', 'GMT'), + ('Indian/Antananarivo', 'Indian/Antananarivo'), + ('Indian/Chagos', 'Indian/Chagos'), + ('Indian/Christmas', 'Indian/Christmas'), + ('Indian/Cocos', 'Indian/Cocos'), + ('Indian/Comoro', 'Indian/Comoro'), + ('Indian/Kerguelen', 'Indian/Kerguelen'), + ('Indian/Mahe', 'Indian/Mahe'), + ('Indian/Maldives', 'Indian/Maldives'), + ('Indian/Mauritius', 'Indian/Mauritius'), + ('Indian/Mayotte', 'Indian/Mayotte'), + ('Indian/Reunion', 'Indian/Reunion'), + ('Pacific/Apia', 'Pacific/Apia'), + ('Pacific/Auckland', 'Pacific/Auckland'), + ('Pacific/Bougainville', 'Pacific/Bougainville'), + ('Pacific/Chatham', 'Pacific/Chatham'), + ('Pacific/Chuuk', 'Pacific/Chuuk'), + ('Pacific/Easter', 'Pacific/Easter'), + ('Pacific/Efate', 'Pacific/Efate'), + ('Pacific/Enderbury', 'Pacific/Enderbury'), + ('Pacific/Fakaofo', 'Pacific/Fakaofo'), + ('Pacific/Fiji', 'Pacific/Fiji'), + ('Pacific/Funafuti', 'Pacific/Funafuti'), + ('Pacific/Galapagos', 'Pacific/Galapagos'), + ('Pacific/Gambier', 'Pacific/Gambier'), + ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), + ('Pacific/Guam', 'Pacific/Guam'), + ('Pacific/Honolulu', 'Pacific/Honolulu'), + ('Pacific/Kiritimati', 'Pacific/Kiritimati'), + ('Pacific/Kosrae', 'Pacific/Kosrae'), + ('Pacific/Kwajalein', 'Pacific/Kwajalein'), + ('Pacific/Majuro', 'Pacific/Majuro'), + ('Pacific/Marquesas', 'Pacific/Marquesas'), + ('Pacific/Midway', 'Pacific/Midway'), + ('Pacific/Nauru', 'Pacific/Nauru'), + ('Pacific/Niue', 'Pacific/Niue'), + ('Pacific/Norfolk', 'Pacific/Norfolk'), + ('Pacific/Noumea', 'Pacific/Noumea'), + ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), + ('Pacific/Palau', 'Pacific/Palau'), + ('Pacific/Pitcairn', 'Pacific/Pitcairn'), + ('Pacific/Pohnpei', 'Pacific/Pohnpei'), + ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), + ('Pacific/Rarotonga', 'Pacific/Rarotonga'), + ('Pacific/Saipan', 'Pacific/Saipan'), + ('Pacific/Tahiti', 'Pacific/Tahiti'), + ('Pacific/Tarawa', 'Pacific/Tarawa'), + ('Pacific/Tongatapu', 'Pacific/Tongatapu'), + ('Pacific/Wake', 'Pacific/Wake'), + ('Pacific/Wallis', 'Pacific/Wallis'), + ('US/Alaska', 'US/Alaska'), + ('US/Arizona', 'US/Arizona'), + ('US/Central', 'US/Central'), + ('US/Eastern', 'US/Eastern'), + ('US/Hawaii', 'US/Hawaii'), + ('US/Mountain', 'US/Mountain'), + ('US/Pacific', 'US/Pacific'), + ('UTC', 'UTC')], + default='UTC', help_text='Used for developer clock page', max_length=100), ), ] diff --git a/devel/migrations/0005_auto_20200628_1600.py b/devel/migrations/0005_auto_20200628_1600.py index af4188b7..d52114e7 100644 --- a/devel/migrations/0005_auto_20200628_1600.py +++ b/devel/migrations/0005_auto_20200628_1600.py @@ -13,6 +13,8 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='userprofile', name='website_rss', - field=models.CharField(blank=True, help_text='RSS Feed of your website for planet.archlinux.org', max_length=200, null=True), + field=models.CharField( + blank=True, help_text='RSS Feed of your website for planet.archlinux.org', + max_length=200, null=True), ), ] diff --git a/devel/models.py b/devel/models.py index 59324746..ed87fa8a 100644 --- a/devel/models.py +++ b/devel/models.py @@ -30,7 +30,8 @@ class UserProfile(models.Model): max_length=50, help_text="Required field") other_contact = models.CharField(max_length=100, null=True, blank=True) - pgp_key = PGPKeyField(max_length=40, null=True, blank=True, + pgp_key = PGPKeyField( + max_length=40, null=True, blank=True, verbose_name="PGP key fingerprint", help_text="consists of 40 hex digits; use `gpg --fingerprint`") website = models.CharField(max_length=200, null=True, blank=True) @@ -44,14 +45,14 @@ class UserProfile(models.Model): occupation = models.CharField(max_length=50, null=True, blank=True) roles = models.CharField(max_length=255, null=True, blank=True) favorite_distros = models.CharField(max_length=255, null=True, blank=True) - picture = models.FileField(upload_to='devs', default='devs/silhouette.png', - help_text="Ideally 125px by 125px") + picture = models.FileField( + upload_to='devs', default='devs/silhouette.png', help_text="Ideally 125px by 125px") user = models.OneToOneField(User, related_name='userprofile', on_delete=models.CASCADE) allowed_repos = models.ManyToManyField('main.Repo', blank=True) - latin_name = models.CharField(max_length=255, null=True, blank=True, - help_text="Latin-form name; used only for non-Latin full names") - rebuilderd_updates = models.BooleanField(default=False, - help_text='Receive reproducible build package updates') + latin_name = models.CharField( + max_length=255, null=True, blank=True, help_text="Latin-form name; used only for non-Latin full names") + rebuilderd_updates = models.BooleanField( + default=False, help_text='Receive reproducible build package updates') last_modified = models.DateTimeField(editable=False) class Meta: @@ -87,11 +88,16 @@ class StaffGroup(models.Model): class MasterKey(models.Model): - owner = models.ForeignKey(User, related_name='masterkey_owner', - help_text="The developer holding this master key", on_delete=models.CASCADE) - revoker = models.ForeignKey(User, related_name='masterkey_revoker', - help_text="The developer holding the revocation certificate", on_delete=models.CASCADE) - pgp_key = PGPKeyField(max_length=40, verbose_name="PGP key fingerprint", + owner = models.ForeignKey( + User, related_name='masterkey_owner', + help_text="The developer holding this master key", + on_delete=models.CASCADE) + revoker = models.ForeignKey( + User, related_name='masterkey_revoker', + help_text="The developer holding the revocation certificate", + on_delete=models.CASCADE) + pgp_key = PGPKeyField( + max_length=40, verbose_name="PGP key fingerprint", help_text="consists of 40 hex digits; use `gpg --fingerprint`") created = models.DateField() revoked = models.DateField(null=True, blank=True) @@ -101,15 +107,15 @@ class MasterKey(models.Model): get_latest_by = 'created' def __str__(self): - return '%s, created %s' % ( - self.owner.get_full_name(), self.created) + return '%s, created %s' % (self.owner.get_full_name(), self.created) class DeveloperKey(models.Model): - owner = models.ForeignKey(User, related_name='all_keys', null=True, - help_text="The developer this key belongs to", on_delete=models.CASCADE) - key = PGPKeyField(max_length=40, verbose_name="PGP key fingerprint", - unique=True) + owner = models.ForeignKey( + User, related_name='all_keys', null=True, + help_text="The developer this key belongs to", + on_delete=models.CASCADE) + key = PGPKeyField(max_length=40, verbose_name="PGP key fingerprint", unique=True) created = models.DateTimeField() expires = models.DateTimeField(null=True, blank=True) revoked = models.DateTimeField(null=True, blank=True) @@ -120,10 +126,8 @@ class DeveloperKey(models.Model): class PGPSignature(models.Model): - signer = PGPKeyField(max_length=40, verbose_name="Signer key fingerprint", - db_index=True) - signee = PGPKeyField(max_length=40, verbose_name="Signee key fingerprint", - db_index=True) + signer = PGPKeyField(max_length=40, verbose_name="Signer key fingerprint", db_index=True) + signee = PGPKeyField(max_length=40, verbose_name="Signee key fingerprint", db_index=True) created = models.DateField() expires = models.DateField(null=True, blank=True) revoked = models.DateField(null=True, blank=True) @@ -193,10 +197,8 @@ def delete_feed_model(sender, **kwargs): Feed.objects.filter(website_rss=userprofile.website_rss).delete() -pre_save.connect(create_feed_model, sender=UserProfile, - dispatch_uid="devel.models") +pre_save.connect(create_feed_model, sender=UserProfile, dispatch_uid="devel.models") -post_save.connect(delete_feed_model, sender=User, - dispatch_uid='main.models') +post_save.connect(delete_feed_model, sender=User, dispatch_uid='main.models') # vim: set ts=4 sw=4 et: diff --git a/devel/reports.py b/devel/reports.py index 2831840a..f163f050 100644 --- a/devel/reports.py +++ b/devel/reports.py @@ -203,8 +203,7 @@ REPORT_INFO = DeveloperReport('uncompressed-info', 'Uncompressed Info Pages', REPORT_ORPHANS = DeveloperReport( 'unneeded-orphans', 'Unneeded Orphans', - 'Packages that have no maintainer and are not required by any ' + - 'other package in any repository', + 'Packages that have no maintainer and are not required by any other package in any repository', unneeded_orphans, personal=False) @@ -215,8 +214,8 @@ REPORT_SIGNATURE = DeveloperReport( REPORT_SIG_TIME = DeveloperReport( 'signature-time', 'Signature Time', - 'Packages where the signature timestamp is more than 24 hours ' + - 'after the build timestamp', signature_time, + 'Packages where the signature timestamp is more than 24 hours after the build timestamp', + signature_time, ['Signature Date', 'Packager'], ['sig_date', 'packager']) NON_EXISTING_DEPENDENCIES = DeveloperReport( @@ -232,8 +231,7 @@ REBUILDERD_PACKAGES = DeveloperReport( 'non-reproducible-packages', 'Non Reproducible package', 'Packages that are not reproducible on our reproducible.archlinux.org test environment', - non_reproducible_packages, - ) + non_reproducible_packages) def available_reports(): diff --git a/devel/templatetags/group.py b/devel/templatetags/group.py index 2133d2f8..4467d2f4 100644 --- a/devel/templatetags/group.py +++ b/devel/templatetags/group.py @@ -2,6 +2,7 @@ from django import template register = template.Library() + @register.filter(name='in_group') def in_group(user, group_name): return user.groups.filter(name=group_name).exists() diff --git a/devel/tests/test_devel.py b/devel/tests/test_devel.py index c8a28c1a..57a03788 100644 --- a/devel/tests/test_devel.py +++ b/devel/tests/test_devel.py @@ -19,8 +19,8 @@ class DevelView(TransactionTestCase): self.profile = UserProfile.objects.create(user=self.user, public_email="{}@awesome.com".format(self.user.username)) self.client.post('/login/', { - 'username': self.user.username, - 'password': password + 'username': self.user.username, + 'password': password }) def tearDown(self): diff --git a/devel/tests/test_pgp_import.py b/devel/tests/test_pgp_import.py index f01e73a3..2748d8b1 100644 --- a/devel/tests/test_pgp_import.py +++ b/devel/tests/test_pgp_import.py @@ -12,10 +12,10 @@ ID2 = 'D8AFDDA07A5B6EDFA7D8CCDAD6D055F927843F1C' ID3 = 'B588C0234ECADD3F0BBBEEBA44F9F02E089294E7' SIG_DATA = [ - 'pub:-:4096:1:{id1}:{created}:::-:::scESCA::::::23::0:'.format(id1=ID1, created=CREATED), - 'fpr:::::::::{id2}:'.format(id2=ID2), - 'uid:-::::{created}::{id3}::{user}::::::::::0:'.format(created=CREATED, id3=ID3, user=USER), - 'sig:::1:{id1}:{created}::::{user}:13x::{id2}:::10:'.format(id1=ID1, created=CREATED, user=USER, id2=ID2) + 'pub:-:4096:1:{id1}:{created}:::-:::scESCA::::::23::0:'.format(id1=ID1, created=CREATED), + 'fpr:::::::::{id2}:'.format(id2=ID2), + 'uid:-::::{created}::{id3}::{user}::::::::::0:'.format(created=CREATED, id3=ID3, user=USER), + 'sig:::1:{id1}:{created}::::{user}:13x::{id2}:::10:'.format(id1=ID1, created=CREATED, user=USER, id2=ID2) ] diff --git a/devel/tests/test_reporead.py b/devel/tests/test_reporead.py index 0ffe3a17..5e92dd56 100644 --- a/devel/tests/test_reporead.py +++ b/devel/tests/test_reporead.py @@ -24,10 +24,10 @@ class RepoReadTest(TransactionTestCase): arch = Arch.objects.get(name__iexact='any') now = datetime.now(tz=timezone.utc) return Package.objects.create(arch=arch, repo=repo, pkgname='systemd', - pkgbase='systemd', pkgver=pkgver, - pkgrel=pkgrel, pkgdesc='Linux kernel', - compressed_size=10, installed_size=20, - last_update=now, created=now) + pkgbase='systemd', pkgver=pkgver, + pkgrel=pkgrel, pkgdesc='Linux kernel', + compressed_size=10, installed_size=20, + last_update=now, created=now) def test_invalid_args(self): with self.assertRaises(CommandError) as e: @@ -41,12 +41,12 @@ class RepoReadTest(TransactionTestCase): with self.assertRaises(CommandError) as e: call_command('reporead', 'x86_64', 'nothing.db.tar.gz') self.assertIn('Specified package database file does not exist.', str(e.exception)) - + def test_invalid_arch(self): with self.assertRaises(CommandError) as e: call_command('reporead', 'armv64', 'devel/fixtures/core.db.tar.gz') self.assertEqual('Specified architecture armv64 is not currently known.', str(e.exception)) - + def test_read_packages(self): with patch('devel.management.commands.reporead.logger') as logger: call_command('reporead', 'x86_64', 'devel/fixtures/core.db.tar.gz') @@ -54,7 +54,8 @@ class RepoReadTest(TransactionTestCase): # Verify contents with tarfile.open('devel/fixtures/core.db.tar.gz') as tar: - files = [name.replace('core.db/', '') for name in tar.getnames() if name != 'core.db' and not 'desc' in name] + files = [name.replace('core.db/', '') for name in tar.getnames() + if name != 'core.db' and 'desc' not in name] packages = Package.objects.all() import_packages = ["{}-{}-{}".format(pkg.pkgname, pkg.pkgver, pkg.pkgrel) for pkg in packages] @@ -89,6 +90,6 @@ class RepoReadTest(TransactionTestCase): call_command('reporead', 'x86_64', 'devel/fixtures/core.db.tar.gz') logger.info.assert_called() - objects = FlagRequest.objects.all() + objects = FlagRequest.objects.all() self.assertEqual(len(objects), 1) self.assertEqual(objects[0].pkgver, staging_pkg.pkgver) diff --git a/devel/tests/test_reports.py b/devel/tests/test_reports.py index 2906d940..70ee7df6 100644 --- a/devel/tests/test_reports.py +++ b/devel/tests/test_reports.py @@ -12,8 +12,8 @@ class DeveloperReport(TransactionTestCase): 'admin@archlinux.org', password) self.client.post('/login/', { - 'username': self.user.username, - 'password': password + 'username': self.user.username, + 'password': password }) def tearDown(self): diff --git a/devel/tests/test_retire_user.py b/devel/tests/test_retire_user.py index 4e1c3985..ac5f26a6 100644 --- a/devel/tests/test_retire_user.py +++ b/devel/tests/test_retire_user.py @@ -11,11 +11,10 @@ from devel.models import UserProfile class RetireUsertest(TransactionTestCase): fixtures = ['main/fixtures/arches.json', 'main/fixtures/repos.json'] - def setUp(self): self.username = 'joe' self.user = User.objects.create(username=self.username, first_name="Joe", - last_name="User", email="user1@example.com") + last_name="User", email="user1@example.com") self.profile = UserProfile.objects.create(user=self.user, public_email="{}@awesome.com".format(self.user.username)) @@ -38,7 +37,7 @@ class RetireUsertest(TransactionTestCase): def test_userprofile_missing(self): user = User.objects.create(username='user2', first_name="Jane", - last_name="User2", email="user2@example.com") + last_name="User2", email="user2@example.com") with self.assertRaises(CommandError) as e: call_command('retire_user', user.username) diff --git a/devel/tests/test_user.py b/devel/tests/test_user.py index 91c0b1e6..557b2abb 100644 --- a/devel/tests/test_user.py +++ b/devel/tests/test_user.py @@ -4,6 +4,7 @@ from django.test import TestCase from devel.utils import UserFinder from devel.models import UserProfile + class DevelTest(TestCase): def test_index(self): response = self.client.get('/devel/') @@ -36,26 +37,27 @@ class DevelTest(TestCase): response = self.client.get('/devel/admin_log', follow=True) self.assertEqual(response.status_code, 200) + class FindUserTest(TestCase): def setUp(self): self.finder = UserFinder() - self.user1 = User.objects.create(username="joeuser", first_name="Joe", - last_name="User", email="user1@example.com") - self.user2 = User.objects.create(username="john", first_name="John", - last_name="", email="user2@example.com") - self.user3 = User.objects.create(username="bjones", first_name="Bob", - last_name="Jones", email="user3@example.com") + self.user1 = User.objects.create( + username="joeuser", first_name="Joe", last_name="User", email="user1@example.com") + self.user2 = User.objects.create( + username="john", first_name="John", last_name="", email="user2@example.com") + self.user3 = User.objects.create( + username="bjones", first_name="Bob", last_name="Jones", email="user3@example.com") for user in (self.user1, self.user2, self.user3): email_addr = "%s@awesome.com" % user.username UserProfile.objects.create(user=user, public_email=email_addr) - self.user4 = User.objects.create(username="tim1", first_name="Tim", - last_name="One", email="tim@example.com") - self.user5 = User.objects.create(username="tim2", first_name="Tim", - last_name="Two", email="timtwo@example.com") + self.user4 = User.objects.create( + username="tim1", first_name="Tim", last_name="One", email="tim@example.com") + self.user5 = User.objects.create( + username="tim2", first_name="Tim", last_name="Two", email="timtwo@example.com") def test_not_matching(self): self.assertIsNone(self.finder.find(None)) @@ -68,54 +70,54 @@ class FindUserTest(TestCase): self.assertIsNone(self.finder.find("Unknown Packager")) def test_by_email(self): - self.assertEqual(self.user1, - self.finder.find("XXX YYY ")) - self.assertEqual(self.user2, - self.finder.find("YYY ZZZ ")) + self.assertEqual( + self.user1, self.finder.find("XXX YYY ")) + self.assertEqual( + self.user2, self.finder.find("YYY ZZZ ")) def test_by_profile_email(self): - self.assertEqual(self.user1, - self.finder.find("XXX ")) - self.assertEqual(self.user2, - self.finder.find("YYY ")) - self.assertEqual(self.user3, - self.finder.find("ZZZ ")) + self.assertEqual( + self.user1, self.finder.find("XXX ")) + self.assertEqual( + self.user2, self.finder.find("YYY ")) + self.assertEqual( + self.user3, self.finder.find("ZZZ ")) def test_by_name(self): - self.assertEqual(self.user1, - self.finder.find("Joe User ")) - self.assertEqual(self.user1, - self.finder.find("Joe User")) - self.assertEqual(self.user2, - self.finder.find("John ")) - self.assertEqual(self.user2, - self.finder.find("John")) - self.assertEqual(self.user3, - self.finder.find("Bob Jones ")) + self.assertEqual( + self.user1, self.finder.find("Joe User ")) + self.assertEqual( + self.user1, self.finder.find("Joe User")) + self.assertEqual( + self.user2, self.finder.find("John ")) + self.assertEqual( + self.user2, self.finder.find("John")) + self.assertEqual( + self.user3, self.finder.find("Bob Jones ")) def test_by_invalid(self): - self.assertEqual(self.user1, - self.finder.find("Joe User ")) - self.assertEqual(self.user3, - self.finder.find("Bob Jones ")) + self.assertEqual( + self.user1, self.finder.find("XXX YYY ")) + self.assertEqual( + self.user3, self.finder.find("Bob Jones ")) def test_ambiguous(self): - self.assertEqual(self.user4, - self.finder.find("Tim One ")) - self.assertEqual(self.user5, - self.finder.find("Tim Two ")) + self.assertEqual( + self.user4, self.finder.find("Tim One ")) + self.assertEqual( + self.user5, self.finder.find("Tim Two ")) self.assertIsNone(self.finder.find("Tim ")) def test_find_by_username(self): diff --git a/devel/utils.py b/devel/utils.py index bd57def9..715bde22 100644 --- a/devel/utils.py +++ b/devel/utils.py @@ -10,12 +10,13 @@ from main.utils import cache_function from main.models import Package from packages.models import PackageRelation + @cache_function(283) def get_annotated_maintainers(): profile_ids = UserProfile.allowed_repos.through.objects.values('userprofile_id') maintainers = User.objects.filter( - is_active=True, userprofile__id__in=profile_ids).order_by( - 'first_name', 'last_name') + is_active=True, userprofile__id__in=profile_ids).order_by( + 'first_name', 'last_name') # annotate the maintainers with # of maintained and flagged packages pkg_count_sql = """ @@ -37,7 +38,7 @@ SELECT pr.user_id, COUNT(*), COUNT(p.flag_date) flag_count[k] = flagged update_count = Package.objects.values_list('packager').order_by( - 'packager').annotate(Count('packager')) + 'packager').annotate(Count('packager')) update_count = dict(update_count) for m in maintainers: @@ -104,8 +105,7 @@ class UserFinder(object): # ignore quoted parts; e.g. nicknames in strings if re.match(r'^[\'"].*[\'"]$', token): continue - name_q &= (Q(first_name__icontains=token) | - Q(last_name__icontains=token)) + name_q &= (Q(first_name__icontains=token) | Q(last_name__icontains=token)) return User.objects.get(name_q) def find(self, userstring): @@ -132,7 +132,7 @@ class UserFinder(object): user = None find_methods = (self.user_email, self.profile_email, - self.username_email, self.user_name) + self.username_email, self.user_name) for matcher in find_methods: user = matcher(name, email) if user is not None: @@ -179,7 +179,7 @@ class UserFinder(object): try: user = User.objects.get( - userprofile__pgp_key__endswith=pgp_key) + userprofile__pgp_key__endswith=pgp_key) except User.DoesNotExist: user = None diff --git a/devel/views.py b/devel/views.py index 96acb720..ec07f70b 100644 --- a/devel/views.py +++ b/devel/views.py @@ -106,8 +106,10 @@ def stats(request): return render(request, 'devel/stats.html', page_dict) + SELECTED_GROUPS = ['Developers', 'Trusted Users', 'Support Staff'] + @login_required def clock(request): groups = Group.objects.filter(name__in=SELECTED_GROUPS) @@ -247,8 +249,7 @@ def new_user_form(request): with transaction.atomic(): form.save() log_addition(request, form.instance.user) - return HttpResponseRedirect('/admin/auth/user/%d/' % \ - form.instance.user.id) + return HttpResponseRedirect('/admin/auth/user/%d/' % form.instance.user.id) else: form = NewUserForm() diff --git a/feeds.py b/feeds.py index 99d23cfb..dd57b5a9 100644 --- a/feeds.py +++ b/feeds.py @@ -153,8 +153,8 @@ class PackageFeed(Feed): # http://diveintomark.org/archives/2004/05/28/howto-atom-id date = item.last_update return 'tag:%s,%s:%s%s' % (Site.objects.get_current().domain, - date.strftime('%Y-%m-%d'), item.get_absolute_url(), - date.strftime('%Y%m%d%H%M')) + date.strftime('%Y-%m-%d'), item.get_absolute_url(), + date.strftime('%Y%m%d%H%M')) def item_pubdate(self, item): return item.last_update @@ -168,6 +168,7 @@ class PackageFeed(Feed): def item_categories(self, item): return (item.repo.name, item.arch.name) + def removal_last_modified(request, *args, **kwargs): try: return Update.objects.latest('created').created @@ -282,8 +283,8 @@ class PackageUpdatesFeed(Feed): # http://diveintomark.org/archives/2004/05/28/howto-atom-id date = item.created return 'tag:%s,%s:%s%s' % (Site.objects.get_current().domain, - date.strftime('%Y-%m-%d'), item.get_absolute_url(), - date.strftime('%Y%m%d%H%M')) + date.strftime('%Y-%m-%d'), item.get_absolute_url(), + date.strftime('%Y%m%d%H%M')) def item_pubdate(self, item): return item.created @@ -319,8 +320,7 @@ class NewsFeed(Feed): __name__ = 'news_feed' def items(self): - return News.objects.select_related('author').order_by( - '-postdate', '-id')[:10] + return News.objects.select_related('author').order_by('-postdate', '-id')[:10] item_guid_is_permalink = False @@ -374,7 +374,7 @@ class ReleaseFeed(Feed): # http://diveintomark.org/archives/2004/05/28/howto-atom-id date = item.release_date return 'tag:%s,%s:%s' % (Site.objects.get_current().domain, - date.strftime('%Y-%m-%d'), item.get_absolute_url()) + date.strftime('%Y-%m-%d'), item.get_absolute_url()) def item_enclosure_url(self, item): domain = Site.objects.get_current().domain @@ -427,7 +427,7 @@ class PlanetFeed(Feed): # http://diveintomark.org/archives/2004/05/28/howto-atom-id date = item.publishdate return 'tag:%s,%s:%s' % (Site.objects.get_current().domain, - date.strftime('%Y-%m-%d'), item.url) + date.strftime('%Y-%m-%d'), item.url) def planet_last_modified(request, *args, **kwargs): diff --git a/local_settings.py.example b/local_settings.py.example index f5b167f5..77d5de94 100644 --- a/local_settings.py.example +++ b/local_settings.py.example @@ -1,57 +1,57 @@ -## Debug settings +# Debug settings DEBUG = False -#DEBUG_TOOLBAR = True +# DEBUG_TOOLBAR = True -## For django debug toolbar +# For django debug toolbar INTERNAL_IPS = ('127.0.0.1',) -## Notification admins +# Notification admins ADMINS = ( - # ('Joe Admin', 'joeadmin@example.com'), + ('Joe Admin', 'joeadmin@example.com'), ) -## PostgreSQL Database settings -#DATABASES = { -# 'default': { -# 'ENGINE' : 'django.db.backends.postgresql', -# 'NAME' : 'archlinux', -# 'USER' : 'archlinux', -# 'PASSWORD': 'archlinux', -# 'HOST' : '', -# 'PORT' : '', -# }, -#} - -## Sqlite Database settings +# PostgreSQL Database settings +# DATABASES = { +# 'default': { +# 'ENGINE': 'django.db.backends.postgresql', +# 'NAME': 'archlinux', +# 'USER': 'archlinux', +# 'PASSWORD': 'archlinux', +# 'HOST': '', +# 'PORT': '', +# }, +# } + +# Sqlite Database settings DATABASES = { 'default': { - 'ENGINE' : 'django.db.backends.sqlite3', - 'NAME' : 'database.db', + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': 'database.db', }, } -## Define cache settings +# Define cache settings CACHES = { 'default': { - 'BACKEND' : 'django.core.cache.backends.dummy.DummyCache', - #'BACKEND' : 'django.core.cache.backends.memcached.MemcachedCache', - #'LOCATION': '127.0.0.1:11211', + 'BACKEND': 'django.core.cache.backends.dummy.DummyCache', + # 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', + # 'LOCATION': '127.0.0.1:11211', } } -## Use secure session cookies? Make these True if you want all -## logged-in actions to take place over HTTPS only. If developing -## locally, you will want to use False. +# Use secure session cookies? Make these True if you want all +# logged-in actions to take place over HTTPS only. If developing +# locally, you will want to use False. SESSION_COOKIE_SECURE = False CSRF_COOKIE_SECURE = False -## location for saving dev pictures +# location for saving dev pictures MEDIA_ROOT = '/srv/example.com/img/' -## web url for serving image files +# web url for serving image files MEDIA_URL = '/media/img/' -## Make this unique, and don't share it with anybody. +# Make this unique, and don't share it with anybody. SECRET_KEY = '00000000000000000000000000000000000000000000000' # vim: set ts=4 sw=4 et: diff --git a/main/admin.py b/main/admin.py index ec2b5bc8..77c94b03 100644 --- a/main/admin.py +++ b/main/admin.py @@ -16,15 +16,13 @@ class ArchAdmin(admin.ModelAdmin): class RepoAdmin(admin.ModelAdmin): - list_display = ('name', 'testing', 'staging', 'bugs_project', - 'bugs_category', 'svn_root') + list_display = ('name', 'testing', 'staging', 'bugs_project', 'bugs_category', 'svn_root') list_filter = ('testing', 'staging') search_fields = ('name',) class PackageAdmin(admin.ModelAdmin): - list_display = ('pkgname', 'full_version', 'repo', 'arch', 'packager', - 'last_update', 'build_date') + list_display = ('pkgname', 'full_version', 'repo', 'arch', 'packager', 'last_update', 'build_date') list_filter = ('repo', 'arch') search_fields = ('pkgname', 'pkgbase', 'pkgdesc') date_hierarchy = 'build_date' diff --git a/main/log.py b/main/log.py index 004dbd7b..4f29f0f6 100644 --- a/main/log.py +++ b/main/log.py @@ -52,7 +52,7 @@ class RateLimitFilter(object): try: cache.set(self.prefix, 1, 300) use_cache = (cache.get(self.prefix) == 1) - except: + except: # noqa use_cache = False if use_cache: diff --git a/main/management/commands/donor_import.py b/main/management/commands/donor_import.py index 12dc0aa9..b533cd57 100644 --- a/main/management/commands/donor_import.py +++ b/main/management/commands/donor_import.py @@ -41,7 +41,6 @@ class Command(BaseCommand): def add_arguments(self, parser): parser.add_argument('maildir', type=str) - def decode_subject(self, subject): subject = decode_header(subject) default_charset = 'utf-8' @@ -49,7 +48,6 @@ class Command(BaseCommand): # UTF-8 return ''.join([codecs.decode(s[0], s[1] or default_charset) for s in subject]) - def parse_subject(self, subject): """Format of the subject is as following: Receipt [$amount] By: John Doe [mail]""" @@ -58,26 +56,24 @@ class Command(BaseCommand): if parsed: return parsed['name'] - def sanitize_name(self, name): - """Sanitizes the parsed name and removes numbers, entries with no - valid characters and finally trims all excess whitespace""" - - # Some submissions contain no alphabetic characters, skip them - if all(not l.isalpha() for l in name): - return u'' + """Sanitizes the parsed name and removes numbers, entries with no + valid characters and finally trims all excess whitespace""" - # Strip any numbers, they could be a bank account number - name = u''.join([l for l in name if not l.isdigit()]) + # Some submissions contain no alphabetic characters, skip them + if all(not l.isalpha() for l in name): + return u'' - # Normalize all capitalized names. (JOHN DOE) - name = u' '.join(l.capitalize() for l in name.split(u' ')) + # Strip any numbers, they could be a bank account number + name = u''.join([l for l in name if not l.isdigit()]) - # Trim excess spaces - name = name.rstrip().lstrip() + # Normalize all capitalized names. (JOHN DOE) + name = u' '.join(l.capitalize() for l in name.split(u' ')) - return name + # Trim excess spaces + name = name.rstrip().lstrip() + return name def handle(self, *args, **options): v = int(options.get('verbosity', 0)) diff --git a/main/migrations/0001_initial.py b/main/migrations/0001_initial.py index cf9b48f6..6b6eec68 100644 --- a/main/migrations/0001_initial.py +++ b/main/migrations/0001_initial.py @@ -18,8 +18,10 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('name', models.CharField(unique=True, max_length=255)), - ('agnostic', models.BooleanField(default=False, help_text='Is this architecture non-platform specific?')), - ('required_signoffs', models.PositiveIntegerField(default=2, help_text='Number of signoffs required for packages of this architecture')), + ('agnostic', models.BooleanField( + default=False, help_text='Is this architecture non-platform specific?')), + ('required_signoffs', models.PositiveIntegerField( + default=2, help_text='Number of signoffs required for packages of this architecture')), ], options={ 'ordering': ('name',), @@ -33,7 +35,8 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), ('name', models.CharField(unique=True, max_length=255)), - ('visible', models.BooleanField(default=True, help_text='Should we show this donor on the public page?')), + ('visible', models.BooleanField( + default=True, help_text='Should we show this donor on the public page?')), ('created', models.DateTimeField()), ], options={ @@ -64,8 +67,10 @@ class Migration(migrations.Migration): ('packager_str', models.CharField(max_length=255, verbose_name='packager string')), ('signature_bytes', models.BinaryField(verbose_name='PGP signature', null=True)), ('flag_date', models.DateTimeField(null=True, blank=True)), - ('arch', models.ForeignKey(related_name='packages', on_delete=django.db.models.deletion.PROTECT, to='main.Arch')), - ('packager', models.ForeignKey(on_delete=django.db.models.deletion.SET_NULL, blank=True, to=settings.AUTH_USER_MODEL, null=True)), + ('arch', models.ForeignKey( + related_name='packages', on_delete=django.db.models.deletion.PROTECT, to='main.Arch')), + ('packager', models.ForeignKey( + on_delete=django.db.models.deletion.SET_NULL, blank=True, to=settings.AUTH_USER_MODEL, null=True)), ], options={ 'ordering': ('pkgname',), @@ -95,9 +100,12 @@ class Migration(migrations.Migration): ('name', models.CharField(unique=True, max_length=255)), ('testing', models.BooleanField(default=False, help_text='Is this repo meant for package testing?')), ('staging', models.BooleanField(default=False, help_text='Is this repo meant for package staging?')), - ('bugs_project', models.SmallIntegerField(default=1, help_text='Flyspray project ID for this repository.')), - ('bugs_category', models.SmallIntegerField(default=2, help_text='Flyspray category ID for this repository.')), - ('svn_root', models.CharField(help_text='SVN root (e.g. path) for this repository.', max_length=64)), + ('bugs_project', models.SmallIntegerField( + default=1, help_text='Flyspray project ID for this repository.')), + ('bugs_category', models.SmallIntegerField( + default=2, help_text='Flyspray category ID for this repository.')), + ('svn_root', models.CharField( + help_text='SVN root (e.g. path) for this repository.', max_length=64)), ], options={ 'ordering': ('name',), @@ -108,7 +116,10 @@ class Migration(migrations.Migration): migrations.AddField( model_name='package', name='repo', - field=models.ForeignKey(related_name='packages', on_delete=django.db.models.deletion.PROTECT, to='main.Repo'), + field=models.ForeignKey( + related_name='packages', + on_delete=django.db.models.deletion.PROTECT, + to='main.Repo'), preserve_default=True, ), migrations.AlterUniqueTogether( diff --git a/main/migrations/0002_repo_public_testing.py b/main/migrations/0002_repo_public_testing.py index 3f87234e..fc9f0f97 100644 --- a/main/migrations/0002_repo_public_testing.py +++ b/main/migrations/0002_repo_public_testing.py @@ -13,6 +13,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='repo', name='public_testing', - field=models.BooleanField(default=False, help_text='Is this repo meant for package testing (without signoffs)?'), + field=models.BooleanField( + default=False, help_text='Is this repo meant for package testing (without signoffs)?'), ), ] diff --git a/main/models.py b/main/models.py index f80786af..086a26ca 100644 --- a/main/models.py +++ b/main/models.py @@ -28,8 +28,8 @@ class PackageManager(models.Manager): class Donor(models.Model): name = models.CharField(max_length=255, unique=True) - visible = models.BooleanField(default=True, - help_text="Should we show this donor on the public page?") + visible = models.BooleanField( + default=True, help_text="Should we show this donor on the public page?") created = models.DateTimeField() def __str__(self): @@ -43,10 +43,10 @@ class Donor(models.Model): class Arch(models.Model): name = models.CharField(max_length=255, unique=True) - agnostic = models.BooleanField(default=False, - help_text="Is this architecture non-platform specific?") - required_signoffs = models.PositiveIntegerField(default=2, - help_text="Number of signoffs required for packages of this architecture") + agnostic = models.BooleanField( + default=False, help_text="Is this architecture non-platform specific?") + required_signoffs = models.PositiveIntegerField( + default=2, help_text="Number of signoffs required for packages of this architecture") def __str__(self): return self.name @@ -62,18 +62,18 @@ class Arch(models.Model): class Repo(models.Model): name = models.CharField(max_length=255, unique=True) - testing = models.BooleanField(default=False, - help_text="Is this repo meant for package testing?") - public_testing = models.BooleanField(default=False, - help_text="Is this repo meant for package testing (without signoffs)?") - staging = models.BooleanField(default=False, - help_text="Is this repo meant for package staging?") - bugs_project = models.SmallIntegerField(default=1, - help_text="Flyspray project ID for this repository.") - bugs_category = models.SmallIntegerField(default=2, - help_text="Flyspray category ID for this repository.") - svn_root = models.CharField(max_length=64, - help_text="SVN root (e.g. path) for this repository.") + testing = models.BooleanField( + default=False, help_text="Is this repo meant for package testing?") + public_testing = models.BooleanField( + default=False, help_text="Is this repo meant for package testing (without signoffs)?") + staging = models.BooleanField( + default=False, help_text="Is this repo meant for package staging?") + bugs_project = models.SmallIntegerField( + default=1, help_text="Flyspray project ID for this repository.") + bugs_category = models.SmallIntegerField( + default=2, help_text="Flyspray category ID for this repository.") + svn_root = models.CharField( + max_length=64, help_text="SVN root (e.g. path) for this repository.") def __str__(self): return self.name @@ -87,10 +87,8 @@ class Repo(models.Model): class Package(models.Model): - repo = models.ForeignKey(Repo, related_name="packages", - on_delete=models.PROTECT) - arch = models.ForeignKey(Arch, related_name="packages", - on_delete=models.PROTECT) + repo = models.ForeignKey(Repo, related_name="packages", on_delete=models.PROTECT) + arch = models.ForeignKey(Arch, related_name="packages", on_delete=models.PROTECT) pkgname = models.CharField(max_length=255) pkgbase = models.CharField(max_length=255, db_index=True) pkgver = models.CharField(max_length=255) @@ -106,8 +104,7 @@ class Package(models.Model): files_last_update = models.DateTimeField(null=True, blank=True) created = models.DateTimeField() packager_str = models.CharField('packager string', max_length=255) - packager = models.ForeignKey(User, null=True, blank=True, - on_delete=models.SET_NULL) + packager = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL) signature_bytes = models.BinaryField('PGP signature', null=True) flag_date = models.DateTimeField(null=True, blank=True) @@ -129,13 +126,12 @@ class Package(models.Model): return '%s-%s' % (self.pkgver, self.pkgrel) def get_absolute_url(self): - return '/packages/%s/%s/%s/' % (self.repo.name.lower(), - self.arch.name, self.pkgname) + return f'/packages/{self.repo.name.lower()}/{self.arch.name}/{self.pkgname}/' def get_full_url(self, proto='https'): '''get a URL suitable for things like email including the domain''' domain = Site.objects.get_current().domain - return '%s://%s%s' % (proto, domain, self.get_absolute_url()) + return f'{proto}://{domain}{self.get_absolute_url()}' @property def signature(self): @@ -151,7 +147,7 @@ class Package(models.Model): if sig and sig.key_id: try: matching_key = DeveloperKey.objects.select_related( - 'owner').get(key=sig.key_id, owner_id__isnull=False) + 'owner').get(key=sig.key_id, owner_id__isnull=False) user = matching_key.owner except DeveloperKey.DoesNotExist: user = None @@ -165,8 +161,8 @@ class Package(models.Model): from packages.models import PackageRelation if self._maintainers is None: self._maintainers = User.objects.filter( - package_relations__pkgbase=self.pkgbase, - package_relations__type=PackageRelation.MAINTAINER) + package_relations__pkgbase=self.pkgbase, + package_relations__type=PackageRelation.MAINTAINER) return self._maintainers @maintainers.setter @@ -200,16 +196,16 @@ class Package(models.Model): SELECT %s UNION ALL SELECT z.name FROM packages_provision z WHERE z.pkg_id = %s )''' - requiredby = Depend.objects.select_related('pkg', - 'pkg__arch', 'pkg__repo').extra( - select={'sorttype': sorttype}, - where=[name_clause], params=[self.pkgname, self.id]).order_by( - 'sorttype', 'pkg__pkgname', - 'pkg__arch__name', 'pkg__repo__name') + requiredby = Depend.objects.select_related( + 'pkg', 'pkg__arch', 'pkg__repo').extra( + select={'sorttype': sorttype}, + where=[name_clause], params=[self.pkgname, self.id]).order_by( + 'sorttype', 'pkg__pkgname', + 'pkg__arch__name', 'pkg__repo__name') if not self.arch.agnostic: # make sure we match architectures if possible requiredby = requiredby.filter( - pkg__arch__in=self.applicable_arches()) + pkg__arch__in=self.applicable_arches()) # if we can use ALPM, ensure our returned Depend objects abide by the # version comparison operators they may specify @@ -223,22 +219,19 @@ class Package(models.Model): new_rqd.append(dep) elif self.pkgname == dep.name: # depends on this package, so check it directly - if alpm.compare_versions(self.full_version, - dep.comparison, dep.version): + if alpm.compare_versions(self.full_version, dep.comparison, dep.version): new_rqd.append(dep) else: # it must be a provision of ours at this point for provide in (p for p in provides if p.name == dep.name): - if alpm.compare_versions(provide.version, - dep.comparison, dep.version): + if alpm.compare_versions(provide.version, dep.comparison, dep.version): new_rqd.append(dep) break requiredby = new_rqd # sort out duplicate packages; this happens if something has a double # versioned depend such as a kernel module - requiredby = [list(vals)[0] for _, vals in - groupby(requiredby, lambda x: x.pkg.id)] + requiredby = [list(vals)[0] for _, vals in groupby(requiredby, lambda x: x.pkg.id)] if not requiredby: return requiredby @@ -258,11 +251,9 @@ class Package(models.Model): # find another package by this name in a different testing or staging # repo; if we can't, we can short-circuit some checks - repo_q = (Q(repo__testing=(not self.repo.testing)) | - Q(repo__staging=(not self.repo.staging))) + repo_q = (Q(repo__testing=(not self.repo.testing)) | Q(repo__staging=(not self.repo.staging))) if not Package.objects.filter( - repo_q, pkgname=self.pkgname, arch=self.arch - ).exclude(id=self.id).exists(): + repo_q, pkgname=self.pkgname, arch=self.arch).exclude(id=self.id).exists(): # there isn't one? short circuit, all required by entries are fine return filtered @@ -274,9 +265,8 @@ class Package(models.Model): dep_pkgs = list(dep_pkgs) dep = dep_pkgs[0] if len(dep_pkgs) > 1: - dep_pkgs = [d for d in dep_pkgs - if d.pkg.repo.testing == self.repo.testing and - d.pkg.repo.staging == self.repo.staging] + dep_pkgs = [d for d in dep_pkgs if d.pkg.repo.testing == self.repo.testing + and d.pkg.repo.staging == self.repo.staging] if len(dep_pkgs) > 0: dep = dep_pkgs[0] trimmed.append(dep) @@ -331,8 +321,8 @@ class Package(models.Model): if conflict.name != self.pkgname: continue if not conflict.comparison or not conflict.version \ - or alpm.compare_versions(self.full_version, - conflict.comparison, conflict.version): + or alpm.compare_versions( + self.full_version, conflict.comparison, conflict.version): new_pkgs.append(package) return new_pkgs @@ -344,14 +334,14 @@ class Package(models.Model): """ try: # start by looking for something in this repo - return Package.objects.normal().get(arch=self.arch, - repo=self.repo, pkgname=self.pkgbase) + return Package.objects.normal().get( + arch=self.arch, repo=self.repo, pkgname=self.pkgbase) except Package.DoesNotExist: # this package might be split across repos? find one # that matches the correct [testing] repo flag - pkglist = Package.objects.normal().filter(arch=self.arch, - repo__testing=self.repo.testing, - repo__staging=self.repo.staging, pkgname=self.pkgbase) + pkglist = Package.objects.normal().filter( + arch=self.arch, repo__testing=self.repo.testing, + repo__staging=self.repo.staging, pkgname=self.pkgbase) if len(pkglist) > 0: return pkglist[0] return None @@ -365,10 +355,10 @@ class Package(models.Model): return value will be an empty list. """ return Package.objects.normal().filter( - arch__in=self.applicable_arches(), - repo__testing=self.repo.testing, - repo__staging=self.repo.staging, - pkgbase=self.pkgbase).exclude(id=self.id) + arch__in=self.applicable_arches(), + repo__testing=self.repo.testing, + repo__staging=self.repo.staging, + pkgbase=self.pkgbase).exclude(id=self.id) def flag_request(self): if self.flag_date is None: @@ -378,9 +368,9 @@ class Package(models.Model): # Note that we don't match on pkgrel here; this is because a pkgrel # bump does not unflag a package so we can still show the same flag # request from a different pkgrel. - request = FlagRequest.objects.filter(pkgbase=self.pkgbase, - repo=self.repo, pkgver=self.pkgver, - epoch=self.epoch, is_spam=False).latest() + request = FlagRequest.objects.filter( + pkgbase=self.pkgbase, repo=self.repo, + pkgver=self.pkgver, epoch=self.epoch, is_spam=False).latest() return request except FlagRequest.DoesNotExist: return None @@ -388,9 +378,9 @@ class Package(models.Model): def is_same_version(self, other): 'is this package similar, name and version-wise, to another' return self.pkgname == other.pkgname \ - and self.pkgver == other.pkgver \ - and self.pkgrel == other.pkgrel \ - and self.epoch == other.epoch + and self.pkgver == other.pkgver \ + and self.pkgrel == other.pkgrel \ + and self.epoch == other.epoch def in_testing(self): '''attempt to locate this package in a testing repo; if we are in @@ -398,8 +388,8 @@ class Package(models.Model): if self.repo.testing: return None try: - return Package.objects.normal().get(repo__testing=True, - pkgname=self.pkgname, arch=self.arch) + return Package.objects.normal().get( + repo__testing=True, pkgname=self.pkgname, arch=self.arch) except Package.DoesNotExist: return None @@ -409,8 +399,8 @@ class Package(models.Model): if self.repo.staging: return None try: - return Package.objects.normal().get(repo__staging=True, - pkgname=self.pkgname, arch=self.arch) + return Package.objects.normal().get( + repo__staging=True, pkgname=self.pkgname, arch=self.arch) except Package.DoesNotExist: return None @@ -426,8 +416,8 @@ class Package(models.Model): names.append('lib32-' + self.pkgname) names.append(self.pkgname + '-multilib') return Package.objects.normal().filter( - pkgname__in=names).exclude(id=self.id).order_by( - 'arch__name', 'repo__name') + pkgname__in=names).exclude(id=self.id).order_by( + 'arch__name', 'repo__name') class PackageFile(models.Model): @@ -478,11 +468,10 @@ class RebuilderdStatus(models.Model): return "pkg=%s, status=%s" % (self.pkg, self.status_str) -from django.db.models.signals import pre_save +from django.db.models.signals import pre_save # noqa # note: reporead sets the 'created' field on Package objects, so no signal # listener is set up here to do so -pre_save.connect(set_created_field, sender=Donor, - dispatch_uid="main.models") +pre_save.connect(set_created_field, sender=Donor, dispatch_uid="main.models") # vim: set ts=4 sw=4 et: diff --git a/main/templatetags/attributes.py b/main/templatetags/attributes.py index ab09b63e..a6be4b50 100644 --- a/main/templatetags/attributes.py +++ b/main/templatetags/attributes.py @@ -2,9 +2,10 @@ import re from django import template from django.conf import settings -numeric_test = re.compile("^\d+$") +numeric_test = re.compile(r"^\d+$") register = template.Library() + def attribute(value, arg): """Gets an attribute of an object dynamically from a string name""" if hasattr(value, str(arg)): @@ -16,6 +17,7 @@ def attribute(value, arg): else: return settings.TEMPLATE_STRING_IF_INVALID + register.filter('attribute', attribute) # vim: set ts=4 sw=4 et: diff --git a/main/templatetags/cdn.py b/main/templatetags/cdn.py index 2be23607..035c95a3 100644 --- a/main/templatetags/cdn.py +++ b/main/templatetags/cdn.py @@ -21,6 +21,7 @@ def jquery_tablesorter(): link = staticfiles_storage.url(filename) return format_html('' % link) + @register.simple_tag def d3js(): version = '3.5.0' diff --git a/main/templatetags/flags.py b/main/templatetags/flags.py index d47ee707..54115d35 100644 --- a/main/templatetags/flags.py +++ b/main/templatetags/flags.py @@ -9,7 +9,7 @@ def country_flag(country): if not country: return '' return format_html(' ' % ( - str(country.code).lower(), str(country.name))) + str(country.code).lower(), str(country.name))) # vim: set ts=4 sw=4 et: diff --git a/main/templatetags/pgp.py b/main/templatetags/pgp.py index 4597e10b..686c7da1 100644 --- a/main/templatetags/pgp.py +++ b/main/templatetags/pgp.py @@ -13,10 +13,11 @@ def format_key(key_id): elif len(key_id) == 40: # normal display format is 5 groups of 4 hex chars seperated by spaces, # double space, then 5 more groups of 4 hex chars - split = tuple(key_id[i:i+4] for i in range(0, 40, 4)) + split = tuple(key_id[i:i + 4] for i in range(0, 40, 4)) return '%s\u00a0 %s' % (' '.join(split[0:5]), ' '.join(split[5:10])) return '0x%s' % key_id + @register.simple_tag def pgp_key_link(key_id, link_text=None): if not key_id: @@ -36,8 +37,7 @@ def pgp_key_link(key_id, link_text=None): return format_key(key_id) pgp_server_secure = getattr(settings, 'PGP_SERVER_SECURE', False) scheme = 'https' if pgp_server_secure else 'http' - url = '%s://%s/pks/lookup?op=vindex&fingerprint=on&exact=on&search=0x%s' % \ - (scheme, pgp_server, key_id) + url = '%s://%s/pks/lookup?op=vindex&fingerprint=on&exact=on&search=0x%s' % (scheme, pgp_server, key_id) if link_text is None: link_text = '0x%s' % key_id[-8:] values = (url, format_key(key_id), link_text) diff --git a/main/tests/test_donor_import.py b/main/tests/test_donor_import.py index 0f27eee7..33fcad1f 100644 --- a/main/tests/test_donor_import.py +++ b/main/tests/test_donor_import.py @@ -19,9 +19,6 @@ class DonorImportTest(TransactionTestCase): def setUp(self): self.command = Command() - def gen_parse_subject(self, data): - return self.command.parse_subject(valid.format(data)) - def test_parse_subject(self): self.assertIsNone(self.command.parse_subject('garbage')) diff --git a/main/tests/test_templatetags_pgp.py b/main/tests/test_templatetags_pgp.py index 39ace88b..3a55ff1a 100644 --- a/main/tests/test_templatetags_pgp.py +++ b/main/tests/test_templatetags_pgp.py @@ -6,7 +6,6 @@ from main.templatetags.pgp import pgp_key_link, format_key, pgp_fingerprint class PGPTemplateTest(TestCase): - def test_format_key(self): # 40 len case pgp_key = '423423fD9004FB063E2C81117BFB1108D234DAFZ' diff --git a/main/utils.py b/main/utils.py index 57026616..2fb1ea76 100644 --- a/main/utils.py +++ b/main/utils.py @@ -146,8 +146,7 @@ class PackageStandin(object): return getattr(self.package, name) def get_absolute_url(self): - return '/packages/%s/%s/%s/' % ( - self.repo.name.lower(), self.arch.name, self.pkgbase) + return f'/packages/{self.repo.name.lower()}/{self.arch.name}/{self.pkgname}/' class DependStandin(object): diff --git a/mirrors/admin.py b/mirrors/admin.py index 8cfb3d05..b542e97b 100644 --- a/mirrors/admin.py +++ b/mirrors/admin.py @@ -5,7 +5,7 @@ from django import forms from django.contrib import admin from .models import (Mirror, MirrorProtocol, MirrorUrl, MirrorRsync, - CheckLocation) + CheckLocation) class MirrorUrlForm(forms.ModelForm): @@ -54,24 +54,24 @@ class MirrorAdminForm(forms.ModelForm): class Meta: model = Mirror fields = ('name', 'tier', 'upstream', 'admin_email', 'alternate_email', - 'public', 'active', 'isos', 'rsync_user', 'rsync_password', - 'bug', 'notes') + 'public', 'active', 'isos', 'rsync_user', 'rsync_password', + 'bug', 'notes') upstream = forms.ModelChoiceField( - queryset=Mirror.objects.filter(tier__gte=0, tier__lte=1), - required=False) + queryset=Mirror.objects.filter(tier__gte=0, tier__lte=1), + required=False) class MirrorAdmin(admin.ModelAdmin): form = MirrorAdminForm list_display = ('name', 'tier', 'active', 'public', - 'isos', 'admin_email', 'alternate_email') + 'isos', 'admin_email', 'alternate_email') list_filter = ('tier', 'active', 'public') search_fields = ('name', 'admin_email', 'alternate_email') readonly_fields = ('created', 'last_modified') inlines = [ - MirrorUrlInlineAdmin, - MirrorRsyncInlineAdmin, + MirrorUrlInlineAdmin, + MirrorRsyncInlineAdmin, ] def save_model(self, request, obj, form, change): diff --git a/mirrors/management/commands/mirrorcheck.py b/mirrors/management/commands/mirrorcheck.py index 70429b71..79772523 100644 --- a/mirrors/management/commands/mirrorcheck.py +++ b/mirrors/management/commands/mirrorcheck.py @@ -70,7 +70,7 @@ class Command(BaseCommand): timeout = options.get('timeout') urls = MirrorUrl.objects.select_related('protocol').filter( - active=True, mirror__active=True, mirror__public=True) + active=True, mirror__active=True, mirror__public=True) location = options.get('location', None) if location: @@ -183,8 +183,7 @@ def check_rsync_url(mirror_url, location, timeout): elif location.family == socket.AF_INET: ipopt = '--ipv4' lastsync_path = os.path.join(tempdir, 'lastsync') - rsync_cmd = ["rsync", "--quiet", "--contimeout=%d" % timeout, - "--timeout=%d" % timeout] + rsync_cmd = ["rsync", "--quiet", "--contimeout=%d" % timeout, "--timeout=%d" % timeout] if ipopt: rsync_cmd.append(ipopt) rsync_cmd.append(url) @@ -194,8 +193,7 @@ def check_rsync_url(mirror_url, location, timeout): if logger.isEnabledFor(logging.DEBUG): logger.debug("rsync cmd: %s", ' '.join(rsync_cmd)) start = time.time() - proc = subprocess.Popen(rsync_cmd, stdout=devnull, - stderr=subprocess.PIPE) + proc = subprocess.Popen(rsync_cmd, stdout=devnull, stderr=subprocess.PIPE) _, errdata = proc.communicate() end = time.time() log.duration = end - start @@ -229,8 +227,7 @@ def mirror_url_worker(work, output, location, timeout): try: if url.protocol.protocol == 'rsync': log = check_rsync_url(url, location, timeout) - elif (url.protocol.protocol == 'ftp' and location and - location.family == socket.AF_INET6): + elif (url.protocol.protocol == 'ftp' and location and location.family == socket.AF_INET6): # IPv6 + FTP don't work; skip checking completely log = None else: @@ -251,8 +248,7 @@ class MirrorCheckPool(object): self.tasks.put(url) self.threads = [] for _ in range(num_threads): - thread = Thread(target=mirror_url_worker, - args=(self.tasks, self.logs, location, timeout)) + thread = Thread(target=mirror_url_worker, args=(self.tasks, self.logs, location, timeout)) thread.daemon = True self.threads.append(thread) diff --git a/mirrors/management/commands/mirrorresolv.py b/mirrors/management/commands/mirrorresolv.py index d3d8d5f6..e2981476 100644 --- a/mirrors/management/commands/mirrorresolv.py +++ b/mirrors/management/commands/mirrorresolv.py @@ -23,6 +23,7 @@ logging.basicConfig( stream=sys.stderr) logger = logging.getLogger() + class Command(BaseCommand): help = "Runs a check on all active mirror URLs to determine if they are reachable via IPv4 and/or v6." @@ -37,6 +38,7 @@ class Command(BaseCommand): return resolve_mirrors() + def resolve_mirrors(): logger.debug("requesting list of mirror URLs") for mirrorurl in MirrorUrl.objects.filter(active=True, mirror__active=True): @@ -48,7 +50,7 @@ def resolve_mirrors(): mirrorurl.has_ipv4 = socket.AF_INET in families mirrorurl.has_ipv6 = socket.AF_INET6 in families logger.debug("%s: v4: %s v6: %s", mirrorurl.hostname, - mirrorurl.has_ipv4, mirrorurl.has_ipv6) + mirrorurl.has_ipv4, mirrorurl.has_ipv6) # now check new values, only update if new != old newvals = (mirrorurl.has_ipv4, mirrorurl.has_ipv6) if newvals != oldvals: diff --git a/mirrors/migrations/0001_squashed_0002_mirrorurl_bandwidth.py b/mirrors/migrations/0001_squashed_0002_mirrorurl_bandwidth.py index 1818287c..9cfc439b 100644 --- a/mirrors/migrations/0001_squashed_0002_mirrorurl_bandwidth.py +++ b/mirrors/migrations/0001_squashed_0002_mirrorurl_bandwidth.py @@ -34,7 +34,8 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=255, unique=True)), - ('tier', models.SmallIntegerField(choices=[(0, 'Tier 0'), (1, 'Tier 1'), (2, 'Tier 2'), (-1, 'Untiered')], default=2)), + ('tier', models.SmallIntegerField( + choices=[(0, 'Tier 0'), (1, 'Tier 1'), (2, 'Tier 2'), (-1, 'Untiered')], default=2)), ('admin_email', models.EmailField(blank=True, max_length=255)), ('alternate_email', models.EmailField(blank=True, max_length=255)), ('public', models.BooleanField(default=True)), @@ -46,7 +47,8 @@ class Migration(migrations.Migration): ('notes', models.TextField(blank=True)), ('created', models.DateTimeField(editable=False)), ('last_modified', models.DateTimeField(editable=False)), - ('upstream', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='mirrors.Mirror')), + ('upstream', models.ForeignKey( + null=True, on_delete=django.db.models.deletion.SET_NULL, to='mirrors.Mirror')), ], options={ 'ordering': ('name',), @@ -61,7 +63,9 @@ class Migration(migrations.Migration): ('duration', models.FloatField(null=True)), ('is_success', models.BooleanField(default=True)), ('error', models.TextField(blank=True, default='')), - ('location', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='logs', to='mirrors.CheckLocation')), + ('location', models.ForeignKey( + null=True, on_delete=django.db.models.deletion.CASCADE, + related_name='logs', to='mirrors.CheckLocation')), ], options={ 'get_latest_by': 'check_time', @@ -73,8 +77,10 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('protocol', models.CharField(max_length=10, unique=True)), - ('is_download', models.BooleanField(default=True, help_text='Is protocol useful for end-users, e.g. HTTP')), - ('default', models.BooleanField(default=True, help_text='Included by default when building mirror list?')), + ('is_download', models.BooleanField( + default=True, help_text='Is protocol useful for end-users, e.g. HTTP')), + ('default', models.BooleanField( + default=True, help_text='Included by default when building mirror list?')), ('created', models.DateTimeField(editable=False)), ], options={ @@ -87,7 +93,9 @@ class Migration(migrations.Migration): ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('ip', mirrors.fields.IPNetworkField(max_length=44, verbose_name='IP')), ('created', models.DateTimeField(editable=False)), - ('mirror', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rsync_ips', to='mirrors.Mirror')), + ('mirror', models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name='rsync_ips', to='mirrors.Mirror')), ], options={ 'ordering': ('ip',), @@ -104,8 +112,12 @@ class Migration(migrations.Migration): ('has_ipv6', models.BooleanField(default=False, editable=False, verbose_name='IPv6 capable')), ('created', models.DateTimeField(editable=False)), ('active', models.BooleanField(default=True)), - ('mirror', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='urls', to='mirrors.Mirror')), - ('protocol', models.ForeignKey(editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='urls', to='mirrors.MirrorProtocol')), + ('mirror', models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name='urls', to='mirrors.Mirror')), + ('protocol', models.ForeignKey( + editable=False, on_delete=django.db.models.deletion.PROTECT, + related_name='urls', to='mirrors.MirrorProtocol')), ('bandwidth', models.FloatField(blank=True, null=True, verbose_name='bandwidth (mbits)')), ], options={ @@ -115,6 +127,8 @@ class Migration(migrations.Migration): migrations.AddField( model_name='mirrorlog', name='url', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='logs', to='mirrors.MirrorUrl'), + field=models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name='logs', to='mirrors.MirrorUrl'), ), ] diff --git a/mirrors/models.py b/mirrors/models.py index f6e70d99..17ac02df 100644 --- a/mirrors/models.py +++ b/mirrors/models.py @@ -54,10 +54,10 @@ class Mirror(models.Model): class MirrorProtocol(models.Model): protocol = models.CharField(max_length=10, unique=True) - is_download = models.BooleanField(default=True, - help_text="Is protocol useful for end-users, e.g. HTTP") - default = models.BooleanField(default=True, - help_text="Included by default when building mirror list?") + is_download = models.BooleanField( + default=True, help_text="Is protocol useful for end-users, e.g. HTTP") + default = models.BooleanField( + default=True, help_text="Included by default when building mirror list?") created = models.DateTimeField(editable=False) def __str__(self): @@ -69,14 +69,13 @@ class MirrorProtocol(models.Model): class MirrorUrl(models.Model): url = models.CharField("URL", max_length=255, unique=True) - protocol = models.ForeignKey(MirrorProtocol, related_name="urls", - editable=False, on_delete=models.PROTECT) + protocol = models.ForeignKey( + MirrorProtocol, related_name="urls", + editable=False, on_delete=models.PROTECT) mirror = models.ForeignKey(Mirror, related_name="urls", on_delete=models.CASCADE) country = CountryField(blank=True, db_index=True) - has_ipv4 = models.BooleanField("IPv4 capable", default=True, - editable=False) - has_ipv6 = models.BooleanField("IPv6 capable", default=False, - editable=False) + has_ipv4 = models.BooleanField("IPv4 capable", default=True, editable=False) + has_ipv6 = models.BooleanField("IPv6 capable", default=False, editable=False) active = models.BooleanField(default=True) bandwidth = models.FloatField("bandwidth (mbits)", null=True, blank=True) created = models.DateTimeField(editable=False) @@ -137,8 +136,8 @@ class MirrorRsync(models.Model): class CheckLocation(models.Model): hostname = models.CharField(max_length=255) - source_ip = models.GenericIPAddressField('source IP', - unpack_ipv4=True, unique=True) + source_ip = models.GenericIPAddressField( + 'source IP', unpack_ipv4=True, unique=True) country = CountryField() created = models.DateTimeField(editable=False) @@ -191,7 +190,6 @@ class MirrorLog(models.Model): for model in (Mirror, MirrorProtocol, MirrorUrl, MirrorRsync, CheckLocation): - pre_save.connect(set_created_field, sender=model, - dispatch_uid="mirrors.models") + pre_save.connect(set_created_field, sender=model, dispatch_uid="mirrors.models") # vim: set ts=4 sw=4 et: diff --git a/mirrors/templatetags/mirror_status.py b/mirrors/templatetags/mirror_status.py index 83c1571a..26d7ebac 100644 --- a/mirrors/templatetags/mirror_status.py +++ b/mirrors/templatetags/mirror_status.py @@ -3,6 +3,7 @@ from django import template register = template.Library() + @register.filter def duration(value): if not value and type(value) != timedelta: @@ -13,6 +14,7 @@ def duration(value): hrs, mins = divmod(mins, 60) return '%d:%02d' % (hrs, mins) + @register.filter def hours(value): if not value and type(value) != timedelta: diff --git a/mirrors/tests/__init__.py b/mirrors/tests/__init__.py index 4ea5e1fb..cd239adb 100644 --- a/mirrors/tests/__init__.py +++ b/mirrors/tests/__init__.py @@ -3,11 +3,11 @@ from mirrors.models import MirrorUrl, MirrorProtocol, Mirror def create_mirror_url(name='mirror1', country='US', protocol='http', url='https://archlinux.org/'): - mirror = Mirror.objects.create(name=name, - admin_email='admin@archlinux.org') - mirror_protocol = MirrorProtocol.objects.create(protocol=protocol) - mirror_url = MirrorUrl.objects.create(url=url, - protocol=mirror_protocol, - mirror=mirror, - country=country) - return mirror_url + mirror = Mirror.objects.create(name=name, + admin_email='admin@archlinux.org') + mirror_protocol = MirrorProtocol.objects.create(protocol=protocol) + mirror_url = MirrorUrl.objects.create(url=url, + protocol=mirror_protocol, + mirror=mirror, + country=country) + return mirror_url diff --git a/mirrors/tests/test_mirrorcheck.py b/mirrors/tests/test_mirrorcheck.py index c4a6450d..611cd115 100644 --- a/mirrors/tests/test_mirrorcheck.py +++ b/mirrors/tests/test_mirrorcheck.py @@ -147,7 +147,7 @@ class MirrorCheckTest(TestCase): def test_checklocation_model(self): checkloc = CheckLocation.objects.create(hostname='archlinux.org', - source_ip='1.1.1.1') + source_ip='1.1.1.1') with mock.patch('mirrors.management.commands.mirrorcheck.logger') as logger: call_command('mirrorcheck', '-l', '1') logger.info.assert_called() diff --git a/mirrors/tests/test_mirrorrsync.py b/mirrors/tests/test_mirrorrsync.py index 31dc325d..bf5d26fd 100644 --- a/mirrors/tests/test_mirrorrsync.py +++ b/mirrors/tests/test_mirrorrsync.py @@ -6,6 +6,7 @@ from mirrors.models import MirrorRsync, Mirror TEST_IPV6 = "2a0b:4342:1a31:410::" TEST_IPV4 = "8.8.8.8" + class MirrorRsyncTest(TransactionTestCase): def setUp(self): self.mirror = Mirror.objects.create(name='rmirror', diff --git a/mirrors/tests/test_templatetags.py b/mirrors/tests/test_templatetags.py index ec9b61bd..157329f8 100644 --- a/mirrors/tests/test_templatetags.py +++ b/mirrors/tests/test_templatetags.py @@ -19,7 +19,7 @@ class MirrorTemplateTagTest(SimpleTestCase): self.assertEqual(hours(timedelta(hours=5)), '5 hours') self.assertEqual(hours(timedelta(hours=1)), '1 hour') - self.assertEqual(hours(timedelta(seconds=60*60)), '1 hour') + self.assertEqual(hours(timedelta(seconds=60 * 60)), '1 hour') def test_percentage(self): self.assertEqual(percentage(None), u'') diff --git a/mirrors/utils.py b/mirrors/utils.py index bf0af23f..78538fb6 100644 --- a/mirrors/utils.py +++ b/mirrors/utils.py @@ -20,6 +20,7 @@ def dictfetchall(cursor): for row in cursor.fetchall() ] + def status_data(cutoff_time, mirror_id=None): if mirror_id is not None: params = [cutoff_time, mirror_id] @@ -117,12 +118,11 @@ def get_mirror_statuses(cutoff=DEFAULT_CUTOFF, mirror_id=None, show_all=False): cutoff_time = now() - cutoff urls = MirrorUrl.objects.select_related( - 'mirror', 'protocol').order_by('mirror__id', 'url') + 'mirror', 'protocol').order_by('mirror__id', 'url') if mirror_id: urls = urls.filter(mirror_id=mirror_id) if not show_all: - urls = urls.filter(active=True, mirror__active=True, - mirror__public=True) + urls = urls.filter(active=True, mirror__active=True, mirror__public=True) if urls: url_data = status_data(cutoff_time, mirror_id) @@ -133,10 +133,10 @@ def get_mirror_statuses(cutoff=DEFAULT_CUTOFF, mirror_id=None, show_all=False): if mirror_id: check_info = check_info.filter(url__mirror_id=mirror_id) check_info = check_info.aggregate( - mn=Min('check_time'), mx=Max('check_time')) + mn=Min('check_time'), mx=Max('check_time')) if num_checks > 1: check_frequency = (check_info['mx'] - check_info['mn']) \ - / (num_checks - 1) + / (num_checks - 1) else: check_frequency = None else: @@ -157,21 +157,21 @@ def get_mirror_statuses(cutoff=DEFAULT_CUTOFF, mirror_id=None, show_all=False): def get_mirror_errors(cutoff=DEFAULT_CUTOFF, mirror_id=None, show_all=False): cutoff_time = now() - cutoff errors = MirrorLog.objects.filter( - is_success=False, check_time__gte=cutoff_time, - url__mirror__public=True).values('url__id', 'error').annotate( - error_count=Count('error'), last_occurred=Max('check_time') - ).order_by('-last_occurred', '-error_count') + is_success=False, check_time__gte=cutoff_time, url__mirror__public=True).values( + 'url__id', 'error').annotate( + error_count=Count('error'), last_occurred=Max('check_time')).order_by( + '-last_occurred', '-error_count') if mirror_id: errors = errors.filter(url__mirror_id=mirror_id) if not show_all: - errors = errors.filter(url__active=True, url__mirror__active=True, - url__mirror__public=True) + errors = errors.filter( + url__active=True, url__mirror__active=True, url__mirror__public=True) errors = list(errors) to_fetch = [err['url__id'] for err in errors] urls = MirrorUrl.objects.select_related( - 'mirror', 'protocol').in_bulk(to_fetch) + 'mirror', 'protocol').in_bulk(to_fetch) for err in errors: err['url'] = urls[err['url__id']] return errors @@ -184,19 +184,19 @@ def get_mirror_url_for_download(cutoff=DEFAULT_CUTOFF): the last batch of status rows.''' cutoff_time = now() - cutoff log_data = MirrorLog.objects.filter( - check_time__gte=cutoff_time).aggregate( - Max('check_time'), Max('last_sync')) + check_time__gte=cutoff_time).aggregate( + Max('check_time'), Max('last_sync')) if log_data['check_time__max'] is not None: min_check_time = log_data['check_time__max'] - timedelta(minutes=5) min_sync_time = log_data['last_sync__max'] - timedelta(minutes=20) best_logs = MirrorLog.objects.select_related('url').filter( - is_success=True, - check_time__gte=min_check_time, last_sync__gte=min_sync_time, - url__active=True, - url__mirror__public=True, url__mirror__active=True, - url__protocol__default=True, - url__protocol__protocol='https').order_by( - 'duration')[:1] + is_success=True, + check_time__gte=min_check_time, last_sync__gte=min_sync_time, + url__active=True, + url__mirror__public=True, url__mirror__active=True, + url__protocol__default=True, + url__protocol__protocol='https').order_by( + 'duration')[:1] if best_logs: return best_logs[0].url diff --git a/mirrors/views/__init__.py b/mirrors/views/__init__.py index 831bbf0b..19af4535 100644 --- a/mirrors/views/__init__.py +++ b/mirrors/views/__init__.py @@ -9,8 +9,7 @@ from django.utils.timezone import now from django.views.decorators.http import condition from django_countries.fields import Country -from ..models import (Mirror, MirrorUrl, MirrorProtocol, MirrorLog, - CheckLocation) +from ..models import Mirror, MirrorUrl, MirrorLog from ..utils import get_mirror_statuses, get_mirror_errors @@ -22,18 +21,18 @@ def mirrors(request, tier=None): raise Http404 mirror_list = mirror_list.filter(tier=tier) protos = MirrorUrl.objects.values_list( - 'mirror_id', 'protocol__protocol').order_by( - 'mirror_id', 'protocol__protocol').distinct() + 'mirror_id', 'protocol__protocol').order_by( + 'mirror_id', 'protocol__protocol').distinct() countries = MirrorUrl.objects.values_list( - 'mirror_id', 'country').order_by( - 'mirror_id', 'country').distinct() + 'mirror_id', 'country').order_by( + 'mirror_id', 'country').distinct() if not request.user.is_authenticated: mirror_list = mirror_list.filter(public=True, active=True) protos = protos.filter( - mirror__public=True, mirror__active=True, active=True) + mirror__public=True, mirror__active=True, active=True) countries = countries.filter( - mirror__public=True, mirror__active=True, active=True) + mirror__public=True, mirror__active=True, active=True) protos = {k: list(v) for k, v in groupby(protos, key=itemgetter(0))} countries = {k: list(v) for k, v in groupby(countries, key=itemgetter(0))} @@ -47,7 +46,7 @@ def mirrors(request, tier=None): mirror.country = Country(item_countries[0][1]) return render(request, 'mirrors/mirrors.html', - {'mirror_list': mirror_list}) + {'mirror_list': mirror_list}) def mirror_details(request, name): @@ -58,10 +57,8 @@ def mirror_details(request, name): raise Http404 error_cutoff = timedelta(days=7) - status_info = get_mirror_statuses(mirror_id=mirror.id, - show_all=authorized) - checked_urls = {url for url in status_info['urls'] \ - if url.mirror_id == mirror.id} + status_info = get_mirror_statuses(mirror_id=mirror.id, show_all=authorized) + checked_urls = {url for url in status_info['urls'] if url.mirror_id == mirror.id} all_urls = mirror.urls.select_related('protocol') if not authorized: all_urls = all_urls.filter(active=True) @@ -70,12 +67,12 @@ def mirror_details(request, name): other_urls = all_urls.difference(checked_urls) for url in other_urls: for attr in ('last_sync', 'completion_pct', 'delay', 'duration_avg', - 'duration_stddev', 'score'): + 'duration_stddev', 'score'): setattr(url, attr, None) all_urls = sorted(checked_urls.union(other_urls), key=attrgetter('url')) error_logs = get_mirror_errors(mirror_id=mirror.id, cutoff=error_cutoff, - show_all=True) + show_all=True) context = { 'mirror': mirror, @@ -88,7 +85,7 @@ def mirror_details(request, name): def url_details(request, name, url_id): url = get_object_or_404(MirrorUrl.objects.select_related(), - id=url_id, mirror__name=name) + id=url_id, mirror__name=name) mirror = url.mirror authorized = request.user.is_authenticated if not authorized and \ @@ -97,7 +94,7 @@ def url_details(request, name, url_id): error_cutoff = timedelta(days=7) cutoff_time = now() - error_cutoff logs = MirrorLog.objects.select_related('location').filter( - url=url, check_time__gte=cutoff_time).order_by('-check_time') + url=url, check_time__gte=cutoff_time).order_by('-check_time') context = { 'url': url, @@ -139,8 +136,7 @@ def status(request, tier=None): error_logs = get_mirror_errors() if tier is not None: - error_logs = [log for log in error_logs - if log['url'].mirror.tier == tier] + error_logs = [log for log in error_logs if log['url'].mirror.tier == tier] context = status_info.copy() context.update({ diff --git a/mirrors/views/api.py b/mirrors/views/api.py index 268bf330..361e4e87 100644 --- a/mirrors/views/api.py +++ b/mirrors/views/api.py @@ -6,8 +6,7 @@ from django.http import Http404, HttpResponse from django.shortcuts import get_object_or_404 from django.utils.timezone import now -from ..models import (Mirror, MirrorUrl, MirrorProtocol, MirrorLog, - CheckLocation) +from ..models import (Mirror, MirrorUrl, MirrorProtocol, MirrorLog, CheckLocation) from ..utils import get_mirror_statuses, DEFAULT_CUTOFF @@ -15,7 +14,7 @@ class MirrorStatusJSONEncoder(DjangoJSONEncoder): '''Base JSONEncoder extended to handle datetime.timedelta and MirrorUrl serialization. The base class takes care of datetime.datetime types.''' url_attributes = ('url', 'protocol', 'last_sync', 'completion_pct', - 'delay', 'duration_avg', 'duration_stddev', 'score', 'active') + 'delay', 'duration_avg', 'duration_stddev', 'score', 'active') def default(self, obj): if isinstance(obj, timedelta): @@ -39,14 +38,14 @@ class MirrorStatusJSONEncoder(DjangoJSONEncoder): class ExtendedMirrorStatusJSONEncoder(MirrorStatusJSONEncoder): '''Adds URL check history information.''' log_attributes = ('check_time', 'last_sync', 'duration', 'is_success', - 'location_id') + 'location_id') def default(self, obj): if isinstance(obj, MirrorUrl): data = super(ExtendedMirrorStatusJSONEncoder, self).default(obj) cutoff = now() - DEFAULT_CUTOFF data['logs'] = list(obj.logs.filter( - check_time__gte=cutoff).order_by('check_time')) + check_time__gte=cutoff).order_by('check_time')) return data if isinstance(obj, MirrorLog): data = {attr: getattr(obj, attr) for attr in self.log_attributes} @@ -91,16 +90,14 @@ def mirror_details_json(request, name): mirror = get_object_or_404(Mirror, name=name) if not authorized and (not mirror.public or not mirror.active): raise Http404 - status_info = get_mirror_statuses(mirror_id=mirror.id, - show_all=authorized) + status_info = get_mirror_statuses(mirror_id=mirror.id, show_all=authorized) data = status_info.copy() data['version'] = 4 data['details'] = mirror.get_full_url() if authorized and request.user.has_perm('mirrors.change_mirror'): data['admin_email'] = mirror.admin_email data['alternate_email'] = mirror.alternate_email - to_json = json.dumps(data, ensure_ascii=False, - cls=ExtendedMirrorStatusJSONEncoder) + to_json = json.dumps(data, ensure_ascii=False, cls=ExtendedMirrorStatusJSONEncoder) response = HttpResponse(to_json, content_type='application/json') return response diff --git a/mirrors/views/mirrorlist.py b/mirrors/views/mirrorlist.py index 45c01819..dadb64ca 100644 --- a/mirrors/views/mirrorlist.py +++ b/mirrors/views/mirrorlist.py @@ -12,23 +12,21 @@ from ..utils import get_mirror_statuses import random + class MirrorlistForm(forms.Form): - country = forms.MultipleChoiceField(required=False, - widget=SelectMultiple(attrs={'size': '12'})) - protocol = forms.MultipleChoiceField(required=False, - widget=CheckboxSelectMultiple) - ip_version = forms.MultipleChoiceField(required=False, - label="IP version", choices=(('4','IPv4'), ('6','IPv6')), - widget=CheckboxSelectMultiple) + country = forms.MultipleChoiceField(required=False, widget=SelectMultiple(attrs={'size': '12'})) + protocol = forms.MultipleChoiceField(required=False, widget=CheckboxSelectMultiple) + ip_version = forms.MultipleChoiceField( + required=False, label="IP version", choices=(('4', 'IPv4'), ('6', 'IPv6')), + widget=CheckboxSelectMultiple) use_mirror_status = forms.BooleanField(required=False) def __init__(self, *args, **kwargs): super(MirrorlistForm, self).__init__(*args, **kwargs) fields = self.fields - fields['country'].choices = [('all','All')] + self.get_countries() + fields['country'].choices = [('all', 'All')] + self.get_countries() fields['country'].initial = ['all'] - protos = [(p.protocol, p.protocol) for p in - MirrorProtocol.objects.filter(is_download=True)] + protos = [(p.protocol, p.protocol) for p in MirrorProtocol.objects.filter(is_download=True)] initial = MirrorProtocol.objects.filter(is_download=True, default=True) fields['protocol'].choices = protos fields['protocol'].initial = [p.protocol for p in initial] @@ -36,20 +34,20 @@ class MirrorlistForm(forms.Form): def get_countries(self): country_codes = set() - country_codes.update(MirrorUrl.objects.filter(active=True, - mirror__active=True).exclude(country='').values_list( - 'country', flat=True).order_by().distinct()) + country_codes.update(MirrorUrl.objects.filter( + active=True, mirror__active=True).exclude(country='').values_list( + 'country', flat=True).order_by().distinct()) code_list = [(code, countries.name(code)) for code in country_codes] return sorted(code_list, key=itemgetter(1)) def as_div(self): "Returns this form rendered as HTML s." return self._html_output( - normal_row = u'%(label)s %(field)s%(help_text)s', - error_row = u'%s', - row_ender = '', - help_text_html = u' %s', - errors_on_separate_row = True) + normal_row=u'%(label)s %(field)s%(help_text)s', + error_row=u'%s', + row_ender='', + help_text_html=u' %s', + errors_on_separate_row=True) @csrf_exempt @@ -64,12 +62,12 @@ def generate_mirrorlist(request): ipv4 = '4' in form.cleaned_data['ip_version'] ipv6 = '6' in form.cleaned_data['ip_version'] return find_mirrors(request, countries, protocols, - use_status, ipv4, ipv6) + use_status, ipv4, ipv6) else: form = MirrorlistForm() return render(request, 'mirrors/mirrorlist_generate.html', - {'mirrorlist_form': form}) + {'mirrorlist_form': form}) def status_filter(original_urls): @@ -88,7 +86,7 @@ def status_filter(original_urls): def find_mirrors(request, countries=None, protocols=None, use_status=False, - ipv4_supported=True, ipv6_supported=True): + ipv4_supported=True, ipv6_supported=True): if not protocols: protocols = MirrorProtocol.objects.filter(is_download=True) elif hasattr(protocols, 'model') and protocols.model == MirrorProtocol: @@ -97,8 +95,8 @@ def find_mirrors(request, countries=None, protocols=None, use_status=False, else: protocols = MirrorProtocol.objects.filter(protocol__in=protocols) qset = MirrorUrl.objects.select_related().filter( - protocol__in=protocols, active=True, - mirror__public=True, mirror__active=True) + protocol__in=protocols, active=True, + mirror__public=True, mirror__active=True) if countries and 'all' not in countries: qset = qset.filter(country__in=countries) diff --git a/news/migrations/0001_squashed_0002_news_send_announce.py b/news/migrations/0001_squashed_0002_news_send_announce.py index 9250e4e4..59f438c5 100644 --- a/news/migrations/0001_squashed_0002_news_send_announce.py +++ b/news/migrations/0001_squashed_0002_news_send_announce.py @@ -27,7 +27,8 @@ class Migration(migrations.Migration): ('guid', models.CharField(editable=False, max_length=255)), ('content', models.TextField()), ('safe_mode', models.BooleanField(default=True)), - ('author', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='news_author', to=settings.AUTH_USER_MODEL)), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, + related_name='news_author', to=settings.AUTH_USER_MODEL)), ('send_announce', models.BooleanField(default=True)), ], options={ diff --git a/news/models.py b/news/models.py index 7e321f70..340d737e 100644 --- a/news/models.py +++ b/news/models.py @@ -1,4 +1,5 @@ from django.db import models +from django.db.models.signals import pre_save from django.contrib.auth.models import User from django.contrib.sites.models import Site from django.utils.safestring import mark_safe @@ -10,7 +11,7 @@ from main.utils import parse_markdown class News(models.Model): slug = models.SlugField(max_length=255, unique=True) author = models.ForeignKey(User, related_name='news_author', - on_delete=models.PROTECT) + on_delete=models.PROTECT) postdate = models.DateTimeField("post date", db_index=True) last_modified = models.DateTimeField(editable=False, db_index=True) title = models.CharField(max_length=255) @@ -42,13 +43,9 @@ def set_news_fields(sender, **kwargs): if not news.postdate: news.postdate = current_time # http://diveintomark.org/archives/2004/05/28/howto-atom-id - news.guid = 'tag:%s,%s:%s' % (Site.objects.get_current(), - current_time.strftime('%Y-%m-%d'), news.get_absolute_url()) - + news.guid = f"tag:{Site.objects.get_current()},{current_time.strftime('%Y-%m-%d')}:{news.get_absolute_url()}" -from django.db.models.signals import pre_save -pre_save.connect(set_news_fields, sender=News, - dispatch_uid="news.models") +pre_save.connect(set_news_fields, sender=News, dispatch_uid="news.models") # vim: set ts=4 sw=4 et: diff --git a/news/tests.py b/news/tests.py index b7cdd2dd..7996cad5 100644 --- a/news/tests.py +++ b/news/tests.py @@ -32,8 +32,8 @@ class NewsCrud(TransactionTestCase): 'admin@archlinux.org', password) self.client.post('/login/', { - 'username': self.user.username, - 'password': password + 'username': self.user.username, + 'password': password }) def tearDown(self): diff --git a/news/urls.py b/news/urls.py index 111de4f5..32299542 100644 --- a/news/urls.py +++ b/news/urls.py @@ -1,7 +1,7 @@ from django.conf.urls import url from django.contrib.auth.decorators import permission_required from .views import (NewsDetailView, NewsListView, NewsCreateView, NewsEditView, - NewsDeleteView, preview, view_redirect) + NewsDeleteView, preview, view_redirect) urlpatterns = [ diff --git a/news/views.py b/news/views.py index 24423cca..8af42b09 100644 --- a/news/views.py +++ b/news/views.py @@ -5,8 +5,7 @@ from django.http import HttpResponse from django.shortcuts import get_object_or_404, redirect from django.template import loader from django.views.decorators.http import require_POST -from django.views.generic import (DetailView, ListView, - CreateView, UpdateView, DeleteView) +from django.views.generic import DetailView, ListView, CreateView, UpdateView, DeleteView from .models import News from main.utils import find_unique_slug, parse_markdown @@ -48,11 +47,12 @@ class NewsCreateView(CreateView): if settings.MAILMAN_PASSWORD: headers['Approved'] = settings.MAILMAN_PASSWORD template = loader.get_template('news/news_email_notification.txt') - EmailMessage(subject='[arch-announce] %s' % newsitem.title, - body=template.render(ctx), - from_email='"Arch Linux: Recent news updates: %s" ' % newsitem.author.get_full_name(), - to=['arch-announce@archlinux.org'], - headers=headers).send() + EmailMessage( + subject=f'[arch-announce] {newsitem.title}', + body=template.render(ctx), + from_email=f'Arch Linux: Recent news updates: {newsitem.author.get_full_name()} ', # noqa + to=['arch-announce@archlinux.org'], + headers=headers).send() return super(NewsCreateView, self).form_valid(form) diff --git a/packages/admin.py b/packages/admin.py index 889bae25..792e65e8 100644 --- a/packages/admin.py +++ b/packages/admin.py @@ -1,7 +1,7 @@ from django.contrib import admin -from .models import (PackageRelation, FlagRequest, - Signoff, SignoffSpecification, Update) +from .models import (PackageRelation, FlagRequest, Signoff, SignoffSpecification, + Update) class PackageRelationAdmin(admin.ModelAdmin): @@ -14,7 +14,7 @@ class PackageRelationAdmin(admin.ModelAdmin): class FlagRequestAdmin(admin.ModelAdmin): list_display = ('pkgbase', 'full_version', 'repo', 'created', 'who', - 'is_spam', 'is_legitimate', 'message') + 'is_spam', 'is_legitimate', 'message') list_filter = ('is_spam', 'is_legitimate', 'repo', 'created') search_fields = ('pkgbase', 'user_email', 'message') ordering = ('-created',) @@ -26,7 +26,7 @@ class FlagRequestAdmin(admin.ModelAdmin): class SignoffAdmin(admin.ModelAdmin): list_display = ('pkgbase', 'full_version', 'arch', 'repo', - 'user', 'created', 'revoked') + 'user', 'created', 'revoked') list_filter = ('arch', 'repo', 'user', 'created') search_fields = ('pkgbase', 'user__username') ordering = ('-created',) @@ -34,7 +34,7 @@ class SignoffAdmin(admin.ModelAdmin): class SignoffSpecificationAdmin(admin.ModelAdmin): list_display = ('pkgbase', 'full_version', 'arch', 'repo', - 'user', 'created', 'comments') + 'user', 'created', 'comments') list_filter = ('arch', 'repo', 'user', 'created') search_fields = ('pkgbase', 'user__username') ordering = ('-created',) @@ -46,7 +46,7 @@ class SignoffSpecificationAdmin(admin.ModelAdmin): class UpdateAdmin(admin.ModelAdmin): list_display = ('pkgname', 'repo', 'arch', 'action_flag', - 'old_version', 'new_version', 'created') + 'old_version', 'new_version', 'created') list_filter = ('action_flag', 'repo', 'arch', 'created') search_fields = ('pkgname',) ordering = ('-created',) diff --git a/packages/alpm.py b/packages/alpm.py index a4c540c4..8b6bba57 100644 --- a/packages/alpm.py +++ b/packages/alpm.py @@ -3,7 +3,7 @@ from ctypes.util import find_library import operator -def load_alpm(name=None): # pragma: no cover +def load_alpm(name=None): # pragma: no cover # Load the alpm library and set up some of the functions we might use if name is None: name = find_library('alpm') @@ -27,6 +27,7 @@ def load_alpm(name=None): # pragma: no cover ALPM = load_alpm() + class AlpmAPI(object): OPERATOR_MAP = { '=': operator.eq, @@ -62,14 +63,14 @@ class AlpmAPI(object): return func(res, 0) -def main(): # pragma: no cover +def main(): # pragma: no cover api = AlpmAPI() print((api.version())) print((api.vercmp(1, 2))) print((api.compare_versions(1, '<', 2))) -if __name__ == '__main__': # pragma: no cover +if __name__ == '__main__': # pragma: no cover main() # vim: set ts=4 sw=4 et: diff --git a/packages/management/commands/populate_signoffs.py b/packages/management/commands/populate_signoffs.py index 4e4de2d5..a86fa846 100644 --- a/packages/management/commands/populate_signoffs.py +++ b/packages/management/commands/populate_signoffs.py @@ -28,6 +28,7 @@ logging.basicConfig( stream=sys.stderr) logger = logging.getLogger() + class Command(BaseCommand): help = """Pull the latest commit message from SVN for a given package that is signoff-eligible and does not have an existing comment attached""" @@ -44,6 +45,7 @@ is signoff-eligible and does not have an existing comment attached""" add_signoff_comments() cleanup_signoff_comments() + def svn_log(pkgbase, repo): '''Retrieve the most recent SVN log entry for the given pkgbase and repository. The configured setting SVN_BASE_URL is used along with the @@ -55,7 +57,7 @@ def svn_log(pkgbase, repo): xml = XML(log_data) revision = int(xml.find('logentry').get('revision')) date = datetime.strptime(xml.findtext('logentry/date'), - '%Y-%m-%dT%H:%M:%S.%fZ') + '%Y-%m-%dT%H:%M:%S.%fZ') return { 'revision': revision, 'date': date, @@ -63,6 +65,7 @@ def svn_log(pkgbase, repo): 'message': xml.findtext('logentry/msg'), } + def cached_svn_log(pkgbase, repo): '''Retrieve the cached version of the SVN log if possible, else delegate to svn_log() to do the work and cache the result.''' @@ -72,18 +75,22 @@ def cached_svn_log(pkgbase, repo): log = svn_log(pkgbase, repo) cached_svn_log.cache[key] = log return log + + cached_svn_log.cache = {} + def create_specification(package, log, finder): trimmed_message = log['message'].strip() required = package.arch.required_signoffs spec = SignoffSpecification(pkgbase=package.pkgbase, - pkgver=package.pkgver, pkgrel=package.pkgrel, - epoch=package.epoch, arch=package.arch, repo=package.repo, - comments=trimmed_message, required=required) + pkgver=package.pkgver, pkgrel=package.pkgrel, + epoch=package.epoch, arch=package.arch, repo=package.repo, + comments=trimmed_message, required=required) spec.user = finder.find_by_username(log['author']) return spec + def add_signoff_comments(): logger.info("getting all signoff groups") groups = get_signoff_groups() @@ -101,9 +108,10 @@ def add_signoff_comments(): logger.info("creating spec with SVN message for %s", group.pkgbase) spec = create_specification(group.packages[0], log, finder) spec.save() - except: + except: # noqa logger.exception("error getting SVN log for %s", group.pkgbase) + def cleanup_signoff_comments(): logger.info("getting all signoff groups") groups = get_signoff_groups() diff --git a/packages/migrations/0001_squashed_0003_auto_20170524_0704.py b/packages/migrations/0001_squashed_0003_auto_20170524_0704.py index a9131139..17657307 100644 --- a/packages/migrations/0001_squashed_0003_auto_20170524_0704.py +++ b/packages/migrations/0001_squashed_0003_auto_20170524_0704.py @@ -24,7 +24,8 @@ class Migration(migrations.Migration): ('name', models.CharField(db_index=True, max_length=255)), ('version', models.CharField(default='', max_length=255)), ('comparison', models.CharField(default='', max_length=255)), - ('pkg', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='conflicts', to='main.Package')), + ('pkg', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, + related_name='conflicts', to='main.Package')), ], options={ 'ordering': ('name',), @@ -39,8 +40,11 @@ class Migration(migrations.Migration): ('version', models.CharField(default='', max_length=255)), ('comparison', models.CharField(default='', max_length=255)), ('description', models.TextField(blank=True, null=True)), - ('deptype', models.CharField(choices=[('D', 'Depend'), ('O', 'Optional Depend'), ('M', 'Make Depend'), ('C', 'Check Depend')], default='D', max_length=1)), - ('pkg', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='depends', to='main.Package')), + ('deptype', models.CharField( + choices=[('D', 'Depend'), ('O', 'Optional Depend'), ('M', 'Make Depend'), ('C', 'Check Depend')], + default='D', max_length=1)), + ('pkg', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='depends', + to='main.Package')), ], options={ 'ordering': ('name',), @@ -61,9 +65,11 @@ class Migration(migrations.Migration): ('num_packages', models.PositiveIntegerField(default=1, verbose_name='number of packages')), ('message', models.TextField(blank=True, verbose_name='message to developer')), ('is_spam', models.BooleanField(default=False, help_text='Is this comment from a real person?')), - ('is_legitimate', models.BooleanField(default=True, help_text='Is this actually an out-of-date flag request?')), + ('is_legitimate', models.BooleanField(default=True, + help_text='Is this actually an out-of-date flag request?')), ('repo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.Repo')), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL)), ], options={ 'get_latest_by': 'created', @@ -74,7 +80,8 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=255)), - ('pkg', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='licenses', to='main.Package')), + ('pkg', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, + related_name='licenses', to='main.Package')), ], options={ 'ordering': ('name',), @@ -85,7 +92,8 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(db_index=True, max_length=255)), - ('pkg', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='groups', to='main.Package')), + ('pkg', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, + related_name='groups', to='main.Package')), ], options={ 'ordering': ('name',), @@ -98,7 +106,8 @@ class Migration(migrations.Migration): ('pkgbase', models.CharField(max_length=255)), ('type', models.PositiveIntegerField(choices=[(1, 'Maintainer'), (2, 'Watcher')], default=1)), ('created', models.DateTimeField(editable=False)), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='package_relations', to=settings.AUTH_USER_MODEL)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, + related_name='package_relations', to=settings.AUTH_USER_MODEL)), ], ), migrations.CreateModel( @@ -107,7 +116,8 @@ class Migration(migrations.Migration): ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(db_index=True, max_length=255)), ('version', models.CharField(default='', max_length=255)), - ('pkg', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='provides', to='main.Package')), + ('pkg', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, + related_name='provides', to='main.Package')), ], options={ 'ordering': ('name',), @@ -121,7 +131,8 @@ class Migration(migrations.Migration): ('name', models.CharField(db_index=True, max_length=255)), ('version', models.CharField(default='', max_length=255)), ('comparison', models.CharField(default='', max_length=255)), - ('pkg', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='replaces', to='main.Package')), + ('pkg', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, + related_name='replaces', to='main.Package')), ], options={ 'ordering': ('name',), @@ -141,7 +152,8 @@ class Migration(migrations.Migration): ('comments', models.TextField(blank=True, null=True)), ('arch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.Arch')), ('repo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.Repo')), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='package_signoffs', to=settings.AUTH_USER_MODEL)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, + related_name='package_signoffs', to=settings.AUTH_USER_MODEL)), ], ), migrations.CreateModel( @@ -153,13 +165,16 @@ class Migration(migrations.Migration): ('pkgrel', models.CharField(max_length=255)), ('epoch', models.PositiveIntegerField(default=0)), ('created', models.DateTimeField(editable=False)), - ('required', models.PositiveIntegerField(default=2, help_text='How many signoffs are required for this package?')), + ('required', models.PositiveIntegerField(default=2, + help_text='How many signoffs are required for this package?')), ('enabled', models.BooleanField(default=True, help_text='Is this package eligible for signoffs?')), - ('known_bad', models.BooleanField(default=False, help_text='Is this package known to be broken in some way?')), + ('known_bad', models.BooleanField(default=False, + help_text='Is this package known to be broken in some way?')), ('comments', models.TextField(blank=True, null=True)), ('arch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.Arch')), ('repo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.Repo')), - ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL)), ], ), migrations.CreateModel( @@ -168,7 +183,8 @@ class Migration(migrations.Migration): ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('pkgname', models.CharField(db_index=True, max_length=255)), ('pkgbase', models.CharField(max_length=255)), - ('action_flag', models.PositiveSmallIntegerField(choices=[(1, 'Addition'), (2, 'Change'), (3, 'Deletion')], verbose_name='action flag')), + ('action_flag', models.PositiveSmallIntegerField( + choices=[(1, 'Addition'), (2, 'Change'), (3, 'Deletion')], verbose_name='action flag')), ('created', models.DateTimeField(db_index=True, editable=False)), ('old_pkgver', models.CharField(max_length=255, null=True)), ('old_pkgrel', models.CharField(max_length=255, null=True)), @@ -176,9 +192,12 @@ class Migration(migrations.Migration): ('new_pkgver', models.CharField(max_length=255, null=True)), ('new_pkgrel', models.CharField(max_length=255, null=True)), ('new_epoch', models.PositiveIntegerField(null=True)), - ('arch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='updates', to='main.Arch')), - ('package', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='updates', to='main.Package')), - ('repo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='updates', to='main.Repo')), + ('arch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, + related_name='updates', to='main.Arch')), + ('package', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, + related_name='updates', to='main.Package')), + ('repo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, + related_name='updates', to='main.Repo')), ], options={ 'get_latest_by': 'created', diff --git a/packages/models.py b/packages/models.py index a64a9e5a..b41b3719 100644 --- a/packages/models.py +++ b/packages/models.py @@ -20,8 +20,8 @@ class PackageRelation(models.Model): MAINTAINER = 1 WATCHER = 2 TYPE_CHOICES = ( - (MAINTAINER, 'Maintainer'), - (WATCHER, 'Watcher'), + (MAINTAINER, 'Maintainer'), + (WATCHER, 'Watcher'), ) pkgbase = models.CharField(max_length=255) user = models.ForeignKey(User, related_name="package_relations", on_delete=models.CASCADE) @@ -42,8 +42,7 @@ class PackageRelation(models.Model): return Update.objects.filter(pkgbase=self.pkgbase).latest() def __str__(self): - return '%s: %s (%s)' % ( - self.pkgbase, self.user, self.get_type_display()) + return f'{self.pkgbase}: {self.user} ({self.get_typw_display()})' class SignoffSpecificationManager(models.Manager): @@ -51,8 +50,8 @@ class SignoffSpecificationManager(models.Manager): '''Utility method to pull all relevant name-version fields from a package and get a matching signoff specification.''' return self.get( - pkgbase=pkg.pkgbase, pkgver=pkg.pkgver, pkgrel=pkg.pkgrel, - epoch=pkg.epoch, arch=pkg.arch, repo=pkg.repo) + pkgbase=pkg.pkgbase, pkgver=pkg.pkgver, pkgrel=pkg.pkgrel, + epoch=pkg.epoch, arch=pkg.arch, repo=pkg.repo) def get_or_default_from_package(self, pkg): '''utility method to pull all relevant name-version fields from a @@ -60,8 +59,8 @@ class SignoffSpecificationManager(models.Manager): base case.''' try: return self.get( - pkgbase=pkg.pkgbase, pkgver=pkg.pkgver, pkgrel=pkg.pkgrel, - epoch=pkg.epoch, arch=pkg.arch, repo=pkg.repo) + pkgbase=pkg.pkgbase, pkgver=pkg.pkgver, pkgrel=pkg.pkgrel, + epoch=pkg.epoch, arch=pkg.arch, repo=pkg.repo) except SignoffSpecification.DoesNotExist: return fake_signoff_spec(pkg.arch) @@ -82,11 +81,11 @@ class SignoffSpecification(models.Model): user = models.ForeignKey(User, null=True, on_delete=models.CASCADE) created = models.DateTimeField(editable=False) required = models.PositiveIntegerField(default=2, - help_text="How many signoffs are required for this package?") + help_text="How many signoffs are required for this package?") enabled = models.BooleanField(default=True, - help_text="Is this package eligible for signoffs?") + help_text="Is this package eligible for signoffs?") known_bad = models.BooleanField(default=False, - help_text="Is this package known to be broken in some way?") + help_text="Is this package known to be broken in some way?") comments = models.TextField(null=True, blank=True) objects = SignoffSpecificationManager() @@ -104,8 +103,9 @@ class SignoffSpecification(models.Model): # Fake signoff specs for when we don't have persisted ones in the database. # These have all necessary attributes of the real thing but are lighter weight # and have no chance of being persisted. -FakeSignoffSpecification = namedtuple('FakeSignoffSpecification', - ('required', 'enabled', 'known_bad', 'comments')) +FakeSignoffSpecification = namedtuple( + 'FakeSignoffSpecification', + ('required', 'enabled', 'known_bad', 'comments')) def fake_signoff_spec(arch): @@ -118,22 +118,23 @@ class SignoffManager(models.Manager): package and get a matching signoff.''' not_revoked = not revoked return self.get( - pkgbase=pkg.pkgbase, pkgver=pkg.pkgver, pkgrel=pkg.pkgrel, - epoch=pkg.epoch, arch=pkg.arch, repo=pkg.repo, - revoked__isnull=not_revoked, user=user) + pkgbase=pkg.pkgbase, pkgver=pkg.pkgver, pkgrel=pkg.pkgrel, + epoch=pkg.epoch, arch=pkg.arch, repo=pkg.repo, + revoked__isnull=not_revoked, user=user) def get_or_create_from_package(self, pkg, user): '''Utility method to pull all relevant name-version fields from a package and get or create a matching signoff.''' return self.get_or_create( - pkgbase=pkg.pkgbase, pkgver=pkg.pkgver, pkgrel=pkg.pkgrel, - epoch=pkg.epoch, arch=pkg.arch, repo=pkg.repo, - revoked=None, user=user) + pkgbase=pkg.pkgbase, pkgver=pkg.pkgver, pkgrel=pkg.pkgrel, + epoch=pkg.epoch, arch=pkg.arch, repo=pkg.repo, + revoked=None, user=user) def for_package(self, pkg): return self.select_related('user').filter( - pkgbase=pkg.pkgbase, pkgver=pkg.pkgver, pkgrel=pkg.pkgrel, - epoch=pkg.epoch, arch=pkg.arch, repo=pkg.repo) + pkgbase=pkg.pkgbase, pkgver=pkg.pkgver, pkgrel=pkg.pkgrel, + epoch=pkg.epoch, arch=pkg.arch, repo=pkg.repo) + class Signoff(models.Model): ''' @@ -157,8 +158,8 @@ class Signoff(models.Model): @property def packages(self): return Package.objects.normal().filter(pkgbase=self.pkgbase, - pkgver=self.pkgver, pkgrel=self.pkgrel, epoch=self.epoch, - arch=self.arch, repo=self.repo) + pkgver=self.pkgver, pkgrel=self.pkgrel, epoch=self.epoch, + arch=self.arch, repo=self.repo) @property def full_version(self): @@ -170,8 +171,7 @@ class Signoff(models.Model): revoked = '' if self.revoked: revoked = ' (revoked)' - return '%s-%s: %s%s' % ( - self.pkgbase, self.full_version, self.user, revoked) + return f'{self.pkgbase}-{self.full_version}: {self.user}{revoked}' class FlagRequest(models.Model): @@ -190,9 +190,9 @@ class FlagRequest(models.Model): num_packages = models.PositiveIntegerField('number of packages', default=1) message = models.TextField('message to developer', blank=True) is_spam = models.BooleanField(default=False, - help_text="Is this comment from a real person?") + help_text="Is this comment from a real person?") is_legitimate = models.BooleanField(default=True, - help_text="Is this actually an out-of-date flag request?") + help_text="Is this actually an out-of-date flag request?") class Meta: get_latest_by = 'created' @@ -215,10 +215,10 @@ class FlagRequest(models.Model): def get_associated_packages(self): return Package.objects.normal().filter( - pkgbase=self.pkgbase, - repo__testing=self.repo.testing, - repo__staging=self.repo.staging).order_by( - 'pkgname', 'repo__name', 'arch__name') + pkgbase=self.pkgbase, + repo__testing=self.repo.testing, + repo__staging=self.repo.staging).order_by( + 'pkgname', 'repo__name', 'arch__name') def __str__(self): return '%s from %s on %s' % (self.pkgbase, self.who(), self.created) @@ -249,9 +249,9 @@ class UpdateManager(models.Manager): if new_pkg: update.action_flag = CHANGE # ensure we should even be logging this - if (old_pkg.pkgver == new_pkg.pkgver and - old_pkg.pkgrel == new_pkg.pkgrel and - old_pkg.epoch == new_pkg.epoch): + if (old_pkg.pkgver == new_pkg.pkgver + and old_pkg.pkgrel == new_pkg.pkgrel + and old_pkg.epoch == new_pkg.epoch): # all relevant fields were the same; e.g. a force update return else: @@ -277,13 +277,12 @@ class Update(models.Model): ) package = models.ForeignKey(Package, related_name="updates", - null=True, on_delete=models.SET_NULL) + null=True, on_delete=models.SET_NULL) repo = models.ForeignKey(Repo, related_name="updates", on_delete=models.CASCADE) arch = models.ForeignKey(Arch, related_name="updates", on_delete=models.CASCADE) pkgname = models.CharField(max_length=255, db_index=True) pkgbase = models.CharField(max_length=255) - action_flag = models.PositiveSmallIntegerField('action flag', - choices=UPDATE_ACTION_CHOICES) + action_flag = models.PositiveSmallIntegerField('action flag', choices=UPDATE_ACTION_CHOICES) created = models.DateTimeField(editable=False, db_index=True) old_pkgver = models.CharField(max_length=255, null=True) @@ -325,12 +324,10 @@ class Update(models.Model): return '%s-%s' % (self.new_pkgver, self.new_pkgrel) def elsewhere(self): - return Package.objects.normal().filter( - pkgname=self.pkgname, arch=self.arch) + return Package.objects.normal().filter(pkgname=self.pkgname, arch=self.arch) def replacements(self): - pkgs = Package.objects.normal().filter( - replaces__name=self.pkgname) + pkgs = Package.objects.normal().filter(replaces__name=self.pkgname) if not self.arch.agnostic: # make sure we match architectures if possible arches = set(Arch.objects.filter(agnostic=True)) @@ -339,12 +336,10 @@ class Update(models.Model): return pkgs def get_absolute_url(self): - return '/packages/%s/%s/%s/' % (self.repo.name.lower(), - self.arch.name, self.pkgname) + return f'/packages/{self.repo.name.lower()}/{self.arch.name}/{self.pkgname}/' def __str__(self): - return '%s of %s on %s' % (self.get_action_flag_display(), - self.pkgname, self.created) + return f'{self.get_action_flag_display()} of {self.pkgname} on {self.created}' class PackageGroup(models.Model): @@ -386,7 +381,7 @@ class RelatedToBase(models.Model): # TODO: this may in fact be faster- select only the fields we know will # actually get used, saving us some bandwidth and hopefully query # construction time. However, reality hasn't quite proved it out yet. - #pkgs = Package.objects.select_related('repo', 'arch').only( + # pkgs = Package.objects.select_related('repo', 'arch').only( # 'id', 'pkgname', 'epoch', 'pkgver', 'pkgrel', # 'repo__id', 'repo__name', 'repo__testing', 'repo__staging', # 'arch__id', 'arch__name').filter(pkgname=self.name) @@ -398,9 +393,8 @@ class RelatedToBase(models.Model): # actually satisfy the requirements if self.comparison and self.version: alpm = AlpmAPI() - pkgs = [pkg for pkg in pkgs if not alpm.available or - alpm.compare_versions(pkg.full_version, self.comparison, - self.version)] + pkgs = [pkg for pkg in pkgs if not alpm.available + or alpm.compare_versions(pkg.full_version, self.comparison, self.version)] if len(pkgs) == 0: # couldn't find a package in the DB # it should be a virtual depend (or a removed package) @@ -426,8 +420,7 @@ class RelatedToBase(models.Model): '''Return providers of this related package. Does *not* include exact matches as it checks the Provision names only, use get_best_satisfier() instead for exact matches.''' - pkgs = Package.objects.normal().filter( - provides__name=self.name).order_by().distinct() + pkgs = Package.objects.normal().filter(provides__name=self.name).order_by().distinct() if not self.pkg.arch.agnostic: # make sure we match architectures if possible arches = self.pkg.applicable_arches() @@ -443,16 +436,14 @@ class RelatedToBase(models.Model): for provide in package.provides.all(): if provide.name != self.name: continue - if alpm.compare_versions(provide.version, - self.comparison, self.version): + if alpm.compare_versions(provide.version, self.comparison, self.version): new_pkgs.append(package) pkgs = new_pkgs # Sort providers by preference. We sort those in same staging/testing # combination first, followed by others. We sort by a (staging, # testing) match tuple that will be (True, True) in the best case. - key_func = lambda x: (x.repo.staging == self.pkg.repo.staging, - x.repo.testing == self.pkg.repo.testing) + key_func = lambda x: (x.repo.staging == self.pkg.repo.staging, x.repo.testing == self.pkg.repo.testing) return sorted(pkgs, key=key_func, reverse=True) def __str__(self): @@ -476,8 +467,7 @@ class Depend(RelatedToBase): pkg = models.ForeignKey(Package, related_name='depends', on_delete=models.CASCADE) comparison = models.CharField(max_length=255, default='') description = models.TextField(null=True, blank=True) - deptype = models.CharField(max_length=1, default='D', - choices=DEPTYPE_CHOICES) + deptype = models.CharField(max_length=1, default='D', choices=DEPTYPE_CHOICES) def __str__(self): '''For depends, we may also have a description and a modifier.''' @@ -510,8 +500,7 @@ class Replacement(RelatedToBase): # hook up some signals for sender in (FlagRequest, PackageRelation, - SignoffSpecification, Signoff, Update): - pre_save.connect(set_created_field, sender=sender, - dispatch_uid="packages.models") + SignoffSpecification, Signoff, Update): + pre_save.connect(set_created_field, sender=sender, dispatch_uid="packages.models") # vim: set ts=4 sw=4 et: diff --git a/packages/templatetags/package_extras.py b/packages/templatetags/package_extras.py index 5486c61d..0f10c15b 100644 --- a/packages/templatetags/package_extras.py +++ b/packages/templatetags/package_extras.py @@ -29,11 +29,9 @@ def do_buildsortqs(parser, token): try: _, sortfield = token.split_contents() except ValueError: - raise template.TemplateSyntaxError( - "%r tag requires a single argument" % token) + raise template.TemplateSyntaxError("%r tag requires a single argument" % token) if not (sortfield[0] == sortfield[-1] and sortfield[0] in ('"', "'")): - raise template.TemplateSyntaxError( - "%r tag's argument should be in quotes" % token) + raise template.TemplateSyntaxError("%r tag's argument should be in quotes" % token) return BuildQueryStringNode(sortfield[1:-1]) diff --git a/packages/tests.py b/packages/tests.py index f2dae8cb..0b3eb4bf 100644 --- a/packages/tests.py +++ b/packages/tests.py @@ -326,8 +326,8 @@ class UnFlagPackage(TransactionTestCase): self.profile.allowed_repos.add(Repo.objects.get(name='Core')) self.profile.save() self.client.post('/login/', { - 'username': self.user.username, - 'password': password + 'username': self.user.username, + 'password': password }) def tearDown(self): @@ -380,8 +380,8 @@ class AdoptOrphanPackage(TransactionTestCase): self.profile.allowed_repos.add(Repo.objects.get(name='Core')) self.profile.save() self.client.post('/login/', { - 'username': self.user.username, - 'password': password + 'username': self.user.username, + 'password': password }) def tearDown(self): @@ -443,8 +443,8 @@ class SignOffTest(TransactionTestCase): self.profile.allowed_repos.add(Repo.objects.get(name='Core')) self.profile.save() self.client.post('/login/', { - 'username': self.user.username, - 'password': password + 'username': self.user.username, + 'password': password }) def tearDown(self): diff --git a/packages/urls.py b/packages/urls.py index 7532af29..708df96c 100644 --- a/packages/urls.py +++ b/packages/urls.py @@ -1,39 +1,39 @@ from django.conf.urls import include, url -from .views.search import SearchListView from packages import views +from packages.views import display, flag, signoff, search package_patterns = [ - url(r'^$', views.details), - url(r'^json/$', views.details_json), - url(r'^files/$', views.files), - url(r'^files/json/$', views.files_json), - url(r'^flag/$', views.flag), - url(r'^flag/done/$', views.flag_confirmed, name='package-flag-confirmed'), - url(r'^unflag/$', views.unflag), - url(r'^unflag/all/$', views.unflag_all), - url(r'^signoff/$', views.signoff_package), - url(r'^signoff/revoke/$', views.signoff_package, {'revoke': True}), - url(r'^signoff/options/$', views.signoff_options), - url(r'^download/$', views.download), + url(r'^$', display.details), + url(r'^json/$', display.details_json), + url(r'^files/$', display.files), + url(r'^files/json/$', display.files_json), + url(r'^flag/$', flag.flag), + url(r'^flag/done/$', flag.flag_confirmed, name='package-flag-confirmed'), + url(r'^unflag/$', flag.unflag), + url(r'^unflag/all/$', flag.unflag_all), + url(r'^signoff/$', signoff.signoff_package), + url(r'^signoff/revoke/$', signoff.signoff_package, {'revoke': True}), + url(r'^signoff/options/$', signoff.signoff_options), + url(r'^download/$', display.download), ] urlpatterns = [ - url(r'^flaghelp/$', views.flaghelp), - url(r'^signoffs/$', views.signoffs, name='package-signoffs'), - url(r'^signoffs/json/$', views.signoffs_json, name='package-signoffs-json'), + url(r'^flaghelp/$', flag.flaghelp), + url(r'^signoffs/$', signoff.signoffs, name='package-signoffs'), + url(r'^signoffs/json/$', signoff.signoffs_json, name='package-signoffs-json'), url(r'^update/$', views.update), - url(r'^$', SearchListView.as_view(), name='packages-search'), - url(r'^search/json/$', views.search_json), + url(r'^$', search.SearchListView.as_view(), name='packages-search'), + url(r'^search/json/$', search.search_json), url(r'^differences/$', views.arch_differences, name='packages-differences'), url(r'^stale_relations/$', views.stale_relations), url(r'^stale_relations/update/$', views.stale_relations_update), - url(r'^(?P[^ /]+)/$', views.details), - url(r'^(?P[A-z0-9\-]+)/(?P[^ /]+)/$', views.details), + url(r'^(?P[^ /]+)/$', display.details), + url(r'^(?P[A-z0-9\-]+)/(?P[^ /]+)/$', display.details), # canonical package url. subviews defined above url(r'^(?P[A-z0-9\-]+)/(?P[A-z0-9]+)/(?P[^ /]+)/', include(package_patterns)), ] diff --git a/packages/urls_groups.py b/packages/urls_groups.py index daf26206..bc81640d 100644 --- a/packages/urls_groups.py +++ b/packages/urls_groups.py @@ -1,6 +1,6 @@ from django.conf.urls import url -from packages.views import groups, group_details +from packages.views.display import groups, group_details urlpatterns = [ url(r'^$', groups, name='groups-list'), diff --git a/packages/utils.py b/packages/utils.py index 1104f7d7..c0d41c83 100644 --- a/packages/utils.py +++ b/packages/utils.py @@ -10,11 +10,10 @@ from django.db.models.query import QuerySet from django.contrib.auth.models import User from main.models import Package, PackageFile, Arch, Repo -from main.utils import (database_vendor, - groupby_preserve_order, PackageStandin) +from main.utils import database_vendor, groupby_preserve_order, PackageStandin from .models import (PackageGroup, PackageRelation, - License, Depend, Conflict, Provision, Replacement, - SignoffSpecification, Signoff, fake_signoff_spec) + License, Depend, Conflict, Provision, Replacement, + SignoffSpecification, Signoff, fake_signoff_spec) from todolists.models import TodolistPackage @@ -36,15 +35,17 @@ def parse_version(version): def get_group_info(include_arches=None): raw_groups = PackageGroup.objects.values_list( - 'name', 'pkg__arch__name').order_by('name').annotate( - cnt=Count('pkg'), last_update=Max('pkg__last_update')) + 'name', 'pkg__arch__name').order_by('name').annotate( + cnt=Count('pkg'), last_update=Max('pkg__last_update')) # now for post_processing. we need to separate things out and add # the count in for 'any' to all of the other architectures. group_mapping = {} for grp in raw_groups: arch_groups = group_mapping.setdefault(grp[1], {}) - arch_groups[grp[0]] = {'name': grp[0], 'arch': grp[1], - 'count': grp[2], 'last_update': grp[3]} + arch_groups[grp[0]] = { + 'name': grp[0], 'arch': grp[1], + 'count': grp[2], 'last_update': grp[3] + } # we want to promote the count of 'any' packages in groups to the # other architectures, and also add any 'any'-only groups @@ -78,7 +79,7 @@ def get_split_packages_info(): matching the split pkgbase.''' pkgnames = Package.objects.values('pkgname') split_pkgs = Package.objects.exclude(pkgname=F('pkgbase')).exclude( - pkgbase__in=pkgnames).values('pkgbase', 'repo', 'arch').annotate( + pkgbase__in=pkgnames).values('pkgbase', 'repo', 'arch').annotate( last_update=Max('last_update')).distinct() all_arches = Arch.objects.in_bulk({s['arch'] for s in split_pkgs}) all_repos = Repo.objects.in_bulk({s['repo'] for s in split_pkgs}) @@ -192,7 +193,7 @@ SELECT DISTINCT id cursor.execute(sql, [PackageRelation.MAINTAINER]) to_fetch = [row[0] for row in cursor.fetchall()] relations = PackageRelation.objects.select_related( - 'user', 'user__userprofile').filter( + 'user', 'user__userprofile').filter( id__in=to_fetch) return relations @@ -207,8 +208,8 @@ def attach_maintainers(packages): packages = list(packages) pkgbases = {p.pkgbase for p in packages if p is not None} rels = PackageRelation.objects.filter(type=PackageRelation.MAINTAINER, - pkgbase__in=pkgbases).values_list( - 'pkgbase', 'user_id').order_by().distinct() + pkgbase__in=pkgbases).values_list( + 'pkgbase', 'user_id').order_by().distinct() # get all the user objects we will need user_ids = {rel[1] for rel in rels} @@ -319,8 +320,7 @@ class PackageSignoffGroup(object): return user in (s.user for s in self.signoffs if not s.revoked) def __unicode__(self): - return '%s-%s (%s): %d' % ( - self.pkgbase, self.version, self.arch, len(self.signoffs)) + return f'{self.pkgbase}-{self.version} (self.arch): {len(self.signoffs)}' def signoffs_id_query(model, repos): @@ -359,8 +359,7 @@ def get_current_signoffs(repos): def get_current_specifications(repos): '''Returns a list of signoff specification objects for the given repos.''' to_fetch = signoffs_id_query(SignoffSpecification, repos) - return SignoffSpecification.objects.select_related('arch').in_bulk( - to_fetch).values() + return SignoffSpecification.objects.select_related('arch').in_bulk(to_fetch).values() def get_target_repo_map(repos): @@ -390,14 +389,13 @@ def get_signoff_groups(repos=None, user=None): repo_ids = [r.pk for r in repos] test_pkgs = Package.objects.select_related( - 'arch', 'repo', 'packager').filter(repo__in=repo_ids) + 'arch', 'repo', 'packager').filter(repo__in=repo_ids) packages = test_pkgs.order_by('pkgname') packages = attach_maintainers(packages) # Filter by user if asked to do so if user is not None: - packages = [p for p in packages if user == p.packager - or user in p.maintainers] + packages = [p for p in packages if user == p.packager or user in p.maintainers] # Collect all pkgbase values in testing repos pkgtorepo = get_target_repo_map(repos) @@ -411,8 +409,7 @@ def get_signoff_groups(repos=None, user=None): signoff_groups = [] for group in grouped: signoff_group = PackageSignoffGroup(group) - signoff_group.target_repo = pkgtorepo.get(signoff_group.pkgbase, - "Unknown") + signoff_group.target_repo = pkgtorepo.get(signoff_group.pkgbase, "Unknown") signoff_group.find_signoffs(signoffs) signoff_group.find_specification(specs) signoff_groups.append(signoff_group) @@ -420,16 +417,16 @@ def get_signoff_groups(repos=None, user=None): return signoff_groups -DEPENDENCY_TYPES = [('D', 'depends'), ('O', 'optdepends'), - ('M', 'makedepends'), ('C', 'checkdepends')] +DEPENDENCY_TYPES = [('D', 'depends'), ('O', 'optdepends'), + ('M', 'makedepends'), ('C', 'checkdepends')] + class PackageJSONEncoder(DjangoJSONEncoder): - pkg_attributes = ['pkgname', 'pkgbase', 'repo', 'arch', 'pkgver', - 'pkgrel', 'epoch', 'pkgdesc', 'url', 'filename', 'compressed_size', - 'installed_size', 'build_date', 'last_update', 'flag_date', - 'maintainers', 'packager'] - pkg_list_attributes = ['groups', 'licenses', 'conflicts', - 'provides', 'replaces'] + pkg_attributes = ['pkgname', 'pkgbase', 'repo', 'arch', 'pkgver', 'pkgrel', + 'epoch', 'pkgdesc', 'url', 'filename', 'compressed_size', + 'installed_size', 'build_date', 'last_update', 'flag_date', + 'maintainers', 'packager'] + pkg_list_attributes = ['groups', 'licenses', 'conflicts', 'provides', 'replaces'] todolistpackage_attributes = ['status_str'] def default(self, obj): diff --git a/packages/views/__init__.py b/packages/views/__init__.py index 904043af..b294190a 100644 --- a/packages/views/__init__.py +++ b/packages/views/__init__.py @@ -3,7 +3,6 @@ import json from django.contrib import messages from django.contrib.auth.decorators import permission_required -from django.contrib.auth.models import User from django.core.cache import cache from django.db.models import Q from django.http import HttpResponse @@ -15,13 +14,6 @@ from main.models import Package from ..models import PackageRelation from ..utils import multilib_differences, get_wrong_permissions -# make other views available from this same package -from .display import (details, groups, group_details, files, details_json, - files_json, download) -from .flag import flaghelp, flag, flag_confirmed, unflag, unflag_all -from .search import search_json -from .signoff import signoffs, signoff_package, signoff_options, signoffs_json - @require_safe @cache_control(public=True, max_age=86400) @@ -29,8 +21,8 @@ def opensearch(request): domain = "%s://%s" % (request.scheme, request.META.get('HTTP_HOST')) return render(request, 'packages/opensearch.xml', - {'domain': domain}, - content_type='application/opensearchdescription+xml') + {'domain': domain}, + content_type='application/opensearchdescription+xml') @require_safe @@ -40,15 +32,14 @@ def opensearch_suggest(request): if search_term == '': return HttpResponse('', content_type='application/x-suggestions+json') - cache_key = 'opensearch:packages:' + \ - hashlib.md5(search_term.encode('utf-8')).hexdigest() + cache_key = 'opensearch:packages:' + hashlib.md5(search_term.encode('utf-8')).hexdigest() to_json = cache.get(cache_key, None) if to_json is None: # Package names are lowercase by convention q = Q(pkgname__istartswith=search_term) names = Package.objects.filter(q).values_list( - 'pkgname', flat=True).order_by('pkgname').distinct()[:10] + 'pkgname', flat=True).order_by('pkgname').distinct()[:10] results = (search_term, tuple(names)) to_json = json.dumps(results, ensure_ascii=False) cache.set(cache_key, to_json, 613) @@ -65,13 +56,12 @@ def update(request): repos = request.user.userprofile.allowed_repos.all() pkgs = Package.objects.filter(id__in=ids, repo__in=repos) disallowed_pkgs = Package.objects.filter(id__in=ids).exclude( - repo__in=repos) + repo__in=repos) if disallowed_pkgs: messages.warning(request, - "You do not have permission to adopt: %s." % ( - ' '.join([p.pkgname for p in disallowed_pkgs]) - )) + "You do not have permission to adopt: %s." % + (' '.join([p.pkgname for p in disallowed_pkgs]))) for pkg in pkgs: if request.user in pkg.maintainers: @@ -90,10 +80,10 @@ def update(request): for pkg in Package.objects.filter(id__in=ids): if request.user in pkg.maintainers: rels = PackageRelation.objects.filter( - pkgbase=pkg.pkgbase, - user=request.user, - type=PackageRelation.MAINTAINER - ) + pkgbase=pkg.pkgbase, + user=request.user, + type=PackageRelation.MAINTAINER + ) count += rels.count() rels.delete() @@ -106,10 +96,11 @@ def update(request): def arch_differences(request): context = { - 'multilib_differences': multilib_differences() + 'multilib_differences': multilib_differences() } return render(request, 'packages/differences.html', context) + @permission_required('main.change_package') def stale_relations(request): relations = PackageRelation.objects.select_related('user') @@ -117,16 +108,17 @@ def stale_relations(request): inactive_user = relations.filter(user__is_active=False) missing_pkgbase = relations.exclude( - pkgbase__in=pkgbases).order_by('pkgbase') + pkgbase__in=pkgbases).order_by('pkgbase') wrong_permissions = get_wrong_permissions() context = { - 'inactive_user': inactive_user, - 'missing_pkgbase': missing_pkgbase, - 'wrong_permissions': wrong_permissions, + 'inactive_user': inactive_user, + 'missing_pkgbase': missing_pkgbase, + 'wrong_permissions': wrong_permissions, } return render(request, 'packages/stale_relations.html', context) + @permission_required('packages.delete_packagerelation') @require_POST def stale_relations_update(request): diff --git a/packages/views/display.py b/packages/views/display.py index 76849cfc..88307f7e 100644 --- a/packages/views/display.py +++ b/packages/views/display.py @@ -14,7 +14,7 @@ from ..utils import get_group_info, PackageJSONEncoder def arch_plus_agnostic(arch): - arches = [ arch ] + arches = [arch] arches.extend(Arch.objects.filter(agnostic=True).order_by()) return arches @@ -24,8 +24,8 @@ def split_package_details(request, name, repo, arch): name. If so, we can show a listing page for the entire set of packages.''' arches = arch_plus_agnostic(arch) pkgs = Package.objects.normal().filter(pkgbase=name, - repo__testing=repo.testing, repo__staging=repo.staging, - arch__in=arches).order_by('pkgname') + repo__testing=repo.testing, repo__staging=repo.staging, + arch__in=arches).order_by('pkgname') if not pkgs: return None # we have packages, but ensure at least one is in the given repo @@ -49,7 +49,7 @@ def recently_removed_package(request, name, repo, arch, cutoff=CUTOFF): requester in the right direction.''' arches = arch_plus_agnostic(arch) match = Update.objects.select_related('arch', 'repo').filter( - pkgname=name, repo=repo, arch__in=arches) + pkgname=name, repo=repo, arch__in=arches) if cutoff is not None: when = now() - cutoff match = match.filter(created__gte=when) @@ -100,7 +100,7 @@ def redirect_agnostic(request, name, repo, arch): # except only one matching result pkgs = Package.objects.select_related( 'arch', 'repo', 'packager').filter(pkgname=name, - repo=repo, arch__agnostic=True)[:2] + repo=repo, arch__agnostic=True)[:2] if len(pkgs) == 1: return redirect(pkgs[0], permanent=True) return None @@ -125,15 +125,15 @@ def details(request, name='', repo='', arch=''): repo_obj = get_object_or_404(Repo, name__iexact=repo) try: pkg = Package.objects.select_related( - 'arch', 'repo', 'packager').get(pkgname=name, - repo=repo_obj, arch=arch_obj) + 'arch', 'repo', 'packager').get(pkgname=name, + repo=repo_obj, arch=arch_obj) if request.method == 'HEAD': return empty_response() return render(request, 'packages/details.html', {'pkg': pkg}) except Package.DoesNotExist: # attempt a variety of fallback options before 404ing options = (redirect_agnostic, split_package_details, - recently_removed_package, replaced_package) + recently_removed_package, replaced_package) for method in options: ret = method(request, name, repo_obj, arch_obj) if ret: @@ -161,7 +161,7 @@ def group_details(request, arch, name): arch = get_object_or_404(Arch, name=arch) arches = arch_plus_agnostic(arch) pkgs = Package.objects.normal().filter( - groups__name=name, arch__in=arches).order_by('pkgname') + groups__name=name, arch__in=arches).order_by('pkgname') if not pkgs: raise Http404 context = { @@ -175,7 +175,7 @@ def group_details(request, arch, name): def files(request, name, repo, arch): pkg = get_object_or_404(Package.objects.normal(), - pkgname=name, repo__name__iexact=repo, arch__name=arch) + pkgname=name, repo__name__iexact=repo, arch__name=arch) # files are inserted in sorted order, so preserve that fileslist = PackageFile.objects.filter(pkg=pkg).order_by('id') dir_count = sum(1 for f in fileslist if f.is_directory) @@ -192,14 +192,14 @@ def files(request, name, repo, arch): def details_json(request, name, repo, arch): pkg = get_object_or_404(Package.objects.normal(), - pkgname=name, repo__name__iexact=repo, arch__name=arch) + pkgname=name, repo__name__iexact=repo, arch__name=arch) to_json = json.dumps(pkg, ensure_ascii=False, cls=PackageJSONEncoder) return HttpResponse(to_json, content_type='application/json') def files_json(request, name, repo, arch): pkg = get_object_or_404(Package.objects.normal(), - pkgname=name, repo__name__iexact=repo, arch__name=arch) + pkgname=name, repo__name__iexact=repo, arch__name=arch) # files are inserted in sorted order, so preserve that fileslist = PackageFile.objects.filter(pkg=pkg).order_by('id') dir_count = sum(1 for f in fileslist if f.is_directory) @@ -220,7 +220,7 @@ def files_json(request, name, repo, arch): def download(request, name, repo, arch): pkg = get_object_or_404(Package.objects.normal(), - pkgname=name, repo__name__iexact=repo, arch__name=arch) + pkgname=name, repo__name__iexact=repo, arch__name=arch) url = get_mirror_url_for_download() if not url: raise Http404 @@ -229,7 +229,8 @@ def download(request, name, repo, arch): # grab the first non-any arch to fake the download path arch = Arch.objects.exclude(agnostic=True)[0].name url = '{host}{repo}/os/{arch}/{filename}'.format(host=url.url, - repo=pkg.repo.name.lower(), arch=arch, filename=pkg.filename) + repo=pkg.repo.name.lower(), + arch=arch, filename=pkg.filename) return redirect(url) # vim: set ts=4 sw=4 et: diff --git a/packages/views/flag.py b/packages/views/flag.py index 91995ee7..93aa0aaf 100644 --- a/packages/views/flag.py +++ b/packages/views/flag.py @@ -17,12 +17,12 @@ from main.models import Package class FlagForm(forms.Form): email = forms.EmailField(label='E-mail Address') message = forms.CharField(label='Message To Developer', - widget=forms.Textarea) + widget=forms.Textarea) # The field below is used to filter out bots that blindly fill out all # input elements website = forms.CharField(label='', - widget=forms.TextInput(), - required=False) + widget=forms.TextInput(), + required=False) def __init__(self, *args, **kwargs): # we remove the 'email' field if this form is being shown to a @@ -37,8 +37,7 @@ class FlagForm(forms.Form): # make sure the message isn't garbage (only punctuation or whitespace) # and ensure a certain minimum length if re.match(r'^[^0-9A-Za-z]+$', data) or len(data) < 3: - raise forms.ValidationError( - "Enter a valid and useful out-of-date message.") + raise forms.ValidationError("Enter a valid and useful out-of-date message.") return data @@ -50,16 +49,16 @@ def flaghelp(request): @never_cache def flag(request, name, repo, arch): pkg = get_object_or_404(Package.objects.normal(), - pkgname=name, repo__name__iexact=repo, arch__name=arch) + pkgname=name, repo__name__iexact=repo, arch__name=arch) if pkg.flag_date is not None: # already flagged. do nothing. return render(request, 'packages/flagged.html', {'pkg': pkg}) # find all packages from (hopefully) the same PKGBUILD pkgs = Package.objects.normal().filter( - pkgbase=pkg.pkgbase, flag_date__isnull=True, - repo__testing=pkg.repo.testing, - repo__staging=pkg.repo.staging).order_by( - 'pkgname', 'repo__name', 'arch__name') + pkgbase=pkg.pkgbase, flag_date__isnull=True, + repo__testing=pkg.repo.testing, + repo__staging=pkg.repo.staging).order_by( + 'pkgname', 'repo__name', 'arch__name') authenticated = request.user.is_authenticated @@ -71,7 +70,7 @@ def flag(request, name, repo, arch): # find a common version if there is one available to store versions = set((pkg.pkgver, pkg.pkgrel, pkg.epoch) - for pkg in flagged_pkgs) + for pkg in flagged_pkgs) if len(versions) == 1: version = versions.pop() else: @@ -90,10 +89,10 @@ def flag(request, name, repo, arch): pkgs.update(flag_date=current_time) # store our flag request flag_request = FlagRequest(created=current_time, - user_email=email, message=message, - ip_address=ip_addr, pkgbase=pkg.pkgbase, - repo=pkg.repo, pkgver=version[0], pkgrel=version[1], - epoch=version[2], num_packages=len(flagged_pkgs)) + user_email=email, message=message, + ip_address=ip_addr, pkgbase=pkg.pkgbase, + repo=pkg.repo, pkgver=version[0], pkgrel=version[1], + epoch=version[2], num_packages=len(flagged_pkgs)) if authenticated: flag_request.user = request.user flag_request.save() @@ -103,12 +102,10 @@ def flag(request, name, repo, arch): maints = pkg.maintainers if not maints: toemail = settings.NOTIFICATIONS - subject = 'Orphan %s package [%s] marked out-of-date' % \ - (pkg.repo.name, pkg.pkgname) + subject = f'Orphan {pkg.repo.name} package [{pkg.pkgname}] marked out-of-date' else: toemail = [] - subject = '%s package [%s] marked out-of-date' % \ - (pkg.repo.name, pkg.pkgname) + subject = f'{pkg.repo.name} package [{pkg.pkgname}] marked out-of-date' for maint in maints: if maint.userprofile.notify is True: toemail.append(maint.email) @@ -123,15 +120,14 @@ def flag(request, name, repo, arch): 'packages': flagged_pkgs, } msg = EmailMessage(subject, - tmpl.render(ctx), - 'Arch Website Notification ', - toemail, - headers={"Reply-To": email } - ) + tmpl.render(ctx), + 'Arch Website Notification ', + toemail, + headers={"Reply-To": email}) msg.send(fail_silently=True) return redirect('package-flag-confirmed', name=name, repo=repo, - arch=arch) + arch=arch) else: form = FlagForm(authenticated=authenticated) @@ -142,34 +138,37 @@ def flag(request, name, repo, arch): } return render(request, 'packages/flag.html', context) + def flag_confirmed(request, name, repo, arch): pkg = get_object_or_404(Package, - pkgname=name, repo__name__iexact=repo, arch__name=arch) + pkgname=name, repo__name__iexact=repo, arch__name=arch) pkgs = Package.objects.normal().filter( - pkgbase=pkg.pkgbase, flag_date=pkg.flag_date, - repo__testing=pkg.repo.testing, - repo__staging=pkg.repo.staging).order_by( - 'pkgname', 'repo__name', 'arch__name') + pkgbase=pkg.pkgbase, flag_date=pkg.flag_date, + repo__testing=pkg.repo.testing, + repo__staging=pkg.repo.staging).order_by( + 'pkgname', 'repo__name', 'arch__name') context = {'package': pkg, 'packages': pkgs} return render(request, 'packages/flag_confirmed.html', context) + @permission_required('main.change_package') def unflag(request, name, repo, arch): pkg = get_object_or_404(Package.objects.normal(), - pkgname=name, repo__name__iexact=repo, arch__name=arch) + pkgname=name, repo__name__iexact=repo, arch__name=arch) pkg.flag_date = None pkg.save() return redirect(pkg) + @permission_required('main.change_package') def unflag_all(request, name, repo, arch): pkg = get_object_or_404(Package.objects.normal(), - pkgname=name, repo__name__iexact=repo, arch__name=arch) + pkgname=name, repo__name__iexact=repo, arch__name=arch) # find all packages from (hopefully) the same PKGBUILD pkgs = Package.objects.filter(pkgbase=pkg.pkgbase, - repo__testing=pkg.repo.testing, repo__staging=pkg.repo.staging) + repo__testing=pkg.repo.testing, repo__staging=pkg.repo.staging) pkgs.update(flag_date=None) return redirect(pkg) diff --git a/packages/views/search.py b/packages/views/search.py index b8f18ed5..875fbd65 100644 --- a/packages/views/search.py +++ b/packages/views/search.py @@ -28,8 +28,8 @@ class PackageSearchForm(forms.Form): maintainer = forms.ChoiceField(required=False) packager = forms.ChoiceField(required=False) flagged = forms.ChoiceField( - choices=[('', 'All')] + make_choice(['Flagged', 'Not Flagged']), - required=False) + choices=[('', 'All')] + make_choice(['Flagged', 'Not Flagged']), + required=False) def __init__(self, *args, **kwargs): show_staging = kwargs.pop('show_staging', False) @@ -37,20 +37,18 @@ class PackageSearchForm(forms.Form): repos = Repo.objects.all() if not show_staging: repos = repos.filter(staging=False) - self.fields['repo'].choices = make_choice( - [repo.name for repo in repos]) - self.fields['arch'].choices = make_choice( - [arch.name for arch in Arch.objects.all()]) + self.fields['repo'].choices = make_choice([repo.name for repo in repos]) + self.fields['arch'].choices = make_choice([arch.name for arch in Arch.objects.all()]) self.fields['q'].widget.attrs.update({"size": "30"}) profile_ids = UserProfile.allowed_repos.through.objects.values('userprofile_id') people = User.objects.filter( - is_active=True, userprofile__id__in=profile_ids).order_by( - 'first_name', 'last_name') + is_active=True, userprofile__id__in=profile_ids).order_by( + 'first_name', 'last_name') maintainers = [('', 'All'), ('orphan', 'Orphan')] + \ - [(p.username, p.get_full_name()) for p in people] + [(p.username, p.get_full_name()) for p in people] packagers = [('', 'All'), ('unknown', 'Unknown')] + \ - [(p.username, p.get_full_name()) for p in people] + [(p.username, p.get_full_name()) for p in people] self.fields['maintainer'].choices = maintainers self.fields['packager'].choices = packagers @@ -66,26 +64,23 @@ class PackageSearchForm(forms.Form): def parse_form(form, packages): if form.cleaned_data['repo']: - packages = packages.filter( - repo__name__in=form.cleaned_data['repo']) + packages = packages.filter(repo__name__in=form.cleaned_data['repo']) if form.cleaned_data['arch']: - packages = packages.filter( - arch__name__in=form.cleaned_data['arch']) + packages = packages.filter(arch__name__in=form.cleaned_data['arch']) if form.cleaned_data['maintainer'] == 'orphan': inner_q = PackageRelation.objects.all().values('pkgbase') packages = packages.exclude(pkgbase__in=inner_q) elif form.cleaned_data['maintainer']: inner_q = PackageRelation.objects.filter( - user__username=form.cleaned_data['maintainer']).values('pkgbase') + user__username=form.cleaned_data['maintainer']).values('pkgbase') packages = packages.filter(pkgbase__in=inner_q) if form.cleaned_data['packager'] == 'unknown': packages = packages.filter(packager__isnull=True) elif form.cleaned_data['packager']: - packages = packages.filter( - packager__username=form.cleaned_data['packager']) + packages = packages.filter(packager__username=form.cleaned_data['packager']) if form.cleaned_data['flagged'] == 'Flagged': packages = packages.filter(flag_date__isnull=False) @@ -131,7 +126,7 @@ class SearchListView(ListView): if request.method == 'HEAD': return empty_response() self.form = PackageSearchForm(data=request.GET, - show_staging=self.request.user.is_authenticated) + show_staging=self.request.user.is_authenticated) return super(SearchListView, self).get(request, *args, **kwargs) def get_queryset(self): @@ -169,14 +164,13 @@ def search_json(request): if request.GET: form = PackageSearchForm(data=request.GET, - show_staging=request.user.is_authenticated) + show_staging=request.user.is_authenticated) if form.is_valid(): form_limit = form.cleaned_data.get('limit', limit) limit = min(limit, form_limit) if form_limit else limit container['limit'] = limit - packages = Package.objects.select_related('arch', 'repo', - 'packager') + packages = Package.objects.select_related('arch', 'repo', 'packager') if not request.user.is_authenticated: packages = packages.filter(repo__staging=False) packages = parse_form(form, packages) diff --git a/packages/views/signoff.py b/packages/views/signoff.py index 7c2d5224..5e05c28a 100644 --- a/packages/views/signoff.py +++ b/packages/views/signoff.py @@ -16,7 +16,8 @@ from django.views.decorators.cache import never_cache from main.models import Package, Arch, Repo from ..models import SignoffSpecification, Signoff from ..utils import (get_signoff_groups, approved_by_signoffs, - PackageSignoffGroup) + PackageSignoffGroup) + @permission_required('packages.change_signoff') def signoffs(request): @@ -31,19 +32,19 @@ def signoffs(request): } return render(request, 'packages/signoffs.html', context) + @permission_required('packages.change_signoff') @never_cache def signoff_package(request, name, repo, arch, revoke=False): packages = get_list_or_404(Package, pkgbase=name, - arch__name=arch, repo__name__iexact=repo, repo__testing=True) + arch__name=arch, repo__name__iexact=repo, repo__testing=True) package = packages[0] spec = SignoffSpecification.objects.get_or_default_from_package(package) if revoke: try: - signoff = Signoff.objects.get_from_package( - package, request.user, False) + signoff = Signoff.objects.get_from_package(package, request.user, False) except Signoff.DoesNotExist: raise Http404 signoff.revoked = now() @@ -53,10 +54,8 @@ def signoff_package(request, name, repo, arch, revoke=False): # ensure we should even be accepting signoffs if spec.known_bad or not spec.enabled: return render(request, '403.html', status=403) - signoff, created = Signoff.objects.get_or_create_from_package( - package, request.user) - signoffs = Signoff.objects.for_package(package).filter( - revoked__isnull=True) + signoff, created = Signoff.objects.get_or_create_from_package(package, request.user) + signoffs = Signoff.objects.for_package(package).filter(revoked__isnull=True) if signoffs.count() == spec.required: packager = package.packager @@ -64,8 +63,7 @@ def signoff_package(request, name, repo, arch, revoke=False): # TODO: Handle notification when packager does not exist if packager: toemail = [packager.email] - subject = f'{package.repo.name} package ' + \ - f'[{package.pkgname} {package.full_version}] approved' + subject = f'{package.repo.name} package [{package.pkgname} {package.full_version}] approved' # send notification email to the maintainers tmpl = loader.get_template('packages/approved.txt') @@ -74,10 +72,9 @@ def signoff_package(request, name, repo, arch, revoke=False): 'pkg': package, } msg = EmailMessage(subject, - tmpl.render(ctx), - 'Arch Website Notification ', - toemail, - ) + tmpl.render(ctx), + 'Arch Website Notification ', + toemail) msg.send(fail_silently=True) all_signoffs = Signoff.objects.for_package(package) @@ -93,25 +90,27 @@ def signoff_package(request, name, repo, arch, revoke=False): 'user': str(request.user), } return HttpResponse(json.dumps(data, ensure_ascii=False), - content_type='application/json') + content_type='application/json') return redirect('package-signoffs') + class SignoffOptionsForm(forms.ModelForm): apply_all = forms.BooleanField(required=False, - help_text="Apply these options to all architectures?") + help_text="Apply these options to all architectures?") class Meta: model = SignoffSpecification fields = ('required', 'enabled', 'known_bad', 'comments') + def _signoff_options_all(request, name, repo): seen_ids = set() with transaction.atomic(): # find or create a specification for all architectures, then # graft the form data onto them packages = Package.objects.filter(pkgbase=name, - repo__name__iexact=repo, repo__testing=True) + repo__name__iexact=repo, repo__testing=True) for package in packages: try: spec = SignoffSpecification.objects.get_from_package(package) @@ -119,9 +118,9 @@ def _signoff_options_all(request, name, repo): continue except SignoffSpecification.DoesNotExist: spec = SignoffSpecification(pkgbase=package.pkgbase, - pkgver=package.pkgver, pkgrel=package.pkgrel, - epoch=package.epoch, arch=package.arch, - repo=package.repo) + pkgver=package.pkgver, pkgrel=package.pkgrel, + epoch=package.epoch, arch=package.arch, + repo=package.repo) if spec.user is None: spec.user = request.user @@ -131,11 +130,12 @@ def _signoff_options_all(request, name, repo): form.save() seen_ids.add(form.instance.pk) + @permission_required('main.change_package') @never_cache def signoff_options(request, name, repo, arch): packages = get_list_or_404(Package, pkgbase=name, - arch__name=arch, repo__name__iexact=repo, repo__testing=True) + arch__name=arch, repo__name__iexact=repo, repo__testing=True) package = packages[0] if request.user != package.packager and \ @@ -147,8 +147,8 @@ def signoff_options(request, name, repo, arch): except SignoffSpecification.DoesNotExist: # create a fake one, but don't save it just yet spec = SignoffSpecification(pkgbase=package.pkgbase, - pkgver=package.pkgver, pkgrel=package.pkgrel, - epoch=package.epoch, arch=package.arch, repo=package.repo) + pkgver=package.pkgver, pkgrel=package.pkgrel, + epoch=package.epoch, arch=package.arch, repo=package.repo) if spec.user is None: spec.user = request.user @@ -171,11 +171,12 @@ def signoff_options(request, name, repo, arch): } return render(request, 'packages/signoff_options.html', context) + class SignoffJSONEncoder(DjangoJSONEncoder): '''Base JSONEncoder extended to handle all serialization of all classes related to signoffs.''' signoff_group_attrs = ['arch', 'last_update', 'maintainers', 'packager', - 'pkgbase', 'repo', 'signoffs', 'target_repo', 'version'] + 'pkgbase', 'repo', 'signoffs', 'target_repo', 'version'] signoff_spec_attrs = ['required', 'enabled', 'known_bad', 'comments'] signoff_attrs = ['user', 'created', 'revoked'] @@ -187,7 +188,7 @@ class SignoffJSONEncoder(DjangoJSONEncoder): data['package_count'] = len(obj.packages) data['approved'] = obj.approved() data.update((attr, getattr(obj.specification, attr)) - for attr in self.signoff_spec_attrs) + for attr in self.signoff_spec_attrs) return data elif isinstance(obj, Signoff): return {attr: getattr(obj, attr) for attr in self.signoff_attrs} @@ -199,6 +200,7 @@ class SignoffJSONEncoder(DjangoJSONEncoder): return list(obj) return super(SignoffJSONEncoder, self).default(obj) + @permission_required('packages.change_signoff') def signoffs_json(request): signoff_groups = sorted(get_signoff_groups(), key=attrgetter('pkgbase')) diff --git a/planet/admin.py b/planet/admin.py index 59f02a0e..db91f9ae 100644 --- a/planet/admin.py +++ b/planet/admin.py @@ -8,16 +8,19 @@ class FeedItemAdmin(admin.ModelAdmin): list_filter = ('publishdate',) search_fields = ('title',) + class FeedAdmin(admin.ModelAdmin): list_display = ('title', 'website',) list_filter = ('title',) search_fields = ('title',) + class PlanetAdmin(admin.ModelAdmin): list_display = ('name', 'website',) list_filter = ('name',) search_fields = ('name',) + admin.site.register(Feed, FeedAdmin) admin.site.register(FeedItem, FeedItemAdmin) admin.site.register(Planet, PlanetAdmin) diff --git a/planet/migrations/0001_initial.py b/planet/migrations/0001_initial.py index 948b2532..a7592cef 100644 --- a/planet/migrations/0001_initial.py +++ b/planet/migrations/0001_initial.py @@ -50,7 +50,8 @@ class Migration(migrations.Migration): ('author', models.CharField(max_length=255)), ('publishdate', models.DateTimeField(db_index=True, verbose_name='publish date')), ('url', models.CharField(max_length=255, verbose_name='URL')), - ('feed', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='feed', to='planet.Feed')), + ('feed', models.ForeignKey( + null=True, on_delete=django.db.models.deletion.CASCADE, related_name='feed', to='planet.Feed')), ], options={ 'verbose_name_plural': 'Feed Items', diff --git a/planet/models.py b/planet/models.py index 2aaeb7f5..0eb5eabf 100644 --- a/planet/models.py +++ b/planet/models.py @@ -19,6 +19,7 @@ class Feed(models.Model): get_latest_by = 'title' ordering = ('-title',) + class FeedItem(models.Model): title = models.CharField(max_length=255) summary = models.CharField(max_length=FEEDITEM_SUMMARY_LIMIT) @@ -40,6 +41,7 @@ class FeedItem(models.Model): get_latest_by = 'publishdate' ordering = ('-publishdate',) + class Planet(models.Model): ''' The planet model contains related Arch Linux planet instances. diff --git a/planet/tests/test_command.py b/planet/tests/test_command.py index e93ce51a..5c2fd9b3 100644 --- a/planet/tests/test_command.py +++ b/planet/tests/test_command.py @@ -14,6 +14,7 @@ class Result(dict): def get(self, value): return getattr(self, value) + class Entry(dict): title = 'title' description = 'lorem ipsum' diff --git a/releng/admin.py b/releng/admin.py index 251cc90a..ef924c4b 100644 --- a/releng/admin.py +++ b/releng/admin.py @@ -2,9 +2,10 @@ from django.contrib import admin from .models import Release + class ReleaseAdmin(admin.ModelAdmin): list_display = ('version', 'release_date', 'kernel_version', 'available', - 'created') + 'created') list_filter = ('available', 'release_date') readonly_fields = ('created', 'last_modified') diff --git a/releng/migrations/0001_squashed_0005_auto_20180616_0947.py b/releng/migrations/0001_squashed_0005_auto_20180616_0947.py index 76f10f60..4269ebf4 100644 --- a/releng/migrations/0001_squashed_0005_auto_20180616_0947.py +++ b/releng/migrations/0001_squashed_0005_auto_20180616_0947.py @@ -16,6 +16,7 @@ def release_populate_last_modified_forwards(apps, schema_editor): Release = apps.get_model('releng', 'Release') Release.objects.update(last_modified=models.F('created')) + def release_populate_last_modified_backwards(apps, schema_editor): pass @@ -144,7 +145,8 @@ class Migration(migrations.Migration): ('available', models.BooleanField(default=True)), ('info', models.TextField(blank=True, verbose_name='Public information')), ('torrent_data', models.TextField(blank=True, help_text='base64-encoded torrent file')), - ('last_modified', models.DateTimeField(default=datetime.datetime(2001, 1, 1, 0, 0, tzinfo=utc), editable=False)), + ('last_modified', models.DateTimeField(default=datetime.datetime(2001, 1, 1, 0, 0, + tzinfo=utc), editable=False)), ], options={ 'ordering': ('-release_date', '-version'), @@ -171,18 +173,25 @@ class Migration(migrations.Migration): ('created', models.DateTimeField(editable=False)), ('success', models.BooleanField(default=True)), ('comments', models.TextField(blank=True, null=True)), - ('architecture', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='releng.Architecture')), + ('architecture', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, + to='releng.Architecture')), ('boot_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='releng.BootType')), ('bootloader', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='releng.Bootloader')), - ('clock_choice', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='releng.ClockChoice')), + ('clock_choice', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, + to='releng.ClockChoice')), ('filesystem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='releng.Filesystem')), - ('hardware_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='releng.HardwareType')), - ('install_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='releng.InstallType')), + ('hardware_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, + to='releng.HardwareType')), + ('install_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, + to='releng.InstallType')), ('iso', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='releng.Iso')), ('iso_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='releng.IsoType')), ('modules', models.ManyToManyField(blank=True, null=True, to='releng.Module')), - ('rollback_filesystem', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='rollback_test_set', to='releng.Filesystem')), - ('rollback_modules', models.ManyToManyField(blank=True, null=True, related_name='rollback_test_set', to='releng.Module')), + ('rollback_filesystem', models.ForeignKey(blank=True, null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name='rollback_test_set', to='releng.Filesystem')), + ('rollback_modules', models.ManyToManyField(blank=True, null=True, related_name='rollback_test_set', + to='releng.Module')), ('source', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='releng.Source')), ], ), diff --git a/releng/migrations/0003_release_pgp_key.py b/releng/migrations/0003_release_pgp_key.py index a211a798..3ff103c6 100644 --- a/releng/migrations/0003_release_pgp_key.py +++ b/releng/migrations/0003_release_pgp_key.py @@ -14,6 +14,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='release', name='pgp_key', - field=devel.fields.PGPKeyField(blank=True, help_text='consists of 40 hex digits; use `gpg --fingerprint`', max_length=40, null=True, verbose_name='PGP key fingerprint'), + field=devel.fields.PGPKeyField(blank=True, help_text='consists of 40 hex digits; use `gpg --fingerprint`', + max_length=40, null=True, verbose_name='PGP key fingerprint'), ), ] diff --git a/releng/views.py b/releng/views.py index 8699c5b2..f3a177d0 100644 --- a/releng/views.py +++ b/releng/views.py @@ -59,7 +59,7 @@ def releases_json(request): releases = Release.objects.all() try: latest_version = Release.objects.filter(available=True).values_list( - 'version', flat=True).latest() + 'version', flat=True).latest() except Release.DoesNotExist: latest_version = None @@ -90,7 +90,7 @@ def netboot_config(request): def netboot_info(request): - return render(request, "releng/netboot.html", - {'security_banner': settings.NETBOOT_SECURITY_BANNER}) + return render(request, "releng/netboot.html", + {'security_banner': settings.NETBOOT_SECURITY_BANNER}) # vim: set ts=4 sw=4 et: diff --git a/settings.py b/settings.py index e33ee46d..5376f943 100644 --- a/settings.py +++ b/settings.py @@ -197,7 +197,7 @@ REBUILDERD_URL = 'https://reproducible.archlinux.org/api/v0/pkgs/list' # Import local settings try: - from local_settings import * + from local_settings import * # noqa except ImportError: pass @@ -223,9 +223,7 @@ TEMPLATES = [ # Enable the debug toolbar if requested if DEBUG_TOOLBAR: - MIDDLEWARE = \ - ['debug_toolbar.middleware.DebugToolbarMiddleware'] + \ - list(MIDDLEWARE) + MIDDLEWARE = ['debug_toolbar.middleware.DebugToolbarMiddleware'] + list(MIDDLEWARE) INSTALLED_APPS = list(INSTALLED_APPS) + ['debug_toolbar'] diff --git a/sitemaps.py b/sitemaps.py index 220775ca..10241516 100644 --- a/sitemaps.py +++ b/sitemaps.py @@ -14,9 +14,9 @@ from todolists.models import Todolist class PackagesSitemap(Sitemap): def items(self): return Package.objects.normal().only( - 'pkgname', 'last_update', 'files_last_update', - 'repo__name', 'repo__testing', 'repo__staging', - 'arch__name') + 'pkgname', 'last_update', 'files_last_update', + 'repo__name', 'repo__testing', 'repo__staging', + 'arch__name') def lastmod(self, obj): return obj.last_update @@ -70,8 +70,7 @@ class SplitPackagesSitemap(Sitemap): return obj['last_update'] def location(self, obj): - return '/packages/%s/%s/%s/' % ( - obj['repo'].name.lower(), obj['arch'], obj['pkgbase']) + return f"/packages/{obj['repo'].name.lower()}/{obj['arch']}/obj['pkgbase']/" class NewsSitemap(Sitemap): @@ -144,24 +143,24 @@ class BaseSitemap(Sitemap): DEFAULT_PRIORITY = 0.7 base_viewnames = ( - ('index', 1.0, 'hourly'), - ('packages-search', 0.8, 'hourly'), - ('page-download', 0.8, 'monthly'), - ('page-keys', 0.8, 'weekly'), - ('news-list', 0.7, 'weekly'), - ('groups-list', 0.5, 'weekly'), - ('mirror-status', 0.4, 'hourly'), - 'page-about', - 'page-art', - 'page-svn', - 'page-donate', - 'feeds-list', - 'mirror-list', - 'mirror-status', - 'mirrorlist', - 'packages-differences', - 'releng-release-list', - 'visualize-index', + ('index', 1.0, 'hourly'), + ('packages-search', 0.8, 'hourly'), + ('page-download', 0.8, 'monthly'), + ('page-keys', 0.8, 'weekly'), + ('news-list', 0.7, 'weekly'), + ('groups-list', 0.5, 'weekly'), + ('mirror-status', 0.4, 'hourly'), + 'page-about', + 'page-art', + 'page-svn', + 'page-donate', + 'feeds-list', + 'mirror-list', + 'mirror-status', + 'mirrorlist', + 'packages-differences', + 'releng-release-list', + 'visualize-index', ) def items(self): diff --git a/todolists/migrations/0001_squashed_0002_remove_todolist_old_id.py b/todolists/migrations/0001_squashed_0002_remove_todolist_old_id.py index 4acb0fe5..5c12b504 100644 --- a/todolists/migrations/0001_squashed_0002_remove_todolist_old_id.py +++ b/todolists/migrations/0001_squashed_0002_remove_todolist_old_id.py @@ -28,7 +28,8 @@ class Migration(migrations.Migration): ('created', models.DateTimeField(db_index=True)), ('last_modified', models.DateTimeField(editable=False)), ('raw', models.TextField(blank=True)), - ('creator', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='created_todolists', to=settings.AUTH_USER_MODEL)), + ('creator', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, + related_name='created_todolists', to=settings.AUTH_USER_MODEL)), ], options={ 'get_latest_by': 'created', @@ -37,19 +38,22 @@ class Migration(migrations.Migration): migrations.CreateModel( name='TodolistPackage', fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('id', models.AutoField(auto_created=True, primary_key=True, + serialize=False, verbose_name='ID')), ('pkgname', models.CharField(max_length=255)), ('pkgbase', models.CharField(max_length=255)), ('created', models.DateTimeField(editable=False)), ('last_modified', models.DateTimeField(editable=False)), ('removed', models.DateTimeField(blank=True, null=True)), - ('status', models.SmallIntegerField(choices=[(0, 'Incomplete'), (1, 'Complete'), (2, 'In-progress')], default=0)), + ('status', models.SmallIntegerField( + choices=[(0, 'Incomplete'), (1, 'Complete'), (2, 'In-progress')], default=0)), ('comments', models.TextField(blank=True, null=True)), ('arch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.Arch')), ('pkg', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='main.Package')), ('repo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.Repo')), ('todolist', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='todolists.Todolist')), - ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, + to=settings.AUTH_USER_MODEL)), ], options={ 'get_latest_by': 'created', diff --git a/todolists/models.py b/todolists/models.py index c89d09b6..caeccff9 100644 --- a/todolists/models.py +++ b/todolists/models.py @@ -39,9 +39,9 @@ class Todolist(models.Model): def packages(self): if not hasattr(self, '_packages'): self._packages = self.todolistpackage_set.filter( - removed__isnull=True).select_related( - 'pkg', 'repo', 'arch', 'user__userprofile').order_by( - 'pkgname', 'arch') + removed__isnull=True).select_related( + 'pkg', 'repo', 'arch', 'user__userprofile').order_by( + 'pkgname', 'arch') return self._packages diff --git a/todolists/tests/test_models.py b/todolists/tests/test_models.py index 4e629f37..52b11df2 100644 --- a/todolists/tests/test_models.py +++ b/todolists/tests/test_models.py @@ -37,9 +37,9 @@ class TestTodolist(TestCase): def test_packages(self): pkg = Package.objects.first() todopkg = TodolistPackage.objects.create(pkg=pkg, pkgname=pkg.pkgname, - pkgbase=pkg.pkgbase, arch=pkg.arch, - repo=pkg.repo, user=self.user, - todolist=self.todolist) + pkgbase=pkg.pkgbase, arch=pkg.arch, + repo=pkg.repo, user=self.user, + todolist=self.todolist) pkgs = self.todolist.packages() self.assertEqual(len(pkgs), 1) self.assertEqual(pkgs[0], todopkg) diff --git a/todolists/tests/test_views.py b/todolists/tests/test_views.py index 8c605bc3..bebb8d1a 100644 --- a/todolists/tests/test_views.py +++ b/todolists/tests/test_views.py @@ -46,9 +46,8 @@ class TestTodolistAdmin(TestCase): password) self.client.post('/login/', { - 'username': self.user.username, - 'password': password - }) + 'username': self.user.username, + 'password': password}) def tearDown(self): Todolist.objects.all().delete() diff --git a/todolists/urls.py b/todolists/urls.py index 91f3712f..78f833bd 100644 --- a/todolists/urls.py +++ b/todolists/urls.py @@ -2,7 +2,7 @@ from django.conf.urls import url from django.contrib.auth.decorators import permission_required from .views import (view, view_json, add, edit, flag, - list_pkgbases, DeleteTodolist, TodolistListView) + list_pkgbases, DeleteTodolist, TodolistListView) urlpatterns = [ url(r'^$', TodolistListView.as_view(), name='todolist-list'), diff --git a/todolists/utils.py b/todolists/utils.py index c090520f..6dc68077 100644 --- a/todolists/utils.py +++ b/todolists/utils.py @@ -21,7 +21,7 @@ SELECT todolist_id, count(*), SUM(CASE WHEN status = %s THEN 1 ELSE 0 END) def get_annotated_todolists(incomplete_only=False): lists = Todolist.objects.all().defer('raw').select_related( - 'creator').order_by('-created') + 'creator').order_by('-created') lookup = todo_counts() # tag each list with package counts @@ -32,7 +32,7 @@ def get_annotated_todolists(incomplete_only=False): todolist.incomplete_count = counts[0] - counts[1] if incomplete_only: - lists = [l for l in lists if l.incomplete_count > 0] + lists = [lst for lst in lists if lst.incomplete_count > 0] else: lists = sorted(lists, key=lambda todolist: todolist.incomplete_count == 0) return lists @@ -42,9 +42,9 @@ def attach_staging(packages, list_id): '''Look for any staging version of the packages provided and attach them to the 'staging' attribute on each package if found.''' pkgnames = TodolistPackage.objects.filter( - todolist_id=list_id).values('pkgname') + todolist_id=list_id).values('pkgname') staging_pkgs = Package.objects.normal().filter(repo__staging=True, - pkgname__in=pkgnames) + pkgname__in=pkgnames) # now build a lookup dict to attach to the correct package lookup = {(p.pkgname, p.arch): p for p in staging_pkgs} diff --git a/todolists/views.py b/todolists/views.py index fdc5cfc6..4a0df38d 100644 --- a/todolists/views.py +++ b/todolists/views.py @@ -5,7 +5,7 @@ from django import forms from django.http import HttpResponse from django.core.mail import send_mail from django.shortcuts import (get_list_or_404, get_object_or_404, - redirect, render) + redirect, render) from django.db import transaction from django.views.decorators.cache import never_cache from django.views.generic import DeleteView, ListView @@ -21,16 +21,16 @@ from .utils import get_annotated_todolists, attach_staging class TodoListForm(forms.ModelForm): raw = forms.CharField(label='Packages', required=False, - help_text='(one per line)', - widget=forms.Textarea(attrs={'rows': '20', 'cols': '60'})) + help_text='(one per line)', + widget=forms.Textarea(attrs={'rows': '20', 'cols': '60'})) def package_names(self): return {s.strip() for s in self.cleaned_data['raw'].split("\n")} def packages(self): return Package.objects.normal().filter( - pkgname__in=self.package_names(), - repo__testing=False, repo__staging=False).order_by('arch') + pkgname__in=self.package_names(), + repo__testing=False, repo__staging=False).order_by('arch') class Meta: model = Todolist @@ -60,7 +60,7 @@ def flag(request, slug, pkg_id): def view(request, slug): todolist = get_object_or_404(Todolist, slug=slug) svn_roots = Repo.objects.values_list( - 'svn_root', flat=True).order_by().distinct() + 'svn_root', flat=True).order_by().distinct() # we don't hold onto the result, but the objects are the same here, # so accessing maintainers in the template is now cheap attach_maintainers(todolist.packages()) @@ -81,9 +81,9 @@ def list_pkgbases(request, slug, svn_root): todolist = get_object_or_404(Todolist, slug=slug) repos = get_list_or_404(Repo, svn_root=svn_root) pkgbases = TodolistPackage.objects.values_list( - 'pkgbase', flat=True).filter( - todolist=todolist, repo__in=repos, removed__isnull=True).order_by( - 'pkgbase').distinct() + 'pkgbase', flat=True).filter( + todolist=todolist, repo__in=repos, removed__isnull=True).order_by( + 'pkgbase').distinct() return HttpResponse('\n'.join(pkgbases), content_type='text/plain') @@ -108,10 +108,10 @@ def add(request): form = TodoListForm() page_dict = { - 'title': 'Add Todo List', - 'description': '', - 'form': form, - 'submit_text': 'Create List' + 'title': 'Add Todo List', + 'description': '', + 'form': form, + 'submit_text': 'Create List' } return render(request, 'general_form.html', page_dict) @@ -128,13 +128,13 @@ def edit(request, slug): return redirect(todo_list) else: form = TodoListForm(instance=todo_list, - initial={'packages': todo_list.raw}) + initial={'packages': todo_list.raw}) page_dict = { - 'title': 'Edit Todo List: %s' % todo_list.name, - 'description': '', - 'form': form, - 'submit_text': 'Save List' + 'title': f'Edit Todo List: {todo_list.name}', + 'description': '', + 'form': form, + 'submit_text': 'Save List' } return render(request, 'general_form.html', page_dict) @@ -171,7 +171,7 @@ def create_todolist_packages(form, creator=None): to_remove.add(todo_pkg.pk) TodolistPackage.objects.filter( - pk__in=to_remove).update(removed=timestamp) + pk__in=to_remove).update(removed=timestamp) # Add (or mark unremoved) any packages in the new packages list todo_pkgs = [] @@ -183,10 +183,10 @@ def create_todolist_packages(form, creator=None): 'repo': package.repo, } todo_pkg, created = TodolistPackage.objects.get_or_create( - todolist=todolist, - pkgname=package.pkgname, - arch=package.arch, - defaults=defaults) + todolist=todolist, + pkgname=package.pkgname, + arch=package.arch, + defaults=defaults) if created: todo_pkgs.append(todo_pkg) else: @@ -226,10 +226,10 @@ def send_todolist_emails(todo_list, new_packages): } template = loader.get_template('todolists/email_notification.txt') send_mail('Packages added to todo list \'%s\'' % todo_list.name, - template.render(ctx), - 'Arch Website Notification ', - [maint], - fail_silently=True) + template.render(ctx), + 'Arch Website Notification ', + [maint], + fail_silently=True) class TodoListJSONEncoder(PackageJSONEncoder): diff --git a/urls.py b/urls.py index 1bfbc7f4..b676b7b0 100644 --- a/urls.py +++ b/urls.py @@ -60,7 +60,8 @@ feeds_patterns = [ url(r'^packages/(added|removed)/$', cache_page(313)(PackageUpdatesFeed())), url(r'^packages/(added|removed)/(?P[A-z0-9]+)/$', cache_page(313)(PackageUpdatesFeed())), url(r'^packages/(added|removed)/all/(?P[A-z0-9\-]+)/$', cache_page(313)(PackageUpdatesFeed())), - url(r'^packages/(added|removed)/(?P[A-z0-9]+)/(?P[A-z0-9\-]+)/$', cache_page(313)(PackageUpdatesFeed())), + url(r'^packages/(added|removed)/(?P[A-z0-9]+)/(?P[A-z0-9\-]+)/$', + cache_page(313)(PackageUpdatesFeed())), url(r'^packages/(?P[A-z0-9]+)/$', cache_page(313)(PackageFeed())), url(r'^packages/all/(?P[A-z0-9\-]+)/$', cache_page(313)(PackageFeed())), url(r'^packages/(?P[A-z0-9]+)/(?P[A-z0-9\-]+)/$', cache_page(313)(PackageFeed())), @@ -76,16 +77,16 @@ urlpatterns.extend([ # Includes and other remaining stuff urlpatterns.extend([ - url(r'^admin/', admin.site.urls), - url(r'^devel/', include(devel.urls)), - url(r'^feeds/', include(feeds_patterns)), - url(r'^groups/', include(packages.urls_groups)), - url(r'^mirrorlist/',include(mirrors.urls_mirrorlist)), - url(r'^mirrors/', include(mirrors.urls)), - url(r'^news/', include(news.urls)), - url(r'^packages/', include(packages.urls)), - url(r'^releng/', include(releng.urls)), - url(r'^todo/', include(todolists.urls)), + url(r'^admin/', admin.site.urls), + url(r'^devel/', include(devel.urls)), + url(r'^feeds/', include(feeds_patterns)), + url(r'^groups/', include(packages.urls_groups)), + url(r'^mirrorlist/', include(mirrors.urls_mirrorlist)), + url(r'^mirrors/', include(mirrors.urls)), + url(r'^news/', include(news.urls)), + url(r'^packages/', include(packages.urls)), + url(r'^releng/', include(releng.urls)), + url(r'^todo/', include(todolists.urls)), url(r'^visualize/', include(visualize.urls)), url(r'^opensearch/packages/$', packages.views.opensearch, name='opensearch-packages'), url(r'^opensearch/packages/suggest$', packages.views.opensearch_suggest, name='opensearch-packages-suggest'), @@ -116,6 +117,7 @@ if settings.DEBUG_TOOLBAR: path('__debug__/', include(debug_toolbar.urls)), ]) + # displays all archweb urls def show_urls(urllist=urlpatterns, depth=0): # pragma: no cover for entry in urllist: diff --git a/visualize/views.py b/visualize/views.py index 27b2e03f..991dac29 100644 --- a/visualize/views.py +++ b/visualize/views.py @@ -14,10 +14,10 @@ def index(request): def arch_repo_data(): qs = Package.objects.select_related().values( - 'arch__name', 'repo__name').annotate( - count=Count('pk'), csize=Sum('compressed_size'), - isize=Sum('installed_size'), - flagged=Count('flag_date')).order_by() + 'arch__name', 'repo__name').annotate( + count=Count('pk'), csize=Sum('compressed_size'), + isize=Sum('installed_size'), + flagged=Count('flag_date')).order_by() arches = Arch.objects.values_list('name', flat=True) repos = Repo.objects.values_list('name', flat=True) @@ -52,8 +52,8 @@ def arch_repo_data(): repo_groups[repo]['data'].append(values) data = { - 'by_arch': { 'name': 'Architectures', 'data': list(arch_groups.values()) }, - 'by_repo': { 'name': 'Repositories', 'data': list(repo_groups.values()) }, + 'by_arch': {'name': 'Architectures', 'data': list(arch_groups.values())}, + 'by_repo': {'name': 'Repositories', 'data': list(repo_groups.values())}, } return data -- cgit v1.2.3-55-g3dc8