Import and export timelines
parent
f3d1de684d
commit
ce3d9aaf48
|
@ -65,6 +65,14 @@ def store_user_stories(project, data):
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def store_timeline_entries(project, data):
|
||||||
|
results = []
|
||||||
|
for timeline in data.get('timeline', []):
|
||||||
|
tl = service.store_timeline_entry(project, timeline)
|
||||||
|
results.append(tl)
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
def store_issues(project, data):
|
def store_issues(project, data):
|
||||||
issues = []
|
issues = []
|
||||||
for issue in data.get('issues', []):
|
for issue in data.get('issues', []):
|
||||||
|
@ -167,4 +175,11 @@ def dict_to_project(data, owner=None):
|
||||||
|
|
||||||
store_tags_colors(proj, data)
|
store_tags_colors(proj, data)
|
||||||
|
|
||||||
|
if service.get_errors(clear=False):
|
||||||
|
raise TaigaImportError('error importing colors')
|
||||||
|
|
||||||
|
store_timeline_entries(proj, data)
|
||||||
|
if service.get_errors(clear=False):
|
||||||
|
raise TaigaImportError('error importing timelines')
|
||||||
|
|
||||||
return proj
|
return proj
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
import copy
|
||||||
import os
|
import os
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
@ -39,6 +40,8 @@ from taiga.projects.milestones import models as milestones_models
|
||||||
from taiga.projects.wiki import models as wiki_models
|
from taiga.projects.wiki import models as wiki_models
|
||||||
from taiga.projects.history import models as history_models
|
from taiga.projects.history import models as history_models
|
||||||
from taiga.projects.attachments import models as attachments_models
|
from taiga.projects.attachments import models as attachments_models
|
||||||
|
from taiga.timeline import models as timeline_models
|
||||||
|
from taiga.timeline import service as timeline_service
|
||||||
from taiga.users import models as users_models
|
from taiga.users import models as users_models
|
||||||
from taiga.projects.votes import services as votes_service
|
from taiga.projects.votes import services as votes_service
|
||||||
from taiga.projects.history import services as history_service
|
from taiga.projects.history import services as history_service
|
||||||
|
@ -548,6 +551,39 @@ class WikiLinkExportSerializer(serializers.ModelSerializer):
|
||||||
exclude = ('id', 'project')
|
exclude = ('id', 'project')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TimelineDataField(serializers.WritableField):
|
||||||
|
read_only = False
|
||||||
|
|
||||||
|
def to_native(self, data):
|
||||||
|
new_data = copy.deepcopy(data)
|
||||||
|
try:
|
||||||
|
user = users_models.User.objects.get(pk=new_data["user"]["id"])
|
||||||
|
new_data["user"]["email"] = user.email
|
||||||
|
del new_data["user"]["id"]
|
||||||
|
except users_models.User.DoesNotExist:
|
||||||
|
pass
|
||||||
|
return new_data
|
||||||
|
|
||||||
|
def from_native(self, data):
|
||||||
|
new_data = copy.deepcopy(data)
|
||||||
|
try:
|
||||||
|
user = users_models.User.objects.get(email=new_data["user"]["email"])
|
||||||
|
new_data["user"]["id"] = user.id
|
||||||
|
del new_data["user"]["email"]
|
||||||
|
except users_models.User.DoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return new_data
|
||||||
|
|
||||||
|
|
||||||
|
class TimelineExportSerializer(serializers.ModelSerializer):
|
||||||
|
data = TimelineDataField()
|
||||||
|
class Meta:
|
||||||
|
model = timeline_models.Timeline
|
||||||
|
exclude = ('id', 'project', 'namespace', 'object_id')
|
||||||
|
|
||||||
|
|
||||||
class ProjectExportSerializer(serializers.ModelSerializer):
|
class ProjectExportSerializer(serializers.ModelSerializer):
|
||||||
owner = UserRelatedField(required=False)
|
owner = UserRelatedField(required=False)
|
||||||
default_points = serializers.SlugRelatedField(slug_field="name", required=False)
|
default_points = serializers.SlugRelatedField(slug_field="name", required=False)
|
||||||
|
@ -579,7 +615,12 @@ class ProjectExportSerializer(serializers.ModelSerializer):
|
||||||
anon_permissions = PgArrayField(required=False)
|
anon_permissions = PgArrayField(required=False)
|
||||||
public_permissions = PgArrayField(required=False)
|
public_permissions = PgArrayField(required=False)
|
||||||
modified_date = serializers.DateTimeField(required=False)
|
modified_date = serializers.DateTimeField(required=False)
|
||||||
|
timeline = serializers.SerializerMethodField("get_timeline")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = projects_models.Project
|
model = projects_models.Project
|
||||||
exclude = ('id', 'creation_template', 'members')
|
exclude = ('id', 'creation_template', 'members')
|
||||||
|
|
||||||
|
def get_timeline(self, obj):
|
||||||
|
timeline_qs = timeline_service.get_project_timeline(obj)
|
||||||
|
return TimelineExportSerializer(timeline_qs, many=True).data
|
||||||
|
|
|
@ -23,6 +23,7 @@ from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
|
||||||
from taiga.projects.history.services import make_key_from_model_object
|
from taiga.projects.history.services import make_key_from_model_object
|
||||||
|
from taiga.timeline.service import build_project_namespace
|
||||||
from taiga.projects.references import sequences as seq
|
from taiga.projects.references import sequences as seq
|
||||||
from taiga.projects.references import models as refs
|
from taiga.projects.references import models as refs
|
||||||
from taiga.projects.services import find_invited_user
|
from taiga.projects.services import find_invited_user
|
||||||
|
@ -275,6 +276,19 @@ def store_attachment(project, obj, attachment):
|
||||||
return serialized
|
return serialized
|
||||||
|
|
||||||
|
|
||||||
|
def store_timeline_entry(project, timeline):
|
||||||
|
serialized = serializers.TimelineExportSerializer(data=timeline, context={"project": project})
|
||||||
|
if serialized.is_valid():
|
||||||
|
serialized.object.project = project
|
||||||
|
serialized.object.namespace = build_project_namespace(project)
|
||||||
|
serialized.object.object_id = project.id
|
||||||
|
serialized.object._importing = True
|
||||||
|
serialized.save()
|
||||||
|
return serialized
|
||||||
|
add_errors("timeline", serialized.errors)
|
||||||
|
return serialized
|
||||||
|
|
||||||
|
|
||||||
def store_history(project, obj, history):
|
def store_history(project, obj, history):
|
||||||
serialized = serializers.HistoryExportSerializer(data=history, context={"project": project})
|
serialized = serializers.HistoryExportSerializer(data=history, context={"project": project})
|
||||||
if serialized.is_valid():
|
if serialized.is_valid():
|
||||||
|
|
|
@ -76,6 +76,8 @@ class HistoryEntry(models.Model):
|
||||||
# snapshot. The rest are partial snapshot.
|
# snapshot. The rest are partial snapshot.
|
||||||
is_snapshot = models.BooleanField(default=False)
|
is_snapshot = models.BooleanField(default=False)
|
||||||
|
|
||||||
|
_importing = None
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def is_change(self):
|
def is_change(self):
|
||||||
return self.type == HistoryType.change
|
return self.type == HistoryType.change
|
||||||
|
|
|
@ -29,8 +29,8 @@ class Timeline(models.Model):
|
||||||
content_type = models.ForeignKey(ContentType, related_name="content_type_timelines")
|
content_type = models.ForeignKey(ContentType, related_name="content_type_timelines")
|
||||||
object_id = models.PositiveIntegerField()
|
object_id = models.PositiveIntegerField()
|
||||||
content_object = GenericForeignKey('content_type', 'object_id')
|
content_object = GenericForeignKey('content_type', 'object_id')
|
||||||
namespace = models.SlugField(default="default")
|
namespace = models.CharField(max_length=250, default="default", db_index=True)
|
||||||
event_type = models.SlugField()
|
event_type = models.CharField(max_length=250, db_index=True)
|
||||||
project = models.ForeignKey(Project)
|
project = models.ForeignKey(Project)
|
||||||
data = JsonField()
|
data = JsonField()
|
||||||
data_content_type = models.ForeignKey(ContentType, related_name="data_timelines")
|
data_content_type = models.ForeignKey(ContentType, related_name="data_timelines")
|
||||||
|
|
|
@ -71,6 +71,9 @@ def _push_to_timelines(project, user, obj, event_type, extra_data={}):
|
||||||
|
|
||||||
|
|
||||||
def on_new_history_entry(sender, instance, created, **kwargs):
|
def on_new_history_entry(sender, instance, created, **kwargs):
|
||||||
|
if instance._importing:
|
||||||
|
return
|
||||||
|
|
||||||
if instance.is_hidden:
|
if instance.is_hidden:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue