class Bulletin(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) version = AutoIncVersionField() publish = models.BooleanField(default=False) public = models.BooleanField(default=False) title = models.CharField(max_length=250) body = MarkdownxField() published = models.DateTimeField(null=True, blank=True) created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) class Meta: verbose_name = _('bulletin') verbose_name_plural = _('bulletins') ordering = ['-published'] def __str__(self): return self.title def save(self, *args, **kwargs): if self.publish and self.published is None: self.published = timezone.now() super().save(*args, **kwargs) @property def as_html(self): return markdownify(self.body)
class ProductVersion(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.ForeignKey(Product, on_delete=models.PROTECT, verbose_name="製品名") version = models.ForeignKey(Version, on_delete=models.PROTECT, verbose_name="製品バージョン") creator = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, verbose_name="作成者", related_name="product_version_created_by") created_at = models.DateTimeField(auto_now_add=True, verbose_name="作成日時") ver = AutoIncVersionField("バージョン") class Meta: ordering = ("name", "version") unique_together = [["name", "version"]] # ユニーク制約 # constraints = [ # models.UniqueConstraint( # fields=["name", "version"], # name="app_version_unique" # ) # ] # @classmethod # def check_duplicate(cls, name: str, version: str): # """ # 登録済みはTrue, 登録なしはFalse # """ # return cls.objects.filter(name=name, version=version).exists() def __str__(self): return '%s/%s' % (self.name, self.version)
class Product(models.Model): P = [ ('h', 'Hardware'), ('o', 'Operating System'), ('a', 'Application'), ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField("製品名", max_length=150, unique=True) part = models.CharField("種別", max_length=1, choices=P) vendor = models.CharField("ベンダ名", max_length=150) url = models.URLField("ベンダURL") creator = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, verbose_name="作成者", related_name="product_created_by") created_at = models.DateTimeField(auto_now_add=True, verbose_name="作成日時") ver = AutoIncVersionField("バージョン") class Meta: # nameフィールドのアルファベット順に並び替え ordering = ("name", ) def __str__(self): return self.name
class ChemicalAnalysis(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) version = AutoIncVersionField() public_data = models.BooleanField(default=False) reference_x = models.FloatField(blank=True, null=True) reference_y = models.FloatField(blank=True, null=True) stage_x = models.FloatField(blank=True, null=True) stage_y = models.FloatField(blank=True, null=True) analysis_method = models.CharField(max_length=50, blank=True, null=True) where_done = models.CharField(max_length=50, blank=True, null=True) analyst = models.CharField(max_length=50, blank=True, null=True) analysis_date = models.DateTimeField(blank=True, null=True) date_precision = models.SmallIntegerField(blank=True, null=True) description = models.CharField(max_length=1024, blank=True, null=True) total = models.FloatField(blank=True, null=True) spot_id = models.BigIntegerField() subsample = models.ForeignKey('samples.Subsample', related_name='chemical_analyses') mineral = models.ForeignKey('samples.Mineral', blank=True, null=True) owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='chemical_analyses') elements = models.ManyToManyField('Element', through='ChemicalAnalysisElement') oxides = models.ManyToManyField('Oxide', through='ChemicalAnalysisOxide') # Free-text field; stored as an CharField to avoid joining to the # references table every time we retrieve chemical analyses reference = models.CharField(max_length=100, blank=True, null=True) class Meta: db_table = 'chemical_analyses'
class ProductJson(models.Model): # this field is for optimistic locking version = AutoIncVersionField() # contains the json data, can be optimized with specific libraries, but for simplicity we'll use text data = models.TextField() # updated every time save() is called on the model last_modified = models.DateTimeField(auto_now=True) # each ProductJson has exactly on Product product = models.OneToOneField(Product, related_name='product_json')
class AutoIncConcurrentModel(models.Model): version = AutoIncVersionField(db_column='cm_version_id') username = models.CharField(max_length=30, blank=True, null=True) last_name = models.CharField(max_length=30, blank=True, null=True) char_field = models.CharField(max_length=30, blank=True, null=True) date_field = models.DateField(blank=True, null=True) class Meta: app_label = 'concurrency'
class Grid(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) version = AutoIncVersionField() subsample = models.ForeignKey(Subsample) width = models.SmallIntegerField() height = models.SmallIntegerField() public_data = models.BooleanField(default=False) class Meta: db_table = 'grids'
class Pridev(models.Model): tekst = models.CharField('текст', max_length=50, blank=True, null=True) vreme = models.DateTimeField('време последње измене', default=now) version = AutoIncVersionField() def __str__(self): return self.tekst if self.tekst else '-' class Meta: verbose_name = 'придев' verbose_name_plural = 'придеви'
class Subsample(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=100) version = AutoIncVersionField() sample = models.ForeignKey(Sample, related_name='subsamples') public_data = models.BooleanField(default=False) owner = models.ForeignKey(settings.AUTH_USER_MODEL) subsample_type = models.ForeignKey(SubsampleType) class Meta: db_table = 'subsamples'
class Appointment(models.Model): clinic = models.ForeignKey(to=Clinic, on_delete=models.CASCADE, related_name='appointments') date = models.DateField(null=True, blank=True) time = models.TimeField(null=True, blank=True) typeOf = models.ForeignKey(to=AppointmentType, on_delete=models.CASCADE) #price from .clinic.prices discount = models.IntegerField(default=0) doctor = models.ForeignKey(to='users.Doctor', on_delete=models.CASCADE, related_name='appointments') # if the operatingRoom is Null => this is a request for the ClinicAdmin to approve operatingRoom = models.ForeignKey(to=OperatingRoom, on_delete=models.CASCADE, null=True) # if the patient is null => the appointment was set inAdvance patient = models.ForeignKey(to='users.Patient', on_delete=models.CASCADE, related_name='appointments', null=True, blank=True) created = models.DateField(null=True, blank=True) version = AutoIncVersionField(default=1) class Meta: constraints = [ models.UniqueConstraint( fields=['clinic', 'date', 'time', 'doctor'], name='unique doctor date time for a clinic') ] ordering = ['typeOf', 'date'] def save(self, *args, **kwargs): if (not self.created): self.created = date.today() super(Appointment, self).save(*args, **kwargs) if self.operatingRoom is None: clinic_admins = ClinicAdmin.objects.select_related( 'employedAt').filter(employedAt=self.clinic) to_emails = [admin.email for admin in clinic_admins] send_mail( APPOINTMENT_REQUEST_TITLE, APPOINTMENT_REQUEST_BODY % (self.date, self.time, self.typeOf, self.doctor, self.patient), settings.EMAIL_HOST_USER, to_emails, fail_silently=True) def __str__(self): return f'{self.clinic.name} - {self.typeOf.typeName} - {self.date} : {self.time}, {self.doctor.email}, {self.operatingRoom},'
class AutoIncConcurrentModel(models.Model): version = AutoIncVersionField(db_column='cm_version_id') username = models.CharField(max_length=30, blank=True, null=True) date_field = models.DateField(blank=True, null=True) class Meta: app_label = 'demo' verbose_name = "AutoIncConcurrentModel" verbose_name_plural = "AutoIncConcurrentModel" def __unicode__(self): return "{0.__class__.__name__} #{0.pk}".format(self)
class Scene(models.Model): name = models.CharField(null=True, max_length=32) world = models.FileField(null=True) camera = models.ForeignKey(Camera, on_delete=models.SET_NULL, null=True) quality = models.ForeignKey(Quality, null=True, on_delete=models.PROTECT) img = models.FileField(null=True, upload_to='scenes/') status = models.CharField(null=True, blank=True, max_length=32) worker = models.ForeignKey('Machine', null=True, blank=True, on_delete=models.SET_NULL) version = AutoIncVersionField() # img = models.FileField(null=True, upload_to=f'{settings.MEDIA_URL[1:]}/scenes') def orderRender(self, engine='Eevee'): pass
class Odrednica(models.Model): rec = models.CharField('реч', max_length=50, blank=True, null=True) sortable_rec = models.CharField('реч за сортирање', max_length=50, blank=True, null=True) ijekavski = models.CharField('ијекавски', max_length=50, blank=True, null=True) vrsta = models.IntegerField('врста', choices=VRSTA_ODREDNICE) podvrsta = models.ForeignKey(PodvrstaReci, verbose_name='подврста', on_delete=models.PROTECT, blank=True, null=True) rod = models.IntegerField('род', choices=ROD, default=0, blank=True, null=True) nastavak = models.CharField('наставак', max_length=50, blank=True, null=True) nastavak_ij = models.CharField('наставак ијекавски', max_length=50, blank=True, null=True) info = models.CharField('инфо', max_length=2000, blank=True, null=True) glagolski_vid = models.IntegerField('глаголски вид', choices=GLAGOLSKI_VID, blank=True, null=True) glagolski_rod = models.IntegerField('глаголски род', choices=GLAGOLSKI_ROD, blank=True, null=True) prikazi_gl_rod = models.BooleanField('прикажи глаголски род', null=True, blank=True) ima_se_znacenja = models.BooleanField('има значења за ~ ce', null=True, blank=True) prezent = models.CharField('презент', max_length=50, blank=True, null=True) prezent_ij = models.CharField('презент', max_length=50, blank=True, null=True) broj_pregleda = models.IntegerField('број прегледа', default=0) vreme_kreiranja = models.DateTimeField('време креирања', default=now) poslednja_izmena = models.DateTimeField('време последње измене', default=now) stanje = models.IntegerField('фаза обраде', choices=STANJE_ODREDNICE, default=1) opciono_se = models.BooleanField('опционо се', null=True, blank=True) version = AutoIncVersionField() rbr_homonima = models.PositiveSmallIntegerField('редни број хомонима', null=True, blank=True, default=None) obradjivac = models.ForeignKey(UserProxy, verbose_name='обрађивач', on_delete=models.PROTECT, related_name='odrednice_obradjivaca', blank=True, null=True) redaktor = models.ForeignKey(UserProxy, verbose_name='редактор', on_delete=models.PROTECT, related_name='odrednice_redaktora', blank=True, null=True) urednik = models.ForeignKey(UserProxy, verbose_name='уредник', on_delete=models.PROTECT, related_name='odrednice_urednika', blank=True, null=True) napomene = models.TextField('напомене', max_length=2000, blank=True, null=True) freetext = models.TextField('алтернативни опис', max_length=2000, blank=True, null=True) status = models.ForeignKey(StatusOdrednice, verbose_name='статус одреднице', null=True, blank=True, on_delete=models.PROTECT) ravnopravne_varijante = models.BooleanField('равноправне варијанте', default=True) def __str__(self): return self.rec if self.rec else '-' def ima_napomene(self): if not self.napomene: return False return True class Meta: verbose_name = 'одредница' verbose_name_plural = 'одреднице' indexes = [ models.Index(fields=['rec']), models.Index(fields=['sortable_rec', 'rbr_homonima']), models.Index(fields=['poslednja_izmena']) ] def get_absolute_url(self): return reverse("odrednice:odrednica-detail", kwargs={"pk": self.pk})
class Sample(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) version = AutoIncVersionField() public_data = models.BooleanField(default=False) number = models.CharField(max_length=35) owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='samples') aliases = ArrayField(models.CharField(max_length=35, blank=True), blank=True, null=True) collection_date = models.DateTimeField(blank=True, null=True) description = models.TextField(blank=True, null=True) location_name = models.CharField(max_length=50, blank=True, null=True) location_coords = models.PointField() location_error = models.FloatField(blank=True, null=True) rock_type = models.ForeignKey(RockType) date_precision = models.SmallIntegerField(blank=True, null=True) metamorphic_regions = models.ManyToManyField('MetamorphicRegion') metamorphic_grades = models.ManyToManyField('MetamorphicGrade') minerals = models.ManyToManyField('Mineral', through='SampleMineral', related_name='samples') references = models.ManyToManyField('GeoReference', related_name='samples') # Free-text field. Ugh. Stored as an CharField to avoid joining to the # country table every time we retrieve sample(s). country = models.CharField(max_length=100, blank=True, null=True) # Free-text field; stored as an ArrayField to avoid joining to the # regions table every time we retrieve sample(s). regions = ArrayField(models.CharField(max_length=100, blank=True), blank=True, null=True) # Free text field with no validation; collector_name = models.CharField(max_length=50, blank=True, null=True) # Unused; here for backward compatibility collector_id = models.ForeignKey(settings.AUTH_USER_MODEL, db_column='collector_id', related_name='+', blank=True, null=True) # Unused; here for backward compatibility sesar_number = models.CharField(max_length=9, blank=True, null=True) class Meta: db_table = 'samples' ordering = ['id']
class ManagedTVModel(models.Model): """Model including optimistic version control field (the V in the class name), and creation/update timestamps fields (the T in the class name), but managed by Django. this is the same as the VersionedTimestampedModel, but *WITHOUT* the hack required to get record IDs from the DB that we have to use with the tables from the original CCAPI and the way Grails defined them. """ version = AutoIncVersionField() date_created = models.DateTimeField(auto_now_add=True) last_updated = models.DateTimeField(auto_now=True) class Meta: abstract = True
class BookStock(models.Model): """在庫モデル""" class Meta: db_table = 'stock' verbose_name = verbose_name_plural = '在庫' book = models.OneToOneField(Book, verbose_name='本', on_delete=models.CASCADE) quantity = models.PositiveIntegerField('在庫数', default=0) updated_at = models.DateTimeField('更新日時', auto_now=True) version = AutoIncVersionField(verbose_name='バージョン') def __str__(self): return f'{self.book.title} ({self.quantity})'
class Product(models.Model): name = models.CharField(max_length=100) vendor = models.CharField(max_length=100) category = models.ForeignKey(Category, on_delete=models.PROTECT) supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE) description = models.TextField(max_length=2000, blank=True, null=True) price = models.DecimalField(max_digits=10, decimal_places=2) available_quantity = models.IntegerField(default=0) version = AutoIncVersionField(default=1) def __str__(self): return self.name class Meta: verbose_name = 'product' verbose_name_plural = 'products'
class Redirect(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) version = AutoIncVersionField() path = models.CharField(max_length=32, unique=True, validators=[URLPathValidator()]) location = models.URLField(max_length=2048) created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) def save(self, *args, **kwargs): self.path = urljoin('/', self.path) super().save(*args, **kwargs) @property def url(self): scheme = 'https' if settings.REDIRECT_SECURE else 'http' return '{0}://{1}{2}'.format(scheme, settings.REDIRECT_HOST, self.path)
class Glagol(models.Model): infinitiv = models.CharField('инфинитив', max_length=50, blank=True, null=True) vid = models.IntegerField('глаголски вид', choices=GLAGOLSKI_VID) rod = models.IntegerField('глаголски род', choices=GLAGOLSKI_ROD) rgp_mj = models.CharField('РГП муш јед', max_length=50, blank=True, null=True) rgp_zj = models.CharField('РГП жен јед', max_length=50, blank=True, null=True) rgp_sj = models.CharField('РГП сре јед', max_length=50, blank=True, null=True) rgp_mm = models.CharField('РГП муш мно', max_length=50, blank=True, null=True) rgp_zm = models.CharField('РГП жен мно', max_length=50, blank=True, null=True) rgp_sm = models.CharField('РГП сре мно', max_length=50, blank=True, null=True) gpp = models.CharField('ГПП', max_length=50, blank=True, null=True) gps = models.CharField('ГПС', max_length=50, blank=True, null=True) vreme = models.DateTimeField('време последње измене', default=now) version = AutoIncVersionField() def __str__(self): return self.infinitiv if self.infinitiv else '-' class Meta: verbose_name = 'глагол' verbose_name_plural = 'глаголи'
class Version(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) version = models.CharField("製品バージョン", max_length=150, unique=True) name = models.ManyToManyField( Product, through="ProductVersion", ) creator = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, verbose_name="作成者", related_name="version_created_by") created_at = models.DateTimeField(auto_now_add=True, verbose_name="作成日時") ver = AutoIncVersionField("バージョン") class Meta: # versionフィールドの数字(小大)文字順に並び替え ordering = ("version", ) def __str__(self): return self.version
class Order(models.Model): kind = models.ForeignKey(ProductKind, null=True, on_delete=models.PROTECT) quality = models.ForeignKey(Quality, null=True, on_delete=models.PROTECT) rule = models.CharField(null=True, max_length=1024, blank=True) running = models.BooleanField(null=True) # 0 - в очереди, #1 - выполняется, #null - не требует запуска renders_done = models.PositiveIntegerField(default=0) renders_posted = models.PositiveIntegerField(default=0) status = models.CharField(null=True, blank=True, max_length=32) volume = models.PositiveIntegerField(default=0, null=True, blank=True) worker = models.ForeignKey('Machine', null=True, blank=True, on_delete=models.SET_NULL) version = AutoIncVersionField() @property def model(self): return self.kind.product.model def run(self): # sending to rabbitMQ if os.getenv('RABBIT_HOST'): # put message into rabbit try: import pika, json credentials = pika.PlainCredentials(os.getenv('RABBIT_USER'), os.getenv('RABBIT_PASSWORD')) parameters = pika.ConnectionParameters(os.getenv('RABBIT_HOST'), os.getenv('RABBIT_PORT'), os.getenv('RABBIT_VIRTUALHOST', default='/'), credentials=credentials) connection = pika.BlockingConnection(parameters) channel = connection.channel() data = {'model': str(self.kind.product.model.blend), 'order_id': str(self.pk)} # , 'rule': self.rule, 'quality': self.quality channel.basic_publish(exchange='', routing_key='orders', body=json.dumps(data)) connection.close() self.running = False # put to queue self.volume = self.N self.save() # if success - save it return 'ok' except Exception as err: self.running = None self.save() print(f'MQTT ERROR {repr(err)}') return repr(err) else: self.running = False # put to queue self.volume = self.N self.save() return "RABBIT_HOST missed in the env! but if queue command looks in db - it can be run because it in the queue" def cancel(self): try: self.running = None if not self.renders_done: self.worker = None self.save() except: print("concurrent access to order - can't cancel") pass def cleanData(self): shutil.rmtree(self.rendersPath) self.renders_done = 0 self.worker = None self.save() def postData(self, copy_type): src = os.path.join(self.rendersPath, str(self.quality.id)) dest = os.path.join(self.kind.product.rendersPath, str(self.quality.id)) if not os.path.exists(dest): os.makedirs(dest) for f in os.listdir(src): if f[0] != '.' and os.path.isfile(os.path.join(src, f)): if (copy_type == 'copy'): shutil.copyfile(os.path.join(src, f), os.path.join(dest, f)) elif (copy_type == 'move'): shutil.move(os.path.join(src, f), os.path.join(dest, f)) else: #sym os.symlink(os.path.join(src, f), os.path.join(dest, f)) # very useful for rendering! @property def cycles(self): result = [] if not self.kind: return result config = self.kind.cycles rules = {} if self.rule: for r in self.rule.split(';'): pr = r.split(':') rules[pr[0].lower()] = pr[1] for conf in config: cycle = {'config': conf, 'meshes': conf.part.meshes.all().values_list('name', flat=True), 'finishes': []} if not conf.colorChart: rule = rules[conf.part.name.lower()] if conf.part.name.lower() in rules else "*" try: # finishes by comma cycle['finishes'] = [Finish.objects.get(pk=int(f)) for f in rule.split(',')] except: if conf.optional: # + (1 if c['config'].optional else 0) cycle['finishes'].append(Finish.objects.get(pattern__nature__name='none')) if rule == "*": cycle['finishes'] += sorted([f for f in conf.finishes], key=lambda f: f.pattern_id) elif rule[0] == 'p': p_id = int(rule[1:]) cycle['finishes'] += Pattern.objects.get(pk=p_id).finishes result.append(cycle) return result @property def N(self): res = 1 for c in self.cycles: if c['config'].colorChart: continue res *= len(c['finishes']) return res def clone(self): o = Order() o.kind = self.kind o.shadow = self.shadow o.quailty = self.quailty #o.N = 0 return o def get_absolute_url(self): return reverse('order-update', kwargs={'order_id': self.pk}) @property def rendersPath(self): return os.path.join(self.kind.product.rendersPath, 'orders', str(self.pk)) @property def relRendersPath(self): return os.path.join(self.kind.product.relRendersPath, 'orders', str(self.pk)) # @property # def donePath(self): # return os.path.join(self.rendersPath, "done") @property def diskSize(self): try: return get_kbsize(self.rendersPath) except: return 0 @property def renders(self): wild = '**/*.{jpg,png}' return [str(f)[len(settings.MEDIA_ROOT) + 1:].replace('\\', '/') for f in pathlib.Path(self.rendersPath).glob(wild, flags=pathlib.BRACE)] # @property # def renderDirs(self): # for show data contents in the order # dirs = {} # wild = "**.*" # # todo use Path instgead of os.path https://docs.python.org/3/library/pathlib.html # if os.path.exists(self.rendersPath): # for d in os.listdir(self.rendersPath): # if d[0] == '.': # continue # dd = os.path.join(self.rendersPath, d) # if os.path.isdir(dd): # dirs[d] = len(list(pathlib.Path(dd).glob(wild))) # return dirs @property def doneLog(self): url = os.path.join(self.rendersPath, f'order-{self.pk}.log') try: with open(url) as done_log: done_renders = done_log.read().split('\n') head = done_renders.pop(0) if len(done_renders[-1]) == 0: done_renders.pop(-1) return {'url': url, 'count': len(done_renders), 'started': head.split('\t')[0]} except: return {'url': url} # def url(self, key=""): # if self.N > 1 or not self.renders_done: # return '' # if not key: # key = self.kind.parse_rules(self.rule.split(';'))['file'] # try: # do.s3.Object(settings.AWS_STORAGE_BUCKET_NAME, key).load() # return do.s3client.generate_presigned_url(ClientMethod='get_object', # Params={'Bucket': settings.AWS_STORAGE_BUCKET_NAME, # 'Key': key}, # ExpiresIn=600) # except: # return "" def __str__(self): return f"[{self.pk}]order for product kind {self.kind}, {self.quality}, rules:'{self.rule}' volume={self.N}"
class Imenica(models.Model): vrsta = models.ForeignKey(VrstaImenice, verbose_name='врста именице', on_delete=models.DO_NOTHING) nomjed = models.CharField('номинатив једнине', max_length=50, blank=True, null=True) genjed = models.CharField('генитив једнине', max_length=50, blank=True, null=True) datjed = models.CharField('датив једнине', max_length=50, blank=True, null=True) akujed = models.CharField('акузатив једнине', max_length=50, blank=True, null=True) vokjed = models.CharField('вокатив једнине', max_length=50, blank=True, null=True) insjed = models.CharField('инструментал једнине', max_length=50, blank=True, null=True) lokjed = models.CharField('локатив једнине', max_length=50, blank=True, null=True) nommno = models.CharField('номинатив множине', max_length=50, blank=True, null=True) genmno = models.CharField('генитив множине', max_length=50, blank=True, null=True) datmno = models.CharField('датив множине', max_length=50, blank=True, null=True) akumno = models.CharField('акузатив множине', max_length=50, blank=True, null=True) vokmno = models.CharField('вокатив множине', max_length=50, blank=True, null=True) insmno = models.CharField('инструментал множине', max_length=50, blank=True, null=True) lokmno = models.CharField('локатив множине', max_length=50, blank=True, null=True) vreme = models.DateTimeField('време последње измене', default=now) version = AutoIncVersionField() def __str__(self): return self.nomjed if self.nomjed else '-' class Meta: verbose_name = 'именица' verbose_name_plural = 'именице'
class Vulnerability(models.Model): class Meta: ordering = ("cve_id", ) id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) # CVSS V3 cve_id = models.CharField("CVE ID", max_length=14, default="CVE-0000-00000", unique=True) url = models.URLField( "URL", default="https://nvd.nist.gov/vuln/detail/CVE-YYYY-NNNNN", unique=True) """ 「攻撃に関する基準」 """ # 攻撃元区分 AV = [ ('ネットワーク', 'Network'), ('隣接', 'Adjacent'), ('ローカル', 'Local'), ('物理', 'Physical'), ] access_vector = models.CharField("攻撃元区分", max_length=8, choices=AV) # 攻撃の複雑さ AC = [ ('低', 'Low'), ('高', 'High'), ] access_complexity = models.CharField("攻撃条件の複雑さ", max_length=4, choices=AC) # 必要な特権レベル PR = [ ('不要', 'None'), ('低', 'Low'), ('高', 'High'), ] privileges_required = models.CharField("必要な特権レベル", max_length=4, choices=PR) # 必要なユーザ関与レベル UI = [ ('不要', 'None'), ('要', 'Required'), ] user_interaction = models.CharField("ユーザ関与レベル", max_length=8, choices=UI) # 攻撃された際の他方面への影響範囲の広がり S = [ ('変更なし', 'Unchanged'), ('変更あり', 'Changed'), ] scope = models.CharField("スコープ", max_length=9, choices=S) """ ここまで「攻撃に関する基準」 """ """ 「影響度」に関する基準 """ # 攻撃された際のシステム内の機密情報が漏洩する可能性(機密性に対する影響度) C = [ ('なし', 'None'), ('低', 'Low'), ('高', 'High'), ] confidentiality_impact = models.CharField("情報漏えいの可能性", max_length=4, choices=C) # 攻撃された場合の情報改ざんの可能性(完全性に対する影響度) I = [ ('なし', 'None'), ( '低', 'Low', ), ('高', 'High'), ] integrity_impact = models.CharField("情報改ざんの可能性", max_length=4, choices=I) # 攻撃された場合の業務が遅延・停止する可能性(可用性に対する影響度) A = [ ('なし', 'None'), ('低', 'Low'), ('高', 'High'), ] availability_impact = models.CharField("業務停止の可能性", max_length=4, choices=A) """ ここまで「影響度」に関する基準 """ base_score = models.DecimalField( max_digits=3, decimal_places=1, validators=[MinValueValidator(0.0), MaxValueValidator(10.0)], verbose_name="基本値") """ NVDにおける脆弱性分類 Weaknesses for Simplified Mapping of Published Vulnerabilities https://nvd.nist.gov/General/News/NVD-CWE-Slice-Update-2019 https://cwe.mitre.org/data/definitions/1003.html """ CWE = [ ('不適切な入力確認', 'CWE-20'), ('インジェクション', 'CWE-74'), ('不適切なエンコード、または出力のエスケープ', 'CWE-116'), ('バッファエラー', 'CWE-119'), ('情報漏えい', 'CWE-200'), ('不適切な権限管理', 'CWE-269'), ('不適切な認証', 'CWE-287'), ('重要なデータの暗号化の欠如', 'CWE-311'), ('不適切な暗号強度', 'CWE-326'), ('不完全、または危険な暗号アルゴリズムの使用', 'CWE-327'), ('不十分なランダム値の使用', 'CWE-330'), ('データの信頼性についての不十分な検証', 'CWE-345'), ('競合状態', 'CWE-362'), ('リソースの枯渇', 'CWE-400'), ('リソースの不適切なシャットダウンおよびリリース', 'CWE-404'), ('解釈の競合', 'CWE-436'), ('別領域リソースに対する外部からの制御可能な参照', 'CWE-610'), ('不適切な同期', 'CWE-662'), ('不適切な初期化', 'CWE-665'), ('誤った領域へのリソースの漏えい', 'CWE-668'), ('領域間での誤ったリソース移動', 'CWE-669'), ('常に不適切な制御フローの実装', 'CWE-670'), ('有効期限後または解放後のリソースの操作', 'CWE-672'), ('不適切な再帰制御', 'CWE-674'), ('計算の誤り', 'CWE-682'), ('不適切な比較', 'CWE-697'), ('不正な型変換またはキャスト', 'CWE-704'), ('誤って解決された名前や参照の使用', 'CWE-706'), ('重要なリソースに対する不適切なパーミッションの割り当て', 'CWE-732'), ('例外的な状態における不適切なチェック', 'CWE-754'), ('例外的な状態における不適切な処理', 'CWE-755'), ('過度な繰り返し', 'CWE-834'), ('認証の欠如', 'CWE-862'), ('不正な認証', 'CWE-863'), ('動的に操作されるコードリソースの不適切な制御', 'CWE-913'), ('重要な情報のセキュアでない格納', 'CWE-922'), ('その他', 'CWE-Other'), ] weakness_enumertation = models.CharField("脆弱性のタイプ", max_length=50, choices=CWE) overview = models.TextField("概要") solution = models.TextField("対策方法") vendor_information = models.TextField("ベンダ情報") creator = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, verbose_name="作成者", related_name="vulnerability_created_by") updater = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, verbose_name="更新者", related_name="vulnerability_updated_by") created_at = models.DateTimeField(auto_now_add=True, verbose_name="作成日時") updated_at = models.DateTimeField(auto_now=True, verbose_name="更新日時") affected_software = models.ManyToManyField(ProductVersion, verbose_name="影響を受けるシステム", related_name="vulnerability") ver = AutoIncVersionField("バージョン") def __str__(self): return self.cve_id
class Product(models.Model): # this field is for optimistic locking version = AutoIncVersionField() name = models.CharField(max_length=200, null=False, blank=False) last_modified = models.DateTimeField(auto_now=True)
def test_south_can_introspect_autoincversionfield(self): self.assertTrue(can_introspect(AutoIncVersionField()))