Compare commits
	
		
			3 commits
		
	
	
		
			472e272305
			...
			e44bdd7be2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e44bdd7be2 | |||
| 345b32f286 | |||
| d499b781d4 | 
					 11 changed files with 212 additions and 387 deletions
				
			
		|  | @ -5,24 +5,7 @@ with the django admin site. | ||||||
| """ | """ | ||||||
| from django.contrib import admin | from django.contrib import admin | ||||||
| 
 | 
 | ||||||
| from .models import ( | from domains.models import HostingDomain, MailDomain | ||||||
|     DNSComment, |  | ||||||
|     DNSCryptoKey, |  | ||||||
|     DNSDomain, |  | ||||||
|     DNSDomainMetadata, |  | ||||||
|     DNSRecord, |  | ||||||
|     DNSSupermaster, |  | ||||||
|     DNSTSIGKey, |  | ||||||
|     HostingDomain, |  | ||||||
|     MailDomain, |  | ||||||
| ) |  | ||||||
| 
 | 
 | ||||||
| admin.site.register(MailDomain) | admin.site.register(MailDomain) | ||||||
| admin.site.register(HostingDomain) | admin.site.register(HostingDomain) | ||||||
| admin.site.register(DNSComment) |  | ||||||
| admin.site.register(DNSCryptoKey) |  | ||||||
| admin.site.register(DNSDomain) |  | ||||||
| admin.site.register(DNSDomainMetadata) |  | ||||||
| admin.site.register(DNSRecord) |  | ||||||
| admin.site.register(DNSSupermaster) |  | ||||||
| admin.site.register(DNSTSIGKey) |  | ||||||
|  |  | ||||||
|  | @ -0,0 +1,74 @@ | ||||||
|  | # Generated by Django 3.2.18 on 2023-04-15 09:53 | ||||||
|  | 
 | ||||||
|  | from django.db import migrations | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  | 
 | ||||||
