Exemple #1
0
class SystemVariable(models.Model):
    """Model to store system wide variable like account/invoice counter

    Never use this model directly and use the trionyx.config.variables
    """

    code = models.CharField(max_length=128, unique=True)
    value = models.JSONField()

    def __str__(self):
        """System variable representation"""
        return self.code
Exemple #2
0
class Log(models.BaseModel):
    """Log"""

    CRITICAL = 50
    ERROR = 40
    WARNING = 30
    INFO = 20
    DEBUG = 10
    NOTSET = 0

    LEVEL_CHOICES = [
        (CRITICAL, _('Critical')),
        (ERROR, _('Error')),
        (WARNING, _('Warning')),
        (INFO, _('Info')),
        (DEBUG, _('Debug')),
        (NOTSET, _('Not set')),
    ]

    log_hash = models.CharField(_('Log hash'), max_length=32)
    level = models.IntegerField(_('Level'), choices=LEVEL_CHOICES)
    message = models.TextField(_('Message'))
    file_path = models.CharField(_('File path'), max_length=256)
    file_line = models.IntegerField(_('File line'))
    traceback = models.TextField(_('Traceback'), default='')

    last_event = models.DateTimeField(_('Last event'))
    log_count = models.IntegerField(_('Log count'), default=1)

    objects = LogManager()  # type: ignore

    class Meta:
        """Model meta description"""

        verbose_name = _('Log')
        verbose_name_plural = _('Logs')
Exemple #3
0
class UserAttribute(models.Model):
    """User attribute to store system values for user"""

    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             models.CASCADE,
                             related_name='attributes')
    code = models.CharField(max_length=128, null=False)
    value = models.JSONField()

    objects = UserAttributeManager()

    class Meta:
        """Model meta description"""

        unique_together = ('user', 'code')

    def __str__(self):
        """User Attribute representation"""
        return self.code
Exemple #4
0
class Item(models.BaseModel):
    TYPE_FEATURE = 10
    TYPE_ENHANCEMENT = 20
    TYPE_TASK = 30
    TYPE_BUG = 40
    TYPE_QUESTION = 50

    TYPE_CHOICES = (
        (TYPE_FEATURE, _('Feature')),
        (TYPE_ENHANCEMENT, _('Enhancement')),
        (TYPE_TASK, _('Task')),
        (TYPE_BUG, _('Bug')),
        (TYPE_QUESTION, _('Question')),
    )

    PRIORITY_HIGHEST = 50
    PRIORITY_HIGH = 40
    PRIORITY_MEDIUM = 30
    PRIORITY_LOW = 20
    PRIORITY_LOWEST = 10

    PRIORITY_CHOICES = (
        (PRIORITY_HIGHEST, _('Highest')),
        (PRIORITY_HIGH, _('High')),
        (PRIORITY_MEDIUM, _('Medium')),
        (PRIORITY_LOW, _('Low')),
        (PRIORITY_LOWEST, _('Lowest')),
    )

    project = models.ForeignKey(Project,
                                related_name='items',
                                on_delete=models.CASCADE)
    item_type = models.IntegerField(choices=TYPE_CHOICES,
                                    default=TYPE_FEATURE,
                                    blank=True)
    priority = models.IntegerField(choices=PRIORITY_CHOICES,
                                   default=PRIORITY_MEDIUM,
                                   blank=True)

    code = models.CharField(max_length=32)
    name = models.CharField(max_length=256)
    description = models.TextField(default='', null=True, blank=True)
    completed_on = models.DateField(default=None, null=True, blank=True)

    estimate = models.FloatField(null=True, blank=True)
    non_billable = models.BooleanField(default=False, blank=True)

    # Item stats
    total_worked = models.FloatField(default=0.0, blank=True)
    total_billed = models.FloatField(default=0.0, blank=True)

    @property
    def estimate_used(self):
        return 0.0

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

        if not self.code and self.project:
            with CacheLock('set-item-code', self.project_id):
                self.project.refresh_from_db()  # get latest value
                self.project.item_increment_id += 1
                self.code = f"{self.project.code}-{self.project.item_increment_id}"
                self.save(update_fields=['code'])
                self.project.save(update_fields=['item_increment_id'])

    @classmethod
    def get_type_icon(cls, item_type):
        icon_mapping = {
            cls.TYPE_FEATURE: 'fa fa-star',
            cls.TYPE_ENHANCEMENT: 'fa fa-bolt',
            cls.TYPE_TASK: 'fa fa-check',
            cls.TYPE_BUG: 'fa fa-bug',
            cls.TYPE_QUESTION: 'fa fa-question-circle',
        }

        badge_mapping = {
            cls.TYPE_FEATURE: 'badge-feature',
            cls.TYPE_ENHANCEMENT: 'badge-enhancement',
            cls.TYPE_TASK: 'badge-task',
            cls.TYPE_BUG: 'badge-bug',
            cls.TYPE_QUESTION: 'badge-question',
        }

        return f"<span class='badge badge-icon {badge_mapping[item_type]}'><i class='{icon_mapping[item_type]}'></i></span>"

    @classmethod
    def get_priority_icon(cls, priority):
        icon = 'fa fa-long-arrow-up'
        if priority <= cls.PRIORITY_LOW:
            icon = 'fa fa-long-arrow-down'

        class_mapping = {
            cls.PRIORITY_HIGHEST: 'priority-icon-highest',
            cls.PRIORITY_HIGH: 'priority-icon-high',
            cls.PRIORITY_MEDIUM: 'priority-icon-medium',
            cls.PRIORITY_LOW: 'priority-icon-low',
            cls.PRIORITY_LOWEST: 'priority-icon-lowest',
        }

        return f"<i class='{class_mapping[priority]} {icon}'></i>"
