aa-fitting-mastery 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. aa_fitting_mastery-0.1.0.dist-info/METADATA +304 -0
  2. aa_fitting_mastery-0.1.0.dist-info/RECORD +80 -0
  3. aa_fitting_mastery-0.1.0.dist-info/WHEEL +4 -0
  4. aa_fitting_mastery-0.1.0.dist-info/licenses/LICENSE +21 -0
  5. mastery/__init__.py +7 -0
  6. mastery/app_settings.py +8 -0
  7. mastery/apps.py +7 -0
  8. mastery/auth_hooks.py +29 -0
  9. mastery/management/commands/__init__.py +0 -0
  10. mastery/management/commands/import_sde_masteries.py +69 -0
  11. mastery/migrations/0001_initial.py +133 -0
  12. mastery/migrations/0002_doctrineskillsetgroupmap_default_mastery_level_and_more.py +23 -0
  13. mastery/migrations/0003_make_fitting_mastery_override_nullable.py +25 -0
  14. mastery/migrations/0004_fittingskillcontrol_recommended_level_override.py +20 -0
  15. mastery/migrations/0005_fittingskillsetmap_last_synced_at.py +17 -0
  16. mastery/migrations/0006_fittingskillcontrol_is_manual.py +17 -0
  17. mastery/migrations/0007_general.py +26 -0
  18. mastery/migrations/0008_summary_audience_groups.py +56 -0
  19. mastery/migrations/__init__.py +0 -0
  20. mastery/models/__init__.py +11 -0
  21. mastery/models/certificate_skill.py +20 -0
  22. mastery/models/doctrine_skill_snapshot.py +68 -0
  23. mastery/models/doctrine_skillsetgroup_map.py +29 -0
  24. mastery/models/fitting_skill_control.py +58 -0
  25. mastery/models/fitting_skill_override.py +27 -0
  26. mastery/models/fitting_skillset_map.py +47 -0
  27. mastery/models/general.py +20 -0
  28. mastery/models/sde_version.py +11 -0
  29. mastery/models/ship_mastery.py +11 -0
  30. mastery/models/ship_mastery_certificate.py +16 -0
  31. mastery/models/summary_group.py +51 -0
  32. mastery/services/__init__.py +0 -0
  33. mastery/services/doctrine/__init__.py +1 -0
  34. mastery/services/doctrine/doctrine_map_service.py +47 -0
  35. mastery/services/doctrine/doctrine_skill_service.py +164 -0
  36. mastery/services/fittings/__init__.py +2 -0
  37. mastery/services/fittings/fitting_map_service.py +33 -0
  38. mastery/services/fittings/skill_extractor.py +135 -0
  39. mastery/services/pilots/__init__.py +5 -0
  40. mastery/services/pilots/pilot_access_service.py +58 -0
  41. mastery/services/pilots/pilot_progress_service.py +1025 -0
  42. mastery/services/sde/__init__.py +3 -0
  43. mastery/services/sde/importer.py +105 -0
  44. mastery/services/sde/mastery_service.py +47 -0
  45. mastery/services/sde/version_service.py +37 -0
  46. mastery/services/skills/__init__.py +3 -0
  47. mastery/services/skills/skill_control_service.py +114 -0
  48. mastery/services/skills/skillcheck_service.py +58 -0
  49. mastery/services/skills/suggestion_service.py +165 -0
  50. mastery/tasks.py +29 -0
  51. mastery/templates/mastery/base.html +48 -0
  52. mastery/templates/mastery/doctrine_detail.html +172 -0
  53. mastery/templates/mastery/doctrine_list.html +116 -0
  54. mastery/templates/mastery/fitting_skills.html +315 -0
  55. mastery/templates/mastery/index.html +313 -0
  56. mastery/templates/mastery/partials/ajax_messages.html +7 -0
  57. mastery/templates/mastery/partials/fitting_skill_preview.html +101 -0
  58. mastery/templates/mastery/partials/fitting_skills_editor.html +356 -0
  59. mastery/templates/mastery/pilot_fitting_detail.html +747 -0
  60. mastery/templates/mastery/summary_doctrine_detail.html +92 -0
  61. mastery/templates/mastery/summary_fitting_detail.html +199 -0
  62. mastery/templates/mastery/summary_list_view.html +126 -0
  63. mastery/templates/mastery/summary_settings.html +200 -0
  64. mastery/templatetags/__init__.py +0 -0
  65. mastery/templatetags/skill_render.py +63 -0
  66. mastery/tests/__init__.py +0 -0
  67. mastery/tests/test_auth_hooks.py +27 -0
  68. mastery/tests/test_pilot_progress_service.py +167 -0
  69. mastery/tests/test_services.py +616 -0
  70. mastery/tests/test_tasks.py +55 -0
  71. mastery/tests/test_views.py +1334 -0
  72. mastery/urls.py +67 -0
  73. mastery/views/__init__.py +72 -0
  74. mastery/views/common.py +569 -0
  75. mastery/views/deps.py +34 -0
  76. mastery/views/doctrine.py +150 -0
  77. mastery/views/fitting.py +499 -0
  78. mastery/views/pilot.py +319 -0
  79. mastery/views/summary.py +277 -0
  80. mastery/views/summary_helpers.py +526 -0
