indy-hub 0.1.1__tar.gz

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 (73) hide show
  1. indy_hub-0.1.1/LICENSE +21 -0
  2. indy_hub-0.1.1/PKG-INFO +122 -0
  3. indy_hub-0.1.1/README.md +88 -0
  4. indy_hub-0.1.1/indy_hub/__init__.py +5 -0
  5. indy_hub-0.1.1/indy_hub/admin.py +173 -0
  6. indy_hub-0.1.1/indy_hub/apps.py +94 -0
  7. indy_hub-0.1.1/indy_hub/auth_hooks.py +69 -0
  8. indy_hub-0.1.1/indy_hub/decorators.py +79 -0
  9. indy_hub-0.1.1/indy_hub/esi_helpers.py +141 -0
  10. indy_hub-0.1.1/indy_hub/management/__init__.py +0 -0
  11. indy_hub-0.1.1/indy_hub/management/commands/__init__.py +0 -0
  12. indy_hub-0.1.1/indy_hub/management/commands/cache_esi_data.py +145 -0
  13. indy_hub-0.1.1/indy_hub/management/commands/esi_status.py +82 -0
  14. indy_hub-0.1.1/indy_hub/migrations/0001_initial.py +170 -0
  15. indy_hub-0.1.1/indy_hub/migrations/0002_blueprint_character_name_industryjob_character_name.py +24 -0
  16. indy_hub-0.1.1/indy_hub/migrations/0003_characterupdatetracker_last_refresh_request.py +19 -0
  17. indy_hub-0.1.1/indy_hub/migrations/0004_alter_characterupdatetracker_options_and_more.py +28 -0
  18. indy_hub-0.1.1/indy_hub/migrations/0006_blueprint_copy_share_and_request.py +80 -0
  19. indy_hub-0.1.1/indy_hub/migrations/0007_alter_blueprintcopyrequest_id_and_more.py +28 -0
  20. indy_hub-0.1.1/indy_hub/migrations/0008_add_copies_requested.py +17 -0
  21. indy_hub-0.1.1/indy_hub/migrations/0009_blueprintcopyoffer.py +60 -0
  22. indy_hub-0.1.1/indy_hub/migrations/0010_add_delivered_to_copyrequest.py +22 -0
  23. indy_hub-0.1.1/indy_hub/migrations/0011_alter_blueprintcopyoffer_id.py +21 -0
  24. indy_hub-0.1.1/indy_hub/migrations/0012_industryjob_job_completed_notified.py +19 -0
  25. indy_hub-0.1.1/indy_hub/migrations/0013_characterupdatetracker_jobs_notify_completed.py +19 -0
  26. indy_hub-0.1.1/indy_hub/migrations/0014_alter_blueprint_options_and_more.py +43 -0
  27. indy_hub-0.1.1/indy_hub/migrations/__init__.py +0 -0
  28. indy_hub-0.1.1/indy_hub/models.py +385 -0
  29. indy_hub-0.1.1/indy_hub/notifications.py +44 -0
  30. indy_hub-0.1.1/indy_hub/schedules.py +37 -0
  31. indy_hub-0.1.1/indy_hub/signals.py +115 -0
  32. indy_hub-0.1.1/indy_hub/static/indy_hub/css/blueprints.css +304 -0
  33. indy_hub-0.1.1/indy_hub/static/indy_hub/css/craft_bp.css +70 -0
  34. indy_hub-0.1.1/indy_hub/static/indy_hub/css/index.css +47 -0
  35. indy_hub-0.1.1/indy_hub/static/indy_hub/css/jobs.css +560 -0
  36. indy_hub-0.1.1/indy_hub/static/indy_hub/css/page_headers.css +48 -0
  37. indy_hub-0.1.1/indy_hub/static/indy_hub/css/token_management.css +66 -0
  38. indy_hub-0.1.1/indy_hub/static/indy_hub/js/blueprints.js +413 -0
  39. indy_hub-0.1.1/indy_hub/static/indy_hub/js/craft_bp.js +290 -0
  40. indy_hub-0.1.1/indy_hub/static/indy_hub/js/index.js +61 -0
  41. indy_hub-0.1.1/indy_hub/static/indy_hub/js/jobs.js +392 -0
  42. indy_hub-0.1.1/indy_hub/static/indy_hub/js/personal_bp_list.js +25 -0
  43. indy_hub-0.1.1/indy_hub/static/indy_hub/js/personal_job_list.js +44 -0
  44. indy_hub-0.1.1/indy_hub/static/indy_hub/js/token_management.js +28 -0
  45. indy_hub-0.1.1/indy_hub/tasks/__init__.py +43 -0
  46. indy_hub-0.1.1/indy_hub/tasks/industry.py +432 -0
  47. indy_hub-0.1.1/indy_hub/tasks/user.py +161 -0
  48. indy_hub-0.1.1/indy_hub/tasks.py +37 -0
  49. indy_hub-0.1.1/indy_hub/tasks_new.py +0 -0
  50. indy_hub-0.1.1/indy_hub/templates/indy_hub/All_BP_list.html +152 -0
  51. indy_hub-0.1.1/indy_hub/templates/indy_hub/Craft_BP.html +242 -0
  52. indy_hub-0.1.1/indy_hub/templates/indy_hub/Personnal_BP_list.html +324 -0
  53. indy_hub-0.1.1/indy_hub/templates/indy_hub/Personnal_Job_list.html +187 -0
  54. indy_hub-0.1.1/indy_hub/templates/indy_hub/blueprint_list.html +0 -0
  55. indy_hub-0.1.1/indy_hub/templates/indy_hub/bp_copy_fulfill_requests.html +100 -0
  56. indy_hub-0.1.1/indy_hub/templates/indy_hub/bp_copy_my_requests.html +90 -0
  57. indy_hub-0.1.1/indy_hub/templates/indy_hub/bp_copy_request_page.html +142 -0
  58. indy_hub-0.1.1/indy_hub/templates/indy_hub/index.html +291 -0
  59. indy_hub-0.1.1/indy_hub/templates/indy_hub/material_tree.html +31 -0
  60. indy_hub-0.1.1/indy_hub/templates/indy_hub/token_management.html +218 -0
  61. indy_hub-0.1.1/indy_hub/templatetags/__init__.py +0 -0
  62. indy_hub-0.1.1/indy_hub/templatetags/dict_get.py +12 -0
  63. indy_hub-0.1.1/indy_hub/urls.py +95 -0
  64. indy_hub-0.1.1/indy_hub/utils/__init__.py +3 -0
  65. indy_hub-0.1.1/indy_hub/utils/industry.py +89 -0
  66. indy_hub-0.1.1/indy_hub/utils/user.py +84 -0
  67. indy_hub-0.1.1/indy_hub/utils.py +0 -0
  68. indy_hub-0.1.1/indy_hub/views/__init__.py +3 -0
  69. indy_hub-0.1.1/indy_hub/views/api.py +119 -0
  70. indy_hub-0.1.1/indy_hub/views/industry.py +1070 -0
  71. indy_hub-0.1.1/indy_hub/views/user.py +441 -0
  72. indy_hub-0.1.1/indy_hub/views.py +0 -0
  73. indy_hub-0.1.1/pyproject.toml +65 -0
