From e9d1fea15ebe43ea4c313de639c7075d98625283 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Wed, 10 Jul 2019 11:27:20 -0500 Subject: [PATCH 1/9] add notes field to Townie --- .../migrations/0012_auto_20190710_1622.py | 25 +++++++++++++++++++ ttadmin/users/models.py | 1 + 2 files changed, 26 insertions(+) create mode 100644 ttadmin/users/migrations/0012_auto_20190710_1622.py diff --git a/ttadmin/users/migrations/0012_auto_20190710_1622.py b/ttadmin/users/migrations/0012_auto_20190710_1622.py new file mode 100644 index 0000000..31838e3 --- /dev/null +++ b/ttadmin/users/migrations/0012_auto_20190710_1622.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.2 on 2019-07-10 16:22 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0011_auto_20190416_0126'), + ] + + operations = [ + migrations.AddField( + model_name='townie', + name='notes', + field=models.TextField(blank=True, null=True), + ), + migrations.AlterField( + model_name='townie', + name='referral', + field=models.CharField(blank=True, max_length=100, null=True), + ), + ] diff --git a/ttadmin/users/models.py b/ttadmin/users/models.py index 78e473e..0818b09 100644 --- a/ttadmin/users/models.py +++ b/ttadmin/users/models.py @@ -49,6 +49,7 @@ class Townie(User): socials = TextField(blank=True, null=False, default='') referral = CharField(max_length=100, null=True, blank=True) displayname = CharField(max_length=100, blank=False, null=False) + notes = TextField(blank=True, null=True) @property def home(self): From 2c71afebc223898e4af913dcb3068651ee10580b Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Wed, 10 Jul 2019 11:27:29 -0500 Subject: [PATCH 2/9] mark readonly user signup fields --- ttadmin/users/admin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ttadmin/users/admin.py b/ttadmin/users/admin.py index bcdeace..5d2db04 100644 --- a/ttadmin/users/admin.py +++ b/ttadmin/users/admin.py @@ -22,6 +22,7 @@ class TownieAdmin(admin.ModelAdmin): inlines = [PubkeyInline] list_display = ('username', 'reviewed', 'email') ordering = ('reviewed',) + readonly_fields = ('reasons', 'plans', 'socials') exclude = ('first_name', 'last_name', 'password', 'groups', 'user_permissions', 'last_login', 'is_staff', 'is_active', 'is_superuser') actions = (bulk_review,) search_fields = ('username', 'email', 'displayname') From 9373589c52355f2d20f9b04013ce8e3a774af94b Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Mon, 15 Jul 2019 20:38:11 -0500 Subject: [PATCH 3/9] code for adding a state field to users --- ttadmin/users/admin.py | 19 ++++++++++----- ttadmin/users/models.py | 51 ++++++++++++++++++++++++++--------------- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/ttadmin/users/admin.py b/ttadmin/users/admin.py index 5d2db04..73bad03 100644 --- a/ttadmin/users/admin.py +++ b/ttadmin/users/admin.py @@ -9,20 +9,27 @@ class PubkeyInline(admin.TabularInline): model = Pubkey extra = 1 -def bulk_review(madmin, req, qs): +def bulk_accept(madmin, req, qs): for townie in qs: - townie.reviewed = True + townie.state = 'accepted' townie.save() post_users_to_social(qs) -bulk_review.short_description = 'mark selected townies as reviewed' +bulk_accept.short_description = 'mark selected townies as accepted' + +def bulk_reject(madmin, req, qs): + for townie in qs: + townie.state = 'rejected' + townie.save() + +bulk_reject.short_description = 'mark selected townies as rejected' @admin.register(Townie) class TownieAdmin(admin.ModelAdmin): inlines = [PubkeyInline] - list_display = ('username', 'reviewed', 'email') - ordering = ('reviewed',) + list_display = ('username', 'state', 'email') readonly_fields = ('reasons', 'plans', 'socials') + ordering = ('state',) exclude = ('first_name', 'last_name', 'password', 'groups', 'user_permissions', 'last_login', 'is_staff', 'is_active', 'is_superuser') - actions = (bulk_review,) + actions = (bulk_accept, bulk_reject,) search_fields = ('username', 'email', 'displayname') diff --git a/ttadmin/users/models.py b/ttadmin/users/models.py index 0818b09..392e2d2 100644 --- a/ttadmin/users/models.py +++ b/ttadmin/users/models.py @@ -42,14 +42,37 @@ class Townie(User): class Meta: verbose_name = 'Townie' verbose_name_plural = 'Townies' + + # the actual values here have a leading int for sorting :( + UNREVIEWED = '0_unreviewed' + TEMPBAN = '1_tempban' + ACCEPTED = '2_accepted' + REJECTED = '3_rejected' + PERMABAN = '4_permaban' + STATE_CHOICES = ( + (REJECTED, 'Rejected'), + (ACCEPTED, 'Accepted'), + (UNREVIEWED, 'Unreviewed'), + (PERMABAN, 'Permanently Banned'), + (TEMPBAN, 'Temporarily Banned'), + ) shell = CharField(max_length=50, default="/bin/bash") - reviewed = BooleanField(default=False) + state = CharField(max_length=20, choices=STATE_CHOICES, default=UNREVIEWED) reasons = TextField(blank=True, null=False, default='') plans = TextField(blank=True, null=False, default='') socials = TextField(blank=True, null=False, default='') referral = CharField(max_length=100, null=True, blank=True) displayname = CharField(max_length=100, blank=False, null=False) - notes = TextField(blank=True, null=True) + notes = TextField(blank=True, null=True, + help_text='Use this field to share information about this user (reviewed or not) for other admins to see') + + @property + def accepted(self): + return self.ACCEPTED == self.state + + @property + def unreviewed(self): + return self.UNREVIEWED == self.state @property def home(self): @@ -86,7 +109,7 @@ class Townie(User): """A VERY NOT IDEMPOTENT create function. Originally, I had ambitions to have this be idempotent and able to incrementally update a user as needed, but decided that was overkill for now.""" - assert(self.reviewed) + assert(self.accepted) dot_ssh_path = '/home/{}/.ssh'.format(self.username) error = _guarded_run(['sudo', @@ -208,7 +231,7 @@ def on_pubkey_post_save(sender, instance, **kwargs): townie = townie[0] - if townie.reviewed: + if townie.accepted: townie.write_authorized_keys() @@ -220,13 +243,17 @@ def on_townie_pre_save(sender, instance, **kwargs): existing = Townie.objects.get(id=instance.id) - # See if we need to create this user on disk. - if not existing.reviewed and instance.reviewed is True: + # See if we need to create the user on disk. + if existing.unreviewed and instance.accepted: logger.info('Creating user {} on disk.'.format(instance.username)) instance.create_on_disk() instance.send_welcome_email() instance.write_authorized_keys() return + else: + # This user state transition is currently undefined. In the future, we can check for things + # like bans/unbans and then take the appropriate action. + return # See if this user needs a rename on disk logger.info('checking for rename {} vs {}'.format( @@ -252,15 +279,3 @@ def _guarded_run(cmd_args, **run_args): issue_text='error while running {}: {}'.format( cmd_args, e)) return e - - -# things to consider: -# * what happens when a user is marked as not reviewed? -# * does this signal user deletion? Or does literal Townie deletion signal -# "needs to be removed from disk"? I think it makes the most sense for the -# latter to imply full user deletion. -# * I honestly can't even think of a reason to revert a user to "not reviewed" -# and perhaps it's best to just not make that possible. for now, though, I -# think I can ignore it. -# * what happens when a user needs to be banned? -# * the Townie should be deleted via post_delete signal From a2af7c5c96e47aba1579a3504bb2796bb308b7d2 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Mon, 15 Jul 2019 20:48:05 -0500 Subject: [PATCH 4/9] restore this field to make migrations easier --- ttadmin/users/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ttadmin/users/models.py b/ttadmin/users/models.py index 392e2d2..82b1ad7 100644 --- a/ttadmin/users/models.py +++ b/ttadmin/users/models.py @@ -58,6 +58,7 @@ class Townie(User): ) shell = CharField(max_length=50, default="/bin/bash") state = CharField(max_length=20, choices=STATE_CHOICES, default=UNREVIEWED) + reviewed = BooleanField(default=False) reasons = TextField(blank=True, null=False, default='') plans = TextField(blank=True, null=False, default='') socials = TextField(blank=True, null=False, default='') From e59bd893fd726e181ae90a7522a497b3f6080222 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Mon, 15 Jul 2019 21:10:35 -0500 Subject: [PATCH 5/9] actually remove reviewed field plus required migrations --- .../migrations/0013_auto_20190716_0148.py | 25 +++++++++++++++++++ .../migrations/0014_auto_20190716_0151.py | 23 +++++++++++++++++ .../migrations/0015_remove_townie_reviewed.py | 19 ++++++++++++++ ttadmin/users/models.py | 1 - 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 ttadmin/users/migrations/0013_auto_20190716_0148.py create mode 100644 ttadmin/users/migrations/0014_auto_20190716_0151.py create mode 100644 ttadmin/users/migrations/0015_remove_townie_reviewed.py diff --git a/ttadmin/users/migrations/0013_auto_20190716_0148.py b/ttadmin/users/migrations/0013_auto_20190716_0148.py new file mode 100644 index 0000000..77b7a75 --- /dev/null +++ b/ttadmin/users/migrations/0013_auto_20190716_0148.py @@ -0,0 +1,25 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.2 on 2019-07-16 01:48 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0012_auto_20190710_1622'), + ] + + operations = [ + migrations.AddField( + model_name='townie', + name='state', + field=models.CharField(choices=[('3_rejected', 'Rejected'), ('2_accepted', 'Accepted'), ('0_unreviewed', 'Unreviewed'), ('4_permaban', 'Permanently Banned'), ('1_tempban', 'Temporarily Banned')], default='0_unreviewed', max_length=20), + ), + migrations.AlterField( + model_name='townie', + name='notes', + field=models.TextField(blank=True, help_text='Use this field to share information about this user (reviewed or not) for other admins to see', null=True), + ), + ] diff --git a/ttadmin/users/migrations/0014_auto_20190716_0151.py b/ttadmin/users/migrations/0014_auto_20190716_0151.py new file mode 100644 index 0000000..5aa9775 --- /dev/null +++ b/ttadmin/users/migrations/0014_auto_20190716_0151.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.2 on 2019-07-16 01:51 +from __future__ import unicode_literals + +from django.db import migrations + +def set_state(apps, _): + Townie = apps.get_model('users', 'Townie') + for townie in Townie.objects.all(): + if townie.reviewed: + townie.state = Townie.ACCEPTED + + townie.save() + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0013_auto_20190716_0148'), + ] + + operations = [ + migrations.RunPython(set_state) + ] diff --git a/ttadmin/users/migrations/0015_remove_townie_reviewed.py b/ttadmin/users/migrations/0015_remove_townie_reviewed.py new file mode 100644 index 0000000..73ee79a --- /dev/null +++ b/ttadmin/users/migrations/0015_remove_townie_reviewed.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.2 on 2019-07-16 02:10 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0014_auto_20190716_0151'), + ] + + operations = [ + migrations.RemoveField( + model_name='townie', + name='reviewed', + ), + ] diff --git a/ttadmin/users/models.py b/ttadmin/users/models.py index 82b1ad7..392e2d2 100644 --- a/ttadmin/users/models.py +++ b/ttadmin/users/models.py @@ -58,7 +58,6 @@ class Townie(User): ) shell = CharField(max_length=50, default="/bin/bash") state = CharField(max_length=20, choices=STATE_CHOICES, default=UNREVIEWED) - reviewed = BooleanField(default=False) reasons = TextField(blank=True, null=False, default='') plans = TextField(blank=True, null=False, default='') socials = TextField(blank=True, null=False, default='') From 31adb3cc3a8ff52faa67226379c80ecbeac08d02 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Mon, 15 Jul 2019 21:15:33 -0500 Subject: [PATCH 6/9] rejected users do not occupy a username --- ttadmin/users/forms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ttadmin/users/forms.py b/ttadmin/users/forms.py index ae843e7..b5ae3ea 100644 --- a/ttadmin/users/forms.py +++ b/ttadmin/users/forms.py @@ -23,7 +23,7 @@ def validate_username(username): raise ValidationError('Username too short.') if not USERNAME_RE.match(username): raise ValidationError('Username must be all lowercase, start with a letter, and only use the _ special character') - duplicate = Townie.objects.filter(username=username).count() + duplicate = Townie.objects.filter(username=username).exclude(state=Townie.REJECTED).count() if duplicate > 0: raise ValidationError('Username already in use :(') From dfd843064d3bd884fdeff4522172a7f0f670ee73 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Mon, 15 Jul 2019 21:44:03 -0500 Subject: [PATCH 7/9] messy wip for Note --- ttadmin/help/admin.py | 16 +++++++++++++++- ttadmin/help/migrations/0005_note.py | 27 +++++++++++++++++++++++++++ ttadmin/help/models.py | 9 ++++++++- 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 ttadmin/help/migrations/0005_note.py diff --git a/ttadmin/help/admin.py b/ttadmin/help/admin.py index e29cc6b..17fd30d 100644 --- a/ttadmin/help/admin.py +++ b/ttadmin/help/admin.py @@ -1,5 +1,13 @@ from django.contrib import admin -from .models import Ticket +from django.forms import ModelForm +from .models import Ticket, Note + +class NoteInline(admin.StackedInline): + model = Note + fields = ('created_at', 'body', 'author') + readonly_fields = ('created_at', 'body', 'author') + ordering = ('created_at',) + extra = 1 @admin.register(Ticket) class TicketAdmin(admin.ModelAdmin): @@ -7,3 +15,9 @@ class TicketAdmin(admin.ModelAdmin): list_display = ('submitted', 'issue_status', 'issue_type', 'name', 'email') list_filter = ('issue_status', 'issue_type') fields = ('submitted', 'name', 'email', 'issue_status', 'issue_type', 'issue_text') + + def save_related(request, form, formsets, change): + for formset in formsets: + import ipdb; ipdb.set_trace() + pass # TODO set author based on request + super() diff --git a/ttadmin/help/migrations/0005_note.py b/ttadmin/help/migrations/0005_note.py new file mode 100644 index 0000000..08bf466 --- /dev/null +++ b/ttadmin/help/migrations/0005_note.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.2 on 2019-07-16 02:43 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0015_remove_townie_reviewed'), + ('help', '0004_ticket_submitted'), + ] + + operations = [ + migrations.CreateModel( + name='Note', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(auto_now_add=True)), + ('body', models.TextField()), + ('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.Townie')), + ('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='help.Ticket')), + ], + ), + ] diff --git a/ttadmin/help/models.py b/ttadmin/help/models.py index 17df9b5..3cfb609 100644 --- a/ttadmin/help/models.py +++ b/ttadmin/help/models.py @@ -1,4 +1,4 @@ -from django.db.models import Model, TextField, EmailField, CharField, DateTimeField +from django.db.models import Model, TextField, EmailField, CharField, DateTimeField, ForeignKey ISSUE_TYPE_CHOICES = ( ('logging_in', 'help logging in'), @@ -34,3 +34,10 @@ class Ticket(Model): def __str__(self): return '{} from {}'.format(self.issue_type, self.name) + + +class Note(Model): + created = DateTimeField(auto_now_add=True) + body = TextField(blank=False, null=False) + author = ForeignKey('users.Townie') + ticket = ForeignKey(Ticket) From 02a50e1d1119df301fb356a79198911eea099dc4 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 18 Jul 2019 17:04:59 -0500 Subject: [PATCH 8/9] working support for tickete notes --- ttadmin/help/admin.py | 37 +++++++++++++++---- .../migrations/0006_auto_20190716_0258.py | 22 +++++++++++ ttadmin/help/models.py | 6 ++- 3 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 ttadmin/help/migrations/0006_auto_20190716_0258.py diff --git a/ttadmin/help/admin.py b/ttadmin/help/admin.py index 17fd30d..1c8d448 100644 --- a/ttadmin/help/admin.py +++ b/ttadmin/help/admin.py @@ -2,22 +2,43 @@ from django.contrib import admin from django.forms import ModelForm from .models import Ticket, Note -class NoteInline(admin.StackedInline): + +class ImmutableNoteInline(admin.TabularInline): model = Note - fields = ('created_at', 'body', 'author') - readonly_fields = ('created_at', 'body', 'author') - ordering = ('created_at',) extra = 1 + max_num = 0 + fields = ('author', 'created', 'body') + readonly_fields = ('author', 'created', 'body') + can_delete = False + ordering = ('created',) + + +class NewNoteInline(admin.StackedInline): + model = Note + extra = 0 + fields = ('body',) + + def get_queryset(self, request): + queryset = super().get_queryset(request) + return queryset.none() + @admin.register(Ticket) class TicketAdmin(admin.ModelAdmin): + inlines = [ImmutableNoteInline, NewNoteInline] readonly_fields = ('submitted',) list_display = ('submitted', 'issue_status', 'issue_type', 'name', 'email') list_filter = ('issue_status', 'issue_type') fields = ('submitted', 'name', 'email', 'issue_status', 'issue_type', 'issue_text') - def save_related(request, form, formsets, change): + def save_related(self, request, form, formsets, change): + # THIS IS EXTREMELY BOOTLEG AND MAY BREAK IF MORE INLINES ARE ADDED TO THIS ADMIN. for formset in formsets: - import ipdb; ipdb.set_trace() - pass # TODO set author based on request - super() + if len(formset.forms) == 1: + # It's probably the add new note form (i hope). + note_form = formset.forms[0] + note_form.instance.author = request.user + note_form.instance.save() + note_form.save(commit=False) + note_form.save_m2m() + return super().save_related(request, form, formsets, change) diff --git a/ttadmin/help/migrations/0006_auto_20190716_0258.py b/ttadmin/help/migrations/0006_auto_20190716_0258.py new file mode 100644 index 0000000..3a9a19c --- /dev/null +++ b/ttadmin/help/migrations/0006_auto_20190716_0258.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.2 on 2019-07-16 02:58 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('help', '0005_note'), + ] + + operations = [ + migrations.AlterField( + model_name='note', + name='author', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/ttadmin/help/models.py b/ttadmin/help/models.py index 3cfb609..a9ff5af 100644 --- a/ttadmin/help/models.py +++ b/ttadmin/help/models.py @@ -1,3 +1,4 @@ +from django.contrib.auth.models import User from django.db.models import Model, TextField, EmailField, CharField, DateTimeField, ForeignKey ISSUE_TYPE_CHOICES = ( @@ -39,5 +40,8 @@ class Ticket(Model): class Note(Model): created = DateTimeField(auto_now_add=True) body = TextField(blank=False, null=False) - author = ForeignKey('users.Townie') + author = ForeignKey(User) ticket = ForeignKey(Ticket) + + def __str__(self): + return "admin note" From 32e640b875bc7060c7bc89c6a7d3bbdfc89c20fb Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Thu, 18 Jul 2019 17:25:28 -0500 Subject: [PATCH 9/9] support assigning of help tickets --- ttadmin/help/admin.py | 8 +++---- .../help/migrations/0007_ticket_assigned.py | 23 +++++++++++++++++++ .../migrations/0008_auto_20190718_2223.py | 22 ++++++++++++++++++ ttadmin/help/models.py | 1 + 4 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 ttadmin/help/migrations/0007_ticket_assigned.py create mode 100644 ttadmin/help/migrations/0008_auto_20190718_2223.py diff --git a/ttadmin/help/admin.py b/ttadmin/help/admin.py index 1c8d448..5bb4f43 100644 --- a/ttadmin/help/admin.py +++ b/ttadmin/help/admin.py @@ -26,10 +26,10 @@ class NewNoteInline(admin.StackedInline): @admin.register(Ticket) class TicketAdmin(admin.ModelAdmin): inlines = [ImmutableNoteInline, NewNoteInline] - readonly_fields = ('submitted',) - list_display = ('submitted', 'issue_status', 'issue_type', 'name', 'email') - list_filter = ('issue_status', 'issue_type') - fields = ('submitted', 'name', 'email', 'issue_status', 'issue_type', 'issue_text') + readonly_fields = ('submitted', 'issue_type') + list_display = ('submitted', 'issue_status', 'assigned', 'issue_type', 'name', 'email',) + list_filter = ('issue_status', 'issue_type', 'assigned') + fields = ('submitted', 'name', 'email', 'assigned', 'issue_status', 'issue_type', 'issue_text') def save_related(self, request, form, formsets, change): # THIS IS EXTREMELY BOOTLEG AND MAY BREAK IF MORE INLINES ARE ADDED TO THIS ADMIN. diff --git a/ttadmin/help/migrations/0007_ticket_assigned.py b/ttadmin/help/migrations/0007_ticket_assigned.py new file mode 100644 index 0000000..2b4029a --- /dev/null +++ b/ttadmin/help/migrations/0007_ticket_assigned.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.2 on 2019-07-18 22:21 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('help', '0006_auto_20190716_0258'), + ] + + operations = [ + migrations.AddField( + model_name='ticket', + name='assigned', + field=models.ForeignKey(help_text='Assign this ticket to an admin or unassign it.', null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/ttadmin/help/migrations/0008_auto_20190718_2223.py b/ttadmin/help/migrations/0008_auto_20190718_2223.py new file mode 100644 index 0000000..dd394ee --- /dev/null +++ b/ttadmin/help/migrations/0008_auto_20190718_2223.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.2 on 2019-07-18 22:23 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('help', '0007_ticket_assigned'), + ] + + operations = [ + migrations.AlterField( + model_name='ticket', + name='assigned', + field=models.ForeignKey(blank=True, help_text='Assign this ticket to an admin or unassign it.', null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/ttadmin/help/models.py b/ttadmin/help/models.py index a9ff5af..70609aa 100644 --- a/ttadmin/help/models.py +++ b/ttadmin/help/models.py @@ -32,6 +32,7 @@ class Ticket(Model): null=False, max_length=50, default=ISSUE_STATUS_CHOICES[0][0]) + assigned = ForeignKey(User, blank=True, null=True, help_text="Assign this ticket to an admin or unassign it.") def __str__(self): return '{} from {}'.format(self.issue_type, self.name)