@@ -0,0 +1,304 @@
1
+ Metadata-Version: 2.4
2
+ Name: aa-fitting-mastery
3
+ Version: 0.1.0
4
+ Summary: Fitting Mastery and Skill Plan generator.
5
+ Author-email: Jay <jays.gaming.contact@gmail.com>
6
+ Requires-Python: >=3.8
7
+ Description-Content-Type: text/markdown
8
+ Classifier: Environment :: Web Environment
9
+ Classifier: Framework :: Django
10
+ Classifier: Framework :: Django :: 4.0
11
+ Classifier: Framework :: Django :: 4.2
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Internet :: WWW/HTTP
22
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
23
+ License-File: LICENSE
24
+ Requires-Dist: aa-memberaudit>=4.3.1
25
+ Requires-Dist: fittings>=2.3.0
26
+ Requires-Dist: allianceauth-app-utils>=1.18
27
+ Requires-Dist: allianceauth>=4,<5
28
+ Requires-Dist: django-esi>=8.3.1
29
+ Requires-Dist: django-eveonline-sde>=0.0.1b2
30
+ Project-URL: Changelog, https://github.com/hermesdj/aa-fitting-mastery/-/blob/master/CHANGELOG.md
31
+ Project-URL: Homepage, https://github.com/hermesdj/aa-fitting-mastery
32
+ Project-URL: Source, https://github.com/hermesdj/aa-fitting-mastery
33
+ Project-URL: Tracker, https://github.com/hermesdj/aa-fitting-mastery/-/issues
34
+
35
+ # Fitting Mastery Plugin for Alliance Auth
36
+
37
+ `aa-fitting-mastery` is an [Alliance Auth](https://allianceauth.readthedocs.io/) plugin that turns doctrine fittings into actionable skill plans.
38
+
39
+ It connects your configured doctrines and fittings from the `fittings` plugin with character and skill data from `aa-memberaudit`, then provides:
40
+
41
+ - pilot readiness views for accessible doctrine fittings,
42
+ - missing required and recommended skills,
43
+ - exportable in-game skill plans,
44
+ - configurable required and recommended skill plans per fitting,
45
+ - leadership summary views for doctrine coverage.
46
+
47
+ [![release](https://img.shields.io/pypi/v/aa-fitting-mastery?label=release)](https://pypi.org/project/aa-fitting-mastery/)
48
+ [![python](https://img.shields.io/pypi/pyversions/aa-fitting-mastery)](https://pypi.org/project/aa-fitting-mastery/)
49
+ [![django](https://img.shields.io/pypi/djversions/aa-fitting-mastery?label=django)](https://pypi.org/project/aa-fitting-mastery/)
50
+ [![license](https://img.shields.io/badge/license-MIT-green)](LICENSE)
51
+ [![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit)
52
+ [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
53
+
54
+ ## Contents
55
+
56
+ - [Overview](#overview)
57
+ - [Requirements](#requirements)
58
+ - [Main features](#main-features)
59
+ - [Screenshots](#screenshots)
60
+ - [Installation](#installation)
61
+ - [Updating](#updating)
62
+ - [Configuration](#configuration)
63
+ - [Permissions](#permissions)
64
+ - [How it works](#how-it-works)
65
+ - [Settings](#settings)
66
+
67
+ ## Overview
68
+
69
+ Fitting Mastery is designed for organizations that already manage doctrine ships in `fittings` and track character skills in `aa-memberaudit`.
70
+
71
+ The plugin adds two complementary workflows:
72
+
73
+ 1. **Pilot workflow**
74
+ - members can see which of their characters can fly a doctrine fitting,
75
+ - inspect missing required / recommended skills,
76
+ - export missing skills in a format suitable for EVE skill plan import.
77
+
78
+ 2. **Leadership workflow**
79
+ - doctrine managers can configure fitting skill plans,
80
+ - review suggestions to blacklist or restore skills,
81
+ - define summary groups across corporations and alliances,
82
+ - view doctrine coverage for a selected audience.
83
+
84
+ Access to doctrines and fittings follows the visibility rules from the `fittings` plugin so that category restrictions are respected consistently.
85
+
86
+ ## Requirements
87
+
88
+ This plugin depends on the following components:
89
+
90
+ - `fittings` — required
91
+ - `aa-memberaudit` — required
92
+ - `django-eveonline-sde` / `eve_sde` — required for ship mastery and dogma data
93
+ - Alliance Auth 4.x
94
+
95
+ > **Important**
96
+ > This plugin does **not** replace `fittings` or `aa-memberaudit`.
97
+ > It builds on top of both. You need both plugins installed and working before enabling `mastery`.
98
+
99
+ ## Main features
100
+
101
+ - Generate fitting skill plans from doctrine ships and their modules
102
+ - Merge **required** fitting skills with **recommended** ship mastery skills
103
+ - Add manual skills, blacklist skills, or override recommended levels per fitting
104
+ - Detect and suggest skills that can be removed from a plan
105
+ - Export missing skills in dependency-safe order for in-game EVE import
106
+ - Support multiple export languages for skill names
107
+ - Show member-facing doctrine readiness based on accessible fittings only
108
+ - Show leadership doctrine coverage across configurable corp/alliance audience groups
109
+ - Keep fitting access aligned with the access rules configured in the `fittings` plugin
110
+
111
+ ## Screenshots
112
+
113
+ ### Character progress
114
+
115
+ ![Character progress](https://raw.githubusercontent.com/hermesdj/aa-fitting-mastery/main/docs/view-character-progress.png)
116
+
117
+ ### Fitting skill plan management
118
+
119
+ ![Fitting skill plans](https://raw.githubusercontent.com/hermesdj/aa-fitting-mastery/main/docs/edit-fitting-skill-plans.png)
120
+
121
+ ## Installation
122
+
123
+ ### 1 - Install prerequisites
124
+
125
+ Make sure your Alliance Auth installation already has these apps installed and configured:
126
+
127
+ - `fittings`
128
+ - `memberaudit`
129
+ - `eve_sde`
130
+
131
+ ### 2 - Install the package
132
+
133
+ Install the plugin into your Alliance Auth virtual environment:
134
+
135
+ ```bash
136
+ pip install aa-fitting-mastery
137
+ ```
138
+
139
+ ### 3 - Add the app to Alliance Auth
140
+
141
+ Add `mastery` to `INSTALLED_APPS` in your `local.py`:
142
+
143
+ ```python
144
+ INSTALLED_APPS += [
145
+ "mastery",
146
+ ]
147
+ ```
148
+
149
+ ### 4 - Configure the scheduled SDE mastery update task
150
+
151
+ Add the periodic task to your `CELERYBEAT_SCHEDULE` (every day at midnight):
152
+
153
+ ```python
154
+ from celery.schedules import crontab
155
+
156
+ CELERYBEAT_SCHEDULE["update_sde_masteries"] = {
157
+ "task": "mastery.tasks.update_sde_masteries",
158
+ "schedule": crontab(minute="0", hour="0"),
159
+ }
160
+ ```
161
+
162
+ ### 5 - Run migrations and collect static files
163
+
164
+ ```bash
165
+ python manage.py migrate
166
+ python manage.py collectstatic
167
+ ```
168
+
169
+ ### 6 - Import mastery data
170
+
171
+ Import ship mastery and certificate data from the EVE SDE:
172
+
173
+ ```bash
174
+ python manage.py import_sde_masteries
175
+ ```
176
+
177
+ For a test run without writing to the database:
178
+
179
+ ```bash
180
+ python manage.py import_sde_masteries --dry-run
181
+ ```
182
+
183
+ ### 7 - Restart your services
184
+
185
+ Restart your web and Celery services so the plugin and beat task are loaded.
186
+
187
+ ## Updating
188
+
189
+ To update an existing installation:
190
+
191
+ ```bash
192
+ pip install -U aa-fitting-mastery
193
+ python manage.py migrate
194
+ python manage.py collectstatic
195
+ ```
196
+
197
+ Then restart your web and Celery services.
198
+
199
+ ## Configuration
200
+
201
+ After installation, the usual setup flow is:
202
+
203
+ 1. **Ensure your doctrines and fittings already exist in the `fittings` plugin**
204
+ 2. Open **Manage Skill Plans** in Fitting Mastery
205
+ 3. Generate or sync doctrine skill plans
206
+ 4. Review each fitting and adjust:
207
+ - mastery level,
208
+ - manual skills,
209
+ - blacklisted skills,
210
+ - recommended level overrides,
211
+ - skill suggestions
212
+ 5. If you want doctrine leadership views, create audience groups in **Summary Group Settings**
213
+ 6. Assign the appropriate permissions to members, doctrine managers and leadership roles
214
+
215
+ ### Access model
216
+
217
+ For pilot-facing views, Fitting Mastery uses the same fittings visibility rules as the `fittings` plugin.
218
+
219
+ That means:
220
+
221
+ - users must have access to `fittings` itself,
222
+ - category restrictions remain effective,
223
+ - doctrines and fittings that are hidden in `fittings` will not be exposed by Fitting Mastery.
224
+
225
+ ## Permissions
226
+
227
+ The plugin defines the following permissions:
228
+
229
+ | Code | Description |
230
+ | --- | --- |
231
+ | `basic_access` | Can access the pilot-facing Fitting Mastery pages |
232
+ | `manage_fittings` | Can manage doctrine/fitting skill plans |
233
+ | `doctrine_summary` | Can view leadership doctrine summary pages |
234
+ | `manage_summary_groups` | Can create and manage summary audience groups |
235
+
236
+ ### Recommended usage
237
+
238
+ - **Members**: `basic_access`
239
+ - **Doctrine / fitting managers**: `basic_access`, `manage_fittings`
240
+ - **Leadership / FC / HR reviewers**: `basic_access`, `doctrine_summary`
241
+ - **Admins managing summary scopes**: `manage_summary_groups`
242
+
243
+ In practice, pilot-facing access is usually granted together with fitting visibility from the `fittings` plugin.
244
+
245
+ You will typically also want matching access in the `fittings` plugin, especially `fittings.access_fittings` or `fittings.manage`.
246
+
247
+ ## How it works
248
+
249
+ At a high level the plugin works like this:
250
+
251
+ 1. It reads the ship and module requirements from fitting dogma data
252
+ 2. It reads ship mastery recommendations from imported SDE mastery data
253
+ 3. It combines both into a per-fitting skill plan
254
+ 4. It lets managers refine that plan with blacklists, manual additions and level overrides
255
+ 5. It compares those plans against character skills from `aa-memberaudit`
256
+ 6. It presents the result in pilot and leadership views
257
+
258
+ ### Required vs Recommended
259
+
260
+ - **Required** skills come from fitting / module requirements and their recursive prerequisites
261
+ - **Recommended** skills come from ship mastery data, plus any manual adjustments you configure
262
+
263
+ ### Summary groups
264
+
265
+ Doctrine summary views can be scoped to configurable audience groups.
266
+
267
+ Each summary group can combine:
268
+
269
+ - corporations,
270
+ - alliances,
271
+ - mixed corporation/alliance audiences.
272
+
273
+ This makes it possible to review doctrine coverage for a coalition, SIG, alliance wing or any other relevant operational scope.
274
+
275
+ ### Exported skill plans
276
+
277
+ When exporting missing skills for a pilot, the plugin:
278
+
279
+ - includes all missing intermediate levels,
280
+ - adds missing prerequisites recursively,
281
+ - orders skills so prerequisites appear first,
282
+ - supports multiple languages for skill labels.
283
+
284
+ ## Settings
285
+
286
+ The following setting can be added to your Alliance Auth `local.py`:
287
+
288
+ | Name | Description | Default |
289
+ | --- | --- | --- |
290
+ | `MASTERY_PLAN_ESTIMATE_SP_PER_HOUR` | Training speed used to estimate plan duration in fitting previews | `1800` |
291
+
292
+ Example:
293
+
294
+ ```python
295
+ MASTERY_PLAN_ESTIMATE_SP_PER_HOUR = 1800
296
+ ```
297
+
298
+ ## Notes
299
+
300
+ - If you change doctrine skill plan configuration, regenerate or sync the affected doctrine/fitting so changes are reflected in the active skill set.
301
+ - If leadership summaries are enabled, remember to configure at least one summary audience group.
302
+ - If no mastery data has been imported yet, recommended ship skills will be incomplete until `import_sde_masteries` has been run.
303
+ - Fitting Mastery respects fitting visibility from the `fittings` plugin and will not intentionally expose restricted doctrines or fittings outside that access model.
304
+
@@ -0,0 +1,80 @@
1
+ mastery/__init__.py,sha256=zoqT0a5XHAA49Ejh87JnO4zuDvKp6z6jAqfKnMwRPaA,208
2
+ mastery/app_settings.py,sha256=efQlmIlVIXHXChICmwDl71mKr8Q5WREVPZjq24T06CA,272
3
+ mastery/apps.py,sha256=eWzHG0Eyb3lIpvcstAXZkyvgO-g3wXjQ2azpl2nhV9U,155
4
+ mastery/auth_hooks.py,sha256=cs_uYeDHYzEwjqZOfRMZGYZz9SIvd9QjhU9l4Vs1TfE,723
5
+ mastery/tasks.py,sha256=AmzcqPUvNwQ4XmSyti5xox1lbrPvG2cWQA0VRi4vG6U,1041
6
+ mastery/urls.py,sha256=WXNmUZ0f529aR9-UJI4YisnBv8NEO-NIYf8pDO_gNuQ,2973
7
+ mastery/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ mastery/management/commands/import_sde_masteries.py,sha256=5cnpspLhXagnypJeGfAZZYskq1FX8e8-cNVQioWVSec,2267
9
+ mastery/migrations/0001_initial.py,sha256=TjWdErcIuHX7m8QZPwxNnigbUKYVZsSF65yXi_VFj8g,7727
10
+ mastery/migrations/0002_doctrineskillsetgroupmap_default_mastery_level_and_more.py,sha256=f0g6ZFFYN2iGgiyLnI9_XyN-0Cq8YC4VSXY0bLz9oPw,659
11
+ mastery/migrations/0003_make_fitting_mastery_override_nullable.py,sha256=8pat3ZSgWUjCvlHle42PLfk7nLTIBSZqhgm9OLpRTJc,794
12
+ mastery/migrations/0004_fittingskillcontrol_recommended_level_override.py,sha256=j8P3VjkBJje9q4BCPAznObB5kyRzC8ZzMsOQZSuh5pE,513
13
+ mastery/migrations/0005_fittingskillsetmap_last_synced_at.py,sha256=7L0dpxfl0giFH5EG5HoQo6DmZWbfGtuGbXL_shJ_Ej0,427
14
+ mastery/migrations/0006_fittingskillcontrol_is_manual.py,sha256=2ZX5fJg0E3s7UxPnDcuDNETX1XVDJk1SBu-AY4ctawo,396
15
+ mastery/migrations/0007_general.py,sha256=uQAP8fWM3GWl1sFuCYaVVfc3UyC_dsTuABB7t2gHNBg,685
16
+ mastery/migrations/0008_summary_audience_groups.py,sha256=cJLPcEpHwOIwRVcAPHRRFmgemPmAIYBsO7v0voKdOB4,2375
17
+ mastery/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ mastery/models/__init__.py,sha256=iAp0RCWO3yEzIbeQp8tO_bXcoq_kPI-J2mamkHiNGLI,372
19
+ mastery/models/certificate_skill.py,sha256=iuMnXcM2UMP3QtLC0_Jpf53dY77ott6srtu0BI1wMhU,744
20
+ mastery/models/doctrine_skill_snapshot.py,sha256=8GdjltTYeK66PrscvgPSM4WjXTDIvoYfF_tLFcdDGgg,1728
21
+ mastery/models/doctrine_skillsetgroup_map.py,sha256=hVVcNXUSMmT9oYIlAV6LzEJW5_uoSdd2bm1pd0c9Bjk,824
22
+ mastery/models/fitting_skill_control.py,sha256=HRxzxCTHZijbWH2J88k3IccDJZmiNUxw4iFHDAIf8cQ,1446
23
+ mastery/models/fitting_skill_override.py,sha256=_kl3Owce3-e_nKmSLjlRQf9ROUdswqhWv1mfKdvBEHc,766
24
+ mastery/models/fitting_skillset_map.py,sha256=qahUrh0F0CeTcwmOxmhG6XENgQ8Cv2YsKLuB3T8o-x4,1186
25
+ mastery/models/general.py,sha256=GaCZjR-ZYy5IBTQaJQuLJGlfXetDBmm2Rdqz0s5TjNo,681
26
+ mastery/models/sde_version.py,sha256=osK4dD_qHNucKhSDN-Jagan8k3kjhKARkPUZqBdNzc8,327
27
+ mastery/models/ship_mastery.py,sha256=qwTXkJhVzrkoeUBw-M4x7DiTgD6HDMALKd5QXGMnba4,312
28
+ mastery/models/ship_mastery_certificate.py,sha256=8nrnMO6BbWUmxe5Pqx1CPZXWxdMFoDIlwA-9KNOeNtw,478
29
+ mastery/models/summary_group.py,sha256=5Fr8T9UOEEHnbADn0d467PBgs6G47HQ-6rQz336fjEk,1702
30
+ mastery/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
+ mastery/services/doctrine/__init__.py,sha256=42XnJ10t_7RS_a5SPYS7VJGdOyPFrshRTHXaxulxG7k,36
32
+ mastery/services/doctrine/doctrine_map_service.py,sha256=AtJBurZJSR74_jtXxy-kAbrmFfJACLJVCKYL0pFRRXg,1658
33
+ mastery/services/doctrine/doctrine_skill_service.py,sha256=cjLk-HWO0qy10ZoLMy2WCSTE-O1G1qKCXShFFV1pcbI,7114
34
+ mastery/services/fittings/__init__.py,sha256=MjN6sOywL_infwb2_6tuPgCky5U6azWaRzJ3epW6Z0s,65
35
+ mastery/services/fittings/fitting_map_service.py,sha256=uSPO1HQhEzxuJh6-6TGIK1_Fx1NW0pWSWlBC8QUi2bE,1109
36
+ mastery/services/fittings/skill_extractor.py,sha256=bNlbt8p7D-QMoVY1DWJ-IwROhqrQHplwEW-ktp_2-B8,4355
37
+ mastery/services/pilots/__init__.py,sha256=Z81y83hee4RxB9qyQD2lVYZA9bX37NvjYdfJyZH3_eY,169
38
+ mastery/services/pilots/pilot_access_service.py,sha256=FdbVFSzWkl9onZbixfxnsEOwRd2fuzV-B4pVZp79s0c,2322
39
+ mastery/services/pilots/pilot_progress_service.py,sha256=SQ0ARoOxiI1D75Y2hB2HRzjYuQQEByQ8g_3G9eXgE1I,42169
40
+ mastery/services/sde/__init__.py,sha256=aBKB0gE6lnU6m3D6w0bGmBQ9u6q_ZGr7rw51P-ytAY0,85
41
+ mastery/services/sde/importer.py,sha256=MO6asR41SMpqy_bRjHcze5vw19ACa1NtFOpLD9NrHCs,3830
42
+ mastery/services/sde/mastery_service.py,sha256=IZ0j-S2pnj-Kmm50p-EkvUXSkFDnH6ONy3yvtd8hJMY,1388
43
+ mastery/services/sde/version_service.py,sha256=gUpqwhNgx1WV3YKAUpjV63_TGxKxJF2pCc_PLFc6rMg,1187
44
+ mastery/services/skills/__init__.py,sha256=If6nCdT4B3qG-yYx1_OBUSAJ8f8xYgHRQMypwoDC8DQ,104
45
+ mastery/services/skills/skill_control_service.py,sha256=quKIO0qnucDeIJxBt39J651zs-vMn1A-92htGccHvOU,4397
46
+ mastery/services/skills/skillcheck_service.py,sha256=kYux3_holCDqCYmtoGy5Si65ubmGFGH9hrZXOmq166A,1848
47
+ mastery/services/skills/suggestion_service.py,sha256=sVdKzBX-g43H97qU5aagJwjI0cPAkUhxB4mChhRNqfI,5221
48
+ mastery/templates/mastery/base.html,sha256=vKK4VawAzknAFtcgLCtR6ZRVbObCvqkXylrBskcuSOg,1530
49
+ mastery/templates/mastery/doctrine_detail.html,sha256=dFzMOHAeVK07KwYQYYK-qw8m8AcESXqboTBS2g3JENM,8664
50
+ mastery/templates/mastery/doctrine_list.html,sha256=XyfrV6a2zqlWVJ8Ea8XRAffwKA71onizS___KUseh78,5474
51
+ mastery/templates/mastery/fitting_skills.html,sha256=7WGX7whtD5UeZfH7jYcjHky9dKRGpYz362bvyPJzAWs,9438
52
+ mastery/templates/mastery/index.html,sha256=ZVpjyEuoh30dOgDktUMP-jGsvScrCMkiYvmoNug1roU,14969
53
+ mastery/templates/mastery/pilot_fitting_detail.html,sha256=SsaodqvhM-cPDm8xoBEZXjw4qtfAtVbL6SpKK9eX6Dk,42810
54
+ mastery/templates/mastery/summary_doctrine_detail.html,sha256=Gp5bFiNnsbFu45S4OVQXQBZA_coEG8dx40iH9QFtbyk,5827
55
+ mastery/templates/mastery/summary_fitting_detail.html,sha256=YsqxIUF238XLLK2Xx9z_MzPlVYFhlLGmHUfpHtw1tMI,12821
56
+ mastery/templates/mastery/summary_list_view.html,sha256=JP3koYysmiiAw0PdNm7IIT2BrJH-1nS9tAJYmG7xIps,6934
57
+ mastery/templates/mastery/summary_settings.html,sha256=D-Tm7NPjbQEEeNcNl8hemshTSdSi02jf4Ptl4yRx8Xg,10392
58
+ mastery/templates/mastery/partials/ajax_messages.html,sha256=hQUl2VDCnjeHQ88s3a8fxoEhnX6Myjgstin1q8Eaz1Y,291
59
+ mastery/templates/mastery/partials/fitting_skill_preview.html,sha256=S4-xA8ZV48JVi_FRPcs_flyDHhYhsJFD_XCTNgZpXiQ,4171
60
+ mastery/templates/mastery/partials/fitting_skills_editor.html,sha256=YHJrxIv1uhfOErLqiS2Hv2iFneJh3kd6TJHMJZhCV14,21766
61
+ mastery/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
+ mastery/templatetags/skill_render.py,sha256=zw2uWmwyg_DmIgbSsK0jFyFcZAreLkSph9SoMZIqd94,1809
63
+ mastery/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
+ mastery/tests/test_auth_hooks.py,sha256=mLzlV0rWW17mseOLY-TsoQwUJa4BQLlATsYMXEnTEI0,777
65
+ mastery/tests/test_pilot_progress_service.py,sha256=Msmo8uOV_L8kn3u8q1vDH_8ObZefUmLWzTvwYjzClrg,6535
66
+ mastery/tests/test_services.py,sha256=M6DUvGf7i_d87rPiCg4EpHTYh5spytEsasqyEEBmPcw,27692
67
+ mastery/tests/test_tasks.py,sha256=bsB_BgbnsWB2sqts3Fdx3KrrUVsNNxtr4-Owz68MOE4,2444
68
+ mastery/tests/test_views.py,sha256=yvKjAfzCW1Pq-08YyOsTJK98V73cwzaRJpABHqgNS4w,56487
69
+ mastery/views/__init__.py,sha256=YDZVj0sXxtmkhG4iSwQfoxVJAJfuWR4X-CFGYAH9ejM,1932
70
+ mastery/views/common.py,sha256=1YOytDT6OQ3NPeOcRflLK1qUCnYIZV77wojeoSOpojc,19696
71
+ mastery/views/deps.py,sha256=9wfa7tUSSqjCAnEwaKTkfM7AEYaMBCdNyUyLV6u78Ls,1390
72
+ mastery/views/doctrine.py,sha256=_-EzmEH_VXdMUzGczyn7XWzm-QsHj2nzJUUpdYRnh3A,5554
73
+ mastery/views/fitting.py,sha256=9eSGu5AhFrkVb4T_aYjPEYSYKaI2zXo-e4gKkXnf5tQ,17414
74
+ mastery/views/pilot.py,sha256=I5A_WEeFGdfAmGlZSAwU8BIekSAoubwpHrgRt15F3iI,12982
75
+ mastery/views/summary.py,sha256=ae0dkzvHgdsVsAR8n_-Bliso2_ANkLdpUdtSRxo5CHM,11470
76
+ mastery/views/summary_helpers.py,sha256=LsI-hvVa5V_EB-yP2dYjabOMF4O-t_AugK5WdwObcvs,18684
77
+ aa_fitting_mastery-0.1.0.dist-info/licenses/LICENSE,sha256=kM9zGC-yCxQyVxHjoM3Pu_Yb8mSa1fa-Kx0ZgL13CKY,1062
78
+ aa_fitting_mastery-0.1.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
79
+ aa_fitting_mastery-0.1.0.dist-info/METADATA,sha256=lNFH3wGfnpG1KQE1BiB12kGxGaMXwFNvoi8gpV43raY,10786
80
+ aa_fitting_mastery-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: flit 3.12.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jay's
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
mastery/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ """Fitting Mastery and Skill Plan generator."""
2
+
3
+ default_app_config = "mastery.apps.MasteryConfig" # pylint: disable=invalid-name
4
+
5
+ __appname__ = "mastery"
6
+ __version__ = "0.1.0"
7
+ __title__ = "Fitting Mastery"
@@ -0,0 +1,8 @@
1
+ """Settings for Fitting Mastery."""
2
+
3
+ from app_utils.app_settings import clean_setting
4
+
5
+ MASTERY_PLAN_ESTIMATE_SP_PER_HOUR = clean_setting(
6
+ "MASTERY_PLAN_ESTIMATE_SP_PER_HOUR", 1800, min_value=1
7
+ )
8
+ """Training speed used to estimate plan duration in fitting previews."""
mastery/apps.py ADDED
@@ -0,0 +1,7 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class MasteryConfig(AppConfig):
5
+ name = "mastery"
6
+ label = "mastery"
7
+ verbose_name = "Fitting Mastery Plugin"
mastery/auth_hooks.py ADDED
@@ -0,0 +1,29 @@
1
+ from allianceauth import hooks
2
+ from allianceauth.services.hooks import UrlHook, MenuItemHook
3
+
4
+ from . import urls
5
+
6
+ class MasteryMenu(MenuItemHook):
7
+ def __init__(self):
8
+ MenuItemHook.__init__(
9
+ self,
10
+ "Skill Planner",
11
+ "fas fa-chart-bar",
12
+ "mastery:pilot_index",
13
+ navactive=["mastery:"],
14
+ )
15
+
16
+ def render(self, request):
17
+ if request.user.has_perm("mastery.basic_access"):
18
+ return MenuItemHook.render(self, request)
19
+ return ""
20
+
21
+
22
+ @hooks.register("menu_item_hook")
23
+ def register_menu():
24
+ return MasteryMenu()
25
+
26
+
27
+ @hooks.register("url_hook")
28
+ def register_urls():
29
+ return UrlHook(urls, "fitting-mastery", r"^fitting-mastery/")
File without changes
@@ -0,0 +1,69 @@
1
+ """Management command to import SDE masteries and certificates."""
2
+
3
+ import time
4
+
5
+ from django.core.management import BaseCommand
6
+
7
+ from mastery.services.sde.importer import SdeMasteryImporter
8
+ from mastery.services.sde.version_service import SdeVersionService
9
+
10
+
11
+ class Command(BaseCommand):
12
+ """Import SDE mastery data into local mastery models."""
13
+
14
+ def add_arguments(self, parser):
15
+ parser.add_argument(
16
+ "--force",
17
+ action="store_true",
18
+ help="Force import even if SDE version is up to date",
19
+ )
20
+ parser.add_argument(
21
+ "--dry-run",
22
+ action="store_true",
23
+ help="Perform a dry run without making any changes",
24
+ )
25
+
26
+ def handle(self, *args, **options):
27
+ start = time.time()
28
+ version_service = SdeVersionService()
29
+
30
+ latest = version_service.fetch_latest()
31
+ current = version_service.get_current()
32
+
33
+ if current:
34
+ self.stdout.write(f"Current SDE version: {current.build_number}")
35
+ else:
36
+ self.stdout.write("No SDE imported yet")
37
+
38
+ self.stdout.write(f"Latest SDE version: {latest['build_number']}")
39
+
40
+ if (
41
+ current
42
+ and current.build_number == latest["build_number"]
43
+ and not options["force"]
44
+ ):
45
+ self.stdout.write(self.style.SUCCESS("SDE is up to date, skipping import"))
46
+ return
47
+
48
+ dry_run = options["dry_run"]
49
+
50
+ if dry_run:
51
+ self.stdout.write(self.style.WARNING("Running in DRY-RUN mode"))
52
+
53
+ # IMPORT
54
+ importer = SdeMasteryImporter()
55
+ zip_file = importer.download()
56
+
57
+ masteries = importer.extract_yaml(zip_file, "masteries.yaml")
58
+ self.stdout.write(f"Masteries loaded: {len(masteries)} ships")
59
+
60
+ certificates = importer.extract_yaml(zip_file, "certificates.yaml")
61
+ self.stdout.write(f"Certificates loaded: {len(certificates)} entries")
62
+
63
+ if dry_run:
64
+ self.stdout.write(self.style.WARNING("Dry-run: skipping DB import"))
65
+ return
66
+
67
+ importer.exec_import(latest, masteries, certificates, dry_run=dry_run)
68
+
69
+ self.stdout.write(self.style.SUCCESS(f"SDE import complete, done in {time.time() - start:.2f}s"))