From 47611d9f8b527f82d60efa426fa4ca552b2f4d1b Mon Sep 17 00:00:00 2001 From: NessArt Date: Fri, 30 Jun 2023 11:23:56 +0200 Subject: [PATCH 01/54] zwischenstand mit div und innerHtml --- .../app/base-editor/base-editor.component.css | 8 +++++- .../base-editor/base-editor.component.html | 13 ++++++++-- .../app/base-editor/base-editor.component.ts | 25 +++++++++++++++++++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.css b/frontend/src/app/base-editor/base-editor.component.css index 0d69e7051..7583d6540 100644 --- a/frontend/src/app/base-editor/base-editor.component.css +++ b/frontend/src/app/base-editor/base-editor.component.css @@ -418,4 +418,10 @@ input.scenario, input.background { width: 11px !important; height: 11px !important; - } \ No newline at end of file + } + + .regex-expression { + color: var(--ocean-blue); + font-weight: bold; + /* Add any other desired styles */ +} diff --git a/frontend/src/app/base-editor/base-editor.component.html b/frontend/src/app/base-editor/base-editor.component.html index f2d1e90ad..21da95998 100644 --- a/frontend/src/app/base-editor/base-editor.component.html +++ b/frontend/src/app/base-editor/base-editor.component.html @@ -95,8 +95,17 @@
- + +
+
diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index cde43bc40..d44284d1b 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -141,6 +141,9 @@ export class BaseEditorComponent { exampleChild: ExampleTableComponent; + @ViewChild('textField1') textField1: ElementRef; + regexDetected: boolean = false; + /** * Subscribtions for all EventEmitter */ @@ -269,6 +272,7 @@ export class BaseEditorComponent { if (this.exampleChildren.last != undefined) { this.exampleChild = this.exampleChildren.last; } + this.textField1.nativeElement.addEventListener('input', this.highlightRegex.bind(this)); } /** @@ -1677,4 +1681,25 @@ export class BaseEditorComponent { this.markUnsaved(); } + highlightRegex() { // /[a-z]+\d+/gi + console.log('in hightlight') + const regexPattern = /\/[^\n\/]+\/[a-z]*/gi; // Regex pattern to recognize and highlight regex expressions + const textContent = this.textField1.nativeElement.textContent; + const regexMatchedText = textContent.match(regexPattern); + console.log(textContent) + console.log(regexMatchedText) + + if (regexMatchedText) { + this.regexDetected = true; + + const highlightedText = textContent.replace(regexPattern, (match) => { + return `${match}`; + }); + + this.textField1.nativeElement.innerHTML = highlightedText; + } else { + this.regexDetected = false; + } + } + } From 7e5f77ddbfdc05c4a2383762d99d0233f72de6e4 Mon Sep 17 00:00:00 2001 From: NessArt Date: Thu, 6 Jul 2023 13:27:25 +0200 Subject: [PATCH 02/54] zwischenstand mit div und ohne innerHtml aber position fehler --- .../app/base-editor/base-editor.component.css | 11 +- .../base-editor/base-editor.component.html | 7 +- .../app/base-editor/base-editor.component.ts | 152 +++++++++++++++--- 3 files changed, 138 insertions(+), 32 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.css b/frontend/src/app/base-editor/base-editor.component.css index 7583d6540..de9074103 100644 --- a/frontend/src/app/base-editor/base-editor.component.css +++ b/frontend/src/app/base-editor/base-editor.component.css @@ -420,8 +420,11 @@ input.scenario, input.background { } - .regex-expression { - color: var(--ocean-blue); - font-weight: bold; - /* Add any other desired styles */ +.content_editable_element { /*not needed !?*/ + white-space: pre-wrap; /* css-3 */ + white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + word-wrap: break-word; /* Internet Explorer 5.5+ */ } + diff --git a/frontend/src/app/base-editor/base-editor.component.html b/frontend/src/app/base-editor/base-editor.component.html index 21da95998..72371664d 100644 --- a/frontend/src/app/base-editor/base-editor.component.html +++ b/frontend/src/app/base-editor/base-editor.component.html @@ -98,13 +98,14 @@
+ +
diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index d44284d1b..7adbb085e 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -1,7 +1,7 @@ import { ApiService } from 'src/app/Services/api.service'; import { CopyExampleToast } from '../copyExample-toast'; import { CdkDragDrop, CdkDragStart, DragRef, moveItemInArray } from '@angular/cdk/drag-drop'; -import { Component, ElementRef, Input, QueryList, ViewChild, ViewChildren } from '@angular/core'; +import { Component, ElementRef, Input, QueryList, Renderer2, ViewChild, ViewChildren } from '@angular/core'; import { ToastrService } from 'ngx-toastr'; import { AddBlockFormComponent } from '../modals/add-block-form/add-block-form.component'; import { NewStepRequestComponent } from '../modals/new-step-request/new-step-request.component'; @@ -141,7 +141,7 @@ export class BaseEditorComponent { exampleChild: ExampleTableComponent; - @ViewChild('textField1') textField1: ElementRef; + //@ViewChild('textField1', { static: true }) textField1: ElementRef; regexDetected: boolean = false; /** @@ -160,7 +160,8 @@ export class BaseEditorComponent { public exampleService: ExampleService, public scenarioService: ScenarioService, public backgroundService: BackgroundService, - public apiService: ApiService) {} + public apiService: ApiService, + private renderer: Renderer2) {} ngOnInit(): void { this.addBlocktoScenarioObservable = this.blockService.addBlockToScenarioEvent.subscribe(block => { @@ -252,6 +253,9 @@ export class BaseEditorComponent { } ngAfterViewInit(): void { + const textField = document.getElementById('textField1'); + textField.addEventListener('input', this.highlightRegex.bind(this)); + this.step_type_input.changes.subscribe(_ => { this.step_type_input.forEach(in_field => { if ( in_field.nativeElement.id === this.lastToFocus) { @@ -272,7 +276,6 @@ export class BaseEditorComponent { if (this.exampleChildren.last != undefined) { this.exampleChild = this.exampleChildren.last; } - this.textField1.nativeElement.addEventListener('input', this.highlightRegex.bind(this)); } /** @@ -1681,25 +1684,124 @@ export class BaseEditorComponent { this.markUnsaved(); } - highlightRegex() { // /[a-z]+\d+/gi - console.log('in hightlight') - const regexPattern = /\/[^\n\/]+\/[a-z]*/gi; // Regex pattern to recognize and highlight regex expressions - const textContent = this.textField1.nativeElement.textContent; - const regexMatchedText = textContent.match(regexPattern); - console.log(textContent) - console.log(regexMatchedText) - - if (regexMatchedText) { - this.regexDetected = true; - - const highlightedText = textContent.replace(regexPattern, (match) => { - return `${match}`; - }); - - this.textField1.nativeElement.innerHTML = highlightedText; - } else { - this.regexDetected = false; + /*highlightRegex() { // with input field + hi + const regexPattern = // Regex pattern to recognize and highlight regex expressions + + const divElement = document.getElementById('textField1'); + const selection = window.getSelection(); + + // Store the current selection position + const selectionStart = selection ? selection.anchorOffset : 0; + + const textContent = divElement.innerText || ''; + + const regexMatchedText = textContent.match(regexPattern); + const regexDetected = regexMatchedText !== null; + + // Clear previous styling + divElement.innerHTML = ''; + + if (regexDetected) { + const fragment = document.createDocumentFragment(); + let currentIndex = 0; + + for (const match of regexMatchedText) { + const startIndex = textContent.indexOf(match, currentIndex); + const nonRegexPart = textContent.substring(currentIndex, startIndex); + + if (nonRegexPart) { + const nonRegexNode = document.createTextNode(nonRegexPart); + fragment.appendChild(nonRegexNode); + } + + const span = document.createElement('span'); + span.style.color = 'var(--ocean-blue)'; + span.style.fontWeight = 'bold'; + span.textContent = match; + fragment.appendChild(span); + + currentIndex = startIndex + match.length; + } + + const remainingText = textContent.substring(currentIndex); + if (remainingText) { + const remainingTextNode = document.createTextNode(remainingText); + fragment.appendChild(remainingTextNode); + } + + divElement.appendChild(fragment); + } else { + // No regex matches, simply set the text content + divElement.innerText = textContent; + } + + // Restore the cursor position + if (selection) { + const updatedLength = divElement.innerText.length; + const updatedStart = Math.min(selectionStart, updatedLength); + const updatedEnd = Math.min(selectionStart, updatedLength); + + selection.removeAllRanges(); + const range = document.createRange(); + range.setStart(divElement.firstChild, updatedStart); + range.setEnd(divElement.firstChild, updatedEnd); + selection.addRange(range); + } + }*/ + highlightRegex() { // div but cursor position bad + const regexPattern = /\/[^\n\/]+\/[a-z]*/gi; // Regex pattern to recognize and highlight regex expressions + + const textField = document.getElementById('textField1'); + const textContent = textField.textContent; + + const regexMatchedText = textContent.match(regexPattern); + this.regexDetected = regexMatchedText !== null; + + // Clear previous styling + this.renderer.setStyle(textField, 'color', ''); + this.renderer.setStyle(textField, 'fontWeight', ''); + + if (this.regexDetected) { + const matches: RegExpExecArray[] = []; + let match: RegExpExecArray | null; + + while ((match = regexPattern.exec(textContent)) !== null) { + matches.push(match); + } + + const fragment = document.createDocumentFragment(); + let currentIndex = 0; + + for (const match of matches) { + const nonRegexPart = textContent.substring(currentIndex, match.index); + const matchText = match[0]; + + if (nonRegexPart) { + const nonRegexNode = document.createTextNode(nonRegexPart); + fragment.appendChild(nonRegexNode); + } + + const span = document.createElement('span'); + span.style.color = 'var(--ocean-blue)'; + span.style.fontWeight = 'bold'; + span.appendChild(document.createTextNode(matchText)); + fragment.appendChild(span); + + currentIndex = match.index + matchText.length; + } + + const remainingText = textContent.substring(currentIndex); + if (remainingText) { + const remainingTextNode = document.createTextNode(remainingText); + fragment.appendChild(remainingTextNode); + } + + while (textField.firstChild) { + textField.removeChild(textField.firstChild); + } + + textField.appendChild(fragment); + } } - } - -} +} // /[a-z]+\d+/gi \ No newline at end of file From c8982b4199b1e9770935d147670e2a4aa5dab5a0 Mon Sep 17 00:00:00 2001 From: NessArt Date: Wed, 9 Aug 2023 15:12:23 +0200 Subject: [PATCH 03/54] WIP cursor pos working --- .../app/base-editor/base-editor.component.ts | 136 +++++++++--------- 1 file changed, 66 insertions(+), 70 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index 7adbb085e..b0edb2ae5 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -253,8 +253,8 @@ export class BaseEditorComponent { } ngAfterViewInit(): void { - const textField = document.getElementById('textField1'); - textField.addEventListener('input', this.highlightRegex.bind(this)); + //const textField = document.getElementById('textField1'); + //textField.addEventListener('input', this.highlightRegex.bind(this)); this.step_type_input.changes.subscribe(_ => { this.step_type_input.forEach(in_field => { @@ -1684,77 +1684,15 @@ export class BaseEditorComponent { this.markUnsaved(); } - /*highlightRegex() { // with input field - hi - const regexPattern = // Regex pattern to recognize and highlight regex expressions - - const divElement = document.getElementById('textField1'); - const selection = window.getSelection(); - - // Store the current selection position - const selectionStart = selection ? selection.anchorOffset : 0; - - const textContent = divElement.innerText || ''; - - const regexMatchedText = textContent.match(regexPattern); - const regexDetected = regexMatchedText !== null; - - // Clear previous styling - divElement.innerHTML = ''; - - if (regexDetected) { - const fragment = document.createDocumentFragment(); - let currentIndex = 0; - - for (const match of regexMatchedText) { - const startIndex = textContent.indexOf(match, currentIndex); - const nonRegexPart = textContent.substring(currentIndex, startIndex); - - if (nonRegexPart) { - const nonRegexNode = document.createTextNode(nonRegexPart); - fragment.appendChild(nonRegexNode); - } - - const span = document.createElement('span'); - span.style.color = 'var(--ocean-blue)'; - span.style.fontWeight = 'bold'; - span.textContent = match; - fragment.appendChild(span); - - currentIndex = startIndex + match.length; - } - - const remainingText = textContent.substring(currentIndex); - if (remainingText) { - const remainingTextNode = document.createTextNode(remainingText); - fragment.appendChild(remainingTextNode); - } - - divElement.appendChild(fragment); - } else { - // No regex matches, simply set the text content - divElement.innerText = textContent; - } - - // Restore the cursor position - if (selection) { - const updatedLength = divElement.innerText.length; - const updatedStart = Math.min(selectionStart, updatedLength); - const updatedEnd = Math.min(selectionStart, updatedLength); - - selection.removeAllRanges(); - const range = document.createRange(); - range.setStart(divElement.firstChild, updatedStart); - range.setEnd(divElement.firstChild, updatedEnd); - selection.addRange(range); - } - }*/ - highlightRegex() { // div but cursor position bad + + highlightRegex() { const regexPattern = /\/[^\n\/]+\/[a-z]*/gi; // Regex pattern to recognize and highlight regex expressions const textField = document.getElementById('textField1'); const textContent = textField.textContent; - + //Get current cursor position + const offset = this.getCaretCharacterOffsetWithin(textField) + const regexMatchedText = textContent.match(regexPattern); this.regexDetected = regexMatchedText !== null; @@ -1803,5 +1741,63 @@ export class BaseEditorComponent { textField.appendChild(fragment); } + + // Set cursor to correct position + if (this.regexDetected){ + const selection = window.getSelection(); + selection.removeAllRanges() + + let length = 0; + let preLength = 0; + let node=0; + let offsetIndex=0; + + for(let i = 0; i<= textField.childNodes.length; i++) { + length = textField.childNodes[i].textContent.length + if (preLength+length>=offset){ + offsetIndex = offset-preLength + node=i + break; + } + else { + preLength = preLength+length + } + } + if (textField.childNodes[node].nodeType == 3){ + selection.setBaseAndExtent(textField.childNodes[node], offsetIndex, textField.childNodes[node], offsetIndex) + } else { + selection.setBaseAndExtent(textField.childNodes[node].childNodes[0], offsetIndex, textField.childNodes[node].childNodes[0], offsetIndex) + } + } } -} // /[a-z]+\d+/gi \ No newline at end of file + + /** + * Helper for Regex Highlighter, extract current cursor position + * @param element HTMLElement + * @returns num, offset of cursor position + */ + getCaretCharacterOffsetWithin(element) { + var caretOffset = 0; + var doc = element.ownerDocument || element.document; + var win = doc.defaultView || doc.parentWindow; + var sel; + if (typeof win.getSelection != "undefined") { + sel = win.getSelection(); + if (sel.rangeCount > 0) { + var range = win.getSelection().getRangeAt(0); + var preCaretRange = range.cloneRange(); + preCaretRange.selectNodeContents(element); + preCaretRange.setEnd(range.endContainer, range.endOffset); + caretOffset = preCaretRange.toString().length; + } + } else if ( (sel = doc.selection) && sel.type != "Control") { + var textRange = sel.createRange(); + var preCaretTextRange = doc.body.createTextRange(); + preCaretTextRange.moveToElementText(element); + preCaretTextRange.setEndPoint("EndToEnd", textRange); + caretOffset = preCaretTextRange.text.length; + } + return caretOffset; + } + +} \ No newline at end of file From cd430ce34b36e48739679827fc3040f80110bf1a Mon Sep 17 00:00:00 2001 From: NessArt Date: Wed, 9 Aug 2023 16:17:55 +0200 Subject: [PATCH 04/54] WIP div as input --- frontend/src/app/base-editor/base-editor.component.html | 8 +------- frontend/src/app/base-editor/base-editor.component.ts | 7 ++++--- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.html b/frontend/src/app/base-editor/base-editor.component.html index 72371664d..44980930b 100644 --- a/frontend/src/app/base-editor/base-editor.component.html +++ b/frontend/src/app/base-editor/base-editor.component.html @@ -97,13 +97,7 @@
-
+
{{currentStep.values[0]}}
diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index b0edb2ae5..444a180d8 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -1685,10 +1685,10 @@ export class BaseEditorComponent { } - highlightRegex() { + highlightRegex(element, stepIndex: number, valueIndex: number, stepType: string, step?:StepType) { const regexPattern = /\/[^\n\/]+\/[a-z]*/gi; // Regex pattern to recognize and highlight regex expressions - - const textField = document.getElementById('textField1'); + + const textField = document.getElementById(element.id); const textContent = textField.textContent; //Get current cursor position const offset = this.getCaretCharacterOffsetWithin(textField) @@ -1769,6 +1769,7 @@ export class BaseEditorComponent { selection.setBaseAndExtent(textField.childNodes[node].childNodes[0], offsetIndex, textField.childNodes[node].childNodes[0], offsetIndex) } } + this.addToValues(textContent, stepIndex, valueIndex, stepType, step) } /** From 3de82fc9ddd009412400e7090765250f483de6f8 Mon Sep 17 00:00:00 2001 From: NessArt Date: Wed, 9 Aug 2023 16:31:39 +0200 Subject: [PATCH 05/54] doku --- .../app/base-editor/base-editor.component.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index 444a180d8..1751419f1 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -1685,6 +1685,15 @@ export class BaseEditorComponent { } + /** + * Add value and highlight regex, Style regex in value and give value to addToValue() function + * Value is in textContent and style is in innerHTML + * @param element HTMLElement of div, id needed for hightlightRegex, textContend needed for addToValue + * @param stepIndex for addToValue + * @param valueIndex for addToValue + * @param stepType for addToValue + * @param step for addToValue + */ highlightRegex(element, stepIndex: number, valueIndex: number, stepType: string, step?:StepType) { const regexPattern = /\/[^\n\/]+\/[a-z]*/gi; // Regex pattern to recognize and highlight regex expressions @@ -1711,6 +1720,7 @@ export class BaseEditorComponent { const fragment = document.createDocumentFragment(); let currentIndex = 0; + // Create span with style for every regex match for (const match of matches) { const nonRegexPart = textContent.substring(currentIndex, match.index); const matchText = match[0]; @@ -1747,11 +1757,11 @@ export class BaseEditorComponent { const selection = window.getSelection(); selection.removeAllRanges() + // Check in which node the cursor is and set new offsetIndex to position in that node let length = 0; let preLength = 0; let node=0; let offsetIndex=0; - for(let i = 0; i<= textField.childNodes.length; i++) { length = textField.childNodes[i].textContent.length if (preLength+length>=offset){ @@ -1763,12 +1773,13 @@ export class BaseEditorComponent { preLength = preLength+length } } - if (textField.childNodes[node].nodeType == 3){ + if (textField.childNodes[node].nodeType == 3){ // in case childNode is text selection.setBaseAndExtent(textField.childNodes[node], offsetIndex, textField.childNodes[node], offsetIndex) - } else { + } else { // in case childNode is span, childNode of span is text selection.setBaseAndExtent(textField.childNodes[node].childNodes[0], offsetIndex, textField.childNodes[node].childNodes[0], offsetIndex) } } + this.addToValues(textContent, stepIndex, valueIndex, stepType, step) } From d1fa822a29ffc3650f640f2b2ebce4a8c0b94a16 Mon Sep 17 00:00:00 2001 From: NessArt Date: Thu, 10 Aug 2023 18:19:25 +0200 Subject: [PATCH 06/54] toast, cursor improvement, second input --- .../base-editor/base-editor.component.html | 10 ++-- .../app/base-editor/base-editor.component.ts | 50 ++++++++++++++----- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.html b/frontend/src/app/base-editor/base-editor.component.html index 44980930b..ac93aedec 100644 --- a/frontend/src/app/base-editor/base-editor.component.html +++ b/frontend/src/app/base-editor/base-editor.component.html @@ -97,10 +97,7 @@
-
{{currentStep.values[0]}}
- - - +
{{currentStep.values[0]}}
@@ -131,8 +128,9 @@
- + +
{{currentStep.values[1]}}
diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index 1751419f1..7a7f6c238 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -31,6 +31,8 @@ export class BaseEditorComponent { @ViewChildren('step_type_input1') step_type_input1: QueryList; + @ViewChildren('step_type_input2') step_type_input2: QueryList; + /** * View child of the example table */ @@ -141,8 +143,7 @@ export class BaseEditorComponent { exampleChild: ExampleTableComponent; - //@ViewChild('textField1', { static: true }) textField1: ElementRef; - regexDetected: boolean = false; + regexInStory: boolean = false; /** * Subscribtions for all EventEmitter @@ -253,9 +254,6 @@ export class BaseEditorComponent { } ngAfterViewInit(): void { - //const textField = document.getElementById('textField1'); - //textField.addEventListener('input', this.highlightRegex.bind(this)); - this.step_type_input.changes.subscribe(_ => { this.step_type_input.forEach(in_field => { if ( in_field.nativeElement.id === this.lastToFocus) { @@ -276,6 +274,14 @@ export class BaseEditorComponent { if (this.exampleChildren.last != undefined) { this.exampleChild = this.exampleChildren.last; } + + // Regex Highlight on init + this.step_type_input1.forEach(in_field => { + this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) + }); + this.step_type_input2.forEach(in_field => { + this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) + }); } /** @@ -1688,28 +1694,33 @@ export class BaseEditorComponent { /** * Add value and highlight regex, Style regex in value and give value to addToValue() function * Value is in textContent and style is in innerHTML - * @param element HTMLElement of div, id needed for hightlightRegex, textContend needed for addToValue + * @param element id of HTML div * @param stepIndex for addToValue * @param valueIndex for addToValue * @param stepType for addToValue * @param step for addToValue + * @param initialCall if call is from ngAfterViewInit */ - highlightRegex(element, stepIndex: number, valueIndex: number, stepType: string, step?:StepType) { + highlightRegex(element:string, stepIndex?: number, valueIndex?: number, stepType?: string, step?:StepType, initialCall?:boolean) { const regexPattern = /\/[^\n\/]+\/[a-z]*/gi; // Regex pattern to recognize and highlight regex expressions - const textField = document.getElementById(element.id); + const textField = document.getElementById(element); const textContent = textField.textContent; //Get current cursor position const offset = this.getCaretCharacterOffsetWithin(textField) + if(!initialCall){ + this.addToValues(textContent, stepIndex, valueIndex, stepType, step) + } + const regexMatchedText = textContent.match(regexPattern); - this.regexDetected = regexMatchedText !== null; + const regexDetected = regexMatchedText !== null; // Clear previous styling this.renderer.setStyle(textField, 'color', ''); this.renderer.setStyle(textField, 'fontWeight', ''); - if (this.regexDetected) { + if (regexDetected) { const matches: RegExpExecArray[] = []; let match: RegExpExecArray | null; @@ -1753,7 +1764,9 @@ export class BaseEditorComponent { } // Set cursor to correct position - if (this.regexDetected){ + if(!initialCall){ + requestAnimationFrame(() => { + if (regexDetected){ //maybe not needed const selection = window.getSelection(); selection.removeAllRanges() @@ -1778,9 +1791,20 @@ export class BaseEditorComponent { } else { // in case childNode is span, childNode of span is text selection.setBaseAndExtent(textField.childNodes[node].childNodes[0], offsetIndex, textField.childNodes[node].childNodes[0], offsetIndex) } + } else { + const selection = window.getSelection(); + selection.removeAllRanges(); + selection.setBaseAndExtent(textField.firstChild, offset, textField.firstChild, offset) + } + })} + if(initialCall && regexDetected) { + this.regexInStory = true + } + + if(regexDetected && !this.regexInStory){ + this.regexInStory = true + this.toastr.info('Regex Highlight'); } - - this.addToValues(textContent, stepIndex, valueIndex, stepType, step) } /** From 601ebfe01fbfe001d583d88af9fa92efea81c2bb Mon Sep 17 00:00:00 2001 From: NessArt Date: Thu, 10 Aug 2023 18:34:01 +0200 Subject: [PATCH 07/54] drittes Inputfeld --- frontend/src/app/base-editor/base-editor.component.html | 5 +++-- frontend/src/app/base-editor/base-editor.component.ts | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.html b/frontend/src/app/base-editor/base-editor.component.html index ac93aedec..f8ad8515d 100644 --- a/frontend/src/app/base-editor/base-editor.component.html +++ b/frontend/src/app/base-editor/base-editor.component.html @@ -163,8 +163,9 @@
- + +
{{currentStep.values[2]}}
diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index 7a7f6c238..dbd627d4a 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -33,6 +33,8 @@ export class BaseEditorComponent { @ViewChildren('step_type_input2') step_type_input2: QueryList; + @ViewChildren('step_type_input3') step_type_input3: QueryList; + /** * View child of the example table */ @@ -282,6 +284,9 @@ export class BaseEditorComponent { this.step_type_input2.forEach(in_field => { this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) }); + this.step_type_input3.forEach(in_field => { + this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) + }); } /** From bf82edccb9441b308327d43d3ac8e477a8adc998 Mon Sep 17 00:00:00 2001 From: NessArt Date: Thu, 10 Aug 2023 18:49:22 +0200 Subject: [PATCH 08/54] moved initial highlight call --- .../app/base-editor/base-editor.component.ts | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index dbd627d4a..870f0f390 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -205,7 +205,7 @@ export class BaseEditorComponent { } } }); - + } ngOnDestroy(): void { @@ -253,6 +253,18 @@ export class BaseEditorComponent { if(this.allChecked) { this.checkAllSteps(this.allChecked); } + + // Regex Highlight on init + if(this.step_type_input1){ + this.step_type_input1.forEach(in_field => { + this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) + }); + this.step_type_input2.forEach(in_field => { + this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) + }); + this.step_type_input3.forEach(in_field => { + this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) + });} } ngAfterViewInit(): void { @@ -276,17 +288,6 @@ export class BaseEditorComponent { if (this.exampleChildren.last != undefined) { this.exampleChild = this.exampleChildren.last; } - - // Regex Highlight on init - this.step_type_input1.forEach(in_field => { - this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) - }); - this.step_type_input2.forEach(in_field => { - this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) - }); - this.step_type_input3.forEach(in_field => { - this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) - }); } /** @@ -1805,7 +1806,7 @@ export class BaseEditorComponent { if(initialCall && regexDetected) { this.regexInStory = true } - + console.log(this.regexInStory, regexDetected) if(regexDetected && !this.regexInStory){ this.regexInStory = true this.toastr.info('Regex Highlight'); From 6587d840dd34a86ba26cb9cdd57476c94ca31c71 Mon Sep 17 00:00:00 2001 From: NessArt Date: Fri, 11 Aug 2023 12:02:32 +0200 Subject: [PATCH 09/54] toast only when regex new in story --- frontend/src/app/base-editor/base-editor.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index 870f0f390..242085927 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -255,6 +255,7 @@ export class BaseEditorComponent { } // Regex Highlight on init + this.regexInStory = false if(this.step_type_input1){ this.step_type_input1.forEach(in_field => { this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) From e555474083a40dfcac88ebbef89e2ea20af02bb9 Mon Sep 17 00:00:00 2001 From: NessArt Date: Fri, 11 Aug 2023 12:32:17 +0200 Subject: [PATCH 10/54] WIP --- .../app/base-editor/base-editor.component.ts | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index 242085927..6def79324 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -1770,12 +1770,19 @@ export class BaseEditorComponent { textField.appendChild(fragment); } + // Toastr logic + if(initialCall && regexDetected) { + this.regexInStory = true + } + if(regexDetected && !this.regexInStory){ + this.regexInStory = true + this.toastr.info('Regex Highlight'); + } + // Set cursor to correct position if(!initialCall){ - requestAnimationFrame(() => { - if (regexDetected){ //maybe not needed - const selection = window.getSelection(); - selection.removeAllRanges() + //if (regexDetected){ //maybe not needed + console.log(offset) // Check in which node the cursor is and set new offsetIndex to position in that node let length = 0; @@ -1793,24 +1800,29 @@ export class BaseEditorComponent { preLength = preLength+length } } + console.log(node, offset, offsetIndex) + requestAnimationFrame(() => { if (textField.childNodes[node].nodeType == 3){ // in case childNode is text + const selection = window.getSelection(); + selection.removeAllRanges() selection.setBaseAndExtent(textField.childNodes[node], offsetIndex, textField.childNodes[node], offsetIndex) + console.log('in if') } else { // in case childNode is span, childNode of span is text + const selection = window.getSelection(); + selection.removeAllRanges() selection.setBaseAndExtent(textField.childNodes[node].childNodes[0], offsetIndex, textField.childNodes[node].childNodes[0], offsetIndex) + console.log('in else 1') } - } else { + console.log(window.getSelection()) + }) + /*} else { + //requestAnimationFrame(() => { const selection = window.getSelection(); selection.removeAllRanges(); selection.setBaseAndExtent(textField.firstChild, offset, textField.firstChild, offset) - } - })} - if(initialCall && regexDetected) { - this.regexInStory = true - } - console.log(this.regexInStory, regexDetected) - if(regexDetected && !this.regexInStory){ - this.regexInStory = true - this.toastr.info('Regex Highlight'); + console.log('in else 2') + //}) + }*/ } } From 534dead7dd274b5485a79c3cd0dc3a122f0f8172 Mon Sep 17 00:00:00 2001 From: NessArt Date: Fri, 11 Aug 2023 14:06:06 +0200 Subject: [PATCH 11/54] WIP lifecycle call and keystroke call interfere with each other so that cursor position is broken --- .../app/base-editor/base-editor.component.ts | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index 6def79324..2f8d4afc0 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -1781,8 +1781,9 @@ export class BaseEditorComponent { // Set cursor to correct position if(!initialCall){ - //if (regexDetected){ //maybe not needed - console.log(offset) + if (regexDetected){ //maybe not needed + const selection = window.getSelection(); + selection.removeAllRanges() // Check in which node the cursor is and set new offsetIndex to position in that node let length = 0; @@ -1800,29 +1801,21 @@ export class BaseEditorComponent { preLength = preLength+length } } - console.log(node, offset, offsetIndex) + requestAnimationFrame(() => { if (textField.childNodes[node].nodeType == 3){ // in case childNode is text - const selection = window.getSelection(); - selection.removeAllRanges() selection.setBaseAndExtent(textField.childNodes[node], offsetIndex, textField.childNodes[node], offsetIndex) - console.log('in if') } else { // in case childNode is span, childNode of span is text - const selection = window.getSelection(); - selection.removeAllRanges() selection.setBaseAndExtent(textField.childNodes[node].childNodes[0], offsetIndex, textField.childNodes[node].childNodes[0], offsetIndex) - console.log('in else 1') } - console.log(window.getSelection()) }) - /*} else { - //requestAnimationFrame(() => { + } else { + requestAnimationFrame(() => { const selection = window.getSelection(); selection.removeAllRanges(); selection.setBaseAndExtent(textField.firstChild, offset, textField.firstChild, offset) - console.log('in else 2') - //}) - }*/ + }) + } } } From 866a8873de9ad3b0987c8d10bbc6b94ab11f6b60 Mon Sep 17 00:00:00 2001 From: NessArt Date: Fri, 11 Aug 2023 14:10:45 +0200 Subject: [PATCH 12/54] lifecycle and keystroke dont interfere --- .../app/base-editor/base-editor.component.ts | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index 2f8d4afc0..332a0cd57 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -146,6 +146,7 @@ export class BaseEditorComponent { exampleChild: ExampleTableComponent; regexInStory: boolean = false; + initialRegex: boolean = true; /** * Subscribtions for all EventEmitter @@ -230,6 +231,10 @@ export class BaseEditorComponent { } + ngOnChanges(){ + this.initialRegex = true; + } + /** * retrieves the saved block from the session storage */ @@ -255,17 +260,20 @@ export class BaseEditorComponent { } // Regex Highlight on init - this.regexInStory = false - if(this.step_type_input1){ - this.step_type_input1.forEach(in_field => { - this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) - }); - this.step_type_input2.forEach(in_field => { - this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) - }); - this.step_type_input3.forEach(in_field => { - this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) - });} + if(this.initialRegex){ + this.regexInStory = false + if(this.step_type_input1){ + this.step_type_input1.forEach(in_field => { + this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) + }); + this.step_type_input2.forEach(in_field => { + this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) + }); + this.step_type_input3.forEach(in_field => { + this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) + }); + } + } } ngAfterViewInit(): void { @@ -1720,6 +1728,10 @@ export class BaseEditorComponent { this.addToValues(textContent, stepIndex, valueIndex, stepType, step) } + if(!initialCall){ + this.initialRegex = false; + } + const regexMatchedText = textContent.match(regexPattern); const regexDetected = regexMatchedText !== null; From e7a375aa2c4b8e162654c1a6bd28d82ca3c0cd99 Mon Sep 17 00:00:00 2001 From: NessArt Date: Fri, 22 Sep 2023 10:02:58 +0200 Subject: [PATCH 13/54] style of new divs like old text input --- .../app/base-editor/base-editor.component.css | 18 +++++++++++++++++- .../app/base-editor/base-editor.component.html | 6 +++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.css b/frontend/src/app/base-editor/base-editor.component.css index de9074103..757ddf19c 100644 --- a/frontend/src/app/base-editor/base-editor.component.css +++ b/frontend/src/app/base-editor/base-editor.component.css @@ -420,7 +420,7 @@ input.scenario, input.background { } -.content_editable_element { /*not needed !?*/ +.contentEditableElement { /*not needed !?*/ white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ @@ -428,3 +428,19 @@ input.scenario, input.background { word-wrap: break-word; /* Internet Explorer 5.5+ */ } +.inputEditableDiv{ + margin: 1px; + padding: 1px; + border: none; + border-bottom: 1px solid #333; + position: relative; + top: -2px; + width: auto; + min-width: 5px; + + margin-left: 10px; + margin-right: 10px; + padding-left: 5px; + padding-right: 5px; +} + diff --git a/frontend/src/app/base-editor/base-editor.component.html b/frontend/src/app/base-editor/base-editor.component.html index bd2046df9..fc0bbe5dd 100644 --- a/frontend/src/app/base-editor/base-editor.component.html +++ b/frontend/src/app/base-editor/base-editor.component.html @@ -97,7 +97,7 @@
-
{{currentStep.values[0]}}
+
{{currentStep.values[0]}}
@@ -130,7 +130,7 @@
-
{{currentStep.values[1]}}
+
{{currentStep.values[1]}}
@@ -165,7 +165,7 @@
-
{{currentStep.values[2]}}
+
{{currentStep.values[2]}}
From 0c13cea0228bffe7813c2ddb5c2f57773bfbb589 Mon Sep 17 00:00:00 2001 From: NessArt Date: Wed, 4 Oct 2023 12:55:47 +0200 Subject: [PATCH 14/54] regex styling in background --- .../app/base-editor/base-editor.component.html | 15 +++++++++------ .../src/app/base-editor/base-editor.component.ts | 7 ++++++- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.html b/frontend/src/app/base-editor/base-editor.component.html index fc0bbe5dd..9f4e4574f 100644 --- a/frontend/src/app/base-editor/base-editor.component.html +++ b/frontend/src/app/base-editor/base-editor.component.html @@ -279,18 +279,21 @@ {{j+1}}. {{currentStep.pre}}
- + +
{{currentStep.values[0]}}
{{currentStep.mid}}
- + +
{{currentStep.values[1]}}
{{currentStep.post}}
- + +
{{currentStep.values[2]}}
diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index 06b073c5e..8710e29bb 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -272,7 +272,12 @@ export class BaseEditorComponent { // Regex Highlight on init if(this.initialRegex){ this.regexInStory = false - if(this.step_type_input1){ + if(this.step_type_input){ //background + this.step_type_input.forEach(in_field => { + this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) + }); + } + if(this.step_type_input1){ //scenario this.step_type_input1.forEach(in_field => { this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) }); From 87706ef36995b2b1585500018869e2222612bbd6 Mon Sep 17 00:00:00 2001 From: NessArt Date: Thu, 5 Oct 2023 15:31:56 +0200 Subject: [PATCH 15/54] regex highlight only for selected steps --- .../base-editor/base-editor.component.html | 14 ++-- .../app/base-editor/base-editor.component.ts | 67 +++++++++++-------- 2 files changed, 47 insertions(+), 34 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.html b/frontend/src/app/base-editor/base-editor.component.html index 9f4e4574f..44484e71c 100644 --- a/frontend/src/app/base-editor/base-editor.component.html +++ b/frontend/src/app/base-editor/base-editor.component.html @@ -91,13 +91,13 @@ {{ selectedCount(selectedScenario.stepDefinitions,i) || 1 }}
- {{i+1}}.{{j+1}} {{currentStep.pre}} + {{i+1}}.{{j+1}} 
{{currentStep.pre}}
-
{{currentStep.values[0]}}
+
{{currentStep.values[0]}}
@@ -130,7 +130,7 @@
-
{{currentStep.values[1]}}
+
{{currentStep.values[1]}}
@@ -165,7 +165,7 @@
-
{{currentStep.values[2]}}
+
{{currentStep.values[2]}}
@@ -281,19 +281,19 @@
-
{{currentStep.values[0]}}
+
{{currentStep.values[0]}}
{{currentStep.mid}}
-
{{currentStep.values[1]}}
+
{{currentStep.values[1]}}
{{currentStep.post}}
-
{{currentStep.values[2]}}
+
{{currentStep.values[2]}}
diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index 8710e29bb..be5e1e355 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -29,6 +29,8 @@ export class BaseEditorComponent { @ViewChildren('step_type_input') step_type_input: QueryList; + @ViewChildren('step_type_pre') step_type_pre: QueryList; + @ViewChildren('step_type_input1') step_type_input1: QueryList; @ViewChildren('step_type_input2') step_type_input2: QueryList; @@ -272,21 +274,25 @@ export class BaseEditorComponent { // Regex Highlight on init if(this.initialRegex){ this.regexInStory = false - if(this.step_type_input){ //background + //Logic currently not needed since regex only in then step + /*if(this.step_type_input){ //background this.step_type_input.forEach(in_field => { this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) }); - } + }*/ if(this.step_type_input1){ //scenario - this.step_type_input1.forEach(in_field => { - this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) + const stepTypePre = this.step_type_pre.toArray() + this.step_type_input1.forEach((in_field, index) => { + this.highlightRegex(in_field.nativeElement.id,undefined,0,undefined,undefined,stepTypePre[index].nativeElement.innerText, true) }); - this.step_type_input2.forEach(in_field => { - this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) - }); - this.step_type_input3.forEach(in_field => { - this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) + + //Logic currently not needed since regex only in first input field + /*this.step_type_input2.forEach((in_field, index) => { + this.highlightRegex(in_field.nativeElement.id,undefined,1,undefined,undefined,stepTypePre1[index].nativeElement.innerText, true) }); + this.step_type_input3.forEach((in_field, index) => { + this.highlightRegex(in_field.nativeElement.id,undefined,2,undefined,undefined,stepTypePre1[index].nativeElement.innerText, true) + });*/ } } } @@ -374,7 +380,6 @@ export class BaseEditorComponent { * @param stepType */ updateScenarioValues(input: string, stepIndex: number, valueIndex: number, stepType: string) { - console.log(this.selectedScenario.stepDefinitions); switch (stepType) { case 'given': @@ -1734,15 +1739,19 @@ export class BaseEditorComponent { * @param valueIndex for addToValue * @param stepType for addToValue * @param step for addToValue + * @param stepPre pre text of step * @param initialCall if call is from ngAfterViewInit */ - highlightRegex(element:string, stepIndex?: number, valueIndex?: number, stepType?: string, step?:StepType, initialCall?:boolean) { + highlightRegex(element:string, stepIndex?: number, valueIndex?: number, stepType?: string, step?:StepType, stepPre?: string, initialCall?:boolean) { const regexPattern = /\/[^\n\/]+\/[a-z]*/gi; // Regex pattern to recognize and highlight regex expressions const textField = document.getElementById(element); const textContent = textField.textContent; //Get current cursor position const offset = this.getCaretCharacterOffsetWithin(textField) + const regexSteps = ['So I can see the text', 'So I can see the text:', 'So I can\'t see the text:', 'So I can\'t see text in the textbox:'] + + let textIsRegex = false; if(!initialCall){ this.addToValues(textContent, stepIndex, valueIndex, stepType, step) @@ -1752,14 +1761,17 @@ export class BaseEditorComponent { this.initialRegex = false; } - const regexMatchedText = textContent.match(regexPattern); - const regexDetected = regexMatchedText !== null; - - // Clear previous styling - this.renderer.setStyle(textField, 'color', ''); - this.renderer.setStyle(textField, 'fontWeight', ''); - + if(0==valueIndex && regexSteps.includes(stepPre)){ + + const regexMatchedText = textContent.match(regexPattern); + const regexDetected = regexMatchedText !== null; + + // Clear previous styling + this.renderer.setStyle(textField, 'color', ''); + this.renderer.setStyle(textField, 'fontWeight', ''); + if (regexDetected) { + textIsRegex = true; const matches: RegExpExecArray[] = []; let match: RegExpExecArray | null; @@ -1801,19 +1813,20 @@ export class BaseEditorComponent { textField.appendChild(fragment); } - - // Toastr logic - if(initialCall && regexDetected) { - this.regexInStory = true - } - if(regexDetected && !this.regexInStory){ - this.regexInStory = true - this.toastr.info('Regex Highlight'); + // Toastr logic + if(initialCall && regexDetected) { + this.regexInStory = true + } + if(regexDetected && !this.regexInStory){ + this.regexInStory = true + this.toastr.info('Regex Highlight'); + } } + // Set cursor to correct position if(!initialCall){ - if (regexDetected){ //maybe not needed + if (textIsRegex){ //maybe not needed const selection = window.getSelection(); selection.removeAllRanges() From 5a6db2836f8efe0851d6de38881aa410bb1aad8d Mon Sep 17 00:00:00 2001 From: NessArt Date: Thu, 12 Oct 2023 16:19:26 +0200 Subject: [PATCH 16/54] WIP highlighting in then steps and /^m/ --- .../app/base-editor/base-editor.component.ts | 100 +++++++++--------- 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index be5e1e355..cbf9883fd 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -1731,6 +1731,11 @@ export class BaseEditorComponent { } + //TODO + //darkmode, handhabung felder vergleichen (str v), multiple scenario + //beim hinzufügen von blöcken oder kopierten wird nicht gehighlighted + //zentrale Bloeke + /** * Add value and highlight regex, Style regex in value and give value to addToValue() function * Value is in textContent and style is in innerHTML @@ -1743,14 +1748,12 @@ export class BaseEditorComponent { * @param initialCall if call is from ngAfterViewInit */ highlightRegex(element:string, stepIndex?: number, valueIndex?: number, stepType?: string, step?:StepType, stepPre?: string, initialCall?:boolean) { - const regexPattern = /\/[^\n\/]+\/[a-z]*/gi; // Regex pattern to recognize and highlight regex expressions - + const regexPattern = /\/\^[^/]*\//g///\/\^[^/]*\//g;// Regex pattern to recognize and highlight regex expressions -> start with /^ and end with / const textField = document.getElementById(element); const textContent = textField.textContent; //Get current cursor position const offset = this.getCaretCharacterOffsetWithin(textField) const regexSteps = ['So I can see the text', 'So I can see the text:', 'So I can\'t see the text:', 'So I can\'t see text in the textbox:'] - let textIsRegex = false; if(!initialCall){ @@ -1761,67 +1764,66 @@ export class BaseEditorComponent { this.initialRegex = false; } - if(0==valueIndex && regexSteps.includes(stepPre)){ + // Clear previous styling + this.renderer.setStyle(textField, 'color', ''); + this.renderer.setStyle(textField, 'fontWeight', ''); - const regexMatchedText = textContent.match(regexPattern); - const regexDetected = regexMatchedText !== null; + var regexDetected = false; - // Clear previous styling - this.renderer.setStyle(textField, 'color', ''); - this.renderer.setStyle(textField, 'fontWeight', ''); - - if (regexDetected) { - textIsRegex = true; - const matches: RegExpExecArray[] = []; - let match: RegExpExecArray | null; + const matches: RegExpExecArray[] = []; + let match: RegExpExecArray | null; - while ((match = regexPattern.exec(textContent)) !== null) { - matches.push(match); - } + while ((match = regexPattern.exec(textContent)) !== null) { + matches.push(match); + textIsRegex = true; + } - const fragment = document.createDocumentFragment(); - let currentIndex = 0; + const fragment = document.createDocumentFragment(); + let currentIndex = 0; - // Create span with style for every regex match - for (const match of matches) { - const nonRegexPart = textContent.substring(currentIndex, match.index); - const matchText = match[0]; + // Create span with style for every regex match + for (const match of matches) { + const nonRegexPart = textContent.substring(currentIndex, match.index); + const matchText = match[0]; - if (nonRegexPart) { - const nonRegexNode = document.createTextNode(nonRegexPart); - fragment.appendChild(nonRegexNode); - } + if (nonRegexPart) { + const nonRegexNode = document.createTextNode(nonRegexPart); + fragment.appendChild(nonRegexNode); + } - const span = document.createElement('span'); + const span = document.createElement('span'); + if(0==valueIndex && regexSteps.includes(stepPre)){ + regexDetected = true; span.style.color = 'var(--ocean-blue)'; span.style.fontWeight = 'bold'; - span.appendChild(document.createTextNode(matchText)); - fragment.appendChild(span); - - currentIndex = match.index + matchText.length; } + span.appendChild(document.createTextNode(matchText)); + fragment.appendChild(span); - const remainingText = textContent.substring(currentIndex); - if (remainingText) { - const remainingTextNode = document.createTextNode(remainingText); - fragment.appendChild(remainingTextNode); - } + currentIndex = match.index + matchText.length; + } - while (textField.firstChild) { - textField.removeChild(textField.firstChild); - } + const remainingText = textContent.substring(currentIndex); + if (remainingText) { + const remainingTextNode = document.createTextNode(remainingText); + fragment.appendChild(remainingTextNode); + } - textField.appendChild(fragment); + while (textField.firstChild) { + textField.removeChild(textField.firstChild); } - // Toastr logic - if(initialCall && regexDetected) { - this.regexInStory = true - } - if(regexDetected && !this.regexInStory){ - this.regexInStory = true - this.toastr.info('Regex Highlight'); - } + + textField.appendChild(fragment); + + // Toastr logic + if(initialCall && regexDetected) { + this.regexInStory = true } + if(regexDetected && !this.regexInStory){ + this.regexInStory = true + this.toastr.info('Regex Highlight'); + } + // Set cursor to correct position From 043bc913b518b85b3570d62cb51dacf9b647f68b Mon Sep 17 00:00:00 2001 From: NessArt Date: Thu, 12 Oct 2023 16:48:07 +0200 Subject: [PATCH 17/54] @@ highlight for regex --- frontend/src/app/base-editor/base-editor.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index cbf9883fd..7ffd6954c 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -1748,7 +1748,7 @@ export class BaseEditorComponent { * @param initialCall if call is from ngAfterViewInit */ highlightRegex(element:string, stepIndex?: number, valueIndex?: number, stepType?: string, step?:StepType, stepPre?: string, initialCall?:boolean) { - const regexPattern = /\/\^[^/]*\//g///\/\^[^/]*\//g;// Regex pattern to recognize and highlight regex expressions -> start with /^ and end with / + const regexPattern = /@@[^ ]+/g;// Regex pattern to recognize and highlight regex expressions -> start with @@ const textField = document.getElementById(element); const textContent = textField.textContent; //Get current cursor position From 6baef6423e12b4d2e15c61a1bf96ba00ac8b6685 Mon Sep 17 00:00:00 2001 From: NessArt Date: Fri, 13 Oct 2023 10:54:41 +0200 Subject: [PATCH 18/54] merge fix ts file --- frontend/src/app/base-editor/base-editor.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index d6503003f..7773d444b 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -1,7 +1,6 @@ import { ApiService } from 'src/app/Services/api.service'; import { CdkDragDrop, CdkDragStart, DragRef, moveItemInArray } from '@angular/cdk/drag-drop'; -import { Component, ElementRef, Input, QueryList, Renderer2, ViewChild, ViewChildren } from '@angular/core'; -import { Component, ElementRef, EventEmitter, Input, Output, QueryList, ViewChild, ViewChildren } from '@angular/core'; +import { Component, ElementRef, EventEmitter, Input, Output, Renderer2, QueryList, ViewChild, ViewChildren } from '@angular/core'; import { ToastrService } from 'ngx-toastr'; import { AddBlockFormComponent } from '../modals/add-block-form/add-block-form.component'; import { NewStepRequestComponent } from '../modals/new-step-request/new-step-request.component'; From 8c59fc61aa79ecd61d5d85e00b58a806b4b6dadf Mon Sep 17 00:00:00 2001 From: NessArt Date: Tue, 24 Oct 2023 11:00:19 +0200 Subject: [PATCH 19/54] css merge fix and html merge --- .../app/base-editor/base-editor.component.css | 3 -- .../base-editor/base-editor.component.html | 32 +++++++++++-------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.css b/frontend/src/app/base-editor/base-editor.component.css index 50b400478..4d4a7569c 100644 --- a/frontend/src/app/base-editor/base-editor.component.css +++ b/frontend/src/app/base-editor/base-editor.component.css @@ -507,9 +507,6 @@ input.background { padding-top: 0; } - - } - .contentEditableElement { /*not needed !?*/ white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ diff --git a/frontend/src/app/base-editor/base-editor.component.html b/frontend/src/app/base-editor/base-editor.component.html index fdbee7e87..a42800953 100644 --- a/frontend/src/app/base-editor/base-editor.component.html +++ b/frontend/src/app/base-editor/base-editor.component.html @@ -144,18 +144,19 @@ context: {$implicit: currentStep}">
- {{currentStep.pre}} +  
{{currentStep.pre}}
- + style="padding-left: 5px; padding-right: 5px;min-width: 100px; padding-bottom: 1px;" /--> +
{{currentStep.values[0]}}
- + style="padding-left: 5px; padding-right: 5px;min-width: 100px" /--> +
{{currentStep.values[1]}}
- + style="padding-left: 5px; padding-right: 5px;min-width: 100px" /--> +
{{currentStep.values[2]}}
{{j+1}}. {{currentStep.pre}}
- + style="padding-left: 5px; padding-right: 5px;min-width: 100px" /--> +
{{currentStep.values[0]}}
{{currentStep.mid}}
- + style="padding-left: 5px; padding-right: 5px;min-width: 100px" /--> +
{{currentStep.values[1]}}
{{currentStep.post}}
- + style="padding-left: 5px; padding-right: 5px;min-width: 100px" /--> +
{{currentStep.values[2]}}
From e6a96af4ef293b1dff1b71b56acb8c5a1903b65c Mon Sep 17 00:00:00 2001 From: NessArt Date: Thu, 9 Nov 2023 15:57:37 +0100 Subject: [PATCH 20/54] wip --- .../app/base-editor/base-editor.component.css | 2 +- .../app/base-editor/base-editor.component.ts | 21 ++- .../example-table/example-table.component.css | 12 ++ .../example-table.component.html | 18 +-- .../example-table/example-table.component.ts | 144 ++++++++++++++++++ 5 files changed, 181 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.css b/frontend/src/app/base-editor/base-editor.component.css index 4d4a7569c..aeedb0d1c 100644 --- a/frontend/src/app/base-editor/base-editor.component.css +++ b/frontend/src/app/base-editor/base-editor.component.css @@ -507,7 +507,7 @@ input.background { padding-top: 0; } -.contentEditableElement { /*not needed !?*/ +.contentEditableElement { /*needed for trailing whitespaces*/ white-space: pre-wrap; /* css-3 */ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ white-space: -pre-wrap; /* Opera 4-6 */ diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index 7773d444b..0aeef1c59 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -2013,9 +2013,22 @@ export class BaseEditorComponent { //TODO - //darkmode, handhabung felder vergleichen (str v), multiple scenario + //multiple scenario //beim hinzufügen von blöcken oder kopierten wird nicht gehighlighted - //zentrale Bloeke + //zentrale Bloeke -> geht aber in ansicht ohne feld schwarz + //higlighting start @@ und ende whitespace oder zeile + + //span.setAttribute('class', 'regexStyling'); -> wie funktioniert darkmode + /*.regexStyling { + color: var(--ocean-blue); + font-weight: bold; +} + +.darkTheme .regexStyling em{ + color: var(--light-blue) !important; + font-weight: bold; +}*/ + /** * Add value and highlight regex, Style regex in value and give value to addToValue() function @@ -2045,10 +2058,6 @@ export class BaseEditorComponent { this.initialRegex = false; } - // Clear previous styling - this.renderer.setStyle(textField, 'color', ''); - this.renderer.setStyle(textField, 'fontWeight', ''); - var regexDetected = false; const matches: RegExpExecArray[] = []; diff --git a/frontend/src/app/example-table/example-table.component.css b/frontend/src/app/example-table/example-table.component.css index 694c734a3..338f62e28 100644 --- a/frontend/src/app/example-table/example-table.component.css +++ b/frontend/src/app/example-table/example-table.component.css @@ -134,4 +134,16 @@ th.mat-header-cell:first-of-type, td.mat-cell:first-of-type, td.mat-footer-cell: font-size: 17px; margin: 2px; margin-right: 5px; +} + +.blue-text { + color: blue; +} + +.contentEditableElement { /*needed for trailing whitespaces*/ + white-space: pre-wrap; /* css-3 */ + white-space: -moz-pre-wrap; /* Mozilla, since 1999 */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + word-wrap: break-word; /* Internet Explorer 5.5+ */ } \ No newline at end of file diff --git a/frontend/src/app/example-table/example-table.component.html b/frontend/src/app/example-table/example-table.component.html index faeae00bb..45143c011 100644 --- a/frontend/src/app/example-table/example-table.component.html +++ b/frontend/src/app/example-table/example-table.component.html @@ -36,15 +36,15 @@     

{{rowIndex+1}}.

- - - {{element[column]}} - - - - - - +
+ +
{{element[column]}}
+ + + +
diff --git a/frontend/src/app/example-table/example-table.component.ts b/frontend/src/app/example-table/example-table.component.ts index 568181084..c25892853 100644 --- a/frontend/src/app/example-table/example-table.component.ts +++ b/frontend/src/app/example-table/example-table.component.ts @@ -391,4 +391,148 @@ export class ExampleTableComponent implements OnInit { this.selectedScenario.stepDefinitions.example[i].values = newData[i-1] } } + + private highlightMatches(el, columnIndex, rowIndex, initialCall) { + const regex = /@@[^ ]+/g; + const inputValue: string = el.textContent; + const offset = this.getCaretCharacterOffsetWithin(el) + + if(!initialCall){ + this.selectedScenario.stepDefinitions.example[rowIndex + 1].values[columnIndex-1] = inputValue + } + const trailingWhitepace = inputValue.slice(-1) == ' ' + console.log('inputValue', el.innerHTML.slice(-1)) + console.log('textContent',el.textContent.slice(-1)) + console.log(trailingWhitepace) + + const highlightedText = inputValue.replace(regex, (match) => `${match}`); + + const textIsRegex = regex.test(inputValue); + console.log(inputValue) + //if (trailingWhitepace){ + //highlightedText.concat(' ') + //} + console.log(highlightedText) + el.innerHTML = highlightedText + console.log(el) + + /*var regexDetected = false; + let textIsRegex = false; + + const matches: RegExpExecArray[] = []; + let match: RegExpExecArray | null; + + while ((match = regex.exec(inputValue)) !== null) { + matches.push(match); + textIsRegex = true; + } + + const fragment = document.createDocumentFragment(); + let currentIndex = 0; + + // Create span with style for every regex match + for (const match of matches) { + const nonRegexPart = inputValue.substring(currentIndex, match.index); + const matchText = match[0]; + + if (nonRegexPart) { + const nonRegexNode = document.createTextNode(nonRegexPart); + fragment.appendChild(nonRegexNode); + } + + const span = document.createElement('span'); + regexDetected = true; + span.style.color = 'var(--ocean-blue)'; + span.style.fontWeight = 'bold'; + + span.appendChild(document.createTextNode(matchText)); + fragment.appendChild(span); + + currentIndex = match.index + matchText.length; + } + + const remainingText = inputValue.substring(currentIndex); + if (remainingText) { + const remainingTextNode = document.createTextNode(remainingText); + fragment.appendChild(remainingTextNode); + } + + while (el.firstChild) { + el.removeChild(el.firstChild); + } + + el.appendChild(fragment); + + console.log(el)*/ + + // Set cursor to correct position + if(!initialCall){ + if (textIsRegex){ //maybe not needed + const selection = window.getSelection(); + selection.removeAllRanges() + + // Check in which node the cursor is and set new offsetIndex to position in that node + let length = 0; + let preLength = 0; + let node=0; + let offsetIndex=0; + for(let i = 0; i<= el.childNodes.length; i++) { + length = el.childNodes[i].textContent.length + if (preLength+length>=offset){ + offsetIndex = offset-preLength + node=i + break; + } + else { + preLength = preLength+length + } + } + + requestAnimationFrame(() => { + if (el.childNodes[node].nodeType == 3){ // in case childNode is text + selection.setBaseAndExtent(el.childNodes[node], offsetIndex, el.childNodes[node], offsetIndex) + } else { // in case childNode is span, childNode of span is text + selection.setBaseAndExtent(el.childNodes[node].childNodes[0], offsetIndex, el.childNodes[node].childNodes[0], offsetIndex) + } + }) + } else { + requestAnimationFrame(() => { + const selection = window.getSelection(); + selection.removeAllRanges(); + selection.setBaseAndExtent(el.firstChild, offset, el.firstChild, offset) + }) + } + } + + + } + + /** + * Helper for Regex Highlighter, extract current cursor position + * @param element HTMLElement + * @returns num, offset of cursor position + */ + getCaretCharacterOffsetWithin(element) { + var caretOffset = 0; + var doc = element.ownerDocument || element.document; + var win = doc.defaultView || doc.parentWindow; + var sel; + if (typeof win.getSelection != "undefined") { + sel = win.getSelection(); + if (sel.rangeCount > 0) { + var range = win.getSelection().getRangeAt(0); + var preCaretRange = range.cloneRange(); + preCaretRange.selectNodeContents(element); + preCaretRange.setEnd(range.endContainer, range.endOffset); + caretOffset = preCaretRange.toString().length; + } + } else if ( (sel = doc.selection) && sel.type != "Control") { + var textRange = sel.createRange(); + var preCaretTextRange = doc.body.createTextRange(); + preCaretTextRange.moveToElementText(element); + preCaretTextRange.setEndPoint("EndToEnd", textRange); + caretOffset = preCaretTextRange.text.length; + } + return caretOffset; +} } From 0908841c2c69f4541ca04cf7db56be22cb0c7e24 Mon Sep 17 00:00:00 2001 From: i3rotlher Date: Tue, 14 Nov 2023 17:08:23 +0100 Subject: [PATCH 21/54] updated db calls --- backend/package-lock.json | 309 ++++++++++++++++++------ backend/package.json | 8 +- backend/src/database/DbConnector.js | 26 +- backend/src/database/DbServices.js | 271 +++++++++++---------- backend/src/database/installDatabase.js | 18 +- backend/src/database/mongoDB_admin.js | 43 ++-- backend/src/database/mongodatabase.js | 192 ++++++++------- backend/src/server.js | 8 +- backend/src/serverRouter/blockRouter.js | 2 +- backend/src/serverRouter/userRouter.js | 23 +- 10 files changed, 540 insertions(+), 360 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 0b9af320c..c3876f458 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -24,7 +24,7 @@ "express-session": "^1.17.2", "geckodriver": "^3.0.1", "moment": "^2.29.4", - "mongodb": "^3.7.3", + "mongodb": "^6.2.0", "node-fetch": "^2.6.7", "nodemailer": "^6.7.5", "passport": "^0.6.0", @@ -56,7 +56,7 @@ "typescript": "^4.9.4" }, "engines": { - "node": "18.13.0" + "node": "^18.13.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -1763,6 +1763,14 @@ "node-pre-gyp": "bin/node-pre-gyp" } }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.1.tgz", + "integrity": "sha512-t7c5K033joZZMspnHg/gWPE4kandgc2OxE74aYOtGKfgB9VPuVJPix0H6fhmm2erj5PBJ21mqcx34lpIGtUCsQ==", + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2083,6 +2091,20 @@ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==" }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + }, + "node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, "node_modules/@types/yargs": { "version": "17.0.11", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.11.tgz", @@ -2555,9 +2577,9 @@ } }, "node_modules/bl/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -2568,7 +2590,7 @@ "util-deprecate": "~1.0.1" } }, - "node_modules/bl/node_modules/readable-stream/node_modules/safe-buffer": { + "node_modules/bl/node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" @@ -2581,11 +2603,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/bl/node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -2673,11 +2690,11 @@ } }, "node_modules/bson": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", - "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.2.0.tgz", + "integrity": "sha512-ID1cI+7bazPDyL9wYy9GaQ8gEEohWvcUl/Yf0dIdutJxnmInEEyCsb4awy/OiBfall7zBA179Pahi3vCdFze3Q==", "engines": { - "node": ">=0.6.19" + "node": ">=16.20.1" } }, "node_modules/buffer-from": { @@ -3019,6 +3036,52 @@ "mongodb": "^3.1.0" } }, + "node_modules/connect-mongo/node_modules/bson": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/connect-mongo/node_modules/mongodb": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.4.tgz", + "integrity": "sha512-K5q8aBqEXMwWdVNh94UQTwZ6BejVbFhh1uB6c5FKtPE9eUMZPUO3sRZdgIEcHSrAWmxzpG/FeODDKL388sqRmw==", + "dependencies": { + "bl": "^2.2.1", + "bson": "^1.1.4", + "denque": "^1.4.1", + "optional-require": "^1.1.8", + "safe-buffer": "^5.1.2" + }, + "engines": { + "node": ">=4" + }, + "optionalDependencies": { + "saslprep": "^1.0.0" + }, + "peerDependenciesMeta": { + "aws4": { + "optional": true + }, + "bson-ext": { + "optional": true + }, + "kerberos": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "mongodb-extjson": { + "optional": true + }, + "snappy": { + "optional": true + } + } + }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -7380,8 +7443,7 @@ "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "optional": true + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" }, "node_modules/merge-descriptors": { "version": "1.0.1", @@ -7510,27 +7572,34 @@ } }, "node_modules/mongodb": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", - "integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.2.0.tgz", + "integrity": "sha512-d7OSuGjGWDZ5usZPqfvb36laQ9CPhnWkAGHT61x5P95p/8nMVeH8asloMwW6GcYFeB0Vj4CB/1wOTDG2RA9BFA==", "dependencies": { - "bl": "^2.2.1", - "bson": "^1.1.4", - "denque": "^1.4.1", - "optional-require": "^1.1.8", - "safe-buffer": "^5.1.2" + "@mongodb-js/saslprep": "^1.1.0", + "bson": "^6.2.0", + "mongodb-connection-string-url": "^2.6.0" }, "engines": { - "node": ">=4" + "node": ">=16.20.1" }, - "optionalDependencies": { - "saslprep": "^1.0.0" + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.188.0", + "@mongodb-js/zstd": "^1.1.0", + "gcp-metadata": "^5.2.0", + "kerberos": "^2.0.1", + "mongodb-client-encryption": ">=6.0.0 <7", + "snappy": "^7.2.2", + "socks": "^2.7.1" }, "peerDependenciesMeta": { - "aws4": { + "@aws-sdk/credential-providers": { "optional": true }, - "bson-ext": { + "@mongodb-js/zstd": { + "optional": true + }, + "gcp-metadata": { "optional": true }, "kerberos": { @@ -7539,14 +7608,54 @@ "mongodb-client-encryption": { "optional": true }, - "mongodb-extjson": { + "snappy": { "optional": true }, - "snappy": { + "socks": { "optional": true } } }, + "node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -8246,8 +8355,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "peer": true, "engines": { "node": ">=6" } @@ -8805,8 +8912,7 @@ "node_modules/sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", - "optional": true, + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", "dependencies": { "memory-pager": "^1.0.2" } @@ -11051,6 +11157,14 @@ "tar": "^6.1.11" } }, + "@mongodb-js/saslprep": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.1.tgz", + "integrity": "sha512-t7c5K033joZZMspnHg/gWPE4kandgc2OxE74aYOtGKfgB9VPuVJPix0H6fhmm2erj5PBJ21mqcx34lpIGtUCsQ==", + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -11352,6 +11466,20 @@ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==" }, + "@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==" + }, + "@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "requires": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, "@types/yargs": { "version": "17.0.11", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.11.tgz", @@ -11711,9 +11839,9 @@ }, "dependencies": { "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -11722,28 +11850,19 @@ "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } } }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - } } } } @@ -11812,9 +11931,9 @@ } }, "bson": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", - "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.2.0.tgz", + "integrity": "sha512-ID1cI+7bazPDyL9wYy9GaQ8gEEohWvcUl/Yf0dIdutJxnmInEEyCsb4awy/OiBfall7zBA179Pahi3vCdFze3Q==" }, "buffer-from": { "version": "1.1.2", @@ -12074,6 +12193,26 @@ "integrity": "sha512-0Mx88079Z20CG909wCFlR3UxhMYGg6Ibn1hkIje1hwsqOLWtL9HJV+XD0DAjUvQScK6WqY/FA8tSVQM9rR64Rw==", "requires": { "mongodb": "^3.1.0" + }, + "dependencies": { + "bson": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" + }, + "mongodb": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.4.tgz", + "integrity": "sha512-K5q8aBqEXMwWdVNh94UQTwZ6BejVbFhh1uB6c5FKtPE9eUMZPUO3sRZdgIEcHSrAWmxzpG/FeODDKL388sqRmw==", + "requires": { + "bl": "^2.2.1", + "bson": "^1.1.4", + "denque": "^1.4.1", + "optional-require": "^1.1.8", + "safe-buffer": "^5.1.2", + "saslprep": "^1.0.0" + } + } } }, "console-control-strings": { @@ -15408,8 +15547,7 @@ "memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "optional": true + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" }, "merge-descriptors": { "version": "1.0.1", @@ -15505,16 +15643,46 @@ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" }, "mongodb": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", - "integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.2.0.tgz", + "integrity": "sha512-d7OSuGjGWDZ5usZPqfvb36laQ9CPhnWkAGHT61x5P95p/8nMVeH8asloMwW6GcYFeB0Vj4CB/1wOTDG2RA9BFA==", "requires": { - "bl": "^2.2.1", - "bson": "^1.1.4", - "denque": "^1.4.1", - "optional-require": "^1.1.8", - "safe-buffer": "^5.1.2", - "saslprep": "^1.0.0" + "@mongodb-js/saslprep": "^1.1.0", + "bson": "^6.2.0", + "mongodb-connection-string-url": "^2.6.0" + } + }, + "mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "requires": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + }, + "dependencies": { + "tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" + }, + "whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "requires": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + } + } } }, "ms": { @@ -16033,9 +16201,7 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "peer": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "qs": { "version": "6.10.3", @@ -16425,8 +16591,7 @@ "sparse-bitfield": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", - "optional": true, + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", "requires": { "memory-pager": "^1.0.2" } diff --git a/backend/package.json b/backend/package.json index f185e42a5..947f72bba 100644 --- a/backend/package.json +++ b/backend/package.json @@ -2,7 +2,7 @@ "name": "seed-test-backend", "version": "1.6.2", "engines": { - "node": "18.13.0" + "node": "^18.13.0" }, "scripts": { "start": "tsc && node src/server.js", @@ -32,7 +32,7 @@ "express-session": "^1.17.2", "geckodriver": "^3.0.1", "moment": "^2.29.4", - "mongodb": "^3.7.3", + "mongodb": "^6.2.0", "node-fetch": "^2.6.7", "nodemailer": "^6.7.5", "passport": "^0.6.0", @@ -69,6 +69,8 @@ "/spec/serverHelper.spec.js", "/node_modules/" ], - "setupFiles": ["./spec/setupTest.js"] + "setupFiles": [ + "./spec/setupTest.js" + ] } } diff --git a/backend/src/database/DbConnector.js b/backend/src/database/DbConnector.js index eab5ffb36..1c2b6fb4e 100644 --- a/backend/src/database/DbConnector.js +++ b/backend/src/database/DbConnector.js @@ -1,21 +1,23 @@ const { MongoClient } = require('mongodb'); -const { exit } = require('process'); +const { setTimeout } = require('timers/promises'); const uri = process.env.DATABASE_URI || 'mongodb://SeedAdmin:SeedTest@seedmongodb:27017'; let connection = []; // Create the database connection -async function establishConnection(callback) { - // eslint-disable-next-line max-len - MongoClient.connect(uri, { poolSize: 20, useNewUrlParser: true, useUnifiedTopology: true }, async (err, db) => { - if (err) { - console.log('DB_ERROR: Can`t connect to DB. The Project may not be set up correctly. For more information read the README'); - exit(-1); - } - connection = db.db('Seed'); - if (typeof callback === 'function' && callback()) callback(connection); - console.log('Established Database Connection!'); - }); +async function establishConnection(attempt) { + const attempts = attempt || 1; + if (attempt > 3) throw new Error('\x1b[31mFailed to connect to the database after multiple retries.\x1b[0m'); + + try { + const client = await MongoClient.connect(uri, { maxPoolSize: 20 }); + connection = client.db('Seed'); + return client; + } catch (err) { + console.log(`\x1b[38;5;208mConnection failed! Retrying... ${attempts}\x1b[0m`); + await setTimeout(3000); + return establishConnection(attempts + 1); + } } function getConnection() { diff --git a/backend/src/database/DbServices.js b/backend/src/database/DbServices.js index 7271dd8db..8583a7f36 100644 --- a/backend/src/database/DbServices.js +++ b/backend/src/database/DbServices.js @@ -13,11 +13,11 @@ const toString = require('stream-to-string'); const assert = require('assert'); const mongodb = require('mongodb'); const fs = require('fs'); +const Collection = require('mongodb/lib/collection'); const dbConnection = require('./DbConnector'); const emptyStory = require('../models/emptyStory'); const emptyScenario = require('../models/emptyScenario'); const emptyBackground = require('../models/emptyBackground'); -const Collection = require('mongodb/lib/collection'); if (process.env.NODE_ENV !== 'production') { require('dotenv').config(); @@ -37,7 +37,7 @@ const ReportsCollection = 'Reports'; // Opening a pooling Database Connection via DbConnector dbConnection.establishConnection() - .then(() => console.log('db ', dbConnection.getConnection())); + .then(() => console.log('\x1b[32m%s\x1b[0m \x1b[33m%s\x1b[0m', 'Connected to database @', dbConnection.getConnection().client.s.options.srvHost)); /** * Writes a PasswordResetRequest in the DB @@ -87,7 +87,7 @@ async function getResetRequestByEmail(mail) { } /** - * deletes Password reset request + * deletes Password reset request * @param {*} mail * @returns deletion Report */ @@ -110,7 +110,7 @@ async function deleteRequest(mail) { async function getUserById(userId) { try { const db = dbConnection.getConnection(); - return await db.collection(userCollection).findOne({ _id: ObjectId(userId) }); + return await db.collection(userCollection).findOne({ _id: new ObjectId(userId) }); } catch (e) { console.log(`ERROR in getUserById: ${e}`); throw e; @@ -150,7 +150,7 @@ async function getUserByEmail(email) { /** * - * @param {object} user {email:string, userId: String, password: string} + * @param {object} user {email:string, userId: String, password: string} * @returns */ async function registerUser(user) { @@ -161,7 +161,7 @@ async function registerUser(user) { let result; if (dbUser !== null) throw Error('User already exists'); else if (user.userId) { // update in register? attacker with userId could re-set anything - result = await collection.update({ _id: ObjectId(user.userId) }, { $set: { email: user.email, password: user.password } }); + result = await collection.update({ _id: new ObjectId(user.userId) }, { $set: { email: user.email, password: user.password } }); } else { delete user.userId; const query = { email: user.email.toString(), password: user.password }; @@ -197,14 +197,14 @@ async function registerGithubUser(user) { * @returns */ function replaceUser(newUser, collection) { - const myObjt = { _id: ObjectId(newUser._id) }; + const myObjt = { _id: new ObjectId(newUser._id) }; return collection.findOneAndReplace(myObjt, newUser).then((res) => res.value); } async function updateGithubToken(objId, updatedToken) { try { const db = dbConnection.getConnection(); - return await db.collection(userCollection).updateOne({ _id: ObjectId(objId) }, { $set: { 'github.githubToken': updatedToken } }); + return await db.collection(userCollection).updateOne({ _id: new ObjectId(objId) }, { $set: { 'github.githubToken': updatedToken } }); } catch (e) { console.log(`ERROR in updateGithubToken: ${e}`); throw e; @@ -247,7 +247,7 @@ async function mergeGithub(userId, login, id) { */ // TODO: storySource wont be needed anymore function findStory(storyId, collection) { - const id = ObjectId(storyId); + const id = new ObjectId(storyId); return new Promise((resolve, reject) => { collection.findOne({ _id: id }, (err, result) => { if (err) reject(err); @@ -264,9 +264,9 @@ function findStory(storyId, collection) { */ function replace(story, collection) { const filter = { - _id: ObjectId(story._id.toString()), + _id: new ObjectId(story._id.toString()) }; - story._id = ObjectId(story._id); + story._id = new ObjectId(story._id); return new Promise((resolve, reject) => { collection.findOneAndReplace(filter, story, (err, result) => { if (err) reject(err); @@ -290,8 +290,8 @@ async function updateStory(updatedStory) { try { const db = dbConnection.getConnection(); const collection = await db.collection(storiesCollection); - updatedStory._id = ObjectId(updatedStory._id.toString()) - return await collection.findOneAndReplace({_id: ObjectId(updatedStory._id.toString())}, updatedStory, {returnDocument: "after"}) + updatedStory._id = new ObjectId(updatedStory._id.toString()); + return await collection.findOneAndReplace({ _id: new ObjectId(updatedStory._id.toString()) }, updatedStory, { returnDocument: 'after' }); } catch (e) { console.log(`ERROR updateStory: ${e}`); throw e; @@ -299,7 +299,7 @@ async function updateStory(updatedStory) { } // get One Story -// searches the story either by mongoDB _id:ObjectId() or by story_id (from GitHub or Jira) +// searches the story either by mongoDB _id:new ObjectId() or by story_id (from GitHub or Jira) async function getOneStory(storyId) { let query; try { @@ -312,7 +312,7 @@ async function getOneStory(storyId) { }; } else { query = { - _id: ObjectId(storyId.toString()) + _id: new ObjectId(storyId.toString()) }; } return await collection.findOne(query); @@ -329,11 +329,11 @@ async function createStoryGroup(repoID, name, members, sequence) { try { const db = dbConnection.getConnection(); const groups = await db.collection(repositoriesCollection).findOneAndUpdate( - { _id: ObjectId(repoID) }, + { _id: new ObjectId(repoID) }, { $push: { groups: { - _id: ObjectId(), name, member_stories: members, isSequential: sequence + _id: new ObjectId(), name, member_stories: members, isSequential: sequence } } }, @@ -348,13 +348,13 @@ async function createStoryGroup(repoID, name, members, sequence) { async function updateStoryGroup(repoId, groupId, updatedGroup) { try { const db = dbConnection.getConnection(); - updatedGroup._id = ObjectId(updatedGroup._id); + updatedGroup._id = new ObjectId(updatedGroup._id); const collection = await db.collection(repositoriesCollection); - const repo = await collection.findOne({ _id: ObjectId(repoId) }); + const repo = await collection.findOne({ _id: new ObjectId(repoId) }); // leave with double equal: const index = repo.groups.findIndex((o) => o._id == groupId); repo.groups[index] = updatedGroup; - await collection.updateOne({ _id: ObjectId(repoId) }, { $set: repo }); + await collection.updateOne({ _id: new ObjectId(repoId) }, { $set: repo }); return updatedGroup; } catch (e) { console.log(`ERROR in updateStoryGroup: ${e}`); @@ -365,11 +365,11 @@ async function deleteStoryGroup(repoId, groupId) { try { const db = dbConnection.getConnection(); const collection = await db.collection(repositoriesCollection); - const repo = await collection.findOne({ _id: ObjectId(repoId) }); + const repo = await collection.findOne({ _id: new ObjectId(repoId) }); // leave with double equal: const index = repo.groups.findIndex((o) => o._id == groupId); repo.groups.splice(index, 1); - await collection.updateOne({ _id: ObjectId(repoId) }, { $set: repo }); + await collection.updateOne({ _id: new ObjectId(repoId) }, { $set: repo }); return null; } catch (e) { console.log(`ERROR in deleteStoryGroup: ${e}`); @@ -379,7 +379,7 @@ async function deleteStoryGroup(repoId, groupId) { async function getAllStoryGroups(repoId) { try { const db = dbConnection.getConnection(); - return await db.collection(repositoriesCollection).findOne({ _id: ObjectId(repoId) }, { projection: { groups: 1 } }); + return await db.collection(repositoriesCollection).findOne({ _id: new ObjectId(repoId) }, { projection: { groups: 1 } }); } catch (e) { console.log(`ERROR in getAllStoryGroups: ${e}`); } @@ -419,7 +419,7 @@ async function removeFromStoryGroup(repoId, groupId, storyId) { async function updateStoryGroupsArray(repoId, groupsArray) { try { const db = dbConnection.getConnection(); - return await db.collection(repositoriesCollection).findOneAndUpdate({ _id: ObjectId(repoId) }, { $set: { groups: groupsArray } }, { projection: { groups: 1 } }); + return await db.collection(repositoriesCollection).findOneAndUpdate({ _id: new ObjectId(repoId) }, { $set: { groups: groupsArray } }, { projection: { groups: 1 } }); } catch (e) { console.log(`ERROR in updateStoryGroupsArray: ${e}`); } @@ -445,7 +445,7 @@ async function updateBackground(storyId, updatedBackground) { try { const db = dbConnection.getConnection(); const collection = await db.collection(storiesCollection); - return collection.findOneAndUpdate({ _id: ObjectId(storyId) },{$set:{"background": updatedBackground}},{returnDocument: "after", upsert: true}).then((res)=>res.value); + return collection.findOneAndUpdate({ _id: new ObjectId(storyId) }, { $set: { background: updatedBackground } }, { returnDocument: 'after', upsert: true }).then((res) => res.value); } catch (e) { console.log(`ERROR in updateBackground: ${e}`); throw e; @@ -462,10 +462,10 @@ async function createStory(storyTitle, storyDescription, repoId) { let finalIssueNumber = 1; try { const db = dbConnection.getConnection(); - const repo = await db.collection(repositoriesCollection).findOne({ _id: ObjectId(repoId) }); + const repo = await db.collection(repositoriesCollection).findOne({ _id: new ObjectId(repoId) }); if (repo && repo.stories.length > 0) { for (const storyId of repo.stories) { - const story = await db.collection(storiesCollection).findOne({ _id: ObjectId(storyId) }); + const story = await db.collection(storiesCollection).findOne({ _id: new ObjectId(storyId) }); iNumberArray.push(story.issue_number); } finalIssueNumber = iNumberArray.findIndex((_, i) => !iNumberArray.includes(i + 1)) + 1; @@ -487,18 +487,18 @@ async function createStory(storyTitle, storyDescription, repoId) { * @param {*} storyId * @returns deleteReport */ -async function deleteStory(repoId, storyId) { //TODO refactor use promise all +async function deleteStory(repoId, storyId) { // TODO refactor use promise all try { const db = dbConnection.getConnection(); const repo = await db.collection(repositoriesCollection); try { - const groups = await repo.findOne({ _id: ObjectId(repoId) }, { projection: { groups: 1 } }); + const groups = await repo.findOne({ _id: new ObjectId(repoId) }, { projection: { groups: 1 } }); for (const index in groups.groups) groups.groups[index].member_stories = groups.groups[index].member_stories.filter((story) => story !== storyId); - await repo.findOneAndUpdate({ _id: ObjectId(repoId) }, { $set: { groups: groups.groups } }); + await repo.findOneAndUpdate({ _id: new ObjectId(repoId) }, { $set: { groups: groups.groups } }); try { - await repo.findOneAndUpdate({ _id: ObjectId(repoId) }, { $pull: { stories: ObjectId(storyId) } }); + await repo.findOneAndUpdate({ _id: new ObjectId(repoId) }, { $pull: { stories: new ObjectId(storyId) } }); try { - return await db.collection(storiesCollection).findOneAndDelete({ _id: ObjectId(storyId) }); + return await db.collection(storiesCollection).findOneAndDelete({ _id: new ObjectId(storyId) }); } catch (e) { console.log(`ERROR in deleteStory, couldn't delete the Story. Trying to recreate the Repo- and GroupsEntry: ${e}`); // TODO: recreate both Entrys @@ -520,7 +520,7 @@ async function deleteStory(repoId, storyId) { //TODO refactor use promise all async function insertStoryIdIntoRepo(storyId, repoId) { try { const db = dbConnection.getConnection(); - return await db.collection(repositoriesCollection).findOneAndUpdate({ _id: ObjectId(repoId) }, { $push: { stories: ObjectId(storyId) } }); + return await db.collection(repositoriesCollection).findOneAndUpdate({ _id: new ObjectId(repoId) }, { $push: { stories: new ObjectId(storyId) } }); } catch (e) { console.log(`ERROR in insertStoryIdIntoRepo: ${e}`); throw e; @@ -530,20 +530,20 @@ async function insertStoryIdIntoRepo(storyId, repoId) { async function updateScenarioList(storyId, scenarioList) { try { const db = dbConnection.getConnection(); - return await db.collection(storiesCollection).findOneAndUpdate({ _id: ObjectId(storyId) }, { $set: { scenarios: scenarioList } }); + return await db.collection(storiesCollection).findOneAndUpdate({ _id: new ObjectId(storyId) }, { $set: { scenarios: scenarioList } }); } catch (e) { console.log(`ERROR in insertStoryIdIntoRepo: ${e}`); throw e; } } -async function getAllStoriesOfRepo( repoId) { +async function getAllStoriesOfRepo(repoId) { const storiesArray = []; try { const db = dbConnection.getConnection(); - const repo = await db.collection(repositoriesCollection).findOne({ _id: ObjectId(repoId) }); + const repo = await db.collection(repositoriesCollection).findOne({ _id: new ObjectId(repoId) }); if (repo) for (const entry of repo.stories) { - const story = await db.collection(storiesCollection).findOne({ _id: ObjectId(entry) }); + const story = await db.collection(storiesCollection).findOne({ _id: new ObjectId(entry) }); storiesArray.push(story); } return storiesArray; @@ -557,7 +557,7 @@ async function getAllStoriesOfRepo( repoId) { async function getOneScenario(storyId, scenarioId) { try { const db = dbConnection.getConnection(); - const scenarios = await db.collection(storiesCollection).findOne({ _id: ObjectId(storyId), 'scenarios.scenario_id': scenarioId }, { projection: { scenarios: 1 } }); + const scenarios = await db.collection(storiesCollection).findOne({ _id: new ObjectId(storyId), 'scenarios.scenario_id': scenarioId }, { projection: { scenarios: 1 } }); return scenarios.scenarios.find((o) => o.scenario_id === scenarioId); } catch (e) { console.log(`ERROR in getOneScenario: ${e}`); @@ -605,10 +605,15 @@ async function updateScenario(storyId, updatedScenario) { try { const db = dbConnection.getConnection(); const collection = await db.collection(storiesCollection); - return collection.findOneAndUpdate({ _id: ObjectId(storyId) },{$set:{"scenarios.$[it]": updatedScenario}}, - {arrayFilters:[{"it.scenario_id": updatedScenario.scenario_id}], returnDocument: "after", upsert: true, projection:{scenarios:true}})//Options - .then((res)=>{return res.value}) - .then((result)=> result.scenarios.find((scen)=>scen.scenario_id==updatedScenario.scenario_id)) + return collection.findOneAndUpdate( + { _id: new ObjectId(storyId) }, + { $set: { 'scenarios.$[it]': updatedScenario } }, + { + arrayFilters: [{ 'it.scenario_id': updatedScenario.scenario_id }], returnDocument: 'after', upsert: true, projection: { scenarios: true } + } + )// Options + .then((res) => res.value) + .then((result) => result.scenarios.find((scen) => scen.scenario_id == updatedScenario.scenario_id)); } catch (e) { console.log(`ERROR in updateScenario: ${e}`); throw e; @@ -620,7 +625,7 @@ async function deleteScenario(storyId, scenarioId) { try { const db = dbConnection.getConnection(); const collection = await db.collection(storiesCollection); - return collection.findOneAndUpdate({ _id: ObjectId(storyId) },{$pull:{"scenarios":{"scenario_id": scenarioId}}},{returnDocument: "after"}).then((res)=> res.value); + return collection.findOneAndUpdate({ _id: new ObjectId(storyId) }, { $pull: { scenarios: { scenario_id: scenarioId } } }, { returnDocument: 'after' }).then((res) => res.value); } catch (e) { console.log(`ERROR in deleteScenario: ${e}`); throw e; @@ -630,19 +635,19 @@ async function deleteScenario(storyId, scenarioId) { // gets all Repositories of one user async function getRepository(userID) { try { - const myObjt = { owner: ObjectId(userID) }; + const myObjt = { owner: new ObjectId(userID) }; const db = dbConnection.getConnection(); const wGCollection = await db.collection(WorkgroupsCollection); const repoCollection = await db.collection(repositoriesCollection); - const user = await db.collection(userCollection).findOne({ _id: ObjectId(userID) }); + const user = await db.collection(userCollection).findOne({ _id: new ObjectId(userID) }); const positiveWorkgroups = await wGCollection.find({ Members: { $elemMatch: { email: user.email, canEdit: true } } }).toArray(); - const PWgArray = positiveWorkgroups.map((entry) => ObjectId(entry.Repo)); + const PWgArray = positiveWorkgroups.map((entry) => new ObjectId(entry.Repo)); const PWgRepos = await repoCollection.find({ _id: { $in: PWgArray } }).toArray(); PWgRepos.forEach((element) => { element.canEdit = true; }); const negativeWorkgroups = await wGCollection.find({ Members: { $elemMatch: { email: user.email, canEdit: false } } }).toArray(); - const NWgArray = negativeWorkgroups.map((entry) => ObjectId(entry.Repo)); + const NWgArray = negativeWorkgroups.map((entry) => new ObjectId(entry.Repo)); const NWgRepos = await repoCollection.find({ _id: { $in: NWgArray } }).toArray(); NWgRepos.forEach((element) => { element.canEdit = false; @@ -661,7 +666,7 @@ async function getRepository(userID) { // deletes all Repositories of own User async function deleteRepositorys(ownerID) { // TODO: Dringend! Die eingetragenen Storys und die Einträge in Stories und Groups müssen gelöscht werden try { - const query = { owner: ObjectId(ownerID) }; + const query = { owner: new ObjectId(ownerID) }; const db = dbConnection.getConnection(); const collection = await db.collection(repositoriesCollection); return await collection.deleteMany(query); @@ -672,14 +677,14 @@ async function deleteRepositorys(ownerID) { // TODO: Dringend! Die eingetragenen } async function deleteRepository(repoId, ownerId) { // TODO: Dringend! Die eingetragenen Storys und die Einträge in Stories und Groups müssen gelöscht werden - try {// todo delete Workgroup, delete story Reports + try { // todo delete Workgroup, delete story Reports const db = dbConnection.getConnection(); - const collectionRepo = await db.collection(repositoriesCollection) + const collectionRepo = await db.collection(repositoriesCollection); // const collectionStory = await db.collection(storiesCollection) - // const repo = await collectionRepo.findOne({ owner: ObjectId(ownerId), _id: ObjectId(repoId)}) - // const storIds = repo.stories.map((val)=>ObjectId(val)) + // const repo = await collectionRepo.findOne({ owner: new ObjectId(ownerId), _id: new ObjectId(repoId)}) + // const storIds = repo.stories.map((val)=>new ObjectId(val)) // const storiesRes = await collectionStory.deleteMany({_id:{$in: storIds}}) - return collectionRepo.deleteOne({ owner: ObjectId(ownerId), _id: ObjectId(repoId)}) + return collectionRepo.deleteOne({ owner: new ObjectId(ownerId), _id: new ObjectId(repoId) }); } catch (e) { console.log(`ERROR in deleteRepository${e}`); throw e; @@ -688,7 +693,7 @@ async function deleteRepository(repoId, ownerId) { // TODO: Dringend! Die einget async function getOneRepository(ownerId, name) { try { - const repo = { owner: ObjectId(ownerId), repoName: name }; + const repo = { owner: new ObjectId(ownerId), repoName: name }; const db = dbConnection.getConnection(); return db.collection(repositoriesCollection).findOne(repo); } catch (e) { @@ -698,7 +703,7 @@ async function getOneRepository(ownerId, name) { async function getOneRepositoryById(repoId) { try { - const repo = { _id: ObjectId(repoId) }; + const repo = { _id: new ObjectId(repoId) }; const db = dbConnection.getConnection(); return db.collection(repositoriesCollection).findOne(repo); } catch (e) { @@ -758,14 +763,14 @@ async function getAllSourceReposFromDb(source) { async function createRepo(ownerId, name) { try { const emptyRepo = { - owner: ObjectId(ownerId), repoName: name.toString(), stories: [], repoType: 'db', customBlocks: [], groups: [] + owner: new ObjectId(ownerId), repoName: name.toString(), stories: [], repoType: 'db', customBlocks: [], groups: [] }; const db = dbConnection.getConnection(); const collection = await db.collection(repositoriesCollection); - const query = { owner: ObjectId(ownerId), repoName: name.toString() }; + const query = { owner: new ObjectId(ownerId), repoName: name.toString() }; const existingRepo = await collection.findOne(query); if (existingRepo !== null || !name) return 'Sie besitzen bereits ein Repository mit diesem Namen!';// existing or empty name - return collection.insertOne(emptyRepo).then((ret)=>ret.insertedId) + return collection.insertOne(emptyRepo).then((ret) => ret.insertedId); } catch (e) { console.log(`ERROR in createRepo${e}`); } @@ -780,7 +785,7 @@ async function createRepo(ownerId, name) { */ async function updateRepository(repoID, newName, user) { try { - const repoFilter = { owner: ObjectId(user), _id: ObjectId(repoID) }; + const repoFilter = { owner: new ObjectId(user), _id: new ObjectId(repoID) }; const db = dbConnection.getConnection(); const collection = await db.collection(repositoriesCollection); return collection.findOneAndUpdate(repoFilter, { $set: { repoName: newName } }, { returnNewDocument: true }); @@ -810,7 +815,7 @@ async function createGitRepo(gitOwnerId, repoName, userGithubId, userId) { newRepo = { owner: '', gitOwner: gitOwnerId, repoName, stories: [], repoType: 'github', customBlocks: [] }; - if (userGithubId === gitOwnerId) newRepo.owner = ObjectId(userId); + if (userGithubId === gitOwnerId) newRepo.owner = new ObjectId(userId); return await db.collection(repositoriesCollection).insertOne(newRepo); } catch (e) { console.log(`ERROR in createGitRepo${e}`); @@ -822,11 +827,11 @@ async function removeFromWorkgroup(repoId, user) { try { const db = dbConnection.getConnection(); const wGcollection = await db.collection(WorkgroupsCollection); - const repo = await db.collection(repositoriesCollection).findOne({ _id: ObjectId(repoId) }); + const repo = await db.collection(repositoriesCollection).findOne({ _id: new ObjectId(repoId) }); const owner = await db.collection(userCollection).findOne({ _id: repo.owner }); - const workGroup = await wGcollection.findOneAndUpdate({ Repo: ObjectId(repoId) }, { $pull: { Members: { email: user.email } } }); + const workGroup = await wGcollection.findOneAndUpdate({ Repo: new ObjectId(repoId) }, { $pull: { Members: { email: user.email } } }); if (workGroup.value) { - const wG = await wGcollection.findOne({ Repo: ObjectId(repoId) }); + const wG = await wGcollection.findOne({ Repo: new ObjectId(repoId) }); const result = { owner: {}, member: [] }; result.owner = { email: owner.email, canEdit: true }; result.member = wG.Members; @@ -834,7 +839,7 @@ async function removeFromWorkgroup(repoId, user) { } return; } catch (e) { - console.log(`ERROR in removeFromWorkgroup: ${e }`); + console.log(`ERROR in removeFromWorkgroup: ${e}`); throw e; } } @@ -845,14 +850,14 @@ async function updateOwnerInRepo(repoId, newOwnerId, oldOwnerId) { const oldOwner = await getUserById(oldOwnerId); // set new Owner for the given Repo const newOwner = await getUserById(newOwnerId); - await db.collection(repositoriesCollection).findOne({ _id: ObjectId(repoId) }); - await db.collection(repositoriesCollection).findOneAndUpdate({ _id: ObjectId(repoId) }, { $set: { owner: newOwnerId } }); + await db.collection(repositoriesCollection).findOne({ _id: new ObjectId(repoId) }); + await db.collection(repositoriesCollection).findOneAndUpdate({ _id: new ObjectId(repoId) }, { $set: { owner: newOwnerId } }); // remove the new Owner from Workgroup await removeFromWorkgroup(repoId, newOwner); // add old Owner as Member and update Email in Workgroup const wgMember = { email: oldOwner.email, canEdit: Boolean(true) }; - await db.collection(WorkgroupsCollection).findOneAndUpdate({ Repo: ObjectId(repoId) }, { $set: { owner: newOwner.email }, $push: { Members: wgMember } }); + await db.collection(WorkgroupsCollection).findOneAndUpdate({ Repo: new ObjectId(repoId) }, { $set: { owner: newOwner.email }, $push: { Members: wgMember } }); return 'Success'; } catch (e) { console.log(`ERROR in updateOwnerInRepo ${e}`); @@ -862,9 +867,9 @@ async function updateOwnerInRepo(repoId, newOwnerId, oldOwnerId) { async function updateStoriesArrayInRepo(repoId, storiesArray) { // TODO: vllt in updateStory reinnehmen dann spare ich den DBAufruf try { - const sortedStoriesArray = storiesArray.map((s) => ObjectId(s)); + const sortedStoriesArray = storiesArray.map((s) => new ObjectId(s)); const db = dbConnection.getConnection(); - return await db.collection(repositoriesCollection).findOneAndUpdate({ _id: ObjectId(repoId) }, { $set: { stories: sortedStoriesArray } }, { returnNewDocument: true }); + return await db.collection(repositoriesCollection).findOneAndUpdate({ _id: new ObjectId(repoId) }, { $set: { stories: sortedStoriesArray } }, { returnNewDocument: true }); } catch (e) { console.log(`ERROR in updateStoriesArrayInRepo${e}`); throw e; @@ -901,7 +906,7 @@ async function getTestReports(storyId) { const db = dbConnection.getConnection(); console.log('Getting Report for storyId :', storyId); result = await db.collection(ReportDataCollection).find( - { storyId: ObjectId(storyId) }, + { storyId: new ObjectId(storyId) }, { projection: { jsonReport: 0, reportOptions: 0, json: 0 } } ) .toArray(); @@ -917,7 +922,7 @@ async function getGroupTestReports(storyId) { const db = dbConnection.getConnection(); console.log('Getting Groups Reports for storyId :', storyId); // projection value 0 excludes from returning - const query = { storyStatuses: { $elemMatch: { storyId: ObjectId(storyId) } } }; + const query = { storyStatuses: { $elemMatch: { storyId: new ObjectId(storyId) } } }; const result = await db.collection(ReportDataCollection).find( query, { projection: { jsonReport: 0, reportOptions: 0, json: 0 } } @@ -937,18 +942,18 @@ async function deleteReport(reportId) { try { const db = dbConnection.getConnection(); const collection = await db.collection(ReportDataCollection); - const reportData = await collection.findOne({ _id: ObjectId(reportId) }); + const reportData = await collection.findOne({ _id: new ObjectId(reportId) }); if (reportData.smallReport) { idToDelete = reportData.smallReport; console.log('Trying to delete smallReport', idToDelete, ' in DB for Report', reportId); - await db.collection(ReportsCollection).deleteOne({ _id: ObjectId(idToDelete) }); - result = await collection.deleteOne({ _id: ObjectId(reportId) }); + await db.collection(ReportsCollection).deleteOne({ _id: new ObjectId(idToDelete) }); + result = await collection.deleteOne({ _id: new ObjectId(reportId) }); } else { idToDelete = reportData.bigReport; console.log('trying to delete bigReport', idToDelete, ' in DB for Report', reportId); const bucket = await new mongodb.GridFSBucket(db, { bucketName: 'GridFS' }); - bucket.delete(ObjectId(idToDelete)); - result = await collection.deleteOne({ _id: ObjectId(reportId) }); + bucket.delete(new ObjectId(idToDelete)); + result = await collection.deleteOne({ _id: new ObjectId(reportId) }); } } catch (e) { console.log('ERROR in deleteReport', e); @@ -959,7 +964,7 @@ async function deleteReport(reportId) { async function setIsSavedTestReport(testReportId, isSaved) { try { const db = dbConnection.getConnection(); - db.collection(ReportDataCollection).updateOne({ _id: ObjectId(testReportId) }, { + db.collection(ReportDataCollection).updateOne({ _id: new ObjectId(testReportId) }, { $set: { isSaved } }); } catch (e) { @@ -971,7 +976,7 @@ async function setIsSavedTestReport(testReportId, isSaved) { async function updateStoryStatus(storyId, storyLastTestStatus) { try { const db = dbConnection.getConnection(); - db.collection(storiesCollection).updateOne({ _id: ObjectId(storyId) }, { + db.collection(storiesCollection).updateOne({ _id: new ObjectId(storyId) }, { $set: { lastTestPassed: storyLastTestStatus } }); return 'done'; @@ -984,16 +989,15 @@ async function updateStoryStatus(storyId, storyLastTestStatus) { async function updateScenarioStatus(storyId, scenarioId, scenarioLastTestStatus) { // TODO: testen try { const db = dbConnection.getConnection(); - return await db.collection(storiesCollection).updateOne( - { - _id: ObjectId(storyId), - scenarios: { - $elemMatch: - { scenario_id: scenarioId } - } - }, { - $set: { 'scenarios.$.lastTestPassed': scenarioLastTestStatus } - }); + return await db.collection(storiesCollection).updateOne({ + _id: new ObjectId(storyId), + scenarios: { + $elemMatch: + { scenario_id: scenarioId } + } + }, { + $set: { 'scenarios.$.lastTestPassed': scenarioLastTestStatus } + }); } catch (e) { console.log('Error in updateScenarioStatus. Could not set scenario LastTestPassed: ', e); } @@ -1002,7 +1006,7 @@ async function updateScenarioStatus(storyId, scenarioId, scenarioLastTestStatus) async function uploadBigJsonData(data, fileName) { const db = dbConnection.getConnection(); const bucket = await new mongodb.GridFSBucket(db, { bucketName: 'GridFS' }); - const id = ObjectId(); + const id = new ObjectId(); str(JSON.stringify(data)) .pipe(bucket.openUploadStreamWithId(id, fileName)) .on('error', async (error) => { @@ -1022,7 +1026,7 @@ async function uploadReport(reportResults) { const collection = await db.collection(ReportDataCollection); fs.readFile(reportResults.reportOptions.jsonFile, 'utf8', async (err, data) => { if (err) console.log(err); - const jReport = { jsonReport: data, created: new Date()}; + const jReport = { jsonReport: data, created: new Date() }; const len = Buffer.byteLength(JSON.stringify(data)); if (len >= 16000000) { try { @@ -1058,7 +1062,7 @@ async function getReportFromDB(report) { }; } else { const bucket = await new mongodb.GridFSBucket(db, { bucketName: 'GridFS' }); - const reportString = await toString(bucket.openDownloadStream(ObjectId(report.bigReport.toString()))); + const reportString = await toString(bucket.openDownloadStream(new ObjectId(report.bigReport.toString()))); const reportJson = JSON.parse(reportString); result = { _id: report._id, @@ -1086,7 +1090,7 @@ async function getReportByName(reportName) { async function getReportById(reportId) { try { const db = dbConnection.getConnection(); - const report = await db.collection(ReportDataCollection).findOne({ _id: ObjectId(reportId.toString()) }); + const report = await db.collection(ReportDataCollection).findOne({ _id: new ObjectId(reportId.toString()) }); return await getReportFromDB(report); } catch (e) { console.log('ERROR in getReportById (DBServices)', e); @@ -1098,7 +1102,7 @@ async function getReportDataById(reportId) { try { const db = dbConnection.getConnection(); return await db.collection(ReportDataCollection) - .findOne({ _id: ObjectId(reportId.toString()) }); + .findOne({ _id: new ObjectId(reportId.toString()) }); } catch (e) { console.log('ERROR in getReportDataById (DBServices)', e); return {}; @@ -1107,17 +1111,18 @@ async function getReportDataById(reportId) { // delete User in DB needs ID async function deleteUser(userID) { - try {// delete user from Workgroup - const oId = ObjectId(userID); + try { // delete user from Workgroup + const oId = new ObjectId(userID); const myObjt = { _id: oId }; const db = dbConnection.getConnection(); - const repos = await db.collection(repositoriesCollection).find({ owner: oId }).toArray(); + const repos = await db.collection(repositoriesCollection).find({ owner: oId }) + .toArray(); if (repos) { - for (const repo of repos) for (const storyID of repo.stories) await db.collection(storiesCollection).deleteOne({ _id: ObjectId(storyID) }); // use delete repo? + for (const repo of repos) for (const storyID of repo.stories) await db.collection(storiesCollection).deleteOne({ _id: new ObjectId(storyID) }); // use delete repo? const resultRepo = await db.collection(repositoriesCollection).deleteMany({ owner: oId }); const resultUser = await db.collection(userCollection).deleteOne(myObjt); - return {resultUser, resultRepo}; + return { resultUser, resultRepo }; } return null; } catch (e) { @@ -1129,7 +1134,7 @@ async function deleteUser(userID) { // update a User in DB needs ID and JsonObject User returns altered JsonObject User async function updateUser(userID, updatedUser) { try { - const oId = ObjectId(userID); + const oId = new ObjectId(userID); const myObjt = { _id: oId }; const db = dbConnection.getConnection(); const result = await db.collection(userCollection).findOneAndReplace(myObjt, updatedUser); @@ -1143,7 +1148,7 @@ async function updateUser(userID, updatedUser) { // get UserData needs ID returns JsonObject User async function getUserData(userID) { try { - const oId = ObjectId(userID); + const oId = new ObjectId(userID); const myObjt = { _id: oId }; const db = dbConnection.getConnection(); return await db.collection(userCollection).findOne(myObjt); @@ -1156,8 +1161,8 @@ async function getUserData(userID) { async function saveBlock(block) { try { block = mongoSanitize(block); - block.repositoryId = ObjectId(block.repositoryId) - block.owner = ObjectId(block.owner.toString()) + block.repositoryId = new ObjectId(block.repositoryId); + block.owner = new ObjectId(block.owner.toString()); const db = dbConnection.getConnection(); return await db.collection(CustomBlocksCollection).insertOne(block); } catch (e) { @@ -1168,14 +1173,14 @@ async function saveBlock(block) { async function updateBlock(blockId, updatedBlock) { try { - updatedBlock._id = ObjectId(updatedBlock._id); - updatedBlock.repositoryId = ObjectId(updatedBlock.repositoryId); - updatedBlock.owner = ObjectId(updatedBlock.owner); + updatedBlock._id = new ObjectId(updatedBlock._id); + updatedBlock.repositoryId = new ObjectId(updatedBlock.repositoryId); + updatedBlock.owner = new ObjectId(updatedBlock.owner); const db = dbConnection.getConnection(); - updatedBlock._id = ObjectId(updatedBlock._id) - updatedBlock.repositoryId = ObjectId(updatedBlock.repositoryId); - updatedBlock.owner = ObjectId(updatedBlock.owner); - await db.collection(CustomBlocksCollection).findOneAndReplace({_id: ObjectId(blockId)}, updatedBlock); + updatedBlock._id = new ObjectId(updatedBlock._id); + updatedBlock.repositoryId = new ObjectId(updatedBlock.repositoryId); + updatedBlock.owner = new ObjectId(updatedBlock.owner); + await db.collection(CustomBlocksCollection).findOneAndReplace({ _id: new ObjectId(blockId) }, updatedBlock); } catch (e) { console.log(`ERROR in updateBlock: ${e}`); throw e; @@ -1187,7 +1192,7 @@ async function getBlock(blockId) { try { const db = dbConnection.getConnection(); return await db.collection(CustomBlocksCollection) - .findOne({ _id: ObjectId(blockId) }); + .findOne({ _id: new ObjectId(blockId) }); } catch (e) { console.log(`ERROR in getBlock: ${e}`); throw e; @@ -1198,8 +1203,8 @@ async function getBlock(blockId) { async function getBlocks(repoId) { try { const db = dbConnection.getConnection(); - return await db.collection(CustomBlocksCollection).find({ repositoryId: ObjectId(repoId) }) - .toArray(); + return await db.collection(CustomBlocksCollection).find({ repositoryId: new ObjectId(repoId) }) + .toArray(); } catch (e) { console.log(`ERROR in getBlocks: ${e}`); throw e; @@ -1209,8 +1214,8 @@ async function getBlocks(repoId) { async function deleteBlock(blockId, userId) { try { const myObjt = { - _id: ObjectId(blockId), - owner: ObjectId(userId) + _id: new ObjectId(blockId), + owner: new ObjectId(userId) }; const db = dbConnection.getConnection(); await db.collection(CustomBlocksCollection).deleteOne(myObjt); @@ -1224,7 +1229,7 @@ async function deleteBlock(blockId, userId) { async function getWorkgroup(id) { try { const db = dbConnection.getConnection(); - return await db.collection(WorkgroupsCollection).findOne({ Repo: ObjectId(id) }); + return await db.collection(WorkgroupsCollection).findOne({ Repo: new ObjectId(id) }); } catch (e) { console.log(`ERROR in getWorkgroup: ${e}`); throw e; @@ -1232,29 +1237,29 @@ async function getWorkgroup(id) { } /** - * + * * @param {*} repoId Repository Id * @param {object} user User object {email:string, canEdit:boolean} - * @returns + * @returns */ async function addMember(repoId, user) { try { const db = dbConnection.getConnection(); const wGCollection = await db.collection(WorkgroupsCollection); - const check = await wGCollection.findOne({ Repo: ObjectId(repoId), Members: { $elemMatch: { email: user.email } } }); + const check = await wGCollection.findOne({ Repo: new ObjectId(repoId), Members: { $elemMatch: { email: user.email } } }); if (check) return 'Dieser User ist bereits in der Workgroup'; - const repo = await db.collection(repositoriesCollection).findOne({ _id: ObjectId(repoId) }); + const repo = await db.collection(repositoriesCollection).findOne({ _id: new ObjectId(repoId) }); const owner = await db.collection(userCollection).findOne({ _id: repo.owner }); - const workGroup = await wGCollection.findOne({ Repo: ObjectId(repoId) }); - if (!workGroup) { + const workGroup = await wGCollection.findOne({ Repo: new ObjectId(repoId) }); + if (!workGroup) { await wGCollection.insertOne({ - name: repo.repoName, owner: owner.email, Repo: ObjectId(repoId), Members: [{ email: user.email, canEdit: Boolean(user.canEdit) }] + name: repo.repoName, owner: owner.email, Repo: new ObjectId(repoId), Members: [{ email: user.email, canEdit: Boolean(user.canEdit) }] }); } else { - await wGCollection.findOneAndUpdate({ Repo: ObjectId(repoId) }, { $push: { Members: user } }); + await wGCollection.findOneAndUpdate({ Repo: new ObjectId(repoId) }, { $push: { Members: user } }); } const result = { owner: {}, member: [] }; - const wG = await wGCollection.findOne({ Repo: ObjectId(repoId) }); + const wG = await wGCollection.findOne({ Repo: new ObjectId(repoId) }); result.owner = { email: owner.email, canEdit: true }; result.member = wG.Members; return result; @@ -1268,12 +1273,12 @@ async function updateMemberStatus(repoId, user) { try { const db = dbConnection.getConnection(); const wGCollection = await db.collection(WorkgroupsCollection); - const repo = await db.collection(repositoriesCollection).findOne({ _id: ObjectId(repoId) }); + const repo = await db.collection(repositoriesCollection).findOne({ _id: new ObjectId(repoId) }); const usersCollection = await db.collection(userCollection); const owner = await usersCollection.findOne({ _id: repo.owner }); - const updatedWG = await wGCollection.findOneAndUpdate({ Repo: ObjectId(repoId) }, { $set: { 'Members.$[elem].canEdit': Boolean(user.canEdit) } }, { arrayFilters: [{ 'elem.email': user.email }] }); + const updatedWG = await wGCollection.findOneAndUpdate({ Repo: new ObjectId(repoId) }, { $set: { 'Members.$[elem].canEdit': Boolean(user.canEdit) } }, { arrayFilters: [{ 'elem.email': user.email }] }); if (updatedWG) { - const wG = await wGCollection.findOne({ Repo: ObjectId(repoId) }); + const wG = await wGCollection.findOne({ Repo: new ObjectId(repoId) }); const result = { owner: {}, member: [] }; result.owner = { email: owner.email, canEdit: true }; result.member = wG.Members; @@ -1288,9 +1293,9 @@ async function updateMemberStatus(repoId, user) { async function getMembers(id) { try { const db = dbConnection.getConnection(); - const repo = await db.collection(repositoriesCollection).findOne({ _id: ObjectId(id) }); + const repo = await db.collection(repositoriesCollection).findOne({ _id: new ObjectId(id) }); const owner = await db.collection(userCollection).findOne({ _id: repo.owner }); - const wG = await db.collection(WorkgroupsCollection).findOne({ Repo: ObjectId(id) }); + const wG = await db.collection(WorkgroupsCollection).findOne({ Repo: new ObjectId(id) }); if (!wG) return { owner: { email: owner.email, canEdit: true }, member: [] }; const result = { owner: {}, member: [] }; result.owner = { email: owner.email, canEdit: true }; @@ -1307,7 +1312,7 @@ async function updateOneDriver(id, driver) { const oneDriver = !driver.oneDriver; const db = dbConnection.getConnection(); const result = await db.collection(storiesCollection).findOneAndUpdate( - { _id: ObjectId(id) }, + { _id: new ObjectId(id) }, { $set: { oneDriver } } ); return result.value; @@ -1318,7 +1323,7 @@ async function updateOneDriver(id, driver) { function mongoSanitize(v) { // from https://github.com/vkarpov15/mongo-sanitize if (v instanceof Object) { - for (var key in v) { + for (const key in v) { if (/^\$/.test(key)) { delete v[key]; } else { @@ -1327,7 +1332,7 @@ function mongoSanitize(v) { // from https://github.com/vkarpov15/mongo-sanitize } } return v; -}; +} module.exports = { setIsSavedTestReport, @@ -1402,4 +1407,4 @@ module.exports = { updateOwnerInRepo, updateRepository, getOneRepositoryById -}; \ No newline at end of file +}; diff --git a/backend/src/database/installDatabase.js b/backend/src/database/installDatabase.js index 26072b963..378eb316b 100644 --- a/backend/src/database/installDatabase.js +++ b/backend/src/database/installDatabase.js @@ -5,17 +5,17 @@ require('dotenv').config(); const uri = process.env.DATABASE_URI || 'mongodb://SeedAdmin:SeedTest@localhost:27017'; -async function checkConnection() { - let fails = 1; - while (fails <= 3) try { - const client = await MongoClient.connect(uri, { poolSize: 20, useNewUrlParser: true, useUnifiedTopology: true }); +async function getConnection(attempt) { + const attempts = attempt || 1; + if (attempt > 3) throw new Error('\x1b[31mFailed to connect to the database after multiple retries.\x1b[0m'); + + try { + const client = await MongoClient.connect(uri, { maxPoolSize: 20 }); return client; } catch (err) { - console.log(`Connection failed! Retrying... ${fails}`); - fails++; + console.log(`\x1b[38;5;208mConnection failed! Retrying... ${attempts}\x1b[0m`); + return getConnection(attempts + 1); } - - throw new Error('Failed to connect to the database after multiple retries.'); } async function makeCollection(dbo, name) { @@ -41,7 +41,7 @@ async function makeCollection(dbo, name) { async function installDatabase() { console.log(`\x1b[33m Setting Up DB in: ${uri}\n\x1b[0m`); - const client = await checkConnection(); + const client = await getConnection(); const dbo = client.db('Seed'); console.log('Starting: steps'); diff --git a/backend/src/database/mongoDB_admin.js b/backend/src/database/mongoDB_admin.js index 33fdef021..3244a84ee 100644 --- a/backend/src/database/mongoDB_admin.js +++ b/backend/src/database/mongoDB_admin.js @@ -7,7 +7,7 @@ const mongo = require('./DbServices'); const stepTypes = require('./stepTypes'); require('dotenv').config(); -const uri = process.env.DATABASE_URI || "mongodb://SeedAdmin:SeedTest@seedmongodb:27017"; +const uri = process.env.DATABASE_URI || 'mongodb://SeedAdmin:SeedTest@seedmongodb:27017'; const dbName = 'Seed'; // /////////////////////////////////////////// ADMIN METHODS //////////////////////////////////////////// @@ -83,7 +83,7 @@ async function createContent() { // show all Collections function getCollections() { - MongoClient.connect(uri, { useNewUrlParser: true }, (err, db) => { + MongoClient.connect(uri, (err, db) => { if (err) throw err; const dbo = db.db(dbName); dbo.listCollections().toArray((error, result) => { @@ -94,18 +94,10 @@ function getCollections() { }); } -async function installDatabase() { - console.log (`Setting Up DB in: ${uri}`); - await makeCollection('stepTypes'); - await makeCollection('Stories'); - await makeCollection('User'); - await insertMore('stepTypes', stepTypes()); -} - // create Collection async function makeCollection(name) { let connection = []; - await MongoClient.connect(uri, { poolSize: 20, useNewUrlParser: true, useUnifiedTopology: true }, async (err, dbo) => { + await MongoClient.connect(uri, { maxPoolSize: 20 }, async (err, dbo) => { if (err) throw err; connection = dbo.db('Seed'); }); @@ -120,7 +112,7 @@ async function makeCollection(name) { // insert One document (collectionname, {document}) function insertOne(collection, content) { - MongoClient.connect(uri, { useNewUrlParser: true }, (err, db) => { + MongoClient.connect(uri, (err, db) => { if (err) throw err; const dbo = db.db(dbName); dbo.collection(collection).insertOne(content, (error) => { @@ -156,7 +148,7 @@ async function backupScenarios() { // insert Many documents ("collectionname", [{documents},{...}] ) function insertMore(name, content) { - MongoClient.connect(uri, { useNewUrlParser: true }, (err, db) => { + MongoClient.connect(uri, (err, db) => { if (err) throw err; const dbo = db.db(dbName); dbo.collection(name).insertMany(content, (error, res) => { @@ -168,7 +160,7 @@ function insertMore(name, content) { } function update(story_id, updatedStuff) { - MongoClient.connect(uri, { useNewUrlParser: true }, (err, db) => { + MongoClient.connect(uri, (err, db) => { if (err) throw err; const dbo = db.db(dbName); dbo.collection(collection).updateOne({ story_id }, { $set: updatedStuff }, (error, res) => { @@ -180,7 +172,7 @@ function update(story_id, updatedStuff) { // doesnt work yet function eraseAllStories() { - MongoClient.connect(uri, { useNewUrlParser: true }, (err, db) => { + MongoClient.connect(uri, (err, db) => { if (err) throw err; const dbo = db.db(dbName); dbo.collection(collection).deleteOne({}, (error) => { @@ -192,7 +184,7 @@ function eraseAllStories() { // shows single story function showStory(story_id) { - MongoClient.connect(uri, { useNewUrlParser: true }, (err, db) => { + MongoClient.connect(uri, (err, db) => { if (err) throw err; const dbo = db.db(dbName); const myObjt = { story_id }; @@ -206,7 +198,7 @@ function showStory(story_id) { // delete collection function dropCollection() { - MongoClient.connect(uri, { useNewUrlParser: true }, (err, db) => { + MongoClient.connect(uri, (err, db) => { if (err) throw err; const dbo = db.db(dbName); dbo.collection(collection).drop((error, delOK) => { @@ -217,9 +209,8 @@ function dropCollection() { }); } - function deleteOldReports() { - MongoClient.connect(uri, { useNewUrlParser: true }, (err, db) => { + MongoClient.connect(uri, (err, db) => { if (err) throw err; const dbo = db.db(dbName); dbo.collection('TestReport').deleteMany({ reportTime: { $lt: 1622505600000 } }); @@ -229,15 +220,15 @@ function deleteOldReports() { } function fixOldReports() { - MongoClient.connect(uri, { useNewUrlParser: true }, (err, db) => { + MongoClient.connect(uri, (err, db) => { if (err) throw err; const dbo = db.db(dbName); dbo.collection('TestReport') // use updateMany for all reports .updateOne({}, { $rename: { - 'testStatus': 'overallTestStatus', - 'jsonReport': 'json' + testStatus: 'overallTestStatus', + jsonReport: 'json' } }); console.log('Updated Something'); @@ -245,6 +236,14 @@ function fixOldReports() { }); } +async function installDatabase() { + console.log(`Setting Up DB in: ${uri}`); + await makeCollection('stepTypes'); + await makeCollection('Stories'); + await makeCollection('User'); + await insertMore('stepTypes', stepTypes()); +} + module.exports = { installDatabase }; diff --git a/backend/src/database/mongodatabase.js b/backend/src/database/mongodatabase.js index 0f0d4e5f5..dc5563691 100644 --- a/backend/src/database/mongodatabase.js +++ b/backend/src/database/mongodatabase.js @@ -16,7 +16,7 @@ if (!process.env.NODE_ENV) { const dotenv = require('dotenv').config(); } -const uri = process.env.DATABASE_URI || "mongodb://SeedAdmin:SeedTest@seedmongodb:27017"; +const uri = process.env.DATABASE_URI || 'mongodb://SeedAdmin:SeedTest@seedmongodb:27017'; const dbName = 'Seed'; const userCollection = 'User'; const storiesCollection = 'Stories'; @@ -40,7 +40,7 @@ const ReportsCollection = 'Reports'; function connectDb() { return new Promise((resolve, reject) => { mongodb.MongoClient - .connect(uri, { useNewUrlParser: true, useUnifiedTopology: true }, (err, db) => { + .connect(uri, (err, db) => { if (err) reject(err); else resolve(db); }); @@ -118,11 +118,11 @@ async function registerUser(user) { let result; if (dbUser !== null) throw Error('User already exists'); else - if (user.userId) result = await collection.update({ _id: ObjectId(user.userId) }, { $set: { email: user.email, password: user.password } }); - else { - delete user.userId; - result = await collection.insertOne(user); - } + if (user.userId) result = await collection.update({ _id: new ObjectId(user.userId) }, { $set: { email: user.email, password: user.password } }); + else { + delete user.userId; + result = await collection.insertOne(user); + } if (db) db.close(); console.log('I am closing the DB here - registerUser'); return result; @@ -199,7 +199,7 @@ async function getUserById(id) { const db = await connectDb(); const dbo = await db.db(dbName); const collection = await dbo.collection(userCollection); - const result = await collection.findOne({ _id: ObjectId(id) }); + const result = await collection.findOne({ _id: new ObjectId(id) }); db.close(); console.log('I am closing the DB here - getUserById'); return result; @@ -216,7 +216,7 @@ async function updateGithubToken(objId, updatedToken) { const db = await connectDb(); const dbo = await db.db(dbName); const collection = await dbo.collection(userCollection); - const user = await collection.updateOne({ _id: ObjectId(objId) }, { $set: { 'github.githubToken': updatedToken } }); + const user = await collection.updateOne({ _id: new ObjectId(objId) }, { $set: { 'github.githubToken': updatedToken } }); db.close(); console.log('I am closing the DB here - updateGithubToken'); return user; @@ -251,7 +251,7 @@ function selectUsersCollection(db) { } function findStory(storyId, collection) { - const id = ObjectId(storyId); + const id = new ObjectId(storyId); return new Promise((resolve, reject) => { collection.findOne({ _id: id }, (err, result) => { if (err) reject(err); @@ -262,10 +262,10 @@ function findStory(storyId, collection) { function replace(story, collection) { const filter = { - _id: ObjectId(story._id), + _id: new ObjectId(story._id), storySource: story.storySource }; - story._id = ObjectId(story._id); + story._id = new ObjectId(story._id); return new Promise((resolve, reject) => { collection.findOneAndReplace(filter, story, (err, result) => { if (err) reject(err); @@ -282,7 +282,7 @@ async function disconnectGithub(user) { } function replaceUser(newUser, collection) { - const myObjt = { _id: ObjectId(newUser._id) }; + const myObjt = { _id: new ObjectId(newUser._id) }; return new Promise((resolve, reject) => { collection.findOneAndReplace(myObjt, newUser, (err, result) => { if (err) reject(err); @@ -312,9 +312,9 @@ async function getOneStory(storyId) { try { db = await connectDb(); const collection = await selectStoriesCollection(db); - let story = await collection.findOne({ _id: ObjectId(storyId) }); + let story = await collection.findOne({ _id: new ObjectId(storyId) }); // TODO remove later when all used stories have the tag storySource - if (!story) story = await collection.findOne({ _id: ObjectId(storyId) }); + if (!story) story = await collection.findOne({ _id: new ObjectId(storyId) }); return story; } catch (e) { console.log(`UPS!!!! FEHLER in getOneStory: ${e}`); @@ -349,11 +349,11 @@ async function createStoryGroup(repoID, name, members, sequence) { const collection = await selectRepositoryCollection(db); const groups = await collection.findOneAndUpdate( - { _id: ObjectId(repoID) }, + { _id: new ObjectId(repoID) }, { $push: { groups: { - _id: ObjectId(), name, member_stories: members, isSequential: sequence + _id: new ObjectId(), name, member_stories: members, isSequential: sequence } } }, @@ -372,13 +372,13 @@ async function updateStoryGroup(repoId, groupId, updatedGroup) { let db; try { db = await connectDb(); - updatedGroup._id = ObjectId(updatedGroup._id); + updatedGroup._id = new ObjectId(updatedGroup._id); const collection = await selectRepositoryCollection(db); - const repo = await collection.findOne({ _id: ObjectId(repoId) }); + const repo = await collection.findOne({ _id: new ObjectId(repoId) }); // leave with double equal: const index = repo.groups.findIndex((o) => o._id == groupId); repo.groups[index] = updatedGroup; - await collection.updateOne({ _id: ObjectId(repoId) }, { $set: repo }); + await collection.updateOne({ _id: new ObjectId(repoId) }, { $set: repo }); return updatedGroup; } catch (e) { console.log(`UPS!!!! FEHLER in updateStoryGroup: ${e}`); @@ -393,11 +393,11 @@ async function deleteStoryGroup(repoId, groupId) { try { db = await connectDb(); const collection = await selectRepositoryCollection(db); - const repo = await collection.findOne({ _id: ObjectId(repoId) }); + const repo = await collection.findOne({ _id: new ObjectId(repoId) }); // leave with double equal: const index = repo.groups.findIndex((o) => o._id == groupId); repo.groups.splice(index, 1); - await collection.updateOne({ _id: ObjectId(repoId) }, { $set: repo }); + await collection.updateOne({ _id: new ObjectId(repoId) }, { $set: repo }); return null; } catch (e) { console.log(`UPS!!!! FEHLER in deleteStoryGroup: ${e}`); @@ -434,7 +434,7 @@ async function getAllStoryGroups(repoId) { try { db = await connectDb(); const collection = await selectRepositoryCollection(db); - return await collection.findOne({ _id: ObjectId(repoId) }, { projection: { groups: 1 } }); + return await collection.findOne({ _id: new ObjectId(repoId) }, { projection: { groups: 1 } }); } catch (e) { console.log(`UPS!!!! FEHLER in getAllStoryGroups: ${e}`); } finally { @@ -448,7 +448,7 @@ async function updateStoryGroupsArray(repoId, groupsArray) { try { db = await connectDb(); const collection = await selectRepositoryCollection(db); - return await collection.findOneAndUpdate({ _id: ObjectId(repoId) }, { $set: { groups: groupsArray } }, { projection: { groups: 1 } }); + return await collection.findOneAndUpdate({ _id: new ObjectId(repoId) }, { $set: { groups: groupsArray } }, { projection: { groups: 1 } }); } catch (e) { console.log(`UPS!!!! FEHLER in updateStoryGroupsArray: ${e}`); } finally { @@ -527,10 +527,10 @@ async function createStory(storyTitel, storyDescription, repoId) { db = await connectDb(); const repoCollection = await selectRepositoryCollection(db); const collection = await selectStoriesCollection(db); - const repo = await repoCollection.findOne({ _id: ObjectId(repoId) }); + const repo = await repoCollection.findOne({ _id: new ObjectId(repoId) }); if (repo) if (repo.stories.length > 0) { for (const storyId of repo.stories) { - const story = await collection.findOne({ _id: ObjectId(storyId) }); + const story = await collection.findOne({ _id: new ObjectId(storyId) }); iNumberArray.push(story.issue_number); } for (let i = 0; i <= iNumberArray.length; i++) { @@ -563,12 +563,12 @@ async function deleteStory(repoId, storyId) { db = await connectDb(); const collection = await selectStoriesCollection(db); const repo = await selectRepositoryCollection(db); - const delStory = await collection.findOneAndDelete({ _id: ObjectId(storyId) }); - await repo.findOneAndUpdate({ _id: ObjectId(repoId) }, { $pull: { stories: ObjectId(storyId) } }); + const delStory = await collection.findOneAndDelete({ _id: new ObjectId(storyId) }); + await repo.findOneAndUpdate({ _id: new ObjectId(repoId) }, { $pull: { stories: new ObjectId(storyId) } }); - const groups = await repo.findOne({ _id: ObjectId(repoId) }, { projection: { groups: 1 } }); + const groups = await repo.findOne({ _id: new ObjectId(repoId) }, { projection: { groups: 1 } }); for (const index in groups.groups) groups.groups[index].member_stories = groups.groups[index].member_stories.filter((story) => story !== storyId); - await repo.findOneAndUpdate({ _id: ObjectId(repoId) }, { $set: { groups: groups.groups } }); + await repo.findOneAndUpdate({ _id: new ObjectId(repoId) }, { $set: { groups: groups.groups } }); return delStory; } catch (e) { console.log(`UPS!!!! FEHLER in deleteStory: ${e}`); @@ -584,7 +584,7 @@ async function insertStoryIdIntoRepo(storyId, repoId) { try { db = await connectDb(); const collectionRepo = await selectRepositoryCollection(db); - return await collectionRepo.findOneAndUpdate({ _id: ObjectId(repoId) }, { $push: { stories: ObjectId(storyId) } }); + return await collectionRepo.findOneAndUpdate({ _id: new ObjectId(repoId) }, { $push: { stories: new ObjectId(storyId) } }); } catch (e) { console.log(`UPS!!!! FEHLER in insertStoryIdIntoRepo: ${e}`); throw e; @@ -599,7 +599,7 @@ async function updateScenarioList(storyId, scenarioList) { try { db = await connectDb(); const collection = await selectStoriesCollection(db); - return await collection.findOneAndUpdate({ _id: ObjectId(storyId) }, { $set: { scenarios: scenarioList } }); + return await collection.findOneAndUpdate({ _id: new ObjectId(storyId) }, { $set: { scenarios: scenarioList } }); } catch (e) { console.log(`UPS!!!! FEHLER in insertStoryIdIntoRepo: ${e}`); throw e; @@ -616,9 +616,9 @@ async function getAllStoriesOfRepo(ownerId, repoName, repoId) { db = await connectDb(); const collectionRepo = await selectRepositoryCollection(db); const collectionStories = await selectStoriesCollection(db); - const repo = await collectionRepo.findOne({ _id: ObjectId(repoId) }); + const repo = await collectionRepo.findOne({ _id: new ObjectId(repoId) }); if (repo) for (const entry of repo.stories) { - const story = await collectionStories.findOne({ _id: ObjectId(entry) }); + const story = await collectionStories.findOne({ _id: new ObjectId(entry) }); storiesArray.push(story); } return storiesArray; @@ -637,7 +637,7 @@ async function getOneScenario(storyId, storySource, scenarioId) { try { db = await connectDb(); const collection = await selectStoriesCollection(db); - const scenarios = await collection.findOne({ _id: ObjectId(storyId), storySource, 'scenarios.scenario_id': scenarioId }, { projection: { scenarios: 1 } }); + const scenarios = await collection.findOne({ _id: new ObjectId(storyId), storySource, 'scenarios.scenario_id': scenarioId }, { projection: { scenarios: 1 } }); return scenarios.scenarios.find((o) => o.scenario_id === scenarioId); } catch (e) { console.log(`UPS!!!! FEHLER in getOneScenario: ${e}`); @@ -731,21 +731,21 @@ async function deleteScenario(storyId, scenarioId) { async function getRepository(userID) { let db; try { - const myObjt = { owner: ObjectId(userID) }; + const myObjt = { owner: new ObjectId(userID) }; db = await connectDb(); const dbo = db.db(dbName); const wGCollection = await dbo.collection(WorkgroupsCollection); const repoCollection = await selectRepositoryCollection(db); const usersCollection = await selectUsersCollection(db); - const user = await usersCollection.findOne({ _id: ObjectId(userID) }); + const user = await usersCollection.findOne({ _id: new ObjectId(userID) }); const positiveWorkgroups = await wGCollection.find({ Members: { $elemMatch: { email: user.email, canEdit: true } } }).toArray(); - const PWgArray = positiveWorkgroups.map((entry) => ObjectId(entry.Repo)); + const PWgArray = positiveWorkgroups.map((entry) => new ObjectId(entry.Repo)); const PWgRepos = await repoCollection.find({ _id: { $in: PWgArray } }).toArray(); PWgRepos.forEach((element) => { element.canEdit = true; }); const negativeWorkgroups = await wGCollection.find({ Members: { $elemMatch: { email: user.email, canEdit: false } } }).toArray(); - const NWgArray = negativeWorkgroups.map((entry) => ObjectId(entry.Repo)); + const NWgArray = negativeWorkgroups.map((entry) => new ObjectId(entry.Repo)); const NWgRepos = await repoCollection.find({ _id: { $in: NWgArray } }).toArray(); NWgRepos.forEach((element) => { element.canEdit = false; @@ -769,7 +769,7 @@ async function getRepository(userID) { async function deleteRepositorys(ownerID) { let db; try { - const myObjt = { owner: ObjectId(ownerID) }; + const myObjt = { owner: new ObjectId(ownerID) }; db = await connectDb(); const collection = await selectRepositoryCollection(db); return await collection.deleteMany(myObjt); @@ -787,7 +787,7 @@ async function deleteRepository(repoId, ownerId) { try { db = await connectDb(); const collectionRepo = await selectRepositoryCollection(db); - const repo = await collectionRepo.findOne({ owner: ObjectId(ownerId), _id: ObjectId(repoId) }); + const repo = await collectionRepo.findOne({ owner: new ObjectId(ownerId), _id: new ObjectId(repoId) }); return await collectionRepo.deleteOne(repo); } catch (e) { console.log(`UPS!!!! FEHLER in deleteRepository${e}`); @@ -800,7 +800,7 @@ async function deleteRepository(repoId, ownerId) { async function getOneRepository(ownerId, name) { try { - const repo = { owner: ObjectId(ownerId), repoName: name }; + const repo = { owner: new ObjectId(ownerId), repoName: name }; const db = await connectDb(); const collection = await selectRepositoryCollection(db); const result = await collection.findOne(repo); @@ -832,7 +832,7 @@ async function createRepo(ownerId, name) { }; const db = await connectDb(); const collection = await selectRepositoryCollection(db); - const result = await collection.findOne({ owner: ObjectId(ownerId), repoName: name }); + const result = await collection.findOne({ owner: new ObjectId(ownerId), repoName: name }); if (result !== null) return 'Sie besitzen bereits ein Repository mit diesem Namen!'; collection.insertOne(emptyRepo); } @@ -866,7 +866,7 @@ async function createGitOwnerRepoIfNoneExists(ownerId, githubId, gitOwnerId, rep try { db = await connectDb(); const collection = await selectRepositoryCollection(db); - const result = await collection.findOne({ owner: ObjectId(ownerId), repoName }); + const result = await collection.findOne({ owner: new ObjectId(ownerId), repoName }); if (result === null) { let repo = await collection.findOne({ gitOwner: gitOwnerId, repoName }); // create repo / project if there is none @@ -877,7 +877,7 @@ async function createGitOwnerRepoIfNoneExists(ownerId, githubId, gitOwnerId, rep repo = await collection.insertOne(newRepo); return repo; } - if (repo.gitOwner === githubId) repo.owner = ObjectId(ownerId); + if (repo.gitOwner === githubId) repo.owner = new ObjectId(ownerId); return repo; } return result._id; @@ -893,10 +893,10 @@ async function createGitOwnerRepoIfNoneExists(ownerId, githubId, gitOwnerId, rep async function updateStoriesArrayInRepo(repoId, storiesArray) { let db; try { - const sortedStoriesArray = storiesArray.map((s) => ObjectId(s)); + const sortedStoriesArray = storiesArray.map((s) => new ObjectId(s)); db = await connectDb(); const collection = await selectRepositoryCollection(db); - return await collection.findOneAndUpdate({ _id: ObjectId(repoId) }, { $set: { stories: sortedStoriesArray } }, { returnNewDocument: true }); + return await collection.findOneAndUpdate({ _id: new ObjectId(repoId) }, { $set: { stories: sortedStoriesArray } }, { returnNewDocument: true }); } catch (e) { console.log(`UPS!!!! FEHLER in updateStoriesArrayInRepo${e}`); throw e; @@ -943,8 +943,10 @@ async function getTestReports(storyId) { const dbo = db.db(dbName); const collection = await dbo.collection(ReportDataCollection); console.log('Getting Report for storyId :', storyId); - result = await collection.find({ storyId: ObjectId(storyId) }, - { projection: { jsonReport: 0, reportOptions: 0, json: 0 } }).toArray(); + result = await collection.find( + { storyId: new ObjectId(storyId) }, + { projection: { jsonReport: 0, reportOptions: 0, json: 0 } } + ).toArray(); console.log('Got ', result.length, ' reports for :', storyId); } catch (e) { console.log('UPS!!!! FEHLER in getTestReports', e); @@ -963,9 +965,11 @@ async function getGroupTestReports(storyId) { const collection = await dbo.collection(ReportDataCollection); console.log('Getting Groups Reports for storyId :', storyId); // projection value 0 excludes from returning - const query = { storyStatuses: { $elemMatch: { storyId: ObjectId(storyId) } } }; - const result = await collection.find(query, - { projection: { jsonReport: 0, reportOptions: 0, json: 0 } }).toArray(); + const query = { storyStatuses: { $elemMatch: { storyId: new ObjectId(storyId) } } }; + const result = await collection.find( + query, + { projection: { jsonReport: 0, reportOptions: 0, json: 0 } } + ).toArray(); db.close(); console.log('I am closing the DB here - getGroupTestReports'); console.log('Got ', result.length, ' Group Reports for :', storyId); @@ -984,19 +988,19 @@ async function deleteReport(reportId) { db = await connectDb(); const dbo = db.db(dbName); const collection = await dbo.collection(ReportDataCollection); - const reportData = await collection.findOne({ _id: ObjectId(reportId) }); + const reportData = await collection.findOne({ _id: new ObjectId(reportId) }); if (reportData.smallReport) { idToDelete = reportData.smallReport; console.log('Trying to delete smallReport', idToDelete, ' in DB for Report', reportId); const reportsCollection = await dbo.collection(ReportsCollection); - await reportsCollection.deleteOne({ _id: ObjectId(idToDelete) }); - result = await collection.deleteOne({ _id: ObjectId(reportId) }); + await reportsCollection.deleteOne({ _id: new ObjectId(idToDelete) }); + result = await collection.deleteOne({ _id: new ObjectId(reportId) }); } else { idToDelete = reportData.bigReport; console.log('trying to delete bigReport', idToDelete, ' in DB for Report', reportId); const bucket = await new mongodb.GridFSBucket(dbo, { bucketName: 'GridFS' }); - bucket.delete(ObjectId(idToDelete)); - result = await collection.deleteOne({ _id: ObjectId(reportId) }); + bucket.delete(new ObjectId(idToDelete)); + result = await collection.deleteOne({ _id: new ObjectId(reportId) }); } } catch (e) { console.log('UPS!!!! FEHLER in deleteReport', e); @@ -1014,10 +1018,12 @@ async function setIsSavedTestReport(testReportId, isSaved) { db = await connectDb(); const dbo = db.db(dbName); const collection = await dbo.collection(ReportDataCollection); - const updatedReport = await collection.findOne({ _id: ObjectId(testReportId) }); + const updatedReport = await collection.findOne({ _id: new ObjectId(testReportId) }); updatedReport.isSaved = isSaved; - result = await collection.findOneAndReplace({ _id: ObjectId(testReportId) }, - updatedReport); + result = await collection.findOneAndReplace( + { _id: new ObjectId(testReportId) }, + updatedReport + ); } catch (e) { console.log('UPS!!!! FEHLER in setIsSavedTestReport', e); } finally { @@ -1032,7 +1038,7 @@ async function updateStoryStatus(storyId, storyLastTestStatus) { try { db = await connectDb(); const dbo = db.db(dbName); - dbo.collection(storiesCollection).updateOne({ _id: ObjectId(storyId) }, { + dbo.collection(storiesCollection).updateOne({ _id: new ObjectId(storyId) }, { $set: { lastTestPassed: storyLastTestStatus } }); // db.close(); @@ -1049,7 +1055,7 @@ async function updateScenarioStatus(storyId, scenarioId, scenarioLastTestStatus) db = await connectDb(); const dbo = db.db(dbName); const collection = await dbo.collection(storiesCollection); - const story = await collection.findOne({ _id: ObjectId(storyId) }); + const story = await collection.findOne({ _id: new ObjectId(storyId) }); const scenarioList = story.scenarios; const scenario = scenarioList.find((scen) => scen.scenario_id === parseInt(scenarioId, 10)); @@ -1058,7 +1064,7 @@ async function updateScenarioStatus(storyId, scenarioId, scenarioLastTestStatus) scenario.lastTestPassed = scenarioLastTestStatus; story.scenarios[index] = scenario; } - return await collection.findOneAndReplace({ _id: ObjectId(storyId) }, story); + return await collection.findOneAndReplace({ _id: new ObjectId(storyId) }, story); } catch (e) { console.log('Error in updateScenarioStatus. Could not set scenario LastTestPassed: ', e); } finally { @@ -1071,7 +1077,7 @@ async function uploadBigJsonData(data, fileName) { const db = await connectDb(); const dbo = db.db(dbName); const bucket = await new mongodb.GridFSBucket(dbo, { bucketName: 'GridFS' }); - const id = ObjectId(); + const id = new ObjectId(); str(JSON.stringify(data)) .pipe(bucket.openUploadStreamWithId(id, fileName)) .on('error', async (error) => { @@ -1079,7 +1085,7 @@ async function uploadBigJsonData(data, fileName) { }) .on('finish', async () => { console.log('Done! Uplaoded BigReport'); - console.log('ObjectID: of Big Report: ' + id); + console.log(`ObjectID: of Big Report: ${id}`); return id; }); return id; @@ -1096,7 +1102,7 @@ async function uploadReport(reportResults) { if (len >= 16000000) { try { reportData.bigReport = await uploadBigJsonData(jReport, reportResults.storyId); - console.log('ObjectID: of Big Report in UplaodReport: ' + reportData.bigReport); + console.log(`ObjectID: of Big Report in UplaodReport: ${reportData.bigReport}`); collection.insertOne(reportData); } catch (e) { console.log('UPS!!!! FEHLER in uploadReport', e); @@ -1130,11 +1136,11 @@ async function getReport(reportName) { const report = await collection.findOne({ reportName }); if (report.smallReport) { const reportCollection = await dbo.collection(ReportsCollection); - const reportJson = await reportCollection.findOne({ _id: ObjectId(report.smallReport) }); + const reportJson = await reportCollection.findOne({ _id: new ObjectId(report.smallReport) }); result = { _id: report._id, jsonReport: reportJson.jsonReport }; } else { const bucket = await new mongodb.GridFSBucket(dbo, { bucketName: 'GridFS' }); - const reportString = await toString(bucket.openDownloadStream(ObjectId(report.bigReport.toString()))); + const reportString = await toString(bucket.openDownloadStream(new ObjectId(report.bigReport.toString()))); const reportJson = JSON.parse(reportString); result = { _id: report._id, jsonReport: reportJson.jsonReport }; } @@ -1170,7 +1176,7 @@ async function createUser(user) { async function deleteUser(userID) { let db; try { - const oId = ObjectId(userID); + const oId = new ObjectId(userID); const myObjt = { _id: oId }; db = await connectDb(); const collection = await selectUsersCollection(db); @@ -1178,7 +1184,7 @@ async function deleteUser(userID) { const collectionStories = await selectStoriesCollection(db); const repos = await collectionRepo.find({ owner: oId }).toArray(); if (repos) { - for (const repo of repos) for (const storyID of repo.stories) await collectionStories.deleteOne({ _id: ObjectId(storyID) }); + for (const repo of repos) for (const storyID of repo.stories) await collectionStories.deleteOne({ _id: new ObjectId(storyID) }); const resultRepo = await collectionRepo.deleteMany({ owner: oId }); const resultUser = await collection.deleteOne(myObjt); @@ -1198,7 +1204,7 @@ async function deleteUser(userID) { async function updateUser(userID, updatedUser) { let db; try { - const oId = ObjectId(userID); + const oId = new ObjectId(userID); const myObjt = { _id: oId }; db = await connectDb(); const collection = await selectUsersCollection(db); @@ -1217,7 +1223,7 @@ async function updateUser(userID, updatedUser) { async function getUserData(userID) { let db; try { - const oId = ObjectId(userID); + const oId = new ObjectId(userID); const myObjt = { _id: oId }; db = await connectDb(); const collection = await selectUsersCollection(db); @@ -1234,7 +1240,7 @@ async function getUserData(userID) { async function saveBlock(block) { let db; try { - block.repositoryId = ObjectId(block.repositoryId); + block.repositoryId = new ObjectId(block.repositoryId); db = await connectDb(); const dbo = db.db(dbName); const collection = await dbo.collection(CustomBlocksCollection); @@ -1272,7 +1278,7 @@ async function getBlocks(userId, repoId) { db = await connectDb(); const dbo = db.db(dbName); const collection = await dbo.collection(CustomBlocksCollection); - return await collection.find({ repositoryId: ObjectId(repoId) }).toArray(); + return await collection.find({ repositoryId: new ObjectId(repoId) }).toArray(); } catch (e) { console.log(`UPS!!!! FEHLER in getBlocks: ${e}`); throw e; @@ -1286,8 +1292,8 @@ async function deleteBlock(blockId, userId) { let db; try { const myObjt = { - _id: ObjectId(blockId), - owner: ObjectId(userId) + _id: new ObjectId(blockId), + owner: new ObjectId(userId) }; db = await connectDb(); const dbo = db.db(dbName); @@ -1309,7 +1315,7 @@ async function getWorkgroup(id) { db = await connectDb(); const dbo = db.db(dbName); const collection = await dbo.collection(WorkgroupsCollection); - return await collection.findOne({ Repo: ObjectId(id) }); + return await collection.findOne({ Repo: new ObjectId(id) }); } catch (e) { console.log(`UPS!!!! FEHLER in getWorkgroup: ${e}`); throw e; @@ -1325,27 +1331,27 @@ async function addMember(id, user) { db = await connectDb(); const dbo = db.db(dbName); const wGCollection = await dbo.collection(WorkgroupsCollection); - const check = await wGCollection.findOne({ Repo: ObjectId(id), Members: { $elemMatch: { email: user.email } } }); + const check = await wGCollection.findOne({ Repo: new ObjectId(id), Members: { $elemMatch: { email: user.email } } }); if (check) return 'Dieser User ist bereits in der Workgroup'; const rCollection = await dbo.collection(repositoriesCollection); - const repo = await rCollection.findOne({ _id: ObjectId(id) }); + const repo = await rCollection.findOne({ _id: new ObjectId(id) }); const usersCollection = await selectUsersCollection(db); const owner = await usersCollection.findOne({ _id: repo.owner }); - const workGroup = await wGCollection.findOne({ Repo: ObjectId(id) }); + const workGroup = await wGCollection.findOne({ Repo: new ObjectId(id) }); if (!workGroup) { await wGCollection.insertOne({ - name: repo.repoName, owner: owner.email, Repo: ObjectId(id), Members: [{ email: user.email, canEdit: user.canEdit }] + name: repo.repoName, owner: owner.email, Repo: new ObjectId(id), Members: [{ email: user.email, canEdit: user.canEdit }] }); const result = { owner: {}, member: [] }; - const wG = await wGCollection.findOne({ Repo: ObjectId(id) }); + const wG = await wGCollection.findOne({ Repo: new ObjectId(id) }); result.owner = { email: owner.email, canEdit: true }; result.member = wG.Members; return result; } // if there is a workGroup already: - await wGCollection.findOneAndUpdate({ Repo: ObjectId(id) }, { $push: { Members: user } }); + await wGCollection.findOneAndUpdate({ Repo: new ObjectId(id) }, { $push: { Members: user } }); const result = { owner: {}, member: [] }; - const wG = await wGCollection.findOne({ Repo: ObjectId(id) }); + const wG = await wGCollection.findOne({ Repo: new ObjectId(id) }); result.owner = { email: owner.email, canEdit: true }; result.member = wG.Members; return result; @@ -1365,12 +1371,12 @@ async function updateMemberStatus(repoId, user) { const dbo = db.db(dbName); const wGCollection = await dbo.collection(WorkgroupsCollection); const rCollection = await dbo.collection(repositoriesCollection); - const repo = await rCollection.findOne({ _id: ObjectId(repoId) }); + const repo = await rCollection.findOne({ _id: new ObjectId(repoId) }); const usersCollection = await selectUsersCollection(db); const owner = await usersCollection.findOne({ _id: repo.owner }); - const updatedWG = await wGCollection.findOneAndUpdate({ Repo: ObjectId(repoId) }, { $set: { 'Members.$[elem].canEdit': user.canEdit } }, { arrayFilters: [{ 'elem.email': user.email }] }); + const updatedWG = await wGCollection.findOneAndUpdate({ Repo: new ObjectId(repoId) }, { $set: { 'Members.$[elem].canEdit': user.canEdit } }, { arrayFilters: [{ 'elem.email': user.email }] }); if (updatedWG) { - const wG = await wGCollection.findOne({ Repo: ObjectId(repoId) }); + const wG = await wGCollection.findOne({ Repo: new ObjectId(repoId) }); const result = { owner: {}, member: [] }; result.owner = { email: owner.email, canEdit: true }; result.member = wG.Members; @@ -1392,10 +1398,10 @@ async function getMembers(id) { const dbo = db.db(dbName); const wGCollection = await dbo.collection(WorkgroupsCollection); const rCollection = await dbo.collection(repositoriesCollection); - const repo = await rCollection.findOne({ _id: ObjectId(id) }); + const repo = await rCollection.findOne({ _id: new ObjectId(id) }); const usersCollection = await selectUsersCollection(db); const owner = await usersCollection.findOne({ _id: repo.owner }); - const wG = await wGCollection.findOne({ Repo: ObjectId(id) }); + const wG = await wGCollection.findOne({ Repo: new ObjectId(id) }); if (!wG) return { owner: { email: owner.email, canEdit: true }, member: [] }; const result = { owner: {}, member: [] }; result.owner = { email: owner.email, canEdit: true }; @@ -1417,12 +1423,12 @@ async function removeFromWorkgroup(id, user) { const dbo = db.db(dbName); const wGcollection = await dbo.collection(WorkgroupsCollection); const rCollection = await dbo.collection(repositoriesCollection); - const repo = await rCollection.findOne({ _id: ObjectId(id) }); + const repo = await rCollection.findOne({ _id: new ObjectId(id) }); const usersCollection = await selectUsersCollection(db); const owner = await usersCollection.findOne({ _id: repo.owner }); - const workGroup = await wGcollection.findOneAndUpdate({ Repo: ObjectId(id) }, { $pull: { Members: { email: user.email } } }); + const workGroup = await wGcollection.findOneAndUpdate({ Repo: new ObjectId(id) }, { $pull: { Members: { email: user.email } } }); if (workGroup) { - const wG = await wGcollection.findOne({ Repo: ObjectId(id) }); + const wG = await wGcollection.findOne({ Repo: new ObjectId(id) }); const result = { owner: {}, member: [] }; result.owner = { email: owner.email, canEdit: true }; result.member = wG.Members; @@ -1444,7 +1450,7 @@ async function updateOneDriver(id, driver) { db = await connectDb(); const collection = await selectStoriesCollection(db); const result = await collection.findOneAndUpdate( - { _id: ObjectId(id) }, + { _id: new ObjectId(id) }, { $set: { oneDriver } } ); return result.value; diff --git a/backend/src/server.js b/backend/src/server.js index 14aa358c5..8bc489531 100644 --- a/backend/src/server.js +++ b/backend/src/server.js @@ -40,11 +40,11 @@ if (process.env.NODE_ENV) app .use(flash()) .use(session({ store: new MongoStore({ - url: process.env.DATABASE_URI || "mongodb://SeedAdmin:SeedTest@seedmongodb:27017", + url: process.env.DATABASE_URI || 'mongodb://SeedAdmin:SeedTest@seedmongodb:27017', dbName: 'Seed', collection: 'Sessions' }), - secret: process.env.SESSION_SECRET || "unsaveSecret", + secret: process.env.SESSION_SECRET || 'unsaveSecret', resave: false, saveUninitialized: false, proxy: true, @@ -56,7 +56,7 @@ if (process.env.NODE_ENV) app else app .use(flash()) .use(session({ - secret: process.env.SESSION_SECRET || "unsaveSecret", + secret: process.env.SESSION_SECRET || 'unsaveSecret', resave: false, saveUninitialized: false, proxy: true @@ -74,7 +74,7 @@ app .use(passport.initialize()) .use(passport.session()) .use((_, __, next) => { - logging.httpLog(_, __, next) + logging.httpLog(_, __, next); }) .use('/api/script', scriptRouter) .use('/api/run', runReportRouter) diff --git a/backend/src/serverRouter/blockRouter.js b/backend/src/serverRouter/blockRouter.js index b453f72cf..cafbb5546 100644 --- a/backend/src/serverRouter/blockRouter.js +++ b/backend/src/serverRouter/blockRouter.js @@ -37,7 +37,7 @@ router.post('/', async (req, res) => { try { const { body } = req; if (!req.user) { res.sendStatus(401); return; } - body.owner = ObjectID(req.user._id); + body.owner = new ObjectID(req.user._id); const result = await mongo.saveBlock(body); res.status(200).json(result); } catch (error) { diff --git a/backend/src/serverRouter/userRouter.js b/backend/src/serverRouter/userRouter.js index 75b27587f..8bf6bed08 100644 --- a/backend/src/serverRouter/userRouter.js +++ b/backend/src/serverRouter/userRouter.js @@ -63,8 +63,8 @@ router.post('/resetpassword', async (req, res) => { try { await nodeMail.sendResetLink(thisUser.email, id); res.status(200) - .json(); - } catch(err) { + .json(); + } catch (err) { res.status(500).send(err.message); } } catch (error) { @@ -72,7 +72,7 @@ router.post('/resetpassword', async (req, res) => { .json(error); } else { console.log('UserRouter/ResetPassword: der Benutzer konnte nicht in der Datenbank gefunden werden!'); - res.status(404).send("No user found with the given email adress!"); + res.status(404).send('No user found with the given email adress!'); } }); @@ -167,7 +167,7 @@ router.post('/register', async (req, res) => { // logout for user router.get('/logout', async (req, res) => { - req.logout({}, () => {}); + req.logout({}, () => { }); res.clearCookie('connect.sid', { path: '/' }); res.status(200).send({ status: 'success' }); }); @@ -187,6 +187,7 @@ router.get('/repositories', (req, res) => { githubId = 0; } // get repositories from individual sources + console.log(req); Promise.all([ projectMng.starredRepositories(req.user._id, githubId, githubName, token), projectMng.ownRepositories(req.user._id, githubId, githubName, token), @@ -257,7 +258,7 @@ router.get('/stories', async (req, res) => { // put into ticketManagement.ts const { source } = req.query; // get GitHub Repo / Projects if (source === 'github' || !source) try { - if (!userMng.checkValidGithub(req.query.githubName, req.query.repository))console.log('Username or Reponame not valid'); + if (!userMng.checkValidGithub(req.query.githubName, req.query.repository)) console.log('Username or Reponame not valid'); const githubName = (req.user) ? req.query.githubName : process.env.TESTACCOUNT_NAME; const githubRepo = (req.user) ? req.query.repository : process.env.TESTACCOUNT_REPO; @@ -310,7 +311,7 @@ router.get('/stories', async (req, res) => { // put into ticketManagement.ts } catch (err) { res.status(503).send(err.message); - // get Jira Repo / Projects + // get Jira Repo / Projects } else if (source === 'jira' && typeof req.user !== 'undefined' && typeof req.user.jira !== 'undefined' && req.query.projectKey !== 'null') { // prepare request const { projectKey } = req.query; @@ -318,7 +319,7 @@ router.get('/stories', async (req, res) => { // put into ticketManagement.ts const clearPass = jiraTracker.decryptPassword(req.user.jira); const { AccountName, AuthMethod, Host } = req.user.jira; let authString = `Bearer ${clearPass}`; - if (AuthMethod === 'basic') { + if (AuthMethod === 'basic') { const auth = Buffer.from(`${AccountName}:${clearPass}`).toString('base64'); authString = `Basic ${auth}`; } @@ -438,9 +439,9 @@ router.get('/callback', (req, res) => { const TOKEN_URL = 'https://github.com/login/oauth/access_token'; const params = new URLSearchParams(); if (!process.env.GITHUB_CLIENT_ID || !process.env.GITHUB_CLIENT_SECRET) { - console.log("To use github authentication please provide your GITHUB_CLIENT_ID and your GITHUB_CLIENT_SECRET. You can see how to in the README."); - res.status(501).send("No GITHUB_CLIENT_ID or GITHUB_CLIENT_SECRET provided.") - return + console.log('To use github authentication please provide your GITHUB_CLIENT_ID and your GITHUB_CLIENT_SECRET. You can see how to in the README.'); + res.status(501).send('No GITHUB_CLIENT_ID or GITHUB_CLIENT_SECRET provided.'); + return; } params.append('client_id', process.env.GITHUB_CLIENT_ID); @@ -467,7 +468,7 @@ router.get('/callback', (req, res) => { router.post('/log', (req, res) => { const stream = fs.createWriteStream('./logs/front.log', { flags: 'a' }); - stream.write(req.body.message + JSON.stringify(req.body.additional) + '\n'); + stream.write(`${req.body.message + JSON.stringify(req.body.additional)}\n`); stream.close(); res.status(200).json('logged'); }); From e184ee7d23feb85b281c635baa2cc1558b531fc2 Mon Sep 17 00:00:00 2001 From: i3rotlher Date: Wed, 15 Nov 2023 11:02:50 +0100 Subject: [PATCH 22/54] removed log --- backend/src/serverRouter/userRouter.js | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/serverRouter/userRouter.js b/backend/src/serverRouter/userRouter.js index 8bf6bed08..769df09d5 100644 --- a/backend/src/serverRouter/userRouter.js +++ b/backend/src/serverRouter/userRouter.js @@ -187,7 +187,6 @@ router.get('/repositories', (req, res) => { githubId = 0; } // get repositories from individual sources - console.log(req); Promise.all([ projectMng.starredRepositories(req.user._id, githubId, githubName, token), projectMng.ownRepositories(req.user._id, githubId, githubName, token), From 33bad4996bd6d70392eebbb8a2f752537cdcdcf6 Mon Sep 17 00:00:00 2001 From: i3rotlher Date: Wed, 15 Nov 2023 12:26:12 +0100 Subject: [PATCH 23/54] updated resolves --- backend/src/database/DbServices.js | 21 ++++----------------- backend/src/database/mongodatabase.js | 14 ++------------ 2 files changed, 6 insertions(+), 29 deletions(-) diff --git a/backend/src/database/DbServices.js b/backend/src/database/DbServices.js index 8583a7f36..1e918dda9 100644 --- a/backend/src/database/DbServices.js +++ b/backend/src/database/DbServices.js @@ -198,7 +198,7 @@ async function registerGithubUser(user) { */ function replaceUser(newUser, collection) { const myObjt = { _id: new ObjectId(newUser._id) }; - return collection.findOneAndReplace(myObjt, newUser).then((res) => res.value); + return collection.findOneAndReplace(myObjt, newUser); } async function updateGithubToken(objId, updatedToken) { @@ -242,18 +242,11 @@ async function mergeGithub(userId, login, id) { * * @returns updated UserObject * @param storyId - * @param storySource * @param collection */ -// TODO: storySource wont be needed anymore function findStory(storyId, collection) { const id = new ObjectId(storyId); - return new Promise((resolve, reject) => { - collection.findOne({ _id: id }, (err, result) => { - if (err) reject(err); - else resolve(result); - }); - }); + return collection.findOne({ _id: id }); } /** @@ -267,12 +260,7 @@ function replace(story, collection) { _id: new ObjectId(story._id.toString()) }; story._id = new ObjectId(story._id); - return new Promise((resolve, reject) => { - collection.findOneAndReplace(filter, story, (err, result) => { - if (err) reject(err); - else resolve(result.value); - }); - }); + return collection.findOneAndReplace(filter, story); } async function disconnectGithub(user) { @@ -445,7 +433,7 @@ async function updateBackground(storyId, updatedBackground) { try { const db = dbConnection.getConnection(); const collection = await db.collection(storiesCollection); - return collection.findOneAndUpdate({ _id: new ObjectId(storyId) }, { $set: { background: updatedBackground } }, { returnDocument: 'after', upsert: true }).then((res) => res.value); + return collection.findOneAndUpdate({ _id: new ObjectId(storyId) }, { $set: { background: updatedBackground } }, { returnDocument: 'after', upsert: true }); } catch (e) { console.log(`ERROR in updateBackground: ${e}`); throw e; @@ -612,7 +600,6 @@ async function updateScenario(storyId, updatedScenario) { arrayFilters: [{ 'it.scenario_id': updatedScenario.scenario_id }], returnDocument: 'after', upsert: true, projection: { scenarios: true } } )// Options - .then((res) => res.value) .then((result) => result.scenarios.find((scen) => scen.scenario_id == updatedScenario.scenario_id)); } catch (e) { console.log(`ERROR in updateScenario: ${e}`); diff --git a/backend/src/database/mongodatabase.js b/backend/src/database/mongodatabase.js index dc5563691..c8684f04a 100644 --- a/backend/src/database/mongodatabase.js +++ b/backend/src/database/mongodatabase.js @@ -266,12 +266,7 @@ function replace(story, collection) { storySource: story.storySource }; story._id = new ObjectId(story._id); - return new Promise((resolve, reject) => { - collection.findOneAndReplace(filter, story, (err, result) => { - if (err) reject(err); - else resolve(result.value); - }); - }); + return collection.findOneAndReplace(filter, story); } async function disconnectGithub(user) { @@ -283,12 +278,7 @@ async function disconnectGithub(user) { function replaceUser(newUser, collection) { const myObjt = { _id: new ObjectId(newUser._id) }; - return new Promise((resolve, reject) => { - collection.findOneAndReplace(myObjt, newUser, (err, result) => { - if (err) reject(err); - else resolve(result.value); - }); - }); + return collection.findOneAndReplace(myObjt, newUser); } async function updateStory(updatedStuff) { From 8685bb0c2643f8e2c6245247531f4dc23940defa Mon Sep 17 00:00:00 2001 From: NessArt Date: Thu, 16 Nov 2023 13:47:42 +0100 Subject: [PATCH 24/54] working multiple scenario highlight --- .../app/base-editor/base-editor.component.ts | 16 +---- .../example-table.component.html | 2 +- .../example-table/example-table.component.ts | 68 ++++++++++++------- 3 files changed, 46 insertions(+), 40 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index 0aeef1c59..8c40cd607 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -2013,21 +2013,7 @@ export class BaseEditorComponent { //TODO - //multiple scenario //beim hinzufügen von blöcken oder kopierten wird nicht gehighlighted - //zentrale Bloeke -> geht aber in ansicht ohne feld schwarz - //higlighting start @@ und ende whitespace oder zeile - - //span.setAttribute('class', 'regexStyling'); -> wie funktioniert darkmode - /*.regexStyling { - color: var(--ocean-blue); - font-weight: bold; -} - -.darkTheme .regexStyling em{ - color: var(--light-blue) !important; - font-weight: bold; -}*/ /** @@ -2039,7 +2025,7 @@ export class BaseEditorComponent { * @param stepType for addToValue * @param step for addToValue * @param stepPre pre text of step - * @param initialCall if call is from ngAfterViewInit + * @param initialCall if call is from ngDoCheck */ highlightRegex(element:string, stepIndex?: number, valueIndex?: number, stepType?: string, step?:StepType, stepPre?: string, initialCall?:boolean) { const regexPattern = /@@[^ ]+/g;// Regex pattern to recognize and highlight regex expressions -> start with @@ diff --git a/frontend/src/app/example-table/example-table.component.html b/frontend/src/app/example-table/example-table.component.html index 45143c011..3c0779cef 100644 --- a/frontend/src/app/example-table/example-table.component.html +++ b/frontend/src/app/example-table/example-table.component.html @@ -38,7 +38,7 @@
-
{{element[column]}}
+
{{element[column]}}
-
{{currentStep.values[0]}}
+
{{currentStep.values[0]}}
-
{{currentStep.values[1]}}
+
{{currentStep.values[1]}}
-
{{currentStep.values[2]}}
+
{{currentStep.values[2]}}
-
{{currentStep.values[0]}}
+
{{currentStep.values[0]}}
{{currentStep.mid}}
@@ -420,7 +420,7 @@ *ngIf="currentStep.values[1] != null" type="text" value="{{currentStep.values[1]}}" on-input="addToValues(step_type_input.value,j,1,currentStep.stepType)" style="padding-left: 5px; padding-right: 5px;min-width: 100px" /--> -
{{currentStep.values[1]}}
+
{{currentStep.values[1]}}
{{currentStep.post}}
@@ -429,7 +429,7 @@ *ngFor="let value of currentStep.values | slice:2; let n = index" type="text" value="{{value}}" on-input="addToValues(step_type_input.value,j , n + 2, currentStep.stepType)" style="padding-left: 5px; padding-right: 5px;min-width: 100px" /--> -
{{currentStep.values[2]}}
+
{{currentStep.values[2]}}
diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index 2131a6485..f8e52e9c2 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -78,6 +78,7 @@ export class BaseEditorComponent { this.checkAllSteps(false); } this.selectedScenario = scenario; + this.initialRegex = true; } @Input() @@ -93,6 +94,7 @@ export class BaseEditorComponent { @Input() set newlySelectedStory(story: Story) { this.selectedStory = story; + this.initialRegex = true; } /** @@ -230,6 +232,7 @@ export class BaseEditorComponent { this.renameExampleObservable = this.exampleService.renameExampleEvent.subscribe(value => { this.renameExample(value.name, value.column); }); this.scenarioChangedObservable = this.scenarioService.scenarioChangedEvent.subscribe(() => { this.checkAllSteps(false); + this.initialRegex = true; }); this.backgroundChangedObservable = this.backgroundService.backgroundChangedEvent.subscribe(() => { this.checkAllSteps(false); @@ -276,10 +279,6 @@ export class BaseEditorComponent { } - ngOnChanges(){ - this.initialRegex = true; - } - /** * retrieves the saved block from the session storage */ @@ -306,29 +305,20 @@ export class BaseEditorComponent { if (this.allChecked) { this.checkAllSteps(this.allChecked); } + } + ngAfterViewChecked(){ + this.regexDOMChangesHelper() if(this.initialRegex){ this.regexHighlightOnInit() } } ngAfterViewInit(): void { - this.step_type_input.changes.subscribe(_ => { - this.step_type_input.forEach(in_field => { - if (in_field.nativeElement.id === this.lastToFocus) { - in_field.nativeElement.focus(); - } - }); - this.lastToFocus = ''; - }); - this.step_type_input1.changes.subscribe(_ => { - this.step_type_input1.forEach(in_field => { - if (in_field.nativeElement.id === this.lastToFocus) { - in_field.nativeElement.focus(); - } - }); - this.lastToFocus = ''; - }); + this.regexDOMChangesHelper() + if(this.initialRegex){ + this.regexHighlightOnInit() + } if (this.exampleChildren.last != undefined) { this.exampleChild = this.exampleChildren.last; @@ -2015,28 +2005,24 @@ export class BaseEditorComponent { this.markUnsaved(); } - //TODO code redundanz, tooltip mouseposition, story/scenario highlight wenn wechsel (directives?), example - /** * Add value and highlight regex, Style regex in value and give value to addToValue() function * Value is in textContent and style is in innerHTML * If initialCall only check if a regex is already there and hightlight it * Only hightlights regex in first field of regexSteps, only then steps for now. Gets checked with stepPre * Get cursor position with getCaretCharacterOffsetWithin Helper and set position again, else it is lost because of overwriting and changing the HTML Element in case of hightlighting - * @param element id of HTML div + * @param element HTML element of contentedible div * @param stepIndex for addToValue * @param valueIndex for addToValue * @param stepType for addToValue * @param step for addToValue * @param stepPre pre text of step - * @param initialCall if call is from ngDoCheck + * @param initialCall if call is from ngAfterView */ - highlightRegex(element:string, stepIndex?: number, valueIndex?: number, stepType?: string, step?:StepType, stepPre?: string, initialCall?:boolean) { + highlightRegex(element, stepIndex?: number, valueIndex?: number, stepType?: string, step?:StepType, stepPre?: string, initialCall?:boolean) { const regexPattern =/(\{Regex:)(.*?)(\})(?=\s|$)/g;// Regex pattern to recognize and highlight regex expressions -> start with {Regex: and end with } - //const regexPattern2 =/\/\^.*?\$\/(?:\s*\/\^.*?\$\/)*(?=\s|$)/g;// Regex pattern to recognize and highlight regex expressions -> start with /^ and end with $/ - //const regexPattern = new RegExp(`${regexPattern1.source}|${regexPattern2.source}`, 'g'); - const textField = document.getElementById(element); + const textField = element//document.getElementById(element); const textContent = textField.textContent; //Get current cursor position const offset = this.getCaretCharacterOffsetWithin(textField) @@ -2071,7 +2057,6 @@ export class BaseEditorComponent { }); } } - textField.innerHTML = highlightedText // Toastr logic @@ -2176,27 +2161,81 @@ export class BaseEditorComponent { */ regexHighlightOnInit(){ // Regex Highlight on init - this.regexInStory = false + this.regexInStory = false; + this.initialRegex = false; //Logic currently not needed since regex only in then step /*if(this.step_type_input){ //background this.step_type_input.forEach(in_field => { this.highlightRegex(in_field.nativeElement.id,undefined,undefined,undefined,undefined,true) }); }*/ - if(this.step_type_input1){ //scenario + if(this.step_type_input1){ //scenario first input value const stepTypePre = this.step_type_pre.toArray() this.step_type_input1.forEach((in_field, index) => { - this.highlightRegex(in_field.nativeElement.id,undefined,0,undefined,undefined,stepTypePre[index].nativeElement.innerText, true) + this.highlightRegex(in_field.nativeElement,undefined,0,undefined,undefined,stepTypePre[index].nativeElement.innerText, true) }); //Logic currently not needed since regex only in first input field - /*this.step_type_input2.forEach((in_field, index) => { - this.highlightRegex(in_field.nativeElement.id,undefined,1,undefined,undefined,stepTypePre1[index].nativeElement.innerText, true) + /*this.step_type_input2.forEach((in_field, index) => { //scenario second input value + this.highlightRegex(in_field.nativeElement.id,undefined,1,undefined,undefined,stepTypePre1[index].nativeElement.innerText, true) }); - this.step_type_input3.forEach((in_field, index) => { - this.highlightRegex(in_field.nativeElement.id,undefined,2,undefined,undefined,stepTypePre1[index].nativeElement.innerText, true) + this.step_type_input3.forEach((in_field, index) => { //scenario third input value + this.highlightRegex(in_field.nativeElement.id,undefined,2,undefined,undefined,stepTypePre1[index].nativeElement.innerText, true) });*/ } } + /** + * Helper for DOM change subscription + */ + regexDOMChangesHelper(){ + + //Logic currently not needed + /*this.step_type_input.changes.subscribe(_ => { //background + this.step_type_input.forEach(in_field => { + if (in_field.nativeElement.id === this.lastToFocus) { + in_field.nativeElement.focus(); + } + }); + this.lastToFocus = ''; + });*/ + + this.step_type_pre.changes.subscribe(_ => { //scenario text before first input value + this.step_type_pre.forEach(in_field => { + if (in_field.nativeElement.id === this.lastToFocus) { + in_field.nativeElement.focus(); + } + }); + this.lastToFocus = ''; + }); + + this.step_type_input1.changes.subscribe(_ => { //scenario first input value + this.step_type_input1.forEach(in_field => { + if (in_field.nativeElement.id === this.lastToFocus) { + in_field.nativeElement.focus(); + } + }); + this.lastToFocus = ''; + }); + + //Logic currently not needed + /*this.step_type_input2.changes.subscribe(_ => { //scenario second input value + this.step_type_input2.forEach(in_field => { + if (in_field.nativeElement.id === this.lastToFocus) { + in_field.nativeElement.focus(); + } + }); + this.lastToFocus = ''; + }); + this.step_type_input3.changes.subscribe(_ => { //scenario third input value + this.step_type_input3.forEach(in_field => { + if (in_field.nativeElement.id === this.lastToFocus) { + in_field.nativeElement.focus(); + } + }); + this.lastToFocus = ''; + });*/ + + } + } \ No newline at end of file diff --git a/frontend/src/app/example-table/example-table.component.ts b/frontend/src/app/example-table/example-table.component.ts index 05b627584..0dcf3d3db 100644 --- a/frontend/src/app/example-table/example-table.component.ts +++ b/frontend/src/app/example-table/example-table.component.ts @@ -132,6 +132,7 @@ export class ExampleTableComponent implements OnInit { set newSelectedScenario(scenario: Scenario) { this.selectedScenario = scenario; this.updateTable(); + this.initialRegex = true; } @Input() isDark: boolean; @@ -175,7 +176,7 @@ export class ExampleTableComponent implements OnInit { this.isDark = this.themeService.isDarkMode(); this.themeObservable = this.themeService.themeChanged.subscribe((changedTheme) => { this.isDark = this.themeService.isDarkMode(); - this.regexHightlightOnInit(); + this.regexHighlightOnInit(); }); } @@ -192,9 +193,17 @@ export class ExampleTableComponent implements OnInit { } } - ngDoCheck(){ + ngAfterViewInit(){ + this.regexDOMChangesHelper(); if(this.initialRegex){ - this.regexHightlightOnInit(); + this.regexHighlightOnInit() + } + } + + ngAfterViewChecked(){ + this.regexDOMChangesHelper(); + if(this.initialRegex){ + this.regexHighlightOnInit() } } @@ -247,7 +256,7 @@ export class ExampleTableComponent implements OnInit { } this.data.push(js); } - this.regexHightlightOnInit(); + this.regexHighlightOnInit(); } /** @@ -418,9 +427,7 @@ export class ExampleTableComponent implements OnInit { * @param initialCall if call is from ngDoCheck */ private highlightRegex(el, columnIndex, rowIndex, initialCall) { - const regexPattern1 =/\[Regex:(.*?)](?=\s|$)/g;// Regex pattern to recognize and highlight regex expressions -> start with [Regex: and end with ] - const regexPattern2 =/\/\^.*?\$\/(?:\s*\/\^.*?\$\/)*(?=\s|$)/g;// Regex pattern to recognize and highlight regex expressions -> start with /^ and end with $/ - const regex = /(\{Regex:)(.*?)(\})(?=\s|$)/g;//new RegExp(`${regexPattern1.source}|${regexPattern2.source}`, 'g'); + const regex = /(\{Regex:)(.*?)(\})(?=\s|$)/g;// Regex pattern to recognize and highlight regex expressions -> start with {Regex: and end with } const inputValue: string = el.textContent; const offset = this.getCaretCharacterOffsetWithin(el) @@ -553,12 +560,20 @@ export class ExampleTableComponent implements OnInit { /** * Helper for inital hightlighting */ - regexHightlightOnInit(){ + regexHighlightOnInit(){ this.regexInStory = false - if(this.example_input){ - this.example_input.forEach(in_field => { - this.highlightRegex(in_field.nativeElement, undefined, undefined, true) - }); - } + this.initialRegex = false + if(this.example_input){ + this.example_input.forEach(in_field => { + this.highlightRegex(in_field.nativeElement, undefined, undefined, true) + }); + } + } + + /** + * Helper for DOM change subscription + */ + regexDOMChangesHelper(){ + this.example_input.changes.subscribe(_ => {}); } } From 923817418a8bb3730a4ee32adec3544b0daacec9 Mon Sep 17 00:00:00 2001 From: i3rotlher Date: Mon, 4 Dec 2023 14:18:48 +0100 Subject: [PATCH 39/54] result.value -> result --- backend/src/database/DbServices.js | 8 ++++---- backend/src/database/mongodatabase.js | 8 ++++---- backend/src/serverRouter/blockRouter.js | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/backend/src/database/DbServices.js b/backend/src/database/DbServices.js index 6dfd5f224..d075689d8 100644 --- a/backend/src/database/DbServices.js +++ b/backend/src/database/DbServices.js @@ -874,13 +874,13 @@ async function upsertEntry(storyId, updatedContent) { upsert: false }); // TODO remove later when all used stories have the tag storySource - if (!result.value) { + if (!result) { myObjt.storySource = undefined; result = await collection.findOneAndUpdate(myObjt, { $set: updatedContent }, { upsert: true }); } - return result.value; + return result; } catch (e) { console.log(`ERROR in upsertEntry: ${e}`); throw e; @@ -1125,7 +1125,7 @@ async function updateUser(userID, updatedUser) { const myObjt = { _id: oId }; const db = dbConnection.getConnection(); const result = await db.collection(userCollection).findOneAndReplace(myObjt, updatedUser); - return result.value; + return result; } catch (e) { console.log(`ERROR in updateUser: ${e}`); throw e; @@ -1302,7 +1302,7 @@ async function updateOneDriver(id, driver) { { _id: new ObjectId(id) }, { $set: { oneDriver } } ); - return result.value; + return result; } catch (e) { console.log('ERROR in updateOneDriver: ', e); } diff --git a/backend/src/database/mongodatabase.js b/backend/src/database/mongodatabase.js index e019dde74..3f4cffb44 100644 --- a/backend/src/database/mongodatabase.js +++ b/backend/src/database/mongodatabase.js @@ -909,13 +909,13 @@ async function upsertEntry(storyId, updatedContent, storySource) { upsert: false }); // TODO remove later when all used stories have the tag storySource - if (!result.value) { + if (!result) { myObjt.storySource = undefined; result = await collection.findOneAndUpdate(myObjt, { $set: updatedContent }, { upsert: true }); } - return result.value; + return result; } catch (e) { console.log(`UPS!!!! FEHLER in upsertEntry: ${e}`); throw e; @@ -1199,7 +1199,7 @@ async function updateUser(userID, updatedUser) { db = await connectDb(); const collection = await selectUsersCollection(db); const result = await collection.findOneAndReplace(myObjt, updatedUser); - return result.value; + return result; } catch (e) { console.log(`UPS!!!! FEHLER in updateUser: ${e}`); throw e; @@ -1443,7 +1443,7 @@ async function updateOneDriver(id, driver) { { _id: new ObjectId(id) }, { $set: { oneDriver } } ); - return result.value; + return result; } catch (e) { console.log('UPS!!!! FEHLER in updateOneDriver: ', e); } finally { diff --git a/backend/src/serverRouter/blockRouter.js b/backend/src/serverRouter/blockRouter.js index cafbb5546..6a84ffa33 100644 --- a/backend/src/serverRouter/blockRouter.js +++ b/backend/src/serverRouter/blockRouter.js @@ -52,7 +52,7 @@ router.put('/block', async (req, res) => { if (!req.user) res.sendStatus(401); else { const result = await mongo.updateBlock(body); - res.status(200).json(result.value); + res.status(200).json(result); } } catch (error) { handleError(res, error, error, 500); From ac6ea68ac6b985c90980e138e0116a7389d5e020 Mon Sep 17 00:00:00 2001 From: i3rotlher Date: Tue, 5 Dec 2023 13:47:48 +0100 Subject: [PATCH 40/54] version updated --- frontend/src/app/app.component.html | 65 ++++++++++++++++------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/frontend/src/app/app.component.html b/frontend/src/app/app.component.html index ce9ec947c..cda109466 100644 --- a/frontend/src/app/app.component.html +++ b/frontend/src/app/app.component.html @@ -3,42 +3,47 @@
- Version 1.6.3 {{version === '' ? " (demo)" : ""}} + Version 1.7.0 {{version === '' ? " (demo)" : ""}}
- This is a demo version of Seed-Test. - Please note that to use it in production, you need to make some configurations to ensure it's fully functional. - Certain features may not work until you complete the installation process. + This is a demo version of Seed-Test. + Please note that to use it in production, you need to make some configurations to ensure it's fully + functional. + Certain features may not work until you complete the installation process. We strongly advise against using this unconfigured version in a production environment. For more information, please refer to the README. @@ -59,20 +64,19 @@

brightness_5 - + bedtime
+
\ No newline at end of file From fffeb18b6872e37ea8a9cbb347be7bbb9b36b6ad Mon Sep 17 00:00:00 2001 From: i3rotlher Date: Tue, 5 Dec 2023 13:49:29 +0100 Subject: [PATCH 41/54] updated versions --- backend/package.json | 6 ++++-- frontend/package.json | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/backend/package.json b/backend/package.json index f185e42a5..5af2dee9d 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "seed-test-backend", - "version": "1.6.2", + "version": "1.7.0", "engines": { "node": "18.13.0" }, @@ -69,6 +69,8 @@ "/spec/serverHelper.spec.js", "/node_modules/" ], - "setupFiles": ["./spec/setupTest.js"] + "setupFiles": [ + "./spec/setupTest.js" + ] } } diff --git a/frontend/package.json b/frontend/package.json index 8085ec660..98ec34b9b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "seed-test-frontend", - "version": "1.6.2", + "version": "1.7.0", "engines": { "node": "18.13.0" }, From 44a2baab48c84c3ae69953c19ff665696bfe3259 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20K=C3=B6hler?= Date: Wed, 6 Dec 2023 01:29:22 +0100 Subject: [PATCH 42/54] allow inline regex execution for then text --- backend/features/step_definitions/stepdefs.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/backend/features/step_definitions/stepdefs.js b/backend/features/step_definitions/stepdefs.js index 1237f07ca..c692cb0aa 100644 --- a/backend/features/step_definitions/stepdefs.js +++ b/backend/features/step_definitions/stepdefs.js @@ -665,6 +665,9 @@ Then('So I will be navigated to the website: {string}', async function checkUrl( // Search a textfield in the html code and assert it with a Text Then('So I can see the text {string} in the textbox: {string}', async function checkForTextInField(expectedText, label) { + const regex = /\{Regex:([^}]*)\}/g; + const resultString = expectedText.replace(regex, '($1)'); + const world = this; const identifiers = [`//*[@id='${label}']`, `//*[@*='${label}']`, `//*[contains(@*, '${label}')]`, @@ -677,7 +680,7 @@ Then('So I can see the text {string} in the textbox: {string}', async function c let resp = await elem.getText(); resp = resp == '' ? await elem.getAttribute('value') : resp; resp = resp == '' ? await elem.getAttribute('outerHTML') : resp; - match(resp, RegExp(expectedText.toString()), `Textfield does not contain the string/regex: ${expectedText} , actual: ${resp}`); + match(resp, RegExp(resultString), `Textfield does not contain the string/regex: ${resultString} , actual: ${resp}`); }) .catch(async (e) => { await driver.takeScreenshot().then(async (buffer) => { @@ -690,6 +693,8 @@ Then('So I can see the text {string} in the textbox: {string}', async function c // Search if a is text in html code Then('So I can see the text: {string}', async function (expectedText) { // text is present + const regex = /\{Regex:([^}]*)\}/g; + const resultString = expectedText.replace(regex, '($1)'); const world = this; try { await driver.wait(async () => driver.executeScript('return document.readyState').then(async (readyState) => readyState === 'complete')); @@ -699,7 +704,7 @@ Then('So I can see the text: {string}', async function (expectedText) { // text const innerHtmlBody = await driver.executeScript('return document.documentElement.innerHTML'); const outerHtmlBody = await driver.executeScript('return document.documentElement.outerHTML'); const bodyAll = cssBody + innerHtmlBody + outerHtmlBody; - match(bodyAll, RegExp(expectedText.toString()), `Page HTML does not contain the string/regex: ${expectedText}`); + match(bodyAll, RegExp(resultString), `Page HTML does not contain the string/regex: ${resultString}`); }); } catch (e) { await driver.takeScreenshot().then(async (buffer) => { From 296b1d1b45cd191c116d413bf4ff97e242b0d09d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20K=C3=B6hler?= Date: Thu, 7 Dec 2023 11:27:49 +0100 Subject: [PATCH 43/54] include nested Brackets: Regex --- backend/features/step_definitions/stepdefs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/features/step_definitions/stepdefs.js b/backend/features/step_definitions/stepdefs.js index c692cb0aa..461a5b74f 100644 --- a/backend/features/step_definitions/stepdefs.js +++ b/backend/features/step_definitions/stepdefs.js @@ -693,7 +693,7 @@ Then('So I can see the text {string} in the textbox: {string}', async function c // Search if a is text in html code Then('So I can see the text: {string}', async function (expectedText) { // text is present - const regex = /\{Regex:([^}]*)\}/g; + const regex = /\{Regex:([^}]*(?:\{[^}]*\}[^}]*)*)(\})(?=\s|$)/g; const resultString = expectedText.replace(regex, '($1)'); const world = this; try { From 76f708418ee9e3a2f6cbc45c2e2e8f951423f37e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20K=C3=B6hler?= Date: Tue, 12 Dec 2023 15:11:17 +0100 Subject: [PATCH 44/54] expand regex to all then text --- backend/features/step_definitions/stepdefs.js | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/backend/features/step_definitions/stepdefs.js b/backend/features/step_definitions/stepdefs.js index 461a5b74f..a0588b900 100644 --- a/backend/features/step_definitions/stepdefs.js +++ b/backend/features/step_definitions/stepdefs.js @@ -663,10 +663,16 @@ Then('So I will be navigated to the website: {string}', async function checkUrl( await driver.sleep(100 + currentParameters.waitTime); }); +const resolveRegex = (rawString) => { + // undefined to empty string + rawString = !rawString ? '' : rawString; + const regex = /\{Regex:([^}]*(?:\{[^}]*\}[^}]*)*)(\})(?=\s|$)/g; + return rawString.replace(regex, '($1)'); +}; + // Search a textfield in the html code and assert it with a Text Then('So I can see the text {string} in the textbox: {string}', async function checkForTextInField(expectedText, label) { - const regex = /\{Regex:([^}]*)\}/g; - const resultString = expectedText.replace(regex, '($1)'); + const resultString = resolveRegex(expectedText); const world = this; @@ -692,9 +698,8 @@ Then('So I can see the text {string} in the textbox: {string}', async function c }); // Search if a is text in html code -Then('So I can see the text: {string}', async function (expectedText) { // text is present - const regex = /\{Regex:([^}]*(?:\{[^}]*\}[^}]*)*)(\})(?=\s|$)/g; - const resultString = expectedText.replace(regex, '($1)'); +Then('So I can see the text: {string}', async function textPresent(expectedText) { // text is present + const resultString = resolveRegex(expectedText); const world = this; try { await driver.wait(async () => driver.executeScript('return document.readyState').then(async (readyState) => readyState === 'complete')); @@ -716,7 +721,7 @@ Then('So I can see the text: {string}', async function (expectedText) { // text }); // Search a textfield in the html code and assert if it's empty -Then('So I can\'t see text in the textbox: {string}', async function (label) { +Then('So I can\'t see text in the textbox: {string}', async function textAbsent(label) { const world = this; const identifiers = [`//*[@id='${label}']`, `//*[@*='${label}']`, `//*[contains(@id, '${label}')]`, `${label}`]; const promises = []; @@ -805,6 +810,7 @@ Then('So the picture {string} has the name {string}', async function checkPictur // Search if a text isn't in html code Then('So I can\'t see the text: {string}', async function checkIfTextIsMissing(expectedText) { + const resultString = resolveRegex(expectedText.toString()); const world = this; try { await driver.wait(async () => driver.executeScript('return document.readyState').then(async (readyState) => readyState === 'complete')); @@ -813,7 +819,7 @@ Then('So I can\'t see the text: {string}', async function checkIfTextIsMissing(e const innerHtmlBody = await driver.executeScript('return document.documentElement.innerHTML'); const outerHtmlBody = await driver.executeScript('return document.documentElement.outerHTML'); const bodyAll = cssBody + innerHtmlBody + outerHtmlBody; - doesNotMatch(bodyAll, RegExp(expectedText.toString()), `Page HTML does contain the string/regex: ${expectedText}`); + doesNotMatch(bodyAll, RegExp(resultString), `Page HTML does contain the string/regex: ${resultString}`); }); } catch (e) { await driver.takeScreenshot().then(async (buffer) => { From 34353c63431c4142c43db5595d8036f5bc574a5a Mon Sep 17 00:00:00 2001 From: i3rotlher Date: Tue, 12 Dec 2023 21:48:53 +0100 Subject: [PATCH 45/54] mongoDB Update fix --- backend/package-lock.json | 4 ++-- backend/src/database/DbServices.js | 6 +++--- backend/src/database/mongodatabase.js | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index c3876f458..12bf807eb 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "seed-test-backend", - "version": "1.6.2", + "version": "1.7.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "seed-test-backend", - "version": "1.6.2", + "version": "1.7.0", "dependencies": { "@cucumber/cucumber": "^7.3.2", "@types/promise-fs": "^2.1.2", diff --git a/backend/src/database/DbServices.js b/backend/src/database/DbServices.js index d075689d8..96ad726c0 100644 --- a/backend/src/database/DbServices.js +++ b/backend/src/database/DbServices.js @@ -327,7 +327,7 @@ async function createStoryGroup(repoID, name, members, sequence) { }, { upsert: true, projection: { groups: 1 } } ); - return groups.value.groups.slice(-1)._id; + return groups.groups.slice(-1)._id; } catch (e) { console.log(`ERROR in createStoryGroup: ${e}`); } @@ -612,7 +612,7 @@ async function deleteScenario(storyId, scenarioId) { try { const db = dbConnection.getConnection(); const collection = await db.collection(storiesCollection); - return collection.findOneAndUpdate({ _id: new ObjectId(storyId) }, { $pull: { scenarios: { scenario_id: scenarioId } } }, { returnDocument: 'after' }).then((res) => res.value); + return collection.findOneAndUpdate({ _id: new ObjectId(storyId) }, { $pull: { scenarios: { scenario_id: scenarioId } } }, { returnDocument: 'after' }).then((res) => res); } catch (e) { console.log(`ERROR in deleteScenario: ${e}`); throw e; @@ -817,7 +817,7 @@ async function removeFromWorkgroup(repoId, user) { const repo = await db.collection(repositoriesCollection).findOne({ _id: new ObjectId(repoId) }); const owner = await db.collection(userCollection).findOne({ _id: repo.owner }); const workGroup = await wGcollection.findOneAndUpdate({ Repo: new ObjectId(repoId) }, { $pull: { Members: { email: user.email } } }); - if (workGroup.value) { + if (workGroup) { const wG = await wGcollection.findOne({ Repo: new ObjectId(repoId) }); const result = { owner: {}, member: [] }; result.owner = { email: owner.email, canEdit: true }; diff --git a/backend/src/database/mongodatabase.js b/backend/src/database/mongodatabase.js index 3f4cffb44..95e2ee87c 100644 --- a/backend/src/database/mongodatabase.js +++ b/backend/src/database/mongodatabase.js @@ -349,7 +349,7 @@ async function createStoryGroup(repoID, name, members, sequence) { }, { upsert: true, projection: { groups: 1 } } ); - return groups.value.groups.slice(-1)._id; + return groups.groups.slice(-1)._id; } catch (e) { console.log(`UPS!!!! FEHLER in createStoryGroup: ${e}`); } finally { From b2ce4bf0141639f3b3916d3b5e918aa8d269cc88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20K=C3=B6hler?= Date: Thu, 14 Dec 2023 14:38:48 +0100 Subject: [PATCH 46/54] Fix: Resolve bug causing undefined in non regex steps --- frontend/src/app/base-editor/base-editor.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index 14f80752f..3194034a6 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -2071,7 +2071,7 @@ export class BaseEditorComponent { }); } } - textField.innerHTML = highlightedText + textField.innerHTML = highlightedText ? highlightedText : textContent; // Toastr logic if(initialCall && regexDetected) { From 04e480729b04d3b315e0632e34aa2cfc88817e3f Mon Sep 17 00:00:00 2001 From: i3rotlher Date: Fri, 15 Dec 2023 13:23:08 +0100 Subject: [PATCH 47/54] CI: Repo and Group -> Secrets --- .github/workflows/CI_Tests_and_Report.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/CI_Tests_and_Report.yaml b/.github/workflows/CI_Tests_and_Report.yaml index a295a3d03..87a7563ac 100644 --- a/.github/workflows/CI_Tests_and_Report.yaml +++ b/.github/workflows/CI_Tests_and_Report.yaml @@ -133,14 +133,14 @@ jobs: - name: Send sanity POST request and store response env: # <-- api url for sanity test -->/<---- repository_id --->/<------ group_id ------> - API_URL: localhost:8080/api/sanity/test/632893aad3bd45536c41b684/6400a70f5eda22409c4d2ed9 + API_URL: localhost:8080/api/sanity/test/${{ secrets.SANITY_REPO_ID }}/${{ secrets.SANITY_GROUP_ID }} run: | curl -X POST -H 'Content-Type: application/json' -d '{"email": "${{ secrets.SEED_EMAIL }}", "password": "${{ secrets.SEED_PW }}", "stayLoggedIn": true, "repository": "Seed-Test", "source": "db"}' "$API_URL" > sanityReport.txt - name: print sanity run: | echo $(cat sanityReport.txt) - + - name: Get passed and total sanity run: | passed=$(awk '/Steps:/ { match($0, /[0-9]+ passed/); print substr($0, RSTART, RLENGTH-7) }' sanityReport.txt) @@ -193,4 +193,4 @@ jobs: sanityStepsFailed: ${{ steps.passed-total-sanity.outputs.failedSteps }} sanityStepsSkipped: ${{ steps.passed-total-sanity.outputs.skippedSteps }} workflowLink: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - webhook: ${{ secrets.MS_TEAMS_WEBHOOK_URI }} \ No newline at end of file + webhook: ${{ secrets.MS_TEAMS_WEBHOOK_URI }} From 559dcccd288f33d36b8be6bc6e3cf6f657e87f1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20K=C3=B6hler?= Date: Fri, 15 Dec 2023 18:47:57 +0100 Subject: [PATCH 48/54] Fix: Add credentials to oneDriver request --- frontend/src/app/Services/story.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/Services/story.service.ts b/frontend/src/app/Services/story.service.ts index 07876b430..334637421 100644 --- a/frontend/src/app/Services/story.service.ts +++ b/frontend/src/app/Services/story.service.ts @@ -175,7 +175,7 @@ export class StoryService { */ public changeOneDriver(oneDriver: boolean, storyID: any) { return this.http - .post(this.apiService.apiServer + '/story/oneDriver/' + storyID, { oneDriver }); + .post(this.apiService.apiServer + '/story/oneDriver/' + storyID, { oneDriver }, ApiService.getOptions()); } /** * Checking the same name of the story From 2af55391e06cddef3d36ccfa721b692a58c60d84 Mon Sep 17 00:00:00 2001 From: NessArt Date: Mon, 18 Dec 2023 16:24:19 +0100 Subject: [PATCH 49/54] remove duplicated code with new service --- .../Services/highlight-input.service.spec.ts | 16 ++ .../app/Services/highlight-input.service.ts | 154 ++++++++++++++++++ .../app/base-editor/base-editor.component.ts | 128 +-------------- .../example-table/example-table.component.ts | 122 +------------- 4 files changed, 182 insertions(+), 238 deletions(-) create mode 100644 frontend/src/app/Services/highlight-input.service.spec.ts create mode 100644 frontend/src/app/Services/highlight-input.service.ts diff --git a/frontend/src/app/Services/highlight-input.service.spec.ts b/frontend/src/app/Services/highlight-input.service.spec.ts new file mode 100644 index 000000000..ff787fe87 --- /dev/null +++ b/frontend/src/app/Services/highlight-input.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { HighlightInputService } from './highlight-input.service'; + +describe('HighlightInputService', () => { + let service: HighlightInputService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(HighlightInputService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/Services/highlight-input.service.ts b/frontend/src/app/Services/highlight-input.service.ts new file mode 100644 index 000000000..9e36bce16 --- /dev/null +++ b/frontend/src/app/Services/highlight-input.service.ts @@ -0,0 +1,154 @@ +import { Injectable } from '@angular/core'; +import { ToastrService } from 'ngx-toastr'; + +@Injectable({ + providedIn: 'root' +}) +export class HighlightInputService { + + constructor(public toastr: ToastrService) { } + targetOffset: number = 0; + + /** + * Add value and highlight regex, Style regex in value and give value to addToValue() function + * Value is in textContent and style is in innerHTML + * If initialCall only check if a regex is already there and hightlight it + * If valueIndex only hightlights regex in first field of regexSteps, only then steps for now. Gets checked with stepPre + * Get cursor position with getCaretCharacterOffsetWithin Helper and set position again, else it is lost because of overwriting and changing the HTML Element in case of hightlighting + * @param element HTML element of contentedible div + * @param initialCall if call is from ngAfterView + * @param isDark theming Service + * @param regexInStory if first regex in Story + * @param valueIndex index of input field + * @param stepPre pre text of step + * @returns if a regex was detected + */ + highlightRegex(element, initialCall?:boolean, isDark?:boolean, regexInStory?:boolean, valueIndex?: number, stepPre?: string) { + const regexPattern =/(\{Regex:)(.*?)(\})(?=\s|$)/g;// Regex pattern to recognize and highlight regex expressions -> start with {Regex: and end with } + + const textField = element + const textContent = textField.textContent; + //Get current cursor position + const offset = this.getCaretCharacterOffsetWithin(textField) + const regexSteps = ['So I can see the text', 'So I can see the text:', 'So I can\'t see the text:', 'So I can\'t see text in the textbox:'] + var regexDetected = false; + + let highlightedText; + if(!valueIndex || (0==valueIndex && regexSteps.includes(stepPre))){ + if(isDark){ + highlightedText = textContent.replace(regexPattern, (match, match1, match2, match3) => { + regexDetected = true; + return ``+ + `${match1}`+ + `${match2}`+ + `${match3}`; + }); + } else{ + highlightedText = textContent.replace(regexPattern, (match, match1, match2, match3) => { + regexDetected = true; + return ``+ + `${match1}`+ + `${match2}`+ + `${match3}`; + }); + } + } + textField.innerHTML = highlightedText ? highlightedText : textContent; + + // Toastr logic + if(initialCall && regexDetected) { + regexInStory = true + } + if(regexDetected && !regexInStory){ + this.toastr.info('View our Documentation for more Info','Regular Expression detected!'); + } + + // Set cursor to correct position + if(!initialCall){ + if (regexDetected) { //maybe not needed + const selection = window.getSelection(); + selection.removeAllRanges() + + // Call the function to find the correct node and offset + this.targetOffset = offset + const result = this.findNodeAndOffset(textField); + + if (result !== null) { + const [node, offsetIndex] = result; + requestAnimationFrame(() => { + if (node.nodeType === 3) { + // Text node + selection.setBaseAndExtent(node, offsetIndex, node, offsetIndex); + } else if (node.nodeType === 1 && node.childNodes.length > 0) { + // Element node with child nodes (e.g., ) + selection.setBaseAndExtent(node.childNodes[0], offsetIndex, node.childNodes[0], offsetIndex); + } + }); + } + } else { + requestAnimationFrame(() => { + const selection = window.getSelection(); + selection.removeAllRanges(); + selection.setBaseAndExtent(textField.firstChild, offset, textField.firstChild, offset) + }) + } + } + return regexDetected; + } + +/** + * Helper for Regex Highlighter, find right node and index for current cursor position + * @param element HTMLElement + * @returns node: node with cursor, number: offest of cursor in node + */ + findNodeAndOffset(element: Node): [Node, number] | null { + if (element.nodeType === 3) { + // Text node + const textLength = (element.nodeValue || "").length; + if (this.targetOffset <= textLength) { + return [element, this.targetOffset]; + } else { + this.targetOffset -= textLength; + } + } else if (element.nodeType === 1){ + // Element node + for (let i = 0; i < element.childNodes.length; i++) { + const child = element.childNodes[i]; + const result = this.findNodeAndOffset(child); + if (result !== null) { + return result; + } + } + } + return null; + } + + /** + * Helper for Regex Highlighter, extract current cursor position + * @param element HTMLElement + * @returns num, offset of cursor position + */ + getCaretCharacterOffsetWithin(element) { + var caretOffset = 0; + var doc = element.ownerDocument || element.document; + var win = doc.defaultView || doc.parentWindow; + var sel; + if (typeof win.getSelection != "undefined") { + sel = win.getSelection(); + if (sel.rangeCount > 0) { + var range = win.getSelection().getRangeAt(0); + var preCaretRange = range.cloneRange(); + preCaretRange.selectNodeContents(element); + preCaretRange.setEnd(range.endContainer, range.endOffset); + caretOffset = preCaretRange.toString().length; + } + } else if ( (sel = doc.selection) && sel.type != "Control") { + var textRange = sel.createRange(); + var preCaretTextRange = doc.body.createTextRange(); + preCaretTextRange.moveToElementText(element); + preCaretTextRange.setEndPoint("EndToEnd", textRange); + caretOffset = preCaretTextRange.text.length; + } + return caretOffset; + } +} diff --git a/frontend/src/app/base-editor/base-editor.component.ts b/frontend/src/app/base-editor/base-editor.component.ts index 3194034a6..f5d96321e 100644 --- a/frontend/src/app/base-editor/base-editor.component.ts +++ b/frontend/src/app/base-editor/base-editor.component.ts @@ -22,6 +22,7 @@ import { InfoWarningToast } from '../info-warning-toast'; import { EditBlockComponent } from '../modals/edit-block/edit-block.component'; import { DeleteToast } from '../delete-toast'; import { ThemingService } from '../Services/theming.service'; +import { HighlightInputService } from '../Services/highlight-input.service'; @Component({ selector: 'app-base-editor', @@ -174,7 +175,6 @@ export class BaseEditorComponent { regexInStory: boolean = false; initialRegex: boolean = true; - targetOffset: number = 0; @Input() isDark: boolean; @@ -196,7 +196,8 @@ export class BaseEditorComponent { public scenarioService: ScenarioService, public backgroundService: BackgroundService, public apiService: ApiService, - public themeService: ThemingService) {} + public themeService: ThemingService, + public highlightInputService: HighlightInputService) {} ngOnInit(): void { this.addBlocktoScenarioObservable = this.blockService.addBlockToScenarioEvent.subscribe(block => { @@ -2024,7 +2025,6 @@ export class BaseEditorComponent { * Value is in textContent and style is in innerHTML * If initialCall only check if a regex is already there and hightlight it * Only hightlights regex in first field of regexSteps, only then steps for now. Gets checked with stepPre - * Get cursor position with getCaretCharacterOffsetWithin Helper and set position again, else it is lost because of overwriting and changing the HTML Element in case of hightlighting * @param element HTML element of contentedible div * @param stepIndex for addToValue * @param valueIndex for addToValue @@ -2034,13 +2034,8 @@ export class BaseEditorComponent { * @param initialCall if call is from ngAfterView */ highlightRegex(element, stepIndex?: number, valueIndex?: number, stepType?: string, step?:StepType, stepPre?: string, initialCall?:boolean) { - const regexPattern =/(\{Regex:)(.*?)(\})(?=\s|$)/g;// Regex pattern to recognize and highlight regex expressions -> start with {Regex: and end with } - - const textField = element//document.getElementById(element); + const textField = element; const textContent = textField.textContent; - //Get current cursor position - const offset = this.getCaretCharacterOffsetWithin(textField) - const regexSteps = ['So I can see the text', 'So I can see the text:', 'So I can\'t see the text:', 'So I can\'t see text in the textbox:'] var regexDetected = false; if(!initialCall){ @@ -2051,123 +2046,12 @@ export class BaseEditorComponent { this.initialRegex = false; } - let highlightedText; - if(0==valueIndex && regexSteps.includes(stepPre)){ - if(this.isDark){ - highlightedText = textContent.replace(regexPattern, (match, match1, match2, match3) => { - regexDetected = true; - return ``+ - `${match1}`+ - `${match2}`+ - `${match3}`; - }); - } else{ - highlightedText = textContent.replace(regexPattern, (match, match1, match2, match3) => { - regexDetected = true; - return ``+ - `${match1}`+ - `${match2}`+ - `${match3}`; - }); - } - } - textField.innerHTML = highlightedText ? highlightedText : textContent; + regexDetected = this.highlightInputService.highlightRegex(element, initialCall, this.isDark, this.regexInStory, valueIndex, stepPre) - // Toastr logic if(initialCall && regexDetected) { this.regexInStory = true } - if(regexDetected && !this.regexInStory){ - this.regexInStory = true - this.toastr.info('View our Documentation for more Info','Regular Expression detected!'); - } - - // Set cursor to correct position - if(!initialCall){ - if (regexDetected) { //maybe not needed - const selection = window.getSelection(); - selection.removeAllRanges() - - // Call the function to find the correct node and offset - this.targetOffset = offset - const result = this.findNodeAndOffset(textField); - - if (result !== null) { - const [node, offsetIndex] = result; - requestAnimationFrame(() => { - if (node.nodeType === 3) { - // Text node - selection.setBaseAndExtent(node, offsetIndex, node, offsetIndex); - } else if (node.nodeType === 1 && node.childNodes.length > 0) { - // Element node with child nodes (e.g., ) - selection.setBaseAndExtent(node.childNodes[0], offsetIndex, node.childNodes[0], offsetIndex); - } - }); - } - } else { - requestAnimationFrame(() => { - const selection = window.getSelection(); - selection.removeAllRanges(); - selection.setBaseAndExtent(textField.firstChild, offset, textField.firstChild, offset) - }) - } - } - } - - /** - * Helper for Regex Highlighter, find right node and index for current cursor position - * @param element HTMLElement - * @returns node: node with cursor, number: offest of cursor in node - */ - findNodeAndOffset(element: Node): [Node, number] | null { - if (element.nodeType === 3) { - // Text node - const textLength = (element.nodeValue || "").length; - if (this.targetOffset <= textLength) { - return [element, this.targetOffset]; - } else { - this.targetOffset -= textLength; - } - } else if (element.nodeType === 1){ - // Element node - for (let i = 0; i < element.childNodes.length; i++) { - const child = element.childNodes[i]; - const result = this.findNodeAndOffset(child); - if (result !== null) { - return result; - } - } - } - return null; - } - - /** - * Helper for Regex Highlighter, extract current cursor position - * @param element HTMLElement - * @returns num, offset of cursor position - */ - getCaretCharacterOffsetWithin(element) { - var caretOffset = 0; - var doc = element.ownerDocument || element.document; - var win = doc.defaultView || doc.parentWindow; - var sel; - if (typeof win.getSelection != "undefined") { - sel = win.getSelection(); - if (sel.rangeCount > 0) { - var range = win.getSelection().getRangeAt(0); - var preCaretRange = range.cloneRange(); - preCaretRange.selectNodeContents(element); - preCaretRange.setEnd(range.endContainer, range.endOffset); - caretOffset = preCaretRange.toString().length; - } - } else if ( (sel = doc.selection) && sel.type != "Control") { - var textRange = sel.createRange(); - var preCaretTextRange = doc.body.createTextRange(); - preCaretTextRange.moveToElementText(element); - preCaretTextRange.setEndPoint("EndToEnd", textRange); - caretOffset = preCaretTextRange.text.length; - } - return caretOffset; + } /** diff --git a/frontend/src/app/example-table/example-table.component.ts b/frontend/src/app/example-table/example-table.component.ts index 0dcf3d3db..30a3028e4 100644 --- a/frontend/src/app/example-table/example-table.component.ts +++ b/frontend/src/app/example-table/example-table.component.ts @@ -15,6 +15,7 @@ import { MatTable } from '@angular/material/table'; import { StepDefinition } from '../model/StepDefinition'; import { ThemePalette } from '@angular/material/core'; import { ThemingService } from '../Services/theming.service'; +import { HighlightInputService } from '../Services/highlight-input.service'; @Component({ @@ -158,8 +159,8 @@ export class ExampleTableComponent implements OnInit { private toastr: ToastrService, public exampleService: ExampleService, public apiService: ApiService, - public themeService: ThemingService - + public themeService: ThemingService, + public highlightInputService: HighlightInputService ) {} /** @@ -427,9 +428,7 @@ export class ExampleTableComponent implements OnInit { * @param initialCall if call is from ngDoCheck */ private highlightRegex(el, columnIndex, rowIndex, initialCall) { - const regex = /(\{Regex:)(.*?)(\})(?=\s|$)/g;// Regex pattern to recognize and highlight regex expressions -> start with {Regex: and end with } const inputValue: string = el.textContent; - const offset = this.getCaretCharacterOffsetWithin(el) if(!initialCall){ this.selectedScenario.stepDefinitions.example[rowIndex + 1].values[columnIndex-1] = inputValue; @@ -438,123 +437,14 @@ export class ExampleTableComponent implements OnInit { if(!initialCall){ this.initialRegex = false; } - - let highlightedText: string; - var regexDetected = false; - if(this.isDark){ - highlightedText = inputValue.replace(regex, (match, match1, match2, match3) => { - regexDetected = true; - return ``+ - `${match1}`+ - `${match2}`+ - `${match3}`; - }); - } else{ - highlightedText = inputValue.replace(regex, (match, match1, match2, match3) => { - regexDetected = true; - return ``+ - `${match1}`+ - `${match2}`+ - `${match3}`; - }); - } - el.innerHTML = highlightedText + var regexDetected = false; + + regexDetected = this.highlightInputService.highlightRegex(el,initialCall, this.isDark, this.regexInStory) if(initialCall && regexDetected) { this.regexInStory = true } - if(regexDetected && !this.regexInStory){ - this.regexInStory = true - this.toastr.info('View our Documentation for more Info','Regular Expression detected!'); - } - - // Set cursor to correct position - if(!initialCall){ - if (regexDetected){ //maybe not needed - const selection = window.getSelection(); - selection.removeAllRanges() - - // Call the function to find the correct node and offset - this.targetOffset = offset - const result = this.findNodeAndOffset(el); - - if (result !== null) { - const [node, offsetIndex] = result; - requestAnimationFrame(() => { - if (node.nodeType === 3) { - // Text node - selection.setBaseAndExtent(node, offsetIndex, node, offsetIndex); - } else if (node.nodeType === 1 && node.childNodes.length > 0) { - // Element node with child nodes (e.g., ) - selection.setBaseAndExtent(node.childNodes[0], offsetIndex, node.childNodes[0], offsetIndex); - } - }); - } - } else { - requestAnimationFrame(() => { - const selection = window.getSelection(); - selection.removeAllRanges(); - selection.setBaseAndExtent(el.firstChild, offset, el.firstChild, offset) - }) - } - } - } - - /** - * Helper for Regex Highlighter, find right node and index for current cursor position - * @param element HTMLElement - * @returns node: node with cursor, number: offest of cursor in node - */ - findNodeAndOffset(element: Node): [Node, number] | null { - if (element.nodeType === 3) { - // Text node - const textLength = (element.nodeValue || "").length; - if (this.targetOffset <= textLength) { - return [element, this.targetOffset]; - } else { - this.targetOffset -= textLength; - } - } else if (element.nodeType === 1){ - // Element node - for (let i = 0; i < element.childNodes.length; i++) { - const child = element.childNodes[i]; - const result = this.findNodeAndOffset(child); - if (result !== null) { - return result; - } - } - } - return null; - } - - /** - * Helper for Regex Highlighter, extract current cursor position - * @param element HTMLElement - * @returns num, offset of cursor position - */ - getCaretCharacterOffsetWithin(element) { - var caretOffset = 0; - var doc = element.ownerDocument || element.document; - var win = doc.defaultView || doc.parentWindow; - var sel; - if (typeof win.getSelection != "undefined") { - sel = win.getSelection(); - if (sel.rangeCount > 0) { - var range = win.getSelection().getRangeAt(0); - var preCaretRange = range.cloneRange(); - preCaretRange.selectNodeContents(element); - preCaretRange.setEnd(range.endContainer, range.endOffset); - caretOffset = preCaretRange.toString().length; - } - } else if ( (sel = doc.selection) && sel.type != "Control") { - var textRange = sel.createRange(); - var preCaretTextRange = doc.body.createTextRange(); - preCaretTextRange.moveToElementText(element); - preCaretTextRange.setEndPoint("EndToEnd", textRange); - caretOffset = preCaretTextRange.text.length; - } - return caretOffset; } /** From 0045d220cf532d54facf50fd7ebfa0b1d9ef3ad8 Mon Sep 17 00:00:00 2001 From: NessArt Date: Thu, 21 Dec 2023 13:44:16 +0100 Subject: [PATCH 50/54] alternate background color --- .../app/stories-bar/stories-bar.component.html | 4 ++-- frontend/src/styles.scss | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/stories-bar/stories-bar.component.html b/frontend/src/app/stories-bar/stories-bar.component.html index f1850ea74..ba5d0001d 100644 --- a/frontend/src/app/stories-bar/stories-bar.component.html +++ b/frontend/src/app/stories-bar/stories-bar.component.html @@ -53,8 +53,8 @@ Group - -- - + -- + {{group}} diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index 0701ac019..d5de75cd5 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -1147,6 +1147,21 @@ mat-mdc-select{ height: 40px; } +.even-row-mat-option { + background-color: white; + font-size: 14px; +} + +.odd-row-mat-option { + background-color: rgba(0, 0, 0, 0.04); + font-size: 14px; +} + +.darkTheme .even-row-mat-option{ + background-color: #6c7c84;; + font-size: 14px; +} + .darkTheme .mat-mdc-option.mdc-list-item--selected:not(.mdc-list-item--disabled) .mdc-list-item__primary-text, .darkTheme .mat-pseudo-checkbox-checked.mat-pseudo-checkbox-minimal:after, .darkTheme .mdc-text-field--focused:not(.mdc-text-field--disabled) .mdc-floating-label { From d7fbc9ed35a9165854cb16e805daa1ec53301521 Mon Sep 17 00:00:00 2001 From: NessArt Date: Fri, 22 Dec 2023 12:18:16 +0100 Subject: [PATCH 51/54] style all dropdown with alternate colors --- .../account-management.component.html | 2 +- .../src/app/base-editor/base-editor.component.css | 3 ++- .../src/app/base-editor/base-editor.component.html | 12 ++++++------ .../workgroup-edit/workgroup-edit.component.html | 2 +- .../src/app/stories-bar/stories-bar.component.html | 8 ++++---- frontend/src/styles.scss | 9 +++++++++ 6 files changed, 23 insertions(+), 13 deletions(-) diff --git a/frontend/src/app/account-management/account-management.component.html b/frontend/src/app/account-management/account-management.component.html index 32ace815b..81ca86664 100644 --- a/frontend/src/app/account-management/account-management.component.html +++ b/frontend/src/app/account-management/account-management.component.html @@ -55,7 +55,7 @@

Seed-Test Account

Project - {{repo.value}} + {{repo.value}}
diff --git a/frontend/src/app/base-editor/base-editor.component.css b/frontend/src/app/base-editor/base-editor.component.css index a99cb01ca..31bc24432 100644 --- a/frontend/src/app/base-editor/base-editor.component.css +++ b/frontend/src/app/base-editor/base-editor.component.css @@ -330,7 +330,8 @@ mat-expansion-panel.stepBlockContainer .mat-expansion-panel-body { } .exampleListOption { - font-weight: bold !important; + /*font-weight: bold !important;*/ + font-size: 16px; } .exampleButton{ diff --git a/frontend/src/app/base-editor/base-editor.component.html b/frontend/src/app/base-editor/base-editor.component.html index ddfada626..6cddfca06 100644 --- a/frontend/src/app/base-editor/base-editor.component.html +++ b/frontend/src/app/base-editor/base-editor.component.html @@ -167,7 +167,7 @@ - {{exampleList}} @@ -191,7 +191,7 @@ - + {{dropdownValue}} @@ -217,7 +217,7 @@ - {{exampleList}} @@ -242,7 +242,7 @@ - + {{dropdownValue}} @@ -269,7 +269,7 @@ - {{exampleList}} @@ -294,7 +294,7 @@ - + {{dropdownValue}} diff --git a/frontend/src/app/modals/workgroup-edit/workgroup-edit.component.html b/frontend/src/app/modals/workgroup-edit/workgroup-edit.component.html index d92cfc95e..2d3007d86 100644 --- a/frontend/src/app/modals/workgroup-edit/workgroup-edit.component.html +++ b/frontend/src/app/modals/workgroup-edit/workgroup-edit.component.html @@ -18,7 +18,7 @@ Project Owner - + {{element.email}} diff --git a/frontend/src/app/stories-bar/stories-bar.component.html b/frontend/src/app/stories-bar/stories-bar.component.html index ba5d0001d..7dc568a38 100644 --- a/frontend/src/app/stories-bar/stories-bar.component.html +++ b/frontend/src/app/stories-bar/stories-bar.component.html @@ -35,8 +35,8 @@ Assignee - -- - + -- + {{assignee}} @@ -44,8 +44,8 @@ Status Of Story - -- - + -- + {{testPassed}} diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index d5de75cd5..c697a580d 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -1150,16 +1150,25 @@ mat-mdc-select{ .even-row-mat-option { background-color: white; font-size: 14px; + font-weight: normal !important; } .odd-row-mat-option { background-color: rgba(0, 0, 0, 0.04); font-size: 14px; + font-weight: normal !important; } .darkTheme .even-row-mat-option{ background-color: #6c7c84;; font-size: 14px; + font-weight: normal !important; +} + +.darkTheme .odd-row-mat-option{ + background-color: rgba(255,255,255,.08); + font-size: 14px; + font-weight: normal !important; } .darkTheme .mat-mdc-option.mdc-list-item--selected:not(.mdc-list-item--disabled) .mdc-list-item__primary-text, From ca06b5d6d1cc8c6472a3cb69055cf12753abaaea Mon Sep 17 00:00:00 2001 From: NessArt Date: Fri, 22 Dec 2023 12:22:51 +0100 Subject: [PATCH 52/54] resolve sonarcloud issues --- frontend/src/app/base-editor/base-editor.component.css | 1 - frontend/src/styles.scss | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/app/base-editor/base-editor.component.css b/frontend/src/app/base-editor/base-editor.component.css index 2b291d86c..f6a9cd315 100644 --- a/frontend/src/app/base-editor/base-editor.component.css +++ b/frontend/src/app/base-editor/base-editor.component.css @@ -330,7 +330,6 @@ mat-expansion-panel.stepBlockContainer .mat-expansion-panel-body { } .exampleListOption { - /*font-weight: bold !important;*/ font-size: 16px; } diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index c697a580d..9479f488e 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -1160,7 +1160,7 @@ mat-mdc-select{ } .darkTheme .even-row-mat-option{ - background-color: #6c7c84;; + background-color: #6c7c84; font-size: 14px; font-weight: normal !important; } From 33c1eebc0cb978fca9334836bf786d349c38bd17 Mon Sep 17 00:00:00 2001 From: jonycoo Date: Fri, 22 Dec 2023 15:28:52 +0100 Subject: [PATCH 53/54] Drop down (#501) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * debug error Signed-off-by: jonycoo * dropdown via ARIA role * ty another way dropdown * working dropdown by ARIA * buggy integration to original dropdown * original & ARIA dropdown * fixed standard version selector * weiterer fix für xpath option in aria --------- Signed-off-by: jonycoo --- backend/features/step_definitions/stepdefs.js | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/backend/features/step_definitions/stepdefs.js b/backend/features/step_definitions/stepdefs.js index a0588b900..d05cd500b 100644 --- a/backend/features/step_definitions/stepdefs.js +++ b/backend/features/step_definitions/stepdefs.js @@ -462,15 +462,37 @@ When('I select {string} from the selection {string}', async function clickRadioB }); // Select an Option from a dropdown-menu -When('I select the option {string} from the drop-down-menue {string}', async (value, dropd) => { - let world; +When('I select the option {string} from the drop-down-menue {string}', async function (value, dropd) { + const world = this; const identifiers = [`//*[@*='${dropd}']/option[text()='${value}']`, `//label[contains(text(),'${dropd}')]/following::button[text()='${value}']`, - `//label[contains(text(),'${dropd}')]/following::span[text()='${value}']`, `//*[contains(text(),'${dropd}')]/following::*[contains(text(),'${value}']`, `${dropd}`]; - const promises = []; - for (const idString of identifiers) promises.push(driver.wait(until.elementLocated(By.xpath(idString)), searchTimeout, `Timed out after ${searchTimeout} ms`, 100)); + `//label[contains(text(),'${dropd}')]/following::span[text()='${value}']`, `//*[contains(text(),'${dropd}')]/following::*[contains(text(),'${value}']`, `//*[@role='listbox']//*[self::li[@role='option' and text()='${value}'] or parent::li[@role='option' and text()='${value}']]`, + `${dropd}//option[contains(text(),'${value}') or contains(@id, '${value}') or contains(@*,'${value}')]`]; + const promises = identifiers.map((idString) => + driver.wait( + until.elementLocated(By.xpath(idString)), + searchTimeout, + `Timed out after ${searchTimeout} ms`, + 100 + ) + ); await Promise.any(promises) .then((elem) => elem.click()) + .catch(async (e) => { + const ariaProm = [driver.findElement(By.xpath(`//*[contains(text(),"${dropd}") or contains(@id, "${dropd}") or contains(@*, "${dropd}")]`)), driver.findElement(By.xpath(`${dropd}`))]; + const dropdownElement = await Promise.any(ariaProm); + await dropdownElement.click(); + + const ariaOptProm = [driver.findElement(By.xpath(`(//*[contains(text(),'${value}') or contains(@id, '${value}') or contains(@*, '${value}')]/option) | (//*[@role='listbox']//*[ancestor::*[@role='option']//*[contains(text(),'${value}')]]) + `)), driver.findElement(By.xpath(`${value}`))]; + const dropdownOption = await Promise.any(ariaOptProm).catch((e) => { throw e; }); + + // Wait for the dropdown options to be visible + await driver.wait(until.elementIsVisible(dropdownOption)).catch((e) => { throw e; }); + + // Select the option from the dropdown + await dropdownOption.click(); + }) .catch(async (e) => { await driver.takeScreenshot().then(async (buffer) => { world.attach(buffer, 'image/png'); From c7440cf990a025dc6f722e1bd397454820ae0ea0 Mon Sep 17 00:00:00 2001 From: NessArt Date: Wed, 27 Dec 2023 15:21:11 +0100 Subject: [PATCH 54/54] add padding for project drop down --- .../app/account-management/account-management.component.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/src/app/account-management/account-management.component.css b/frontend/src/app/account-management/account-management.component.css index 61afb2544..10e09662c 100644 --- a/frontend/src/app/account-management/account-management.component.css +++ b/frontend/src/app/account-management/account-management.component.css @@ -338,4 +338,8 @@ h2, h1{ text-align: center; color:white; opacity: 1; +} + +.mat-mdc-option{ + padding: 0px 16px 0px 16px !important; } \ No newline at end of file