MiniDocs/src/MiniDocs/LeDatabase.extension.st

221 lines
7.9 KiB
Smalltalk

Extension { #name : #LeDatabase }
{ #category : #'*MiniDocs' }
LeDatabase >> addPageCopy: aLePage [
| page |
page := LePage new.
page title: ('Copy of ', aLePage title,' (id: ', (page uid asString copyFrom: 1 to: 8), ')').
aLePage allChildrenDepthFirst do: [ :snippet | | newSnippet |
newSnippet := snippet class new.
newSnippet className = 'LeTextSnippet' ifTrue: [ newSnippet
string: snippet contentAsString ].
newSnippet className = 'LePharoSnippet' ifTrue: [ newSnippet code: snippet contentAsString ].
newSnippet uid: LeUID new.
page addSnippet: newSnippet.
newSnippet database: self.
self registerSnippet: newSnippet ].
self addPage: page.
^ page
]
{ #category : #'*MiniDocs' }
LeDatabase >> addPageFromMarkdeep: markdeepDocTree withRemote: externalDocLocation [
| remoteMetadata divSnippets dataSnippets snippets page |
divSnippets := (markdeepDocTree xpath: '//div[@st-class]') asOrderedCollection
collect: [ :xmlElement | xmlElement postCopy ].
remoteMetadata := Markdeep new metadataFromXML: markdeepDocTree.
remoteMetadata at: 'origin' put: externalDocLocation.
dataSnippets := self sanitizeMarkdeepSnippets: divSnippets withMetadata: remoteMetadata.
snippets := dataSnippets collect: [ :each | each asLepiterSnippet ].
page := LePage new
title: (remoteMetadata at: 'title');
basicUid: (UUID fromString36: (remoteMetadata at: 'id'));
createTime: (LeTime new time: (remoteMetadata at: 'created') asDateAndTime);
editTime: (LeTime new time: (remoteMetadata at: 'modified') asDateAndTime);
latestEditTime: (LeTime new time: (remoteMetadata at: 'modified') asDateAndTime);
createEmail: (remoteMetadata at: 'creator');
editEmail: (remoteMetadata at: 'modifier').
snippets do: [ :snippet | | currentParent |
page addSnippet: snippet.
currentParent := page detectParentSnippetWithUid: (snippet metadata at: 'parent').
snippet parent: currentParent.
].
page children
do: [ :snippet |
(self hasBlockUID: snippet uid)
ifTrue: [ | existingPage |
existingPage := self pages
detect: [ :pageTemp | pageTemp includesSnippetUid: snippet uid ].
self importErrorForLocal: existingPage withRemote: externalDocLocation.
^ self ]
ifFalse: [ snippet database: self.
self registerSnippet: snippet ] ].
self addPage: page.
^ page
]
{ #category : #'*MiniDocs' }
LeDatabase >> addPageFromMarkdeepUrl: aString [
| page |
page := self detectLocalPageForRemote: aString.
page
ifNotNil: [ :arg |
self importErrorForLocal: page withRemote: aString.
^ self ].
^ self addPageFromMarkdeep: (self docTreeForLink: aString) withRemote: aString
]
{ #category : #'*MiniDocs' }
LeDatabase >> detectLocalPageForRemote: markdeepDocUrl [
| markdeepHelper id remoteMetadata docTree |
markdeepHelper := Markdeep new.
docTree := self docTreeForLink: markdeepDocUrl.
remoteMetadata := markdeepHelper metadataFromXML: docTree.
id := remoteMetadata at: 'id' ifAbsent: [ nil ].
^ self pageWithID: id ifAbsent: [ ^ nil ].
]
{ #category : #'*MiniDocs' }
LeDatabase >> docTreeForLink: aString [
^ (XMLHTMLParser on: aString asUrl retrieveContents) parseDocument
]
{ #category : #'*MiniDocs' }
LeDatabase >> errorCardFor: error [
| keepButton overwriteButton backupButton errorMessageUI localPage errorKey |
errorKey := error keys first.
localPage := self pageWithID: errorKey.
keepButton := BrButton new
aptitude: BrGlamorousButtonWithIconAndLabelAptitude;
label: 'Keep existing local page';
icon: BrGlamorousVectorIcons cancel;
margin: (BlInsets left: 10);
action: [ :aButton |
aButton phlow spawnObject: localPage.
self errors removeKey: errorKey
].
overwriteButton := BrButton new
aptitude: BrGlamorousButtonWithIconAndLabelAptitude;
label: 'Overwrite with remote page';
icon: BrGlamorousVectorIcons edit;
action: [ :aButton |
self removePage: localPage.
aButton phlow spawnObject: (self addPageFromMarkdeepUrl: (error at: errorKey at: 'remote')).
self errors removeKey: errorKey
];
margin: (BlInsets left: 10).
backupButton := BrButton new
aptitude: BrGlamorousButtonWithIconAndLabelAptitude;
label: 'Backup local page';
icon: BrGlamorousVectorIcons changes;
action: [ :aButton | ];
margin: (BlInsets left: 10).
errorMessageUI := BrEditor new
aptitude: BrGlamorousRegularEditorAptitude new ;
text: (error at: errorKey at: 'message');
vFitContent.
^ { errorMessageUI. keepButton. overwriteButton. backupButton }
]
{ #category : #'*MiniDocs' }
LeDatabase >> errors [
^ self optionAt: 'errors' ifAbsentPut: [ Dictionary new ]
]
{ #category : #'*MiniDocs' }
LeDatabase >> gtViewErrorDetailsOn: aView [
<gtView>
^ aView explicit
title: 'Errors' translated;
priority: 5;
stencil: [ | container |
container := BlElement new
layout: BlFlowLayout new;
constraintsDo: [ :c |
c vertical fitContent.
c horizontal matchParent ];
padding: (BlInsets all: 10).
container
addChildren: (self errorCardFor: self errors)
].
]
{ #category : #'*MiniDocs' }
LeDatabase >> importErrorForLocal: page withRemote: externalDocLocation [
| message id error |
id := page uidString.
message := String streamContents: [ :stream |
stream
nextPutAll: 'IMPORTATION ERROR: A page with
';
nextPut: Character lf;
nextPutAll: ' id: ' , id;
nextPut: Character lf;
nextPutAll: ' title: ' , page contentAsString;
nextPut: Character lf;
nextPut: Character lf;
nextPutAll: 'already exists in this database and includes overlapping contents';
nextPut: Character lf;
nextPutAll: 'with the page you are trying to import from:
';
nextPut: Character lf;
nextPutAll: externalDocLocation;
nextPut: Character lf;
nextPut: Character lf;
nextPutAll:
'Please choose one of the following options to addres the issue:
' ].
error := Dictionary new
at: 'remote' put: externalDocLocation;
at: 'message' put: message ;
yourself.
self errors at: id put: error
]
{ #category : #'*MiniDocs' }
LeDatabase >> options [
^ options
]
{ #category : #'*MiniDocs' }
LeDatabase >> previewSanitizedPageFromMarkdeep: markdeepDocTree withRemote: externalDocLocation [
| remoteMetadata divSnippets divSnippetsSanitized |
divSnippets := (markdeepDocTree xpath: '//div[@st-class]') asOrderedCollection
collect: [ :xmlElement | xmlElement postCopy ].
remoteMetadata := Markdeep new metadataFromXML: markdeepDocTree.
remoteMetadata at: 'origin' put: externalDocLocation.
divSnippetsSanitized := self sanitizeMarkdeepSnippets: divSnippets withMetadata: remoteMetadata.
^ { divSnippets . divSnippetsSanitized . remoteMetadata }
]
{ #category : #'*MiniDocs' }
LeDatabase >> sanitizeMarkdeepSnippets: divSnippets withMetadata: remoteMetadata [
^ divSnippets collectWithIndex: [:markdeepDiv :i | | snippetData creationTime modificationTime timestampWarning |
snippetData := markdeepDiv asSnippetDictionary.
creationTime := snippetData at: 'created'.
modificationTime := snippetData at: 'modified'.
timestampWarning := [:timestamp | 'Modified timestamps: ', timestamp ,' date and time was replaced instead of nil value. See "origin" metadata for more historical traceability information.'].
(creationTime = 'nil' and: [ modificationTime ~= 'nil' ])
ifTrue: [
snippetData redefineTimestampsBefore: modificationTime.
snippetData addErrata: (timestampWarning value: 'creation').
snippetData at: 'origin' put: (remoteMetadata at: 'origin').
].
(creationTime = 'nil' and: [ modificationTime = 'nil' ])
ifTrue: [ | timeDiff |
timeDiff := divSnippets size - i. "Suggesting that last snippets were modified after the first ones."
modificationTime := (remoteMetadata at: 'created') asDateAndTime - timeDiff seconds.
snippetData redefineTimestampsBefore: modificationTime.
snippetData addErrata: (timestampWarning value: 'creation').
snippetData addErrata: (timestampWarning value: 'modification').
snippetData at: 'origin' put: (remoteMetadata at: 'origin').
].
snippetData.
]
]