Exemple #5
0
class Project(models.BaseModel):
    STATUS_DRAFT = 10
    STATUS_ACTIVE = 20
    STATUS_ON_HOLD = 30
    STATUS_COMPLETED = 40
    STATUS_CANCELED = 99

    STATUS_CHOICES = [
        (STATUS_DRAFT, _('Draft')),
        (STATUS_ACTIVE, _('Active')),
        (STATUS_ON_HOLD, _('On hold')),
        (STATUS_COMPLETED, _('Completed')),
        (STATUS_CANCELED, _('Canceled')),
    ]

    TYPE_FIXED = 10
    TYPE_HOURLY_BASED = 20

    TYPE_CHOICES = [
        (TYPE_FIXED, _('Fixed')),
        (TYPE_HOURLY_BASED, _('Hourly based')),
    ]

    # Connect Project to other Model
    for_object_type = models.ForeignKey(
        'contenttypes.ContentType',
        models.SET_NULL,
        blank=True,
        null=True,
        verbose_name=_('Object type'),
    )
    for_object_id = models.BigIntegerField(_('Object ID'),
                                           blank=True,
                                           null=True)
    for_object = GenericForeignKey('for_object_type', 'for_object_id')

    name = models.CharField(max_length=256)
    code = models.CharField(max_length=10, unique=True)
    status = models.IntegerField(choices=STATUS_CHOICES, default=STATUS_DRAFT)
    project_type = models.IntegerField(choices=TYPE_CHOICES,
                                       default=TYPE_FIXED)
    description = models.TextField(default='', null=True, blank=True)

    deadline = models.DateField(default=None, null=True, blank=True)
    started_on = models.DateField(default=None, null=True, blank=True)
    completed_on = models.DateField(default=None, null=True, blank=True)

    fixed_price = models.PriceField(null=True, blank=True)
    project_hourly_rate = models.PriceField(null=True, blank=True)

    item_increment_id = models.IntegerField(default=0)

    # Project stats
    open_items = models.IntegerField(default=0)
    completed_items = models.IntegerField(default=0)

    total_items_estimate = models.FloatField(default=0.0)
    total_worked = models.FloatField(default=0.0)
    total_billed = models.FloatField(default=0.0)

    @property
    def hourly_rate(self):
        return float(self.project_hourly_rate if self.
                     project_hourly_rate else app_settings.HOURLY_RATE)

    @property
    def estimate_used(self):
        return 0.0

    def save(self, *args, **kwargs):
        self.code = str(self.code).upper()
        super().save(*args, **kwargs)
