(destinationID: string, force: string|boolean, authorId = '')
| 729 | } |
| 730 | |
| 731 | async copyPadWithoutHistory(destinationID: string, force: string|boolean, authorId = '') { |
| 732 | // flush the source pad |
| 733 | this.saveToDatabase(); |
| 734 | |
| 735 | // if it's a group pad, let's make sure the group exists. |
| 736 | const destGroupID = await this.checkIfGroupExistAndReturnIt(destinationID); |
| 737 | |
| 738 | // if force is true and already exists a Pad with the same id, remove that Pad |
| 739 | await this.removePadIfForceIsTrueAndAlreadyExist(destinationID, force); |
| 740 | |
| 741 | await this.copyAuthorInfoToDestinationPad(destinationID); |
| 742 | |
| 743 | // Group pad? Add it to the group's list |
| 744 | if (destGroupID) { |
| 745 | await db.setSub(`group:${destGroupID}`, ['pads', destinationID], 1); |
| 746 | } |
| 747 | |
| 748 | // initialize the pad with a new line to avoid getting the defaultText |
| 749 | const dstPad = await padManager.getPad(destinationID, '\n', authorId); |
| 750 | dstPad.pool = this.pool.clone(); |
| 751 | |
| 752 | const oldAText = this.atext; |
| 753 | |
| 754 | // The author to attribute inserts to when the historical op lacks |
| 755 | // one (legacy server-internal flows / .etherpad imports). Caller- |
| 756 | // supplied authorId wins; otherwise the stable system author. |
| 757 | // appendRevision now requires every insert to carry an author, so |
| 758 | // unattributed ops in the source pad would otherwise throw here. |
| 759 | const replayAuthorId = authorId || Pad.SYSTEM_AUTHOR_ID; |
| 760 | |
| 761 | // based on Changeset.makeSplice |
| 762 | const assem = new SmartOpAssembler(); |
| 763 | for (const op of opsFromAText(oldAText)) { |
| 764 | if (op.opcode === '+') { |
| 765 | const map = AttributeMap.fromString(op.attribs, dstPad.pool); |
| 766 | if (!map.get('author')) { |
| 767 | map.set('author', replayAuthorId); |
| 768 | op.attribs = map.toString(); |
| 769 | } |
| 770 | } |
| 771 | assem.append(op); |
| 772 | } |
| 773 | assem.endDocument(); |
| 774 | |
| 775 | // although we have instantiated the dstPad with '\n', an additional '\n' is |
| 776 | // added internally, so the pad text on the revision 0 is "\n\n" |
| 777 | const oldLength = 2; |
| 778 | |
| 779 | const newLength = assem.getLengthChange(); |
| 780 | const newText = oldAText.text; |
| 781 | |
| 782 | // create a changeset that removes the previous text and add the newText with |
| 783 | // all atributes present on the source pad |
| 784 | const changeset = pack(oldLength, newLength, assem.toString(), newText); |
| 785 | dstPad.appendRevision(changeset, authorId); |
| 786 | |
| 787 | await hooks.aCallAll('padCopy', { |
| 788 | get originalPad() { |
no test coverage detected