Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 119 additions & 2 deletions server/mergin/sync/files.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@
import datetime
from enum import Enum
import os
from dataclasses import dataclass
from dataclasses import dataclass, field
from typing import Optional, List
import uuid
from flask import current_app
from marshmallow import ValidationError, fields, EXCLUDE, post_dump, validates_schema
from marshmallow import (
ValidationError,
fields,
EXCLUDE,
post_dump,
validates_schema,
post_load,
)
from pathvalidate import sanitize_filename

from .utils import (
Expand Down Expand Up @@ -234,3 +241,113 @@ def patch_field(self, data, **kwargs):
if not data.get("diff"):
data.pop("diff")
return data


@dataclass
class DeltaDiffFile:
"""Diff file path in diffs list"""

path: str


class DeltaChangeDiffFileSchema(ma.Schema):
"""Schema for diff file path in diffs list"""

path = fields.String(required=True)


@dataclass
class DeltaChangeBase(File):
"""Base class for changes stored in json list or returned from delta endpoint"""

change: PushChangeType
version: int


@dataclass
class DeltaChangeMerged(DeltaChangeBase):
"""Delta item with merged diffs to list of multiple diff files"""

diffs: List[DeltaDiffFile] = field(default_factory=list)

def to_data_delta(self):
"""Convert DeltaMerged to DeltaData with single diff"""
result = DeltaChange(
path=self.path,
size=self.size,
checksum=self.checksum,
change=self.change,
version=self.version,
)
if self.diffs:
result.diff = self.diffs[0].path
return result


@dataclass
class DeltaChange(DeltaChangeBase):
"""Change items stored in database as list of this item with single diff file"""

diff: Optional[str] = None

def to_merged(self) -> DeltaChangeMerged:
"""Convert to DeltaMerged with multiple diffs"""
result = DeltaChangeMerged(
path=self.path,
size=self.size,
checksum=self.checksum,
change=self.change,
version=self.version,
)
if self.diff:
result.diffs = [DeltaDiffFile(path=self.diff)]
return result


class DeltaChangeBaseSchema(ma.Schema):
"""Base schema for delta json and response from delta endpoint"""

path = fields.String(required=True)
size = fields.Integer(required=True)
checksum = fields.String(required=True)
version = fields.Integer(required=True)
change = fields.Enum(PushChangeType, by_value=True, required=True)


class DeltaChangeSchema(DeltaChangeBaseSchema):
"""Schema for change data in changes column"""

diff = fields.String(required=False)

@post_load
def make_object(self, data, **kwargs):
return DeltaChange(**data)

@post_dump
def patch_field(self, data, **kwargs):
# drop 'diff' key entirely if empty or None as database would expect
if not data.get("diff"):
data.pop("diff", None)
return data


class DeltaChangeItemSchema(DeltaChangeBaseSchema):
"""Schema for delta changes response"""

diffs = fields.List(fields.Nested(DeltaChangeDiffFileSchema()))

@post_dump
def patch_field(self, data, **kwargs):
# drop 'diffs' key entirely if empty or None as clients would expect
if not data.get("diffs"):
data.pop("diffs", None)
return data


class DeltaChangeRespSchema(ma.Schema):
"""Schema for list of delta changes wrapped in items field"""

items = fields.List(fields.Nested(DeltaChangeItemSchema()))

class Meta:
unknown = EXCLUDE
Loading
Loading