Exemple #6
0
class User(models.BaseModel, AbstractBaseUser, PermissionsMixin):
    """User model"""

    email = models.EmailField(_('Email'), max_length=255, unique=True)
    first_name = models.CharField(_('First name'),
                                  max_length=64,
                                  blank=True,
                                  default='')
    last_name = models.CharField(_('Last name'),
                                 max_length=64,
                                 blank=True,
                                 default='')
    is_active = models.BooleanField(_('Active'), default=True)
    date_joined = models.DateTimeField(_('Date joined'), default=timezone.now)
    last_online = models.DateTimeField(_('Last online'), blank=True, null=True)
    avatar = models.ImageField(_('Avatar'),
                               blank=True,
                               upload_to='avatars/',
                               default='')

    language = models.CharField(_('Language'),
                                max_length=6,
                                choices=settings.LANGUAGES,
                                default=default_language)
    timezone = models.CharField(_('Timezone'),
                                max_length=32,
                                choices=TIMEZONES,
                                default=default_timezone)

    USERNAME_FIELD = 'email'

    objects = UserManager()

    class Meta:
        """Model meta description"""

        verbose_name = _('User')
        verbose_name_plural = _('Users')

    def get_full_name(self):
        """Get full username if no name is set email is given"""
        if self.first_name and self.last_name:
            return "{} {}".format(self.first_name, self.last_name)
        return self.email

    def get_short_name(self):
        """Get short name if no name is set email is given"""
        if self.first_name:
            return self.first_name
        return self.email

    def set_attribute(self, code, value):
        """Set user attribute"""
        models.get_class(UserAttribute).objects.set_attribute(
            self, code, value)

    def get_attribute(self, code, default=None):
        """Get user attribute"""
        return models.get_class(UserAttribute).objects.get_attribute(
            self, code, default)

    @contextmanager
    def locale_override(self):
        """Override locale settings to user settings"""
        with translation.override(self.language), timezone.override(
                self.timezone):
            yield

    def send_email(self,
                   subject,
                   body='',
                   html_template=None,
                   template_context=None,
                   files=None):
        """Send email to user"""
        if not body and not html_template:
            raise ValueError('You must supply a body or/and html_template')

        with self.locale_override():
            message = EmailMultiAlternatives(
                subject=subject,
                body=body,
                from_email=settings.DEFAULT_FROM_EMAIL,
                to=[self.email])

            if html_template:
                message.attach_alternative(
                    render_to_string(
                        html_template,
                        template_context if template_context else {}),
                    "text/html")

        if files:
            for file in files:
                message.attach(file.name, file.read())

        return message.send()
Exemple #7
0
class Task(models.BaseModel):
    """Task model"""

    SCHEDULED = 10
    QUEUE = 20
    LOCKED = 30
    RUNNING = 40
    COMPLETED = 50
    FAILED = 99

    STATUS_CHOICES = (
        (SCHEDULED, _('Scheduled')),
        (QUEUE, _('Queue')),
        (LOCKED, _('Locked')),
        (RUNNING, _('Running')),
        (COMPLETED, _('Completed')),
        (FAILED, _('Failed')),
    )

    celery_task_id = models.CharField(max_length=64, unique=True)
    status = models.IntegerField(_('Status'),
                                 choices=STATUS_CHOICES,
                                 default=QUEUE)
    identifier = models.CharField(_('Identifier'),
                                  max_length=255,
                                  default='not_set')
    description = models.TextField(_('Description'), default='')

    progress = models.PositiveIntegerField(_('Progress'), default=0)
    progress_output = models.JSONField(_('Progress output'), default=list)

    scheduled_at = models.DateTimeField(_('Scheduled at'),
                                        blank=True,
                                        null=True)
    started_at = models.DateTimeField(_('started at'), blank=True, null=True)
    execution_time = models.IntegerField(_('Execution time'), default=0)
    result = models.TextField(_('Result'), blank=True, default='')

    user = models.ForeignKey(settings.AUTH_USER_MODEL,
                             models.SET_NULL,
                             blank=True,
                             null=True,
                             verbose_name=_('Started by'))
    object_type = models.ForeignKey('contenttypes.ContentType',
                                    models.SET_NULL,
                                    blank=True,
                                    null=True,
                                    related_name='+',
                                    verbose_name=_('Object type'))
    object_id = models.BigIntegerField(_('Object ID'), blank=True, null=True)
    object = fields.GenericForeignKey('object_type', 'object_id')
    object_verbose_name = models.TextField(_('Object name'),
                                           blank=True,
                                           default='')

    class Meta:
        """Model meta description"""

        verbose_name = _('Task')
        verbose_name_plural = _('Tasks')

    def cancel_celery_task(self, kill=False):
        """
        Make sure we cancel the task (if in queue/scheduled).
        :param: kill Also kill the task if it's running, defaults to False.
        """
        celery_control = Control(current_app)
        celery_control.revoke(task_id=self.celery_task_id, terminate=kill)