blob: f7fb321ab413389e288894fec6adfa693bb2bf03 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import difflib
import functools
import logging
import uuid
from django.db import models
from django.urls import reverse
logger = logging.getLogger(__name__)
class Product(models.Model):
prefix = models.TextField(primary_key=True)
name = models.TextField()
description = models.TextField(blank=True, null=True)
owner = models.TextField(blank=True, null=True)
class Meta:
db_table = 'bloodhound_product'
class ProductConfig(models.Model):
"""Possibly legacy table - keeping for now"""
product = models.ForeignKey(Product, on_delete=models.CASCADE)
section = models.TextField()
option = models.TextField()
value = models.TextField(blank=True, null=True)
class Meta:
db_table = 'bloodhound_productconfig'
unique_together = (('product', 'section', 'option'),)
class ProductResourceMap(models.Model):
"""Possibly legacy model - keeping for now"""
product_id = models.ForeignKey(Product, on_delete=models.CASCADE)
resource_type = models.TextField(blank=True, null=True)
resource_id = models.TextField(blank=True, null=True)
class Meta:
db_table = 'bloodhound_productresourcemap'
class ModelCommon(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
created = models.DateTimeField(auto_now_add=True, editable=False)
class Meta:
abstract = True
class Ticket(ModelCommon):
def api_url(self):
return reverse('ticket-detail', args=(self.id,))
def api_events_url(self):
return reverse('changeevent-list', args=(self.id,))
def last_update(self):
last_event = self.changeevent_set.order_by('created').last()
return self.created if last_event is None else last_event.created
def add_field_event(self, field, newvalue):
current_lines = self.get_field_value(field).splitlines(keepends=True)
replace_lines = newvalue.splitlines(keepends=True)
result = '\n'.join(difflib.ndiff(current_lines, replace_lines))
tfield, created = TicketField.objects.get_or_create(name=field)
c = ChangeEvent(ticket=self, field=tfield, diff=result)
c.save()
def get_field_value(self, field):
try:
tfield = TicketField.objects.get(name=field)
except TicketField.DoesNotExist as e:
return ''
event = self.changeevent_set.filter(field=tfield).order_by('created').last()
return '' if event is None else event.value()
class TicketField(ModelCommon):
name = models.CharField(max_length=32)
def api_url(self):
return reverse('ticketfield-detail', args=(self.id,))
class ChangeEvent(ModelCommon):
ticket = models.ForeignKey(Ticket, models.CASCADE, null=False)
field = models.ForeignKey(TicketField, models.CASCADE)
diff = models.TextField()
def value(self, which=2):
return ''.join(difflib.restore(self.diff.splitlines(keepends=True), which)).strip()
old_value = functools.partialmethod(value, which=1)
def __str__(self):
return "Change to: {}; Field: {}; Diff: {}".format(
self.ticket, self.field, self.diff)
def api_url(self):
return reverse('changeevent-detail', args=(self.ticket.id, self.id,))
def api_ticket_url(self):
return reverse('ticket-detail', args=(self.ticket.id,))