diff --git a/allianceauth/authentication/views.py b/allianceauth/authentication/views.py index 7d8c33d5..b2121442 100644 --- a/allianceauth/authentication/views.py +++ b/allianceauth/authentication/views.py @@ -6,7 +6,7 @@ from django.contrib.auth import login, authenticate from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User from django.core import signing -from django.core.urlresolvers import reverse +from django.urls import reverse from django.shortcuts import redirect from django.utils.translation import ugettext_lazy as _ from esi.decorators import token_required diff --git a/allianceauth/corputils/models.py b/allianceauth/corputils/models.py index 58643a67..c07d68c0 100644 --- a/allianceauth/corputils/models.py +++ b/allianceauth/corputils/models.py @@ -18,7 +18,7 @@ logger = logging.getLogger(__name__) class CorpStats(models.Model): token = models.ForeignKey(Token, on_delete=models.CASCADE) - corp = models.OneToOneField(EveCorporationInfo) + corp = models.OneToOneField(EveCorporationInfo, on_delete=models.CASCADE) last_update = models.DateTimeField(auto_now=True) class Meta: diff --git a/allianceauth/eveonline/migrations/0009_on_delete.py b/allianceauth/eveonline/migrations/0009_on_delete.py new file mode 100644 index 00000000..ad534248 --- /dev/null +++ b/allianceauth/eveonline/migrations/0009_on_delete.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-09-28 02:16 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('eveonline', '0008_remove_apikeys'), + ] + + operations = [ + migrations.AlterField( + model_name='evecorporationinfo', + name='alliance', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='eveonline.EveAllianceInfo'), + ), + ] diff --git a/allianceauth/eveonline/models.py b/allianceauth/eveonline/models.py index 43b48500..b7754c52 100644 --- a/allianceauth/eveonline/models.py +++ b/allianceauth/eveonline/models.py @@ -1,4 +1,5 @@ from django.db import models +from typing import Union from .managers import EveCharacterManager, EveCharacterProviderManager from .managers import EveCorporationManager, EveCorporationProviderManager @@ -6,34 +7,6 @@ from .managers import EveAllianceManager, EveAllianceProviderManager from . import providers -class EveCharacter(models.Model): - character_id = models.CharField(max_length=254, unique=True) - character_name = models.CharField(max_length=254, unique=True) - corporation_id = models.CharField(max_length=254) - corporation_name = models.CharField(max_length=254) - corporation_ticker = models.CharField(max_length=254) - alliance_id = models.CharField(max_length=254, blank=True, null=True, default='') - alliance_name = models.CharField(max_length=254, blank=True, null=True, default='') - - objects = EveCharacterManager() - provider = EveCharacterProviderManager() - - def update_character(self, character: providers.Character = None): - if character is None: - character = self.provider.get_character(self.character_id) - self.character_name = character.name - self.corporation_id = character.corp.id - self.corporation_name = character.corp.name - self.corporation_ticker = character.corp.ticker - self.alliance_id = character.alliance.id - self.alliance_name = character.alliance.name - self.save() - return self - - def __str__(self): - return self.character_name - - class EveAllianceInfo(models.Model): alliance_id = models.CharField(max_length=254, unique=True) alliance_name = models.CharField(max_length=254, unique=True) @@ -68,7 +41,7 @@ class EveCorporationInfo(models.Model): corporation_name = models.CharField(max_length=254, unique=True) corporation_ticker = models.CharField(max_length=254) member_count = models.IntegerField() - alliance = models.ForeignKey(EveAllianceInfo, blank=True, null=True) + alliance = models.ForeignKey(EveAllianceInfo, blank=True, null=True, on_delete=models.SET_NULL) objects = EveCorporationManager() provider = EveCorporationProviderManager() @@ -86,3 +59,51 @@ class EveCorporationInfo(models.Model): def __str__(self): return self.corporation_name + + +class EveCharacter(models.Model): + character_id = models.CharField(max_length=254, unique=True) + character_name = models.CharField(max_length=254, unique=True) + corporation_id = models.CharField(max_length=254) + corporation_name = models.CharField(max_length=254) + corporation_ticker = models.CharField(max_length=254) + alliance_id = models.CharField(max_length=254, blank=True, null=True, default='') + alliance_name = models.CharField(max_length=254, blank=True, null=True, default='') + + objects = EveCharacterManager() + provider = EveCharacterProviderManager() + + @property + def alliance(self) -> Union[EveAllianceInfo, None]: + """ + Pseudo foreign key from alliance_id to EveAllianceInfo + :raises: EveAllianceInfo.DoesNotExist + :return: EveAllianceInfo or None + """ + if self.alliance_id is None: + return None + return EveAllianceInfo.objects.get(alliance_id=self.alliance_id) + + @property + def corporation(self) -> EveCorporationInfo: + """ + Pseudo foreign key from corporation_id to EveCorporationInfo + :raises: EveCorporationInfo.DoesNotExist + :return: EveCorporationInfo + """ + return EveCorporationInfo.objects.get(corporation_id=self.corporation_id) + + def update_character(self, character: providers.Character = None): + if character is None: + character = self.provider.get_character(self.character_id) + self.character_name = character.name + self.corporation_id = character.corp.id + self.corporation_name = character.corp.name + self.corporation_ticker = character.corp.ticker + self.alliance_id = character.alliance.id + self.alliance_name = character.alliance.name + self.save() + return self + + def __str__(self): + return self.character_name diff --git a/allianceauth/eveonline/tests/test_models.py b/allianceauth/eveonline/tests/test_models.py new file mode 100644 index 00000000..3471a588 --- /dev/null +++ b/allianceauth/eveonline/tests/test_models.py @@ -0,0 +1,121 @@ +from django.test import TestCase + +from ..models import EveCharacter, EveCorporationInfo, EveAllianceInfo + + +class EveCharacterTestCase(TestCase): + def test_corporation_prop(self): + """ + Test that the correct corporation is returned by the corporation property + """ + character = EveCharacter.objects.create( + character_id='1234', + character_name='character.name', + corporation_id='2345', + corporation_name='character.corp.name', + corporation_ticker='character.corp.ticker', + alliance_id='character.alliance.id', + alliance_name='character.alliance.name', + ) + + expected = EveCorporationInfo.objects.create( + corporation_id='2345', + corporation_name='corp.name', + corporation_ticker='corp.ticker', + member_count=10, + alliance=None, + ) + + incorrect = EveCorporationInfo.objects.create( + corporation_id='9999', + corporation_name='corp.name1', + corporation_ticker='corp.ticker1', + member_count=10, + alliance=None, + ) + + self.assertEqual(character.corporation, expected) + self.assertNotEqual(character.corporation, incorrect) + + def test_corporation_prop_exception(self): + """ + Check that an exception is raised when the expected + object is not in the database + """ + character = EveCharacter.objects.create( + character_id='1234', + character_name='character.name', + corporation_id='2345', + corporation_name='character.corp.name', + corporation_ticker='character.corp.ticker', + alliance_id='character.alliance.id', + alliance_name='character.alliance.name', + ) + + with self.assertRaises(EveCorporationInfo.DoesNotExist): + result = character.corporation + + def test_alliance_prop(self): + """ + Test that the correct alliance is returned by the alliance property + """ + character = EveCharacter.objects.create( + character_id='1234', + character_name='character.name', + corporation_id='2345', + corporation_name='character.corp.name', + corporation_ticker='character.corp.ticker', + alliance_id='3456', + alliance_name='character.alliance.name', + ) + + expected = EveAllianceInfo.objects.create( + alliance_id='3456', + alliance_name='alliance.name', + alliance_ticker='alliance.ticker', + executor_corp_id='alliance.executor_corp_id', + ) + + incorrect = EveAllianceInfo.objects.create( + alliance_id='9001', + alliance_name='alliance.name1', + alliance_ticker='alliance.ticker1', + executor_corp_id='alliance.executor_corp_id1', + ) + + self.assertEqual(character.alliance, expected) + self.assertNotEqual(character.alliance, incorrect) + + def test_alliance_prop_exception(self): + """ + Check that an exception is raised when the expected + object is not in the database + """ + character = EveCharacter.objects.create( + character_id='1234', + character_name='character.name', + corporation_id='2345', + corporation_name='character.corp.name', + corporation_ticker='character.corp.ticker', + alliance_id='3456', + alliance_name='character.alliance.name', + ) + + with self.assertRaises(EveAllianceInfo.DoesNotExist): + result = character.alliance + + def test_alliance_prop_none(self): + """ + Check that None is returned when the character has no alliance + """ + character = EveCharacter.objects.create( + character_id='1234', + character_name='character.name', + corporation_id='2345', + corporation_name='character.corp.name', + corporation_ticker='character.corp.ticker', + alliance_id=None, + alliance_name=None, + ) + + self.assertIsNone(character.alliance) diff --git a/allianceauth/fleetactivitytracking/models.py b/allianceauth/fleetactivitytracking/models.py index 3cf4607d..8bb248b4 100644 --- a/allianceauth/fleetactivitytracking/models.py +++ b/allianceauth/fleetactivitytracking/models.py @@ -23,11 +23,11 @@ class Fatlink(models.Model): class Fat(models.Model): character = models.ForeignKey(EveCharacter, on_delete=models.CASCADE) - fatlink = models.ForeignKey(Fatlink) + fatlink = models.ForeignKey(Fatlink, on_delete=models.CASCADE) system = models.CharField(max_length=30) shiptype = models.CharField(max_length=30) station = models.CharField(max_length=125) - user = models.ForeignKey(User) + user = models.ForeignKey(User, on_delete=models.CASCADE) class Meta: unique_together = (('character', 'fatlink'),) diff --git a/allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html b/allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html index 8b507612..7bb16bf6 100644 --- a/allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html +++ b/allianceauth/fleetactivitytracking/templates/fleetactivitytracking/fatlinkmodify.html @@ -2,7 +2,6 @@ {% load bootstrap %} {% load staticfiles %} {% load i18n %} -{% load bootstrap_pagination %} {% block title %}Alliance Auth{% endblock %} {% block page_title %}{% trans "Fatlink view" %}{% endblock page_title %} @@ -20,9 +19,6 @@
{% trans "Registered characters" %}
-
- {% bootstrap_paginate registered_fats range=10 %} -
diff --git a/allianceauth/fleetactivitytracking/views.py b/allianceauth/fleetactivitytracking/views.py index 614f9baa..2d20a666 100644 --- a/allianceauth/fleetactivitytracking/views.py +++ b/allianceauth/fleetactivitytracking/views.py @@ -29,19 +29,6 @@ SWAGGER_SPEC_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'sw logger = logging.getLogger(__name__) -FATS_PER_PAGE = int(getattr(settings, 'FATS_PER_PAGE', 20)) - - -def get_page(model_list, page_num): - p = Paginator(model_list, FATS_PER_PAGE) - try: - fats = p.page(page_num) - except PageNotAnInteger: - fats = p.page(1) - except EmptyPage: - fats = p.page(p.num_pages) - return fats - class CorpStat(object): def __init__(self, corp_id, start_of_month, start_of_next_month, corp=None): @@ -359,8 +346,6 @@ def modify_fatlink_view(request, hash=""): registered_fats = Fat.objects.filter(fatlink=fatlink).order_by('character__character_name') - fat_page = get_page(registered_fats, request.GET.get('page', 1)) - - context = {'fatlink': fatlink, 'registered_fats': fat_page} + context = {'fatlink': fatlink, 'registered_fats': registered_fats} return render(request, 'fleetactivitytracking/fatlinkmodify.html', context=context) diff --git a/allianceauth/groupmanagement/migrations/0007_on_delete.py b/allianceauth/groupmanagement/migrations/0007_on_delete.py new file mode 100644 index 00000000..022e93bd --- /dev/null +++ b/allianceauth/groupmanagement/migrations/0007_on_delete.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-09-28 02:16 +from __future__ import unicode_literals + +import django.contrib.auth.models +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0008_alter_user_username_max_length'), + ('groupmanagement', '0006_request_groups_perm'), + ] + + operations = [ + migrations.CreateModel( + name='ProxyGroup', + fields=[ + ], + options={ + 'verbose_name': 'group', + 'indexes': [], + 'proxy': True, + 'verbose_name_plural': 'groups', + }, + bases=('auth.group',), + managers=[ + ('objects', django.contrib.auth.models.GroupManager()), + ], + ), + migrations.RemoveField( + model_name='grouprequest', + name='main_char', + ), + ] diff --git a/allianceauth/groupmanagement/models.py b/allianceauth/groupmanagement/models.py index bcb1b24d..ed9310ef 100644 --- a/allianceauth/groupmanagement/models.py +++ b/allianceauth/groupmanagement/models.py @@ -10,9 +10,16 @@ from allianceauth.eveonline.models import EveCharacter class GroupRequest(models.Model): status = models.CharField(max_length=254) leave_request = models.BooleanField(default=0) - user = models.ForeignKey(User) - group = models.ForeignKey(Group) - main_char = models.ForeignKey(EveCharacter) + user = models.ForeignKey(User, on_delete=models.CASCADE) + group = models.ForeignKey(Group, on_delete=models.CASCADE) + + @property + def main_char(self): + """ + Legacy property for main character + :return: self.users main character + """ + return self.user.profile.main_character def __str__(self): return self.user.username + ":" + self.group.name diff --git a/allianceauth/hrapplications/models.py b/allianceauth/hrapplications/models.py index 82317549..a9bf57e8 100755 --- a/allianceauth/hrapplications/models.py +++ b/allianceauth/hrapplications/models.py @@ -23,7 +23,7 @@ class ApplicationChoice(models.Model): class ApplicationForm(models.Model): questions = SortedManyToManyField(ApplicationQuestion) - corp = models.OneToOneField(EveCorporationInfo) + corp = models.OneToOneField(EveCorporationInfo, on_delete=models.CASCADE) def __str__(self): return str(self.corp) diff --git a/allianceauth/optimer/migrations/0004_on_delete.py b/allianceauth/optimer/migrations/0004_on_delete.py new file mode 100644 index 00000000..958cdff8 --- /dev/null +++ b/allianceauth/optimer/migrations/0004_on_delete.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-09-28 02:16 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('optimer', '0003_make_strings_more_stringy'), + ] + + operations = [ + migrations.AlterField( + model_name='optimer', + name='eve_character', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='eveonline.EveCharacter'), + ), + ] diff --git a/allianceauth/optimer/models.py b/allianceauth/optimer/models.py index fe9d19b9..08a17e3e 100644 --- a/allianceauth/optimer/models.py +++ b/allianceauth/optimer/models.py @@ -17,7 +17,7 @@ class OpTimer(models.Model): operation_name = models.CharField(max_length=254, default="") fc = models.CharField(max_length=254, default="") post_time = models.DateTimeField(default=timezone.now) - eve_character = models.ForeignKey(EveCharacter) + eve_character = models.ForeignKey(EveCharacter, null=True, on_delete=models.SET_NULL) def __str__(self): return self.operation_name diff --git a/allianceauth/permissions_tool/tests.py b/allianceauth/permissions_tool/tests.py index b432fa29..42b35ddf 100644 --- a/allianceauth/permissions_tool/tests.py +++ b/allianceauth/permissions_tool/tests.py @@ -10,7 +10,6 @@ from allianceauth.tests.auth_utils import AuthUtils class PermissionsToolViewsTestCase(TestCase): def setUp(self): self.member = AuthUtils.create_member('auth_member') - self.member.set_password('password') self.member.email = 'auth_member@example.com' self.member.save() self.none_user = AuthUtils.create_user('none_user', disconnect_signals=True) @@ -18,7 +17,6 @@ class PermissionsToolViewsTestCase(TestCase): self.none_user3 = AuthUtils.create_user('none_user3', disconnect_signals=True) self.no_perm_user = AuthUtils.create_user('no_perm_user', disconnect_signals=True) - self.no_perm_user.set_password('password') AuthUtils.disconnect_signals() self.no_perm_group = Group.objects.create(name="No Permission Group") @@ -38,17 +36,16 @@ class PermissionsToolViewsTestCase(TestCase): AuthUtils.connect_signals() def test_menu_item(self): - self.client.login(username=self.member.username, password='password') + self.client.force_login(self.member) response = self.client.get(urls.reverse('permissions_tool:overview')) - response_content = str(response.content, encoding='utf8') + response_content = response.content.decode('utf-8') - self.assertInHTML( - '
  • Permissions Audit
  • ', - response_content) + self.assertInHTML('
  • ' + ' Permissions Audit
  • ', response_content) def test_permissions_overview(self): - self.client.login(username=self.member.username, password='password') + self.client.force_login(self.member) response = self.client.get(urls.reverse('permissions_tool:overview')) @@ -63,22 +60,25 @@ class PermissionsToolViewsTestCase(TestCase): for perm in response.context['permissions']: if perm['permission'] == self.permission: tested_context = True - self.assertDictContainsSubset({'users': 1}, perm) - self.assertDictContainsSubset({'groups': 1}, perm) - self.assertDictContainsSubset({'group_users': 3}, perm) + self.assertIn('users', perm) + self.assertEqual(perm['users'], 1) + self.assertIn('groups', perm) + self.assertEqual(perm['groups'], 1) + self.assertIn('group_users', perm) + self.assertEqual(perm['group_users'], 3) break self.assertTrue(tested_context) def test_permissions_overview_perms(self): # Ensure permission effectively denys access - self.client.login(username=self.no_perm_user.username, password='password') + self.client.force_login(self.no_perm_user) response = self.client.get(urls.reverse('permissions_tool:overview')) self.assertEqual(response.status_code, 302) def test_permissions_audit(self): - self.client.login(username=self.member.username, password='password') + self.client.force_login(self.member) response = self.client.get(urls.reverse('permissions_tool:audit', kwargs={ @@ -99,7 +99,7 @@ class PermissionsToolViewsTestCase(TestCase): def test_permissions_audit_perms(self): # Ensure permission effectively denys access - self.client.login(username=self.no_perm_user.username, password='password') + self.client.force_login(self.no_perm_user) response = self.client.get(urls.reverse('permissions_tool:audit', kwargs={ diff --git a/allianceauth/services/migrations/0001_initial.py b/allianceauth/services/migrations/0001_initial.py deleted file mode 100644 index a482d393..00000000 --- a/allianceauth/services/migrations/0001_initial.py +++ /dev/null @@ -1,38 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.1 on 2016-09-05 21:40 -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): - - initial = True - - dependencies = [ - ('auth', '0008_alter_user_username_max_length'), - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='DiscordAuthToken', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('email', models.CharField(max_length=254, unique=True)), - ('token', models.CharField(max_length=254)), - ('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), - ], - ), - migrations.CreateModel( - name='GroupCache', - fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('created', models.DateTimeField(auto_now_add=True)), - ('groups', models.TextField(default={})), - ('service', models.CharField(choices=[(b'discourse', b'discourse'), (b'discord', b'discord')], max_length=254, unique=True)), - ], - ), - ] diff --git a/allianceauth/services/migrations/0002_auto_20161016_0135.py b/allianceauth/services/migrations/0002_auto_20161016_0135.py deleted file mode 100644 index 68749395..00000000 --- a/allianceauth/services/migrations/0002_auto_20161016_0135.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.1 on 2016-10-16 01:35 -from __future__ import unicode_literals - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('services', '0001_initial'), - ] - - operations = [ - migrations.RemoveField( - model_name='discordauthtoken', - name='user', - ), - migrations.DeleteModel( - name='DiscordAuthToken', - ), - ] diff --git a/allianceauth/services/migrations/0003_delete_groupcache.py b/allianceauth/services/migrations/0003_delete_groupcache.py deleted file mode 100644 index cc949a31..00000000 --- a/allianceauth/services/migrations/0003_delete_groupcache.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.10.5 on 2017-09-02 06:07 -from __future__ import unicode_literals - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('services', '0002_auto_20161016_0135'), - ] - - operations = [ - migrations.DeleteModel( - name='GroupCache', - ), - ] diff --git a/allianceauth/services/migrations/__init__.py b/allianceauth/services/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/allianceauth/services/modules/discord/tests.py b/allianceauth/services/modules/discord/tests.py index db255028..e52044fc 100644 --- a/allianceauth/services/modules/discord/tests.py +++ b/allianceauth/services/modules/discord/tests.py @@ -141,12 +141,10 @@ class DiscordHooksTestCase(TestCase): class DiscordViewsTestCase(TestCase): def setUp(self): self.member = AuthUtils.create_member('auth_member') - self.member.set_password('password') - self.member.save() add_permissions() def login(self): - self.client.login(username=self.member.username, password='password') + self.client.force_login(self.member) @mock.patch(MODULE_PATH + '.views.DiscordOAuthManager') def test_activate(self, manager): diff --git a/allianceauth/services/modules/discord/urls.py b/allianceauth/services/modules/discord/urls.py index 056ebc3e..30f48937 100644 --- a/allianceauth/services/modules/discord/urls.py +++ b/allianceauth/services/modules/discord/urls.py @@ -2,6 +2,8 @@ from django.conf.urls import url, include from . import views +app_name = 'discord' + module_urls = [ # Discord Service Control url(r'^activate/$', views.activate_discord, name='activate'), @@ -12,5 +14,5 @@ module_urls = [ ] urlpatterns = [ - url(r'^discord/', include(module_urls, namespace='discord')) + url(r'^discord/', include((module_urls, app_name), namespace=app_name)) ] diff --git a/allianceauth/services/modules/discourse/tests.py b/allianceauth/services/modules/discourse/tests.py index 189a0c55..38eda84f 100644 --- a/allianceauth/services/modules/discourse/tests.py +++ b/allianceauth/services/modules/discourse/tests.py @@ -113,14 +113,12 @@ class DiscourseHooksTestCase(TestCase): class DiscourseViewsTestCase(TestCase): def setUp(self): self.member = AuthUtils.create_member('auth_member') - self.member.set_password('password') - self.member.save() AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation') add_permissions() @mock.patch(MODULE_PATH + '.tasks.DiscourseManager') def test_sso_member(self, manager): - self.client.login(username=self.member.username, password='password') + self.client.force_login(self.member) data = {'sso': 'bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D%0A', 'sig': '2828aa29899722b35a2f191d34ef9b3ce695e0e6eeec47deb46d588d70c7cb56'} response = self.client.get('/discourse/sso', data=data, follow=False) diff --git a/allianceauth/services/modules/example/urls.py b/allianceauth/services/modules/example/urls.py index 3df31b1a..f72d9abd 100644 --- a/allianceauth/services/modules/example/urls.py +++ b/allianceauth/services/modules/example/urls.py @@ -1,9 +1,11 @@ from django.conf.urls import url, include +app_name = 'example' + module_urls = [ # Add your module URLs here ] urlpatterns = [ - url(r'^example/', include(module_urls, namespace='example')), + url(r'^example/', include((module_urls, app_name), namespace=app_name)), ] diff --git a/allianceauth/services/modules/ips4/tests.py b/allianceauth/services/modules/ips4/tests.py index 613c95d5..e568f0bd 100644 --- a/allianceauth/services/modules/ips4/tests.py +++ b/allianceauth/services/modules/ips4/tests.py @@ -68,14 +68,13 @@ class Ips4HooksTestCase(TestCase): class Ips4ViewsTestCase(TestCase): def setUp(self): self.member = AuthUtils.create_member('auth_member') - self.member.set_password('password') self.member.email = 'auth_member@example.com' self.member.save() AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation') add_permissions() def login(self): - self.client.login(username=self.member.username, password='password') + self.client.force_login(self.member) @mock.patch(MODULE_PATH + '.views.Ips4Manager') def test_activate(self, manager): diff --git a/allianceauth/services/modules/ips4/urls.py b/allianceauth/services/modules/ips4/urls.py index f6c65907..a13a98e6 100644 --- a/allianceauth/services/modules/ips4/urls.py +++ b/allianceauth/services/modules/ips4/urls.py @@ -2,6 +2,8 @@ from django.conf.urls import url, include from . import views +app_name = 'ips4' + module_urls = [ # IPS4 Service Control url(r'^activate/$', views.activate_ips4, name='activate'), @@ -11,5 +13,5 @@ module_urls = [ ] urlpatterns = [ - url(r'^ips4/', include(module_urls, namespace='ips4')) + url(r'^ips4/', include((module_urls, app_name), namespace=app_name)) ] diff --git a/allianceauth/services/modules/market/tests.py b/allianceauth/services/modules/market/tests.py index fa463925..71674fe9 100644 --- a/allianceauth/services/modules/market/tests.py +++ b/allianceauth/services/modules/market/tests.py @@ -96,14 +96,13 @@ class MarketHooksTestCase(TestCase): class MarketViewsTestCase(TestCase): def setUp(self): self.member = AuthUtils.create_member('auth_member') - self.member.set_password('password') self.member.email = 'auth_member@example.com' self.member.save() AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation') add_permissions() def login(self): - self.client.login(username=self.member.username, password='password') + self.client.force_login(self.member) @mock.patch(MODULE_PATH + '.views.MarketManager') def test_activate(self, manager): diff --git a/allianceauth/services/modules/market/urls.py b/allianceauth/services/modules/market/urls.py index d588c792..3381ec29 100644 --- a/allianceauth/services/modules/market/urls.py +++ b/allianceauth/services/modules/market/urls.py @@ -2,6 +2,8 @@ from django.conf.urls import url, include from . import views +app_name = 'evernusmarket' + module_urls = [ # Alliance Market Control url(r'^activate/$', views.activate_market, name='activate'), @@ -11,5 +13,5 @@ module_urls = [ ] urlpatterns = [ - url(r'^evernus-market/', include(module_urls, namespace='evernusmarket')) + url(r'^evernus-market/', include((module_urls, app_name), namespace=app_name)) ] diff --git a/allianceauth/services/modules/mumble/models.py b/allianceauth/services/modules/mumble/models.py index 8df6be40..6e0a8e0d 100644 --- a/allianceauth/services/modules/mumble/models.py +++ b/allianceauth/services/modules/mumble/models.py @@ -2,7 +2,7 @@ from django.db import models class MumbleUser(models.Model): - user = models.OneToOneField('auth.User', related_name='mumble', null=True) + user = models.OneToOneField('auth.User', related_name='mumble', null=True, on_delete=models.CASCADE) username = models.CharField(max_length=254, unique=True) pwhash = models.CharField(max_length=80) hashfn = models.CharField(max_length=20, default='sha1') diff --git a/allianceauth/services/modules/mumble/tests.py b/allianceauth/services/modules/mumble/tests.py index 4cd16cc0..84308d8b 100644 --- a/allianceauth/services/modules/mumble/tests.py +++ b/allianceauth/services/modules/mumble/tests.py @@ -119,7 +119,6 @@ class MumbleHooksTestCase(TestCase): class MumbleViewsTestCase(TestCase): def setUp(self): self.member = AuthUtils.create_member('auth_member') - self.member.set_password('password') self.member.email = 'auth_member@example.com' self.member.save() AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation', @@ -127,7 +126,7 @@ class MumbleViewsTestCase(TestCase): add_permissions() def login(self): - self.client.login(username=self.member.username, password='password') + self.client.force_login(self.member) def test_activate(self): self.login() diff --git a/allianceauth/services/modules/mumble/urls.py b/allianceauth/services/modules/mumble/urls.py index b60034a9..dd0e04ef 100644 --- a/allianceauth/services/modules/mumble/urls.py +++ b/allianceauth/services/modules/mumble/urls.py @@ -2,6 +2,8 @@ from django.conf.urls import url, include from . import views +app_name = 'mumble' + module_urls = [ # Mumble service control url(r'^activate/$', views.activate_mumble, name='activate'), @@ -12,5 +14,5 @@ module_urls = [ ] urlpatterns = [ - url(r'^mumble/', include(module_urls, namespace='mumble')) + url(r'^mumble/', include((module_urls, app_name), namespace=app_name)) ] diff --git a/allianceauth/services/modules/openfire/tests.py b/allianceauth/services/modules/openfire/tests.py index 503c948c..a2c50a85 100644 --- a/allianceauth/services/modules/openfire/tests.py +++ b/allianceauth/services/modules/openfire/tests.py @@ -123,14 +123,13 @@ class OpenfireHooksTestCase(TestCase): class OpenfireViewsTestCase(TestCase): def setUp(self): self.member = AuthUtils.create_member('auth_member') - self.member.set_password('password') self.member.email = 'auth_member@example.com' self.member.save() AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation') add_permissions() def login(self): - self.client.login(username=self.member.username, password='password') + self.client.force_login(self.member) @mock.patch(MODULE_PATH + '.tasks.OpenfireManager') @mock.patch(MODULE_PATH + '.views.OpenfireManager') diff --git a/allianceauth/services/modules/openfire/urls.py b/allianceauth/services/modules/openfire/urls.py index 4e80a4a9..230d9fb4 100644 --- a/allianceauth/services/modules/openfire/urls.py +++ b/allianceauth/services/modules/openfire/urls.py @@ -2,6 +2,8 @@ from django.conf.urls import url, include from . import views +app_name = 'openfire' + module_urls = [ # Jabber Service Control url(r'^activate/$', views.activate_jabber, name='activate'), @@ -12,5 +14,5 @@ module_urls = [ ] urlpatterns = [ - url(r'^openfire/', include(module_urls, namespace='openfire')), + url(r'^openfire/', include((module_urls, app_name), namespace=app_name)), ] diff --git a/allianceauth/services/modules/phpbb3/tests.py b/allianceauth/services/modules/phpbb3/tests.py index 42feb087..cd5de997 100644 --- a/allianceauth/services/modules/phpbb3/tests.py +++ b/allianceauth/services/modules/phpbb3/tests.py @@ -123,14 +123,13 @@ class Phpbb3HooksTestCase(TestCase): class Phpbb3ViewsTestCase(TestCase): def setUp(self): self.member = AuthUtils.create_member('auth_member') - self.member.set_password('password') self.member.email = 'auth_member@example.com' self.member.save() AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation') add_permissions() def login(self): - self.client.login(username=self.member.username, password='password') + self.client.force_login(self.member) @mock.patch(MODULE_PATH + '.tasks.Phpbb3Manager') @mock.patch(MODULE_PATH + '.views.Phpbb3Manager') diff --git a/allianceauth/services/modules/phpbb3/urls.py b/allianceauth/services/modules/phpbb3/urls.py index fd1840a5..26611469 100644 --- a/allianceauth/services/modules/phpbb3/urls.py +++ b/allianceauth/services/modules/phpbb3/urls.py @@ -2,6 +2,8 @@ from django.conf.urls import url, include from . import views +app_name = 'phpbb3' + module_urls = [ # Forum Service Control url(r'^activate/$', views.activate_forum, name='activate'), @@ -11,5 +13,5 @@ module_urls = [ ] urlpatterns = [ - url(r'^phpbb3/', include(module_urls, namespace='phpbb3')) + url(r'^phpbb3/', include((module_urls, app_name), namespace=app_name)) ] diff --git a/allianceauth/services/modules/seat/tests.py b/allianceauth/services/modules/seat/tests.py index 54a2db0b..ebd13049 100644 --- a/allianceauth/services/modules/seat/tests.py +++ b/allianceauth/services/modules/seat/tests.py @@ -127,14 +127,13 @@ class SeatHooksTestCase(TestCase): class SeatViewsTestCase(TestCase): def setUp(self): self.member = AuthUtils.create_member('auth_member') - self.member.set_password('password') self.member.email = 'auth_member@example.com' self.member.save() AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation') add_permissions() def login(self): - self.client.login(username=self.member.username, password='password') + self.client.force_login(self.member) @mock.patch(MODULE_PATH + '.tasks.SeatManager') @mock.patch(MODULE_PATH + '.views.SeatManager') diff --git a/allianceauth/services/modules/seat/urls.py b/allianceauth/services/modules/seat/urls.py index 418f6c6f..c374681c 100644 --- a/allianceauth/services/modules/seat/urls.py +++ b/allianceauth/services/modules/seat/urls.py @@ -2,6 +2,8 @@ from django.conf.urls import url, include from . import views +app_name='seat' + module_urls = [ # SeAT Service Control url(r'^activate/$', views.activate_seat, name='activate'), @@ -11,5 +13,5 @@ module_urls = [ ] urlpatterns = [ - url(r'^seat/', include(module_urls, namespace='seat')), + url(r'^seat/', include((module_urls, app_name), namespace=app_name)), ] diff --git a/allianceauth/services/modules/smf/tests.py b/allianceauth/services/modules/smf/tests.py index c185c407..ed58e818 100644 --- a/allianceauth/services/modules/smf/tests.py +++ b/allianceauth/services/modules/smf/tests.py @@ -123,14 +123,13 @@ class SmfHooksTestCase(TestCase): class SmfViewsTestCase(TestCase): def setUp(self): self.member = AuthUtils.create_member('auth_member') - self.member.set_password('password') self.member.email = 'auth_member@example.com' self.member.save() AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation') add_permissions() def login(self): - self.client.login(username=self.member.username, password='password') + self.client.force_login(self.member) @mock.patch(MODULE_PATH + '.tasks.SmfManager') @mock.patch(MODULE_PATH + '.views.SmfManager') diff --git a/allianceauth/services/modules/smf/urls.py b/allianceauth/services/modules/smf/urls.py index 475ee98d..59e396bf 100644 --- a/allianceauth/services/modules/smf/urls.py +++ b/allianceauth/services/modules/smf/urls.py @@ -2,6 +2,8 @@ from django.conf.urls import url, include from . import views +app_name = 'smf' + module_urls = [ # SMF Service Control url(r'^activate/$', views.activate_smf, name='activate'), @@ -11,5 +13,5 @@ module_urls = [ ] urlpatterns = [ - url(r'^smf/', include(module_urls, namespace='smf')), + url(r'^smf/', include((module_urls, app_name), namespace=app_name)), ] diff --git a/allianceauth/services/modules/teamspeak3/migrations/0001_initial.py b/allianceauth/services/modules/teamspeak3/migrations/0001_initial.py index 0e5f552f..a46605d3 100644 --- a/allianceauth/services/modules/teamspeak3/migrations/0001_initial.py +++ b/allianceauth/services/modules/teamspeak3/migrations/0001_initial.py @@ -24,7 +24,7 @@ class Migration(migrations.Migration): ('auth_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='auth.Group')), ], options={ - 'db_table': 'services_authts', + 'db_table': 'teamspeak3_authts', 'verbose_name': 'Auth / TS Group', }, ), @@ -35,7 +35,7 @@ class Migration(migrations.Migration): ('ts_group_name', models.CharField(max_length=30)), ], options={ - 'db_table': 'services_tsgroup', + 'db_table': 'teamspeak3_tsgroup', 'verbose_name': 'TS Group', }, ), @@ -47,7 +47,7 @@ class Migration(migrations.Migration): ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], options={ - 'db_table': 'services_usertsgroup', + 'db_table': 'teamspeak3_usertsgroup', 'verbose_name': 'User TS Group', }, ), diff --git a/allianceauth/services/modules/teamspeak3/models.py b/allianceauth/services/modules/teamspeak3/models.py index 0aa885f8..97e66cfd 100644 --- a/allianceauth/services/modules/teamspeak3/models.py +++ b/allianceauth/services/modules/teamspeak3/models.py @@ -1,8 +1,9 @@ from django.db import models +from django.contrib.auth.models import User, Group class Teamspeak3User(models.Model): - user = models.OneToOneField('auth.User', + user = models.OneToOneField(User, primary_key=True, on_delete=models.CASCADE, related_name='teamspeak3') @@ -30,7 +31,7 @@ class TSgroup(models.Model): class AuthTS(models.Model): - auth_group = models.ForeignKey('auth.Group') + auth_group = models.ForeignKey(Group, on_delete=models.CASCADE) ts_group = models.ManyToManyField(TSgroup) class Meta: @@ -41,7 +42,7 @@ class AuthTS(models.Model): class UserTSgroup(models.Model): - user = models.ForeignKey('auth.User') + user = models.ForeignKey(User, on_delete=models.CASCADE) ts_group = models.ManyToManyField(TSgroup) class Meta: diff --git a/allianceauth/services/modules/teamspeak3/tests.py b/allianceauth/services/modules/teamspeak3/tests.py index f17b5774..62ac4d88 100644 --- a/allianceauth/services/modules/teamspeak3/tests.py +++ b/allianceauth/services/modules/teamspeak3/tests.py @@ -136,7 +136,6 @@ class Teamspeak3ViewsTestCase(TestCase): # Inert signals before setup begins with mock.patch(MODULE_PATH + '.signals.trigger_all_ts_update') as trigger_all_ts_update: self.member = AuthUtils.create_member('auth_member') - self.member.set_password('password') self.member.email = 'auth_member@example.com' self.member.save() AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation') @@ -150,7 +149,7 @@ class Teamspeak3ViewsTestCase(TestCase): def login(self, user=None, password=None): if user is None: user = self.member - self.client.login(username=user.username, password=password if password else 'password') + self.client.force_login(user) @mock.patch(MODULE_PATH + '.forms.Teamspeak3Manager') @mock.patch(MODULE_PATH + '.views.Teamspeak3Manager') diff --git a/allianceauth/services/modules/teamspeak3/urls.py b/allianceauth/services/modules/teamspeak3/urls.py index ba4e00e8..98bf6992 100644 --- a/allianceauth/services/modules/teamspeak3/urls.py +++ b/allianceauth/services/modules/teamspeak3/urls.py @@ -2,6 +2,8 @@ from django.conf.urls import url, include from . import views +app_name = 'teamspeak3' + module_urls = [ # Teamspeak3 service control url(r'^activate/$', views.activate_teamspeak3, @@ -16,5 +18,5 @@ module_urls = [ ] urlpatterns = [ - url(r'^teamspeak3/', include(module_urls, namespace='teamspeak3')), + url(r'^teamspeak3/', include((module_urls, app_name), namespace=app_name)), ] diff --git a/allianceauth/services/modules/xenforo/tests.py b/allianceauth/services/modules/xenforo/tests.py index 333e10b9..f0814359 100644 --- a/allianceauth/services/modules/xenforo/tests.py +++ b/allianceauth/services/modules/xenforo/tests.py @@ -99,14 +99,13 @@ class XenforoHooksTestCase(TestCase): class XenforoViewsTestCase(TestCase): def setUp(self): self.member = AuthUtils.create_member('auth_member') - self.member.set_password('password') self.member.email = 'auth_member@example.com' self.member.save() AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation') add_permissions() def login(self): - self.client.login(username=self.member.username, password='password') + self.client.force_login(self.member) @mock.patch(MODULE_PATH + '.tasks.XenForoManager') @mock.patch(MODULE_PATH + '.views.XenForoManager') diff --git a/allianceauth/services/modules/xenforo/urls.py b/allianceauth/services/modules/xenforo/urls.py index d63a3bce..123e7bfe 100644 --- a/allianceauth/services/modules/xenforo/urls.py +++ b/allianceauth/services/modules/xenforo/urls.py @@ -2,6 +2,8 @@ from django.conf.urls import url, include from . import views +app_name = 'xenforo' + module_urls = [ # XenForo service control url(r'^activate/$', views.activate_xenforo_forum, name='activate'), @@ -11,5 +13,5 @@ module_urls = [ ] urlpatterns = [ - url(r'^xenforo/', include(module_urls, namespace='xenforo')), + url(r'^xenforo/', include((module_urls, app_name), namespace=app_name)), ] diff --git a/allianceauth/services/urls.py b/allianceauth/services/urls.py index 1a341255..0503d292 100644 --- a/allianceauth/services/urls.py +++ b/allianceauth/services/urls.py @@ -5,11 +5,11 @@ from . import views urlpatterns = [ # Services - url(r'^services/', include([ + url(r'^services/', include(([ url(r'^$', views.services_view, name='services'), # Tools url(r'^tool/fleet_formatter_tool/$', views.fleet_formatter_view, name='fleet_format_tool'), - ], namespace='services')), + ], 'services'), namespace='services')), ] # Append hooked service urls diff --git a/allianceauth/settings/base.py b/allianceauth/settings/base.py index ae7729b5..1630d76a 100644 --- a/allianceauth/settings/base.py +++ b/allianceauth/settings/base.py @@ -27,7 +27,6 @@ INSTALLED_APPS = [ 'django.contrib.humanize', 'django_celery_beat', 'bootstrapform', - 'bootstrap_pagination', 'sortedm2m', 'esi', 'allianceauth', diff --git a/allianceauth/srp/migrations/0004_on_delete.py b/allianceauth/srp/migrations/0004_on_delete.py new file mode 100644 index 00000000..d4fd505a --- /dev/null +++ b/allianceauth/srp/migrations/0004_on_delete.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-09-28 02:16 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('srp', '0003_make_strings_more_stringy'), + ] + + operations = [ + migrations.AlterField( + model_name='srpfleetmain', + name='fleet_commander', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='eveonline.EveCharacter'), + ), + migrations.AlterField( + model_name='srpuserrequest', + name='character', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='eveonline.EveCharacter'), + ), + ] diff --git a/allianceauth/srp/models.py b/allianceauth/srp/models.py index 6effbef4..b3ebc7d9 100755 --- a/allianceauth/srp/models.py +++ b/allianceauth/srp/models.py @@ -10,7 +10,7 @@ class SrpFleetMain(models.Model): fleet_time = models.DateTimeField() fleet_srp_code = models.CharField(max_length=254, default="") fleet_srp_status = models.CharField(max_length=254, default="") - fleet_commander = models.ForeignKey(EveCharacter) + fleet_commander = models.ForeignKey(EveCharacter, null=True, on_delete=models.SET_NULL) fleet_srp_aar_link = models.CharField(max_length=254, default="") def __str__(self): @@ -40,8 +40,8 @@ class SrpUserRequest(models.Model): additional_info = models.CharField(max_length=254, default="") srp_status = models.CharField(max_length=8, default="Pending", choices=SRP_STATUS_CHOICES) srp_total_amount = models.BigIntegerField(default=0) - character = models.ForeignKey(EveCharacter) - srp_fleet_main = models.ForeignKey(SrpFleetMain) + character = models.ForeignKey(EveCharacter, null=True, on_delete=models.SET_NULL) + srp_fleet_main = models.ForeignKey(SrpFleetMain, on_delete=models.CASCADE) kb_total_loss = models.BigIntegerField(default=0) srp_ship_name = models.CharField(max_length=254, default="") post_time = models.DateTimeField(default=timezone.now) diff --git a/allianceauth/tests/auth_utils.py b/allianceauth/tests/auth_utils.py index 5ae1d6a9..cc27676a 100644 --- a/allianceauth/tests/auth_utils.py +++ b/allianceauth/tests/auth_utils.py @@ -142,7 +142,6 @@ class AuthUtils: class BaseViewTestCase(TestCase): def setUp(self): self.member = AuthUtils.create_member('auth_member') - self.member.set_password('password') self.member.email = 'auth_member@example.com' self.member.save() AuthUtils.add_main_character(self.member, 'auth_member', '12345', corp_id='111', corp_name='Test Corporation', @@ -150,4 +149,4 @@ class BaseViewTestCase(TestCase): def login(self): token = Token.objects.create(character_id='12345', character_name='auth_member', character_owner_hash='1', user=self.member, access_token='1') - self.client.login(token=token) \ No newline at end of file + self.client.login(token=token) diff --git a/allianceauth/thirdparty/navhelper/templatetags/navactive.py b/allianceauth/thirdparty/navhelper/templatetags/navactive.py index ebd7b83c..89abed90 100644 --- a/allianceauth/thirdparty/navhelper/templatetags/navactive.py +++ b/allianceauth/thirdparty/navhelper/templatetags/navactive.py @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ from django.template import Library -from django.core.urlresolvers import resolve +from django.urls import resolve from django.conf import settings import re diff --git a/allianceauth/timerboard/form.py b/allianceauth/timerboard/form.py index 261c11cf..44e4886f 100755 --- a/allianceauth/timerboard/form.py +++ b/allianceauth/timerboard/form.py @@ -1,9 +1,37 @@ +import logging +import datetime from django import forms +from django.utils import timezone from django.core.validators import MaxValueValidator, MinValueValidator from django.utils.translation import ugettext_lazy as _ +from .models import Timer + +logger = logging.getLogger(__name__) + + +class TimerForm(forms.ModelForm): + class Meta: + model = Timer + fields = ('details', 'system', 'planet_moon', 'structure', 'objective', 'important', 'corp_timer') + + def __init__(self, *args, **kwargs): + self.user = kwargs.pop('user', None) + if 'instance' in kwargs and kwargs['instance'] is not None: + # Do conversion from db datetime to days/hours/minutes + # for appropriate fields + current_time = timezone.now() + td = kwargs['instance'].eve_time - current_time + initial = kwargs.pop('initial', dict()) + if 'days_left' not in initial: + initial.update({'days_left': td.days}) + if 'hours_left' not in initial: + initial.update({'hours_left': td.seconds // 3600}) + if 'minutes_left' not in initial: + initial.update({'minutes_left': td.seconds // 60 % 60}) + kwargs.update({'initial': initial}) + super(TimerForm, self).__init__(*args, **kwargs) -class TimerForm(forms.Form): structure_choices = [('POCO', 'POCO'), ('I-HUB', 'I-HUB'), ('POS[S]', 'POS[S]'), ('POS[M]', 'POS[M]'), ('POS[L]', 'POS[L]'), ('Citadel[M]', 'Citadel[M]'), ('Citadel[L]', 'Citadel[L]'), ('Citadel[XL]', 'Citadel[XL]'), @@ -25,3 +53,27 @@ class TimerForm(forms.Form): validators=[MinValueValidator(0), MaxValueValidator(59)]) important = forms.BooleanField(label=_("Important"), required=False) corp_timer = forms.BooleanField(label=_("Corp-Restricted"), required=False) + + def save(self, commit=True): + timer = super(TimerForm, self).save(commit=False) + + # Get character + character = self.user.profile.main_character + corporation = character.corporation + logger.debug("Determined timer save request on behalf " + "of character {} corporation {}".format(character, corporation)) + # calculate future time + future_time = datetime.timedelta(days=self.cleaned_data['days_left'], hours=self.cleaned_data['hours_left'], + minutes=self.cleaned_data['minutes_left']) + current_time = timezone.now() + eve_time = current_time + future_time + logger.debug( + "Determined timer eve time is %s - current time %s, adding %s" % (eve_time, current_time, future_time)) + + timer.eve_time = eve_time + timer.eve_character = character + timer.eve_corp = corporation + timer.user = self.user + if commit: + timer.save() + return timer diff --git a/allianceauth/timerboard/migrations/0003_on_delete.py b/allianceauth/timerboard/migrations/0003_on_delete.py new file mode 100644 index 00000000..899f6dc0 --- /dev/null +++ b/allianceauth/timerboard/migrations/0003_on_delete.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.5 on 2017-09-28 02:16 +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 = [ + ('timerboard', '0002_make_strings_more_stringy'), + ] + + operations = [ + migrations.AlterField( + model_name='timer', + name='eve_character', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='eveonline.EveCharacter'), + ), + migrations.AlterField( + model_name='timer', + name='user', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL), + ), + ] diff --git a/allianceauth/timerboard/models.py b/allianceauth/timerboard/models.py index d1a10c0f..d5391583 100755 --- a/allianceauth/timerboard/models.py +++ b/allianceauth/timerboard/models.py @@ -16,10 +16,10 @@ class Timer(models.Model): objective = models.CharField(max_length=254, default="") eve_time = models.DateTimeField() important = models.BooleanField(default=False) - eve_character = models.ForeignKey(EveCharacter) - eve_corp = models.ForeignKey(EveCorporationInfo) + eve_character = models.ForeignKey(EveCharacter, null=True, on_delete=models.SET_NULL) + eve_corp = models.ForeignKey(EveCorporationInfo, on_delete=models.CASCADE) corp_timer = models.BooleanField(default=False) - user = models.ForeignKey(User) + user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL) def __str__(self): - return str(self.system) + ' ' + str(self.objective) + return str(self.system) + ' ' + str(self.details) diff --git a/allianceauth/timerboard/templates/timerboard/add.html b/allianceauth/timerboard/templates/timerboard/add.html deleted file mode 100644 index b0ce16ad..00000000 --- a/allianceauth/timerboard/templates/timerboard/add.html +++ /dev/null @@ -1,29 +0,0 @@ -{% extends "allianceauth/base.html" %} -{% load bootstrap %} -{% load staticfiles %} -{% load i18n %} -{% get_current_language as LANGUAGE_CODE %} - -{% block title %}{% trans "Alliance Auth - Structure Timer Create" %}{% endblock %} - -{% block page_title %}{% trans "Timer Create" %}{% endblock page_title %} - -{% block content %} -
    -

    {% trans "Create Structure Timer" %}

    - -
    -
    -
    - - {% csrf_token %} - {{ form|bootstrap }} -
    - - -
    -
    -
    -
    - -{% endblock content %} diff --git a/allianceauth/timerboard/templates/timerboard/form.html b/allianceauth/timerboard/templates/timerboard/form.html new file mode 100644 index 00000000..827c06ef --- /dev/null +++ b/allianceauth/timerboard/templates/timerboard/form.html @@ -0,0 +1,33 @@ +{% extends "allianceauth/base.html" %} +{% load bootstrap %} +{% load staticfiles %} +{% load i18n %} + +{% block page_title %} +{% endblock page_title %} + +{% block content %} +
    +

    + {% block page_header %} + {% endblock %} + {% include 'timerboard/index_button.html' %} +

    +
    +
    +
    + + {% csrf_token %} + {{ form|bootstrap }} +
    + + +
    +
    +
    +
    + +{% endblock content %} diff --git a/allianceauth/timerboard/templates/timerboard/index_button.html b/allianceauth/timerboard/templates/timerboard/index_button.html new file mode 100644 index 00000000..cf7e20bf --- /dev/null +++ b/allianceauth/timerboard/templates/timerboard/index_button.html @@ -0,0 +1,4 @@ +{% load i18n %} +
    + Back +
    diff --git a/allianceauth/timerboard/templates/timerboard/timer_confirm_delete.html b/allianceauth/timerboard/templates/timerboard/timer_confirm_delete.html new file mode 100644 index 00000000..63265ba8 --- /dev/null +++ b/allianceauth/timerboard/templates/timerboard/timer_confirm_delete.html @@ -0,0 +1,26 @@ +{% extends "allianceauth/base.html" %} +{% load i18n %} + +{% block page_title %} + Delete Timer +{% endblock page_title %} + +{% block content %} +
    +

    + {% trans "Delete Timer" %} + {% include 'timerboard/index_button.html' %} +

    +
    +
    +
    +
    + {% csrf_token %} +

    {% blocktrans %}Are you sure you want to delete timer "{{ object }}"?{% endblocktrans %}

    + + +
    +
    +
    +
    +{% endblock content %} diff --git a/allianceauth/timerboard/templates/timerboard/timer_create_form.html b/allianceauth/timerboard/templates/timerboard/timer_create_form.html new file mode 100644 index 00000000..750fab08 --- /dev/null +++ b/allianceauth/timerboard/templates/timerboard/timer_create_form.html @@ -0,0 +1,14 @@ +{% extends "timerboard/form.html" %} +{% load i18n %} + +{% block page_title %} + {% trans "Create Timer" %} +{% endblock page_title %} + +{% block page_header %} + {% trans "Create Structure Timer" %} +{% endblock %} + +{% block submit_button_text %} + {% trans "Create Timer" %} +{% endblock %} diff --git a/allianceauth/timerboard/templates/timerboard/timer_update_form.html b/allianceauth/timerboard/templates/timerboard/timer_update_form.html new file mode 100644 index 00000000..e54bcd7f --- /dev/null +++ b/allianceauth/timerboard/templates/timerboard/timer_update_form.html @@ -0,0 +1,14 @@ +{% extends "timerboard/form.html" %} +{% load i18n %} + +{% block page_title %} + {% trans "Update Structure Timer" %} +{% endblock page_title %} + +{% block page_header %} + {% trans "Update Structure Timer" %} +{% endblock %} + +{% block submit_button_text %} + {% trans "Update Structure Timer" %} +{% endblock %} diff --git a/allianceauth/timerboard/templates/timerboard/update.html b/allianceauth/timerboard/templates/timerboard/update.html deleted file mode 100644 index 1b4482c2..00000000 --- a/allianceauth/timerboard/templates/timerboard/update.html +++ /dev/null @@ -1,35 +0,0 @@ -{% extends "allianceauth/base.html" %} -{% load bootstrap %} -{% load staticfiles %} -{% load i18n %} - -{% block title %}Alliance Auth - Update Structure Timer {% endblock %} - -{% block page_title %}{% trans "Update AAR Link" %}{% endblock page_title %} - -{% block content %} - -
    -

    {% trans "Update Structure Timer" %}

    - -
    -
    -
    - {% if no_fleet_id %} - - {% else %} - - {% csrf_token %} - {{ form|bootstrap }} -
    - - - {% endif %} -
    -
    -
    - -
    - -{% endblock content %} diff --git a/allianceauth/timerboard/templates/timerboard/management.html b/allianceauth/timerboard/templates/timerboard/view.html similarity index 98% rename from allianceauth/timerboard/templates/timerboard/management.html rename to allianceauth/timerboard/templates/timerboard/view.html index a63cb810..b5ae816d 100644 --- a/allianceauth/timerboard/templates/timerboard/management.html +++ b/allianceauth/timerboard/templates/timerboard/view.html @@ -3,8 +3,6 @@ {% load i18n %} {% get_current_language as LANGUAGE_CODE %} -{% block title %}Alliance Auth{% endblock %} - {% block page_title %}{% trans "Structure Timer Management" %}{% endblock page_title %} {% block extra_css %}{% endblock extra_css %} @@ -145,7 +143,7 @@ {% if perms.auth.timer_management %} {% if perms.auth.timer_management %} {% if perms.auth.timer_management %}
    {% trans "User" %}{{ timer.eve_character.character_name }} - + @@ -279,7 +277,7 @@ {{ timer.eve_character.character_name }} - + @@ -415,7 +413,7 @@ {{ timer.eve_character.character_name }} - + diff --git a/allianceauth/timerboard/tests.py b/allianceauth/timerboard/tests.py old mode 100755 new mode 100644 index a39b155a..805e228b --- a/allianceauth/timerboard/tests.py +++ b/allianceauth/timerboard/tests.py @@ -1 +1,231 @@ -# Create your tests here. +from django_webtest import WebTest +from django.utils import timezone +from django.urls import reverse +from django.contrib.auth.models import Permission, User +from django.conf import settings + +from datetime import timedelta + +from allianceauth.tests.auth_utils import AuthUtils +from allianceauth.eveonline.models import EveCorporationInfo + +from .models import Timer +from .form import TimerForm + + +class TimerboardViewsTestCase(WebTest): + csrf_checks = False + + def setUp(self): + corp = EveCorporationInfo.objects.create(corporation_id='2345', corporation_name='test corp', + corporation_ticker='testc', member_count=24) + other_corp = EveCorporationInfo.objects.create(corporation_id='9345', corporation_name='other test corp', + corporation_ticker='testd', member_count=1) + self.user = AuthUtils.create_user('test_user') + AuthUtils.add_main_character(self.user, 'test character', '1234', '2345', 'test corp', 'testc') + self.user = User.objects.get_by_natural_key('test_user') + character = self.user.profile.main_character + self.other_user = AuthUtils.create_user('other_test_user') + AuthUtils.add_main_character(self.other_user, 'test character 2', '9234', '9345', 'other test corp', 'testd') + self.other_user = User.objects.get_by_natural_key('other_test_user') + other_character = self.other_user.profile.main_character + + self.timer = Timer.objects.create( + details='details', + system='system', + planet_moon='planet_moon', + structure='structure', + objective='objective', + eve_time=timezone.now() + timedelta(days=30), + important=True, + corp_timer=False, + eve_character=character, + eve_corp=character.corporation, + user=self.user, + ) + self.corp_timer = Timer.objects.create( + details='details', + system='system', + planet_moon='planet_moon', + structure='structure', + objective='objective', + eve_time=timezone.now() + timedelta(days=30), + important=False, + corp_timer=True, + eve_character=character, + eve_corp=character.corporation, + user=self.user, + ) + self.other_corp_timer = Timer.objects.create( + details='details', + system='system', + planet_moon='planet_moon', + structure='structure', + objective='objective', + eve_time=timezone.now() + timedelta(days=30), + important=False, + corp_timer=True, + eve_character=other_character, + eve_corp=other_character.corporation, + user=self.user, + ) + self.expired_timer = Timer.objects.create( + details='details', + system='system', + planet_moon='planet_moon', + structure='structure', + objective='objective', + eve_time=timezone.now() - timedelta(days=30), + important=True, + corp_timer=False, + eve_character=character, + eve_corp=character.corporation, + user=self.user, + ) + + self.view_permission = Permission.objects.get(codename='timer_view') + self.edit_permission = Permission.objects.get(codename='timer_management') + + self.view_url = reverse('timerboard:view') + self.add_url = reverse('timerboard:add') + self.edit_url_name = 'timerboard:edit' + self.delete_url_name = 'timerboard:delete' + + def test_timer_view(self): + self.user.user_permissions.add(self.view_permission) + + self.app.set_user(self.user) + + response = self.app.get(self.view_url) + + context = response.context[-1] + + timers = context['timers'] + corp_timers = context['corp_timers'] + future_timers = context['future_timers'] + past_timers = context['past_timers'] + + self.assertTemplateUsed(response, 'timerboard/view.html') + + self.assertIn(self.timer, timers) + self.assertIn(self.expired_timer, timers) + self.assertNotIn(self.corp_timer, timers) + self.assertNotIn(self.other_corp_timer, timers) + + self.assertNotIn(self.timer, corp_timers) + self.assertNotIn(self.expired_timer, corp_timers) + self.assertIn(self.corp_timer, corp_timers) + self.assertNotIn(self.other_corp_timer, corp_timers) + + self.assertIn(self.timer, future_timers) + self.assertNotIn(self.expired_timer, future_timers) + self.assertNotIn(self.corp_timer, future_timers) + self.assertNotIn(self.other_corp_timer, future_timers) + + self.assertNotIn(self.timer, past_timers) + self.assertIn(self.expired_timer, past_timers) + self.assertNotIn(self.corp_timer, past_timers) + self.assertNotIn(self.other_corp_timer, past_timers) + + def test_timer_view_permission(self): + self.client.force_login(self.user) + response = self.app.get(self.view_url) + self.assertRedirects(response, expected_url=reverse(settings.LOGIN_URL) + '?next=' + self.view_url) + + def test_timer_view_login(self): + response = self.app.get(self.view_url) + self.assertRedirects(response, expected_url=reverse(settings.LOGIN_URL) + '?next=' + self.view_url) + + def test_add_timer_get(self): + self.user.user_permissions.add(self.edit_permission) + self.app.set_user(self.user) + + response = self.app.get(self.add_url) + + self.assertTemplateUsed(response, 'timerboard/timer_create_form.html') + + context = response.context[-1] + + self.assertIs(TimerForm, type(context['form'])) + + def test_add_timer_form_error(self): + self.user.user_permissions.add(self.edit_permission) + self.app.set_user(self.user) + page = self.app.post(self.add_url) + page = page.forms['add-timer-form'].submit() + self.assertContains(page, "This field is required.") + + def test_add_timer_post(self): + self.user.user_permissions.add(self.edit_permission) + self.user.user_permissions.add(self.view_permission) + + self.app.set_user(self.user) + + page = self.app.post(self.add_url) + form = page.forms['add-timer-form'] + + form['details'] = 'details' + form['system'] = 'jita' + form['planet_moon'] = '4-4' + form['structure'] = TimerForm.structure_choices[0][0] + form['objective'] = TimerForm.objective_choices[0][0] + form['days_left'] = 1 + form['hours_left'] = 2 + form['minutes_left'] = 3 + form['important'] = True + form['corp_timer'] = False + + response = form.submit() + + self.assertRedirects(response, self.view_url) + + self.assertTrue(Timer.objects.filter(system='jita', details='details').exists()) + + def test_edit_timer_get(self): + self.user.user_permissions.add(self.edit_permission) + self.app.set_user(self.user) + + response = self.app.get(reverse(self.edit_url_name, args=[self.timer.id])) + context = response.context[-1] + form = context['form'] + data = form.instance + + self.assertTemplateUsed(response, 'timerboard/timer_update_form.html') + self.assertIs(TimerForm, type(form)) + self.assertEqual(data, self.timer) + + def test_edit_timer_post(self): + self.user.user_permissions.add(self.edit_permission) + self.user.user_permissions.add(self.view_permission) + + self.app.set_user(self.user) + + page = self.app.post(reverse(self.edit_url_name, args=[self.timer.id])) + form = page.forms['add-timer-form'] + + form['details'] = 'detailsUNIQUE' + form['system'] = 'jita' + form['planet_moon'] = '4-4' + form['structure'] = TimerForm.structure_choices[0][0] + form['objective'] = TimerForm.objective_choices[0][0] + form['days_left'] = 1 + form['hours_left'] = 2 + form['minutes_left'] = 3 + form['important'] = True + form['corp_timer'] = False + + response = form.submit() + + self.assertRedirects(response, self.view_url) + + self.assertTrue(Timer.objects.filter(system='jita', details='detailsUNIQUE').exists()) + + def test_delete_timer_get(self): + self.user.user_permissions.add(self.edit_permission) + self.app.set_user(self.user) + + response = self.app.get(reverse(self.delete_url_name, args=[self.timer.id])) + + self.assertTemplateUsed(response, 'timerboard/timer_confirm_delete.html') + + self.assertContains(response, 'Are you sure you want to delete timer "'+str(self.timer)) diff --git a/allianceauth/timerboard/urls.py b/allianceauth/timerboard/urls.py index 2a7ef7d6..d4102494 100644 --- a/allianceauth/timerboard/urls.py +++ b/allianceauth/timerboard/urls.py @@ -5,8 +5,8 @@ from . import views app_name = 'timerboard' urlpatterns = [ - url(r'^$', views.timer_view, name='view'), - url(r'^add/$', views.add_timer_view, name='add'), - url(r'^remove/(\w+)$', views.remove_timer, name='remove'), - url(r'^edit/(\w+)$', views.edit_timer, name='edit'), - ] + url(r'^$', views.TimerView.as_view(), name='view'), + url(r'^add/$', views.AddTimerView.as_view(), name='add'), + url(r'^remove/(?P\w+)$', views.RemoveTimerView.as_view(), name='delete'), + url(r'^edit/(?P\w+)$', views.EditTimerView.as_view(), name='edit'), +] diff --git a/allianceauth/timerboard/views.py b/allianceauth/timerboard/views.py index 0e3a06f2..b865978e 100755 --- a/allianceauth/timerboard/views.py +++ b/allianceauth/timerboard/views.py @@ -2,13 +2,14 @@ import datetime import logging from django.contrib import messages -from django.contrib.auth.decorators import login_required -from django.contrib.auth.decorators import permission_required from django.shortcuts import get_object_or_404 from django.shortcuts import render, redirect +from django.views import View +from django.urls import reverse_lazy +from django.views.generic import CreateView, UpdateView, DeleteView +from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin from django.utils import timezone from django.utils.translation import ugettext_lazy as _ -from allianceauth.eveonline.models import EveCorporationInfo from .form import TimerForm from .models import Timer @@ -16,136 +17,72 @@ from .models import Timer logger = logging.getLogger(__name__) -@login_required -@permission_required('auth.timer_view') -def timer_view(request): - logger.debug("timer_view called by user %s" % request.user) - char = request.user.profile.main_character - if char: - corp = EveCorporationInfo.objects.get(corporation_id=char.corporation_id) - else: - corp = None - if corp: - corp_timers = Timer.objects.all().filter(corp_timer=True).filter(eve_corp=corp) - else: - corp_timers = [] - render_items = {'timers': Timer.objects.all().filter(corp_timer=False), - 'corp_timers': corp_timers, - 'future_timers': Timer.objects.all().filter(corp_timer=False).filter( - eve_time__gte=datetime.datetime.now()), - 'past_timers': Timer.objects.all().filter(corp_timer=False).filter( - eve_time__lt=datetime.datetime.now())} - - return render(request, 'timerboard/management.html', context=render_items) +class BaseTimerView(LoginRequiredMixin, PermissionRequiredMixin, View): + pass -@login_required -@permission_required('auth.timer_management') -def add_timer_view(request): - logger.debug("add_timer_view called by user %s" % request.user) - if request.method == 'POST': - form = TimerForm(request.POST) - logger.debug("Request type POST contains form valid: %s" % form.is_valid()) - if form.is_valid(): - # Get character - character = request.user.profile.main_character - corporation = EveCorporationInfo.get_corporation_info_by_id(character.corporation_id) - logger.debug( - "Determined timer add request on behalf of character %s corporation %s" % (character, corporation)) - # calculate future time - future_time = datetime.timedelta(days=form.cleaned_data['days_left'], hours=form.cleaned_data['hours_left'], - minutes=form.cleaned_data['minutes_left']) - current_time = timezone.now() - eve_time = current_time + future_time - logger.debug( - "Determined timer eve time is %s - current time %s, adding %s" % (eve_time, current_time, future_time)) - # handle valid form - timer = Timer() - timer.details = form.cleaned_data['details'] - timer.system = form.cleaned_data['system'] - timer.planet_moon = form.cleaned_data['planet_moon'] - timer.structure = form.cleaned_data['structure'] - timer.objective = form.cleaned_data['objective'] - timer.eve_time = eve_time - timer.important = form.cleaned_data['important'] - timer.corp_timer = form.cleaned_data['corp_timer'] - timer.eve_character = character - timer.eve_corp = corporation - timer.user = request.user - timer.save() - logger.info("Created new timer in %s at %s by user %s" % (timer.system, timer.eve_time, request.user)) - messages.success(request, _('Added new timer in %(system)s at %(time)s.') % {"system": timer.system, "time": timer.eve_time}) - return redirect("timerboard:view") - else: - logger.debug("Returning new TimerForm") - form = TimerForm() +class TimerView(BaseTimerView): + template_name = 'timerboard/view.html' + permission_required = 'auth.timer_view' - render_items = {'form': form} + def get(self, request): + logger.debug("timer_view called by user {}".format(request.user)) + char = request.user.profile.main_character + if char: + corp = char.corporation + else: + corp = None - return render(request, 'timerboard/add.html', context=render_items) - - -@login_required -@permission_required('auth.timer_management') -def remove_timer(request, timer_id): - logger.debug("remove_timer called by user %s for timer id %s" % (request.user, timer_id)) - timer = get_object_or_404(Timer, id=timer_id) - timer.delete() - logger.debug("Deleting timer id %s by user %s" % (timer_id, request.user)) - messages.success(request, _('Deleted timer in %(system)s at %(time)s.') % {'system': timer.system, - 'time': timer.eve_time}) - return redirect("timerboard:view") - - -@login_required -@permission_required('auth.timer_management') -def edit_timer(request, timer_id): - logger.debug("edit_timer called by user %s for timer id %s" % (request.user, timer_id)) - timer = get_object_or_404(Timer, id=timer_id) - if request.method == 'POST': - form = TimerForm(request.POST) - logger.debug("Received POST request containing updated timer form, is valid: %s" % form.is_valid()) - if form.is_valid(): - character = request.user.profile.main_character - corporation = EveCorporationInfo.get_corporation_info_by_id(character.corporation_id) - logger.debug( - "Determined timer edit request on behalf of character %s corporation %s" % (character, corporation)) - # calculate future time - future_time = datetime.timedelta(days=form.cleaned_data['days_left'], hours=form.cleaned_data['hours_left'], - minutes=form.cleaned_data['minutes_left']) - current_time = datetime.datetime.utcnow() - eve_time = current_time + future_time - logger.debug( - "Determined timer eve time is %s - current time %s, adding %s" % (eve_time, current_time, future_time)) - timer.details = form.cleaned_data['details'] - timer.system = form.cleaned_data['system'] - timer.planet_moon = form.cleaned_data['planet_moon'] - timer.structure = form.cleaned_data['structure'] - timer.objective = form.cleaned_data['objective'] - timer.eve_time = eve_time - timer.important = form.cleaned_data['important'] - timer.corp_timer = form.cleaned_data['corp_timer'] - timer.eve_character = character - timer.eve_corp = corporation - logger.info("User %s updating timer id %s " % (request.user, timer_id)) - messages.success(request, _('Saved changes to the timer.')) - timer.save() - return redirect("timerboard:view") - else: - current_time = timezone.now() - td = timer.eve_time - current_time - tddays, tdhours, tdminutes = td.days, td.seconds // 3600, td.seconds // 60 % 60 - data = { - 'details': timer.details, - 'system': timer.system, - 'planet_moon': timer.planet_moon, - 'structure': timer.structure, - 'objective': timer.objective, - 'important': timer.important, - 'corp_timer': timer.corp_timer, - 'days_left': tddays, - 'hours_left': tdhours, - 'minutes_left': tdminutes, + render_items = { + 'timers': Timer.objects.filter(corp_timer=False), + 'corp_timers': Timer.objects.filter(corp_timer=True, eve_corp=corp), + 'future_timers': Timer.objects.filter(corp_timer=False, eve_time__gte=timezone.now()), + 'past_timers': Timer.objects.filter(corp_timer=False, eve_time__lt=timezone.now()), } - form = TimerForm(initial=data) - return render(request, 'timerboard/update.html', context={'form': form}) + + return render(request, self.template_name, context=render_items) + + +class TimerManagementView(BaseTimerView): + permission_required = 'auth.timer_management' + index_redirect = 'timerboard:view' + success_url = reverse_lazy(index_redirect) + model = Timer + form_class = TimerForm + + def get_timer(self, timer_id): + return get_object_or_404(self.model, id=timer_id) + + +class AddUpdateMixin: + def get_form_kwargs(self): + """ + Inject the request user into the kwargs passed to the form + """ + kwargs = super(AddUpdateMixin, self).get_form_kwargs() + kwargs.update({'user': self.request.user}) + return kwargs + + +class AddTimerView(TimerManagementView, AddUpdateMixin, CreateView): + template_name_suffix = '_create_form' + + def form_valid(self, form): + result = super(AddTimerView, self).form_valid(form) + timer = self.object + logger.info("Created new timer in {} at {} by user {}".format(timer.system, timer.eve_time, self.request.user)) + messages.success(self.request, _('Added new timer in %(system)s at %(time)s.') % {"system": timer.system, + "time": timer.eve_time}) + return result + + +class EditTimerView(TimerManagementView, AddUpdateMixin, UpdateView): + template_name_suffix = '_update_form' + + def form_valid(self, form): + messages.success(self.request, _('Saved changes to the timer.')) + return super(EditTimerView, self).form_valid(form) + + +class RemoveTimerView(TimerManagementView, DeleteView): + pass diff --git a/allianceauth/urls.py b/allianceauth/urls.py index 65046588..17219a56 100755 --- a/allianceauth/urls.py +++ b/allianceauth/urls.py @@ -23,15 +23,15 @@ urlpatterns = [ url(r'^i18n/', include('django.conf.urls.i18n')), # Authentication - url(r'', include(allianceauth.authentication.urls, namespace='authentication')), + url(r'', include(allianceauth.authentication.urls)), url(r'^account/login/$', TemplateView.as_view(template_name='public/login.html'), name='auth_login_user'), url(r'account/', include(hmac_urls)), # Admin urls - url(r'^admin/', include(admin.site.urls)), + url(r'^admin/', admin.site.urls), # SSO - url(r'^sso/', include(esi.urls, namespace='esi')), + url(r'^sso/', include((esi.urls, 'esi'), namespace='esi')), url(r'^sso/login$', allianceauth.authentication.views.sso_login, name='auth_sso_login'), # Notifications diff --git a/setup.py b/setup.py index b24804d9..a3409457 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,6 @@ install_requires = [ 'django>=1.11', 'django-bootstrap-form', - 'django-bootstrap-pagination', 'django-registration', 'django-sortedm2m', 'django-redis-cache>=1.7.1', @@ -33,6 +32,7 @@ testing_extras = [ 'coverage>=4.3.1', 'requests-mock>=1.2.0', 'django-nose', + 'django-webtest', ] setup( diff --git a/tox.ini b/tox.ini index 4c2b8b9c..51d1d1ab 100644 --- a/tox.ini +++ b/tox.ini @@ -14,5 +14,7 @@ basepython = deps= dj111: Django>=1.11.1,<2.0 dj20: Django>=2.0a1 + dj20: https://github.com/celery/django-celery-beat/zipball/master#egg=django-celery-beat + dj20: https://github.com/Adarnof/adarnauth-esi/zipball/master#egg=adarnauth-esi install_command = pip install -e ".[testing]" -U {opts} {packages} commands=coverage run runtests.py -v 2