|  |     dependencies = [ | ||||||
|  |         ('domains', '0004_auto_20151107_1708'), | ||||||
|  |     ] | ||||||
|  | 
 | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AlterIndexTogether( | ||||||
|  |             name='dnscomment', | ||||||
|  |             index_together=None, | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='dnscomment', | ||||||
|  |             name='customer', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='dnscomment', | ||||||
|  |             name='domain', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='dnscryptokey', | ||||||
|  |             name='domain', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='dnsdomain', | ||||||
|  |             name='customer', | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='dnsdomainmetadata', | ||||||
|  |             name='domain', | ||||||
|  |         ), | ||||||
|  |         migrations.AlterIndexTogether( | ||||||
|  |             name='dnsrecord', | ||||||
|  |             index_together=None, | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='dnsrecord', | ||||||
|  |             name='domain', | ||||||
|  |         ), | ||||||
|  |         migrations.AlterUniqueTogether( | ||||||
|  |             name='dnssupermaster', | ||||||
|  |             unique_together=None, | ||||||
|  |         ), | ||||||
|  |         migrations.RemoveField( | ||||||
|  |             model_name='dnssupermaster', | ||||||
|  |             name='customer', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='DNSTSIGKey', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='DNSComment', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='DNSCryptoKey', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='DNSDomain', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='DNSDomainMetadata', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='DNSRecord', | ||||||
|  |         ), | ||||||
|  |         migrations.DeleteModel( | ||||||
|  |             name='DNSSupermaster', | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
|  | @ -7,45 +7,8 @@ from __future__ import absolute_import | ||||||
| from django.conf import settings | from django.conf import settings | ||||||
| from django.db import models, transaction | from django.db import models, transaction | ||||||
| from django.utils.translation import gettext as _ | from django.utils.translation import gettext as _ | ||||||
| from model_utils import Choices |  | ||||||
| from model_utils.models import TimeStampedModel | from model_utils.models import TimeStampedModel | ||||||
| 
 | 
 | ||||||
| DNS_DOMAIN_TYPES = Choices( |  | ||||||
|     ("MASTER", _("Master")), |  | ||||||
|     ("SLAVE", _("Slave")), |  | ||||||
|     ("NATIVE", _("Native")), |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| # see https://doc.powerdns.com/md/authoritative/domainmetadata/ |  | ||||||
| DNS_DOMAIN_METADATA_KINDS = Choices( |  | ||||||
|     "ALLOW-DNSUPDATE-FROM", |  | ||||||
|     "ALSO-NOTIFY", |  | ||||||
|     "AXFR-MASTER-TSIG", |  | ||||||
|     "AXFR-SOURCE", |  | ||||||
|     "FORWARD-DNSUPDATE", |  | ||||||
|     "GSS-ACCEPTOR-PRINCIPAL", |  | ||||||
|     "GSS-ALLOW-AXFR-PRINCIPAL", |  | ||||||
|     "LUA-AXFR-SCRIPT", |  | ||||||
|     "NSEC3NARROW", |  | ||||||
|     "NSEC3PARAM", |  | ||||||
|     "PRESIGNED", |  | ||||||
|     "PUBLISH_CDNSKEY", |  | ||||||
|     "PUBLISH_CDS", |  | ||||||
|     "SOA-EDIT", |  | ||||||
|     "SOA-EDIT-DNSUPDATE", |  | ||||||
|     "TSIG-ALLOW-AXFR", |  | ||||||
|     "TSIG-ALLOW-DNSUPDATE", |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| DNS_TSIG_KEY_ALGORITHMS = Choices( |  | ||||||
|     ("hmac-md5", _("HMAC MD5")), |  | ||||||
|     ("hmac-sha1", _("HMAC SHA1")), |  | ||||||
|     ("hmac-sha224", _("HMAC SHA224")), |  | ||||||
|     ("hmac-sha256", _("HMAC SHA256")), |  | ||||||
|     ("hmac-sha384", _("HMAC SHA384")), |  | ||||||
|     ("hmac-sha512", _("HMAC SHA512")), |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| class DomainBase(TimeStampedModel): | class DomainBase(TimeStampedModel): | ||||||
|     """ |     """ | ||||||
|  | @ -140,296 +103,3 @@ class HostingDomain(DomainBase): | ||||||
| 
 | 
 | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return self.domain |         return self.domain | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DNSDomain(DomainBase): |  | ||||||
|     """ |  | ||||||
|     This model represents a DNS zone. The model is similar to the domain table |  | ||||||
|     in the PowerDNS schema specified in |  | ||||||
|     https://doc.powerdns.com/md/authoritative/backend-generic-mypgsql/. |  | ||||||
| 
 |  | ||||||
|     .. code-block:: sql |  | ||||||
| 
 |  | ||||||
|        CREATE TABLE domains ( |  | ||||||
|          id                    SERIAL PRIMARY KEY, |  | ||||||
|          name                  VARCHAR(255) NOT NULL, |  | ||||||
|          master                VARCHAR(128) DEFAULT NULL, |  | ||||||
|          last_check            INT DEFAULT NULL, |  | ||||||
|          type                  VARCHAR(6) NOT NULL, |  | ||||||
|          notified_serial       INT DEFAULT NULL, |  | ||||||
|          account               VARCHAR(40) DEFAULT NULL, |  | ||||||
|          CONSTRAINT c_lowercase_name CHECK ( |  | ||||||
|              ((name)::TEXT = LOWER((name)::TEXT))) |  | ||||||
|        ); |  | ||||||
| 
 |  | ||||||
|        CREATE UNIQUE INDEX name_index ON domains(name); |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     # name is represented by domain |  | ||||||
|     master = models.CharField(max_length=128, blank=True, null=True) |  | ||||||
|     last_check = models.IntegerField(null=True) |  | ||||||
|     domaintype = models.CharField( |  | ||||||
|         max_length=6, choices=DNS_DOMAIN_TYPES, db_column="type" |  | ||||||
|     ) |  | ||||||
|     notified_serial = models.IntegerField(null=True) |  | ||||||
|     # account is represented by customer_id |  | ||||||
|     # check constraint is added via RunSQL in migration |  | ||||||
| 
 |  | ||||||
|     class Meta: |  | ||||||
|         verbose_name = _("DNS domain") |  | ||||||
|         verbose_name_plural = _("DNS domains") |  | ||||||
| 
 |  | ||||||
|     def __str__(self): |  | ||||||
|         return self.domain |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DNSRecord(models.Model): |  | ||||||
|     """ |  | ||||||
|     This model represents a DNS record. The model is similar to the record |  | ||||||
|     table in the PowerDNS schema specified in |  | ||||||
|     https://doc.powerdns.com/md/authoritative/backend-generic-mypgsql/. |  | ||||||
| 
 |  | ||||||
|     .. code-block:: sql |  | ||||||
| 
 |  | ||||||
|        CREATE TABLE records ( |  | ||||||
|          id                    SERIAL PRIMARY KEY, |  | ||||||
|          domain_id             INT DEFAULT NULL, |  | ||||||
|          name                  VARCHAR(255) DEFAULT NULL, |  | ||||||
|          type                  VARCHAR(10) DEFAULT NULL, |  | ||||||
|          content               VARCHAR(65535) DEFAULT NULL, |  | ||||||
|          ttl                   INT DEFAULT NULL, |  | ||||||
|          prio                  INT DEFAULT NULL, |  | ||||||
|          change_date           INT DEFAULT NULL, |  | ||||||
|          disabled              BOOL DEFAULT 'f', |  | ||||||
|          ordername             VARCHAR(255), |  | ||||||
|          auth                  BOOL DEFAULT 't', |  | ||||||
|          CONSTRAINT domain_exists |  | ||||||
|          FOREIGN KEY(domain_id) REFERENCES domains(id) |  | ||||||
|          ON DELETE CASCADE, |  | ||||||
|          CONSTRAINT c_lowercase_name CHECK ( |  | ||||||
|              ((name)::TEXT = LOWER((name)::TEXT))) |  | ||||||
|        ); |  | ||||||
| 
 |  | ||||||
|        CREATE INDEX rec_name_index ON records(name); |  | ||||||
|        CREATE INDEX nametype_index ON records(name,type); |  | ||||||
|        CREATE INDEX domain_id ON records(domain_id); |  | ||||||
|        CREATE INDEX recordorder ON records ( |  | ||||||
|            domain_id, ordername text_pattern_ops); |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     domain = models.ForeignKey("DNSDomain", on_delete=models.CASCADE) |  | ||||||
|     name = models.CharField(max_length=255, blank=True, null=True, db_index=True) |  | ||||||
|     recordtype = models.CharField( |  | ||||||
|         max_length=10, blank=True, null=True, db_column="type" |  | ||||||
|     ) |  | ||||||
|     content = models.CharField(max_length=65535, blank=True, null=True) |  | ||||||
|     ttl = models.IntegerField(null=True) |  | ||||||
|     prio = models.IntegerField(null=True) |  | ||||||
|     change_date = models.IntegerField(null=True) |  | ||||||
|     disabled = models.BooleanField(default=False) |  | ||||||
|     ordername = models.CharField(max_length=255) |  | ||||||
|     auth = models.BooleanField(default=True) |  | ||||||
|     # check constraint and index recordorder are added via RunSQL in migration |  | ||||||
| 
 |  | ||||||
|     class Meta: |  | ||||||
|         verbose_name = _("DNS record") |  | ||||||
|         verbose_name_plural = _("DNS records") |  | ||||||
|         index_together = [["name", "recordtype"]] |  | ||||||
| 
 |  | ||||||
|     def __str__(self): |  | ||||||
|         return "{name} IN {type} {content}".format( |  | ||||||
|             name=self.name, type=self.recordtype, content=self.content |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DNSSupermaster(models.Model): |  | ||||||
|     """ |  | ||||||
|     This model represents the supermasters table in the PowerDNS schema |  | ||||||
|     specified in |  | ||||||
|     https://doc.powerdns.com/md/authoritative/backend-generic-mypgsql/. |  | ||||||
| 
 |  | ||||||
|     .. code-block:: sql |  | ||||||
| 
 |  | ||||||
|        CREATE TABLE supermasters ( |  | ||||||
|          ip                    INET NOT NULL, |  | ||||||
|          nameserver            VARCHAR(255) NOT NULL, |  | ||||||
|          account               VARCHAR(40) NOT NULL, |  | ||||||
|          PRIMARY KEY(ip, nameserver) |  | ||||||
|        ); |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     ip = models.GenericIPAddressField() |  | ||||||
|     nameserver = models.CharField(max_length=255) |  | ||||||
|     # account is replaced by customer |  | ||||||
|     customer = models.ForeignKey( |  | ||||||
|         settings.AUTH_USER_MODEL, verbose_name=_("customer"), on_delete=models.CASCADE |  | ||||||
|     ) |  | ||||||
| 
 |  | ||||||
|     class Meta: |  | ||||||
|         verbose_name = _("DNS supermaster") |  | ||||||
|         verbose_name_plural = _("DNS supermasters") |  | ||||||
|         unique_together = ("ip", "nameserver") |  | ||||||
| 
 |  | ||||||
|     def __str__(self): |  | ||||||
|         return "{ip} {nameserver}".format(ip=self.ip, nameserver=self.nameserver) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DNSComment(models.Model): |  | ||||||
|     """ |  | ||||||
|     This model represents the comments table in the PowerDNS schema specified |  | ||||||
|     in https://doc.powerdns.com/md/authoritative/backend-generic-mypgsql/. The |  | ||||||
|     comments table is used to store user comments related to individual DNS |  | ||||||
|     records. |  | ||||||
| 
 |  | ||||||
|     .. code-block:: sql |  | ||||||
| 
 |  | ||||||
|        CREATE TABLE comments ( |  | ||||||
|          id                    SERIAL PRIMARY KEY, |  | ||||||
|          domain_id             INT NOT NULL, |  | ||||||
|          name                  VARCHAR(255) NOT NULL, |  | ||||||
|          type                  VARCHAR(10) NOT NULL, |  | ||||||
|          modified_at           INT NOT NULL, |  | ||||||
|          account               VARCHAR(40) DEFAULT NULL, |  | ||||||
|          comment               VARCHAR(65535) NOT NULL, |  | ||||||
|          CONSTRAINT domain_exists |  | ||||||
|          FOREIGN KEY(domain_id) REFERENCES domains(id) |  | ||||||
|          ON DELETE CASCADE, |  | ||||||
|          CONSTRAINT c_lowercase_name CHECK ( |  | ||||||
|              ((name)::TEXT = LOWER((name)::TEXT))) |  | ||||||
|        ); |  | ||||||
| 
 |  | ||||||
|        CREATE INDEX comments_domain_id_idx ON comments (domain_id); |  | ||||||
|        CREATE INDEX comments_name_type_idx ON comments (name, type); |  | ||||||
|        CREATE INDEX comments_order_idx ON comments (domain_id, modified_at); |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     domain = models.ForeignKey("DNSDomain", on_delete=models.CASCADE) |  | ||||||
|     name = models.CharField(max_length=255) |  | ||||||
|     commenttype = models.CharField(max_length=10, db_column="type") |  | ||||||
|     modified_at = models.IntegerField() |  | ||||||
|     # account is replaced by customer |  | ||||||
|     customer = models.ForeignKey( |  | ||||||
|         settings.AUTH_USER_MODEL, verbose_name=_("customer"), on_delete=models.CASCADE |  | ||||||
|     ) |  | ||||||
|     comment = models.CharField(max_length=65535) |  | ||||||
|     # check constraint is added via RunSQL in migration |  | ||||||
| 
 |  | ||||||
|     class Meta: |  | ||||||
|         verbose_name = _("DNS comment") |  | ||||||
|         verbose_name_plural = _("DNS comments") |  | ||||||
|         index_together = [["name", "commenttype"], ["domain", "modified_at"]] |  | ||||||
| 
 |  | ||||||
|     def __str__(self): |  | ||||||
|         return "{name} IN {type}: {comment}".format( |  | ||||||
|             name=self.name, type=self.commenttype, comment=self.comment |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DNSDomainMetadata(models.Model): |  | ||||||
|     """ |  | ||||||
|     This model represents the domainmetadata table in the PowerDNS schema |  | ||||||
|     specified in |  | ||||||
|     https://doc.powerdns.com/md/authoritative/backend-generic-mypgsql/. |  | ||||||
|     The domainmetadata table is used to store domain meta data as described in |  | ||||||
|     https://doc.powerdns.com/md/authoritative/domainmetadata/. |  | ||||||
| 
 |  | ||||||
|     .. code-block:: sql |  | ||||||
| 
 |  | ||||||
|        CREATE TABLE domainmetadata ( |  | ||||||
|          id                    SERIAL PRIMARY KEY, |  | ||||||
|          domain_id             INT REFERENCES domains(id) ON DELETE CASCADE, |  | ||||||
|          kind                  VARCHAR(32), |  | ||||||
|          content               TEXT |  | ||||||
|        ); |  | ||||||
| 
 |  | ||||||
|        CREATE INDEX domainidmetaindex ON domainmetadata(domain_id); |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     domain = models.ForeignKey("DNSDomain", on_delete=models.CASCADE) |  | ||||||
|     kind = models.CharField(max_length=32, choices=DNS_DOMAIN_METADATA_KINDS) |  | ||||||
|     content = models.TextField() |  | ||||||
| 
 |  | ||||||
|     class Meta: |  | ||||||
|         verbose_name = _("DNS domain metadata item") |  | ||||||
|         verbose_name_plural = _("DNS domain metadata items") |  | ||||||
| 
 |  | ||||||
|     def __str__(self): |  | ||||||
|         return "{domain} {kind} {content}".format( |  | ||||||
|             domain=self.domain.domain, kind=self.kind, content=self.content |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DNSCryptoKey(models.Model): |  | ||||||
|     """ |  | ||||||
|     This model represents the cryptokeys table in the PowerDNS schema |  | ||||||
|     specified in |  | ||||||
|     https://doc.powerdns.com/md/authoritative/backend-generic-mypgsql/. |  | ||||||
| 
 |  | ||||||
|     .. code-block:: sql |  | ||||||
| 
 |  | ||||||
|        CREATE TABLE cryptokeys ( |  | ||||||
|          id                    SERIAL PRIMARY KEY, |  | ||||||
|          domain_id             INT REFERENCES domains(id) ON DELETE CASCADE, |  | ||||||
|          flags                 INT NOT NULL, |  | ||||||
|          active                BOOL, |  | ||||||
|          content               TEXT |  | ||||||
|        ); |  | ||||||
| 
 |  | ||||||
|        CREATE INDEX domainidindex ON cryptokeys(domain_id); |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     domain = models.ForeignKey("DNSDomain", on_delete=models.CASCADE) |  | ||||||
|     flags = models.IntegerField() |  | ||||||
|     active = models.BooleanField(default=True) |  | ||||||
|     content = models.TextField() |  | ||||||
| 
 |  | ||||||
|     class Meta: |  | ||||||
|         verbose_name = _("DNS crypto key") |  | ||||||
|         verbose_name_plural = _("DNS crypto keys") |  | ||||||
| 
 |  | ||||||
|     def __str__(self): |  | ||||||
|         return "{domain} {content}".format( |  | ||||||
|             domain=self.domain.domain, content=self.content |  | ||||||
|         ) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| class DNSTSIGKey(models.Model): |  | ||||||
|     """ |  | ||||||
|     This model represents the tsigkeys table in the PowerDNS schema specified |  | ||||||
|     in https://doc.powerdns.com/md/authoritative/backend-generic-mypgsql/. |  | ||||||
| 
 |  | ||||||
|     .. code-block:: sql |  | ||||||
| 
 |  | ||||||
|        CREATE TABLE tsigkeys ( |  | ||||||
|          id                    SERIAL PRIMARY KEY, |  | ||||||
|          name                  VARCHAR(255), |  | ||||||
|          algorithm             VARCHAR(50), |  | ||||||
|          secret                VARCHAR(255), |  | ||||||
|          CONSTRAINT c_lowercase_name CHECK ( |  | ||||||
|              ((name)::TEXT = LOWER((name)::TEXT))) |  | ||||||
|        ); |  | ||||||
| 
 |  | ||||||
|        CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm); |  | ||||||
| 
 |  | ||||||
|     """ |  | ||||||
| 
 |  | ||||||
|     name = models.CharField(max_length=255) |  | ||||||
|     algorithm = models.CharField(max_length=50, choices=DNS_TSIG_KEY_ALGORITHMS) |  | ||||||
|     secret = models.CharField(max_length=255) |  | ||||||
|     # check constraint is added via RunSQL in migration |  | ||||||
| 
 |  | ||||||
|     class Meta: |  | ||||||
|         verbose_name = _("DNS TSIG key") |  | ||||||
|         verbose_name_plural = _("DNS TSIG keys") |  | ||||||
|         unique_together = [["name", "algorithm"]] |  | ||||||
| 
 |  | ||||||
|     def __str__(self): |  | ||||||
|         return "{name} {algorithm} XXXX".format( |  | ||||||
|             name=self.name, algorithm=self.algorithm |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| # import celery_app to initialize it | # import celery_app to initialize it | ||||||
| from gnuviechadmin.celery import app as celery_app  # NOQA | from gnuviechadmin.celery import app as celery_app  # NOQA | ||||||
| 
 | 
 | ||||||
| __version__ = '0.12.1' | __version__ = "0.13.0" | ||||||
|  |  | ||||||
|  | @ -86,7 +86,6 @@ USE_TZ = True | ||||||
| 
 | 
 | ||||||
| LOCALE_PATHS = (normpath(join(SITE_ROOT, "gnuviechadmin", "locale")),) | LOCALE_PATHS = (normpath(join(SITE_ROOT, "gnuviechadmin", "locale")),) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # ######### MEDIA CONFIGURATION | # ######### MEDIA CONFIGURATION | ||||||
| # See: https://docs.djangoproject.com/en/dev/ref/settings/#media-root | # See: https://docs.djangoproject.com/en/dev/ref/settings/#media-root | ||||||
| MEDIA_ROOT = normpath(join(SITE_ROOT, "media")) | MEDIA_ROOT = normpath(join(SITE_ROOT, "media")) | ||||||
|  | @ -180,7 +179,6 @@ AUTHENTICATION_BACKENDS = ( | ||||||
|     "allauth.account.auth_backends.AuthenticationBackend", |     "allauth.account.auth_backends.AuthenticationBackend", | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| # ######### URL CONFIGURATION | # ######### URL CONFIGURATION | ||||||
| # See: https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf | # See: https://docs.djangoproject.com/en/dev/ref/settings/#root-urlconf | ||||||
| ROOT_URLCONF = "%s.urls" % SITE_NAME | ROOT_URLCONF = "%s.urls" % SITE_NAME | ||||||
|  | @ -208,6 +206,7 @@ DJANGO_APPS = ( | ||||||
|     # Flatpages for about page |     # Flatpages for about page | ||||||
|     "django.contrib.flatpages", |     "django.contrib.flatpages", | ||||||
|     "crispy_forms", |     "crispy_forms", | ||||||
|  |     "impersonate", | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| ALLAUTH_APPS = ( | ALLAUTH_APPS = ( | ||||||
|  | @ -366,7 +365,10 @@ def show_debug_toolbar(request): | ||||||
| # See: http://django-debug-toolbar.readthedocs.org/en/latest/installation.html#explicit-setup # noqa | # See: http://django-debug-toolbar.readthedocs.org/en/latest/installation.html#explicit-setup # noqa | ||||||
| INSTALLED_APPS += ("debug_toolbar",) | INSTALLED_APPS += ("debug_toolbar",) | ||||||
| 
 | 
 | ||||||
| MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] | MIDDLEWARE += [ | ||||||
|  |     "impersonate.middleware.ImpersonateMiddleware", | ||||||
|  |     "debug_toolbar.middleware.DebugToolbarMiddleware", | ||||||
|  | ] | ||||||
| 
 | 
 | ||||||
| DEBUG_TOOLBAR_CONFIG = { | DEBUG_TOOLBAR_CONFIG = { | ||||||
|     "SHOW_TOOLBAR_CALLBACK": "gnuviechadmin.settings.show_debug_toolbar" |     "SHOW_TOOLBAR_CALLBACK": "gnuviechadmin.settings.show_debug_toolbar" | ||||||
|  |  | ||||||
|  | @ -11,6 +11,8 @@ admin.autodiscover() | ||||||
| 
 | 
 | ||||||
| urlpatterns = [ | urlpatterns = [ | ||||||
|     re_path(r"", include("dashboard.urls")), |     re_path(r"", include("dashboard.urls")), | ||||||
|  |     re_path(r"^admin/", admin.site.urls), | ||||||
|  |     re_path(r"^impersonate/", include("impersonate.urls")), | ||||||
|     re_path(r"^accounts/", include("allauth.urls")), |     re_path(r"^accounts/", include("allauth.urls")), | ||||||
|     re_path(r"^database/", include("userdbs.urls")), |     re_path(r"^database/", include("userdbs.urls")), | ||||||
|     re_path(r"^domains/", include("domains.urls")), |     re_path(r"^domains/", include("domains.urls")), | ||||||
|  | @ -18,7 +20,6 @@ urlpatterns = [ | ||||||
|     re_path(r"^website/", include("websites.urls")), |     re_path(r"^website/", include("websites.urls")), | ||||||
|     re_path(r"^mail/", include("managemails.urls")), |     re_path(r"^mail/", include("managemails.urls")), | ||||||
|     re_path(r"^osuser/", include("osusers.urls")), |     re_path(r"^osuser/", include("osusers.urls")), | ||||||
|     re_path(r"^admin/", admin.site.urls), |  | ||||||
|     re_path(r"^contact/", include("contact_form.urls")), |     re_path(r"^contact/", include("contact_form.urls")), | ||||||
|     re_path(r"^impressum/$", views.flatpage, {"url": "/impressum/"}, name="imprint"), |     re_path(r"^impressum/$", views.flatpage, {"url": "/impressum/"}, name="imprint"), | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | @ -71,6 +71,7 @@ | ||||||
|             <li class="dropdown{% if active_item == 'account' %} active{% endif %}"> |             <li class="dropdown{% if active_item == 'account' %} active{% endif %}"> | ||||||
|               <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-user"></i> {% trans "My Account" %} <span class="caret"></span></a> |               <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><i class="fa fa-user"></i> {% trans "My Account" %} <span class="caret"></span></a> | ||||||
|               <ul class="dropdown-menu" role="menu"> |               <ul class="dropdown-menu" role="menu"> | ||||||
|  |                 {% if user.is_superuser %}<li><a href="{% url 'impersonate-search' %}"><i class="fa fa-angellist"></i> {% trans "Impersonate user" %}</a></li>{% endif %} | ||||||
|                 {% if user.is_staff %}<li><a href="{% url 'admin:index' %}"><i class="fa fa-wrench"></i> {% trans "Admin site" %}</a></li>{% endif %} |                 {% if user.is_staff %}<li><a href="{% url 'admin:index' %}"><i class="fa fa-wrench"></i> {% trans "Admin site" %}</a></li>{% endif %} | ||||||
|                 <li><a href="{% url 'account_email' %}"><i class="fa fa-at"></i> {% trans "Change Email" %}</a></li> |                 <li><a href="{% url 'account_email' %}"><i class="fa fa-at"></i> {% trans "Change Email" %}</a></li> | ||||||
|                 <li><a href="{% url 'socialaccount_connections' %}"><i class="fa fa-users"></i> {% trans "Social Accounts" %}</a></li> |                 <li><a href="{% url 'socialaccount_connections' %}"><i class="fa fa-users"></i> {% trans "Social Accounts" %}</a></li> | ||||||
|  | @ -85,8 +86,14 @@ | ||||||
|           {% if user.is_authenticated %} |           {% if user.is_authenticated %} | ||||||
|           {% user_display user as user_display %} |           {% user_display user as user_display %} | ||||||
|           {% url 'user_profile' slug=user.username as profile_url %} |           {% url 'user_profile' slug=user.username as profile_url %} | ||||||
|  |               {% if user.is_impersonate %} | ||||||
|  |                   {% user_display user.impersonator as impersonator_display %} | ||||||
|  |                   {% url 'impersonate-stop' as stop_impersonation_url %} | ||||||
|  |                   <p class="navbar-text navbar-right">{% blocktrans %}Signed in as <a href="{{ profile_url }}" class="navbar-link" title="My Profile">{{ user_display }}</a> (impersonated by {{ impersonator_display }}, <a href="{{ stop_impersonation_url }}" class="navbar-link">stop impersonation</a>){% endblocktrans %}</p> | ||||||
|  |               {% else %} | ||||||
|                   <p class="navbar-text navbar-right">{% blocktrans %}Signed in as <a href="{{ profile_url }}" class="navbar-link" title="My Profile">{{ user_display }}</a>{% endblocktrans %}</p> |                   <p class="navbar-text navbar-right">{% blocktrans %}Signed in as <a href="{{ profile_url }}" class="navbar-link" title="My Profile">{{ user_display }}</a>{% endblocktrans %}</p> | ||||||
|               {% endif %} |               {% endif %} | ||||||
|  |           {% endif %} | ||||||
|         </div><!--/.nav-collapse --> |         </div><!--/.nav-collapse --> | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
							
								
								
									
										31
									
								
								gnuviechadmin/templates/impersonate/list_users.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								gnuviechadmin/templates/impersonate/list_users.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,31 @@ | ||||||
|  | {% extends "base.html" %} | ||||||
|  | {% load i18n %} | ||||||
|  | 
 | ||||||
|  | {% block title %}{{ block.super }} - {% trans "Django Impersonate - User List" %}{% endblock title %} | ||||||
|  | {% block page_title %}{% blocktrans %}User List - Page {{ page_number }}{% endblocktrans %}{% endblock page_title %} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  |     {% if page.object_list %} | ||||||
|  |         <ul class="list-group"> | ||||||
|  |             {% for user in page.object_list %} | ||||||
|  |                 <li class="list-group-item"><a href="{% url 'impersonate-start' user.pk %}{{ redirect }}">{{ user }}</a> | ||||||
|  |                     - Impersonate | ||||||
|  |                 </li> | ||||||
|  |             {% endfor %} | ||||||
|  |         </ul> | ||||||
|  |     {% endif %} | ||||||
|  | 
 | ||||||
|  |     <p> | ||||||
|  |         <a href="{% url 'impersonate-search' %}">{% trans "Search users" %}</a> | ||||||
|  |     </p> | ||||||
|  | 
 | ||||||
|  |     <p> | ||||||
|  |         {% if page.has_previous %} | ||||||
|  |             <a href="{% url 'impersonate-list' %}?page={{ page.previous_page_number }}">Previous Page</a>   | ||||||
|  |         {% endif %} | ||||||
|  | 
 | ||||||
|  |         {% if page.has_next %} | ||||||
|  |             <a href="{% url 'impersonate-list' %}?page={{ page.next_page_number }}">Next Page</a>   | ||||||
|  |         {% endif %} | ||||||
|  |     </p> | ||||||
|  | {% endblock %} | ||||||
							
								
								
									
										45
									
								
								gnuviechadmin/templates/impersonate/search_users.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								gnuviechadmin/templates/impersonate/search_users.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | ||||||
|  | {% extends "base.html" %} | ||||||
|  | {% load i18n %} | ||||||
|  | 
 | ||||||
|  | {% block title %}{{ block.super }} - {% trans "Django Impersonate - Search Users" %}{% endblock title %} | ||||||
|  | {% block page_title %}Search Users {% if query %}- Page {{ page_number }}{% endif %}{% endblock page_title %} | ||||||
|  | 
 | ||||||
|  | {% block content %} | ||||||
|  |     <form action="{% url 'impersonate-search' %}" method="GET"> | ||||||
|  |         {{ redirect_field }} | ||||||
|  |         <div class="form-group"> | ||||||
|  |             <label for="user-query">{% trans "Enter Search Query:" %}</label> | ||||||
|  |             <input type="text" name="q" id="user-query" class="form-control" | ||||||
|  |                    value="{% if query %}{{ query }}{% endif %}"> | ||||||
|  |         </div> | ||||||
|  |         <button type="submit" class="btn btn-primary">{% trans "Search" %}</button> | ||||||
|  |     </form> | ||||||
|  | 
 | ||||||
|  |     <p> | ||||||
|  |         <a href="{% url 'impersonate-list' %}">{% trans "List all users" %}</a> | ||||||
|  |     </p> | ||||||
|  | 
 | ||||||
|  |     <p> | ||||||
|  |         {% if query and page.object_list %} | ||||||
|  |             <ul class="list-group"> | ||||||
|  |                 {% for user in page.object_list %} | ||||||
|  |                     <li class="list-group-item"><a | ||||||
|  |                             href="{% url 'impersonate-start' user.pk %}{{ redirect }}">{{ user }}</a> - Impersonate | ||||||
|  |                     </li> | ||||||
|  |                 {% endfor %} | ||||||
|  |             </ul> | ||||||
|  |         {% endif %} | ||||||
|  |     </p> | ||||||
|  | 
 | ||||||
|  |     <p> | ||||||
|  |         {% if query and page.has_previous %} | ||||||
|  |             <a href="{% url 'impersonate-search' %}?page={{ page.previous_page_number }}&q={{ query|urlencode }}">Previous | ||||||
|  |                 Page</a>   | ||||||
|  |         {% endif %} | ||||||
|  | 
 | ||||||
|  |         {% if query and page.has_next %} | ||||||
|  |             <a href="{% url 'impersonate-search' %}?page={{ page.next_page_number }}&q={{ query|urlencode }}">Next | ||||||
|  |                 Page</a> | ||||||
|  |         {% endif %} | ||||||
|  |     </p> | ||||||
|  | {% endblock %} | ||||||
							
								
								
									
										13
									
								
								poetry.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										13
									
								
								poetry.lock
									
										
									
										generated
									
									
									
								
							|  | @ -666,6 +666,17 @@ files = [ | ||||||
| django = ">=3.2.4" | django = ">=3.2.4" | ||||||
| sqlparse = ">=0.2" | sqlparse = ">=0.2" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "django-impersonate" | ||||||
|  | version = "1.9.1" | ||||||
|  | description = "Django app to allow superusers to impersonate other users." | ||||||
|  | category = "main" | ||||||
|  | optional = false | ||||||
|  | python-versions = "*" | ||||||
|  | files = [ | ||||||
|  |     {file = "django-impersonate-1.9.1.tar.gz", hash = "sha256:0befdb096198b458507239a6f21574c9e0f608ab01fad352d71eb9284e5bb9c9"}, | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "django-model-utils" | name = "django-model-utils" | ||||||
| version = "4.3.1" | version = "4.3.1" | ||||||
|  | @ -1742,4 +1753,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more | ||||||
| [metadata] | [metadata] | ||||||
| lock-version = "2.0" | lock-version = "2.0" | ||||||
| python-versions = "^3.7" | python-versions = "^3.7" | ||||||
| content-hash = "6041c8bb49cd1df098f1948f8ad2cbd48fd8f42ff44e410f3fecb61be7e80a18" | content-hash = "dd56e0233689448f08dfcae943871bf9d72c05ad7bfd326c69f9ecb33ea8a461" | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| [tool.poetry] | [tool.poetry] | ||||||
| name = "gva" | name = "gva" | ||||||
| version = "0.12.1" | version = "0.13.0" | ||||||
| description = "gnuviechadmin web interface" | description = "gnuviechadmin web interface" | ||||||
| authors = ["Jan Dittberner <jan@dittberner.info>"] | authors = ["Jan Dittberner <jan@dittberner.info>"] | ||||||
| license = "AGPL-3+" | license = "AGPL-3+" | ||||||
|  | @ -19,6 +19,7 @@ gvacommon = {version = "^0.6.0", source = "gnuviech"} | ||||||
| passlib = "^1.7.4" | passlib = "^1.7.4" | ||||||
| redis = "^4.5.1" | redis = "^4.5.1" | ||||||
| requests-oauthlib = "^1.3.1" | requests-oauthlib = "^1.3.1" | ||||||
|  | django-impersonate = "^1.9.1" | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| [tool.poetry.group.dev.dependencies] | [tool.poetry.group.dev.dependencies] | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue