Source code for sortinghat.core.models

# -*- coding: utf-8 -*-
#
# Copyright (C) 2014-2020 Bitergia
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Authors:
#     Santiago Dueñas <sduenas@bitergia.com>
#     Miguel Ángel Fernández <mafesan@bitergia.com>
#

import datetime

import dateutil

from django.db.models import (CASCADE,
                              SET_NULL,
                              Model,
                              BooleanField,
                              CharField,
                              DateTimeField,
                              PositiveIntegerField,
                              ForeignKey,
                              OneToOneField)

from django.db.models import JSONField

from enum import Enum

from grimoirelab_toolkit.datetime import datetime_utcnow

from treebeard.mp_tree import MP_Node

# Default dates for periods
MIN_PERIOD_DATE = datetime.datetime(1900, 1, 1, 0, 0, 0,
                                    tzinfo=dateutil.tz.tzutc())
MAX_PERIOD_DATE = datetime.datetime(2100, 1, 1, 0, 0, 0,
                                    tzinfo=dateutil.tz.tzutc())

# Innodb and utf8mb4 can only index 191 characters
# For more information regarding this topic see:
# https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-conversion.html
MAX_SIZE_CHAR_INDEX = 191
MAX_SIZE_CHAR_FIELD = 128


[docs]class CreationDateTimeField(DateTimeField): """Field automatically set to the current date when an object is created.""" def __init__(self, *args, **kwargs): kwargs.setdefault('editable', False) kwargs.setdefault('default', datetime_utcnow) super().__init__(*args, **kwargs)
[docs]class LastModificationDateTimeField(DateTimeField): """Field automatically set to the current date on each save() call.""" def __init__(self, *args, **kwargs): kwargs.setdefault('editable', False) kwargs.setdefault('default', datetime_utcnow) super().__init__(*args, **kwargs)
[docs] def pre_save(self, model_instance, add): value = datetime_utcnow() setattr(model_instance, self.attname, value) return value
[docs]class EntityBase(Model): created_at = CreationDateTimeField() last_modified = LastModificationDateTimeField()
[docs] class Meta: abstract = True
[docs]class Transaction(Model): tuid = CharField(max_length=MAX_SIZE_CHAR_FIELD, primary_key=True) name = CharField(max_length=MAX_SIZE_CHAR_FIELD) created_at = DateTimeField() closed_at = DateTimeField(null=True) is_closed = BooleanField(default=False) authored_by = CharField(max_length=MAX_SIZE_CHAR_FIELD, null=True) class Meta: db_table = 'transactions' ordering = ('created_at', 'tuid') def __str__(self): return '%s - %s' % (self.tuid, self.name)
[docs]class Operation(Model):
[docs] class OpType(Enum): ADD = 'ADD' DELETE = 'DELETE' UPDATE = 'UPDATE'
[docs] @classmethod def choices(cls): return ((item.name, item.value) for item in cls)
def __str__(self): return self.value
ouid = CharField(max_length=MAX_SIZE_CHAR_FIELD, primary_key=True) op_type = CharField(max_length=MAX_SIZE_CHAR_FIELD, choices=OpType.choices()) entity_type = CharField(max_length=MAX_SIZE_CHAR_FIELD) target = CharField(max_length=MAX_SIZE_CHAR_FIELD) trx = ForeignKey(Transaction, related_name='operations', on_delete=CASCADE, db_column='tuid') timestamp = DateTimeField() args = JSONField() class Meta: db_table = 'operations' ordering = ('timestamp', 'ouid', 'trx') def __str__(self): return '%s - %s - %s - %s - %s' % (self.ouid, self.trx, self.op_type, self.entity_type, self.target)
[docs]class Organization(EntityBase): name = CharField(max_length=MAX_SIZE_CHAR_INDEX) class Meta: db_table = 'organizations' unique_together = ('name',) def __str__(self): return self.name
[docs]class Team(MP_Node, EntityBase): name = CharField(max_length=MAX_SIZE_CHAR_INDEX) organization = ForeignKey(Organization, related_name='teams', on_delete=CASCADE, blank=True, null=True) class Meta: db_table = 'teams' unique_together = ('name', 'organization',) def __str__(self): return self.name
[docs]class Domain(EntityBase): domain = CharField(max_length=MAX_SIZE_CHAR_FIELD) is_top_domain = BooleanField(default=False) organization = ForeignKey(Organization, related_name='domains', on_delete=CASCADE) class Meta: db_table = 'domains_organizations' unique_together = ('domain',) ordering = ('domain',) def __str__(self): return self.domain
[docs]class Country(EntityBase): code = CharField(max_length=2, primary_key=True) name = CharField(max_length=MAX_SIZE_CHAR_INDEX) alpha3 = CharField(max_length=3) class Meta: db_table = 'countries' unique_together = ('alpha3',) def __str__(self): return self.name
[docs]class Individual(EntityBase): mk = CharField(max_length=MAX_SIZE_CHAR_FIELD, primary_key=True) is_locked = BooleanField(default=False) class Meta: db_table = 'individuals' ordering = ('last_modified', 'created_at', 'profile__name',) def __str__(self): return self.mk
[docs]class Identity(EntityBase): uuid = CharField(max_length=MAX_SIZE_CHAR_FIELD, primary_key=True) name = CharField(max_length=MAX_SIZE_CHAR_FIELD, null=True) email = CharField(max_length=MAX_SIZE_CHAR_FIELD, null=True) username = CharField(max_length=MAX_SIZE_CHAR_FIELD, null=True) source = CharField(max_length=32) individual = ForeignKey(Individual, related_name='identities', on_delete=CASCADE, db_column='mk') class Meta: db_table = 'identities' unique_together = ('name', 'email', 'username', 'source', ) def __str__(self): return self.uuid
[docs]class Profile(EntityBase): individual = OneToOneField(Individual, related_name='profile', on_delete=CASCADE, db_column='mk') name = CharField(max_length=MAX_SIZE_CHAR_FIELD, null=True) email = CharField(max_length=MAX_SIZE_CHAR_FIELD, null=True) gender = CharField(max_length=32, null=True) gender_acc = PositiveIntegerField(null=True) is_bot = BooleanField(default=False, null=False) country = ForeignKey(Country, null=True, on_delete=SET_NULL, db_column='country_code') class Meta: db_table = 'profiles' def __str__(self): return self.individual.mk
[docs]class Enrollment(EntityBase): individual = ForeignKey(Individual, related_name='enrollments', on_delete=CASCADE, db_column='mk') organization = ForeignKey(Organization, related_name='enrollments', on_delete=CASCADE) start = DateTimeField(default=MIN_PERIOD_DATE) end = DateTimeField(default=MAX_PERIOD_DATE) class Meta: db_table = 'enrollments' unique_together = ('individual', 'organization', 'start', 'end',) ordering = ('start', 'end', ) def __str__(self): return '%s - %s' % (self.individual.mk, self.organization.name)
[docs]class MatchingBlacklist(EntityBase): excluded = CharField(max_length=MAX_SIZE_CHAR_FIELD, primary_key=True) class Meta: db_table = 'matching_blacklist'