diff options
Diffstat (limited to 'common/src')
| -rw-r--r-- | common/src/leap/soledad/common/couch.py | 98 | 
1 files changed, 16 insertions, 82 deletions
| diff --git a/common/src/leap/soledad/common/couch.py b/common/src/leap/soledad/common/couch.py index c003b14e..126c6b51 100644 --- a/common/src/leap/soledad/common/couch.py +++ b/common/src/leap/soledad/common/couch.py @@ -102,23 +102,8 @@ class CouchDocument(SoledadDocument):          """          SoledadDocument.__init__(self, doc_id, rev, json, has_conflicts)          self.couch_rev = None -        self._conflicts = None          self.transactions = None -    def _ensure_fetch_conflicts(self, get_conflicts_fun): -        """ -        Ensure conflict data has been fetched from the server. - -        :param get_conflicts_fun: A function which, given the document id and -                                  the couch revision, return the conflicted -                                  versions of the current document. -        :type get_conflicts_fun: function -        """ -        if self._conflicts is None: -            self._conflicts = get_conflicts_fun(self.doc_id, -                                                couch_rev=self.couch_rev) -        self.has_conflicts = len(self._conflicts) > 0 -      def get_conflicts(self):          """          Get the conflicted versions of the document. @@ -146,7 +131,7 @@ class CouchDocument(SoledadDocument):          :type doc: CouchDocument          """          if self._conflicts is None: -            raise Exception("Run self._ensure_fetch_conflicts first!") +            raise Exception("Fetch conflicts first!")          self._conflicts.append(doc)          self.has_conflicts = len(self._conflicts) > 0 @@ -158,7 +143,7 @@ class CouchDocument(SoledadDocument):          :type conflict_revs: [str]          """          if self._conflicts is None: -            raise Exception("Run self._ensure_fetch_conflicts first!") +            raise Exception("Fetch conflicts first!")          self._conflicts = filter(              lambda doc: doc.rev not in conflict_revs,              self._conflicts) @@ -731,7 +716,6 @@ class CouchDatabase(CommonBackend):          if check_for_conflicts \                  and '_attachments' in result \                  and 'u1db_conflicts' in result['_attachments']: -            doc.has_conflicts = True              doc.set_conflicts(                  self._build_conflicts(                      doc.doc_id, @@ -1025,7 +1009,7 @@ class CouchDatabase(CommonBackend):              conflicts.append(doc)          return conflicts -    def _get_conflicts(self, doc_id, couch_rev=None): +    def get_doc_conflicts(self, doc_id, couch_rev=None):          """          Get the conflicted versions of a document. @@ -1040,32 +1024,21 @@ class CouchDatabase(CommonBackend):          """          # request conflicts attachment from server          params = {} +        conflicts = []          if couch_rev is not None:              params['rev'] = couch_rev  # restric document's couch revision +        else: +            # TODO: move into resource logic! +            first_entry = self._get_doc(doc_id, check_for_conflicts=True) +            conflicts.append(first_entry)          resource = self._database.resource(doc_id, 'u1db_conflicts')          try:              response = resource.get_json(**params) -            return self._build_conflicts( +            return conflicts + self._build_conflicts(                  doc_id, json.loads(response[2].read()))          except ResourceNotFound:              return [] -    def get_doc_conflicts(self, doc_id): -        """ -        Get the list of conflicts for the given document. - -        The order of the conflicts is such that the first entry is the value -        that would be returned by "get_doc". - -        :return: A list of the document entries that are conflicted. -        :rtype: [CouchDocument] -        """ -        conflict_docs = self._get_conflicts(doc_id) -        if len(conflict_docs) == 0: -            return [] -        this_doc = self._get_doc(doc_id, check_for_conflicts=True) -        return [this_doc] + conflict_docs -      def _get_replica_gen_and_trans_id(self, other_replica_uid):          """          Return the last known generation and transaction id for the other db @@ -1189,43 +1162,6 @@ class CouchDatabase(CommonBackend):          except ResourceNotFound as e:              raise_missing_design_doc_error(e, ddoc_path) -    def _add_conflict(self, doc, my_doc_rev, my_content): -        """ -        Add a conflict to the document. - -        Note that this method does not actually update the backend; rather, it -        updates the CouchDocument object which will provide the conflict data -        when the atomic document update is made. - -        :param doc: The document to have conflicts added to. -        :type doc: CouchDocument -        :param my_doc_rev: The revision of the conflicted document. -        :type my_doc_rev: str -        :param my_content: The content of the conflicted document as a JSON -                           serialized string. -        :type my_content: str -        """ -        doc._ensure_fetch_conflicts(self._get_conflicts) -        doc.add_conflict( -            self._factory(doc_id=doc.doc_id, rev=my_doc_rev, -                          json=my_content)) - -    def _delete_conflicts(self, doc, conflict_revs): -        """ -        Delete the conflicted revisions from the list of conflicts of C{doc}. - -        Note that this method does not actually update the backend; rather, it -        updates the CouchDocument object which will provide the conflict data -        when the atomic document update is made. - -        :param doc: The document to have conflicts deleted. -        :type doc: CouchDocument -        :param conflict_revs: A list of the revisions to be deleted. -        :param conflict_revs: [str] -        """ -        doc._ensure_fetch_conflicts(self._get_conflicts) -        doc.delete_conflicts(conflict_revs) -      def _prune_conflicts(self, doc, doc_vcr):          """          Prune conflicts that are older then the current document's revision, or @@ -1251,7 +1187,7 @@ class CouchDatabase(CommonBackend):              if autoresolved:                  doc_vcr.increment(self._replica_uid)                  doc.rev = doc_vcr.as_str() -            self._delete_conflicts(doc, c_revs_to_prune) +            doc.delete_conflicts(c_revs_to_prune)      def _force_doc_sync_conflict(self, doc):          """ @@ -1262,8 +1198,7 @@ class CouchDatabase(CommonBackend):          """          my_doc = self._get_doc(doc.doc_id, check_for_conflicts=True)          self._prune_conflicts(doc, vectorclock.VectorClockRev(doc.rev)) -        self._add_conflict(doc, my_doc.rev, my_doc.get_json()) -        doc.has_conflicts = True +        doc.add_conflict(my_doc)          self._put_doc(my_doc, doc)      def resolve_doc(self, doc, conflicted_doc_revs): @@ -1308,14 +1243,14 @@ class CouchDatabase(CommonBackend):              # the newer doc version will supersede the one in the database, so              # we copy conflicts before updating the backend.              doc.set_conflicts(cur_doc.get_conflicts())  # copy conflicts over. -            self._delete_conflicts(doc, superseded_revs) +            doc.delete_conflicts(superseded_revs)              self._put_doc(cur_doc, doc)          else:              # the newer doc version does not supersede the one in the              # database, so we will add a conflict to the database and copy              # those over to the document the user has in her hands. -            self._add_conflict(cur_doc, new_rev, doc.get_json()) -            self._delete_conflicts(cur_doc, superseded_revs) +            cur_doc.add_conflict(doc) +            cur_doc.delete_conflicts(superseded_revs)              self._put_doc(cur_doc, cur_doc)  # just update conflicts              # backend has been updated with current conflicts, now copy them              # to the current document. @@ -1405,10 +1340,9 @@ class CouchDatabase(CommonBackend):          if cur_doc is None:              self._put_doc(cur_doc, doc)              return 'inserted' -        else: -            doc.couch_rev = cur_doc.couch_rev +        doc.couch_rev = cur_doc.couch_rev +        doc.set_conflicts(self.get_doc_conflicts(doc.doc_id, doc.couch_rev))          # fetch conflicts because we will eventually manipulate them -        doc._ensure_fetch_conflicts(self._get_conflicts)          # from now on, it works just like u1db sqlite backend          doc_vcr = vectorclock.VectorClockRev(doc.rev)          cur_vcr = vectorclock.VectorClockRev(cur_doc.rev) | 
