diff --git a/backend/api/management/commands/dev_setup.py b/backend/api/management/commands/dev_setup.py index a1d0c13..eb04a01 100644 --- a/backend/api/management/commands/dev_setup.py +++ b/backend/api/management/commands/dev_setup.py @@ -20,11 +20,11 @@ def handle(self, *args, **options): User.objects.all().delete() print('Creating Users') - user1 = User.objects.create_superuser(username='devuser', password='password') - user2 = User.objects.create_superuser(username='devuser2', password='password') + user1 = User.objects.create_superuser(username='devuser', password='password', first_name='Dev User 1') + user2 = User.objects.create_superuser(username='devuser2', password='password', first_name='Dev User 2') print('Creating Characters') - char1 = models.Character.objects.create( + models.Character.objects.create( avatar_url='https://placehold.co/96/2E53A5/F3F3EC.png?text=1', lodestone_id='1', name='Character 1', @@ -68,16 +68,16 @@ def handle(self, *args, **options): has_weapon=True, ) raid_gear = models.Gear.objects.get( - item_level=tier.max_item_level-5, + item_level=tier.max_item_level - 5, name=tier.raid_gear_name, has_weapon=False, ) tome_gear = models.Gear.objects.get( - item_level=tier.max_item_level-5, + item_level=tier.max_item_level - 5, name=tier.tome_gear_name, ) crafted_gear = models.Gear.objects.get( - item_level=tier.max_item_level-25, + item_level=tier.max_item_level - 25, has_weapon=True, has_armour=True, has_accessories=True, diff --git a/backend/api/tests/test_lodestone_gear_import.py b/backend/api/tests/test_lodestone_gear_import.py index b428244..6d6a374 100644 --- a/backend/api/tests/test_lodestone_gear_import.py +++ b/backend/api/tests/test_lodestone_gear_import.py @@ -26,9 +26,60 @@ def tearDown(self): def test_import(self): """ Test Plan; - - Import Eira and ensure her gear matches what I currently had equipped + - Create Gear entries for some ARR items + - Import Niseras and ensure her gear matches what I currently had equipped """ - url = reverse('api:lodestone_gear_import', kwargs={'character_id': '22909725', 'expected_job': 'GNB'}) + ironworks = Gear.objects.create( + name='Augmented Ironworks', + item_level=130, + has_armour=True, + has_accessories=True, + has_weapon=True, + ).pk + koga = Gear.objects.create( + name='Koga', + item_level=90, + has_armour=True, + has_accessories=False, + has_weapon=False, + ).pk + azeyma = Gear.objects.create( + name="Azeyma's", + item_level=560, + has_armour=False, + has_accessories=True, + has_weapon=False, + ).pk + brass = Gear.objects.create( + name='Aetherial Brass', + item_level=16, + has_armour=False, + has_accessories=True, + has_weapon=False, + ).pk + dawn = Gear.objects.create( + name='Dawn', + item_level=18, + has_armour=False, + has_accessories=True, + has_weapon=False, + ).pk + new = Gear.objects.create( + name='Brand New', + item_level=30, + has_armour=False, + has_accessories=True, + has_weapon=False, + ).pk + weathered = Gear.objects.create( + name='Weathered', + item_level=5, + has_armour=False, + has_accessories=True, + has_weapon=False, + ).pk + + url = reverse('api:lodestone_gear_import', kwargs={'character_id': '42935425', 'expected_job': 'NIN'}) user = self._get_user() self.client.force_authenticate(user) response = self.client.get(url) @@ -36,21 +87,21 @@ def test_import(self): # Build an expected data packet expected = { - 'job_id': 'GNB', - 'mainhand': Gear.objects.get(name='Archeo Kingdom').pk, - 'offhand': Gear.objects.get(name='Archeo Kingdom').pk, - 'head': Gear.objects.get(name='Dark Horse Champion', has_armour=True).pk, - 'body': Gear.objects.get(name='Augmented Quetzalli', has_armour=True).pk, - 'hands': Gear.objects.get(name='Quetzalli', has_armour=True).pk, - 'legs': Gear.objects.get(name='Dark Horse Champion', has_armour=True).pk, - 'feet': Gear.objects.get(name='Augmented Quetzalli', has_armour=True).pk, - 'earrings': Gear.objects.get(name='Dark Horse Champion', has_accessories=True).pk, - 'necklace': Gear.objects.get(name='Dark Horse Champion', has_accessories=True).pk, - 'bracelet': Gear.objects.get(name='Augmented Quetzalli', has_accessories=True).pk, - 'right_ring': Gear.objects.get(name='Augmented Quetzalli', has_accessories=True).pk, - 'left_ring': Gear.objects.get(name='Dark Horse Champion', has_accessories=True).pk, - 'min_il': 710, - 'max_il': 730, + 'job_id': 'NIN', + 'mainhand': ironworks, + 'offhand': ironworks, + 'head': koga, + 'body': ironworks, + 'hands': koga, + 'legs': ironworks, + 'feet': koga, + 'earrings': azeyma, + 'necklace': brass, + 'bracelet': dawn, + 'right_ring': new, + 'left_ring': weathered, + 'min_il': 5, + 'max_il': 560, } self.maxDiff = None self.assertDictEqual(response.json(), expected) @@ -130,10 +181,9 @@ def test_import_400_and_404(self): self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) # Job ID doesn't match gear - url = reverse('api:lodestone_gear_import', kwargs={'character_id': '22909725', 'expected_job': 'SAM'}) + url = reverse('api:lodestone_gear_import', kwargs={'character_id': '22909725', 'expected_job': 'MNK'}) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_406_NOT_ACCEPTABLE) - self.assertEqual( - response.json()['message'], - 'Couldn\'t import Gear from Lodestone. Gear was expected to be for "SAM", but "GNB" was found.', + self.assertTrue( + 'Couldn\'t import Gear from Lodestone. Gear was expected to be for "MNK"' in response.json()['message'], ) diff --git a/backend/requirements.txt b/backend/requirements.txt index 0661d27..ad65600 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -24,7 +24,7 @@ cryptography==43.0.3 daphne==3.0.2 defusedxml==0.7.1 Deprecated==1.2.13 -Django==4.2.16 +Django==4.2.17 django-allauth==0.47.0 django-auto-prefetch==1.9.0 djangorestframework==3.15.2 @@ -37,7 +37,7 @@ incremental==24.7.2 inflection==0.5.1 itypes==1.2.0 jellyfish==0.9.0 -Jinja2==3.1.4 +Jinja2==3.1.5 jsonschema==4.17.3 kombu==5.2.3 MarkupSafe==2.1.1 diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a68ba2d..a3685bd 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -17,6 +17,7 @@ "match-sorter": "^6.3.1", "microtip": "^0.2.2", "multi-range-slider-vue": "^1.1.4", + "nanoid": "^3.3.8", "nouislider": "^15.7.0", "vue": "^2.6.11", "vue-class-component": "^7.2.3", @@ -3169,9 +3170,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001566", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001566.tgz", - "integrity": "sha512-ggIhCsTxmITBAMmK8yZjEhCO5/47jKXPu6Dha/wuCS4JePVL+3uiDEBuhu2aIoT+bqTOR8L76Ip1ARL9xYsEJA==", + "version": "1.0.30001690", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", + "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", "dev": true, "funding": [ { @@ -9913,9 +9914,9 @@ "dev": true }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", "funding": [ { "type": "github", diff --git a/frontend/package.json b/frontend/package.json index 427e36b..a120527 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -17,6 +17,7 @@ "match-sorter": "^6.3.1", "microtip": "^0.2.2", "multi-range-slider-vue": "^1.1.4", + "nanoid": "^3.3.8", "nouislider": "^15.7.0", "vue": "^2.6.11", "vue-class-component": "^7.2.3", diff --git a/frontend/src/components/loot/greed_character_entry.vue b/frontend/src/components/loot/greed_character_entry.vue index fcd000c..33ce695 100644 --- a/frontend/src/components/loot/greed_character_entry.vue +++ b/frontend/src/components/loot/greed_character_entry.vue @@ -47,10 +47,10 @@ export default class GreedCharacterEntry extends Vue { @Prop() userHasPermission!: boolean - save(list: GreedItem): void { + save(list: GreedItem | null): void { // A main level function to determine how we save. The modal type can no longer make the determination for us // Some items cannot be saved with an update, even if they are displayed using the raid modal - if (this.item.indexOf('tome') !== -1 || this.item === 'mount') { + if (this.item.indexOf('tome') !== -1 || this.item === 'mount' || list == null) { // We cannot run an update but we do want to save them this.saveWithoutUpdate() } diff --git a/frontend/src/components/loot/greed_raid_modal.vue b/frontend/src/components/loot/greed_raid_modal.vue index e29ad40..4612636 100644 --- a/frontend/src/components/loot/greed_raid_modal.vue +++ b/frontend/src/components/loot/greed_raid_modal.vue @@ -31,6 +31,8 @@ +
Worked out some edgecase issues with the Loot Solver. If you run into any weirdness with your Team's Loot Solver, please let me know!
- -Ever wanted to try running SavageAim locally and messing around with it? Well the README in the GitHub repo just got a whole lot more helpful, and there's now even a command to setup your local database automatically!
++ Made it so that when people have Greed BIS Lists, you can still generically assign items to them without updating one of their BIS Lists if the item is not relevant. +