Commit 9d12be5886380dfcbdc0e2859eac1cfae04fdd78
1 parent
03c5ff87
Exists in
dev
transfer common admins & models into dashboard
Showing
3 changed files
with
627 additions
and
2 deletions
Show diff stats
CHANGELOG
1 | +20-07-2023 (AKo): V0.6.27.0 | ||
2 | + - Add command to download observatory repository | ||
3 | + | ||
1 | 17-07-2023 (AKo): V0.6.27.0 | 4 | 17-07-2023 (AKo): V0.6.27.0 |
2 | - Change obsconfig folders & agents names + location & support CNES SSI Docker requirements | 5 | - Change obsconfig folders & agents names + location & support CNES SSI Docker requirements |
3 | 6 |
src/core/pyros_django/dashboard/admin.py
1 | + | ||
2 | +# Django imports | ||
3 | +from django import forms | ||
1 | from django.contrib import admin | 4 | from django.contrib import admin |
5 | +from django.contrib.auth.models import User | ||
6 | +# EP | ||
7 | +from django.conf import settings | ||
8 | + | ||
9 | +# Project imports | ||
10 | +from user_mgmt.models import Country, Institute, PyrosUser, UserLevel, ScientificProgram | ||
11 | +from common.models import * | ||
12 | +from majordome.models import * | ||
13 | +from env_monitor.models import * | ||
14 | +from devices.models import Detector, Filter, AgentDeviceStatus, FilterWheel, Telescope, PlcDevice, PlcDeviceStatus | ||
15 | +from seq_submit.models import Image, Schedule, Sequence, Album, Plan, ScheduleHasSequences #, StrategyObs, NrtAnalysis | ||
16 | +#from seq_submit.models import Image, StrategyObs, Schedule, Request, Alert, Sequence, Album, Plan, NrtAnalysis, ScheduleHasSequences | ||
17 | + | ||
18 | + | ||
19 | +# EP added | ||
20 | +class ReadOnlyModelAdmin(admin.ModelAdmin): | ||
21 | + """ModelAdmin class that prevents modifications through the admin. | ||
22 | + The changelist and the detail view work, but a 403 is returned | ||
23 | + if one actually tries to edit an object. | ||
24 | + Source: https://gist.github.com/aaugustin/1388243 | ||
25 | + """ | ||
26 | + | ||
27 | + actions = None | ||
28 | + | ||
29 | + def get_readonly_fields(self, request, obj=None): | ||
30 | + return self.fields or [f.name for f in self.model._meta.fields] | ||
31 | + | ||
32 | + def has_add_permission(self, request): | ||
33 | + return False | ||
34 | + | ||
35 | + # Allow viewing objects but not actually changing them | ||
36 | + def has_change_permission(self, request, obj=None): | ||
37 | + if request.method not in ('GET', 'HEAD'): | ||
38 | + return False | ||
39 | + return super(ReadOnlyModelAdmin, self).has_change_permission(request, obj) | ||
40 | + | ||
41 | + def has_delete_permission(self, request, obj=None): | ||
42 | + return False | ||
43 | + | ||
44 | + | ||
45 | +# EP added | ||
46 | + | ||
47 | +# Edit mode | ||
48 | +# DEBUG = False | ||
49 | +# View only mode | ||
50 | +# DEBUG = True | ||
51 | + | ||
52 | +''' Uncomment for production ''' | ||
53 | + | ||
54 | +# if settings.DEBUG: | ||
55 | +# class PyrosModelAdmin(ReadOnlyModelAdmin): | ||
56 | +# pass | ||
57 | +# else: | ||
58 | +# class PyrosModelAdmin(admin.ModelAdmin): | ||
59 | +# pass | ||
60 | + | ||
61 | + | ||
62 | +class PyrosModelAdmin(admin.ModelAdmin): | ||
63 | + pass | ||
64 | + | ||
65 | +# Many To Many interface adapter | ||
66 | + | ||
67 | + | ||
68 | +class PyrosUserAndSPInline(admin.TabularInline): | ||
69 | + #model = ScientificProgram.pyros_users.through | ||
70 | + pass | ||
71 | + | ||
72 | + | ||
73 | +class SequenceAndScheduleInline(admin.TabularInline): | ||
74 | + model = Schedule.sequences.through | ||
75 | + | ||
76 | +class PyrosUserAndUserLevelInline(admin.TabularInline): | ||
77 | + # add admin representation for m2m relation between PyrosUser and UserLevel | ||
78 | + model = UserLevel.pyros_users.through | ||
79 | + | ||
80 | +class ScheduleAdmin(admin.ModelAdmin): | ||
81 | + inlines = [ | ||
82 | + SequenceAndScheduleInline, | ||
83 | + ] | ||
84 | + exclude = ('sequences',) | ||
85 | + | ||
86 | + | ||
87 | +# One To Many interface adapters | ||
88 | + | ||
89 | +class SequenceInline(admin.TabularInline): | ||
90 | + model = Sequence | ||
91 | + readonly_fields = ("name",) | ||
92 | + fields = ("name",) | ||
93 | + show_change_link = True | ||
94 | + | ||
95 | + | ||
96 | +# class RequestInline(admin.TabularInline): | ||
97 | +# model = Request | ||
98 | +# readonly_fields = ("name",) | ||
99 | +# fields = ("name",) | ||
100 | +# show_change_link = True | ||
101 | + | ||
102 | + | ||
103 | +class AlbumInline(admin.TabularInline): | ||
104 | + model = Album | ||
105 | + readonly_fields = ("name",) | ||
106 | + fields = ("name",) | ||
107 | + show_change_link = True | ||
108 | + | ||
109 | + | ||
110 | +class PlanInline(admin.TabularInline): | ||
111 | + model = Plan | ||
112 | + #readonly_fields = ("name",) | ||
113 | + #fields = ("name",) | ||
114 | + show_change_link = True | ||
115 | + | ||
116 | + | ||
117 | +class ImageInline(admin.TabularInline): | ||
118 | + model = Image | ||
119 | + readonly_fields = ("name",) | ||
120 | + fields = ("name",) | ||
121 | + show_change_link = True | ||
122 | + | ||
123 | + | ||
124 | +class DetectorInline(admin.TabularInline): | ||
125 | + model = Detector | ||
126 | + readonly_fields = ("device_name",) | ||
127 | + fields = ("device_name",) | ||
128 | + show_change_link = True | ||
129 | + | ||
130 | + | ||
131 | +class PyrosUserInline(admin.TabularInline): | ||
132 | + model = PyrosUser | ||
133 | + readonly_fields = ("user_username",) | ||
134 | + fields = ("user_username",) | ||
135 | + show_change_link = True | ||
136 | + | ||
137 | + | ||
138 | +class FilterInline(admin.TabularInline): | ||
139 | + model = Filter | ||
140 | + readonly_fields = ("device_name",) | ||
141 | + fields = ("device_name",) | ||
142 | + show_change_link = True | ||
143 | + | ||
144 | + | ||
145 | +# class AlertInline(admin.TabularInline): | ||
146 | +# model = Alert | ||
147 | +# readonly_fields = ("request_name",) | ||
148 | +# fields = ("request_name",) | ||
149 | +# show_change_link = True | ||
150 | + | ||
151 | + | ||
152 | +# Admin model classes | ||
153 | + | ||
154 | +# class RequestAdmin(PyrosModelAdmin): | ||
155 | +# pass | ||
156 | + # inlines = [ | ||
157 | + # SequenceInline, | ||
158 | + # ] | ||
159 | + | ||
160 | + | ||
161 | +class SequenceAdmin(PyrosModelAdmin): | ||
162 | + inlines = [ | ||
163 | + AlbumInline, | ||
164 | + SequenceAndScheduleInline, # for M2M interface | ||
165 | + ] | ||
166 | + | ||
167 | + | ||
168 | +class PyrosUserAdmin(PyrosModelAdmin): | ||
169 | + list_display = ("user_username","is_active","laboratory") | ||
170 | + list_filter = ("is_active",) | ||
171 | + list_editable = ("is_active",) | ||
172 | + inlines = [ | ||
173 | + #RequestInline, | ||
174 | + # A user has many SPs | ||
175 | +# PyrosUserAndSPInline, # for M2M interface | ||
176 | + ] | ||
177 | + | ||
178 | + | ||
179 | +''' | ||
180 | +class StrategyObsAdmin(PyrosModelAdmin): | ||
181 | + inlines = [ | ||
182 | + #AlertInline, | ||
183 | + ] | ||
184 | +''' | ||
185 | + | ||
186 | + | ||
187 | +class ScientificProgramAdmin(PyrosModelAdmin): | ||
188 | + inlines = [ | ||
189 | + #RequestInline, | ||
190 | + # A SP has many users: | ||
191 | + # PyrosUserAndSPInline, # for M2M interface | ||
192 | + ] | ||
193 | + exclude = ('pyros_users',) # for M2M interface | ||
194 | + | ||
195 | + | ||
196 | +class CountryAdmin(PyrosModelAdmin): | ||
197 | + inlines = [ | ||
198 | + PyrosUserInline, | ||
199 | + ] | ||
200 | + | ||
201 | + | ||
202 | +class UserLevelAdmin(PyrosModelAdmin): | ||
203 | + inlines = [ | ||
204 | + #PyrosUserInline, | ||
205 | + PyrosUserAndUserLevelInline, | ||
206 | + ] | ||
207 | + list_display = ("name","priority",) | ||
208 | + # we need to exclude pyros_users which represents the m2m relation between UserLevel and PyrosUser | ||
209 | + exclude = ("pyros_users",) | ||
210 | + | ||
211 | + | ||
212 | +class FilterAdmin(PyrosModelAdmin): | ||
213 | + # inlines = [ | ||
214 | + # PlanInline, | ||
215 | + # ] | ||
216 | + pass | ||
217 | + | ||
218 | + | ||
219 | +class FilterWheelAdmin(PyrosModelAdmin): | ||
220 | + inlines = [ | ||
221 | + FilterInline, | ||
222 | + ] | ||
223 | + | ||
224 | + | ||
225 | +''' | ||
226 | +class NrtAnalysisAdmin(PyrosModelAdmin): | ||
227 | + inlines = [ | ||
228 | + ImageInline, | ||
229 | + ] | ||
230 | +''' | ||
231 | + | ||
232 | + | ||
233 | +class DetectorAdmin(PyrosModelAdmin): | ||
234 | + pass | ||
235 | + # inlines = [ | ||
236 | + # AlbumInline, | ||
237 | + # ] | ||
238 | + | ||
239 | + | ||
240 | +class TelescopeAdmin(PyrosModelAdmin): | ||
241 | + inlines = [ | ||
242 | + DetectorInline, | ||
243 | + ] | ||
244 | + | ||
245 | + | ||
246 | +class PlanAdmin(PyrosModelAdmin): | ||
247 | + inlines = [ | ||
248 | + ImageInline, | ||
249 | + ] | ||
250 | + | ||
251 | + | ||
252 | +# class AlbumAdmin(admin.ModelAdmin): | ||
253 | +class AlbumAdmin(PyrosModelAdmin): | ||
254 | + inlines = [ | ||
255 | + PlanInline, | ||
256 | + ] | ||
257 | + | ||
258 | + | ||
259 | +# Link the models to the admin interface | ||
260 | + | ||
261 | +# (EP added 10/7/19) | ||
262 | +admin.site.register(AgentCmd) | ||
263 | +admin.site.register(AgentLogs) | ||
264 | +admin.site.register(AgentSurvey) | ||
265 | +admin.site.register(AgentDeviceStatus) | ||
266 | + | ||
2 | 267 | ||
3 | -# Register your models here. | 268 | +admin.site.register(Album, AlbumAdmin) |
269 | +#admin.site.register(Alert) | ||
270 | +admin.site.register(Country, CountryAdmin) | ||
271 | +admin.site.register(Detector, DetectorAdmin) | ||
272 | +admin.site.register(Filter, FilterAdmin) | ||
273 | +admin.site.register(FilterWheel, FilterWheelAdmin) | ||
274 | +admin.site.register(Image) | ||
275 | +admin.site.register(Log) | ||
276 | +#admin.site.register(NrtAnalysis, NrtAnalysisAdmin) | ||
277 | +admin.site.register(Plan, PlanAdmin) | ||
278 | +#admin.site.register(Request, RequestAdmin) | ||
279 | +admin.site.register(Schedule, ScheduleAdmin) | ||
280 | +admin.site.register(ScheduleHasSequences) | ||
281 | +admin.site.register(ScientificProgram, ScientificProgramAdmin) | ||
282 | +admin.site.register(Sequence, SequenceAdmin) | ||
283 | +admin.site.register(SiteWatch) | ||
284 | +admin.site.register(SiteWatchHistory) | ||
285 | +#admin.site.register(StrategyObs, StrategyObsAdmin) | ||
286 | +##admin.site.register(TaskId) | ||
287 | +admin.site.register(Telescope, TelescopeAdmin) | ||
288 | +admin.site.register(PyrosUser, PyrosUserAdmin) | ||
289 | +admin.site.register(UserLevel, UserLevelAdmin) | ||
290 | +admin.site.register(Version) | ||
291 | +admin.site.register(WeatherWatch) | ||
292 | +admin.site.register(WeatherWatchHistory) | ||
293 | +admin.site.register(PlcDeviceStatus) | ||
294 | +admin.site.register(PlcDevice) | ||
295 | +admin.site.register(Config) | ||
296 | +admin.site.register(Institute) | ||
4 | \ No newline at end of file | 297 | \ No newline at end of file |
src/core/pyros_django/dashboard/models.py
1 | +##from __future__ import unicode_literals | ||
2 | + | ||
3 | +# (EP 21/9/22) To allow autoreferencing (ex: AgentCmd.create() returns a AgentCmd) | ||
4 | +from __future__ import annotations | ||
5 | + | ||
6 | +# Stdlib imports | ||
7 | +from src.device_controller.abstract_component.device_controller import DeviceCmd | ||
8 | +from datetime import datetime, timedelta, date | ||
9 | +from dateutil.relativedelta import relativedelta | ||
10 | +import os | ||
11 | +import sys | ||
12 | +from typing import Any, List, Tuple, Optional | ||
13 | +import re | ||
14 | + | ||
15 | +# Django imports | ||
16 | +from django.core.validators import MaxValueValidator, MinValueValidator | ||
17 | + | ||
18 | +# DJANGO imports | ||
19 | +from django.contrib.auth.models import AbstractUser, UserManager | ||
1 | from django.db import models | 20 | from django.db import models |
21 | +from django.db.models import Q, Max | ||
22 | +from django.core.validators import MaxValueValidator, MinValueValidator | ||
23 | +#from django.db.models.deletion import DO_NOTHING | ||
24 | +from django.db.models.expressions import F | ||
25 | +from django.db.models.query import QuerySet | ||
26 | +from model_utils import Choices | ||
27 | +from django.utils import timezone | ||
28 | +from asgiref.sync import async_to_sync | ||
29 | +from channels.layers import get_channel_layer | ||
30 | +from django.db.models.signals import post_save | ||
31 | +from django.dispatch import receiver | ||
32 | +# Project imports | ||
33 | +from user_mgmt.models import PyrosUser | ||
34 | +# DeviceCommand is used by class Command | ||
35 | +sys.path.append("../../..") | ||
36 | + | ||
37 | + | ||
38 | + | ||
39 | + | ||
40 | +""" | ||
41 | +STYLE RULES | ||
42 | +=========== | ||
43 | +https://simpleisbetterthancomplex.com/tips/2018/02/10/django-tip-22-designing-better-models.html | ||
44 | +https://steelkiwi.com/blog/best-practices-working-django-models-python/ | ||
45 | + | ||
46 | +- Model name => singular | ||
47 | + Call it Company instead of Companies. | ||
48 | + A model definition is the representation of a single object (the object in this example is a company), | ||
49 | + and not a collection of companies | ||
50 | + The model definition is a class, so always use CapWords convention (no underscores) | ||
51 | + E.g. User, Permission, ContentType, etc. | ||
52 | + | ||
53 | +- For the model’s attributes use snake_case. | ||
54 | + E.g. first_name, last_name, etc | ||
55 | + | ||
56 | +- Blank and Null Fields (https://simpleisbetterthancomplex.com/tips/2016/07/25/django-tip-8-blank-or-null.html) | ||
57 | + - Null: It is database-related. Defines if a given database column will accept null values or not. | ||
58 | + - Blank: It is validation-related. It will be used during forms validation, when calling form.is_valid(). | ||
59 | + Do not use null=True for text-based fields that are optional. | ||
60 | + Otherwise, you will end up having two possible values for “no data”, that is: None and an empty string. | ||
61 | + Having two possible values for “no data” is redundant. | ||
62 | + The Django convention is to use the empty string, not NULL. | ||
63 | + Example: | ||
64 | + # The default values of `null` and `blank` are `False`. | ||
65 | + class Person(models.Model): | ||
66 | + name = models.CharField(max_length=255) # Mandatory | ||
67 | + bio = models.TextField(max_length=500, blank=True) # Optional (don't put null=True) | ||
68 | + birth_date = models.DateField(null=True, blank=True) # Optional (here you may add null=True) | ||
69 | + The default values of null and blank are False. | ||
70 | + Special case, when you need to accept NULL values for a BooleanField, use NullBooleanField instead. | ||
71 | + | ||
72 | +- Choices : you can use Choices from the model_utils library. Take model Article, for instance: | ||
73 | + from model_utils import Choices | ||
74 | + class Article(models.Model): | ||
75 | + STATUSES = Choices( | ||
76 | + (0, 'draft', _('draft')), | ||
77 | + (1, 'published', _('published')) ) | ||
78 | + status = models.IntegerField(choices=STATUSES, default=STATUSES.draft) | ||
79 | + | ||
80 | +- Reverse Relationships | ||
81 | + | ||
82 | + - related_name : | ||
83 | + Rule of thumb: if you are not sure what would be the related_name, | ||
84 | + use the plural of the model holding the ForeignKey. | ||
85 | + ex: | ||
86 | + class Company: | ||
87 | + name = models.CharField(max_length=30) | ||
88 | + class Employee: | ||
89 | + first_name = models.CharField(max_length=30) | ||
90 | + last_name = models.CharField(max_length=30) | ||
91 | + company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='employees') | ||
92 | + usage: | ||
93 | + google = Company.objects.get(name='Google') | ||
94 | + google.employees.all() | ||
95 | + You can also use the reverse relationship to modify the company field on the Employee instances: | ||
96 | + vitor = Employee.objects.get(first_name='Vitor') | ||
97 | + google = Company.objects.get(name='Google') | ||
98 | + google.employees.add(vitor) | ||
99 | + | ||
100 | + - related_query_name : | ||
101 | + This kind of relationship also applies to query filters. | ||
102 | + For example, if I wanted to list all companies that employs people named ‘Vitor’, I could do the following: | ||
103 | + companies = Company.objects.filter(employee__first_name='Vitor') | ||
104 | + If you want to customize the name of this relationship, here is how we do it: | ||
105 | + class Employee: | ||
106 | + first_name = models.CharField(max_length=30) | ||
107 | + last_name = models.CharField(max_length=30) | ||
108 | + company = models.ForeignKey( | ||
109 | + Company, | ||
110 | + on_delete=models.CASCADE, | ||
111 | + related_name='employees', | ||
112 | + related_query_name='person' | ||
113 | + ) | ||
114 | + Then the usage would be: | ||
115 | + companies = Company.objects.filter(person__first_name='Vitor') | ||
116 | + | ||
117 | + To use it consistently, related_name goes as plural and related_query_name goes as singular. | ||
118 | + | ||
119 | + | ||
120 | +GENERAL EXAMPLE | ||
121 | +======= | ||
122 | + | ||
123 | +from django.db import models | ||
124 | +from django.urls import reverse | ||
125 | + | ||
126 | +class Company(models.Model): | ||
127 | + # CHOICES | ||
128 | + PUBLIC_LIMITED_COMPANY = 'PLC' | ||
129 | + PRIVATE_COMPANY_LIMITED = 'LTD' | ||
130 | + LIMITED_LIABILITY_PARTNERSHIP = 'LLP' | ||
131 | + COMPANY_TYPE_CHOICES = ( | ||
132 | + (PUBLIC_LIMITED_COMPANY, 'Public limited company'), | ||
133 | + (PRIVATE_COMPANY_LIMITED, 'Private company limited by shares'), | ||
134 | + (LIMITED_LIABILITY_PARTNERSHIP, 'Limited liability partnership'), | ||
135 | + ) | ||
136 | + | ||
137 | + # DATABASE FIELDS | ||
138 | + name = models.CharField('name', max_length=30) | ||
139 | + vat_identification_number = models.CharField('VAT', max_length=20) | ||
140 | + company_type = models.CharField('type', max_length=3, choices=COMPANY_TYPE_CHOICES) | ||
141 | + | ||
142 | + # MANAGERS | ||
143 | + objects = models.Manager() | ||
144 | + limited_companies = LimitedCompanyManager() | ||
145 | + | ||
146 | + # META CLASS | ||
147 | + class Meta: | ||
148 | + verbose_name = 'company' | ||
149 | + verbose_name_plural = 'companies' | ||
150 | + | ||
151 | + # TO STRING METHOD | ||
152 | + def __str__(self): | ||
153 | + return self.name | ||
154 | + | ||
155 | + # SAVE METHOD | ||
156 | + def save(self, *args, **kwargs): | ||
157 | + do_something() | ||
158 | + super().save(*args, **kwargs) # Call the "real" save() method. | ||
159 | + do_something_else() | ||
160 | + | ||
161 | + # ABSOLUTE URL METHOD | ||
162 | + def get_absolute_url(self): | ||
163 | + return reverse('company_details', kwargs={'pk': self.id}) | ||
164 | + | ||
165 | + # OTHER METHODS | ||
166 | + def process_invoices(self): | ||
167 | + do_something() | ||
168 | + | ||
169 | +""" | ||
170 | + | ||
171 | + | ||
172 | +# --- | ||
173 | +# --- Utility functions | ||
174 | +# --- | ||
175 | + | ||
176 | +def printd(*args, **kwargs): | ||
177 | + if os.environ.get('PYROS_DEBUG', '0') == '1': | ||
178 | + print('(MODEL)', *args, **kwargs) | ||
179 | + | ||
180 | +''' | ||
181 | +def get_or_create_unique_row_from_model(model: models.Model): | ||
182 | + # return model.objects.get(id=1) if model.objects.exists() else model.objects.create(id=1) | ||
183 | + return model.objects.first() if model.objects.exists() else model.objects.create(id=1) | ||
184 | +''' | ||
185 | + | ||
186 | + | ||
187 | + | ||
188 | + | ||
189 | + | ||
190 | +""" | ||
191 | +------------------------ | ||
192 | + BASE MODEL CLASSES | ||
193 | +------------------------ | ||
194 | +""" | ||
195 | + | ||
196 | +""" | ||
197 | +------------------------ | ||
198 | + OTHER MODEL CLASSES | ||
199 | +------------------------ | ||
200 | +""" | ||
201 | + | ||
202 | + | ||
203 | +# TODO: OLD Config : à virer (mais utilisé dans dashboard/templatetags/tags.py) | ||
204 | +class Config(models.Model): | ||
205 | + PYROS_STATE = ["Starting", "Passive", "Standby", | ||
206 | + "Remote", "Startup", "Scheduler", "Closing"] | ||
207 | + | ||
208 | + id = models.IntegerField(default='1', primary_key=True) | ||
209 | + #latitude = models.FloatField(default=1) | ||
210 | + latitude = models.DecimalField( | ||
211 | + max_digits=4, decimal_places=2, | ||
212 | + default=1, | ||
213 | + validators=[ | ||
214 | + MaxValueValidator(90), | ||
215 | + MinValueValidator(-90) | ||
216 | + ] | ||
217 | + ) | ||
218 | + local_time_zone = models.FloatField(default=1) | ||
219 | + #longitude = models.FloatField(default=1) | ||
220 | + longitude = models.DecimalField( | ||
221 | + max_digits=5, decimal_places=2, | ||
222 | + default=1, | ||
223 | + validators=[ | ||
224 | + MaxValueValidator(360), | ||
225 | + MinValueValidator(-360) | ||
226 | + ] | ||
227 | + ) | ||
228 | + altitude = models.FloatField(default=1) | ||
229 | + horizon_line = models.FloatField(default=1) | ||
230 | + row_data_save_frequency = models.IntegerField(default='300') | ||
231 | + request_frequency = models.IntegerField(default='300') | ||
232 | + analysed_data_save = models.IntegerField(default='300') | ||
233 | + telescope_ip_address = models.CharField(max_length=45, default="127.0.0.1") | ||
234 | + camera_ip_address = models.CharField(max_length=45, default="127.0.0.1") | ||
235 | + plc_ip_address = models.CharField(max_length=45, default="127.0.0.1") | ||
236 | + | ||
237 | + # TODO: changer ça, c'est pas clair du tout... | ||
238 | + # True = mode Scheduler-standby, False = mode Remote !!!! | ||
239 | + global_mode = models.BooleanField(default='True') | ||
240 | + | ||
241 | + ack = models.BooleanField(default='False') | ||
242 | + bypass = models.BooleanField(default='True') | ||
243 | + lock = models.BooleanField(default='False') | ||
244 | + pyros_state = models.CharField(max_length=25, default=PYROS_STATE[0]) | ||
245 | + force_passive_mode = models.BooleanField(default='False') | ||
246 | + plc_timeout_seconds = models.PositiveIntegerField(default=60) | ||
247 | + majordome_state = models.CharField(max_length=25, default="") | ||
248 | + ntc = models.BooleanField(default='False') | ||
249 | + majordome_restarted = models.BooleanField(default='False') | ||
250 | + | ||
251 | + class Meta: | ||
252 | + managed = True | ||
253 | + db_table = 'config' | ||
254 | + verbose_name_plural = "Config" | ||
255 | + | ||
256 | + def __str__(self): | ||
257 | + return (str(self.__dict__)) | ||
258 | + | ||
259 | + | ||
260 | + | ||
261 | +class Log(models.Model): | ||
262 | + agent = models.CharField(max_length=45, blank=True, null=True) | ||
263 | + created = models.DateTimeField(blank=True, null=True, auto_now_add=True) | ||
264 | + message = models.TextField(blank=True, null=True) | ||
265 | + | ||
266 | + class Meta: | ||
267 | + managed = True | ||
268 | + db_table = 'log' | ||
269 | + | ||
270 | + def __str__(self): | ||
271 | + return (str(self.agent)) | ||
272 | + | ||
273 | + | ||
274 | +# TODO: à virer car utilisé pour Celery (ou bien à utiliser pour les agents) | ||
275 | +''' | ||
276 | +class TaskId(models.Model): | ||
277 | + task = models.CharField(max_length=45, blank=True, null=True) | ||
278 | + created = models.DateTimeField(blank=True, null=True, auto_now_add=True) | ||
279 | + task_id = models.CharField(max_length=45, blank=True, null=True) | ||
280 | + | ||
281 | + class Meta: | ||
282 | + managed = True | ||
283 | + db_table = 'task_id' | ||
284 | + | ||
285 | + def __str__(self): | ||
286 | + return (str(self.task) + " - " + str(self.task_id)) | ||
287 | +''' | ||
288 | + | ||
289 | + | ||
290 | +class Version(models.Model): | ||
291 | + module_name = models.CharField(max_length=45, blank=True, null=True) | ||
292 | + version = models.CharField(max_length=15, blank=True, null=True) | ||
293 | + created = models.DateTimeField(blank=True, null=True, auto_now_add=True) | ||
294 | + updated = models.DateTimeField(blank=True, null=True, auto_now=True) | ||
295 | + | ||
296 | + class Meta: | ||
297 | + managed = True | ||
298 | + db_table = 'version' | ||
299 | + | ||
300 | + def __str__(self): | ||
301 | + return (str(self.module_name) + " - " + str(self.version)) | ||
302 | + | ||
303 | + | ||
304 | +class Tickets(models.Model): | ||
305 | + created = models.DateTimeField(blank=True, null=True, auto_now_add=True) | ||
306 | + updated = models.DateTimeField(blank=True, null=True, auto_now=True) | ||
307 | + end = models.DateTimeField(blank=True, null=True) | ||
308 | + title = models.TextField(blank=True, null=True) | ||
309 | + description = models.TextField(blank=True, null=True) | ||
310 | + resolution = models.TextField(blank=True, null=True) | ||
311 | + pyros_user = models.ForeignKey(PyrosUser, on_delete=models.DO_NOTHING, related_name="tickets", blank=True, null=True) | ||
312 | + last_modified_by = models.ForeignKey(PyrosUser, on_delete=models.DO_NOTHING, related_name="tickets_modified_by", blank=True, null=True) | ||
313 | + LEVEL_ONE = "ONE" | ||
314 | + LEVEL_TWO = "TWO" | ||
315 | + LEVEL_THREE = "THREE" | ||
316 | + LEVEL_FOUR = "FOUR" | ||
317 | + LEVEL_FIVE = "FIVE" | ||
318 | + SECURITY_LEVEL_CHOICES = ( | ||
319 | + (LEVEL_ONE,"Warning non compromising for the operation of the system"), | ||
320 | + (LEVEL_TWO,"Known issue which can be solved by operating the software remotely"), | ||
321 | + (LEVEL_THREE,"Known issue which can be solved by an human remotely"), | ||
322 | + (LEVEL_FOUR,"Known issue without immediate solution"), | ||
323 | + (LEVEL_FIVE,"Issue not categorized until it happened") | ||
324 | + ) | ||
325 | + security_level = models.TextField(choices=SECURITY_LEVEL_CHOICES, default=LEVEL_ONE) | ||
326 | + | ||
327 | + class Meta: | ||
328 | + managed = True | ||
329 | + db_table = 'tickets' | ||
330 | + verbose_name_plural = "tickets" | ||
331 | + | ||
2 | 332 | ||
3 | -# Create your models here. |