indy_hub-0.1.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 erka Ekanon
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.
@@ -0,0 +1,122 @@
1
+ Metadata-Version: 2.4
2
+ Name: indy-hub
3
+ Version: 0.1.1
4
+ Summary: Indy Hub Plugin for Alliance Auth
5
+ Keywords: allianceauth,eveonline,hub,industry,indy
6
+ Author-email: erka Ekanon <erkaekanon@outlook.com>
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Classifier: Environment :: Web Environment
10
+ Classifier: Framework :: Celery
11
+ Classifier: Framework :: Django
12
+ Classifier: Framework :: Django :: 4.0
13
+ Classifier: Framework :: Django :: 4.2
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Programming Language :: Python :: Implementation :: CPython
24
+ Classifier: Topic :: Internet :: WWW/HTTP
25
+ Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
26
+ License-File: LICENSE
27
+ Requires-Dist: aa-discordnotify>=2
28
+ Requires-Dist: allianceauth>=4,<5
29
+ Requires-Dist: django-eveuniverse>=1.5.7
30
+ Project-URL: Home, https://github.com/Erkaek/aa-Indy_Hub
31
+ Project-URL: Source, https://github.com/Erkaek/aa-Indy_Hub
32
+ Project-URL: Tracker, https://github.com/Erkaek/aa-Indy_Hub/issues
33
+
34
+ # Indy Hub for Alliance Auth
35
+
36
+ A modern industry management module for [Alliance Auth](https://allianceauth.org/), focused on blueprint and job tracking for EVE Online alliances and corporations.
37
+
38
+ ______________________________________________________________________
39
+
40
+ ## ✨ Features (Current)
41
+
42
+ - **Blueprint Library**: View, filter, and search all your EVE Online blueprints by character, type, and efficiency.
43
+ - **Industry Job Tracking**: Monitor and filter your manufacturing, research, and invention jobs in real time.
44
+ - **Blueprint Copy Sharing**: Request, offer, and deliver blueprint copies (BPCs) within your alliance, with notifications for each step.
45
+ - **ESI Integration**: Secure OAuth2-based sync for blueprints and jobs, with periodic background updates (Celery required).
46
+ - **Notifications**: In-app alerts for job completions, copy offers, and deliveries. Optional Discord notifications (via aa-discordnotify).
47
+ - **Modern UI**: Responsive Bootstrap 5 interface, theme-compatible, with accessibility and i18n support.
48
+
49
+ ______________________________________________________________________
50
+
51
+ ## 🚧 In Development
52
+
53
+ - **Alliance-wide Blueprint Library**: Browse all blueprints available in the alliance (admin-controlled visibility).
54
+ - **Advanced Copy Request Fulfillment**: Streamlined workflows for fulfilling and tracking copy requests.
55
+ - **Improved Job Analytics**: More detailed job statistics, filtering, and export options.
56
+ - **Better Admin Tools**: Enhanced dashboards and management commands for admins.
57
+
58
+ ______________________________________________________________________
59
+
60
+ ## 🛣️ Planned / Coming Soon
61
+
62
+ - **Blueprint Lending/Loan System**: Track and manage temporary blueprint loans between members.
63
+ - **Production Cost Estimation**: Integrated cost calculators and market price lookups.
64
+ - **More ESI Scopes**: Support for additional ESI endpoints (e.g., assets, wallet, reactions).
65
+ - **API/Export**: Public API endpoints and improved CSV/Excel export for all lists.
66
+ - **More Notifications**: Customizable notification rules and Discord webhooks.
67
+
68
+ ______________________________________________________________________
69
+
70
+ ## Requirements
71
+
72
+ - Alliance Auth v4+
73
+ - Python 3.10+
74
+ - Django (as required by AA)
75
+ - django-eveuniverse (populated with industry data)
76
+ - Celery (for background sync)
77
+ - (Optional) aa-discordnotify for Discord alerts
78
+
79
+ ______________________________________________________________________
80
+
81
+ ## Quick Install
82
+
83
+ 1. `pip install django-eveuniverse` and `pip install indy_hub`
84
+
85
+ 1. Add `eveuniverse` and `indy_hub` to `INSTALLED_APPS` in your AA settings.
86
+
87
+ 1. Add to your local.py:
88
+
89
+ - EVEUNIVERSE_LOAD_TYPE_MATERIALS = True
90
+ - EVEUNIVERSE_LOAD_MARKET_GROUPS = True
91
+ - EVEUNIVERSE_LOAD_TYPE_MATERIALS = True
92
+
93
+ 1. Run migrations: `python manage.py migrate`
94
+
95
+ 1. Collect static files: `python manage.py collectstatic`
96
+
97
+ 1. Restart your auth.
98
+
99
+ 1. Populate EveUniverse with industry data `python manage.py eveuniverse_load_data types --types-enabled-sections industry_activities type_materials`.
100
+
101
+ 1. Assign the `can access indy_hub` permission to users/groups.
102
+
103
+ ______________________________________________________________________
104
+
105
+ ## Usage
106
+
107
+ - Go to the Indy Hub dashboard in Alliance Auth.
108
+ - Authorize ESI for blueprints and jobs.
109
+ - View/manage your blueprints and jobs, request/offer BPCs, and receive notifications.
110
+
111
+ ______________________________________________________________________
112
+
113
+ ## Support & Contributing
114
+
115
+ - Open an issue or pull request on GitHub for help or to contribute.
116
+
117
+ ______________________________________________________________________
118
+
119
+ ## License
120
+
121
+ MIT License. See [LICENSE](LICENSE) for details.
122
+
@@ -0,0 +1,88 @@
1
+ # Indy Hub for Alliance Auth
2
+
3
+ A modern industry management module for [Alliance Auth](https://allianceauth.org/), focused on blueprint and job tracking for EVE Online alliances and corporations.
4
+
5
+ ______________________________________________________________________
6
+
7
+ ## ✨ Features (Current)
8
+
9
+ - **Blueprint Library**: View, filter, and search all your EVE Online blueprints by character, type, and efficiency.
10
+ - **Industry Job Tracking**: Monitor and filter your manufacturing, research, and invention jobs in real time.
11
+ - **Blueprint Copy Sharing**: Request, offer, and deliver blueprint copies (BPCs) within your alliance, with notifications for each step.
12
+ - **ESI Integration**: Secure OAuth2-based sync for blueprints and jobs, with periodic background updates (Celery required).
13
+ - **Notifications**: In-app alerts for job completions, copy offers, and deliveries. Optional Discord notifications (via aa-discordnotify).
14
+ - **Modern UI**: Responsive Bootstrap 5 interface, theme-compatible, with accessibility and i18n support.
15
+
16
+ ______________________________________________________________________
17
+
18
+ ## 🚧 In Development
19
+
20
+ - **Alliance-wide Blueprint Library**: Browse all blueprints available in the alliance (admin-controlled visibility).
21
+ - **Advanced Copy Request Fulfillment**: Streamlined workflows for fulfilling and tracking copy requests.
22
+ - **Improved Job Analytics**: More detailed job statistics, filtering, and export options.
23
+ - **Better Admin Tools**: Enhanced dashboards and management commands for admins.
24
+
25
+ ______________________________________________________________________
26
+
27
+ ## 🛣️ Planned / Coming Soon
28
+
29
+ - **Blueprint Lending/Loan System**: Track and manage temporary blueprint loans between members.
30
+ - **Production Cost Estimation**: Integrated cost calculators and market price lookups.
31
+ - **More ESI Scopes**: Support for additional ESI endpoints (e.g., assets, wallet, reactions).
32
+ - **API/Export**: Public API endpoints and improved CSV/Excel export for all lists.
33
+ - **More Notifications**: Customizable notification rules and Discord webhooks.
34
+
35
+ ______________________________________________________________________
36
+
37
+ ## Requirements
38
+
39
+ - Alliance Auth v4+
40
+ - Python 3.10+
41
+ - Django (as required by AA)
42
+ - django-eveuniverse (populated with industry data)
43
+ - Celery (for background sync)
44
+ - (Optional) aa-discordnotify for Discord alerts
45
+
46
+ ______________________________________________________________________
47
+
48
+ ## Quick Install
49
+
50
+ 1. `pip install django-eveuniverse` and `pip install indy_hub`
51
+
52
+ 1. Add `eveuniverse` and `indy_hub` to `INSTALLED_APPS` in your AA settings.
53
+
54
+ 1. Add to your local.py:
55
+
56
+ - EVEUNIVERSE_LOAD_TYPE_MATERIALS = True
57
+ - EVEUNIVERSE_LOAD_MARKET_GROUPS = True
58
+ - EVEUNIVERSE_LOAD_TYPE_MATERIALS = True
59
+
60
+ 1. Run migrations: `python manage.py migrate`
61
+
62
+ 1. Collect static files: `python manage.py collectstatic`
63
+
64
+ 1. Restart your auth.
65
+
66
+ 1. Populate EveUniverse with industry data `python manage.py eveuniverse_load_data types --types-enabled-sections industry_activities type_materials`.
67
+
68
+ 1. Assign the `can access indy_hub` permission to users/groups.
69
+
70
+ ______________________________________________________________________
71
+
72
+ ## Usage
73
+
74
+ - Go to the Indy Hub dashboard in Alliance Auth.
75
+ - Authorize ESI for blueprints and jobs.
76
+ - View/manage your blueprints and jobs, request/offer BPCs, and receive notifications.
77
+
78
+ ______________________________________________________________________
79
+
80
+ ## Support & Contributing
81
+
82
+ - Open an issue or pull request on GitHub for help or to contribute.
83
+
84
+ ______________________________________________________________________
85
+
86
+ ## License
87
+
88
+ MIT License. See [LICENSE](LICENSE) for details.
@@ -0,0 +1,5 @@
1
+ """
2
+ Indy Hub - An industrial management application for Alliance Auth
3
+ """
4
+
5
+ __version__ = "0.1.1"
@@ -0,0 +1,173 @@
1
+ """
2
+ Django admin configuration for indy_hub models
3
+ """
4
+
5
+ # Django
6
+ from django.contrib import admin
7
+
8
+ from .models import Blueprint, CharacterUpdateTracker, IndustryJob
9
+
10
+
11
+ @admin.register(Blueprint)
12
+ class BlueprintAdmin(admin.ModelAdmin):
13
+ list_display = [
14
+ "type_name",
15
+ "owner_user",
16
+ "character_id",
17
+ "quantity",
18
+ "material_efficiency",
19
+ "time_efficiency",
20
+ "runs",
21
+ "last_updated",
22
+ ]
23
+ list_filter = ["owner_user", "character_id", "quantity", "last_updated"]
24
+ search_fields = ["type_name", "type_id", "owner_user__username"]
25
+ readonly_fields = ["item_id", "last_updated", "created_at"]
26
+
27
+ fieldsets = (
28
+ (
29
+ "Basic Information",
30
+ {
31
+ "fields": (
32
+ "owner_user",
33
+ "character_id",
34
+ "item_id",
35
+ "type_id",
36
+ "type_name",
37
+ )
38
+ },
39
+ ),
40
+ ("Location", {"fields": ("location_id", "location_flag")}),
41
+ (
42
+ "Blueprint Details",
43
+ {"fields": ("quantity", "material_efficiency", "time_efficiency", "runs")},
44
+ ),
45
+ (
46
+ "Timestamps",
47
+ {"fields": ("created_at", "last_updated"), "classes": ("collapse",)},
48
+ ),
49
+ )
50
+
51
+
52
+ @admin.register(IndustryJob)
53
+ class IndustryJobAdmin(admin.ModelAdmin):
54
+ list_display = [
55
+ "job_id",
56
+ "activity_name",
57
+ "blueprint_type_name",
58
+ "owner_user",
59
+ "character_id",
60
+ "status",
61
+ "runs",
62
+ "start_date",
63
+ "end_date",
64
+ ]
65
+ list_filter = ["status", "activity_id", "owner_user", "character_id", "start_date"]
66
+ search_fields = [
67
+ "blueprint_type_name",
68
+ "product_type_name",
69
+ "activity_name",
70
+ "owner_user__username",
71
+ "job_id",
72
+ ]
73
+ readonly_fields = ["job_id", "last_updated", "created_at", "start_date", "end_date"]
74
+
75
+ fieldsets = (
76
+ (
77
+ "Job Information",
78
+ {
79
+ "fields": (
80
+ "owner_user",
81
+ "character_id",
82
+ "job_id",
83
+ "installer_id",
84
+ "status",
85
+ )
86
+ },
87
+ ),
88
+ (
89
+ "Activity Details",
90
+ {"fields": ("activity_id", "activity_name", "runs", "duration")},
91
+ ),
92
+ (
93
+ "Blueprint Information",
94
+ {"fields": ("blueprint_id", "blueprint_type_id", "blueprint_type_name")},
95
+ ),
96
+ ("Product Information", {"fields": ("product_type_id", "product_type_name")}),
97
+ (
98
+ "Locations",
99
+ {
100
+ "fields": (
101
+ "facility_id",
102
+ "station_id",
103
+ "blueprint_location_id",
104
+ "output_location_id",
105
+ ),
106
+ "classes": ("collapse",),
107
+ },
108
+ ),
109
+ ("Financial", {"fields": ("cost", "licensed_runs"), "classes": ("collapse",)}),
110
+ (
111
+ "Invention/Research",
112
+ {"fields": ("probability", "successful_runs"), "classes": ("collapse",)},
113
+ ),
114
+ (
115
+ "Timestamps",
116
+ {
117
+ "fields": (
118
+ "start_date",
119
+ "end_date",
120
+ "pause_date",
121
+ "completed_date",
122
+ "created_at",
123
+ "last_updated",
124
+ ),
125
+ "classes": ("collapse",),
126
+ },
127
+ ),
128
+ )
129
+
130
+
131
+ @admin.register(CharacterUpdateTracker)
132
+ class CharacterUpdateTrackerAdmin(admin.ModelAdmin):
133
+ list_display = [
134
+ "user",
135
+ "character_id",
136
+ "blueprints_last_update",
137
+ "jobs_last_update",
138
+ "last_refresh_request",
139
+ "updated_at",
140
+ "has_error",
141
+ ]
142
+ list_filter = [
143
+ "user",
144
+ "blueprints_last_update",
145
+ "jobs_last_update",
146
+ "last_refresh_request",
147
+ "updated_at",
148
+ ]
149
+ search_fields = ["user__username", "character_id"]
150
+ readonly_fields = ["updated_at"]
151
+
152
+ @admin.display(
153
+ description="Has Error",
154
+ boolean=True,
155
+ )
156
+ def has_error(self, obj):
157
+ return bool(obj.last_error)
158
+
159
+ fieldsets = (
160
+ ("Character Information", {"fields": ("user", "character_id")}),
161
+ (
162
+ "Update Status",
163
+ {
164
+ "fields": (
165
+ "blueprints_last_update",
166
+ "jobs_last_update",
167
+ "last_refresh_request",
168
+ "updated_at",
169
+ )
170
+ },
171
+ ),
172
+ ("Error Information", {"fields": ("last_error",), "classes": ("collapse",)}),
173
+ )
@@ -0,0 +1,94 @@
1
+ # Standard Library
2
+ import logging
3
+ import sys
4
+ from importlib import import_module
5
+
6
+ # Django
7
+ from django.apps import AppConfig, apps
8
+ from django.conf import settings
9
+ from django.db import connection
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ class IndyHubConfig(AppConfig):
15
+ """
16
+ Django application configuration for IndyHub.
17
+
18
+ Handles initialization of the application, including signal registration
19
+ and configuration of periodic tasks for industry data updates.
20
+ """
21
+
22
+ name = "indy_hub"
23
+ verbose_name = "Indy Hub"
24
+ default_auto_field = "django.db.models.BigAutoField"
25
+
26
+ def ready(self):
27
+ """
28
+ Initializes the application when Django starts.
29
+
30
+ This method:
31
+ 1. Loads signal handlers for event processing
32
+ 2. Sets up periodic tasks for automated industry data updates
33
+ 3. Injects beat schedule for compatibility
34
+ """
35
+ super().ready()
36
+
37
+ # Load signals
38
+ try:
39
+ import_module("indy_hub.signals")
40
+ logger.info("IndyHub signals loaded.")
41
+ except Exception as e:
42
+ logger.exception(f"Error loading signals: {e}")
43
+
44
+ # Skip tasks configuration during tests
45
+ if (
46
+ "test" in sys.argv
47
+ or "runtests.py" in sys.argv[0]
48
+ or hasattr(settings, "TESTING")
49
+ or "pytest" in sys.modules
50
+ ):
51
+ logger.info("Skipping periodic tasks setup during tests.")
52
+ return
53
+
54
+ # Skip during migrations
55
+ if "migrate" in sys.argv or "makemigrations" in sys.argv:
56
+ logger.info("Skipping periodic tasks setup during migrations.")
57
+ return
58
+
59
+ # Check that Celery Beat tables exist
60
+ try:
61
+ with connection.cursor() as cursor:
62
+ cursor.execute(
63
+ "SELECT 1 FROM django_celery_beat_crontabschedule LIMIT 1"
64
+ )
65
+ except Exception as e:
66
+ logger.warning(
67
+ f"Celery Beat tables not available, skipping periodic tasks setup: {e}"
68
+ )
69
+ return
70
+
71
+ # Inject beat schedule for compatibility (optional, non-blocking)
72
+ try:
73
+ # AA Example App
74
+ from indy_hub.schedules import INDY_HUB_BEAT_SCHEDULE
75
+
76
+ if hasattr(settings, "CELERYBEAT_SCHEDULE"):
77
+ settings.CELERYBEAT_SCHEDULE.update(INDY_HUB_BEAT_SCHEDULE)
78
+ else:
79
+ settings.CELERYBEAT_SCHEDULE = INDY_HUB_BEAT_SCHEDULE.copy()
80
+ except Exception as e:
81
+ logger.warning(f"Could not inject indy_hub beat schedule: {e}")
82
+
83
+ # Configure periodic tasks
84
+ try:
85
+ from .tasks import setup_periodic_tasks
86
+
87
+ setup_periodic_tasks()
88
+ logger.info("IndyHub periodic tasks configured.")
89
+ except Exception as e:
90
+ logger.exception(f"Error setting up periodic tasks: {e}")
91
+
92
+ # Check dependencies (optional logging)
93
+ if not apps.is_installed("esi"):
94
+ logger.warning("ESI not installed; some features may be disabled.")
@@ -0,0 +1,69 @@
1
+ # Alliance Auth
2
+ from allianceauth import hooks
3
+ from allianceauth.services.hooks import MenuItemHook, UrlHook
4
+
5
+ from . import urls
6
+
7
+
8
+ class IndyHubMenu(MenuItemHook):
9
+ """
10
+ Adds a menu item for Indy Hub in Alliance Auth navigation.
11
+ """
12
+
13
+ def __init__(self):
14
+ super().__init__(
15
+ "Indy Hub",
16
+ "fas fa-industry fa-fw",
17
+ "indy_hub:index",
18
+ navactive=[
19
+ "indy_hub:index",
20
+ "indy_hub:blueprints_list",
21
+ "indy_hub:jobs_list",
22
+ "indy_hub:token_management",
23
+ ],
24
+ )
25
+
26
+ def render(self, request):
27
+ # Only show to authenticated users with the correct permission
28
+ if not request.user.is_authenticated:
29
+ return ""
30
+ if not request.user.has_perm("indy_hub.can_access_indy_hub"):
31
+ return ""
32
+ # Calculate pending copy requests count
33
+ try:
34
+ from .models import Blueprint, BlueprintCopyRequest
35
+
36
+ bps = Blueprint.objects.filter(owner_user=request.user, quantity=-1)
37
+ count = (
38
+ BlueprintCopyRequest.objects.filter(
39
+ type_id__in=bps.values_list("type_id", flat=True),
40
+ material_efficiency__in=bps.values_list(
41
+ "material_efficiency", flat=True
42
+ ),
43
+ time_efficiency__in=bps.values_list("time_efficiency", flat=True),
44
+ fulfilled=False,
45
+ )
46
+ .exclude(requested_by=request.user)
47
+ .count()
48
+ )
49
+ self.count = count if count > 0 else None
50
+ except Exception:
51
+ self.count = None
52
+ # Delegate rendering to base class
53
+ return super().render(request)
54
+
55
+
56
+ @hooks.register("menu_item_hook")
57
+ def register_menu():
58
+ """
59
+ Register the IndyHub menu item.
60
+ """
61
+ return IndyHubMenu()
62
+
63
+
64
+ @hooks.register("url_hook")
65
+ def register_urls():
66
+ """
67
+ Register IndyHub URL patterns.
68
+ """
69
+ return UrlHook(urls, "indy_hub", r"^indy_hub/")
@@ -0,0 +1,79 @@
1
+ # indy_hub/decorators.py
2
+ # Standard Library
3
+ from functools import wraps
4
+
5
+ # Django
6
+ from django.contrib import messages
7
+ from django.shortcuts import redirect
8
+
9
+ # Import ESI Token only when needed to avoid import issues
10
+ try:
11
+ # Alliance Auth
12
+ from esi.models import Token
13
+ except ImportError:
14
+ Token = None
15
+
16
+
17
+ def token_required(scopes=None):
18
+ """
19
+ Decorator that checks if the user has valid ESI tokens with required scopes.
20
+ If not, redirects to token authorization page.
21
+ """
22
+ if scopes is None:
23
+ scopes = []
24
+
25
+ def decorator(view_func):
26
+ @wraps(view_func)
27
+ def _wrapped_view(request, *args, **kwargs):
28
+ if not request.user.is_authenticated:
29
+ return redirect("auth_login_user")
30
+
31
+ # Check if user has tokens with required scopes
32
+ if Token:
33
+ try:
34
+ tokens = Token.objects.filter(user=request.user).require_scopes(
35
+ scopes
36
+ )
37
+ if not tokens.exists():
38
+ # User doesn't have tokens with required scopes
39
+ scope_names = ", ".join(scopes)
40
+ messages.warning(
41
+ request,
42
+ f"You need to authorize ESI access with the following scopes: {scope_names}",
43
+ )
44
+ return redirect("indy_hub:token_management")
45
+ except Exception as e:
46
+ messages.error(request, f"Error checking ESI tokens: {e}")
47
+ return redirect("indy_hub:token_management")
48
+ else:
49
+ messages.error(request, "ESI module not available")
50
+ return redirect("indy_hub:index")
51
+
52
+ return view_func(request, *args, **kwargs)
53
+
54
+ return _wrapped_view
55
+
56
+ return decorator
57
+
58
+
59
+ def blueprints_token_required(view_func):
60
+ """Decorator specifically for blueprint views."""
61
+ return token_required(["esi-characters.read_blueprints.v1"])(view_func)
62
+
63
+
64
+ def industry_jobs_token_required(view_func):
65
+ """Decorator specifically for industry jobs views."""
66
+ return token_required(["esi-industry.read_character_jobs.v1"])(view_func)
67
+
68
+
69
+ def indy_hub_access_required(view_func):
70
+ @wraps(view_func)
71
+ def _wrapped_view(request, *args, **kwargs):
72
+ if not request.user.is_authenticated:
73
+ return redirect("auth_login_user")
74
+ if not request.user.has_perm("indy_hub.can_access_indy_hub"):
75
+ messages.error(request, "You do not have permission to access Indy Hub.")
76
+ return redirect("indy_hub:index")
77
+ return view_func(request, *args, **kwargs)
78
+
79
+ return _wrapped_view